1
Fork 0

Auto merge of #121679 - lcnr:opaque-wf-check-2, r=oli-obk

stricter hidden type wf-check [based on #115008]

Original work by `@aliemjay` in #115008. A huge thanks to them for originally figuring out this approach ❤️

Fixes https://github.com/rust-lang/rust/issues/114728
Fixes https://github.com/rust-lang/rust/issues/114572

Instead of adding the `WellFormed` obligations when relating opaque types, we now always emit such an obligation when defining the hidden type.

This causes nested opaque types which aren't wf to error, see the comment below for the described impact. I believe this change to be desirable as it significantly reduces complexity by removing special-cases.

It also caused an issue with RPITIT: in defaulted trait methods, we add a `Projection(synthetic_assoc, rpit_of_trait_method)` clause to the `param_env`. This clause is not added to the `ParamEnv` of the nested coroutines. This caused a normalization failure in `fn check_coroutine_obligations` with the new solver. I fixed that by using the env of the typeck root instead.

r? `@oli-obk`
This commit is contained in:
bors 2024-03-06 10:04:26 +00:00
commit 09bc67b915
21 changed files with 313 additions and 136 deletions

View file

@ -402,39 +402,29 @@ fn check_opaque_meets_bounds<'tcx>(
let guar = infcx.err_ctxt().report_fulfillment_errors(errors); let guar = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(guar); return Err(guar);
} }
match origin {
// Checked when type checking the function containing them. let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, defining_use_anchor)?;
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => { let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, &wf_tys);
// HACK: this should also fall through to the hidden type check below, but the original let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
// implementation had a bug where equivalent lifetimes are not identical. This caused us ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
// 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 if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin {
// identity check. // HACK: this should also fall through to the hidden type check below, but the original
let _ = infcx.take_opaque_types(); // implementation had a bug where equivalent lifetimes are not identical. This caused us
return Ok(()); // 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
// Nested opaque types occur only in associated types: // identity check.
// ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; ` let _ = infcx.take_opaque_types();
// They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`. Ok(())
// We don't have to check them here because their well-formedness follows from the WF of } else {
// the projection input types in the defining- and use-sites. // Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
hir::OpaqueTyOrigin::TyAlias { .. } for (mut key, mut ty) in infcx.take_opaque_types() {
if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {} ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
// Can have different predicates to their defining use key = infcx.resolve_vars_if_possible(key);
hir::OpaqueTyOrigin::TyAlias { .. } => { sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
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)?;
} }
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>( fn sanity_check_found_hidden_type<'tcx>(
@ -1549,6 +1539,8 @@ fn opaque_type_cycle_error(
err.emit() err.emit()
} }
// FIXME(@lcnr): This should not be computed per coroutine, but instead once for
// each typeck root.
pub(super) fn check_coroutine_obligations( pub(super) fn check_coroutine_obligations(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
def_id: LocalDefId, def_id: LocalDefId,
@ -1556,7 +1548,7 @@ pub(super) fn check_coroutine_obligations(
debug_assert!(tcx.is_coroutine(def_id.to_def_id())); debug_assert!(tcx.is_coroutine(def_id.to_def_id()));
let typeck = tcx.typeck(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]; let coroutine_interior_predicates = &typeck.coroutine_interior_predicates[&def_id];
debug!(?coroutine_interior_predicates); debug!(?coroutine_interior_predicates);

View file

@ -592,8 +592,25 @@ impl<'tcx> InferCtxt<'tcx> {
obligations: &mut Vec<PredicateObligation<'tcx>>, obligations: &mut Vec<PredicateObligation<'tcx>>,
) { ) {
let tcx = self.tcx; 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) { for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
let predicate = predicate.fold_with(&mut BottomUpFolder { let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx, tcx,

View file

@ -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::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) { DefKind::OpaqueTy => bug!("implied bounds are not defined for opaques"),
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<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
// assumed_wf_types should include those of `Opaque<T>`, `Opaque<T>` 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::Mod DefKind::Mod
| DefKind::Struct | DefKind::Struct
| DefKind::Union | DefKind::Union

View file

@ -1,7 +1,7 @@
fn server() -> impl { fn server() -> impl {
//~^ ERROR at least one trait must be specified //~^ ERROR at least one trait must be specified
//~| ERROR type annotations needed
().map2(|| "") ().map2(|| "")
//~^ ERROR type annotations needed
} }
trait FilterBase2 { trait FilterBase2 {

View file

@ -23,10 +23,10 @@ LL | struct Map2<Segment2, F> {
| +++ | +++
error[E0282]: type annotations needed error[E0282]: type annotations needed
--> $DIR/issue-78720.rs:3:5 --> $DIR/issue-78720.rs:1:16
| |
LL | ().map2(|| "") LL | fn server() -> impl {
| ^^^^^^^^^^^^^^ cannot infer type | ^^^^ cannot infer type
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/issue-78720.rs:8:39 --> $DIR/issue-78720.rs:8:39

View file

@ -1,12 +1,6 @@
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
//@ edition:2021 //@ 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; use std::future::Future;
@ -29,6 +23,7 @@ struct Context {
type TransactionResult<O> = Result<O, ()>; type TransactionResult<O> = Result<O, ()>;
type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>; type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
//~^ ERROR unconstrained opaque type
fn execute_transaction_fut<'f, F, O>( fn execute_transaction_fut<'f, F, O>(
f: F, f: F,
@ -37,6 +32,7 @@ where
F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f
{ {
f f
//~^ ERROR expected generic lifetime parameter, found `'_`
} }
impl Context { impl Context {
@ -44,6 +40,7 @@ impl Context {
&self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> &self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O>
) -> TransactionResult<O> ) -> TransactionResult<O>
{ {
//~^ ERROR expected generic lifetime parameter, found `'_`
let mut conn = Connection {}; let mut conn = Connection {};
let mut transaction = TestTransaction { conn: &mut conn }; let mut transaction = TestTransaction { conn: &mut conn };
f(&mut transaction).await f(&mut transaction).await

View file

@ -1,11 +1,13 @@
error: unconstrained opaque type error: unconstrained opaque type
--> $DIR/issue-86800.rs:31:34 --> $DIR/issue-86800.rs:25:34
| |
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>; LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
error: internal compiler error[E0792]: expected generic lifetime parameter, found `'_` = note: `TransactionFuture` must be used in combination with a concrete type within the same module
--> $DIR/issue-86800.rs:39:5
error[E0792]: expected generic lifetime parameter, found `'_`
--> $DIR/issue-86800.rs:34:5
| |
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>; LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
| --- this generic parameter must be used with a generic lifetime parameter | --- this generic parameter must be used with a generic lifetime parameter
@ -13,9 +15,20 @@ LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResu
LL | f LL | f
| ^ | ^
error: the compiler unexpectedly panicked. this is a bug. error[E0792]: expected generic lifetime parameter, found `'_`
--> $DIR/issue-86800.rs:42:5
|
LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
| --- 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: error: aborting due to 3 previous errors
#0 [mir_borrowck] borrow-checking `execute_transaction_fut`
#1 [type_of_opaque] computing type of opaque `execute_transaction_fut::{opaque#0}` For more information about this error, try `rustc --explain E0792`.
end of query stack

View file

@ -1,9 +1,9 @@
error[E0282]: type annotations needed 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()); LL | let mut gen = Box::pin(foo());
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box` | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box`
... LL |
LL | let mut r = gen.as_mut().resume(()); LL | let mut r = gen.as_mut().resume(());
| ------ type must be known at this point | ------ type must be known at this point
| |
@ -13,10 +13,10 @@ LL | let mut gen = Box::<T>::pin(foo());
| +++++ | +++++
error[E0282]: type annotations needed 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()); LL | fn foo() -> impl Coroutine<Yield = (), Return = ()> {
| ^^^^^ cannot infer type for opaque type `impl Coroutine<Yield = (), Return = ()>` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for opaque type `impl Coroutine<Yield = (), Return = ()>`
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -6,10 +6,10 @@
use std::ops::{Coroutine, CoroutineState}; use std::ops::{Coroutine, CoroutineState};
fn foo() -> impl Coroutine<Yield = (), Return = ()> { fn foo() -> impl Coroutine<Yield = (), Return = ()> {
//[next]~^ ERROR type annotations needed
|| { || {
let mut gen = Box::pin(foo()); let mut gen = Box::pin(foo());
//[next]~^ ERROR type annotations needed //[next]~^ ERROR type annotations needed
//[next]~| ERROR type annotations needed
let mut r = gen.as_mut().resume(()); let mut r = gen.as_mut().resume(());
while let CoroutineState::Yielded(v) = r { while let CoroutineState::Yielded(v) = r {
yield v; yield v;

View file

@ -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);
}

View file

@ -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

View file

@ -6,6 +6,7 @@ use std::future::Future;
async fn wrapper<F>(f: F) async fn wrapper<F>(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` //~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
//~| ERROR: expected a `FnOnce(&'a mut i32)` closure, found `i32`
where where
F:, F:,
for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a, for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,

View file

@ -4,6 +4,7 @@ error[E0277]: expected a `FnOnce(&'a mut i32)` closure, found `i32`
LL | / async fn wrapper<F>(f: F) LL | / async fn wrapper<F>(f: F)
LL | | LL | |
LL | | LL | |
LL | |
LL | | where LL | | where
LL | | F:, LL | | F:,
LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a, LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a,
@ -20,7 +21,21 @@ LL | async fn wrapper<F>(f: F)
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `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` 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: F)
LL | |
LL | |
LL | |
LL | | where
LL | | F:,
LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + '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 | / {
LL | | LL | |
@ -31,6 +46,6 @@ LL | | }
| |
= help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` = 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`. For more information about this error, try `rustc --explain E0277`.

View file

@ -21,6 +21,20 @@ help: consider adding an explicit lifetime bound
LL | for<F> F: 'a, !1_"F": 'a LL | for<F> 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> 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`. For more information about this error, try `rustc --explain E0309`.

View file

@ -2,15 +2,13 @@ error[E0277]: the trait bound `B: Bar` is not satisfied
--> $DIR/issue-90400-2.rs:25:9 --> $DIR/issue-90400-2.rs:25:9
| |
LL | MyBaz(bar) LL | MyBaz(bar)
| ^^^^^^^^^^ the trait `Bar` is not implemented for `B`, which is required by `MyBaz<B>: Baz` | ^^^^^^^^^^ the trait `Bar` is not implemented for `B`
| |
note: required for `MyBaz<B>` to implement `Baz` note: required by a bound in `MyBaz`
--> $DIR/issue-90400-2.rs:30:14 --> $DIR/issue-90400-2.rs:29:17
| |
LL | impl<B: Bar> Baz for MyBaz<B> { LL | struct MyBaz<B: Bar>(B);
| --- ^^^ ^^^^^^^^ | ^^^ required by this bound in `MyBaz`
| |
| unsatisfied trait bound introduced here
help: consider restricting type parameter `B` help: consider restricting type parameter `B`
| |
LL | type FooFn<B: Bar> = impl Baz; LL | type FooFn<B: Bar> = impl Baz;

View file

@ -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: '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<OpaqueAssign<'a>> {
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() {}

View file

@ -1,21 +1,16 @@
error[E0310]: the parameter type `T` may not live long enough 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<T> = impl Sized; LL | fn define<T>() -> OuterOpaque<T> {}
| ^^^^^^^^^^ | ^^
| | | |
| the parameter type `T` must be valid for the static lifetime... | the parameter type `T` must be valid for the static lifetime...
| ...so that the type `T` will meet its required lifetime bounds... | ...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: 'static>(T);
| ^^^^^^^
help: consider adding an explicit lifetime bound help: consider adding an explicit lifetime bound
| |
LL | type InnerOpaque<T: 'static> = impl Sized; LL | fn define<T: 'static>() -> OuterOpaque<T> {}
| +++++++++ | +++++++++
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -0,0 +1,31 @@
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/wf-nested.rs:34:38
|
LL | fn define<T>() -> OuterOpaque<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 define<T: 'static>() -> OuterOpaque<T> {}
| +++++++++
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/wf-nested.rs:37:69
|
LL | fn define_rpit<T>() -> 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<T: 'static>() -> impl Trait<&'static T, Out = impl Sized> {}
| +++++++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0310`.

View file

@ -1,5 +1,19 @@
error[E0310]: the parameter type `T` may not live long enough 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<T>() -> OuterOpaque<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 define<T: 'static>() -> OuterOpaque<T> {}
| +++++++++
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/wf-nested.rs:51:17
| |
LL | let _ = outer.get(); LL | let _ = outer.get();
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -13,7 +27,7 @@ LL | fn test<T: 'static>() {
| +++++++++ | +++++++++
error[E0310]: the parameter type `T` may not live long enough 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(); LL | let _ = outer.get();
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -27,6 +41,6 @@ help: consider adding an explicit lifetime bound
LL | fn test<T: 'static>() { LL | fn test<T: 'static>() {
| +++++++++ | +++++++++
error: aborting due to 2 previous errors error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0310`. For more information about this error, try `rustc --explain E0310`.

View file

@ -1,12 +1,8 @@
// Well-formedness of nested opaque types, i.e. `impl Sized` in // Well-formedness of nested opaque types, i.e. `impl Sized` in
// `type Outer = impl Trait<Assoc = impl Sized>`. // `type Outer = impl Trait<Assoc = impl Sized>`. We check that
// See the comments below. // the nested type is well-formed, even though this would also
// // be implied by the item bounds of the opaque being
//@ revisions: pass pass_sound fail // well-formed. See the comments below.
//@ [pass] check-pass
//@ [pass_sound] check-fail
//@ [fail] check-fail
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
struct IsStatic<T: 'static>(T); struct IsStatic<T: 'static>(T);
@ -23,40 +19,26 @@ impl<T> Trait<&'static T> for () {
type Out = IsStatic<T>; type Out = IsStatic<T>;
} }
// The hidden type for `impl Sized` is `IsStatic<T>`, which requires `T: 'static`.
// We know it is well-formed because it can *only* be referenced as a projection:
// <OuterOpaque<T> as Trait<&'static T>>::Out`.
// So any instantiation of the type already requires proving `T: 'static`.
#[cfg(pass)]
mod pass {
use super::*;
type OuterOpaque<T> = impl Trait<&'static T, Out = impl Sized>;
fn define<T>() -> OuterOpaque<T> {}
}
// Test the soundness of `pass` - We should require `T: 'static` at the use site. // We could theoretically allow this (and previously did), as even
#[cfg(pass_sound)] // though the nested opaque is not well-formed, it can only be
mod pass_sound { // used by normalizing the projection
use super::*; // <OuterOpaque1<T> as Trait<&'static T>>::Out
type OuterOpaque<T> = impl Trait<&'static T, Out = impl Sized>; // Assuming that we check that this projection is well-formed, the wf
fn define<T>() -> OuterOpaque<T> {} // of the nested opaque is implied.
type OuterOpaque1<T> = impl Trait<&'static T, Out = impl Sized>;
fn define<T>() -> OuterOpaque1<T> {}
//~^ ERROR `T` may not live long enough
fn test<T>() { fn define_rpit<T>() -> impl Trait<&'static T, Out = impl Sized> {}
let outer = define::<T>(); //~^ ERROR the parameter type `T` may not live long enough
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 // Similar to `define` but here `impl Sized` can be referenced directly as
// InnerOpaque<T>, so we require an explicit bound `T: 'static`. // InnerOpaque<T>, so the `'static` bound is definitely required for
#[cfg(fail)] // soundness.
mod fail { type InnerOpaque<T> = impl Sized;
use super::*; type OuterOpaque2<T> = impl Trait<&'static T, Out = InnerOpaque<T>>;
type InnerOpaque<T> = impl Sized; //[fail]~ ERROR `T` may not live long enough fn define_nested_rpit<T>() -> OuterOpaque2<T> {}
type OuterOpaque<T> = impl Trait<&'static T, Out = InnerOpaque<T>>; //~^ ERROR the parameter type `T` may not live long enough
fn define<T>() -> OuterOpaque<T> {}
}
fn main() {} fn main() {}

View file

@ -0,0 +1,45 @@
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/wf-nested.rs:30:35
|
LL | fn define<T>() -> OuterOpaque1<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 define<T: 'static>() -> OuterOpaque1<T> {}
| +++++++++
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/wf-nested.rs:33:65
|
LL | fn define_rpit<T>() -> 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<T: 'static>() -> 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<T>() -> OuterOpaque2<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 define_nested_rpit<T: 'static>() -> OuterOpaque2<T> {}
| +++++++++
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0310`.