Skip to content

Commit 1e0832f

Browse files
committed
Allow all impl trait types to capture bound lifetimes
1 parent ee0d3c7 commit 1e0832f

File tree

3 files changed

+159
-47
lines changed

3 files changed

+159
-47
lines changed

src/librustc_ast_lowering/item.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_ast::attr;
77
use rustc_ast::node_id::NodeMap;
88
use rustc_ast::ptr::P;
99
use rustc_ast::visit::{self, AssocCtxt, Visitor};
10+
use rustc_data_structures::fx::FxHashSet;
1011
use rustc_errors::struct_span_err;
1112
use rustc_hir as hir;
1213
use rustc_hir::def::{DefKind, Res};
@@ -286,8 +287,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
286287
ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)),
287288
ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
288289
ItemKind::TyAlias(_, ref gen, _, Some(ref ty)) => {
289-
let ty =
290-
self.lower_ty(ty, ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc));
290+
// We lower
291+
//
292+
// type Foo = impl Trait
293+
//
294+
// to
295+
//
296+
// type Foo = Foo1
297+
// opaque type Foo1: Trait
298+
let ty = self.lower_ty(
299+
ty,
300+
ImplTraitContext::OtherOpaqueTy {
301+
capturable_lifetimes: &mut FxHashSet::default(),
302+
origin: hir::OpaqueTyOrigin::Misc,
303+
},
304+
);
291305
let generics = self.lower_generics(gen, ImplTraitContext::disallowed());
292306
hir::ItemKind::TyAlias(ty, generics)
293307
}
@@ -420,8 +434,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
420434
span: Span,
421435
body: Option<&Expr>,
422436
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
437+
let mut capturable_lifetimes;
423438
let itctx = if self.sess.features_untracked().impl_trait_in_bindings {
424-
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)
439+
capturable_lifetimes = FxHashSet::default();
440+
ImplTraitContext::OtherOpaqueTy {
441+
capturable_lifetimes: &mut capturable_lifetimes,
442+
origin: hir::OpaqueTyOrigin::Misc,
443+
}
425444
} else {
426445
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
427446
};
@@ -829,7 +848,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
829848
Some(ty) => {
830849
let ty = self.lower_ty(
831850
ty,
832-
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc),
851+
ImplTraitContext::OtherOpaqueTy {
852+
capturable_lifetimes: &mut FxHashSet::default(),
853+
origin: hir::OpaqueTyOrigin::Misc,
854+
},
833855
);
834856
hir::ImplItemKind::TyAlias(ty)
835857
}

src/librustc_ast_lowering/lib.rs

