fix previous failures and address review

This commit is contained in:
b-naber 2022-03-22 10:38:46 +01:00
parent 6cf3409e16
commit 8ff1edbe5e
9 changed files with 212 additions and 174 deletions

View file

@ -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,9 +1618,11 @@ 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);
if substs.has_infer_types_or_consts() {
return Err(ErrorHandled::TooGeneric); return Err(ErrorHandled::TooGeneric);
} }
}
let param_env_erased = self.tcx.erase_regions(param_env); let param_env_erased = self.tcx.erase_regions(param_env);
let substs_erased = self.tcx.erase_regions(substs); let substs_erased = self.tcx.erase_regions(substs);

View file

@ -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) {

View file

@ -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,17 +634,27 @@ where
recurse(tcx, ct, &mut f) recurse(tcx, ct, &mut f)
} }
pub(super) struct ConstUnifyCtxt<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
impl<'tcx> ConstUnifyCtxt<'tcx> {
pub(super) fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
ConstUnifyCtxt { tcx, param_env }
}
// Substitutes generics repeatedly to allow AbstractConsts to unify where a // Substitutes generics repeatedly to allow AbstractConsts to unify where a
// ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g. // 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)])])] // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
#[inline] #[inline]
#[instrument(skip(tcx), level = "debug")] #[instrument(skip(self), level = "debug")]
fn try_replace_substs_in_root<'tcx>( pub(super) fn try_replace_substs_in_root(
tcx: TyCtxt<'tcx>, &self,
mut abstr_const: AbstractConst<'tcx>, mut abstr_const: AbstractConst<'tcx>,
) -> Option<AbstractConst<'tcx>> { ) -> Option<AbstractConst<'tcx>> {
while let Node::Leaf(ct) = abstr_const.root(tcx) { while let Node::Leaf(ct) = abstr_const.root(self.tcx) {
match AbstractConst::from_const(tcx, ct) { match AbstractConst::from_const(self.tcx, ct) {
Ok(Some(act)) => abstr_const = act, Ok(Some(act)) => abstr_const = act,
Ok(None) => break, Ok(None) => break,
Err(_) => return None, Err(_) => return None,
@ -643,36 +665,29 @@ fn try_replace_substs_in_root<'tcx>(
} }
/// Tries to unify two abstract constants using structural equality. /// Tries to unify two abstract constants using structural equality.
#[instrument(skip(tcx), level = "debug")] #[instrument(skip(self), level = "debug")]
pub(super) fn try_unify<'tcx>( fn try_unify_inner(&self, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool {
tcx: TyCtxt<'tcx>, let a = if let Some(a) = self.try_replace_substs_in_root(a) {
a: AbstractConst<'tcx>, a
b: AbstractConst<'tcx>, } else {
param_env: ty::ParamEnv<'tcx>,
) -> bool {
let a = match try_replace_substs_in_root(tcx, a) {
Some(a) => a,
None => {
return true; return true;
}
}; };
let b = match try_replace_substs_in_root(tcx, b) { let b = if let Some(b) = self.try_replace_substs_in_root(b) {
Some(b) => b, b
None => { } else {
return true; return true;
}
}; };
let a_root = a.root(tcx); let a_root = a.root(self.tcx);
let b_root = b.root(tcx); let b_root = b.root(self.tcx);
debug!(?a_root, ?b_root); debug!(?a_root, ?b_root);
match (a_root, b_root) { match (a_root, b_root) {
(Node::Leaf(a_ct), Node::Leaf(b_ct)) => { (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
let a_ct = a_ct.eval(tcx, param_env); let a_ct = a_ct.eval(self.tcx, self.param_env);
debug!("a_ct evaluated: {:?}", a_ct); debug!("a_ct evaluated: {:?}", a_ct);
let b_ct = b_ct.eval(tcx, param_env); let b_ct = b_ct.eval(self.tcx, self.param_env);
debug!("b_ct evaluated: {:?}", b_ct); debug!("b_ct evaluated: {:?}", b_ct);
if a_ct.ty() != b_ct.ty() { if a_ct.ty() != b_ct.ty() {
@ -708,23 +723,23 @@ pub(super) fn try_unify<'tcx>(
} }
} }
(Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => { (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) self.try_unify_inner(a.subtree(al), b.subtree(bl))
&& try_unify(tcx, a.subtree(ar), b.subtree(br), param_env) && 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 => { (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) self.try_unify_inner(a.subtree(av), b.subtree(bv))
} }
(Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args)) (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
if a_args.len() == b_args.len() => if a_args.len() == b_args.len() =>
{ {
try_unify(tcx, a.subtree(a_f), b.subtree(b_f), param_env) self.try_unify_inner(a.subtree(a_f), b.subtree(b_f))
&& iter::zip(a_args, b_args) && iter::zip(a_args, b_args)
.all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn), param_env)) .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)) (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) => if (a_ty == b_ty) && (a_kind == b_kind) =>
{ {
try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand), param_env) 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 // use this over `_ => false` to make adding variants to `Node` less error prone
(Node::Cast(..), _) (Node::Cast(..), _)
@ -734,3 +749,4 @@ pub(super) fn try_unify<'tcx>(
| (Node::Leaf(..), _) => false, | (Node::Leaf(..), _) => false,
} }
} }
}

View file

@ -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![]);
} }
} }

View file

@ -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
}; };
} }

View file

@ -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);
} }
} }

View file

@ -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)),

View file

@ -3,9 +3,13 @@
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
// 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; const ISSCALAR: bool = Self::DIM == 0;
fn is_scalar(&self) -> bool {Self::ISSCALAR} fn is_scalar(&self) -> bool {
Self::ISSCALAR
}
} }
trait TensorSize: TensorDimension { trait TensorSize: TensorDimension {
@ -15,15 +19,17 @@ trait TensorSize : TensorDimension {
} }
} }
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!(
NEWDIM >= Self::DIM,
"Updimmed tensor cannot have fewer indices than the initial one."
);
LazyUpdim { size, reference: &self } 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 }> {
@ -31,10 +37,9 @@ trait Broadcastable: TensorSize + Sized {
} }
} }
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> {
@ -42,15 +47,18 @@ impl<'a,T : Broadcastable,const DIM : usize> TensorDimension for LazyUpdim<'a,T,
} }
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)
@ -59,23 +67,25 @@ impl<'a,T : Broadcastable,const DIM : usize> Broadcastable for LazyUpdim<'a,T,{
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)
@ -86,7 +96,9 @@ 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;

View file

@ -2,7 +2,7 @@ error[E0391]: cycle detected when resolving instance `<LazyUpdim<T, {T::DIM}, DI
--> $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