Skip to content

Commit cb94675

Browse files
committed
Auto merge of rust-lang#102417 - oli-obk:opaque_lifetimes2, r=jackh726
Require lifetime bounds for opaque types in order to allow hidden types to capture said lifetimes fixes rust-lang#96996 cc `@aliemjay`
2 parents 57781b2 + 1dc2119 commit cb94675

20 files changed

+142
-28
lines changed

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
226226
}
227227

228228
let definition_ty = instantiated_ty
229-
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
229+
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin)
230230
.ty;
231231

232232
if !check_opaque_type_parameter_valid(

compiler/rustc_hir_analysis/src/check/writeback.rs

+1
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
564564
opaque_type_key,
565565
self.fcx.infcx.tcx,
566566
true,
567+
decl.origin,
567568
);
568569

569570
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);

compiler/rustc_middle/src/ty/mod.rs

+75-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use crate::ty::util::Discr;
2626
pub use adt::*;
2727
pub use assoc::*;
2828
pub use generics::*;
29+
use hir::OpaqueTyOrigin;
2930
use rustc_ast as ast;
3031
use rustc_ast::node_id::NodeMap;
3132
use rustc_attr as attr;
@@ -1309,6 +1310,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
13091310
tcx: TyCtxt<'tcx>,
13101311
// typeck errors have subpar spans for opaque types, so delay error reporting until borrowck.
13111312
ignore_errors: bool,
1313+
origin: OpaqueTyOrigin,
13121314
) -> Self {
13131315
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
13141316

@@ -1320,8 +1322,79 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
13201322
// shifting.
13211323
let id_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
13221324
debug!(?id_substs);
1323-
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
1324-
substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
1325+
1326+
let map = substs.iter().zip(id_substs);
1327+
1328+
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = match origin {
1329+
// HACK: The HIR lowering for async fn does not generate
1330+
// any `+ Captures<'x>` bounds for the `impl Future<...>`, so all async fns with lifetimes
1331+
// would now fail to compile. We should probably just make hir lowering fill this in properly.
1332+
OpaqueTyOrigin::AsyncFn(_) => map.collect(),
1333+
OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::TyAlias => {
1334+
// Opaque types may only use regions that are bound. So for
1335+
// ```rust
1336+
// type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
1337+
// ```
1338+
// we may not use `'c` in the hidden type.
1339+
struct OpaqueTypeLifetimeCollector<'tcx> {
1340+
lifetimes: FxHashSet<ty::Region<'tcx>>,
1341+
}
1342+
1343+
impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> {
1344+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
1345+
self.lifetimes.insert(r);
1346+
r.super_visit_with(self)
1347+
}
1348+
}
1349+
1350+
let mut collector = OpaqueTypeLifetimeCollector { lifetimes: Default::default() };
1351+
1352+
for pred in tcx.bound_explicit_item_bounds(def_id.to_def_id()).transpose_iter() {
1353+
let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
1354+
1355+
trace!(pred=?pred.kind());
1356+
1357+
// We only ignore opaque type substs if the opaque type is the outermost type.
1358+
// The opaque type may be nested within itself via recursion in e.g.
1359+
// type Foo<'a> = impl PartialEq<Foo<'a>>;
1360+
// which thus mentions `'a` and should thus accept hidden types that borrow 'a
1361+
// instead of requiring an additional `+ 'a`.
1362+
match pred.kind().skip_binder() {
1363+
ty::PredicateKind::Trait(TraitPredicate {
1364+
trait_ref: ty::TraitRef { def_id: _, substs },
1365+
constness: _,
1366+
polarity: _,
1367+
}) => {
1368+
trace!(?substs);
1369+
for subst in &substs[1..] {
1370+
subst.visit_with(&mut collector);
1371+
}
1372+
}
1373+
ty::PredicateKind::Projection(ty::ProjectionPredicate {
1374+
projection_ty: ty::ProjectionTy { substs, item_def_id: _ },
1375+
term,
1376+
}) => {
1377+
for subst in &substs[1..] {
1378+
subst.visit_with(&mut collector);
1379+
}
1380+
term.visit_with(&mut collector);
1381+
}
1382+
_ => {
1383+
pred.visit_with(&mut collector);
1384+
}
1385+
}
1386+
}
1387+
let lifetimes = collector.lifetimes;
1388+
trace!(?lifetimes);
1389+
map.filter(|(_, v)| {
1390+
let ty::GenericArgKind::Lifetime(lt) = v.unpack() else {
1391+
return true;
1392+
};
1393+
lifetimes.contains(&lt)
1394+
})
1395+
.collect()
1396+
}
1397+
};
13251398
debug!("map = {:#?}", map);
13261399