+119-28
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,30 @@ enum ImplTraitContext<'b, 'a> {
224224
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
225225
/// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
226226
///
227-
/// We optionally store a `DefId` for the parent item here so we can look up necessary
228-
/// information later. It is `None` when no information about the context should be stored
229-
/// (e.g., for consts and statics).
230-
OpaqueTy(Option<DefId> /* fn def-ID */, hir::OpaqueTyOrigin),
231-
227+
ReturnPositionOpaqueTy {
228+
/// `DefId` for the parent function, used to look up necessary
229+
/// information later.
230+
fn_def_id: DefId,
231+
/// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
232+
origin: hir::OpaqueTyOrigin,
233+
},
234+
/// Impl trait in type aliases, consts and statics.
235+
OtherOpaqueTy {
236+
/// Set of lifetimes that this opaque type can capture, if it uses
237+
/// them. This includes lifetimes bound since we entered this context.
238+
/// For example, in
239+
///
240+
/// type A<'b> = impl for<'a> Trait<'a, Out = impl Sized + 'a>;
241+
///
242+
/// the inner opaque type captures `'a` because it uses it. It doesn't
243+
/// need to capture `'b` because it already inherits the lifetime
244+
/// parameter from `A`.
245+
// FIXME(impl_trait): but `required_region_bounds` will ICE later
246+
// anyway.
247+
capturable_lifetimes: &'b mut FxHashSet<hir::LifetimeName>,
248+
/// Origin: Either OpaqueTyOrigin::Misc or OpaqueTyOrigin::Binding,
249+
origin: hir::OpaqueTyOrigin,
250+
},
232251
/// `impl Trait` is not accepted in this position.
233252
Disallowed(ImplTraitPosition),
234253
}
@@ -253,7 +272,12 @@ impl<'a> ImplTraitContext<'_, 'a> {
253272
use self::ImplTraitContext::*;
254273
match self {
255274
Universal(params) => Universal(params),
256-
OpaqueTy(fn_def_id, origin) => OpaqueTy(*fn_def_id, *origin),
275+
ReturnPositionOpaqueTy { fn_def_id, origin } => {
276+
ReturnPositionOpaqueTy { fn_def_id: *fn_def_id, origin: *origin }
277+
}
278+
OtherOpaqueTy { capturable_lifetimes, origin } => {
279+
OtherOpaqueTy { capturable_lifetimes, origin: *origin }
280+
}
257281
Disallowed(pos) => Disallowed(*pos),
258282
}
259283
}
@@ -1001,6 +1025,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10011025
hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) }
10021026
}
10031027
AssocTyConstraintKind::Bound { ref bounds } => {
1028+
let mut capturable_lifetimes;
10041029
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
10051030
let (desugar_to_impl_trait, itctx) = match itctx {
10061031
// We are in the return position:
@@ -1010,7 +1035,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10101035
// so desugar to
10111036
//
10121037
// fn foo() -> impl Iterator<Item = impl Debug>
1013-
ImplTraitContext::OpaqueTy(..) => (true, itctx),
1038+
ImplTraitContext::ReturnPositionOpaqueTy { .. }
1039+
| ImplTraitContext::OtherOpaqueTy { .. } => (true, itctx),
10141040

10151041
// We are in the argument position, but within a dyn type:
10161042
//
@@ -1028,7 +1054,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10281054
//
10291055
// FIXME: this is only needed until `impl Trait` is allowed in type aliases.
10301056
ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => {
1031-
(true, ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc))
1057+
capturable_lifetimes = FxHashSet::default();
1058+
(
1059+
true,
1060+
ImplTraitContext::OtherOpaqueTy {
1061+
capturable_lifetimes: &mut capturable_lifetimes,
1062+
origin: hir::OpaqueTyOrigin::Misc,
1063+
},
1064+
)
10321065
}
10331066

10341067
// We are in the parameter position, but not within a dyn type:
@@ -1270,10 +1303,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12701303
TyKind::ImplTrait(def_node_id, ref bounds) => {
12711304
let span = t.span;
12721305
match itctx {
1273-
ImplTraitContext::OpaqueTy(fn_def_id, origin) => {
1274-
self.lower_opaque_impl_trait(span, fn_def_id, origin, def_node_id, |this| {
1275-
this.lower_param_bounds(bounds, itctx)
1276-
})
1306+
ImplTraitContext::ReturnPositionOpaqueTy { fn_def_id, origin } => self
1307+
.lower_opaque_impl_trait(
1308+
span,
1309+
Some(fn_def_id),
1310+
origin,
1311+
def_node_id,
1312+
None,
1313+
|this| this.lower_param_bounds(bounds, itctx),
1314+
),
1315+
ImplTraitContext::OtherOpaqueTy { ref capturable_lifetimes, origin } => {
1316+
// Reset capturable lifetimes, any nested impl trait
1317+
// types will inherit lifetimes from this opaque type,
1318+
// so don't need to capture them again.
1319+
let nested_itctx = ImplTraitContext::OtherOpaqueTy {
1320+
capturable_lifetimes: &mut FxHashSet::default(),
1321+
origin,
1322+
};
1323+
self.lower_opaque_impl_trait(
1324+
span,
1325+
None,
1326+
origin,
1327+
def_node_id,
1328+
Some(capturable_lifetimes),
1329+
|this| this.lower_param_bounds(bounds, nested_itctx),
1330+
)
12771331
}
12781332
ImplTraitContext::Universal(in_band_ty_params) => {
12791333
// Add a definition for the in-band `Param`.
@@ -1351,6 +1405,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13511405
fn_def_id: Option<DefId>,
13521406
origin: hir::OpaqueTyOrigin,
13531407
opaque_ty_node_id: NodeId,
1408+
capturable_lifetimes: Option<&FxHashSet<hir::LifetimeName>>,
13541409
lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>,
13551410
) -> hir::TyKind<'hir> {
13561411
debug!(
@@ -1371,17 +1426,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13711426

13721427
let hir_bounds = self.with_hir_id_owner(opaque_ty_node_id, lower_bounds);
13731428

1374-
let (lifetimes, lifetime_defs): (&[_], &[_]) = if fn_def_id.is_some() {
1375-
self.lifetimes_from_impl_trait_bounds(opaque_ty_node_id, opaque_ty_def_id, &hir_bounds)
1376-
} else {
1377-
// Non return-position impl trait captures all of the lifetimes of
1378-
// the parent item.
1379-
(&[], &[])
1380-
};
1429+
let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
1430+
opaque_ty_node_id,
1431+
opaque_ty_def_id,
1432+
&hir_bounds,
1433+
capturable_lifetimes,
1434+
);
13811435

1382-
debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes,);
1436+
debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes);
13831437

1384-
debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs,);
1438+
debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs);
13851439

