mirror of
https://github.com/rust-lang/rust.git
synced 2026-07-13 19:26:30 -04:00
the .eq() in instantiate_normalizes_to_term may fail
This commit is contained in:
@@ -82,7 +82,7 @@ where
|
||||
},
|
||||
|ecx| {
|
||||
ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| {
|
||||
this.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
|
||||
this.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias)?;
|
||||
this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
},
|
||||
@@ -111,13 +111,9 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// When normalizing an associated item, constrain the expected term to `term`.
|
||||
/// When normalizing an associated item, constrain the expected term to `value`.
|
||||
///
|
||||
/// We know `term` to always be a fully unconstrained inference variable, so
|
||||
/// `eq` should never fail here. However, in case `term` contains aliases, we
|
||||
/// emit nested `AliasRelate` goals to structurally normalize the alias.
|
||||
///
|
||||
/// Additionally, when `term` is a const, this registers a `ConstArgHasType`
|
||||
/// Additionally, when `value` is a const, this registers a `ConstArgHasType`
|
||||
/// goal to ensure that the const value's type matches the declared type of
|
||||
/// the alias it was normalized from.
|
||||
///
|
||||
@@ -140,11 +136,13 @@ where
|
||||
fn instantiate_normalizes_to_term(
|
||||
&mut self,
|
||||
goal: Goal<I, NormalizesTo<I>>,
|
||||
term: I::Term,
|
||||
value: I::Term,
|
||||
) -> Result<(), NoSolutionOrRerunNonErased> {
|
||||
self.push_const_arg_has_type_goal(goal.param_env, goal.predicate.alias, term)?;
|
||||
self.eq(goal.param_env, goal.predicate.term, term)
|
||||
.expect("expected goal term to be fully unconstrained");
|
||||
self.push_const_arg_has_type_goal(goal.param_env, goal.predicate.alias, value)?;
|
||||
// While `goal.predicate.term` should always be a fully unconstrained inference variable,
|
||||
// `eq` can still fail if `value` is not fully normalized, due to `eq` eagerly normalizing,
|
||||
// and that normalization can fail.
|
||||
self.eq(goal.param_env, goal.predicate.term, value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -154,14 +152,13 @@ where
|
||||
&mut self,
|
||||
goal: Goal<I, NormalizesTo<I>>,
|
||||
term: ty::AliasTerm<I>,
|
||||
) {
|
||||
) -> Result<(), NoSolutionOrRerunNonErased> {
|
||||
self.relate(
|
||||
goal.param_env,
|
||||
term.to_term(self.cx(), ty::IsRigid::Yes),
|
||||
ty::Invariant,
|
||||
goal.predicate.term,
|
||||
)
|
||||
.expect("expected goal term to be fully unconstrained");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,7 +356,7 @@ where
|
||||
ecx.structurally_instantiate_normalizes_to_term(
|
||||
goal,
|
||||
goal.predicate.alias,
|
||||
);
|
||||
)?;
|
||||
return ecx.evaluate_added_goals_and_make_canonical_response(
|
||||
Certainty::Yes,
|
||||
);
|
||||
@@ -394,7 +391,10 @@ where
|
||||
ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous))?;
|
||||
return then(ecx, Certainty::Yes);
|
||||
} else {
|
||||
ecx.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
|
||||
ecx.structurally_instantiate_normalizes_to_term(
|
||||
goal,
|
||||
goal.predicate.alias,
|
||||
)?;
|
||||
return then(ecx, Certainty::Yes);
|
||||
}
|
||||
} else {
|
||||
@@ -770,7 +770,7 @@ where
|
||||
this.structurally_instantiate_normalizes_to_term(
|
||||
goal,
|
||||
goal.predicate.alias,
|
||||
);
|
||||
)?;
|
||||
this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
});
|
||||
@@ -1026,7 +1026,7 @@ where
|
||||
// this impl candidate anyways. It's still a bit scuffed.
|
||||
ty::Alias(ty::IsRigid::Yes, _) | ty::Param(_) | ty::Placeholder(..) => {
|
||||
return ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
ecx.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
|
||||
ecx.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias)?;
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
});
|
||||
}
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
//@ compile-flags: -Znext-solver
|
||||
|
||||
//! This test is extremely similar to `nested-rerun-not-erased-in-normalizes-to.rs`, however,
|
||||
//! instead of the eager normalization failing due to an anon const when in ErasedNotCoherence, this
|
||||
//! just straight up fails normalization because u32 is not Iterator
|
||||
|
||||
#![feature(ptr_metadata)]
|
||||
|
||||
struct ThisStructAintValid(<u32 as Iterator>::Item);
|
||||
//~^ ERROR `u32` is not an iterator
|
||||
|
||||
fn main() {
|
||||
let y: <ThisStructAintValid as std::ptr::Pointee>::Metadata;
|
||||
//~^ ERROR type mismatch resolving `<ThisStructAintValid as Pointee>::Metadata == _`
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
error[E0277]: `u32` is not an iterator
|
||||
--> $DIR/consider_builtin_pointee_candidate-instantiate-result-fail.rs:9:28
|
||||
|
|
||||
LL | struct ThisStructAintValid(<u32 as Iterator>::Item);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not an iterator
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `u32`
|
||||
|
||||
error[E0271]: type mismatch resolving `<ThisStructAintValid as Pointee>::Metadata == _`
|
||||
--> $DIR/consider_builtin_pointee_candidate-instantiate-result-fail.rs:13:12
|
||||
|
|
||||
LL | let y: <ThisStructAintValid as std::ptr::Pointee>::Metadata;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0271, E0277.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
||||
@@ -0,0 +1,28 @@
|
||||
//@ build-pass
|
||||
//@ compile-flags: -Znext-solver
|
||||
|
||||
//! Consider:
|
||||
//!
|
||||
//! goal is <StructTailHasAnonConst as Pointee>::Metadata == ?0, in a typing context of
|
||||
//! ErasedNotCoherence
|
||||
//!
|
||||
//! `consider_builtin_pointee_candidate` looks at StructTailHasAnonConst, realizes it's an ADT,
|
||||
//! fetches the struct tail (which is `S<{ 2 + 2 }>`), and calls `instantiate_normalizes_to_term`
|
||||
//! with the result of `<Struct<{ 2 + 2 }> as Pointee>::Metadata`
|
||||
//!
|
||||
//! `instantiate_normalizes_to_term` `.eq()`s `<Struct<{ 2 + 2 }> as Pointee>::Metadata` and `?0`
|
||||
//!
|
||||
//! this eagerly normalizes, which normalizes the anon const, which fails due to ErasedNotCoherence
|
||||
//!
|
||||
//! this causes the `.eq()` in `instantiate_normalizes_to_term` to fail, which used to have an
|
||||
//! unwrap, which ICEd
|
||||
|
||||
#![feature(ptr_metadata)]
|
||||
|
||||
struct S<const N: usize>;
|
||||
|
||||
struct StructTailHasAnonConst(S<{ 2 + 2 }>);
|
||||
|
||||
fn main() {
|
||||
let y: <StructTailHasAnonConst as std::ptr::Pointee>::Metadata;
|
||||
}
|
||||
Reference in New Issue
Block a user