diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 999367e758978..81be5c091644e 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -21,10 +21,9 @@ //! `NormalizesTo` goal, at which point the opaque is actually defined. use super::{EvalCtxt, GoalSource}; -use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::traits::query::NoSolution; use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::ty; +use rustc_middle::ty::{self, Ty}; impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self), ret)] @@ -79,7 +78,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } // FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var. - /// Normalize the `term` to equate it later. This does not define opaque types. + /// Normalize the `term` to equate it later. #[instrument(level = "debug", skip(self, param_env), ret)] fn try_normalize_term( &mut self, @@ -88,10 +87,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) -> Result>, NoSolution> { match term.unpack() { ty::TermKind::Ty(ty) => { - // We do no define opaque types here but instead do so in `relate_rigid_alias_or_opaque`. - Ok(self - .try_normalize_ty_recur(param_env, DefineOpaqueTypes::No, 0, ty) - .map(Into::into)) + Ok(self.try_normalize_ty_recur(param_env, 0, ty).map(Into::into)) } ty::TermKind::Const(_) => { if let Some(alias) = term.to_alias_ty(self.tcx()) { @@ -108,4 +104,35 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } } + + fn try_normalize_ty_recur( + &mut self, + param_env: ty::ParamEnv<'tcx>, + depth: usize, + ty: Ty<'tcx>, + ) -> Option> { + if !self.tcx().recursion_limit().value_within_limit(depth) { + return None; + } + + let ty::Alias(_, alias) = *ty.kind() else { + return Some(ty); + }; + + match self.commit_if_ok(|this| { + let normalized_ty = this.next_ty_infer(); + let normalizes_to_goal = Goal::new( + this.tcx(), + param_env, + ty::NormalizesTo { alias, term: normalized_ty.into() }, + ); + this.add_goal(GoalSource::Misc, normalizes_to_goal); + this.try_evaluate_added_goals()?; + let ty = this.resolve_vars_if_possible(normalized_ty); + Ok(this.try_normalize_ty_recur(param_env, depth + 1, ty)) + }) { + Ok(ty) => ty, + Err(NoSolution) => Some(ty), + } + } } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 915d722dd0206..eac630d5f0361 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -269,13 +269,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { vec![Candidate { source, result }] }; - let Some(normalized_self_ty) = - self.try_normalize_ty(goal.param_env, goal.predicate.self_ty()) + let Ok(normalized_self_ty) = + self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty()) else { - debug!("overflow while evaluating self type"); - return dummy_candidate(self, Certainty::OVERFLOW); + return vec![]; }; - if normalized_self_ty.is_ty_var() { debug!("self type has been normalized to infer"); return dummy_candidate(self, Certainty::AMBIGUOUS); @@ -770,19 +768,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| { let trait_ref = goal.predicate.trait_ref(tcx); - #[derive(Debug)] - struct Overflow; - let lazily_normalize_ty = |ty| match ecx.try_normalize_ty(goal.param_env, ty) { - Some(ty) => Ok(ty), - None => Err(Overflow), - }; + let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty); - match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty) { - Err(Overflow) => { - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) - } - Ok(Ok(())) => Err(NoSolution), - Ok(Err(_)) => { + match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? { + Ok(()) => Err(NoSolution), + Err(_) => { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index dd9fd2a904e12..3fbf9cfb354d3 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -15,14 +15,13 @@ //! about it on zulip. use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; -use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::traits::query::NoSolution; use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::traits::solve::{ CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack, QueryResult, Response, }; -use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex}; +use rustc_middle::ty::{self, AliasRelationDirection, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{ CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate, }; @@ -285,49 +284,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Ok(self.make_ambiguous_response_no_constraints(maybe_cause)) } - /// Normalize a type when it is structually matched on. + /// Normalize a type for when it is structurally matched on. /// - /// In nearly all cases this function must be used before matching on a type. + /// This function is necessary in nearly all cases before matching on a type. /// Not doing so is likely to be incomplete and therefore unsound during /// coherence. - #[instrument(level = "debug", skip(self), ret)] - fn try_normalize_ty( - &mut self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - ) -> Option> { - self.try_normalize_ty_recur(param_env, DefineOpaqueTypes::Yes, 0, ty) - } - - fn try_normalize_ty_recur( + fn structurally_normalize_ty( &mut self, param_env: ty::ParamEnv<'tcx>, - define_opaque_types: DefineOpaqueTypes, - depth: usize, ty: Ty<'tcx>, - ) -> Option> { - if !self.tcx().recursion_limit().value_within_limit(depth) { - return None; - } - - let ty::Alias(_, alias) = *ty.kind() else { - return Some(ty); - }; - - match self.commit_if_ok(|this| { - let normalized_ty = this.next_ty_infer(); - let normalizes_to_goal = Goal::new( - this.tcx(), + ) -> Result, NoSolution> { + if let ty::Alias(..) = ty.kind() { + let normalized_ty = self.next_ty_infer(); + let alias_relate_goal = Goal::new( + self.tcx(), param_env, - ty::NormalizesTo { alias, term: normalized_ty.into() }, + ty::PredicateKind::AliasRelate( + ty.into(), + normalized_ty.into(), + AliasRelationDirection::Equate, + ), ); - this.add_goal(GoalSource::Misc, normalizes_to_goal); - this.try_evaluate_added_goals()?; - let ty = this.resolve_vars_if_possible(normalized_ty); - Ok(this.try_normalize_ty_recur(param_env, define_opaque_types, depth + 1, ty)) - }) { - Ok(ty) => ty, - Err(NoSolution) => Some(ty), + self.add_goal(GoalSource::Misc, alias_relate_goal); + self.try_evaluate_added_goals()?; + Ok(self.resolve_vars_if_possible(normalized_ty)) + } else { + Ok(ty) } } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs index b5d1aa06e4eeb..356c3776c04ce 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs @@ -58,21 +58,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - let expected = match self.try_normalize_ty(goal.param_env, expected) { - Some(ty) => { - if ty.is_ty_var() { - return self.evaluate_added_goals_and_make_canonical_response( - Certainty::AMBIGUOUS, - ); - } else { - ty - } - } - None => { - return self - .evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW); - } - }; + let expected = self.structurally_normalize_ty(goal.param_env, expected)?; + if expected.is_ty_var() { + return self + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } // Otherwise, define a new opaque type self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index b185e4e5f8eb0..7b49179ebe4ff 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -521,11 +521,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let a_ty = goal.predicate.self_ty(); // We need to normalize the b_ty since it's matched structurally // in the other functions below. - let b_ty = match ecx - .try_normalize_ty(goal.param_env, goal.predicate.trait_ref.args.type_at(1)) - { - Some(b_ty) => b_ty, - None => return vec![misc_candidate(ecx, Certainty::OVERFLOW)], + let Ok(b_ty) = ecx.structurally_normalize_ty( + goal.param_env, + goal.predicate.trait_ref.args.type_at(1), + ) else { + return vec![]; }; let goal = goal.with(ecx.tcx(), (a_ty, b_ty)); diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr new file mode 100644 index 0000000000000..0d9e2ee8469e8 --- /dev/null +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed + --> $DIR/recursive-coroutine-boxed.rs:10:23 + | +LL | let mut gen = Box::pin(foo()); + | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box` +LL | +LL | let mut r = gen.as_mut().resume(()); + | ------ type must be known at this point + | +help: consider specifying the generic argument + | +LL | let mut gen = Box::::pin(foo()); + | +++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs index b9291f07e2138..2c5d679994f07 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.rs +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.rs @@ -1,5 +1,5 @@ -// check-pass // revisions: current next +//[current] check-pass //[next] compile-flags: -Znext-solver #![feature(coroutines, coroutine_trait)] @@ -8,6 +8,7 @@ use std::ops::{Coroutine, CoroutineState}; fn foo() -> impl Coroutine { || { let mut gen = Box::pin(foo()); + //[next]~^ ERROR type annotations needed let mut r = gen.as_mut().resume(()); while let CoroutineState::Yielded(v) = r { yield v; diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr index e49d1d18b0cf7..69328e2058313 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `A <: B` +error[E0284]: type annotations needed: cannot satisfy `A == B` --> $DIR/two_tait_defining_each_other2.rs:11:5 | LL | x // B's hidden type is A (opaquely) - | ^ cannot satisfy `A <: B` + | ^ cannot satisfy `A == B` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.rs b/tests/ui/impl-trait/two_tait_defining_each_other2.rs index 8a79af19776b7..b2f768f4dcd70 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.rs +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.rs @@ -10,7 +10,7 @@ trait Foo {} fn muh(x: A) -> B { x // B's hidden type is A (opaquely) //[current]~^ ERROR opaque type's hidden type cannot be another opaque type - //[next]~^^ ERROR type annotations needed: cannot satisfy `A <: B` + //[next]~^^ ERROR type annotations needed: cannot satisfy `A == B` } struct Bar; diff --git a/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.rs b/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.rs index 08f26686b2f20..f9f5a1dc24d47 100644 --- a/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.rs +++ b/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.rs @@ -1,9 +1,10 @@ // compile-flags: -Znext-solver -// check-pass - +// FIXME(-Znext-solver): This test is currently broken because the `deduce_closure_signature` +// is unable to look at nested obligations. trait Foo { fn test() -> impl Fn(u32) -> u32 { |x| x.count_ones() + //~^ ERROR type annotations needed } } diff --git a/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.stderr b/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.stderr new file mode 100644 index 0000000000000..3d7cd1af4677f --- /dev/null +++ b/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed + --> $DIR/deduce-closure-signature-after-normalization.rs:6:10 + | +LL | |x| x.count_ones() + | ^ - type must be known at this point + | +help: consider giving this closure parameter an explicit type + | +LL | |x: /* Type */| x.count_ones() + | ++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.is_send.stderr b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.is_send.stderr index bafc4ba18a7a3..158fefd1538f3 100644 --- a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.is_send.stderr +++ b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.is_send.stderr @@ -1,16 +1,9 @@ -error[E0283]: type annotations needed: cannot satisfy `Foo: Send` +error[E0284]: type annotations needed: cannot satisfy `Foo == _` --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18 | LL | needs_send::(); - | ^^^ - | - = note: cannot satisfy `Foo: Send` -note: required by a bound in `needs_send` - --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 - | -LL | fn needs_send() {} - | ^^^^ required by this bound in `needs_send` + | ^^^ cannot satisfy `Foo == _` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr index bafc4ba18a7a3..158fefd1538f3 100644 --- a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr +++ b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr @@ -1,16 +1,9 @@ -error[E0283]: type annotations needed: cannot satisfy `Foo: Send` +error[E0284]: type annotations needed: cannot satisfy `Foo == _` --> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18 | LL | needs_send::(); - | ^^^ - | - = note: cannot satisfy `Foo: Send` -note: required by a bound in `needs_send` - --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 - | -LL | fn needs_send() {} - | ^^^^ required by this bound in `needs_send` + | ^^^ cannot satisfy `Foo == _` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs index ef0360248b59a..9720a653e2bc0 100644 --- a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs +++ b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs @@ -13,7 +13,7 @@ fn needs_send() {} fn test(_: Foo) { needs_send::(); - //~^ ERROR type annotations needed: cannot satisfy `Foo: Send` + //~^ ERROR type annotations needed: cannot satisfy `Foo == _` } fn defines(_: Foo) {