mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
wf-check RPITs
This commit is contained in:
parent
91cae1dcdc
commit
93bc7a428c
@ -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<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
|
||||
// They can only be referenced as `<Opaque<T> 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>(
|
||||
|
@ -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<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::OpaqueTy => bug!("implied bounds are not defined for opaques"),
|
||||
DefKind::Mod
|
||||
| DefKind::Struct
|
||||
| DefKind::Union
|
||||
|
21
tests/ui/impl-trait/wf-check-hidden-type.rs
Normal file
21
tests/ui/impl-trait/wf-check-hidden-type.rs
Normal file
@ -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);
|
||||
}
|
20
tests/ui/impl-trait/wf-check-hidden-type.stderr
Normal file
20
tests/ui/impl-trait/wf-check-hidden-type.stderr
Normal file
@ -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`.
|
37
tests/ui/type-alias-impl-trait/wf-check-definition-site.rs
Normal file
37
tests/ui/type-alias-impl-trait/wf-check-definition-site.rs
Normal file
@ -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: '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<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;
|
||||
//~^ ERROR mismatched types
|
||||
fn test_trait<'a, T: RefAt<'static>>(msg: Ref<'static, T>) -> OpaqueRef<'a, T> {
|
||||
msg
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -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: '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: '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: '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`.
|
@ -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<T> = impl Sized;
|
||||
| ^^^^^^^^^^
|
||||
|
22
tests/ui/type-alias-impl-trait/wf-nested.pass.stderr
Normal file
22
tests/ui/type-alias-impl-trait/wf-nested.pass.stderr
Normal file
@ -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<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...
|
||||
|
|
||||
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
|
||||
|
|
||||
LL | fn define_rpit<T: 'static>() -> impl Trait<&'static T, Out = impl Sized> {}
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0310`.
|
@ -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<T: 'static>() {
|
||||
| +++++++++
|
||||
|
||||
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();
|
||||
| ^^^^^^^^^^^
|
||||
|
@ -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<T> = impl Trait<&'static T, Out = impl Sized>;
|
||||
fn define<T>() -> OuterOpaque<T> {}
|
||||
|
||||
fn define_rpit<T>() -> 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.
|
||||
|
Loading…
Reference in New Issue
Block a user