13271400
// Convert the type from the function into a type valid outside

src/test/ui/impl-trait/issue-86465.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#![feature(type_alias_impl_trait)]
22

3-
type X<'a, 'b> = impl std::fmt::Debug;
3+
pub trait Captures<'a> {}
4+
5+
impl<'a, T: ?Sized> Captures<'a> for T {}
6+
7+
type X<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
48

59
fn f<'t, 'u>(a: &'t u32, b: &'u u32) -> (X<'t, 'u>, X<'u, 't>) {
610
(a, a)

src/test/ui/impl-trait/issue-86465.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: concrete type differs from previous defining opaque type use
2-
--> $DIR/issue-86465.rs:6:5
2+
--> $DIR/issue-86465.rs:10:5
33
|
44
LL | (a, a)
55
| ^^^^^^

src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
#![feature(type_alias_impl_trait)]
22
#![allow(dead_code)]
33

4-
type OneLifetime<'a, 'b> = impl std::fmt::Debug;
4+
pub trait Captures<'a> {}
5+
6+
impl<'a, T: ?Sized> Captures<'a> for T {}
7+
8+
type OneLifetime<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
59

610
fn foo<'a, 'b>(a: &'a u32, b: &'b u32) -> OneLifetime<'a, 'b> {
711
a

src/test/ui/type-alias-impl-trait/different_lifetimes_defining_uses.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error: concrete type differs from previous defining opaque type use
2-
--> $DIR/different_lifetimes_defining_uses.rs:11:5
2+
--> $DIR/different_lifetimes_defining_uses.rs:15:5
33
|
44
LL | b
55
| ^ expected `&'a u32`, got `&'b u32`
66
|
77
note: previous use here
8-
--> $DIR/different_lifetimes_defining_uses.rs:7:5
8+
--> $DIR/different_lifetimes_defining_uses.rs:11:5
99
|
1010
LL | a
1111
| ^

src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
fn main() {}
44

5-
type Two<'a, 'b> = impl std::fmt::Debug;
5+
pub trait Captures<'a> {}
66

7+
impl<'a, T: ?Sized> Captures<'a> for T {}
8+
9+
type Two<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
710

811
fn one<'a>(t: &'a ()) -> Two<'a, 'a> {
912
t

src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
error: non-defining opaque type use in defining scope
2-
--> $DIR/generic_duplicate_lifetime_param.rs:9:5
2+
--> $DIR/generic_duplicate_lifetime_param.rs:12:5
33
|
44
LL | t
55
| ^
66
|
77
note: lifetime used multiple times
8-
--> $DIR/generic_duplicate_lifetime_param.rs:5:10
8+
--> $DIR/generic_duplicate_lifetime_param.rs:9:10
99
|
10-
LL | type Two<'a, 'b> = impl std::fmt::Debug;
10+
LL | type Two<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
1111
| ^^ ^^
1212

1313
error: aborting due to previous error

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ fn main() {}
77
// test that unused generic parameters are ok
88
type TwoTys<T, U> = impl Debug;
99

10-
type TwoLifetimes<'a, 'b> = impl Debug;
10+
11+
pub trait Captures<'a> {}
12+
13+
impl<'a, T: ?Sized> Captures<'a> for T {}
14+
15+
type TwoLifetimes<'a, 'b> = impl Debug + Captures<'a> + Captures<'b>;
1116

1217
type TwoConsts<const X: usize, const Y: usize> = impl Debug;
1318

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: non-defining opaque type use in defining scope
2-
--> $DIR/generic_duplicate_param_use.rs:16:5
2+
--> $DIR/generic_duplicate_param_use.rs:21:5
33
|
44
LL | t
55
| ^
@@ -11,25 +11,25 @@ LL | type TwoTys<T, U> = impl Debug;
1111
| ^ ^
1212

1313
error: non-defining opaque type use in defining scope
14-
--> $DIR/generic_duplicate_param_use.rs:21:5
14+
--> $DIR/generic_duplicate_param_use.rs:26:5
1515
|
1616
LL | t
1717
| ^
1818
|
1919
note: lifetime used multiple times
20-
--> $DIR/generic_duplicate_param_use.rs:10:19
20+
--> $DIR/generic_duplicate_param_use.rs:15:19
2121
|
22-
LL | type TwoLifetimes<'a, 'b> = impl Debug;
22+
LL | type TwoLifetimes<'a, 'b> = impl Debug + Captures<'a> + Captures<'b>;
2323
| ^^ ^^
2424

2525
error: non-defining opaque type use in defining scope
26-
--> $DIR/generic_duplicate_param_use.rs:26:5
26+
--> $DIR/generic_duplicate_param_use.rs:31:5
2727
|
2828
LL | t
2929
| ^
3030
|
3131
note: constant used multiple times
32-
--> $DIR/generic_duplicate_param_use.rs:12:16
32+
--> $DIR/generic_duplicate_param_use.rs:17:16
3333
|
3434
LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug;
3535
| ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^

src/test/ui/type-alias-impl-trait/generic_lifetime_param.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// build-pass (FIXME(62277): could be check-pass?)
1+
// check-pass
22

33
#![feature(type_alias_impl_trait)]
44

55
fn main() {}
66

7-
type Region<'a> = impl std::fmt::Debug;
7+
type Region<'a> = impl std::fmt::Debug + 'a;
8+
89

910
fn region<'b>(a: &'b ()) -> Region<'b> {
1011
a

src/test/ui/type-alias-impl-trait/implied_lifetime_wf_check3.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![feature(type_alias_impl_trait)]
22

33
mod test_lifetime_param {
4-
type Ty<'a> = impl Sized;
4+
type Ty<'a> = impl Sized + 'a;
55
fn defining(a: &str) -> Ty<'_> { a }
66
fn assert_static<'a: 'static>() {}
77
//~^ WARN: unnecessary lifetime parameter `'a`
@@ -10,7 +10,7 @@ mod test_lifetime_param {
1010
}
1111

1212
mod test_higher_kinded_lifetime_param {
13-
type Ty<'a> = impl Sized;
13+
type Ty<'a> = impl Sized + 'a;
1414
fn defining(a: &str) -> Ty<'_> { a }
1515
fn assert_static<'a: 'static>() {}
1616
//~^ WARN: unnecessary lifetime parameter `'a`

src/test/ui/type-alias-impl-trait/issue-89686.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use std::future::Future;
66

7-
type G<'a, T> = impl Future<Output = ()>;
7+
type G<'a, T> = impl Future<Output = ()> + 'a;
88

99
trait Trait {
1010
type F: Future<Output = ()>;

src/test/ui/type-alias-impl-trait/issue-89686.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | async move { self.f().await }
66
|
77
help: consider restricting type parameter `T`
88
|
9-
LL | type G<'a, T: Trait> = impl Future<Output = ()>;
9+
LL | type G<'a, T: Trait> = impl Future<Output = ()> + 'a;
1010
| +++++++
1111

1212
error: aborting due to previous error
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(type_alias_impl_trait)]
2+
3+
type Opaque<'a, T> = impl Sized;
4+
fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
5+
//~^ ERROR: non-defining opaque type use in defining scope
6+
7+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: non-defining opaque type use in defining scope
2+
--> $DIR/missing_lifetime_bound.rs:4:47
3+
|
4+
LL | fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
5+
| ^ lifetime `'a` is part of concrete type but not used in parameter list of the `impl Trait` type alias
6+
7+
error: aborting due to previous error
8+

src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#![feature(type_alias_impl_trait)]
22

3-
type Foo<'a, 'b> = impl std::fmt::Debug;
3+
pub trait Captures<'a> {}
4+
5+
impl<'a, T: ?Sized> Captures<'a> for T {}
6+
7+
type Foo<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
48

59
fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
610
(i, i) //~ ERROR concrete type differs from previous

src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: concrete type differs from previous defining opaque type use
2-
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
2+
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:10:5
33
|
44
LL | (i, i)
55
| ^^^^^^

src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>)
77
(a.clone(), a)
88
}
99

10-
type Foo<'a, 'b> = impl std::fmt::Debug;
10+
pub trait Captures<'a> {}
11+
12+
impl<'a, T: ?Sized> Captures<'a> for T {}
13+
14+
type Foo<'a, 'b> = impl std::fmt::Debug + Captures<'a> + Captures<'b>;
1115

1216
fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
1317
(i, j)

0 commit comments

Comments
 (0)