diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index a89d45c4b0b2a..e3102c4fc34bf 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::traits::query::type_op; +use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use tracing::{debug, instrument}; use type_op::TypeOpOutput; @@ -235,21 +235,38 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let mut normalized_inputs_and_output = Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1); for ty in unnormalized_input_output_tys { + // FIXME(type_alias_impl_trait): This is a temporary fix for + // trait-system-refactor-initiative#159. + // + // We have to make sure that we don't look into opaque types in the signature + // when computing implied bounds as doing so results in implied bounds which + // are not checked by the caller. + // + // This current approach is only sufficient for RPIT(IT) and somewhat of a mess. + // Fixing this properly blocks stabilization of TAIT and RTN. See #160425 for + // more details. + let (param_env, ty) = if tcx.next_trait_solver_globally() { + ty::set_opaques_to_rigid(tcx, (self.infcx.param_env, ty)) + } else { + (self.infcx.param_env, ty) + }; + debug!("build: input_or_output={:?}", ty); // We add implied bounds from both the unnormalized and normalized ty. // See issue #87748 - let constraints_unnorm = self.add_implied_bounds(ty, span); + let constraints_unnorm = self.add_implied_bounds(param_env, ty, span); if let Some(c) = constraints_unnorm { constraints.push(c) } - let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self - .infcx - .fully_perform(Normalize { value: ty::Unnormalized::new_wip(ty) }, span) - .unwrap_or_else(|guar| TypeOpOutput { - output: Ty::new_error(self.infcx.tcx, guar), - constraints: None, - error_info: None, - }); + let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = + param_env + .and(Normalize { value: ty::Unnormalized::new_wip(ty) }) + .fully_perform(self.infcx, self.infcx.root_def_id, span) + .unwrap_or_else(|guar| TypeOpOutput { + output: Ty::new_error(tcx, guar), + constraints: None, + error_info: None, + }); if let Some(c) = constraints_normalize { constraints.push(c) } @@ -276,12 +293,33 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // ``` // Both &Self::Bar and &() are WF if ty != norm_ty { - let constraints_norm = self.add_implied_bounds(norm_ty, span); + let constraints_norm = self.add_implied_bounds(param_env, norm_ty, span); if let Some(c) = constraints_norm { constraints.push(c) } } + // FIXME(type_alias_impl_trait): Part of the above fix. While we don't want to + // normalize opaque types for implied bounds, we do want to normalize them for + // the actual signature. + let norm_ty = if tcx.next_trait_solver_globally() && norm_ty.has_opaque_types() { + let norm_ty = ty::set_aliases_to_non_rigid(tcx, norm_ty); + let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self + .infcx + .fully_perform(Normalize { value: norm_ty }, span) + .unwrap_or_else(|guar| TypeOpOutput { + output: Ty::new_error(tcx, guar), + constraints: None, + error_info: None, + }); + if let Some(c) = constraints_normalize { + constraints.push(c) + } + norm_ty + } else { + norm_ty + }; + normalized_inputs_and_output.push(norm_ty); } @@ -309,7 +347,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // We currently add implied bounds from the normalized ty only. // This is more conservative and matches wfcheck behavior. - let c = self.add_implied_bounds(norm_ty, span); + let c = self.add_implied_bounds(self.infcx.param_env, norm_ty, span); constraints.extend(c); } } @@ -377,12 +415,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { #[instrument(level = "debug", skip(self))] fn add_implied_bounds( &mut self, + param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, span: Span, ) -> Option<&'tcx QueryRegionConstraints<'tcx>> { - let TypeOpOutput { output: bounds, constraints, .. } = self - .infcx - .fully_perform(type_op::ImpliedOutlivesBounds { ty }, span) + // FIXME(type_alias_impl_trait): This should use the `param_env` of the `InferCtxt`, + // however we currently sometimes set the RPITIT opaque as rigid to avoid trait-system-refactor-initiative#159. + let TypeOpOutput { output: bounds, constraints, .. } = param_env + .and(type_op::ImpliedOutlivesBounds { ty }) + .fully_perform(self.infcx, self.infcx.root_def_id, span) .map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty)) .ok()?; debug!(?bounds, ?constraints); diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index f57a9aba69302..aa4886a680409 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -569,6 +569,13 @@ where ty::Unnormalized::new(folded) } +pub fn set_opaques_to_rigid(cx: I, value: T) -> T +where + T: TypeFoldable, +{ + set_aliases_rigidness_with_mode(cx, value, RigidnessFoldMode::OpaqueToRigid) +} + pub fn set_opaques_to_non_rigid(cx: I, value: T) -> ty::Unnormalized where T: TypeFoldable, @@ -607,6 +614,7 @@ enum RigidnessFoldMode { AllToRigid, AllToNonRigid, TypeToRigid, + OpaqueToRigid, OpaqueToNonRigid, } @@ -619,6 +627,7 @@ impl RigidnessFoldMode { v.has_non_rigid_aliases() && v.has_type_flags(ty::TypeFlags::HAS_ALIAS - ty::TypeFlags::HAS_CONST_ALIAS) } + RigidnessFoldMode::OpaqueToRigid => v.has_non_rigid_aliases() && v.has_opaque_types(), RigidnessFoldMode::OpaqueToNonRigid => v.has_rigid_aliases() && v.has_opaque_types(), } } @@ -650,16 +659,23 @@ impl TypeFolder for RigidnessFolder { let alias_ty = alias_ty.fold_with(self); match self.mode { RigidnessFoldMode::AllToRigid | RigidnessFoldMode::TypeToRigid => { - I::Ty::new_alias(self.cx(), ty::IsRigid::Yes, alias_ty) + I::Ty::new_alias(self.cx, ty::IsRigid::Yes, alias_ty) } RigidnessFoldMode::AllToNonRigid => { - I::Ty::new_alias(self.cx(), ty::IsRigid::No, alias_ty) + I::Ty::new_alias(self.cx, ty::IsRigid::No, alias_ty) + } + RigidnessFoldMode::OpaqueToRigid => { + if let ty::AliasTyKind::Opaque { .. } = alias_ty.kind { + I::Ty::new_alias(self.cx, ty::IsRigid::Yes, alias_ty) + } else { + I::Ty::new_alias(self.cx, is_rigid, alias_ty) + } } RigidnessFoldMode::OpaqueToNonRigid => { if let ty::AliasTyKind::Opaque { .. } = alias_ty.kind { - I::Ty::new_alias(self.cx(), ty::IsRigid::No, alias_ty) + I::Ty::new_alias(self.cx, ty::IsRigid::No, alias_ty) } else { - I::Ty::new_alias(self.cx(), is_rigid, alias_ty) + I::Ty::new_alias(self.cx, is_rigid, alias_ty) } } } @@ -681,10 +697,12 @@ impl TypeFolder for RigidnessFolder { I::Const::new_alias(self.cx, ty::IsRigid::Yes, alias_const) } RigidnessFoldMode::AllToNonRigid => { - I::Const::new_alias(self.cx(), ty::IsRigid::No, alias_const) + I::Const::new_alias(self.cx, ty::IsRigid::No, alias_const) } - RigidnessFoldMode::OpaqueToNonRigid | RigidnessFoldMode::TypeToRigid => { - I::Const::new_alias(self.cx(), is_rigid, alias_const) + RigidnessFoldMode::OpaqueToRigid + | RigidnessFoldMode::OpaqueToNonRigid + | RigidnessFoldMode::TypeToRigid => { + I::Const::new_alias(self.cx, is_rigid, alias_const) } } } diff --git a/tests/ui/impl-trait/wf-check-hidden-type.stderr b/tests/ui/impl-trait/wf-check-hidden-type.current.stderr similarity index 91% rename from tests/ui/impl-trait/wf-check-hidden-type.stderr rename to tests/ui/impl-trait/wf-check-hidden-type.current.stderr index 86ba7aff54ada..254bc45796ca2 100644 --- a/tests/ui/impl-trait/wf-check-hidden-type.stderr +++ b/tests/ui/impl-trait/wf-check-hidden-type.current.stderr @@ -1,10 +1,11 @@ error: lifetime may not live long enough - --> $DIR/wf-check-hidden-type.rs:14:5 + --> $DIR/wf-check-hidden-type.rs:21:5 | LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here +LL | LL | None::<&'_ &'_ ()> | ^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | diff --git a/tests/ui/impl-trait/wf-check-hidden-type.next.stderr b/tests/ui/impl-trait/wf-check-hidden-type.next.stderr new file mode 100644 index 0000000000000..88da3916955da --- /dev/null +++ b/tests/ui/impl-trait/wf-check-hidden-type.next.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/wf-check-hidden-type.rs:19:1 + | +LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> { + | ^^^^^^^^--^^--^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | | + | | | lifetime `'b` defined here + | | lifetime `'a` defined here + | requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to 1 previous error + diff --git a/tests/ui/impl-trait/wf-check-hidden-type.rs b/tests/ui/impl-trait/wf-check-hidden-type.rs index c3b1182a98f48..1146d966eeb0d 100644 --- a/tests/ui/impl-trait/wf-check-hidden-type.rs +++ b/tests/ui/impl-trait/wf-check-hidden-type.rs @@ -1,4 +1,10 @@ -//! Regression test for #114728. +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +//! Regression test for #114728. This also catched +//! trait-system-refactor-initiative#159 with the new +//! solver. trait Extend<'a, 'b> { fn extend(self, _: &'a str) -> &'b str; @@ -11,7 +17,8 @@ impl<'a, 'b> Extend<'a, 'b> for Option<&'b &'a ()> { } fn boom<'a, 'b>() -> impl Extend<'a, 'b> { - None::<&'_ &'_ ()> //~ ERROR lifetime may not live long enough + //[next]~^ ERROR lifetime may not live long enough + None::<&'_ &'_ ()> //[current]~ ERROR lifetime may not live long enough } fn main() { diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-2.current.stderr b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-2.current.stderr new file mode 100644 index 0000000000000..ea1b22dd80333 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-2.current.stderr @@ -0,0 +1,17 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-2.rs:18:5 + | +LL | into_y(t) + | ^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn wat(t: T) -> impl Sized + 'static { + | +++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-2.next.stderr b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-2.next.stderr new file mode 100644 index 0000000000000..b34013763219e --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-2.next.stderr @@ -0,0 +1,31 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-2.rs:16:1 + | +LL | fn wat(t: T) -> impl Sized + 'static { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn wat(t: T) -> impl Sized + 'static { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-2.rs:18:5 + | +LL | into_y(t) + | ^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn wat(t: T) -> impl Sized + 'static { + | +++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-2.rs b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-2.rs new file mode 100644 index 0000000000000..5c699dfc53199 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-2.rs @@ -0,0 +1,28 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for trait-system-refactor-initiative#159. We need to make sure +// that computing the implied assumptions of `wat` does not look into the hidden +// type `impl Sized`, as doing so adds a `T: 'static` implied bound which +// its caller does not have to prove. + +fn into_y(t: T) -> impl Sized +where + T: 'static, +{ + t +} +fn wat(t: T) -> impl Sized + 'static { + //[next]~^ ERROR the parameter type `T` may not live long enough + into_y(t) //~ ERROR the parameter type `T` may not live long enough +} + +fn leak(t: &T) -> &'static T { + *(&wat(t) as &dyn std::any::Any).downcast_ref().unwrap() +} + +fn main() { + let buf = leak(&vec![vec![1]]); + dbg!(buf[0][0]); +} diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-3.current.stderr b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-3.current.stderr new file mode 100644 index 0000000000000..0bbd76e54fd4b --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-3.current.stderr @@ -0,0 +1,75 @@ +error[E0310]: the associated type `::Assoc` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:5 + | +LL | (Box::new(x), Outlives::<'static, ::Assoc>(None)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the associated type `::Assoc` must be valid for the static lifetime... + | ...so that the type `::Assoc` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: ::Assoc) -> (Box, impl Sized) where ::Assoc: 'static { + | ++++++++++++++++++++++++++++++++++ + +error[E0310]: the associated type `::Assoc` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:6 + | +LL | (Box::new(x), Outlives::<'static, ::Assoc>(None)) + | ^^^^^^^^^^^ + | | + | the associated type `::Assoc` must be valid for the static lifetime... + | ...so that the type `::Assoc` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: ::Assoc) -> (Box, impl Sized) where ::Assoc: 'static { + | ++++++++++++++++++++++++++++++++++ + +error[E0310]: the associated type `::Assoc` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:6 + | +LL | (Box::new(x), Outlives::<'static, ::Assoc>(None)) + | ^^^^^^^^^^^ + | | + | the associated type `::Assoc` must be valid for the static lifetime... + | ...so that the type `::Assoc` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: ::Assoc) -> (Box, impl Sized) where ::Assoc: 'static { + | ++++++++++++++++++++++++++++++++++ + +error[E0310]: the associated type `::Assoc` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:19 + | +LL | (Box::new(x), Outlives::<'static, ::Assoc>(None)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the associated type `::Assoc` must be valid for the static lifetime... + | ...so that the type `::Assoc` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: ::Assoc) -> (Box, impl Sized) where ::Assoc: 'static { + | ++++++++++++++++++++++++++++++++++ + +error[E0310]: the associated type `::Assoc` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:19 + | +LL | (Box::new(x), Outlives::<'static, ::Assoc>(None)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the associated type `::Assoc` must be valid for the static lifetime... + | ...so that the type `::Assoc` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: ::Assoc) -> (Box, impl Sized) where ::Assoc: 'static { + | ++++++++++++++++++++++++++++++++++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-3.next.stderr b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-3.next.stderr new file mode 100644 index 0000000000000..813e682eaa939 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-3.next.stderr @@ -0,0 +1,75 @@ +error[E0310]: the associated type `::Assoc` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-3.rs:28:1 + | +LL | fn foo(x: ::Assoc) -> (Box, impl Sized) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the associated type `::Assoc` must be valid for the static lifetime... + | ...so that the type `::Assoc` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: ::Assoc) -> (Box, impl Sized) where ::Assoc: 'static { + | ++++++++++++++++++++++++++++++++++ + +error[E0310]: the associated type `::Assoc` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:6 + | +LL | (Box::new(x), Outlives::<'static, ::Assoc>(None)) + | ^^^^^^^^^^^ + | | + | the associated type `::Assoc` must be valid for the static lifetime... + | ...so that the type `::Assoc` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: ::Assoc) -> (Box, impl Sized) where ::Assoc: 'static { + | ++++++++++++++++++++++++++++++++++ + +error[E0310]: the associated type `::Assoc` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:6 + | +LL | (Box::new(x), Outlives::<'static, ::Assoc>(None)) + | ^^^^^^^^^^^ + | | + | the associated type `::Assoc` must be valid for the static lifetime... + | ...so that the type `::Assoc` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: ::Assoc) -> (Box, impl Sized) where ::Assoc: 'static { + | ++++++++++++++++++++++++++++++++++ + +error[E0310]: the associated type `::Assoc` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:19 + | +LL | (Box::new(x), Outlives::<'static, ::Assoc>(None)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the associated type `::Assoc` must be valid for the static lifetime... + | ...so that the type `::Assoc` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: ::Assoc) -> (Box, impl Sized) where ::Assoc: 'static { + | ++++++++++++++++++++++++++++++++++ + +error[E0310]: the associated type `::Assoc` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-3.rs:30:19 + | +LL | (Box::new(x), Outlives::<'static, ::Assoc>(None)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the associated type `::Assoc` must be valid for the static lifetime... + | ...so that the type `::Assoc` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: ::Assoc) -> (Box, impl Sized) where ::Assoc: 'static { + | ++++++++++++++++++++++++++++++++++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-3.rs b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-3.rs new file mode 100644 index 0000000000000..f2ddc2c6c7c21 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-3.rs @@ -0,0 +1,44 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// The original regression test for trait-system-refactor-initiative#159. +// Unlike the other tests here the hidden type has a fresh region var which +// makes the implied bound `::Assoc: 'infer_var`. While this +// variable will end up equal to `'static` later on, we don't really support +// non alias-outlives assumptions with non-universal variables in them. This +// makes this test more involved than the others. + +use std::any::Any; + +struct Outlives<'a, T>(Option<&'a T>); +trait Trait { + type Assoc; +} + +impl Trait for T { + type Assoc = T; +} + +// Computing the implied bounds for `foo` normalizes `impl Sized` to +// `Outlives::<'static, ::Assoc>`, adding the implied bound +// `::Assoc: 'static`. +// +// The caller does not have to prove that bound. +fn foo(x: ::Assoc) -> (Box, impl Sized) { + //[next]~^ ERROR the associated type `::Assoc` may not live long enough + (Box::new(x), Outlives::<'static, ::Assoc>(None)) + //~^ ERROR the associated type `::Assoc` may not live long enough + //~| ERROR the associated type `::Assoc` may not live long enough + //~| ERROR the associated type `::Assoc` may not live long enough + //~| ERROR the associated type `::Assoc` may not live long enough + //[current]~| ERROR the associated type `::Assoc` may not live long enough +} + +fn main() { + let string = String::from("temporary"); + let (any, _proof) = foo::<&str>(string.as_str()); + drop(_proof); + drop(string); + println!("{}", any.downcast_ref::<&str>().unwrap()); +} diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-pass.rs b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-pass.rs new file mode 100644 index 0000000000000..3bbf200f3fb3d --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-pass.rs @@ -0,0 +1,38 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ edition: 2024 +//@ check-pass + +// Regression test for the `typesensei` crater breakage caused by +// trait-system-refactor-initiative#159. Getting an incorrect +// `batch_action::{opaque}: 'a` implied bound means there are now +// two ways to prove that `Action<'a, batch_action::{opaque}>` is +// well-formed. This causes us to emit a type test instead of a +// region constraint, causing this to fail as type tests are checked +// on the frozen region graph. + +use std::{future::Future, marker::PhantomData}; + +pub fn batch_emplace<'a>(s: &'a str) -> Action<'a, impl Future + 'a> { + if false { + let n: Action<'a, _> = loop {}; + n + } else { + new(s, batch_action(s)) + } +} + +// The outlive bound is necessary. +pub struct Action<'a, Fut: 'a> { + _phantom: PhantomData<(&'a str, Fut)>, +} +fn new<'a, Fut>(api: &'a str, fut: Fut) -> Action<'a, Fut> { + loop {} +} + +fn batch_action<'a>(s: &'a str) -> impl Future + 'a { + async {} +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-rpitit.current.stderr b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-rpitit.current.stderr new file mode 100644 index 0000000000000..96609458e51b9 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-rpitit.current.stderr @@ -0,0 +1,117 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:22:9 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:22:10 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:22:10 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:22:23 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:34:9 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:34:10 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:34:10 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:34:23 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-rpitit.next.stderr b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-rpitit.next.stderr new file mode 100644 index 0000000000000..4b98cf1c352fb --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-rpitit.next.stderr @@ -0,0 +1,117 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:20:5 + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:22:10 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:22:10 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:22:23 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:32:5 + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:34:10 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:34:10 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty-rpitit.rs:34:23 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-rpitit.rs b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-rpitit.rs new file mode 100644 index 0000000000000..f1452a1aade04 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty-rpitit.rs @@ -0,0 +1,49 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for trait-system-refactor-initiative#159. We need to make sure +// that computing the implied assumptions of `foo` does not look into the hidden +// type of `impl Sized`, as doing so adds a `T: 'static` implied bound which +// its caller does not have to prove. +// +// In this test the opaque is introduced via an RPITIT synthetic associated type +// in the signature and a `Projection(synthetic_assoc_ty, opaque_ty)` clause in the +// `ParamEnv`. We're initially fixing this bug by incorrectly marking opaque types +// as rigid. This test makes sure we also do so for opaque types in the `ParamEnv`. + +use std::any::Any; + +struct Outlives(Option); + +trait Trait { + fn foo(x: T) -> (Box, impl Sized) { + //[next]~^ ERROR the parameter type `T` may not live long enough + (Box::new(x), Outlives::(None)) + //~^ ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //[current]~| ERROR the parameter type `T` may not live long enough + } +} + +impl Trait for i32 {} +impl Trait for u32 { + fn foo(x: T) -> (Box, impl Sized) { + //[next]~^ ERROR the parameter type `T` may not live long enough + (Box::new(x), Outlives::(None)) + //~^ ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //[current]~| ERROR the parameter type `T` may not live long enough + } +} + + +fn main() { + let any = ::foo(String::from("temporary").as_str()).0; + println!("{}", any.downcast_ref::<&str>().unwrap()); + + let any = ::foo(String::from("temporary").as_str()).0; + println!("{}", any.downcast_ref::<&str>().unwrap()); +} diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty.current.stderr b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty.current.stderr new file mode 100644 index 0000000000000..fc3a4ed9e6cd3 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty.current.stderr @@ -0,0 +1,60 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty.rs:15:5 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty.rs:15:6 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty.rs:15:6 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty.rs:15:19 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty.next.stderr b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty.next.stderr new file mode 100644 index 0000000000000..caa6c316d169c --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty.next.stderr @@ -0,0 +1,60 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty.rs:13:1 + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty.rs:15:6 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty.rs:15:6 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-leak-hidden-ty.rs:15:19 + | +LL | (Box::new(x), Outlives::(None)) + | ^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo(x: T) -> (Box, impl Sized) { + | +++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty.rs b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty.rs new file mode 100644 index 0000000000000..cf03b17fbaed7 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/implied-bounds-leak-hidden-ty.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for trait-system-refactor-initiative#159. We need to make sure +// that computing the implied assumptions of `foo` does not look into the hidden +// type of `impl Sized`, as doing so adds a `T: 'static` implied bound which +// its caller does not have to prove. + +use std::any::Any; + +struct Outlives(Option); +fn foo(x: T) -> (Box, impl Sized) { + //[next]~^ ERROR the parameter type `T` may not live long enough + (Box::new(x), Outlives::(None)) + //~^ ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //[current]~| ERROR the parameter type `T` may not live long enough +} + +fn main() { + let any = foo(String::from("temporary").as_str()).0; + println!("{}", any.downcast_ref::<&str>().unwrap()); +}