diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 298bff99844..845bbdca96a 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -402,39 +402,29 @@ fn check_opaque_meets_bounds<'tcx>( let guar = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(guar); } - match origin { - // Checked when type checking the function containing them. - hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => { - // HACK: this should also fall through to the hidden type check below, but the original - // implementation had a bug where equivalent lifetimes are not identical. This caused us - // to reject existing stable code that is otherwise completely fine. The real fix is to - // compare the hidden types via our type equivalence/relation infra instead of doing an - // identity check. - let _ = infcx.take_opaque_types(); - return Ok(()); - } - // Nested opaque types occur only in associated types: - // ` type Opaque = impl Trait<&'static T, AssocTy = impl Nested>; ` - // They can only be referenced as ` as Trait<&'static T>>::AssocTy`. - // We don't have to check them here because their well-formedness follows from the WF of - // the projection input types in the defining- and use-sites. - hir::OpaqueTyOrigin::TyAlias { .. } - if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {} - // Can have different predicates to their defining use - hir::OpaqueTyOrigin::TyAlias { .. } => { - let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?; - let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, &wf_tys); - let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?; + + let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, defining_use_anchor)?; + let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, &wf_tys); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?; + + if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin { + // HACK: this should also fall through to the hidden type check below, but the original + // implementation had a bug where equivalent lifetimes are not identical. This caused us + // to reject existing stable code that is otherwise completely fine. The real fix is to + // compare the hidden types via our type equivalence/relation infra instead of doing an + // identity check. + let _ = infcx.take_opaque_types(); + Ok(()) + } else { + // Check that any hidden types found during wf checking match the hidden types that `type_of` sees. + for (mut key, mut ty) in infcx.take_opaque_types() { + ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty); + key = infcx.resolve_vars_if_possible(key); + sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?; } + Ok(()) } - // Check that any hidden types found during wf checking match the hidden types that `type_of` sees. - for (mut key, mut ty) in infcx.take_opaque_types() { - ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty); - key = infcx.resolve_vars_if_possible(key); - sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?; - } - Ok(()) } fn sanity_check_found_hidden_type<'tcx>( @@ -1549,6 +1539,8 @@ fn opaque_type_cycle_error( err.emit() } +// FIXME(@lcnr): This should not be computed per coroutine, but instead once for +// each typeck root. pub(super) fn check_coroutine_obligations( tcx: TyCtxt<'_>, def_id: LocalDefId, @@ -1556,7 +1548,7 @@ pub(super) fn check_coroutine_obligations( debug_assert!(tcx.is_coroutine(def_id.to_def_id())); let typeck = tcx.typeck(def_id); - let param_env = tcx.param_env(def_id); + let param_env = tcx.param_env(typeck.hir_owner.def_id); let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id]; debug!(?coroutine_interior_predicates); diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 68b6a2f62fb..b6f3c38cb3f 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -592,8 +592,25 @@ impl<'tcx> InferCtxt<'tcx> { obligations: &mut Vec>, ) { let tcx = self.tcx; - let item_bounds = tcx.explicit_item_bounds(def_id); + // Require that the hidden type is well-formed. We have to + // make sure we wf-check the hidden type to fix #114728. + // + // However, we don't check that all types are well-formed. + // We only do so for types provided by the user or if they are + // "used", e.g. for method selection. + // + // This means we never check the wf requirements of the hidden + // type during MIR borrowck, causing us to infer the wrong + // lifetime for its member constraints which then results in + // unexpected region errors. + obligations.push(traits::Obligation::new( + tcx, + cause.clone(), + param_env, + ty::ClauseKind::WellFormed(hidden_ty.into()), + )); + let item_bounds = tcx.explicit_item_bounds(def_id); for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) { let predicate = predicate.fold_with(&mut BottomUpFolder { tcx, diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 3f9bd509b08..191671bcc1e 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -121,18 +121,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' } } DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)), - DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) { - DefKind::TyAlias => ty::List::empty(), - DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)), - // Nested opaque types only occur in associated types: - // ` type Opaque = impl Trait<&'static T, AssocTy = impl Nested>; ` - // assumed_wf_types should include those of `Opaque`, `Opaque` itself - // and `&'static T`. - DefKind::OpaqueTy => bug!("unimplemented implied bounds for nested opaque types"), - def_kind => { - bug!("unimplemented implied bounds for opaque types with parent {def_kind:?}") - } - }, + DefKind::OpaqueTy => bug!("implied bounds are not defined for opaques"), DefKind::Mod | DefKind::Struct | DefKind::Union diff --git a/tests/ui/closures/issue-78720.rs b/tests/ui/closures/issue-78720.rs index 0e1f78ae3c6..0c4f337ba57 100644 --- a/tests/ui/closures/issue-78720.rs +++ b/tests/ui/closures/issue-78720.rs @@ -1,7 +1,7 @@ fn server() -> impl { -//~^ ERROR at least one trait must be specified + //~^ ERROR at least one trait must be specified + //~| ERROR type annotations needed ().map2(|| "") - //~^ ERROR type annotations needed } trait FilterBase2 { diff --git a/tests/ui/closures/issue-78720.stderr b/tests/ui/closures/issue-78720.stderr index d8d3811af5a..2f57c7616f1 100644 --- a/tests/ui/closures/issue-78720.stderr +++ b/tests/ui/closures/issue-78720.stderr @@ -23,10 +23,10 @@ LL | struct Map2 { | +++ error[E0282]: type annotations needed - --> $DIR/issue-78720.rs:3:5 + --> $DIR/issue-78720.rs:1:16 | -LL | ().map2(|| "") - | ^^^^^^^^^^^^^^ cannot infer type +LL | fn server() -> impl { + | ^^^^ cannot infer type error[E0308]: mismatched types --> $DIR/issue-78720.rs:8:39 diff --git a/tests/ui/impl-trait/issues/issue-86800.rs b/tests/ui/impl-trait/issues/issue-86800.rs index ae6e198c2ad..172ab04f58d 100644 --- a/tests/ui/impl-trait/issues/issue-86800.rs +++ b/tests/ui/impl-trait/issues/issue-86800.rs @@ -1,12 +1,6 @@ #![feature(type_alias_impl_trait)] //@ edition:2021 -//@ compile-flags:-Z treat-err-as-bug=2 -//@ error-pattern: due to `-Z treat-err-as-bug=2 -//@ failure-status:101 -//@ normalize-stderr-test ".*note: .*\n\n" -> "" -//@ normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> "" -//@ rustc-env:RUST_BACKTRACE=0 use std::future::Future; @@ -29,6 +23,7 @@ struct Context { type TransactionResult = Result; type TransactionFuture<'__, O> = impl '__ + Future>; +//~^ ERROR unconstrained opaque type fn execute_transaction_fut<'f, F, O>( f: F, @@ -37,6 +32,7 @@ where F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f { f + //~^ ERROR expected generic lifetime parameter, found `'_` } impl Context { @@ -44,6 +40,7 @@ impl Context { &self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> ) -> TransactionResult { + //~^ ERROR expected generic lifetime parameter, found `'_` let mut conn = Connection {}; let mut transaction = TestTransaction { conn: &mut conn }; f(&mut transaction).await diff --git a/tests/ui/impl-trait/issues/issue-86800.stderr b/tests/ui/impl-trait/issues/issue-86800.stderr index 7af4846a959..146d2f67942 100644 --- a/tests/ui/impl-trait/issues/issue-86800.stderr +++ b/tests/ui/impl-trait/issues/issue-86800.stderr @@ -1,11 +1,13 @@ error: unconstrained opaque type - --> $DIR/issue-86800.rs:31:34 + --> $DIR/issue-86800.rs:25:34 | LL | type TransactionFuture<'__, O> = impl '__ + Future>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -error: internal compiler error[E0792]: expected generic lifetime parameter, found `'_` - --> $DIR/issue-86800.rs:39:5 + = note: `TransactionFuture` must be used in combination with a concrete type within the same module + +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/issue-86800.rs:34:5 | LL | type TransactionFuture<'__, O> = impl '__ + Future>; | --- this generic parameter must be used with a generic lifetime parameter @@ -13,9 +15,20 @@ LL | type TransactionFuture<'__, O> = impl '__ + Future $DIR/issue-86800.rs:42:5 + | +LL | type TransactionFuture<'__, O> = impl '__ + Future>; + | --- this generic parameter must be used with a generic lifetime parameter +... +LL | / { +LL | | +LL | | let mut conn = Connection {}; +LL | | let mut transaction = TestTransaction { conn: &mut conn }; +LL | | f(&mut transaction).await +LL | | } + | |_____^ -query stack during panic: -#0 [mir_borrowck] borrow-checking `execute_transaction_fut` -#1 [type_of_opaque] computing type of opaque `execute_transaction_fut::{opaque#0}` -end of query stack +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr index fee3b86034a..4a5e4bfe94b 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr @@ -1,9 +1,9 @@ error[E0282]: type annotations needed - --> $DIR/recursive-coroutine-boxed.rs:10:23 + --> $DIR/recursive-coroutine-boxed.rs:11: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 | @@ -13,10 +13,10 @@ LL | let mut gen = Box::::pin(foo()); | +++++ error[E0282]: type annotations needed - --> $DIR/recursive-coroutine-boxed.rs:10:32 + --> $DIR/recursive-coroutine-boxed.rs:8:13 | -LL | let mut gen = Box::pin(foo()); - | ^^^^^ cannot infer type for opaque type `impl Coroutine` +LL | fn foo() -> impl Coroutine { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for opaque type `impl Coroutine` error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs index a42ae68f28e..8f0bbb400cf 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.rs +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.rs @@ -6,10 +6,10 @@ use std::ops::{Coroutine, CoroutineState}; fn foo() -> impl Coroutine { + //[next]~^ ERROR type annotations needed || { let mut gen = Box::pin(foo()); //[next]~^ ERROR type annotations needed - //[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/wf-check-hidden-type.rs b/tests/ui/impl-trait/wf-check-hidden-type.rs new file mode 100644 index 00000000000..c3b1182a98f --- /dev/null +++ b/tests/ui/impl-trait/wf-check-hidden-type.rs @@ -0,0 +1,20 @@ +//! Regression test for #114728. + +trait Extend<'a, 'b> { + fn extend(self, _: &'a str) -> &'b str; +} + +impl<'a, 'b> Extend<'a, 'b> for Option<&'b &'a ()> { + fn extend(self, s: &'a str) -> &'b str { + s + } +} + +fn boom<'a, 'b>() -> impl Extend<'a, 'b> { + None::<&'_ &'_ ()> //~ ERROR lifetime may not live long enough +} + +fn main() { + let y = boom().extend(&String::from("temporary")); + println!("{}", y); +} diff --git a/tests/ui/impl-trait/wf-check-hidden-type.stderr b/tests/ui/impl-trait/wf-check-hidden-type.stderr new file mode 100644 index 00000000000..86ba7aff54a --- /dev/null +++ b/tests/ui/impl-trait/wf-check-hidden-type.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/wf-check-hidden-type.rs:14:5 + | +LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | None::<&'_ &'_ ()> + | ^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to 1 previous error + diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs index 03913869503..85eeb5d4c90 100644 --- a/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs +++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs @@ -6,6 +6,7 @@ use std::future::Future; async fn wrapper(f: F) //~^ ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` //~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` +//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32` where F:, for<'a> >::Output: Future + 'a, diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr index 89ebdb57f3c..578ba149baf 100644 --- a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr +++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr @@ -4,6 +4,7 @@ error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` LL | / async fn wrapper(f: F) LL | | LL | | +LL | | LL | | where LL | | F:, LL | | for<'a> >::Output: Future + 'a, @@ -20,7 +21,21 @@ LL | async fn wrapper(f: F) = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` - --> $DIR/issue-76168-hr-outlives-3.rs:12:1 + --> $DIR/issue-76168-hr-outlives-3.rs:6:1 + | +LL | / async fn wrapper(f: F) +LL | | +LL | | +LL | | +LL | | where +LL | | F:, +LL | | for<'a> >::Output: Future + 'a, + | |__________________________________________________________________________^ expected an `FnOnce(&'a mut i32)` closure, found `i32` + | + = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` + +error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32` + --> $DIR/issue-76168-hr-outlives-3.rs:13:1 | LL | / { LL | | @@ -31,6 +46,6 @@ LL | | } | = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr b/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr index 3a4415ed23a..6c259621466 100644 --- a/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr +++ b/tests/ui/traits/non_lifetime_binders/type-match-with-late-bound.stderr @@ -21,6 +21,20 @@ help: consider adding an explicit lifetime bound LL | for F: 'a, !1_"F": 'a | ~~~~~~~~~~~~ -error: aborting due to 1 previous error; 1 warning emitted +error[E0309]: the placeholder type `!2_"F"` may not live long enough + --> $DIR/type-match-with-late-bound.rs:11:1 + | +LL | async fn walk2<'a, T: 'a>(_: T) + | -- the placeholder type `!2_"F"` must be valid for the lifetime `'a` as defined here... +... +LL | {} + | ^^ ...so that the type `F` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | for F: 'a, !2_"F": 'a + | ~~~~~~~~~~~~ + +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0309`. diff --git a/tests/ui/type-alias-impl-trait/issue-90400-2.stderr b/tests/ui/type-alias-impl-trait/issue-90400-2.stderr index 5e978e97d6b..b4b78f8175f 100644 --- a/tests/ui/type-alias-impl-trait/issue-90400-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-90400-2.stderr @@ -2,15 +2,13 @@ error[E0277]: the trait bound `B: Bar` is not satisfied --> $DIR/issue-90400-2.rs:25:9 | LL | MyBaz(bar) - | ^^^^^^^^^^ the trait `Bar` is not implemented for `B`, which is required by `MyBaz: Baz` + | ^^^^^^^^^^ the trait `Bar` is not implemented for `B` | -note: required for `MyBaz` to implement `Baz` - --> $DIR/issue-90400-2.rs:30:14 +note: required by a bound in `MyBaz` + --> $DIR/issue-90400-2.rs:29:17 | -LL | impl Baz for MyBaz { - | --- ^^^ ^^^^^^^^ - | | - | unsatisfied trait bound introduced here +LL | struct MyBaz(B); + | ^^^ required by this bound in `MyBaz` help: consider restricting type parameter `B` | LL | type FooFn = impl Baz; diff --git a/tests/ui/type-alias-impl-trait/wf-check-definition-site.rs b/tests/ui/type-alias-impl-trait/wf-check-definition-site.rs new file mode 100644 index 00000000000..19dd4c17936 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/wf-check-definition-site.rs @@ -0,0 +1,40 @@ +//@ check-pass + +// Regression test for #114572, We were inferring an ill-formed type: +// +// `Opaque<'a> = Static<&'a str>`, vs +// `Opaque<'a> = Static<&'static str>`. +// +// The hidden type of the opaque ends up as `Static<'?0 str>`. When +// computing member constraints we end up choosing `'a` for `?0` unless +// `?0` is already required to outlive `'a`. We achieve this by checking +// that `Static<'?0 str>` is well-formed. +#![feature(type_alias_impl_trait)] + +struct Static(T); + +type OpaqueRet<'a> = impl Sized + 'a; +fn test_return<'a>(msg: Static<&'static u8>) -> OpaqueRet<'a> { + msg +} + +fn test_rpit<'a>(msg: Static<&'static u8>) -> impl Sized + 'a { + msg +} + +type OpaqueAssign<'a> = impl Sized + 'a; +fn test_assign<'a>(msg: Static<&'static u8>) -> Option> { + let _: OpaqueAssign<'a> = msg; + None +} + +// `OpaqueRef<'a, T> = Ref<'a, T>`, vs +// `OpaqueRef<'a, T> = Ref<'static, T>`. +trait RefAt<'a>: 'a {} +struct Ref<'a, T: RefAt<'a>>(&'a T); +type OpaqueRef<'a, T: RefAt<'static>> = impl Sized + 'a; +fn test_trait<'a, T: RefAt<'static>>(msg: Ref<'static, T>) -> OpaqueRef<'a, T> { + msg +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr b/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr index 17c1f8897bf..79b726f83dd 100644 --- a/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr +++ b/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr @@ -1,21 +1,16 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-nested.rs:57:27 + --> $DIR/wf-nested.rs:64:38 | -LL | type InnerOpaque = impl Sized; - | ^^^^^^^^^^ - | | - | the parameter type `T` must be valid for the static lifetime... - | ...so that the type `T` will meet its required lifetime bounds... +LL | fn define() -> OuterOpaque {} + | ^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds | -note: ...that is required by this bound - --> $DIR/wf-nested.rs:12:20 - | -LL | struct IsStatic(T); - | ^^^^^^^ help: consider adding an explicit lifetime bound | -LL | type InnerOpaque = impl Sized; - | +++++++++ +LL | fn define() -> OuterOpaque {} + | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/wf-nested.pass.stderr b/tests/ui/type-alias-impl-trait/wf-nested.pass.stderr new file mode 100644 index 00000000000..b61b69d8e40 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/wf-nested.pass.stderr @@ -0,0 +1,31 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/wf-nested.rs:34:38 + | +LL | fn define() -> OuterOpaque {} + | ^^ + | | + | 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 define() -> OuterOpaque {} + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/wf-nested.rs:37:69 + | +LL | fn define_rpit() -> impl Trait<&'static T, Out = 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 define_rpit() -> impl Trait<&'static T, Out = impl Sized> {} + | +++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr b/tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr index f5d3a218542..dbd3a1394f8 100644 --- a/tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr +++ b/tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr @@ -1,5 +1,19 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-nested.rs:46:17 + --> $DIR/wf-nested.rs:46:38 + | +LL | fn define() -> OuterOpaque {} + | ^^ + | | + | 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 define() -> OuterOpaque {} + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/wf-nested.rs:51:17 | LL | let _ = outer.get(); | ^^^^^^^^^^^ @@ -13,7 +27,7 @@ LL | fn test() { | +++++++++ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-nested.rs:46:17 + --> $DIR/wf-nested.rs:51:17 | LL | let _ = outer.get(); | ^^^^^^^^^^^ @@ -27,6 +41,6 @@ help: consider adding an explicit lifetime bound LL | fn test() { | +++++++++ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/type-alias-impl-trait/wf-nested.rs b/tests/ui/type-alias-impl-trait/wf-nested.rs index 1fc93a3cd27..56c524c6db0 100644 --- a/tests/ui/type-alias-impl-trait/wf-nested.rs +++ b/tests/ui/type-alias-impl-trait/wf-nested.rs @@ -1,12 +1,8 @@ // Well-formedness of nested opaque types, i.e. `impl Sized` in -// `type Outer = impl Trait`. -// See the comments below. -// -//@ revisions: pass pass_sound fail -//@ [pass] check-pass -//@ [pass_sound] check-fail -//@ [fail] check-fail - +// `type Outer = impl Trait`. We check that +// the nested type is well-formed, even though this would also +// be implied by the item bounds of the opaque being +// well-formed. See the comments below. #![feature(type_alias_impl_trait)] struct IsStatic(T); @@ -23,40 +19,26 @@ impl Trait<&'static T> for () { type Out = IsStatic; } -// The hidden type for `impl Sized` is `IsStatic`, which requires `T: 'static`. -// We know it is well-formed because it can *only* be referenced as a projection: -// as Trait<&'static T>>::Out`. -// So any instantiation of the type already requires proving `T: 'static`. -#[cfg(pass)] -mod pass { - use super::*; - type OuterOpaque = impl Trait<&'static T, Out = impl Sized>; - fn define() -> OuterOpaque {} -} -// Test the soundness of `pass` - We should require `T: 'static` at the use site. -#[cfg(pass_sound)] -mod pass_sound { - use super::*; - type OuterOpaque = impl Trait<&'static T, Out = impl Sized>; - fn define() -> OuterOpaque {} +// We could theoretically allow this (and previously did), as even +// though the nested opaque is not well-formed, it can only be +// used by normalizing the projection +// as Trait<&'static T>>::Out +// Assuming that we check that this projection is well-formed, the wf +// of the nested opaque is implied. +type OuterOpaque1 = impl Trait<&'static T, Out = impl Sized>; +fn define() -> OuterOpaque1 {} +//~^ ERROR `T` may not live long enough - fn test() { - let outer = define::(); - let _ = outer.get(); - //[pass_sound]~^ ERROR `T` may not live long enough - //[pass_sound]~| ERROR `T` may not live long enough - } -} +fn define_rpit() -> impl Trait<&'static T, Out = impl Sized> {} +//~^ ERROR the parameter type `T` may not live long enough -// Similar to `pass` but here `impl Sized` can be referenced directly as -// InnerOpaque, so we require an explicit bound `T: 'static`. -#[cfg(fail)] -mod fail { - use super::*; - type InnerOpaque = impl Sized; //[fail]~ ERROR `T` may not live long enough - type OuterOpaque = impl Trait<&'static T, Out = InnerOpaque>; - fn define() -> OuterOpaque {} -} +// Similar to `define` but here `impl Sized` can be referenced directly as +// InnerOpaque, so the `'static` bound is definitely required for +// soundness. +type InnerOpaque = impl Sized; +type OuterOpaque2 = impl Trait<&'static T, Out = InnerOpaque>; +fn define_nested_rpit() -> OuterOpaque2 {} +//~^ ERROR the parameter type `T` may not live long enough fn main() {} diff --git a/tests/ui/type-alias-impl-trait/wf-nested.stderr b/tests/ui/type-alias-impl-trait/wf-nested.stderr new file mode 100644 index 00000000000..6d50e11c5da --- /dev/null +++ b/tests/ui/type-alias-impl-trait/wf-nested.stderr @@ -0,0 +1,45 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/wf-nested.rs:30:35 + | +LL | fn define() -> OuterOpaque1 {} + | ^^ + | | + | 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 define() -> OuterOpaque1 {} + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/wf-nested.rs:33:65 + | +LL | fn define_rpit() -> impl Trait<&'static T, Out = 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 define_rpit() -> impl Trait<&'static T, Out = impl Sized> {} + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/wf-nested.rs:41:47 + | +LL | fn define_nested_rpit() -> OuterOpaque2 {} + | ^^ + | | + | 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 define_nested_rpit() -> OuterOpaque2 {} + | +++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0310`.