diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs index 3427044915f8..9dc65d141b66 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -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>, - 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>, term: ty::AliasTerm, - ) { + ) -> 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) }); } diff --git a/tests/ui/traits/next-solver/consider_builtin_pointee_candidate-instantiate-result-fail.rs b/tests/ui/traits/next-solver/consider_builtin_pointee_candidate-instantiate-result-fail.rs new file mode 100644 index 000000000000..b469165e4b56 --- /dev/null +++ b/tests/ui/traits/next-solver/consider_builtin_pointee_candidate-instantiate-result-fail.rs @@ -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(::Item); +//~^ ERROR `u32` is not an iterator + +fn main() { + let y: ::Metadata; + //~^ ERROR type mismatch resolving `::Metadata == _` +} diff --git a/tests/ui/traits/next-solver/consider_builtin_pointee_candidate-instantiate-result-fail.stderr b/tests/ui/traits/next-solver/consider_builtin_pointee_candidate-instantiate-result-fail.stderr new file mode 100644 index 000000000000..60fd1b35b26a --- /dev/null +++ b/tests/ui/traits/next-solver/consider_builtin_pointee_candidate-instantiate-result-fail.stderr @@ -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(::Item); + | ^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not an iterator + | + = help: the trait `Iterator` is not implemented for `u32` + +error[E0271]: type mismatch resolving `::Metadata == _` + --> $DIR/consider_builtin_pointee_candidate-instantiate-result-fail.rs:13:12 + | +LL | let y: ::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`. diff --git a/tests/ui/traits/next-solver/nested-rerun-not-erased-in-normalizes-to.rs b/tests/ui/traits/next-solver/nested-rerun-not-erased-in-normalizes-to.rs new file mode 100644 index 000000000000..b75598d11c83 --- /dev/null +++ b/tests/ui/traits/next-solver/nested-rerun-not-erased-in-normalizes-to.rs @@ -0,0 +1,28 @@ +//@ build-pass +//@ compile-flags: -Znext-solver + +//! Consider: +//! +//! goal is ::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 ` as Pointee>::Metadata` +//! +//! `instantiate_normalizes_to_term` `.eq()`s ` 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; + +struct StructTailHasAnonConst(S<{ 2 + 2 }>); + +fn main() { + let y: ::Metadata; +}