Skip to content

Commit 93bc7a4

Browse files
committed
wf-check RPITs
1 parent 91cae1d commit 93bc7a4

File tree

10 files changed

+184
-34
lines changed

10 files changed

+184
-34
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -403,16 +403,6 @@ fn check_opaque_meets_bounds<'tcx>(
403403
return Err(guar);
404404
}
405405
match origin {
406-
// Checked when type checking the function containing them.
407-
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
408-
// HACK: this should also fall through to the hidden type check below, but the original
409-
// implementation had a bug where equivalent lifetimes are not identical. This caused us
410-
// to reject existing stable code that is otherwise completely fine. The real fix is to
411-
// compare the hidden types via our type equivalence/relation infra instead of doing an
412-
// identity check.
413-
let _ = infcx.take_opaque_types();
414-
return Ok(());
415-
}
416406
// Nested opaque types occur only in associated types:
417407
// ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
418408
// They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`.
@@ -421,20 +411,33 @@ fn check_opaque_meets_bounds<'tcx>(
421411
hir::OpaqueTyOrigin::TyAlias { .. }
422412
if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
423413
// Can have different predicates to their defining use
424-
hir::OpaqueTyOrigin::TyAlias { .. } => {
425-
let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?;
414+
hir::OpaqueTyOrigin::TyAlias { .. }
415+
| hir::OpaqueTyOrigin::FnReturn(..)
416+
| hir::OpaqueTyOrigin::AsyncFn(..) => {
417+
let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, defining_use_anchor)?;
426418
let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, &wf_tys);
427419
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
428420
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
429421
}
430422
}
431-
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
432-
for (mut key, mut ty) in infcx.take_opaque_types() {
433-
ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
434-
key = infcx.resolve_vars_if_possible(key);
435-
sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
423+
424+
if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin {
425+
// HACK: this should also fall through to the hidden type check below, but the original
426+
// implementation had a bug where equivalent lifetimes are not identical. This caused us
427+
// to reject existing stable code that is otherwise completely fine. The real fix is to
428+
// compare the hidden types via our type equivalence/relation infra instead of doing an
429+
// identity check.
430+
let _ = infcx.take_opaque_types();
431+
Ok(())
432+
} else {
433+
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
434+
for (mut key, mut ty) in infcx.take_opaque_types() {
435+
ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
436+
key = infcx.resolve_vars_if_possible(key);
437+
sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
438+
}
439+
Ok(())
436440
}
437-
Ok(())
438441
}
439442

440443
fn sanity_check_found_hidden_type<'tcx>(