13861440
self.with_hir_id_owner(opaque_ty_node_id, move |lctx| {
13871441
let opaque_ty_item = hir::OpaqueTy {
@@ -1438,6 +1492,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14381492
opaque_ty_id: NodeId,
14391493
parent_def_id: LocalDefId,
14401494
bounds: hir::GenericBounds<'hir>,
1495+
lifetimes_to_include: Option<&FxHashSet<hir::LifetimeName>>,
14411496
) -> (&'hir [hir::GenericArg<'hir>], &'hir [hir::GenericParam<'hir>]) {
14421497
debug!(
14431498
"lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
@@ -1458,6 +1513,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14581513
already_defined_lifetimes: FxHashSet<hir::LifetimeName>,
14591514
output_lifetimes: Vec<hir::GenericArg<'hir>>,
14601515
output_lifetime_params: Vec<hir::GenericParam<'hir>>,
1516+
lifetimes_to_include: Option<&'r FxHashSet<hir::LifetimeName>>,
14611517
}
14621518

14631519
impl<'r, 'a, 'v, 'hir> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a, 'hir> {
@@ -1543,6 +1599,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15431599

15441600
if !self.currently_bound_lifetimes.contains(&name)
15451601
&& !self.already_defined_lifetimes.contains(&name)
1602+
&& self.lifetimes_to_include.map_or(true, |lifetimes| lifetimes.contains(&name))
15461603
{
15471604
self.already_defined_lifetimes.insert(name);
15481605

@@ -1596,6 +1653,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15961653
already_defined_lifetimes: FxHashSet::default(),
15971654
output_lifetimes: Vec::new(),
15981655
output_lifetime_params: Vec::new(),
1656+
lifetimes_to_include,
15991657
};
16001658

16011659
for bound in bounds {
@@ -1620,10 +1678,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16201678
}
16211679
}
16221680
let ty = l.ty.as_ref().map(|t| {
1681+
let mut capturable_lifetimes;
16231682
self.lower_ty(
16241683
t,
16251684
if self.sess.features_untracked().impl_trait_in_bindings {
1626-
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Binding)
1685+
capturable_lifetimes = FxHashSet::default();
1686+
ImplTraitContext::OtherOpaqueTy {
1687+
capturable_lifetimes: &mut capturable_lifetimes,
1688+
origin: hir::OpaqueTyOrigin::Binding,
1689+
}
16271690
} else {
16281691
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
16291692
},
@@ -1726,7 +1789,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
17261789
FnRetTy::Ty(ref ty) => {
17271790
let context = match in_band_ty_params {
17281791
Some((def_id, _)) if impl_trait_return_allow => {
1729-
ImplTraitContext::OpaqueTy(Some(def_id), hir::OpaqueTyOrigin::FnReturn)
1792+
ImplTraitContext::ReturnPositionOpaqueTy {
1793+
fn_def_id: def_id,
1794+
origin: hir::OpaqueTyOrigin::FnReturn,
1795+
}
17301796
}
17311797
_ => ImplTraitContext::disallowed(),
17321798
};
@@ -1945,7 +2011,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19452011
// Foo = impl Trait` is, internally, created as a child of the
19462012
// async fn, so the *type parameters* are inherited. It's
19472013
// only the lifetime parameters that we must supply.
1948-
let opaque_ty_ref = hir::TyKind::Def(hir::ItemId { id: opaque_ty_id }, generic_args);
2014+
let opaque_ty_ref = hir::TyKind::OpaqueDef(hir::ItemId { id: opaque_ty_id }, generic_args);
19492015
let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
19502016
hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
19512017
}
@@ -1963,8 +2029,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19632029
// Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
19642030
// `impl Future` opaque type that `async fn` implicitly
19652031
// generates.
1966-
let context =
1967-
ImplTraitContext::OpaqueTy(Some(fn_def_id), hir::OpaqueTyOrigin::FnReturn);
2032+
let context = ImplTraitContext::ReturnPositionOpaqueTy {
2033+
fn_def_id,
2034+
origin: hir::OpaqueTyOrigin::FnReturn,
2035+
};
19682036
self.lower_ty(ty, context)
19692037
}
19702038
FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
@@ -2114,7 +2182,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21142182
default: default.as_ref().map(|x| {
21152183
self.lower_ty(
21162184
x,
2117-
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc),
2185+
ImplTraitContext::OtherOpaqueTy {
2186+
capturable_lifetimes: &mut FxHashSet::default(),
2187+
origin: hir::OpaqueTyOrigin::Misc,
2188+
},
21182189
)
21192190
}),
21202191
synthetic: param
@@ -2170,8 +2241,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
21702241
&NodeMap::default(),
21712242
itctx.reborrow(),
21722243
);
2244+
21732245
let trait_ref = self.with_in_scope_lifetime_defs(&p.bound_generic_params, |this| {
2174-
this.lower_trait_ref(&p.trait_ref, itctx)
2246+
// Any impl Trait types defined within this scope can capture
2247+
// lifetimes bound on this predicate.
2248+
let lt_def_names = p.bound_generic_params.iter().filter_map(|param| match param.kind {
2249+
GenericParamKind::Lifetime { .. } => Some(hir::LifetimeName::Param(
2250+
ParamName::Plain(param.ident.normalize_to_macros_2_0()),
2251+
)),
2252+
_ => None,
2253+
});
2254+
if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx {
2255+
capturable_lifetimes.extend(lt_def_names.clone());
2256+
}
2257+
2258+
let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow());
2259+
2260+
if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx {
2261+
for param in lt_def_names {
2262+
capturable_lifetimes.remove(&param);
2263+
}
2264+
}
2265+
res
21752266
});
21762267

