From 02aefd4089d7709d9916a32aae13fac800a10764 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 3 Oct 2023 00:22:51 +0000 Subject: [PATCH] Normalize opaques before defining them in the new solver --- .../rustc_trait_selection/src/solve/mod.rs | 14 ++++++++++- .../src/solve/project_goals/opaques.rs | 19 +++++++++++++++ ...3919.stderr => issue-83919.current.stderr} | 2 +- .../impl-trait/issues/issue-83919.next.stderr | 23 +++++++++++++++++++ tests/ui/impl-trait/issues/issue-83919.rs | 9 +++++--- ...err => recursive-generator.current.stderr} | 2 +- .../recursive-generator.next.stderr | 12 ++++++++++ tests/ui/impl-trait/recursive-generator.rs | 3 +++ ...o_tait_defining_each_other.current.stderr} | 6 ++--- .../two_tait_defining_each_other.rs | 6 ++++- ..._tait_defining_each_other3.current.stderr} | 6 ++--- .../two_tait_defining_each_other3.rs | 6 ++++- .../opaque-hidden-ty-is-rigid-projection.rs | 8 +++++++ ...paque-hidden-ty-is-rigid-projection.stderr | 21 +++++++++++++++++ .../type-alias-impl-trait/assoc-type-const.rs | 3 +++ .../assoc-type-lifetime.rs | 3 +++ tests/ui/type-alias-impl-trait/issue-78450.rs | 2 ++ .../wf-in-associated-type.fail.stderr | 4 ++-- .../wf-in-associated-type.rs | 6 +++-- 19 files changed, 137 insertions(+), 18 deletions(-) rename tests/ui/impl-trait/issues/{issue-83919.stderr => issue-83919.current.stderr} (92%) create mode 100644 tests/ui/impl-trait/issues/issue-83919.next.stderr rename tests/ui/impl-trait/{recursive-generator.stderr => recursive-generator.current.stderr} (91%) create mode 100644 tests/ui/impl-trait/recursive-generator.next.stderr rename tests/ui/impl-trait/{two_tait_defining_each_other.stderr => two_tait_defining_each_other.current.stderr} (78%) rename tests/ui/impl-trait/{two_tait_defining_each_other3.stderr => two_tait_defining_each_other3.current.stderr} (76%) create mode 100644 tests/ui/traits/new-solver/opaque-hidden-ty-is-rigid-projection.rs create mode 100644 tests/ui/traits/new-solver/opaque-hidden-ty-is-rigid-projection.stderr diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index d45fe102805ad..faec95dde1976 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -22,6 +22,7 @@ use rustc_middle::traits::solve::{ CanonicalResponse, Certainty, ExternalConstraintsData, Goal, IsNormalizesToHack, QueryResult, Response, }; +use rustc_middle::traits::Reveal; use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{ CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate, @@ -302,10 +303,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { mut ty: Ty<'tcx>, ) -> Result>, NoSolution> { for _ in 0..self.local_overflow_limit() { - let ty::Alias(_, projection_ty) = *ty.kind() else { + let ty::Alias(kind, projection_ty) = *ty.kind() else { return Ok(Some(ty)); }; + // Don't try normalizing an opaque that is not in the defining scope + if kind == ty::Opaque + && param_env.reveal() == Reveal::UserFacing + && !projection_ty + .def_id + .as_local() + .is_some_and(|def_id| self.can_define_opaque_ty(def_id)) + { + return Ok(Some(ty)); + } + let normalized_ty = self.next_ty_infer(); let normalizes_to_goal = Goal::new( self.tcx(), diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs b/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs index ebd129f32b919..a8f51bcf02369 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs @@ -23,12 +23,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else { return Err(NoSolution); }; + // FIXME: at some point we should call queries without defining // new opaque types but having the existing opaque type definitions. // This will require moving this below "Prefer opaques registered already". if !self.can_define_opaque_ty(opaque_ty_def_id) { return Err(NoSolution); } + // FIXME: This may have issues when the args contain aliases... match self.tcx().uses_unique_placeholders_ignoring_regions(opaque_ty.args) { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { @@ -41,6 +43,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } Ok(()) => {} } + // Prefer opaques registered already. let opaque_type_key = ty::OpaqueTypeKey { def_id: opaque_ty_def_id, args: opaque_ty.args }; @@ -53,6 +56,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return self.flounder(&matches); } } + + // Try normalizing the opaque's hidden type. If it's a ty var, + // then refuse to define the opaque type yet. This allows us to + // avoid inferring opaque cycles so eagerly. + let expected = match self.try_normalize_ty(goal.param_env, expected) { + Ok(Some(ty)) if !ty.is_ty_var() => ty, + Ok(_) => { + return self.evaluate_added_goals_and_make_canonical_response( + Certainty::AMBIGUOUS, + ); + } + Err(_) => { + return Err(NoSolution); + } + }; + // Otherwise, define a new opaque type self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; self.add_item_bounds_for_hidden_type( diff --git a/tests/ui/impl-trait/issues/issue-83919.stderr b/tests/ui/impl-trait/issues/issue-83919.current.stderr similarity index 92% rename from tests/ui/impl-trait/issues/issue-83919.stderr rename to tests/ui/impl-trait/issues/issue-83919.current.stderr index d39dcf7fbf5d9..86189a9047317 100644 --- a/tests/ui/impl-trait/issues/issue-83919.stderr +++ b/tests/ui/impl-trait/issues/issue-83919.current.stderr @@ -1,5 +1,5 @@ error[E0277]: `{integer}` is not a future - --> $DIR/issue-83919.rs:21:26 + --> $DIR/issue-83919.rs:23:26 | LL | fn get_fut(&self) -> Self::Fut { | ^^^^^^^^^ `{integer}` is not a future diff --git a/tests/ui/impl-trait/issues/issue-83919.next.stderr b/tests/ui/impl-trait/issues/issue-83919.next.stderr new file mode 100644 index 0000000000000..447326b45cf32 --- /dev/null +++ b/tests/ui/impl-trait/issues/issue-83919.next.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/issue-83919.rs:25:9 + | +LL | fn get_fut(&self) -> Self::Fut { + | --------- expected `::Fut` because of return type +LL | +LL | / async move { +LL | | +LL | | 42 +LL | | // 42 does not impl Future and rustc does actually point out the error, +LL | | // but rustc used to panic. +LL | | // Putting a valid Future here always worked fine. +LL | | } + | |_________^ types differ + | + = note: expected associated type `::Fut` + found `async` block `{async block@$DIR/issue-83919.rs:25:9: 31:10}` + = help: consider constraining the associated type `::Fut` to `{async block@$DIR/issue-83919.rs:25:9: 31:10}` or calling a method that returns `::Fut` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/issues/issue-83919.rs b/tests/ui/impl-trait/issues/issue-83919.rs index 4e699e7f30260..8b7a00bf1e7eb 100644 --- a/tests/ui/impl-trait/issues/issue-83919.rs +++ b/tests/ui/impl-trait/issues/issue-83919.rs @@ -1,7 +1,9 @@ -#![feature(impl_trait_in_assoc_type)] - +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next // edition:2021 +#![feature(impl_trait_in_assoc_type)] + use std::future::Future; trait Foo { @@ -19,8 +21,9 @@ impl Foo for Implementor { type Fut = impl Future; fn get_fut(&self) -> Self::Fut { - //~^ ERROR `{integer}` is not a future + //[current]~^ ERROR `{integer}` is not a future async move { + //[next]~^ ERROR mismatched types 42 // 42 does not impl Future and rustc does actually point out the error, // but rustc used to panic. diff --git a/tests/ui/impl-trait/recursive-generator.stderr b/tests/ui/impl-trait/recursive-generator.current.stderr similarity index 91% rename from tests/ui/impl-trait/recursive-generator.stderr rename to tests/ui/impl-trait/recursive-generator.current.stderr index 86e193d9599a1..8a1cb48569fa4 100644 --- a/tests/ui/impl-trait/recursive-generator.stderr +++ b/tests/ui/impl-trait/recursive-generator.current.stderr @@ -1,5 +1,5 @@ error[E0720]: cannot resolve opaque type - --> $DIR/recursive-generator.rs:5:13 + --> $DIR/recursive-generator.rs:8:13 | LL | fn foo() -> impl Generator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type diff --git a/tests/ui/impl-trait/recursive-generator.next.stderr b/tests/ui/impl-trait/recursive-generator.next.stderr new file mode 100644 index 0000000000000..8a1cb48569fa4 --- /dev/null +++ b/tests/ui/impl-trait/recursive-generator.next.stderr @@ -0,0 +1,12 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-generator.rs:8:13 + | +LL | fn foo() -> impl Generator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type +... +LL | let mut gen = Box::pin(foo()); + | ------- generator captures itself here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0720`. diff --git a/tests/ui/impl-trait/recursive-generator.rs b/tests/ui/impl-trait/recursive-generator.rs index 000af70c4540e..7b7a7e54ed69a 100644 --- a/tests/ui/impl-trait/recursive-generator.rs +++ b/tests/ui/impl-trait/recursive-generator.rs @@ -1,3 +1,6 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + #![feature(generators, generator_trait)] use std::ops::{Generator, GeneratorState}; diff --git a/tests/ui/impl-trait/two_tait_defining_each_other.stderr b/tests/ui/impl-trait/two_tait_defining_each_other.current.stderr similarity index 78% rename from tests/ui/impl-trait/two_tait_defining_each_other.stderr rename to tests/ui/impl-trait/two_tait_defining_each_other.current.stderr index 1a42ac525a6a8..e5f7e5e5c4498 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other.stderr +++ b/tests/ui/impl-trait/two_tait_defining_each_other.current.stderr @@ -1,16 +1,16 @@ error: opaque type's hidden type cannot be another opaque type from the same scope - --> $DIR/two_tait_defining_each_other.rs:12:5 + --> $DIR/two_tait_defining_each_other.rs:16:5 | LL | x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other | ^ one of the two opaque types used here has to be outside its defining scope | note: opaque type whose hidden type is being assigned - --> $DIR/two_tait_defining_each_other.rs:4:10 + --> $DIR/two_tait_defining_each_other.rs:8:10 | LL | type B = impl Foo; | ^^^^^^^^ note: opaque type being used as hidden type - --> $DIR/two_tait_defining_each_other.rs:3:10 + --> $DIR/two_tait_defining_each_other.rs:7:10 | LL | type A = impl Foo; | ^^^^^^^^ diff --git a/tests/ui/impl-trait/two_tait_defining_each_other.rs b/tests/ui/impl-trait/two_tait_defining_each_other.rs index 6eb2a11b22c5f..b43a7cabd0589 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other.rs +++ b/tests/ui/impl-trait/two_tait_defining_each_other.rs @@ -1,3 +1,7 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next +//[next] check-pass + #![feature(type_alias_impl_trait)] type A = impl Foo; @@ -10,7 +14,7 @@ fn muh(x: A) -> B { return Bar; // B's hidden type is Bar } x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other - //~^ ERROR opaque type's hidden type cannot be another opaque type + //[current]~^ ERROR opaque type's hidden type cannot be another opaque type } struct Bar; diff --git a/tests/ui/impl-trait/two_tait_defining_each_other3.stderr b/tests/ui/impl-trait/two_tait_defining_each_other3.current.stderr similarity index 76% rename from tests/ui/impl-trait/two_tait_defining_each_other3.stderr rename to tests/ui/impl-trait/two_tait_defining_each_other3.current.stderr index b06dc16d5e700..f936fd7909b37 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other3.stderr +++ b/tests/ui/impl-trait/two_tait_defining_each_other3.current.stderr @@ -1,16 +1,16 @@ error: opaque type's hidden type cannot be another opaque type from the same scope - --> $DIR/two_tait_defining_each_other3.rs:10:16 + --> $DIR/two_tait_defining_each_other3.rs:14:16 | LL | return x; // B's hidden type is A (opaquely) | ^ one of the two opaque types used here has to be outside its defining scope | note: opaque type whose hidden type is being assigned - --> $DIR/two_tait_defining_each_other3.rs:4:10 + --> $DIR/two_tait_defining_each_other3.rs:8:10 | LL | type B = impl Foo; | ^^^^^^^^ note: opaque type being used as hidden type - --> $DIR/two_tait_defining_each_other3.rs:3:10 + --> $DIR/two_tait_defining_each_other3.rs:7:10 | LL | type A = impl Foo; | ^^^^^^^^ diff --git a/tests/ui/impl-trait/two_tait_defining_each_other3.rs b/tests/ui/impl-trait/two_tait_defining_each_other3.rs index 37f8ae1b84b55..df72d21511e0d 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other3.rs +++ b/tests/ui/impl-trait/two_tait_defining_each_other3.rs @@ -1,3 +1,7 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next +//[next] check-pass + #![feature(type_alias_impl_trait)] type A = impl Foo; @@ -8,7 +12,7 @@ trait Foo {} fn muh(x: A) -> B { if false { return x; // B's hidden type is A (opaquely) - //~^ ERROR opaque type's hidden type cannot be another opaque type + //[current]~^ ERROR opaque type's hidden type cannot be another opaque type } Bar // A's hidden type is `Bar`, because all the return types are compared with each other } diff --git a/tests/ui/traits/new-solver/opaque-hidden-ty-is-rigid-projection.rs b/tests/ui/traits/new-solver/opaque-hidden-ty-is-rigid-projection.rs new file mode 100644 index 0000000000000..be697cb8d5200 --- /dev/null +++ b/tests/ui/traits/new-solver/opaque-hidden-ty-is-rigid-projection.rs @@ -0,0 +1,8 @@ +// known-bug: unknown +// compile-flags: -Ztrait-solver=next + +fn test(x: T::Item) -> impl Sized { + x +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/opaque-hidden-ty-is-rigid-projection.stderr b/tests/ui/traits/new-solver/opaque-hidden-ty-is-rigid-projection.stderr new file mode 100644 index 0000000000000..f26f77d70cb98 --- /dev/null +++ b/tests/ui/traits/new-solver/opaque-hidden-ty-is-rigid-projection.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/opaque-hidden-ty-is-rigid-projection.rs:5:5 + | +LL | fn test(x: T::Item) -> impl Sized { + | ---------- + | | + | the expected opaque type + | expected `impl Sized` because of return type +LL | x + | ^ types differ + | + = note: expected opaque type `impl Sized` + found associated type `::Item` +help: consider constraining the associated type `::Item` to `impl Sized` + | +LL | fn test>(x: T::Item) -> impl Sized { + | +++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/assoc-type-const.rs b/tests/ui/type-alias-impl-trait/assoc-type-const.rs index 62f66914ee330..0e97aadc018ef 100644 --- a/tests/ui/type-alias-impl-trait/assoc-type-const.rs +++ b/tests/ui/type-alias-impl-trait/assoc-type-const.rs @@ -1,6 +1,9 @@ // Tests that we properly detect defining usages when using // const generics in an associated opaque type + // check-pass +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next #![feature(impl_trait_in_assoc_type)] diff --git a/tests/ui/type-alias-impl-trait/assoc-type-lifetime.rs b/tests/ui/type-alias-impl-trait/assoc-type-lifetime.rs index 81dacbcfb7ecc..44466c9348b97 100644 --- a/tests/ui/type-alias-impl-trait/assoc-type-lifetime.rs +++ b/tests/ui/type-alias-impl-trait/assoc-type-lifetime.rs @@ -1,6 +1,9 @@ // Tests that we still detect defining usages when // lifetimes are used in an associated opaque type + // check-pass +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next #![feature(impl_trait_in_assoc_type)] diff --git a/tests/ui/type-alias-impl-trait/issue-78450.rs b/tests/ui/type-alias-impl-trait/issue-78450.rs index 2a984c1ed7133..236e9f4e88cec 100644 --- a/tests/ui/type-alias-impl-trait/issue-78450.rs +++ b/tests/ui/type-alias-impl-trait/issue-78450.rs @@ -1,4 +1,6 @@ // check-pass +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next #![feature(impl_trait_in_assoc_type)] diff --git a/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr b/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr index 7d72c9f811af4..c4ad8434ed147 100644 --- a/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr +++ b/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr @@ -1,5 +1,5 @@ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/wf-in-associated-type.rs:36:23 + --> $DIR/wf-in-associated-type.rs:38:23 | LL | impl<'a, T> Trait<'a, T> for () { | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... @@ -12,7 +12,7 @@ LL | impl<'a, T: 'a> Trait<'a, T> for () { | ++++ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/wf-in-associated-type.rs:36:23 + --> $DIR/wf-in-associated-type.rs:38:23 | LL | impl<'a, T> Trait<'a, T> for () { | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... diff --git a/tests/ui/type-alias-impl-trait/wf-in-associated-type.rs b/tests/ui/type-alias-impl-trait/wf-in-associated-type.rs index 31fbef9f78f83..b966ca4bff0e7 100644 --- a/tests/ui/type-alias-impl-trait/wf-in-associated-type.rs +++ b/tests/ui/type-alias-impl-trait/wf-in-associated-type.rs @@ -1,14 +1,16 @@ // WF check for impl Trait in associated type position. // -// revisions: pass fail +// revisions: pass pass_next fail // [pass] check-pass +// [pass_next] compile-flags: -Ztrait-solver=next +// [pass_next] check-pass // [fail] check-fail #![feature(impl_trait_in_assoc_type)] // The hidden type here (`&'a T`) requires proving `T: 'a`. // We know it holds because of implied bounds from the impl header. -#[cfg(pass)] +#[cfg(any(pass, pass_next))] mod pass { trait Trait { type Opaque1;