Rollup merge of #95179 - b-naber:eval-in-try-unify, r=lcnr

Try to evaluate in try unify and postpone resolution of constants that contain inference variables

We want code like that in [`ui/const-generics/generic_const_exprs/eval-try-unify.rs`](https://github.com/rust-lang/rust/compare/master...b-naber:eval-in-try-unify?expand=1#diff-8027038201cf07a6c96abf3cbf0b0f4fdd8a64ce6292435f01c8ed995b87fe9b) to compile. To do that we need to try to evaluate constants in `try_unify_abstract_consts`, this requires us to be more careful about what constants we try to resolve, specifically we cannot try to resolve constants that still contain inference variables.

r? `@lcnr`
This commit is contained in:
Dylan DPC 2022-03-25 01:34:30 +01:00 committed by GitHub
commit 1fcb8fc3e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 283 additions and 287 deletions

View File

@ -20,8 +20,7 @@
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::mir::interpret::EvalToConstValueResult;
use rustc_middle::mir::interpret::{ErrorHandled, EvalToConstValueResult};
use rustc_middle::traits::select;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
@ -71,7 +70,6 @@
pub mod type_variable;
mod undo_log;
use crate::infer::canonical::OriginalQueryValues;
pub use rustc_middle::infer::unify_key;
#[must_use]
@ -687,15 +685,28 @@ pub struct CombinedSnapshot<'a, 'tcx> {
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// calls `tcx.try_unify_abstract_consts` after
/// canonicalizing the consts.
#[instrument(skip(self), level = "debug")]
pub fn try_unify_abstract_consts(
&self,
a: ty::Unevaluated<'tcx, ()>,
b: ty::Unevaluated<'tcx, ()>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
let canonical = self.canonicalize_query((a, b), &mut OriginalQueryValues::default());
debug!("canonical consts: {:?}", &canonical.value);
// Reject any attempt to unify two unevaluated constants that contain inference
// variables, since inference variables in queries lead to ICEs.
if a.substs.has_infer_types_or_consts()
|| b.substs.has_infer_types_or_consts()
|| param_env.has_infer_types_or_consts()
{
debug!("a or b or param_env contain infer vars in its substs -> cannot unify");
return false;
}
self.tcx.try_unify_abstract_consts(canonical.value)
let param_env_and = param_env.and((a, b));
let erased = self.tcx.erase_regions(param_env_and);
debug!("after erase_regions: {:?}", erased);
self.tcx.try_unify_abstract_consts(erased)
}
pub fn is_in_snapshot(&self) -> bool {
@ -1598,6 +1609,7 @@ pub fn create_next_universe(&self) -> ty::UniverseIndex {
///
/// This handles inferences variables within both `param_env` and `substs` by
/// performing the operation on their respective canonical forms.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
@ -1605,15 +1617,19 @@ pub fn const_eval_resolve(
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
let substs = self.resolve_vars_if_possible(unevaluated.substs);
debug!(?substs);
// Postpone the evaluation of constants whose substs depend on inference
// variables
if substs.has_infer_types_or_consts() {
debug!("substs have infer types or consts: {:?}", substs);
return Err(ErrorHandled::TooGeneric);
}
let param_env_erased = self.tcx.erase_regions(param_env);
let substs_erased = self.tcx.erase_regions(substs);
debug!(?param_env_erased);
debug!(?substs_erased);
let unevaluated = ty::Unevaluated {
def: unevaluated.def,

View File

@ -1,6 +1,7 @@
use super::{ErrorHandled, EvalToConstValueResult, GlobalId};
use crate::mir;
use crate::ty::fold::TypeFoldable;
use crate::ty::subst::InternalSubsts;
use crate::ty::{self, TyCtxt};
use rustc_hir::def_id::DefId;
@ -38,6 +39,16 @@ pub fn const_eval_resolve(
ct: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
// Cannot resolve `Unevaluated` constants that contain inference
// variables. We reject those here since `resolve_opt_const_arg`
// would fail otherwise.
//
// When trying to evaluate constants containing inference variables,
// use `Infcx::const_eval_resolve` instead.
if ct.substs.has_infer_types_or_consts() {
bug!("did not expect inference variables here");
}
match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: ct.promoted };

View File

@ -331,12 +331,12 @@
}
}
query try_unify_abstract_consts(key: (
ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>
)) -> bool {
query try_unify_abstract_consts(key:
ty::ParamEnvAnd<'tcx, (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>
)>) -> bool {
desc {
|tcx| "trying to unify the generic constants {} and {}",
tcx.def_path_str(key.0.def.did), tcx.def_path_str(key.1.def.did)
tcx.def_path_str(key.value.0.def.did), tcx.def_path_str(key.value.1.def.did)
}
}

View File

@ -585,7 +585,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
if tcx.features().generic_const_exprs =>
{
tcx.try_unify_abstract_consts((au.shrink(), bu.shrink()))
tcx.try_unify_abstract_consts(relation.param_env().and((au.shrink(), bu.shrink())))
}
// While this is slightly incorrect, it shouldn't matter for `min_const_generics`

View File

@ -188,6 +188,7 @@ enum FailureKind {
}
}
#[instrument(skip(tcx), level = "debug")]
fn satisfied_from_param_env<'tcx>(
tcx: TyCtxt<'tcx>,
ct: AbstractConst<'tcx>,
@ -197,14 +198,17 @@ fn satisfied_from_param_env<'tcx>(
match pred.kind().skip_binder() {
ty::PredicateKind::ConstEvaluatable(uv) => {
if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
// 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`
let result =
walk_abstract_const(tcx, b_ct, |b_ct| match try_unify(tcx, ct, b_ct) {
let result = walk_abstract_const(tcx, b_ct, |b_ct| {
match const_unify_ctxt.try_unify(ct, b_ct) {
true => ControlFlow::BREAK,
false => ControlFlow::CONTINUE,
});
}
});
if let ControlFlow::Break(()) = result {
debug!("is_const_evaluatable: abstract_const ~~> ok");
@ -637,11 +641,13 @@ pub(super) fn thir_abstract_const<'tcx>(
pub(super) fn try_unify_abstract_consts<'tcx>(
tcx: TyCtxt<'tcx>,
(a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
param_env: ty::ParamEnv<'tcx>,
) -> bool {
(|| {
if let Some(a) = AbstractConst::new(tcx, a)? {
if let Some(b) = AbstractConst::new(tcx, b)? {
return Ok(try_unify(tcx, a, b));
let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
return Ok(const_unify_ctxt.try_unify(a, b));
}
}
@ -689,88 +695,115 @@ fn recurse<'tcx, R>(
recurse(tcx, ct, &mut f)
}
/// Tries to unify two abstract constants using structural equality.
pub(super) fn try_unify<'tcx>(
struct ConstUnifyCtxt<'tcx> {
tcx: TyCtxt<'tcx>,
mut a: AbstractConst<'tcx>,
mut b: AbstractConst<'tcx>,
) -> bool {
// We substitute generics repeatedly to allow AbstractConsts to unify where a
param_env: ty::ParamEnv<'tcx>,
}
impl<'tcx> ConstUnifyCtxt<'tcx> {
// Substitutes generics repeatedly to allow AbstractConsts to unify where a
// 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)])])]
while let Node::Leaf(a_ct) = a.root(tcx) {
match AbstractConst::from_const(tcx, a_ct) {
Ok(Some(a_act)) => a = a_act,
Ok(None) => break,
Err(_) => return true,
}
}
while let Node::Leaf(b_ct) = b.root(tcx) {
match AbstractConst::from_const(tcx, b_ct) {
Ok(Some(b_act)) => b = b_act,
Ok(None) => break,
Err(_) => return true,
}
}
match (a.root(tcx), b.root(tcx)) {
(Node::Leaf(a_ct), Node::Leaf(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,
#[inline]
#[instrument(skip(self), level = "debug")]
fn try_replace_substs_in_root(
&self,
mut abstr_const: AbstractConst<'tcx>,
) -> Option<AbstractConst<'tcx>> {
while let Node::Leaf(ct) = abstr_const.root(self.tcx) {
match AbstractConst::from_const(self.tcx, ct) {
Ok(Some(act)) => abstr_const = act,
Ok(None) => break,
Err(_) => return None,
}
}
(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))
&& try_unify(tcx, a.subtree(ar), b.subtree(br))
Some(abstr_const)
}
/// Tries to unify two abstract constants using structural equality.
#[instrument(skip(self), level = "debug")]
fn try_unify(&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(a.subtree(al), b.subtree(bl))
&& self.try_unify(a.subtree(ar), b.subtree(br))
}
(Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
self.try_unify(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(a.subtree(a_f), b.subtree(b_f))
&& iter::zip(a_args, b_args)
.all(|(&an, &bn)| self.try_unify(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(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))
}
(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))
&& iter::zip(a_args, b_args)
.all(|(&an, &bn)| try_unify(tcx, 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) =>
{
try_unify(tcx, 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,
}
}

View File

@ -580,7 +580,11 @@ fn process_changed_obligations(
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
(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![]);
}
}

View File

@ -862,7 +862,10 @@ pub fn provide(providers: &mut ty::query::Providers) {
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
};
}

View File

@ -639,7 +639,11 @@ fn evaluate_predicate_recursively<'o>(
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
(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);
}
}

View File

@ -243,7 +243,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
(
ty::PredicateKind::ConstEvaluatable(a),
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_b, lt_b)),

View File

@ -0,0 +1,26 @@
// build-pass
#![feature(generic_const_exprs)]
//~^ WARNING the feature `generic_const_exprs` is incomplete
trait Generic {
const ASSOC: usize;
}
impl Generic for u8 {
const ASSOC: usize = 17;
}
impl Generic for u16 {
const ASSOC: usize = 13;
}
fn uses_assoc_type<T: Generic, const N: usize>() -> [u8; N + T::ASSOC] {
[0; N + T::ASSOC]
}
fn only_generic_n<const N: usize>() -> [u8; N + 13] {
uses_assoc_type::<u16, N>()
}
fn main() {}

View File

@ -0,0 +1,11 @@
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/eval-try-unify.rs:3:12
|
LL | #![feature(generic_const_exprs)]
| ^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
warning: 1 warning emitted

View File

@ -2,114 +2,115 @@
#![allow(incomplete_features)]
trait TensorDimension {
const DIM : usize;
const ISSCALAR : bool = Self::DIM == 0;
fn is_scalar(&self) -> bool {Self::ISSCALAR}
}
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)
const DIM: usize;
//~^ ERROR cycle detected when resolving instance
// FIXME Given the current state of the compiler its expected that we cycle here,
// but the cycle is still wrong.
const ISSCALAR: bool = Self::DIM == 0;
fn is_scalar(&self) -> bool {
Self::ISSCALAR
}
}
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 {
type Element;
fn bget(&self, index:[usize;Self::DIM]) -> Option<Self::Element>;
fn lazy_updim<const NEWDIM : usize>(&self, size : [usize;NEWDIM] ) ->
LazyUpdim<Self,{Self::DIM},NEWDIM>
{
assert!(NEWDIM >= Self::DIM,
"Updimmed tensor cannot have fewer indices than the initial one.");
LazyUpdim {size,reference:&self}
fn bget(&self, index: [usize; Self::DIM]) -> Option<Self::Element>;
fn lazy_updim<const NEWDIM: usize>(
&self,
size: [usize; NEWDIM],
) -> LazyUpdim<Self, { Self::DIM }, NEWDIM> {
assert!(
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}>{
BMap {reference:self,closure : foo}
fn bmap<T, F: Fn(Self::Element) -> T>(&self, foo: F) -> BMap<T, Self, F, { Self::DIM }> {
BMap { reference: self, closure: foo }
}
}
struct LazyUpdim<'a,T : Broadcastable,const OLDDIM : usize, const DIM : usize> {
size : [usize;DIM],
reference : &'a T
struct LazyUpdim<'a, T: Broadcastable, const OLDDIM: usize, const DIM: usize> {
size: [usize; DIM],
reference: &'a T,
}
impl<'a,T : Broadcastable,const DIM : usize> TensorDimension for LazyUpdim<'a,T,{T::DIM},DIM> {
const DIM : usize = DIM;
impl<'a, T: Broadcastable, const DIM: usize> TensorDimension for LazyUpdim<'a, T, { T::DIM }, DIM> {
const DIM: usize = DIM;
}
impl<'a,T : Broadcastable,const DIM : usize> TensorSize for LazyUpdim<'a,T,{T::DIM},DIM> {
fn size(&self) -> [usize;DIM] {self.size}
//~^ ERROR method not compatible with trait
impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T::DIM }, DIM> {
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;
fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
//~^ ERROR method not compatible with trait
fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
assert!(DIM >= T::DIM);
if !self.inbounds(index) {return None}
//~^ ERROR unconstrained generic constant
//~| ERROR mismatched types
if !self.inbounds(index) {
return None;
}
let size = self.size();
//~^ ERROR unconstrained generic constant
let newindex : [usize;T::DIM] = Default::default();
//~^ ERROR the trait bound `[usize; _]: Default` is not satisfied
let newindex: [usize; T::DIM] = Default::default();
self.reference.bget(newindex)
}
}
struct BMap<'a,R, T : Broadcastable, F : Fn(T::Element) -> R , const DIM: usize> {
reference : &'a T,
closure : F
struct BMap<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> {
reference: &'a T,
closure: F,
}
impl<'a,R, T : Broadcastable, F : Fn(T::Element) -> R,
const DIM: usize> TensorDimension for BMap<'a,R,T,F,DIM> {
const DIM : usize = DIM;
impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorDimension
for BMap<'a, R, T, F, DIM>
{
const DIM: usize = DIM;
}
impl<'a,R, T : Broadcastable, F : Fn(T::Element) -> R ,
const DIM: usize> TensorSize for BMap<'a,R,T,F,DIM> {
fn size(&self) -> [usize;DIM] {self.reference.size()}
//~^ ERROR unconstrained generic constant
//~| ERROR mismatched types
//~| ERROR method not compatible with trait
impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorSize
for BMap<'a, R, T, F, DIM>
{
fn size(&self) -> [usize; DIM] {
self.reference.size()
}
}
impl<'a,R, T : Broadcastable, F : Fn(T::Element) -> R ,
const DIM: usize> Broadcastable for BMap<'a,R,T,F,DIM> {
impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> Broadcastable
for BMap<'a, R, T, F, DIM>
{
type Element = R;
fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
//~^ ERROR method not compatible with trait
fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
self.reference.bget(index).map(&self.closure)
//~^ ERROR unconstrained generic constant
//~| ERROR mismatched types
}
}
impl<T> TensorDimension for Vec<T> {
const DIM : usize = 1;
const DIM: usize = 1;
}
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> {
type Element = T;
fn bget(& self,index : [usize;1]) -> Option<T> {
fn bget(&self, index: [usize; 1]) -> Option<T> {
self.get(index[0]).cloned()
}
}
fn main() {
let v = vec![1,2,3];
let bv = v.lazy_updim([3,4]);
let bbv = bv.bmap(|x| x*x);
let v = vec![1, 2, 3];
let bv = v.lazy_updim([3, 4]);
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."));
}

View File

@ -1,130 +1,17 @@
error[E0308]: method not compatible with trait
--> $DIR/issue-83765.rs:44:5
error[E0391]: cycle detected when resolving instance `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>::DIM`
--> $DIR/issue-83765.rs:5:5
|
LL | fn size(&self) -> [usize;DIM] {self.size}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
LL | const DIM: usize;
| ^^^^^^^^^^^^^^^^^
|
= note: expected type `Self::DIM`
found type `DIM`
note: ...which requires checking if `TensorDimension` fulfills its obligations...
--> $DIR/issue-83765.rs:4:1
|
LL | trait TensorDimension {
| ^^^^^^^^^^^^^^^^^^^^^
= 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`
error[E0308]: method not compatible with trait
--> $DIR/issue-83765.rs:51:5
|
LL | fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
|
= note: expected type `Self::DIM`
found type `DIM`
error: aborting due to previous error
error[E0308]: method not compatible with trait
--> $DIR/issue-83765.rs:78:5
|
LL | fn size(&self) -> [usize;DIM] {self.reference.size()}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
|
= note: expected type `Self::DIM`
found type `DIM`
error[E0308]: method not compatible with trait
--> $DIR/issue-83765.rs:88:5
|
LL | fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
|
= note: expected type `Self::DIM`
found type `DIM`
error: unconstrained generic constant
--> $DIR/issue-83765.rs:54:18
|
LL | if !self.inbounds(index) {return None}
| ^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
note: required by a bound in `TensorSize::inbounds`
--> $DIR/issue-83765.rs:12:38
|
LL | fn inbounds(&self,index : [usize;Self::DIM]) -> bool {
| ^^^^^^^^^ required by this bound in `TensorSize::inbounds`
error[E0308]: mismatched types
--> $DIR/issue-83765.rs:54:27
|
LL | if !self.inbounds(index) {return None}
| ^^^^^ expected `Self::DIM`, found `DIM`
|
= note: expected type `Self::DIM`
found type `DIM`
error: unconstrained generic constant
--> $DIR/issue-83765.rs:57:25
|
LL | let size = self.size();
| ^^^^
|
= help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
note: required by a bound in `TensorSize::size`
--> $DIR/issue-83765.rs:11:30
|
LL | fn size(&self) -> [usize;Self::DIM];
| ^^^^^^^^^ required by this bound in `TensorSize::size`
error[E0277]: the trait bound `[usize; _]: Default` is not satisfied
--> $DIR/issue-83765.rs:59:41
|
LL | let newindex : [usize;T::DIM] = Default::default();
| ^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[usize; _]`
|
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
LL | impl<'a,T : Broadcastable,const DIM : usize> Broadcastable for LazyUpdim<'a,T,{T::DIM},DIM> where [usize; _]: Default
| +++++++++++++++++++++++++
error: unconstrained generic constant
--> $DIR/issue-83765.rs:78:51
|
LL | fn size(&self) -> [usize;DIM] {self.reference.size()}
| ^^^^
|
= help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
note: required by a bound in `TensorSize::size`
--> $DIR/issue-83765.rs:11:30
|
LL | fn size(&self) -> [usize;Self::DIM];
| ^^^^^^^^^ required by this bound in `TensorSize::size`
error[E0308]: mismatched types
--> $DIR/issue-83765.rs:78:36
|
LL | fn size(&self) -> [usize;DIM] {self.reference.size()}
| ^^^^^^^^^^^^^^^^^^^^^ expected `DIM`, found `Self::DIM`
|
= note: expected type `DIM`
found type `Self::DIM`
error: unconstrained generic constant
--> $DIR/issue-83765.rs:90:24
|
LL | self.reference.bget(index).map(&self.closure)
| ^^^^
|
= help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
note: required by a bound in `Broadcastable::bget`
--> $DIR/issue-83765.rs:20:33
|
LL | fn bget(&self, index:[usize;Self::DIM]) -> Option<Self::Element>;
| ^^^^^^^^^ required by this bound in `Broadcastable::bget`
error[E0308]: mismatched types
--> $DIR/issue-83765.rs:90:29
|
LL | self.reference.bget(index).map(&self.closure)
| ^^^^^ expected `Self::DIM`, found `DIM`
|
= note: expected type `Self::DIM`
found type `DIM`
error: aborting due to 12 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0391`.