21772268
hir::PolyTraitRef { bound_generic_params, trait_ref, span: p.span }

src/librustc_typeck/astconv.rs

+14-15
Original file line numberDiff line numberDiff line change
@@ -2843,19 +2843,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
28432843
let def_id = tcx.hir().local_def_id(item_id.id).to_def_id();
28442844

28452845
match opaque_ty.kind {
2846-
// RPIT (return position impl trait)
2847-
// Only lifetimes mentioned in the impl Trait predicate are
2848-
// captured by the opaque type, so the lifetime parameters
2849-
// from the parent item need to be replaced with `'static`.
2850-
hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => {
2851-
self.impl_trait_ty_to_ty(def_id, lifetimes)
2852-
}
2853-
// This arm is for `impl Trait` in the types of statics,
2854-
// constants, locals and type aliases. These capture all
2855-
// parent lifetimes, so they can use their identity subst.
2856-
hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => {
2857-
let substs = InternalSubsts::identity_for_item(tcx, def_id);
2858-
tcx.mk_opaque(def_id, substs)
2846+
hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
2847+
self.impl_trait_ty_to_ty(def_id, lifetimes, impl_trait_fn.is_some())
28592848
}
28602849
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
28612850
}
@@ -2911,6 +2900,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
29112900
&self,
29122901
def_id: DefId,
29132902
lifetimes: &[hir::GenericArg<'_>],
2903+
replace_parent_lifetimes: bool,
29142904
) -> Ty<'tcx> {
29152905
debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes);
29162906
let tcx = self.tcx();
@@ -2932,9 +2922,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
29322922
_ => bug!(),
29332923
}
29342924
} else {
2935-
// Replace all parent lifetimes with `'static`.
29362925
match param.kind {
2937-
GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
2926+
// For RPIT (return position impl trait), only lifetimes
2927+
// mentioned in the impl Trait predicate are captured by
2928+
// the opaque type, so the lifetime parameters from the
2929+
// parent item need to be replaced with `'static`.
2930+
//
2931+
// For `impl Trait` in the types of statics, constants,
2932+
// locals and type aliases. These capture all parent
2933+
// lifetimes, so they can use their identity subst.
2934+
GenericParamDefKind::Lifetime if replace_parent_lifetimes => {
2935+
tcx.lifetimes.re_static.into()
2936+
}
29382937
_ => tcx.mk_param_from_def(param),
29392938
}
29402939
}

0 commit comments

Comments
 (0)