mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-13 12:36:47 +00:00
Add expand_abstract_const
Adds the ability to directly expand a const to an expr without having to deal with intermediate steps.
This commit is contained in:
parent
f9750c1554
commit
5bb1a9febc
@ -193,18 +193,6 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||
ty::PredicateKind::ConstEvaluatable(a),
|
||||
ty::PredicateKind::ConstEvaluatable(b),
|
||||
) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
|
||||
/*
|
||||
) => {
|
||||
if let (Ok(Some(a)), Ok(Some(b))) = (
|
||||
tcx.expand_bound_abstract_const(tcx.bound_abstract_const(a.def), a.substs),
|
||||
tcx.expand_bound_abstract_const(tcx.bound_abstract_const(b.def), b.substs),
|
||||
) && a.ty() == b.ty() {
|
||||
return relator.relate(a, b).is_ok();
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
*/
|
||||
(
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
|
||||
|
@ -1621,15 +1621,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
// variables
|
||||
let tcx = self.tcx;
|
||||
if substs.has_non_region_infer() {
|
||||
let substs_erased = tcx.erase_regions(unevaluated.substs);
|
||||
let ac = tcx.expand_bound_abstract_const(
|
||||
tcx.bound_abstract_const(unevaluated.def),
|
||||
substs_erased,
|
||||
);
|
||||
let ac = tcx.expand_unevaluated_abstract_const(unevaluated.def, unevaluated.substs);
|
||||
match ac {
|
||||
Ok(None) => {
|
||||
substs = InternalSubsts::identity_for_item(tcx, unevaluated.def.did);
|
||||
param_env = self.tcx.param_env(unevaluated.def.did);
|
||||
param_env = tcx.param_env(unevaluated.def.did);
|
||||
}
|
||||
Ok(Some(ct)) => {
|
||||
if ct.has_non_region_infer() || ct.has_non_region_param() {
|
||||
|
@ -1,5 +1,8 @@
|
||||
//! A subset of a mir body used for const evaluatability checking.
|
||||
use crate::ty::{self, Const, EarlyBinder, FallibleTypeFolder, GenericArg, TyCtxt, TypeFoldable};
|
||||
use crate::ty::{
|
||||
self, subst::SubstsRef, Const, EarlyBinder, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable,
|
||||
TypeSuperFoldable, TypeVisitable,
|
||||
};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
||||
@ -33,71 +36,79 @@ pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>,
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Returns a const with substs applied by
|
||||
pub fn bound_abstract_const(
|
||||
self,
|
||||
uv: ty::WithOptConstParam<DefId>,
|
||||
) -> BoundAbstractConst<'tcx> {
|
||||
self.thir_abstract_const_opt_const_arg(uv).map(|ac| ac.map(|ac| EarlyBinder(ac)))
|
||||
}
|
||||
#[inline]
|
||||
pub fn thir_abstract_const_opt_const_arg(
|
||||
self,
|
||||
def: ty::WithOptConstParam<DefId>,
|
||||
) -> Result<Option<ty::Const<'tcx>>, ErrorGuaranteed> {
|
||||
if let Some((did, param_did)) = def.as_const_arg() {
|
||||
fn bound_abstract_const(self, uv: ty::WithOptConstParam<DefId>) -> BoundAbstractConst<'tcx> {
|
||||
let ac = if let Some((did, param_did)) = uv.as_const_arg() {
|
||||
self.thir_abstract_const_of_const_arg((did, param_did))
|
||||
} else {
|
||||
self.thir_abstract_const(def.did)
|
||||
}
|
||||
self.thir_abstract_const(uv.did)
|
||||
};
|
||||
Ok(ac?.map(|ac| EarlyBinder(ac)))
|
||||
}
|
||||
|
||||
pub fn expand_bound_abstract_const(
|
||||
pub fn expand_abstract_consts<T: TypeFoldable<'tcx>>(
|
||||
self,
|
||||
ct: BoundAbstractConst<'tcx>,
|
||||
substs: &[GenericArg<'tcx>],
|
||||
) -> Result<Option<Const<'tcx>>, ErrorGuaranteed> {
|
||||
ac: T,
|
||||
) -> Result<Option<T>, ErrorGuaranteed> {
|
||||
self._expand_abstract_consts(ac, true)
|
||||
}
|
||||
|
||||
pub fn expand_unevaluated_abstract_const(
|
||||
self,
|
||||
did: ty::WithOptConstParam<DefId>,
|
||||
substs: SubstsRef<'tcx>,
|
||||
) -> Result<Option<ty::Const<'tcx>>, ErrorGuaranteed> {
|
||||
let Some(ac) = self.bound_abstract_const(did)? else {
|
||||
return Ok(None);
|
||||
};
|
||||
let substs = self.erase_regions(substs);
|
||||
let ac = ac.subst(self, substs);
|
||||
self._expand_abstract_consts(ac, false)
|
||||
}
|
||||
|
||||
fn _expand_abstract_consts<T: TypeFoldable<'tcx>>(
|
||||
self,
|
||||
ac: T,
|
||||
first: bool,
|
||||
) -> Result<Option<T>, ErrorGuaranteed> {
|
||||
struct Expander<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
first: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> FallibleTypeFolder<'tcx> for Expander<'tcx> {
|
||||
type Error = ErrorGuaranteed;
|
||||
type Error = Option<ErrorGuaranteed>;
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
fn try_fold_const(&mut self, c: Const<'tcx>) -> Result<Const<'tcx>, ErrorGuaranteed> {
|
||||
use ty::ConstKind::*;
|
||||
let uv = match c.kind() {
|
||||
Unevaluated(uv) => uv,
|
||||
Param(..) | Infer(..) | Bound(..) | Placeholder(..) | Value(..) | Error(..) => {
|
||||
return Ok(c);
|
||||
}
|
||||
Expr(e) => {
|
||||
let new_expr = match e {
|
||||
ty::Expr::Binop(op, l, r) => {
|
||||
ty::Expr::Binop(op, l.try_fold_with(self)?, r.try_fold_with(self)?)
|
||||
}
|
||||
ty::Expr::UnOp(op, v) => ty::Expr::UnOp(op, v.try_fold_with(self)?),
|
||||
ty::Expr::Cast(k, c, t) => {
|
||||
ty::Expr::Cast(k, c.try_fold_with(self)?, t.try_fold_with(self)?)
|
||||
}
|
||||
ty::Expr::FunctionCall(func, args) => ty::Expr::FunctionCall(
|
||||
func.try_fold_with(self)?,
|
||||
args.try_fold_with(self)?,
|
||||
),
|
||||
};
|
||||
return Ok(self.tcx().mk_const(ty::ConstKind::Expr(new_expr), c.ty()));
|
||||
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
||||
if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
|
||||
ty.try_super_fold_with(self)
|
||||
} else {
|
||||
Ok(ty)
|
||||
}
|
||||
}
|
||||
fn try_fold_const(&mut self, c: Const<'tcx>) -> Result<Const<'tcx>, Self::Error> {
|
||||
let ct = match c.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
if let Some(bac) = self.tcx.bound_abstract_const(uv.def)? {
|
||||
let substs = self.tcx.erase_regions(uv.substs);
|
||||
bac.subst(self.tcx, substs)
|
||||
} else if self.first {
|
||||
return Err(None);
|
||||
} else {
|
||||
c
|
||||
}
|
||||
}
|
||||
_ => c,
|
||||
};
|
||||
let bac = self.tcx.bound_abstract_const(uv.def);
|
||||
let ac = self.tcx.expand_bound_abstract_const(bac, uv.substs);
|
||||
if let Ok(Some(ac)) = ac { ac.try_fold_with(self) } else { Ok(c) }
|
||||
self.first = false;
|
||||
ct.try_super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
let Some(ac) = ct? else {
|
||||
return Ok(None);
|
||||
};
|
||||
let ac = ac.subst(self, substs);
|
||||
Ok(Some(ac.try_fold_with(&mut Expander { tcx: self })?))
|
||||
match ac.try_fold_with(&mut Expander { tcx: self, first }) {
|
||||
Ok(c) => Ok(Some(c)),
|
||||
Err(None) => Ok(None),
|
||||
Err(Some(e)) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -626,7 +626,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
|
||||
// an unnormalized (i.e. unevaluated) const in the param-env.
|
||||
// FIXME(generic_const_exprs): Once we always lazily unify unevaluated constants
|
||||
// these `eval` calls can be removed.
|
||||
if !relation.tcx().features().generic_const_exprs {
|
||||
if !tcx.features().generic_const_exprs {
|
||||
a = a.eval(tcx, relation.param_env());
|
||||
b = b.eval(tcx, relation.param_env());
|
||||
}
|
||||
@ -647,12 +647,12 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
|
||||
(ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
|
||||
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
|
||||
|
||||
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
|
||||
(ty::ConstKind::Unevaluated(_au), ty::ConstKind::Unevaluated(_bu))
|
||||
if tcx.features().generic_const_exprs =>
|
||||
{
|
||||
if let (Ok(Some(a)), Ok(Some(b))) = (
|
||||
tcx.expand_bound_abstract_const(tcx.bound_abstract_const(au.def), au.substs),
|
||||
tcx.expand_bound_abstract_const(tcx.bound_abstract_const(bu.def), bu.substs),
|
||||
tcx.expand_abstract_consts(a),
|
||||
tcx.expand_abstract_consts(b),
|
||||
) && a.ty() == b.ty() {
|
||||
return relation.consts(a, b);
|
||||
} else {
|
||||
|
@ -287,12 +287,8 @@ where
|
||||
self.visit_ty(c.ty())?;
|
||||
let tcx = self.def_id_visitor.tcx();
|
||||
if let ty::ConstKind::Unevaluated(uv) = c.kind() &&
|
||||
let Ok(Some(ct)) = tcx.expand_bound_abstract_const(tcx.bound_abstract_const(uv.def),
|
||||
uv.substs) {
|
||||
ct.visit_with(self)?;
|
||||
}
|
||||
if let ty::ConstKind::Expr(e) = c.kind() {
|
||||
e.visit_with(self)?;
|
||||
let Ok(Some(ct)) = tcx.expand_unevaluated_abstract_const(uv.def, uv.substs) {
|
||||
ct.super_visit_with(self)?;
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
|
@ -29,8 +29,7 @@ pub fn is_const_evaluatable<'tcx>(
|
||||
let tcx = infcx.tcx;
|
||||
let uv = match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => uv,
|
||||
// should be recursivee fixes.
|
||||
ty::ConstKind::Expr(..) => todo!(),
|
||||
ty::ConstKind::Expr(_) => bug!("unexpected expr in `is_const_evaluatable: {ct:?}"),
|
||||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Bound(_, _)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
@ -40,10 +39,7 @@ pub fn is_const_evaluatable<'tcx>(
|
||||
};
|
||||
|
||||
if tcx.features().generic_const_exprs {
|
||||
let substs = tcx.erase_regions(uv.substs);
|
||||
if let Some(ct) =
|
||||
tcx.expand_bound_abstract_const(tcx.bound_abstract_const(uv.def), substs)?
|
||||
{
|
||||
if let Some(ct) = tcx.expand_abstract_consts(ct)? {
|
||||
if satisfied_from_param_env(tcx, infcx, ct, param_env)? {
|
||||
return Ok(());
|
||||
}
|
||||
@ -74,17 +70,13 @@ pub fn is_const_evaluatable<'tcx>(
|
||||
//
|
||||
// See #74595 for more details about this.
|
||||
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
|
||||
|
||||
let substs = tcx.erase_regions(uv.substs);
|
||||
match concrete {
|
||||
// If we're evaluating a foreign constant, under a nightly compiler without generic
|
||||
// const exprs, AND it would've passed if that expression had been evaluated with
|
||||
// generic const exprs, then suggest using generic const exprs.
|
||||
// If we're evaluating a generic foreign constant, under a nightly compiler while
|
||||
// the current crate does not enable `feature(generic_const_exprs)`, abort
|
||||
// compilation with a useful error.
|
||||
Err(_) if tcx.sess.is_nightly_build()
|
||||
&& let Ok(Some(ct)) =
|
||||
tcx.expand_bound_abstract_const(tcx.bound_abstract_const(uv.def), substs)
|
||||
&& let ty::ConstKind::Expr(_expr) = ct.kind()
|
||||
&& satisfied_from_param_env(tcx, infcx, ct, param_env) == Ok(true) => {
|
||||
&& let Ok(Some(ac)) = tcx.expand_abstract_consts(ct)
|
||||
&& let ty::ConstKind::Expr(_) = ac.kind() => {
|
||||
tcx.sess
|
||||
.struct_span_fatal(
|
||||
// Slightly better span than just using `span` alone
|
||||
@ -126,46 +118,43 @@ fn satisfied_from_param_env<'tcx>(
|
||||
ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Result<bool, NotConstEvaluatable> {
|
||||
// Try to unify with each subtree in the AbstractConst to allow for
|
||||
// `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
|
||||
// predicate for `(N + 1) * 2`
|
||||
struct Visitor<'a, 'tcx> {
|
||||
ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
}
|
||||
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
||||
type BreakTy = ();
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if c.ty() == self.ct.ty()
|
||||
&& let Ok(_nested_obligations) = self
|
||||
.infcx
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.eq(c, self.ct)
|
||||
{
|
||||
ControlFlow::BREAK
|
||||
} else if let ty::ConstKind::Expr(e) = c.kind() {
|
||||
e.visit_with(self)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for pred in param_env.caller_bounds() {
|
||||
match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::ConstEvaluatable(uv) => {
|
||||
let ty::ConstKind::Unevaluated(uv) = uv.kind() else {
|
||||
ty::PredicateKind::ConstEvaluatable(ce) => {
|
||||
let ty::ConstKind::Unevaluated(_) = ce.kind() else {
|
||||
continue
|
||||
};
|
||||
let substs = tcx.erase_regions(uv.substs);
|
||||
let Some(b_ct) =
|
||||
tcx.expand_bound_abstract_const(tcx.bound_abstract_const(uv.def), substs)? else {
|
||||
return Ok(false);
|
||||
let Some(b_ct) = tcx.expand_abstract_consts(ce)? else {
|
||||
continue
|
||||
};
|
||||
|
||||
// Try to unify with each subtree in the AbstractConst to allow for
|
||||
// `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
|
||||
// predicate for `(N + 1) * 2`
|
||||
struct Visitor<'a, 'tcx> {
|
||||
ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
}
|
||||
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
||||
type BreakTy = ();
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if c.ty() == self.ct.ty()
|
||||
&& let Ok(_nested_obligations) = self
|
||||
.infcx
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.eq(c, self.ct)
|
||||
{
|
||||
//let obligations = nested_obligations.into_obligations();
|
||||
ControlFlow::BREAK
|
||||
} else if let ty::ConstKind::Expr(e) = c.kind() {
|
||||
e.visit_with(self)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut v = Visitor { ct, infcx, param_env };
|
||||
let result = b_ct.visit_with(&mut v);
|
||||
|
||||
|
@ -478,14 +478,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
if let (Ok(Some(a)), Ok(Some(b))) = (
|
||||
tcx.expand_bound_abstract_const(
|
||||
tcx.bound_abstract_const(a.def),
|
||||
a.substs,
|
||||
),
|
||||
tcx.expand_bound_abstract_const(
|
||||
tcx.bound_abstract_const(b.def),
|
||||
b.substs,
|
||||
),
|
||||
tcx.expand_abstract_consts(c1),
|
||||
tcx.expand_abstract_consts(c2),
|
||||
) && a.ty() == b.ty() &&
|
||||
let Ok(new_obligations) = infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
@ -534,7 +528,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(c1, c2)
|
||||
{
|
||||
Ok(_) => ProcessResult::Changed(vec![]),
|
||||
Ok(inf_ok) => {
|
||||
ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
|
||||
}
|
||||
Err(err) => ProcessResult::Error(
|
||||
FulfillmentErrorCode::CodeConstEquateError(
|
||||
ExpectedFound::new(true, c1, c2),
|
||||
|
@ -849,11 +849,8 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
|
||||
//
|
||||
// This shouldn't really matter though as we can't really use any
|
||||
// constants which are not considered const evaluatable.
|
||||
if let ty::ConstKind::Unevaluated(uv) = ct.kind() &&
|
||||
let Ok(Some(ct)) = self
|
||||
.tcx
|
||||
.expand_bound_abstract_const(self.tcx.bound_abstract_const(uv.def), uv.substs)
|
||||
{
|
||||
if let ty::ConstKind::Unevaluated(_uv) = ct.kind() &&
|
||||
let Ok(Some(ct)) = self.tcx.expand_abstract_consts(ct){
|
||||
self.visit_const(ct)
|
||||
} else {
|
||||
ct.super_visit_with(self)
|
||||
|
@ -668,19 +668,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// if the constants depend on generic parameters.
|
||||
//
|
||||
// Let's just see where this breaks :shrug:
|
||||
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
|
||||
if let (ty::ConstKind::Unevaluated(_), ty::ConstKind::Unevaluated(_)) =
|
||||
(c1.kind(), c2.kind())
|
||||
{
|
||||
if let (Ok(Some(a)), Ok(Some(b))) = (
|
||||
tcx.expand_bound_abstract_const(
|
||||
tcx.bound_abstract_const(a.def),
|
||||
a.substs,
|
||||
),
|
||||
tcx.expand_bound_abstract_const(
|
||||
tcx.bound_abstract_const(b.def),
|
||||
b.substs,
|
||||
),
|
||||
) && a.ty() == b.ty() && let Ok(new_obligations) =
|
||||
tcx.expand_abstract_consts(c1),
|
||||
tcx.expand_abstract_consts(c2),
|
||||
) && a.ty() == b.ty() && let Ok(new_obligations) =
|
||||
self.infcx.at(&obligation.cause, obligation.param_env).eq(a, b)
|
||||
{
|
||||
let mut obligations = new_obligations.obligations;
|
||||
@ -718,7 +712,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(c1, c2)
|
||||
{
|
||||
Ok(_) => Ok(EvaluatedToOk),
|
||||
Ok(inf_ok) => self.evaluate_predicates_recursively(
|
||||
previous_stack,
|
||||
inf_ok.into_obligations(),
|
||||
),
|
||||
Err(_) => Ok(EvaluatedToErr),
|
||||
}
|
||||
}
|
||||
|
@ -120,8 +120,6 @@ fn main() {
|
||||
let v = vec![1, 2, 3];
|
||||
let bv = v.lazy_updim([3, 4]);
|
||||
let bbv = bv.bmap(|x| x * x);
|
||||
//~^ ERROR mismatched types
|
||||
|
||||
println!("The size of v is {:?}", bbv.bget([0, 2]).expect("Out of bounds."));
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
@ -98,25 +98,7 @@ LL | self.reference.bget(index).map(&self.closure)
|
||||
= note: expected constant `Self::DIM`
|
||||
found constant `DIM`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-83765.rs:122:15
|
||||
|
|
||||
LL | let bbv = bv.bmap(|x| x * x);
|
||||
| ^^^^^^^^^^^^^^^^^^ expected `<LazyUpdim<'_, Vec<{integer}>, { Self::DIM }, 2> as TensorDimension>::DIM`, found `<LazyUpdim<'_, Vec<{integer}>, { Self::DIM }, 2> as TensorDimension>::DIM`
|
||||
|
|
||||
= note: expected constant `<LazyUpdim<'_, Vec<{integer}>, { Self::DIM }, 2> as TensorDimension>::DIM`
|
||||
found constant `<LazyUpdim<'_, Vec<{integer}>, { Self::DIM }, 2> as TensorDimension>::DIM`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-83765.rs:125:43
|
||||
|
|
||||
LL | println!("The size of v is {:?}", bbv.bget([0, 2]).expect("Out of bounds."));
|
||||
| ^^^^ expected `<LazyUpdim<'_, Vec<{integer}>, { Self::DIM }, 2> as TensorDimension>::DIM`, found `<LazyUpdim<'_, Vec<{integer}>, { Self::DIM }, 2> as TensorDimension>::DIM`
|
||||
|
|
||||
= note: expected constant `<LazyUpdim<'_, Vec<{integer}>, { Self::DIM }, 2> as TensorDimension>::DIM`
|
||||
found constant `<LazyUpdim<'_, Vec<{integer}>, { Self::DIM }, 2> as TensorDimension>::DIM`
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0308.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
Loading…
Reference in New Issue
Block a user