Skip to content

Commit 2110aa1

Browse files
committed
Auto merge of #62849 - davidtwco:prohibit-inheriting-lifetimes, r=<try>
typeck: Prohibit RPIT types that inherit lifetimes Part of #61949. This PR prohibits return position `impl Trait` types that "inherit lifetimes" from the parent scope. The intent is to forbid cases that are challenging until they can be addressed properly. cc @nikomatsakis
2 parents 3ebca72 + 62f89e0 commit 2110aa1

File tree

5 files changed

+130
-5
lines changed

5 files changed

+130
-5
lines changed

src/librustc_typeck/check/mod.rs

+81
Original file line numberDiff line numberDiff line change
@@ -1322,7 +1322,88 @@ fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
13221322
check_packed(tcx, span, def_id);
13231323
}
13241324

1325+
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
1326+
/// projections that would result in "inheriting lifetimes".
13251327
fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, span: Span) {
1328+
check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
1329+
check_opaque_for_cycles(tcx, def_id, substs, span);
1330+
}
1331+
1332+
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
1333+
/// in "inheriting lifetimes".
1334+
fn check_opaque_for_inheriting_lifetimes(
1335+
tcx: TyCtxt<'tcx>,
1336+
def_id: DefId,
1337+
span: Span,
1338+
) {
1339+
let item = tcx.hir().expect_item(
1340+
tcx.hir().as_local_hir_id(def_id).expect("existential type is not local"));
1341+
debug!("check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}",
1342+
def_id, span, item);
1343+
1344+
#[derive(Debug)]
1345+
struct ProhibitOpaqueVisitor<'tcx> {
1346+
opaque_identity_ty: Ty<'tcx>,
1347+
generics: &'tcx ty::Generics,
1348+
};
1349+
1350+
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
1351+
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
1352+
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
1353+
if t == self.opaque_identity_ty { false } else { t.super_visit_with(self) }
1354+
}
1355+
1356+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
1357+
debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
1358+
if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
1359+
return *index < self.generics.parent_count as u32;
1360+
}
1361+
1362+
r.super_visit_with(self)
1363+
}
1364+
}
1365+
1366+
let prohibit_opaque = match item.node {
1367+
ItemKind::Existential(hir::ExistTy { origin: hir::ExistTyOrigin::AsyncFn, .. }) |
1368+
ItemKind::Existential(hir::ExistTy { origin: hir::ExistTyOrigin::ReturnImplTrait, .. }) => {
1369+
let mut visitor = ProhibitOpaqueVisitor {
1370+
opaque_identity_ty: tcx.mk_opaque(
1371+
def_id, InternalSubsts::identity_for_item(tcx, def_id)),
1372+
generics: tcx.generics_of(def_id),
1373+
};
1374+
debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
1375+
1376+
tcx.predicates_of(def_id).predicates.iter().any(
1377+
|(predicate, _)| predicate.visit_with(&mut visitor))
1378+
},
1379+
_ => false,
1380+
};
1381+
1382+
debug!("check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}", prohibit_opaque);
1383+
if prohibit_opaque {
1384+
let is_async = match item.node {
1385+
ItemKind::Existential(hir::ExistTy { origin, .. }) => match origin {
1386+
hir::ExistTyOrigin::AsyncFn => true,
1387+
_ => false,
1388+
},
1389+
_ => unreachable!(),
1390+
};
1391+
1392+
tcx.sess.span_err(span, &format!(
1393+
"`{}` return type cannot contain a projection or `Self` that references lifetimes from \
1394+
a parent scope",
1395+
if is_async { "async fn" } else { "impl Trait" },
1396+
));
1397+
}
1398+
}
1399+
1400+
/// Checks that an opaque type does not contain cycles.
1401+
fn check_opaque_for_cycles<'tcx>(
1402+
tcx: TyCtxt<'tcx>,
1403+
def_id: DefId,
1404+
substs: SubstsRef<'tcx>,
1405+
span: Span,
1406+
) {
13261407
if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id, substs) {
13271408
let mut err = struct_span_err!(
13281409
tcx.sess, span, E0720,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// ignore-tidy-linelength
2+
// edition:2018
3+
#![feature(async_await)]
4+
5+
// This test checks that `Self` is prohibited as a return type. See #61949 for context.
6+
7+
pub struct Foo<'a> {
8+
pub bar: &'a i32,
9+
}
10+
11+
impl<'a> Foo<'a> {
12+
pub async fn new(_bar: &'a i32) -> Self {
13+
//~^ ERROR `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
14+
Foo {
15+
bar: &22
16+
}
17+
}
18+
}
19+
20+
async fn foo() {
21+
let x = {
22+
let bar = 22;
23+
Foo::new(&bar).await
24+
};
25+
drop(x);
26+
}
27+
28+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
2+
--> $DIR/issue-61949-self-return-type.rs:12:40
3+
|
4+
LL | pub async fn new(_bar: &'a i32) -> Self {
5+
| ^^^^
6+
7+
error: aborting due to previous error
8+

src/test/ui/impl-trait/bound-normalization-fail.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// compile-fail
2+
// ignore-tidy-linelength
23
// edition:2018
34

45
#![feature(async_await)]
@@ -45,7 +46,8 @@ mod lifetimes {
4546

4647
/// Missing bound constraining `Assoc`, `T::Assoc` can't be normalized further.
4748
fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
48-
//~^ ERROR: type mismatch
49+
//~^ ERROR: type mismatch
50+
//~^^ ERROR `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
4951
Foo(())
5052
}
5153
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
2-
--> $DIR/bound-normalization-fail.rs:6:12
2+
--> $DIR/bound-normalization-fail.rs:7:12
33
|
44
LL | #![feature(impl_trait_in_bindings)]
55
| ^^^^^^^^^^^^^^^^^^^^^^
66

77
error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
8-
--> $DIR/bound-normalization-fail.rs:30:32
8+
--> $DIR/bound-normalization-fail.rs:31:32
99
|
1010
LL | fn foo_fail<T: Trait>() -> impl FooLike<Output=T::Assoc> {
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found associated type
@@ -14,8 +14,14 @@ LL | fn foo_fail<T: Trait>() -> impl FooLike<Output=T::Assoc> {
1414
found type `<T as impl_trait::Trait>::Assoc`
1515
= note: the return type of a function must have a statically known size
1616

17+
error: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
18+
--> $DIR/bound-normalization-fail.rs:48:41
19+
|
20+
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
22+
1723
error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
18-
--> $DIR/bound-normalization-fail.rs:47:41
24+
--> $DIR/bound-normalization-fail.rs:48:41
1925
|
2026
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
2127
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found associated type
@@ -24,6 +30,6 @@ LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
2430
found type `<T as lifetimes::Trait<'static>>::Assoc`
2531
= note: the return type of a function must have a statically known size
2632

27-
error: aborting due to 2 previous errors
33+
error: aborting due to 3 previous errors
2834

2935
For more information about this error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)