Skip to content

Commit bca15ce

Browse files
authored
Rollup merge of rust-lang#62849 - davidtwco:prohibit-inheriting-lifetimes, r=nikomatsakis
typeck: Prohibit RPIT types that inherit lifetimes Part of rust-lang#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 60960a2 + 861d1bb commit bca15ce

File tree

5 files changed

+132
-6
lines changed

5 files changed

+132
-6
lines changed

src/librustc_typeck/check/mod.rs

+83-1
Original file line numberDiff line numberDiff line change
@@ -1325,12 +1325,94 @@ fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
13251325
check_packed(tcx, span, def_id);
13261326
}
13271327

1328+
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
1329+
/// projections that would result in "inheriting lifetimes".
13281330
fn check_opaque<'tcx>(
13291331
tcx: TyCtxt<'tcx>,
13301332
def_id: DefId,
13311333
substs: SubstsRef<'tcx>,
13321334
span: Span,
1333-
origin: &hir::OpaqueTyOrigin
1335+
origin: &hir::OpaqueTyOrigin,
1336+
) {
1337+
check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
1338+
check_opaque_for_cycles(tcx, def_id, substs, span, origin);
1339+
}
1340+
1341+
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
1342+
/// in "inheriting lifetimes".
1343+
fn check_opaque_for_inheriting_lifetimes(
1344+
tcx: TyCtxt<'tcx>,
1345+
def_id: DefId,
1346+
span: Span,
1347+
) {
1348+
let item = tcx.hir().expect_item(
1349+
tcx.hir().as_local_hir_id(def_id).expect("opaque type is not local"));
1350+
debug!("check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}",
1351+
def_id, span, item);
1352+
1353+
#[derive(Debug)]
1354+
struct ProhibitOpaqueVisitor<'tcx> {
1355+
opaque_identity_ty: Ty<'tcx>,
1356+
generics: &'tcx ty::Generics,
1357+
};
1358+
1359+
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
1360+
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
1361+
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
1362+
if t == self.opaque_identity_ty { false } else { t.super_visit_with(self) }
1363+
}
1364+
1365+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
1366+
debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
1367+
if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
1368+
return *index < self.generics.parent_count as u32;
1369+
}
1370+
1371+
r.super_visit_with(self)
1372+
}
1373+
}
1374+
1375+
let prohibit_opaque = match item.node {
1376+
ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::AsyncFn, .. }) |
1377+
ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn, .. }) => {
1378+
let mut visitor = ProhibitOpaqueVisitor {
1379+
opaque_identity_ty: tcx.mk_opaque(
1380+
def_id, InternalSubsts::identity_for_item(tcx, def_id)),
1381+
generics: tcx.generics_of(def_id),
1382+
};
1383+
debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
1384+
1385+
tcx.predicates_of(def_id).predicates.iter().any(
1386+
|(predicate, _)| predicate.visit_with(&mut visitor))
1387+
},
1388+
_ => false,
1389+
};
1390+
1391+
debug!("check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}", prohibit_opaque);
1392+
if prohibit_opaque {
1393+
let is_async = match item.node {
1394+
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
1395+
hir::OpaqueTyOrigin::AsyncFn => true,
1396+
_ => false,
1397+
},
1398+
_ => unreachable!(),
1399+
};
1400+
1401+
tcx.sess.span_err(span, &format!(
1402+
"`{}` return type cannot contain a projection or `Self` that references lifetimes from \
1403+
a parent scope",
1404+
if is_async { "async fn" } else { "impl Trait" },
1405+
));
1406+
}
1407+
}
1408+
1409+
/// Checks that an opaque type does not contain cycles.
1410+
fn check_opaque_for_cycles<'tcx>(
1411+
tcx: TyCtxt<'tcx>,
1412+
def_id: DefId,
1413+
substs: SubstsRef<'tcx>,
1414+
span: Span,
1415+
origin: &hir::OpaqueTyOrigin,
13341416
) {
13351417
if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id, substs) {
13361418
if let hir::OpaqueTyOrigin::AsyncFn = origin {
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)]
@@ -44,7 +45,8 @@ mod lifetimes {
4445

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

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

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

29-
error: aborting due to 2 previous errors
35+
error: aborting due to 3 previous errors
3036

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

0 commit comments

Comments
 (0)