compiler/rustc_ty_utils/src/implied_bounds.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,18 +121,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
121121
}
122122
}
123123
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
124-
DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) {
125-
DefKind::TyAlias => ty::List::empty(),
126-
DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
127-
// Nested opaque types only occur in associated types:
128-
// ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
129-
// assumed_wf_types should include those of `Opaque<T>`, `Opaque<T>` itself
130-
// and `&'static T`.
131-
DefKind::OpaqueTy => bug!("unimplemented implied bounds for nested opaque types"),
132-
def_kind => {
133-
bug!("unimplemented implied bounds for opaque types with parent {def_kind:?}")
134-
}
135-
},
124+
DefKind::OpaqueTy => bug!("implied bounds are not defined for opaques"),
136125
DefKind::Mod
137126
| DefKind::Struct
138127
| DefKind::Union
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//! Regression test for #114728.
2+
3+
trait Extend<'a, 'b> {
4+
fn extend(self, _: &'a str) -> &'b str;
5+
}
6+
7+
impl<'a, 'b> Extend<'a, 'b> for Option<&'b &'a ()> {
8+
fn extend(self, s: &'a str) -> &'b str {
9+
s
10+
}
11+
}
12+
13+
fn boom<'a, 'b>() -> impl Extend<'a, 'b> {
14+
//~^ ERROR in type `&'b &'a ()`, reference has a longer lifetime than the data it references
15+
None::<&'_ &'_ ()>
16+
}
17+
18+
fn main() {
19+
let y = boom().extend(&String::from("temporary"));
20+
println!("{}", y);
21+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0491]: in type `&'b &'a ()`, reference has a longer lifetime than the data it references
2+
--> $DIR/wf-check-hidden-type.rs:13:22
3+
|
4+
LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> {
5+
| ^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: the pointer is valid for the lifetime `'b` as defined here
8+
--> $DIR/wf-check-hidden-type.rs:13:13
9+
|
10+
LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> {
11+
| ^^
12+
note: but the referenced data is only valid for the lifetime `'a` as defined here
13+
--> $DIR/wf-check-hidden-type.rs:13:9
14+
|
15+
LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> {
16+
| ^^
17+
18+
error: aborting due to 1 previous error
19+
20+
For more information about this error, try `rustc --explain E0491`.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Regression test for #114572, We were inferring an ill-formed type:
2+
//
3+
// `Opaque<'a> = Static<&'a str>`, vs
4+
// `Opaque<'a> = Static<&'static str>`.
5+
#![feature(type_alias_impl_trait)]
6+
7+
struct Static<T: 'static>(T);
8+
9+
type OpaqueRet<'a> = impl Sized + 'a;
10+
//~^ ERROR the type `&'a u8` does not fulfill the required lifetime
11+
fn test_return<'a>(msg: Static<&'static u8>) -> OpaqueRet<'a> {
12+
msg
13+
}
14+
15+
fn test_rpit<'a>(msg: Static<&'static u8>) -> impl Sized + 'a {
16+
//~^ ERROR the type `&'a u8` does not fulfill the required lifetime
17+
msg
18+
}
19+
20+
type OpaqueAssign<'a> = impl Sized + 'a;
21+
//~^ ERROR the type `&'a u8` does not fulfill the required lifetime
22+
fn test_assign<'a>(msg: Static<&'static u8>) -> Option<OpaqueAssign<'a>> {
23+
let _: OpaqueAssign<'a> = msg;
24+
None
25+
}
26+
27+
// `OpaqueRef<'a, T> = Ref<'a, T>`, vs
28+
// `OpaqueRef<'a, T> = Ref<'static, T>`.
29+
trait RefAt<'a>: 'a {}
30+
struct Ref<'a, T: RefAt<'a>>(&'a T);
31+
type OpaqueRef<'a, T: RefAt<'static>> = impl Sized + 'a;
32+
//~^ ERROR mismatched types
33+
fn test_trait<'a, T: RefAt<'static>>(msg: Ref<'static, T>) -> OpaqueRef<'a, T> {
34+
msg
35+
}
36+
37+
fn main() {}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
error[E0477]: the type `&'a u8` does not fulfill the required lifetime
2+
--> $DIR/wf-check-definition-site.rs:9:22
3+
|
4+
LL | type OpaqueRet<'a> = impl Sized + 'a;
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
note: type must satisfy the static lifetime as required by this binding
8+
--> $DIR/wf-check-definition-site.rs:7:18
9+
|
10+
LL | struct Static<T: 'static>(T);
11+
| ^^^^^^^
12+
13+
error[E0477]: the type `&'a u8` does not fulfill the required lifetime
14+
--> $DIR/wf-check-definition-site.rs:15:47
15+
|
16+
LL | fn test_rpit<'a>(msg: Static<&'static u8>) -> impl Sized + 'a {
17+
| ^^^^^^^^^^^^^^^
18+
|
19+
note: type must satisfy the static lifetime as required by this binding
20+
--> $DIR/wf-check-definition-site.rs:7:18
21+
|
22+
LL | struct Static<T: 'static>(T);
23+
| ^^^^^^^
24+
25+
error[E0477]: the type `&'a u8` does not fulfill the required lifetime
26+
--> $DIR/wf-check-definition-site.rs:20:25
27+
|
28+
LL | type OpaqueAssign<'a> = impl Sized + 'a;
29+
| ^^^^^^^^^^^^^^^
30+
|
31+
note: type must satisfy the static lifetime as required by this binding
32+
--> $DIR/wf-check-definition-site.rs:7:18
33+
|
34+
LL | struct Static<T: 'static>(T);
35+
| ^^^^^^^
36+
37+
error[E0308]: mismatched types
38+
--> $DIR/wf-check-definition-site.rs:31:41
39+
|
40+
LL | type OpaqueRef<'a, T: RefAt<'static>> = impl Sized + 'a;
41+
| ^^^^^^^^^^^^^^^ lifetime mismatch
42+
|
43+
= note: expected trait `RefAt<'a>`
44+
found trait `RefAt<'static>`
45+
note: the lifetime `'a` as defined here...
46+
--> $DIR/wf-check-definition-site.rs:31:16
47+
|
48+
LL | type OpaqueRef<'a, T: RefAt<'static>> = impl Sized + 'a;
49+
| ^^
50+
= note: ...does not necessarily outlive the static lifetime
51+
52+
error: aborting due to 4 previous errors
53+
54+
Some errors have detailed explanations: E0308, E0477.
55+
For more information about an error, try `rustc --explain E0308`.

tests/ui/type-alias-impl-trait/wf-nested.fail.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0310]: the parameter type `T` may not live long enough
2-
--> $DIR/wf-nested.rs:57:27
2+
--> $DIR/wf-nested.rs:60:27
33
|
44
LL | type InnerOpaque<T> = impl Sized;
55
| ^^^^^^^^^^
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0310]: the parameter type `T` may not live long enough
2+
--> $DIR/wf-nested.rs:36:57
3+
|
4+
LL | fn define_rpit<T>() -> impl Trait<&'static T, Out = impl Sized> {}
5+
| ^^^^^^^^^^
6+
| |
7+
| the parameter type `T` must be valid for the static lifetime...
8+
| ...so that the type `T` will meet its required lifetime bounds...
9+
|
10+
note: ...that is required by this bound
11+
--> $DIR/wf-nested.rs:12:20
12+
|
13+
LL | struct IsStatic<T: 'static>(T);
14+
| ^^^^^^^
15+
help: consider adding an explicit lifetime bound
16+
|
17+
LL | fn define_rpit<T: 'static>() -> impl Trait<&'static T, Out = impl Sized> {}
18+
| +++++++++
19+
20+
error: aborting due to 1 previous error
21+
22+
For more information about this error, try `rustc --explain E0310`.

