fix previous failures and address review
This commit is contained in:
parent
6cf3409e16
commit
8ff1edbe5e
9 changed files with 212 additions and 174 deletions
|
@ -20,8 +20,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
|
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
|
||||||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
||||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
|
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::{ErrorHandled, EvalToConstValueResult};
|
||||||
use rustc_middle::mir::interpret::EvalToConstValueResult;
|
|
||||||
use rustc_middle::traits::select;
|
use rustc_middle::traits::select;
|
||||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||||
|
@ -695,9 +694,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Reject any attempt to unify two unevaluated constants that contain inference
|
// Reject any attempt to unify two unevaluated constants that contain inference
|
||||||
// variables.
|
// variables, since inference variables in queries lead to ICEs.
|
||||||
// FIXME `TyCtxt::const_eval_resolve` already rejects the resolution of those
|
|
||||||
// constants early, but the canonicalization below messes with that mechanism.
|
|
||||||
if a.substs.has_infer_types_or_consts() || b.substs.has_infer_types_or_consts() {
|
if a.substs.has_infer_types_or_consts() || b.substs.has_infer_types_or_consts() {
|
||||||
debug!("a or b contain infer vars in its substs -> cannot unify");
|
debug!("a or b contain infer vars in its substs -> cannot unify");
|
||||||
return false;
|
return false;
|
||||||
|
@ -1621,8 +1618,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
// Postpone the evaluation of constants whose substs depend on inference
|
// Postpone the evaluation of constants whose substs depend on inference
|
||||||
// variables
|
// variables
|
||||||
if substs.has_infer_types_or_consts() {
|
if substs.has_infer_types_or_consts() {
|
||||||
debug!("has infer types or consts");
|
debug!("substs have infer types or consts: {:?}", substs);
|
||||||
return Err(ErrorHandled::TooGeneric);
|
if substs.has_infer_types_or_consts() {
|
||||||
|
return Err(ErrorHandled::TooGeneric);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let param_env_erased = self.tcx.erase_regions(param_env);
|
let param_env_erased = self.tcx.erase_regions(param_env);
|
||||||
|
|
|
@ -43,7 +43,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
// variables. We reject those here since `resolve_opt_const_arg`
|
// variables. We reject those here since `resolve_opt_const_arg`
|
||||||
// would fail otherwise
|
// would fail otherwise
|
||||||
if ct.substs.has_infer_types_or_consts() {
|
if ct.substs.has_infer_types_or_consts() {
|
||||||
return Err(ErrorHandled::TooGeneric);
|
bug!("did not expect inference variables here");
|
||||||
}
|
}
|
||||||
|
|
||||||
match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
|
match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
|
||||||
|
|
|
@ -569,6 +569,18 @@ pub(super) fn thir_abstract_const<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tries to unify two abstract constants using structural equality.
|
||||||
|
#[instrument(skip(tcx), level = "debug")]
|
||||||
|
pub(super) fn try_unify<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
a: AbstractConst<'tcx>,
|
||||||
|
b: AbstractConst<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
let const_unify_ctxt = ConstUnifyCtxt::new(tcx, param_env);
|
||||||
|
const_unify_ctxt.try_unify_inner(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn try_unify_abstract_consts<'tcx>(
|
pub(super) fn try_unify_abstract_consts<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
(a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
|
(a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
|
||||||
|
@ -622,115 +634,119 @@ where
|
||||||
recurse(tcx, ct, &mut f)
|
recurse(tcx, ct, &mut f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Substitutes generics repeatedly to allow AbstractConsts to unify where a
|
pub(super) struct ConstUnifyCtxt<'tcx> {
|
||||||
// ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
|
|
||||||
// Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
|
|
||||||
#[inline]
|
|
||||||
#[instrument(skip(tcx), level = "debug")]
|
|
||||||
fn try_replace_substs_in_root<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
mut abstr_const: AbstractConst<'tcx>,
|
|
||||||
) -> Option<AbstractConst<'tcx>> {
|
|
||||||
while let Node::Leaf(ct) = abstr_const.root(tcx) {
|
|
||||||
match AbstractConst::from_const(tcx, ct) {
|
|
||||||
Ok(Some(act)) => abstr_const = act,
|
|
||||||
Ok(None) => break,
|
|
||||||
Err(_) => return None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(abstr_const)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tries to unify two abstract constants using structural equality.
|
|
||||||
#[instrument(skip(tcx), level = "debug")]
|
|
||||||
pub(super) fn try_unify<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
a: AbstractConst<'tcx>,
|
|
||||||
b: AbstractConst<'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> bool {
|
}
|
||||||
let a = match try_replace_substs_in_root(tcx, a) {
|
|
||||||
Some(a) => a,
|
|
||||||
None => {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let b = match try_replace_substs_in_root(tcx, b) {
|
impl<'tcx> ConstUnifyCtxt<'tcx> {
|
||||||
Some(b) => b,
|
pub(super) fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||||
None => {
|
ConstUnifyCtxt { tcx, param_env }
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let a_root = a.root(tcx);
|
// Substitutes generics repeatedly to allow AbstractConsts to unify where a
|
||||||
let b_root = b.root(tcx);
|
// ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
|
||||||
debug!(?a_root, ?b_root);
|
// Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
|
||||||
|
#[inline]
|
||||||
match (a_root, b_root) {
|
#[instrument(skip(self), level = "debug")]
|
||||||
(Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
|
pub(super) fn try_replace_substs_in_root(
|
||||||
let a_ct = a_ct.eval(tcx, param_env);
|
&self,
|
||||||
debug!("a_ct evaluated: {:?}", a_ct);
|
mut abstr_const: AbstractConst<'tcx>,
|
||||||
let b_ct = b_ct.eval(tcx, param_env);
|
) -> Option<AbstractConst<'tcx>> {
|
||||||
debug!("b_ct evaluated: {:?}", b_ct);
|
while let Node::Leaf(ct) = abstr_const.root(self.tcx) {
|
||||||
|
match AbstractConst::from_const(self.tcx, ct) {
|
||||||
if a_ct.ty() != b_ct.ty() {
|
Ok(Some(act)) => abstr_const = act,
|
||||||
return false;
|
Ok(None) => break,
|
||||||
}
|
Err(_) => return None,
|
||||||
|
|
||||||
match (a_ct.val(), b_ct.val()) {
|
|
||||||
// We can just unify errors with everything to reduce the amount of
|
|
||||||
// emitted errors here.
|
|
||||||
(ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
|
|
||||||
(ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
|
|
||||||
a_param == b_param
|
|
||||||
}
|
|
||||||
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
|
|
||||||
// If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
|
|
||||||
// we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
|
|
||||||
// means that we only allow inference variables if they are equal.
|
|
||||||
(ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
|
|
||||||
// We expand generic anonymous constants at the start of this function, so this
|
|
||||||
// branch should only be taking when dealing with associated constants, at
|
|
||||||
// which point directly comparing them seems like the desired behavior.
|
|
||||||
//
|
|
||||||
// FIXME(generic_const_exprs): This isn't actually the case.
|
|
||||||
// We also take this branch for concrete anonymous constants and
|
|
||||||
// expand generic anonymous constants with concrete substs.
|
|
||||||
(ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => {
|
|
||||||
a_uv == b_uv
|
|
||||||
}
|
|
||||||
// FIXME(generic_const_exprs): We may want to either actually try
|
|
||||||
// to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
|
|
||||||
// this, for now we just return false here.
|
|
||||||
_ => false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => {
|
|
||||||
try_unify(tcx, a.subtree(al), b.subtree(bl), param_env)
|
Some(abstr_const)
|
||||||
&& try_unify(tcx, a.subtree(ar), b.subtree(br), param_env)
|
}
|
||||||
|
|
||||||
|
/// Tries to unify two abstract constants using structural equality.
|
||||||
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
fn try_unify_inner(&self, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool {
|
||||||
|
let a = if let Some(a) = self.try_replace_substs_in_root(a) {
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
let b = if let Some(b) = self.try_replace_substs_in_root(b) {
|
||||||
|
b
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
let a_root = a.root(self.tcx);
|
||||||
|
let b_root = b.root(self.tcx);
|
||||||
|
debug!(?a_root, ?b_root);
|
||||||
|
|
||||||
|
match (a_root, b_root) {
|
||||||
|
(Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
|
||||||
|
let a_ct = a_ct.eval(self.tcx, self.param_env);
|
||||||
|
debug!("a_ct evaluated: {:?}", a_ct);
|
||||||
|
let b_ct = b_ct.eval(self.tcx, self.param_env);
|
||||||
|
debug!("b_ct evaluated: {:?}", b_ct);
|
||||||
|
|
||||||
|
if a_ct.ty() != b_ct.ty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
match (a_ct.val(), b_ct.val()) {
|
||||||
|
// We can just unify errors with everything to reduce the amount of
|
||||||
|
// emitted errors here.
|
||||||
|
(ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
|
||||||
|
(ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
|
||||||
|
a_param == b_param
|
||||||
|
}
|
||||||
|
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
|
||||||
|
// If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
|
||||||
|
// we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
|
||||||
|
// means that we only allow inference variables if they are equal.
|
||||||
|
(ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
|
||||||
|
// We expand generic anonymous constants at the start of this function, so this
|
||||||
|
// branch should only be taking when dealing with associated constants, at
|
||||||
|
// which point directly comparing them seems like the desired behavior.
|
||||||
|
//
|
||||||
|
// FIXME(generic_const_exprs): This isn't actually the case.
|
||||||
|
// We also take this branch for concrete anonymous constants and
|
||||||
|
// expand generic anonymous constants with concrete substs.
|
||||||
|
(ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => {
|
||||||
|
a_uv == b_uv
|
||||||
|
}
|
||||||
|
// FIXME(generic_const_exprs): We may want to either actually try
|
||||||
|
// to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
|
||||||
|
// this, for now we just return false here.
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => {
|
||||||
|
self.try_unify_inner(a.subtree(al), b.subtree(bl))
|
||||||
|
&& self.try_unify_inner(a.subtree(ar), b.subtree(br))
|
||||||
|
}
|
||||||
|
(Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
|
||||||
|
self.try_unify_inner(a.subtree(av), b.subtree(bv))
|
||||||
|
}
|
||||||
|
(Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
|
||||||
|
if a_args.len() == b_args.len() =>
|
||||||
|
{
|
||||||
|
self.try_unify_inner(a.subtree(a_f), b.subtree(b_f))
|
||||||
|
&& iter::zip(a_args, b_args)
|
||||||
|
.all(|(&an, &bn)| self.try_unify_inner(a.subtree(an), b.subtree(bn)))
|
||||||
|
}
|
||||||
|
(Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
|
||||||
|
if (a_ty == b_ty) && (a_kind == b_kind) =>
|
||||||
|
{
|
||||||
|
self.try_unify_inner(a.subtree(a_operand), b.subtree(b_operand))
|
||||||
|
}
|
||||||
|
// use this over `_ => false` to make adding variants to `Node` less error prone
|
||||||
|
(Node::Cast(..), _)
|
||||||
|
| (Node::FunctionCall(..), _)
|
||||||
|
| (Node::UnaryOp(..), _)
|
||||||
|
| (Node::Binop(..), _)
|
||||||
|
| (Node::Leaf(..), _) => false,
|
||||||
}
|
}
|
||||||
(Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
|
|
||||||
try_unify(tcx, a.subtree(av), b.subtree(bv), param_env)
|
|
||||||
}
|
|
||||||
(Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
|
|
||||||
if a_args.len() == b_args.len() =>
|
|
||||||
{
|
|
||||||
try_unify(tcx, a.subtree(a_f), b.subtree(b_f), param_env)
|
|
||||||
&& iter::zip(a_args, b_args)
|
|
||||||
.all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn), param_env))
|
|
||||||
}
|
|
||||||
(Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
|
|
||||||
if (a_ty == b_ty) && (a_kind == b_kind) =>
|
|
||||||
{
|
|
||||||
try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand), param_env)
|
|
||||||
}
|
|
||||||
// use this over `_ => false` to make adding variants to `Node` less error prone
|
|
||||||
(Node::Cast(..), _)
|
|
||||||
| (Node::FunctionCall(..), _)
|
|
||||||
| (Node::UnaryOp(..), _)
|
|
||||||
| (Node::Binop(..), _)
|
|
||||||
| (Node::Leaf(..), _) => false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -581,7 +581,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
||||||
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
|
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
|
||||||
(c1.val(), c2.val())
|
(c1.val(), c2.val())
|
||||||
{
|
{
|
||||||
if infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
|
if infcx.try_unify_abstract_consts(
|
||||||
|
a.shrink(),
|
||||||
|
b.shrink(),
|
||||||
|
obligation.param_env,
|
||||||
|
) {
|
||||||
return ProcessResult::Changed(vec![]);
|
return ProcessResult::Changed(vec![]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -860,7 +860,10 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
||||||
ty::WithOptConstParam { did, const_param_did: Some(param_did) },
|
ty::WithOptConstParam { did, const_param_did: Some(param_did) },
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
try_unify_abstract_consts: const_evaluatable::try_unify_abstract_consts,
|
try_unify_abstract_consts: |tcx, param_env_and| {
|
||||||
|
let (param_env, (a, b)) = param_env_and.into_parts();
|
||||||
|
const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)
|
||||||
|
},
|
||||||
..*providers
|
..*providers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -643,7 +643,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
|
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
|
||||||
(c1.val(), c2.val())
|
(c1.val(), c2.val())
|
||||||
{
|
{
|
||||||
if self.infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
|
if self.infcx.try_unify_abstract_consts(
|
||||||
|
a.shrink(),
|
||||||
|
b.shrink(),
|
||||||
|
obligation.param_env,
|
||||||
|
) {
|
||||||
return Ok(EvaluatedToOk);
|
return Ok(EvaluatedToOk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,7 +243,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||||
(
|
(
|
||||||
ty::PredicateKind::ConstEvaluatable(a),
|
ty::PredicateKind::ConstEvaluatable(a),
|
||||||
ty::PredicateKind::ConstEvaluatable(b),
|
ty::PredicateKind::ConstEvaluatable(b),
|
||||||
) => tcx.try_unify_abstract_consts((a, b)),
|
) => tcx.try_unify_abstract_consts(self_param_env.and((a, b))),
|
||||||
(
|
(
|
||||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
|
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
|
||||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
|
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
|
||||||
|
|
|
@ -2,103 +2,115 @@
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
trait TensorDimension {
|
trait TensorDimension {
|
||||||
const DIM : usize;
|
const DIM: usize;
|
||||||
//~^ ERROR cycle detected when resolving instance `<LazyUpdim<T, {T::DIM}, DIM>
|
//~^ ERROR cycle detected when resolving instance
|
||||||
const ISSCALAR : bool = Self::DIM == 0;
|
// FIXME Given the current state of the compiler its expected that we cycle here,
|
||||||
fn is_scalar(&self) -> bool {Self::ISSCALAR}
|
// but the cycle is still wrong.
|
||||||
}
|
const ISSCALAR: bool = Self::DIM == 0;
|
||||||
|
fn is_scalar(&self) -> bool {
|
||||||
trait TensorSize : TensorDimension {
|
Self::ISSCALAR
|
||||||
fn size(&self) -> [usize;Self::DIM];
|
|
||||||
fn inbounds(&self,index : [usize;Self::DIM]) -> bool {
|
|
||||||
index.iter().zip(self.size().iter()).all(|(i,s)| i < s)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait TensorSize: TensorDimension {
|
||||||
|
fn size(&self) -> [usize; Self::DIM];
|
||||||
|
fn inbounds(&self, index: [usize; Self::DIM]) -> bool {
|
||||||
|
index.iter().zip(self.size().iter()).all(|(i, s)| i < s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trait Broadcastable: TensorSize + Sized {
|
trait Broadcastable: TensorSize + Sized {
|
||||||
type Element;
|
type Element;
|
||||||
fn bget(&self, index:[usize;Self::DIM]) -> Option<Self::Element>;
|
fn bget(&self, index: [usize; Self::DIM]) -> Option<Self::Element>;
|
||||||
fn lazy_updim<const NEWDIM : usize>(&self, size : [usize;NEWDIM] ) ->
|
fn lazy_updim<const NEWDIM: usize>(
|
||||||
LazyUpdim<Self,{Self::DIM},NEWDIM>
|
&self,
|
||||||
{
|
size: [usize; NEWDIM],
|
||||||
assert!(NEWDIM >= Self::DIM,
|
) -> LazyUpdim<Self, { Self::DIM }, NEWDIM> {
|
||||||
"Updimmed tensor cannot have fewer indices than the initial one.");
|
assert!(
|
||||||
LazyUpdim {size,reference:&self}
|
NEWDIM >= Self::DIM,
|
||||||
|
"Updimmed tensor cannot have fewer indices than the initial one."
|
||||||
|
);
|
||||||
|
LazyUpdim { size, reference: &self }
|
||||||
}
|
}
|
||||||
fn bmap<T,F :Fn(Self::Element) -> T>(&self,foo : F) -> BMap<T,Self,F,{Self::DIM}>{
|
fn bmap<T, F: Fn(Self::Element) -> T>(&self, foo: F) -> BMap<T, Self, F, { Self::DIM }> {
|
||||||
BMap {reference:self,closure : foo}
|
BMap { reference: self, closure: foo }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct LazyUpdim<'a, T: Broadcastable, const OLDDIM: usize, const DIM: usize> {
|
||||||
struct LazyUpdim<'a,T : Broadcastable,const OLDDIM : usize, const DIM : usize> {
|
size: [usize; DIM],
|
||||||
size : [usize;DIM],
|
reference: &'a T,
|
||||||
reference : &'a T
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a,T : Broadcastable,const DIM : usize> TensorDimension for LazyUpdim<'a,T,{T::DIM},DIM> {
|
impl<'a, T: Broadcastable, const DIM: usize> TensorDimension for LazyUpdim<'a, T, { T::DIM }, DIM> {
|
||||||
const DIM : usize = DIM;
|
const DIM: usize = DIM;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a,T : Broadcastable,const DIM : usize> TensorSize for LazyUpdim<'a,T,{T::DIM},DIM> {
|
impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T::DIM }, DIM> {
|
||||||
fn size(&self) -> [usize;DIM] {self.size}
|
fn size(&self) -> [usize; DIM] {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a,T : Broadcastable,const DIM : usize> Broadcastable for LazyUpdim<'a,T,{T::DIM},DIM>
|
impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> {
|
||||||
{
|
|
||||||
type Element = T::Element;
|
type Element = T::Element;
|
||||||
fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
|
fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
|
||||||
assert!(DIM >= T::DIM);
|
assert!(DIM >= T::DIM);
|
||||||
if !self.inbounds(index) {return None}
|
if !self.inbounds(index) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let size = self.size();
|
let size = self.size();
|
||||||
let newindex : [usize;T::DIM] = Default::default();
|
let newindex: [usize; T::DIM] = Default::default();
|
||||||
self.reference.bget(newindex)
|
self.reference.bget(newindex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BMap<'a,R, T : Broadcastable, F : Fn(T::Element) -> R , const DIM: usize> {
|
struct BMap<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> {
|
||||||
reference : &'a T,
|
reference: &'a T,
|
||||||
closure : F
|
closure: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a,R, T : Broadcastable, F : Fn(T::Element) -> R,
|
impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorDimension
|
||||||
const DIM: usize> TensorDimension for BMap<'a,R,T,F,DIM> {
|
for BMap<'a, R, T, F, DIM>
|
||||||
|
{
|
||||||
const DIM : usize = DIM;
|
const DIM: usize = DIM;
|
||||||
}
|
}
|
||||||
impl<'a,R, T : Broadcastable, F : Fn(T::Element) -> R ,
|
impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorSize
|
||||||
const DIM: usize> TensorSize for BMap<'a,R,T,F,DIM> {
|
for BMap<'a, R, T, F, DIM>
|
||||||
|
{
|
||||||
fn size(&self) -> [usize;DIM] {self.reference.size()}
|
fn size(&self) -> [usize; DIM] {
|
||||||
|
self.reference.size()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a,R, T : Broadcastable, F : Fn(T::Element) -> R ,
|
impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> Broadcastable
|
||||||
const DIM: usize> Broadcastable for BMap<'a,R,T,F,DIM> {
|
for BMap<'a, R, T, F, DIM>
|
||||||
|
{
|
||||||
type Element = R;
|
type Element = R;
|
||||||
fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
|
fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
|
||||||
self.reference.bget(index).map(&self.closure)
|
self.reference.bget(index).map(&self.closure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> TensorDimension for Vec<T> {
|
impl<T> TensorDimension for Vec<T> {
|
||||||
const DIM : usize = 1;
|
const DIM: usize = 1;
|
||||||
}
|
}
|
||||||
impl<T> TensorSize for Vec<T> {
|
impl<T> TensorSize for Vec<T> {
|
||||||
fn size(&self) -> [usize;1] {[self.len()]}
|
fn size(&self) -> [usize; 1] {
|
||||||
|
[self.len()]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl<T: Clone> Broadcastable for Vec<T> {
|
impl<T: Clone> Broadcastable for Vec<T> {
|
||||||
type Element = T;
|
type Element = T;
|
||||||
fn bget(& self,index : [usize;1]) -> Option<T> {
|
fn bget(&self, index: [usize; 1]) -> Option<T> {
|
||||||
self.get(index[0]).cloned()
|
self.get(index[0]).cloned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let v = vec![1,2,3];
|
let v = vec![1, 2, 3];
|
||||||
let bv = v.lazy_updim([3,4]);
|
let bv = v.lazy_updim([3, 4]);
|
||||||
let bbv = bv.bmap(|x| x*x);
|
let bbv = bv.bmap(|x| x * x);
|
||||||
|
|
||||||
println!("The size of v is {:?}",bbv.bget([0,2]).expect("Out of bounds."));
|
println!("The size of v is {:?}", bbv.bget([0, 2]).expect("Out of bounds."));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
error[E0391]: cycle detected when resolving instance `<LazyUpdim<T, {T::DIM}, DIM> as TensorDimension>::DIM`
|
error[E0391]: cycle detected when resolving instance `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>::DIM`
|
||||||
--> $DIR/issue-83765.rs:5:5
|
--> $DIR/issue-83765.rs:5:5
|
||||||
|
|
|
|
||||||
LL | const DIM : usize;
|
LL | const DIM: usize;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: ...which requires checking if `TensorDimension` fulfills its obligations...
|
note: ...which requires checking if `TensorDimension` fulfills its obligations...
|
||||||
--> $DIR/issue-83765.rs:4:1
|
--> $DIR/issue-83765.rs:4:1
|
||||||
|
|
|
|
||||||
LL | trait TensorDimension {
|
LL | trait TensorDimension {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: ...which again requires resolving instance `<LazyUpdim<T, {T::DIM}, DIM> as TensorDimension>::DIM`, completing the cycle
|
= note: ...which again requires resolving instance `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>::DIM`, completing the cycle
|
||||||
= note: cycle used when normalizing `<LazyUpdim<T, {T::DIM}, DIM> as TensorDimension>::DIM`
|
= note: cycle used when normalizing `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>::DIM`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue