From 93bc7a428cdf64a822274f7c5647ad46f8ecf122 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 27 Feb 2024 15:00:22 +0100 Subject: [PATCH 1/5] wf-check RPITs --- .../rustc_hir_analysis/src/check/check.rs | 39 +++++++------ compiler/rustc_ty_utils/src/implied_bounds.rs | 13 +---- tests/ui/impl-trait/wf-check-hidden-type.rs | 21 +++++++ .../ui/impl-trait/wf-check-hidden-type.stderr | 20 +++++++ .../wf-check-definition-site.rs | 37 +++++++++++++ .../wf-check-definition-site.stderr | 55 +++++++++++++++++++ .../wf-nested.fail.stderr | 2 +- .../wf-nested.pass.stderr | 22 ++++++++ .../wf-nested.pass_sound.stderr | 4 +- tests/ui/type-alias-impl-trait/wf-nested.rs | 5 +- 10 files changed, 184 insertions(+), 34 deletions(-) create mode 100644 tests/ui/impl-trait/wf-check-hidden-type.rs create mode 100644 tests/ui/impl-trait/wf-check-hidden-type.stderr create mode 100644 tests/ui/type-alias-impl-trait/wf-check-definition-site.rs create mode 100644 tests/ui/type-alias-impl-trait/wf-check-definition-site.stderr create mode 100644 tests/ui/type-alias-impl-trait/wf-nested.pass.stderr diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 3d9aa428c743c..1a3aa95743c96 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -403,16 +403,6 @@ fn check_opaque_meets_bounds<'tcx>( 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`. @@ -421,20 +411,33 @@ fn check_opaque_meets_bounds<'tcx>( 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)?; + hir::OpaqueTyOrigin::TyAlias { .. } + | hir::OpaqueTyOrigin::FnReturn(..) + | hir::OpaqueTyOrigin::AsyncFn(..) => { + 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)?; } } - // 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)?; + + 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(()) } - Ok(()) } fn sanity_check_found_hidden_type<'tcx>( diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 3f9bd509b087c..191671bcc1edd 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/impl-trait/wf-check-hidden-type.rs b/tests/ui/impl-trait/wf-check-hidden-type.rs new file mode 100644 index 0000000000000..29f15024d7664 --- /dev/null +++ b/tests/ui/impl-trait/wf-check-hidden-type.rs @@ -0,0 +1,21 @@ +//! 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> { + //~^ ERROR in type `&'b &'a ()`, reference has a longer lifetime than the data it references + None::<&'_ &'_ ()> +} + +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 0000000000000..10c766c268ceb --- /dev/null +++ b/tests/ui/impl-trait/wf-check-hidden-type.stderr @@ -0,0 +1,20 @@ +error[E0491]: in type `&'b &'a ()`, reference has a longer lifetime than the data it references + --> $DIR/wf-check-hidden-type.rs:13:22 + | +LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> { + | ^^^^^^^^^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime `'b` as defined here + --> $DIR/wf-check-hidden-type.rs:13:13 + | +LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> { + | ^^ +note: but the referenced data is only valid for the lifetime `'a` as defined here + --> $DIR/wf-check-hidden-type.rs:13:9 + | +LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> { + | ^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0491`. 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 0000000000000..2b5c9781a96f8 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/wf-check-definition-site.rs @@ -0,0 +1,37 @@ +// Regression test for #114572, We were inferring an ill-formed type: +// +// `Opaque<'a> = Static<&'a str>`, vs +// `Opaque<'a> = Static<&'static str>`. +#![feature(type_alias_impl_trait)] + +struct Static(T); + +type OpaqueRet<'a> = impl Sized + 'a; +//~^ ERROR the type `&'a u8` does not fulfill the required lifetime +fn test_return<'a>(msg: Static<&'static u8>) -> OpaqueRet<'a> { + msg +} + +fn test_rpit<'a>(msg: Static<&'static u8>) -> impl Sized + 'a { + //~^ ERROR the type `&'a u8` does not fulfill the required lifetime + msg +} + +type OpaqueAssign<'a> = impl Sized + 'a; +//~^ ERROR the type `&'a u8` does not fulfill the required lifetime +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; +//~^ ERROR mismatched types +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-check-definition-site.stderr b/tests/ui/type-alias-impl-trait/wf-check-definition-site.stderr new file mode 100644 index 0000000000000..a51c6bb2ec090 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/wf-check-definition-site.stderr @@ -0,0 +1,55 @@ +error[E0477]: the type `&'a u8` does not fulfill the required lifetime + --> $DIR/wf-check-definition-site.rs:9:22 + | +LL | type OpaqueRet<'a> = impl Sized + 'a; + | ^^^^^^^^^^^^^^^ + | +note: type must satisfy the static lifetime as required by this binding + --> $DIR/wf-check-definition-site.rs:7:18 + | +LL | struct Static(T); + | ^^^^^^^ + +error[E0477]: the type `&'a u8` does not fulfill the required lifetime + --> $DIR/wf-check-definition-site.rs:15:47 + | +LL | fn test_rpit<'a>(msg: Static<&'static u8>) -> impl Sized + 'a { + | ^^^^^^^^^^^^^^^ + | +note: type must satisfy the static lifetime as required by this binding + --> $DIR/wf-check-definition-site.rs:7:18 + | +LL | struct Static(T); + | ^^^^^^^ + +error[E0477]: the type `&'a u8` does not fulfill the required lifetime + --> $DIR/wf-check-definition-site.rs:20:25 + | +LL | type OpaqueAssign<'a> = impl Sized + 'a; + | ^^^^^^^^^^^^^^^ + | +note: type must satisfy the static lifetime as required by this binding + --> $DIR/wf-check-definition-site.rs:7:18 + | +LL | struct Static(T); + | ^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/wf-check-definition-site.rs:31:41 + | +LL | type OpaqueRef<'a, T: RefAt<'static>> = impl Sized + 'a; + | ^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected trait `RefAt<'a>` + found trait `RefAt<'static>` +note: the lifetime `'a` as defined here... + --> $DIR/wf-check-definition-site.rs:31:16 + | +LL | type OpaqueRef<'a, T: RefAt<'static>> = impl Sized + 'a; + | ^^ + = note: ...does not necessarily outlive the static lifetime + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0477. +For more information about an error, try `rustc --explain E0308`. 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 17c1f8897bf0c..dd6b5a166ec45 100644 --- a/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr +++ b/tests/ui/type-alias-impl-trait/wf-nested.fail.stderr @@ -1,5 +1,5 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-nested.rs:57:27 + --> $DIR/wf-nested.rs:60:27 | LL | type InnerOpaque = impl Sized; | ^^^^^^^^^^ 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 0000000000000..820710afef550 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/wf-nested.pass.stderr @@ -0,0 +1,22 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/wf-nested.rs:36:57 + | +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... + | +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 | fn define_rpit() -> impl Trait<&'static T, Out = impl Sized> {} + | +++++++++ + +error: aborting due to 1 previous error + +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 f5d3a218542cd..2bc8be27a6076 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,5 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-nested.rs:46:17 + --> $DIR/wf-nested.rs:49:17 | LL | let _ = outer.get(); | ^^^^^^^^^^^ @@ -13,7 +13,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:49:17 | LL | let _ = outer.get(); | ^^^^^^^^^^^ diff --git a/tests/ui/type-alias-impl-trait/wf-nested.rs b/tests/ui/type-alias-impl-trait/wf-nested.rs index 1fc93a3cd2793..dcb4e251d470f 100644 --- a/tests/ui/type-alias-impl-trait/wf-nested.rs +++ b/tests/ui/type-alias-impl-trait/wf-nested.rs @@ -3,7 +3,7 @@ // See the comments below. // //@ revisions: pass pass_sound fail -//@ [pass] check-pass +//@ [pass] check-fail //@ [pass_sound] check-fail //@ [fail] check-fail @@ -32,6 +32,9 @@ mod pass { use super::*; type OuterOpaque = impl Trait<&'static T, Out = impl Sized>; fn define() -> OuterOpaque {} + + fn define_rpit() -> impl Trait<&'static T, Out = impl Sized> {} + //[pass]~^ ERROR the parameter type `T` may not live long enough } // Test the soundness of `pass` - We should require `T: 'static` at the use site. From 71d82c2899f5d5a4b5ec8c3be3823bf1509d3bf7 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 27 Feb 2024 15:57:49 +0100 Subject: [PATCH 2/5] when defining opaques, require the hidden type to be well-formed --- .../rustc_infer/src/infer/opaque_types.rs | 19 ++++++- tests/ui/closures/issue-78720.rs | 4 +- tests/ui/closures/issue-78720.stderr | 6 +- tests/ui/impl-trait/issues/issue-86800.rs | 9 +-- tests/ui/impl-trait/issues/issue-86800.stderr | 29 +++++++--- .../recursive-coroutine-boxed.next.stderr | 10 ++-- .../impl-trait/recursive-coroutine-boxed.rs | 2 +- tests/ui/impl-trait/wf-check-hidden-type.rs | 3 +- .../ui/impl-trait/wf-check-hidden-type.stderr | 22 +++----- .../ui/lifetimes/issue-76168-hr-outlives-3.rs | 1 + .../issue-76168-hr-outlives-3.stderr | 19 ++++++- .../normalize-async-closure-in-trait.rs | 2 +- .../normalize-async-closure-in-trait.stderr | 15 +++++ .../type-match-with-late-bound.stderr | 16 +++++- .../issue-90400-2.stderr | 12 ++-- .../wf-check-definition-site.rs | 6 +- .../wf-check-definition-site.stderr | 55 ------------------- .../wf-nested.fail.stderr | 21 +++---- .../wf-nested.pass.stderr | 31 +++++++---- .../wf-nested.pass_sound.stderr | 20 ++++++- tests/ui/type-alias-impl-trait/wf-nested.rs | 5 +- 21 files changed, 167 insertions(+), 140 deletions(-) create mode 100644 tests/ui/traits/next-solver/normalize-async-closure-in-trait.stderr delete mode 100644 tests/ui/type-alias-impl-trait/wf-check-definition-site.stderr diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index ec674407e523d..1d27b93221e44 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -605,8 +605,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/tests/ui/closures/issue-78720.rs b/tests/ui/closures/issue-78720.rs index 0e1f78ae3c69b..0c4f337ba57b8 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 d8d3811af5a74..2f57c7616f121 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 ae6e198c2ad46..172ab04f58df4 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 7af4846a9593f..146d2f67942be 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 | | } + | |_____^ + +error: aborting due to 3 previous errors -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 +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 fee3b86034af1..4a5e4bfe94b56 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 a42ae68f28e97..8f0bbb400cff0 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 index 29f15024d7664..c3b1182a98f48 100644 --- a/tests/ui/impl-trait/wf-check-hidden-type.rs +++ b/tests/ui/impl-trait/wf-check-hidden-type.rs @@ -11,8 +11,7 @@ impl<'a, 'b> Extend<'a, 'b> for Option<&'b &'a ()> { } fn boom<'a, 'b>() -> impl Extend<'a, 'b> { - //~^ ERROR in type `&'b &'a ()`, reference has a longer lifetime than the data it references - None::<&'_ &'_ ()> + None::<&'_ &'_ ()> //~ ERROR lifetime may not live long enough } fn main() { diff --git a/tests/ui/impl-trait/wf-check-hidden-type.stderr b/tests/ui/impl-trait/wf-check-hidden-type.stderr index 10c766c268ceb..86ba7aff54ada 100644 --- a/tests/ui/impl-trait/wf-check-hidden-type.stderr +++ b/tests/ui/impl-trait/wf-check-hidden-type.stderr @@ -1,20 +1,14 @@ -error[E0491]: in type `&'b &'a ()`, reference has a longer lifetime than the data it references - --> $DIR/wf-check-hidden-type.rs:13:22 +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` | -note: the pointer is valid for the lifetime `'b` as defined here - --> $DIR/wf-check-hidden-type.rs:13:13 - | -LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> { - | ^^ -note: but the referenced data is only valid for the lifetime `'a` as defined here - --> $DIR/wf-check-hidden-type.rs:13:9 - | -LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> { - | ^^ + = help: consider adding the following bound: `'a: 'b` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0491`. diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs index 03913869503c5..85eeb5d4c901e 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 89ebdb57f3c31..578ba149baf3f 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/next-solver/normalize-async-closure-in-trait.rs b/tests/ui/traits/next-solver/normalize-async-closure-in-trait.rs index 8cdde4f4d51db..968c18cb9f557 100644 --- a/tests/ui/traits/next-solver/normalize-async-closure-in-trait.rs +++ b/tests/ui/traits/next-solver/normalize-async-closure-in-trait.rs @@ -1,5 +1,5 @@ //@ compile-flags: -Znext-solver -//@ check-pass +//@ known-bug: unknown //@ edition:2021 trait Foo { diff --git a/tests/ui/traits/next-solver/normalize-async-closure-in-trait.stderr b/tests/ui/traits/next-solver/normalize-async-closure-in-trait.stderr new file mode 100644 index 0000000000000..c10cddd95b5cc --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-async-closure-in-trait.stderr @@ -0,0 +1,15 @@ +error[E0271]: type mismatch resolving `impl Future == {async fn body@$DIR/normalize-async-closure-in-trait.rs:6:20: 6:22}` + --> $DIR/normalize-async-closure-in-trait.rs:6:20 + | +LL | async fn bar() {} + | ^^ types differ + +error[E0271]: type mismatch resolving `{async fn body@$DIR/normalize-async-closure-in-trait.rs:6:20: 6:22} <: impl Future` + --> $DIR/normalize-async-closure-in-trait.rs:6:20 + | +LL | async fn bar() {} + | ^^ types differ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. 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 3a4415ed23aca..6c259621466d3 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 5e978e97d6b50..b4b78f8175fa2 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 index 2b5c9781a96f8..59c43574f8b33 100644 --- a/tests/ui/type-alias-impl-trait/wf-check-definition-site.rs +++ b/tests/ui/type-alias-impl-trait/wf-check-definition-site.rs @@ -1,3 +1,5 @@ +//@ check-pass + // Regression test for #114572, We were inferring an ill-formed type: // // `Opaque<'a> = Static<&'a str>`, vs @@ -7,18 +9,15 @@ struct Static(T); type OpaqueRet<'a> = impl Sized + 'a; -//~^ ERROR the type `&'a u8` does not fulfill the required lifetime fn test_return<'a>(msg: Static<&'static u8>) -> OpaqueRet<'a> { msg } fn test_rpit<'a>(msg: Static<&'static u8>) -> impl Sized + 'a { - //~^ ERROR the type `&'a u8` does not fulfill the required lifetime msg } type OpaqueAssign<'a> = impl Sized + 'a; -//~^ ERROR the type `&'a u8` does not fulfill the required lifetime fn test_assign<'a>(msg: Static<&'static u8>) -> Option> { let _: OpaqueAssign<'a> = msg; None @@ -29,7 +28,6 @@ fn test_assign<'a>(msg: Static<&'static u8>) -> Option> { trait RefAt<'a>: 'a {} struct Ref<'a, T: RefAt<'a>>(&'a T); type OpaqueRef<'a, T: RefAt<'static>> = impl Sized + 'a; -//~^ ERROR mismatched types fn test_trait<'a, T: RefAt<'static>>(msg: Ref<'static, T>) -> OpaqueRef<'a, T> { msg } diff --git a/tests/ui/type-alias-impl-trait/wf-check-definition-site.stderr b/tests/ui/type-alias-impl-trait/wf-check-definition-site.stderr deleted file mode 100644 index a51c6bb2ec090..0000000000000 --- a/tests/ui/type-alias-impl-trait/wf-check-definition-site.stderr +++ /dev/null @@ -1,55 +0,0 @@ -error[E0477]: the type `&'a u8` does not fulfill the required lifetime - --> $DIR/wf-check-definition-site.rs:9:22 - | -LL | type OpaqueRet<'a> = impl Sized + 'a; - | ^^^^^^^^^^^^^^^ - | -note: type must satisfy the static lifetime as required by this binding - --> $DIR/wf-check-definition-site.rs:7:18 - | -LL | struct Static(T); - | ^^^^^^^ - -error[E0477]: the type `&'a u8` does not fulfill the required lifetime - --> $DIR/wf-check-definition-site.rs:15:47 - | -LL | fn test_rpit<'a>(msg: Static<&'static u8>) -> impl Sized + 'a { - | ^^^^^^^^^^^^^^^ - | -note: type must satisfy the static lifetime as required by this binding - --> $DIR/wf-check-definition-site.rs:7:18 - | -LL | struct Static(T); - | ^^^^^^^ - -error[E0477]: the type `&'a u8` does not fulfill the required lifetime - --> $DIR/wf-check-definition-site.rs:20:25 - | -LL | type OpaqueAssign<'a> = impl Sized + 'a; - | ^^^^^^^^^^^^^^^ - | -note: type must satisfy the static lifetime as required by this binding - --> $DIR/wf-check-definition-site.rs:7:18 - | -LL | struct Static(T); - | ^^^^^^^ - -error[E0308]: mismatched types - --> $DIR/wf-check-definition-site.rs:31:41 - | -LL | type OpaqueRef<'a, T: RefAt<'static>> = impl Sized + 'a; - | ^^^^^^^^^^^^^^^ lifetime mismatch - | - = note: expected trait `RefAt<'a>` - found trait `RefAt<'static>` -note: the lifetime `'a` as defined here... - --> $DIR/wf-check-definition-site.rs:31:16 - | -LL | type OpaqueRef<'a, T: RefAt<'static>> = impl Sized + 'a; - | ^^ - = note: ...does not necessarily outlive the static lifetime - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0308, E0477. -For more information about an error, try `rustc --explain E0308`. 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 dd6b5a166ec45..79b726f83dde0 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:60: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 index 820710afef550..b61b69d8e407e 100644 --- a/tests/ui/type-alias-impl-trait/wf-nested.pass.stderr +++ b/tests/ui/type-alias-impl-trait/wf-nested.pass.stderr @@ -1,22 +1,31 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-nested.rs:36:57 + --> $DIR/wf-nested.rs:34:38 | -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... +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 | -note: ...that is required by this bound - --> $DIR/wf-nested.rs:12:20 +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 | -LL | struct IsStatic(T); - | ^^^^^^^ help: consider adding an explicit lifetime bound | LL | fn define_rpit() -> impl Trait<&'static T, Out = impl Sized> {} | +++++++++ -error: aborting due to 1 previous error +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 2bc8be27a6076..dbd3a1394f89b 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:49: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:49: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 dcb4e251d470f..7f070bbe6c2d9 100644 --- a/tests/ui/type-alias-impl-trait/wf-nested.rs +++ b/tests/ui/type-alias-impl-trait/wf-nested.rs @@ -32,6 +32,7 @@ mod pass { use super::*; type OuterOpaque = impl Trait<&'static T, Out = impl Sized>; fn define() -> OuterOpaque {} + //[pass]~^ ERROR `T` may not live long enough fn define_rpit() -> impl Trait<&'static T, Out = impl Sized> {} //[pass]~^ ERROR the parameter type `T` may not live long enough @@ -43,6 +44,7 @@ mod pass_sound { use super::*; type OuterOpaque = impl Trait<&'static T, Out = impl Sized>; fn define() -> OuterOpaque {} + //[pass_sound]~^ ERROR `T` may not live long enough fn test() { let outer = define::(); @@ -57,9 +59,10 @@ mod pass_sound { #[cfg(fail)] mod fail { use super::*; - type InnerOpaque = impl Sized; //[fail]~ ERROR `T` may not live long enough + type InnerOpaque = impl Sized; type OuterOpaque = impl Trait<&'static T, Out = InnerOpaque>; fn define() -> OuterOpaque {} + //[fail]~^ ERROR the parameter type `T` may not live long enough } fn main() {} From 6591c80eea51bfc019972845c08fdb78f1238760 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 27 Feb 2024 17:13:51 +0100 Subject: [PATCH 3/5] use typeck root when checking closure oblig --- compiler/rustc_hir_analysis/src/check/check.rs | 4 +++- .../normalize-async-closure-in-trait.rs | 2 +- .../normalize-async-closure-in-trait.stderr | 15 --------------- 3 files changed, 4 insertions(+), 17 deletions(-) delete mode 100644 tests/ui/traits/next-solver/normalize-async-closure-in-trait.stderr diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 1a3aa95743c96..cf42a705236e2 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1554,6 +1554,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, @@ -1561,7 +1563,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/tests/ui/traits/next-solver/normalize-async-closure-in-trait.rs b/tests/ui/traits/next-solver/normalize-async-closure-in-trait.rs index 968c18cb9f557..8cdde4f4d51db 100644 --- a/tests/ui/traits/next-solver/normalize-async-closure-in-trait.rs +++ b/tests/ui/traits/next-solver/normalize-async-closure-in-trait.rs @@ -1,5 +1,5 @@ //@ compile-flags: -Znext-solver -//@ known-bug: unknown +//@ check-pass //@ edition:2021 trait Foo { diff --git a/tests/ui/traits/next-solver/normalize-async-closure-in-trait.stderr b/tests/ui/traits/next-solver/normalize-async-closure-in-trait.stderr deleted file mode 100644 index c10cddd95b5cc..0000000000000 --- a/tests/ui/traits/next-solver/normalize-async-closure-in-trait.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0271]: type mismatch resolving `impl Future == {async fn body@$DIR/normalize-async-closure-in-trait.rs:6:20: 6:22}` - --> $DIR/normalize-async-closure-in-trait.rs:6:20 - | -LL | async fn bar() {} - | ^^ types differ - -error[E0271]: type mismatch resolving `{async fn body@$DIR/normalize-async-closure-in-trait.rs:6:20: 6:22} <: impl Future` - --> $DIR/normalize-async-closure-in-trait.rs:6:20 - | -LL | async fn bar() {} - | ^^ types differ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0271`. From 300cffa2d5b4bb4a22dfae3b85f788e8ad882243 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 27 Feb 2024 17:30:24 +0100 Subject: [PATCH 4/5] yeet now unnecessary special-case --- .../rustc_hir_analysis/src/check/check.rs | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index cf42a705236e2..21b074099e24f 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -402,24 +402,11 @@ fn check_opaque_meets_bounds<'tcx>( let guar = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(guar); } - match origin { - // 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 { .. } - | hir::OpaqueTyOrigin::FnReturn(..) - | hir::OpaqueTyOrigin::AsyncFn(..) => { - 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)?; - } - } + + 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 From af0d5082ee6d54bd3f2cb6347802d2a755e5192c Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 27 Feb 2024 17:39:36 +0100 Subject: [PATCH 5/5] update comments --- .../wf-check-definition-site.rs | 5 ++ tests/ui/type-alias-impl-trait/wf-nested.rs | 72 +++++++------------ .../ui/type-alias-impl-trait/wf-nested.stderr | 45 ++++++++++++ 3 files changed, 74 insertions(+), 48 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/wf-nested.stderr 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 index 59c43574f8b33..19dd4c1793677 100644 --- a/tests/ui/type-alias-impl-trait/wf-check-definition-site.rs +++ b/tests/ui/type-alias-impl-trait/wf-check-definition-site.rs @@ -4,6 +4,11 @@ // // `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); diff --git a/tests/ui/type-alias-impl-trait/wf-nested.rs b/tests/ui/type-alias-impl-trait/wf-nested.rs index 7f070bbe6c2d9..56c524c6db066 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-fail -//@ [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,46 +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 {} - //[pass]~^ ERROR `T` may not live long enough - - fn define_rpit() -> impl Trait<&'static T, Out = impl Sized> {} - //[pass]~^ ERROR the parameter type `T` may not live long enough -} - -// 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 {} - //[pass_sound]~^ 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 - } -} - -// 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; - type OuterOpaque = impl Trait<&'static T, Out = InnerOpaque>; - fn define() -> OuterOpaque {} - //[fail]~^ ERROR the parameter type `T` may not live long enough -} +// 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 define_rpit() -> impl Trait<&'static T, Out = impl Sized> {} +//~^ ERROR the parameter type `T` may not live long enough + +// 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 0000000000000..6d50e11c5da84 --- /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`.