tests/ui/type-alias-impl-trait/wf-nested.pass_sound.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0310]: the parameter type `T` may not live long enough
2-
--> $DIR/wf-nested.rs:46:17
2+
--> $DIR/wf-nested.rs:49:17
33
|
44
LL | let _ = outer.get();
55
| ^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL | fn test<T: 'static>() {
1313
| +++++++++
1414

1515
error[E0310]: the parameter type `T` may not live long enough
16-
--> $DIR/wf-nested.rs:46:17
16+
--> $DIR/wf-nested.rs:49:17
1717
|
1818
LL | let _ = outer.get();
1919
| ^^^^^^^^^^^

tests/ui/type-alias-impl-trait/wf-nested.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// See the comments below.
44
//
55
//@ revisions: pass pass_sound fail
6-
//@ [pass] check-pass
6+
//@ [pass] check-fail
77
//@ [pass_sound] check-fail
88
//@ [fail] check-fail
99

@@ -32,6 +32,9 @@ mod pass {
3232
use super::*;
3333
type OuterOpaque<T> = impl Trait<&'static T, Out = impl Sized>;
3434
fn define<T>() -> OuterOpaque<T> {}
35+
36+
fn define_rpit<T>() -> impl Trait<&'static T, Out = impl Sized> {}
37+
//[pass]~^ ERROR the parameter type `T` may not live long enough
3538
}
3639

3740
// Test the soundness of `pass` - We should require `T: 'static` at the use site.

0 commit comments

Comments
 (0)