Skip to content

Commit 266783e

Browse files
committed
Auto merge of #63376 - nikomatsakis:async-await-issue-62517, r=<try>
use different lifetime name for object-lifetime-default elision Introduce a distinct value for `LifetimeName` to use when this is a object-lifetime-default elision. This allows us to avoid creating incorrect lifetime parameters for the opaque types that result. We really need to overhaul this setup at some point! It's getting increasingly byzantine. But this seems like a relatively... surgical fix. r? @cramertj Fixes #62517
2 parents 60960a2 + afa4a2a commit 266783e

22 files changed

+440
-14
lines changed

src/librustc/hir/intravisit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
433433
LifetimeName::Static |
434434
LifetimeName::Error |
435435
LifetimeName::Implicit |
436+
LifetimeName::ImplicitObjectLifetimeDefault |
436437
LifetimeName::Underscore => {}
437438
}
438439
}

src/librustc/hir/lowering.rs

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ enum ParenthesizedGenericArgs {
319319
/// `resolve_lifetime` module. Often we "fallthrough" to that code by generating
320320
/// an "elided" or "underscore" lifetime name. In the future, we probably want to move
321321
/// everything into HIR lowering.
322-
#[derive(Copy, Clone)]
322+
#[derive(Copy, Clone, Debug)]
323323
enum AnonymousLifetimeMode {
324324
/// For **Modern** cases, create a new anonymous region parameter
325325
/// and reference that.
@@ -357,7 +357,7 @@ enum AnonymousLifetimeMode {
357357
}
358358

359359
/// The type of elided lifetime replacement to perform on `async fn` return types.
360-
#[derive(Copy, Clone)]
360+
#[derive(Copy, Clone, Debug)]
361361
enum LtReplacement {
362362
/// Fresh name introduced by the single non-dyn elided lifetime
363363
/// in the arguments of the async fn.
@@ -756,10 +756,16 @@ impl<'a> LoweringContext<'a> {
756756
anonymous_lifetime_mode: AnonymousLifetimeMode,
757757
op: impl FnOnce(&mut Self) -> R,
758758
) -> R {
759+
debug!(
760+
"with_anonymous_lifetime_mode(anonymous_lifetime_mode={:?})",
761+
anonymous_lifetime_mode,
762+
);
759763
let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
760764
self.anonymous_lifetime_mode = anonymous_lifetime_mode;
761765
let result = op(self);
762766
self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
767+
debug!("with_anonymous_lifetime_mode: restoring anonymous_lifetime_mode={:?}",
768+
old_anonymous_lifetime_mode);
763769
result
764770
}
765771

@@ -1396,6 +1402,13 @@ impl<'a> LoweringContext<'a> {
13961402
opaque_ty_node_id: NodeId,
13971403
lower_bounds: impl FnOnce(&mut LoweringContext<'_>) -> hir::GenericBounds,
13981404
) -> hir::TyKind {
1405+
debug!(
1406+
"lower_opaque_impl_trait(fn_def_id={:?}, opaque_ty_node_id={:?}, span={:?})",
1407+
fn_def_id,
1408+
opaque_ty_node_id,
1409+
span,
1410+
);
1411+
13991412
// Make sure we know that some funky desugaring has been going on here.
14001413
// This is a first: there is code in other places like for loop
14011414
// desugaring that explicitly states that we don't want to track that.
@@ -1423,6 +1436,14 @@ impl<'a> LoweringContext<'a> {
14231436
&hir_bounds,
14241437
);
14251438

1439+
debug!(
1440+
"lower_opaque_impl_trait: lifetimes={:#?}", lifetimes,
1441+
);
1442+
1443+
debug!(
1444+
"lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs,
1445+
);
1446+
14261447
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
14271448
let opaque_ty_item = hir::OpaqueTy {
14281449
generics: hir::Generics {
@@ -1438,7 +1459,7 @@ impl<'a> LoweringContext<'a> {
14381459
origin: hir::OpaqueTyOrigin::FnReturn,
14391460
};
14401461

1441-
trace!("exist ty from impl trait def-index: {:#?}", opaque_ty_def_index);
1462+
trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_index);
14421463
let opaque_ty_id = lctx.generate_opaque_type(
14431464
opaque_ty_node_id,
14441465
opaque_ty_item,
@@ -1486,6 +1507,13 @@ impl<'a> LoweringContext<'a> {
14861507
parent_index: DefIndex,
14871508
bounds: &hir::GenericBounds,
14881509
) -> (HirVec<hir::GenericArg>, HirVec<hir::GenericParam>) {
1510+
debug!(
1511+
"lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
1512+
parent_index={:?}, \
1513+
bounds={:#?})",
1514+
opaque_ty_id, parent_index, bounds,
1515+
);
1516+
14891517
// This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
14901518
// appear in the bounds, excluding lifetimes that are created within the bounds.
14911519
// E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
@@ -1573,6 +1601,11 @@ impl<'a> LoweringContext<'a> {
15731601
}
15741602
}
15751603
hir::LifetimeName::Param(_) => lifetime.name,
1604+
1605+
// Refers to some other lifetime that is "in
1606+
// scope" within the type.
1607+
hir::LifetimeName::ImplicitObjectLifetimeDefault => return,
1608+
15761609
hir::LifetimeName::Error | hir::LifetimeName::Static => return,
15771610
};
15781611

@@ -2232,6 +2265,15 @@ impl<'a> LoweringContext<'a> {
22322265
opaque_ty_node_id: NodeId,
22332266
elided_lt_replacement: LtReplacement,
22342267
) -> hir::FunctionRetTy {
2268+
debug!(
2269+
"lower_async_fn_ret_ty(\
2270+
output={:?}, \
2271+
fn_def_id={:?}, \
2272+
opaque_ty_node_id={:?}, \
2273+
elided_lt_replacement={:?})",
2274+
output, fn_def_id, opaque_ty_node_id, elided_lt_replacement,
2275+
);
2276+
22352277
let span = output.span();
22362278

22372279
let opaque_ty_span = self.mark_span_with_reason(
@@ -2258,6 +2300,8 @@ impl<'a> LoweringContext<'a> {
22582300
),
22592301
);
22602302

2303+
debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
2304+
22612305
// Calculate all the lifetimes that should be captured
22622306
// by the opaque type. This should include all in-scope
22632307
// lifetime parameters, including those defined in-band.
@@ -2507,6 +2551,12 @@ impl<'a> LoweringContext<'a> {
25072551
hir::LifetimeName::Implicit
25082552
| hir::LifetimeName::Underscore
25092553
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
2554+
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
2555+
span_bug!(
2556+
param.ident.span,
2557+
"object-lifetime-default should not occur here",
2558+
);
2559+
}
25102560
hir::LifetimeName::Error => ParamName::Error,
25112561
};
25122562

@@ -3273,7 +3323,13 @@ impl<'a> LoweringContext<'a> {
32733323
AnonymousLifetimeMode::Replace(_) => {}
32743324
}
32753325

3276-
self.new_implicit_lifetime(span)
3326+
let r = hir::Lifetime {
3327+
hir_id: self.next_id(),
3328+
span,
3329+
name: hir::LifetimeName::ImplicitObjectLifetimeDefault,
3330+
};
3331+
debug!("elided_dyn_bound: r={:?}", r);
3332+
r
32773333
}
32783334

32793335
fn new_replacement_lifetime(

src/librustc/hir/mod.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,19 @@ pub enum LifetimeName {
222222
/// User wrote nothing (e.g., the lifetime in `&u32`).
223223
Implicit,
224224

225+
/// Implicit lifetime in a context like `dyn Foo`. This is
226+
/// distinguished from implicit lifetimes elsewhere because the
227+
/// lifetime that they default to must appear elsewhere within the
228+
/// enclosing type. This means that, in an `impl Trait` context, we
229+
/// don't have to create a parameter for them. That is, `impl
230+
/// Trait<Item = &u32>` expands to an opaque type like `type
231+
/// Foo<'a> = impl Trait<Item = &'a u32>`, but `impl Trait<item =
232+
/// dyn Bar>` expands to `type Foo = impl Trait<Item = dyn Bar +
233+
/// 'static>`. The latter uses `ImplicitObjectLifetimeDefault` so
234+
/// that surrounding code knows not to create a lifetime
235+
/// parameter.
236+
ImplicitObjectLifetimeDefault,
237+
225238
/// Indicates an error during lowering (usually `'_` in wrong place)
226239
/// that was already reported.
227240
Error,
@@ -236,7 +249,9 @@ pub enum LifetimeName {
236249
impl LifetimeName {
237250
pub fn ident(&self) -> Ident {
238251
match *self {
239-
LifetimeName::Implicit | LifetimeName::Error => Ident::invalid(),
252+
LifetimeName::ImplicitObjectLifetimeDefault
253+
| LifetimeName::Implicit
254+
| LifetimeName::Error => Ident::invalid(),
240255
LifetimeName::Underscore => Ident::with_empty_ctxt(kw::UnderscoreLifetime),
241256
LifetimeName::Static => Ident::with_empty_ctxt(kw::StaticLifetime),
242257
LifetimeName::Param(param_name) => param_name.ident(),
@@ -245,7 +260,9 @@ impl LifetimeName {
245260

246261
pub fn is_elided(&self) -> bool {
247262
match self {
248-
LifetimeName::Implicit | LifetimeName::Underscore => true,
263+
LifetimeName::ImplicitObjectLifetimeDefault
264+
| LifetimeName::Implicit
265+
| LifetimeName::Underscore => true,
249266

250267
// It might seem surprising that `Fresh(_)` counts as
251268
// *not* elided -- but this is because, as far as the code

src/librustc/infer/opaque_types/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
11081108
// Use the same type variable if the exact same opaque type appears more
11091109
// than once in the return type (e.g., if it's passed to a type alias).
11101110
if let Some(opaque_defn) = self.opaque_types.get(&def_id) {
1111+
debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
11111112
return opaque_defn.concrete_ty;
11121113
}
11131114
let span = tcx.def_span(def_id);

src/librustc/middle/resolve_lifetime.rs

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
//! used between functions, and they operate in a purely top-down
66
//! way. Therefore, we break lifetime name resolution into a separate pass.
77
8+
// ignore-tidy-filelength
9+
810
use crate::hir::def::{Res, DefKind};
911
use crate::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
1012
use crate::hir::map::Map;
@@ -556,6 +558,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
556558

557559
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
558560
debug!("visit_ty: id={:?} ty={:?}", ty.hir_id, ty);
561+
debug!("visit_ty: ty.node={:?}", ty.node);
559562
match ty.node {
560563
hir::TyKind::BareFn(ref c) => {
561564
let next_early_index = self.next_early_index();
@@ -585,11 +588,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
585588
self.is_in_fn_syntax = was_in_fn_syntax;
586589
}
587590
hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
591+
debug!("visit_ty: TraitObject(bounds={:?}, lifetime={:?})", bounds, lifetime);
588592
for bound in bounds {
589593
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
590594
}
591595
match lifetime.name {
592596
LifetimeName::Implicit => {
597+
// For types like `dyn Foo`, we should
598+
// generate a special form of elided.
599+
span_bug!(
600+
ty.span,
601+
"object-lifetime-default expected, not implict",
602+
);
603+
}
604+
LifetimeName::ImplicitObjectLifetimeDefault => {
593605
// If the user does not write *anything*, we
594606
// use the object lifetime defaulting
595607
// rules. So e.g., `Box<dyn Debug>` becomes
@@ -897,6 +909,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
897909
}
898910

899911
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
912+
debug!("visit_lifetime(lifetime_ref={:?})", lifetime_ref);
900913
if lifetime_ref.is_elided() {
901914
self.resolve_elided_lifetimes(vec![lifetime_ref]);
902915
return;
@@ -1911,6 +1924,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
19111924
}
19121925

19131926
fn visit_segment_args(&mut self, res: Res, depth: usize, generic_args: &'tcx hir::GenericArgs) {
1927+
debug!(
1928+
"visit_segment_args(res={:?}, depth={:?}, generic_args={:?})",
1929+
res,
1930+
depth,
1931+
generic_args,
1932+
);
1933+
19141934
if generic_args.parenthesized {
19151935
let was_in_fn_syntax = self.is_in_fn_syntax;
19161936
self.is_in_fn_syntax = true;
@@ -1964,6 +1984,23 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
19641984
_ => None,
19651985
};
19661986

1987+
debug!("visit_segment_args: type_def_id={:?}", type_def_id);
1988+
1989+
// Compute a vector of defaults, one for each type parameter,
1990+
// per the rules given in RFCs 599 and 1156. Example:
1991+
//
1992+
// ```rust
1993+
// struct Foo<'a, T: 'a, U> { }
1994+
// ```
1995+
//
1996+
// If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default
1997+
// `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound)
1998+
// and `dyn Baz` to `dyn Baz + 'static` (because there is no
1999+
// such bound).
2000+
//
2001+
// Therefore, we would compute `object_lifetime_defaults` to a
2002+
// vector like `['x, 'static]`. Note that the vector only
2003+
// includes type parameters.
19672004
let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| {
19682005
let in_body = {
19692006
let mut scope = self.scope;
@@ -2003,6 +2040,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20032040
.collect()
20042041
})
20052042
};
2043+
debug!("visit_segment_args: unsubst={:?}", unsubst);
20062044
unsubst
20072045
.iter()
20082046
.map(|set| match *set {
@@ -2023,6 +2061,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20232061
.collect()
20242062
});
20252063

2064+
debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults);
2065+
20262066
let mut i = 0;
20272067
for arg in &generic_args.args {
20282068
match arg {
@@ -2045,8 +2085,49 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20452085
}
20462086
}
20472087

2088+
// Hack: when resolving the type `XX` in binding like `dyn
2089+
// Foo<'b, Item = XX>`, the current object-lifetime default
2090+
// would be to examine the trait `Foo` to check whether it has
2091+
// a lifetime bound declared on `Item`. e.g., if `Foo` is
2092+
// declared like so, then the default object lifetime bound in
2093+
// `XX` should be `'b`:
2094+
//
2095+
// ```rust
2096+
// trait Foo<'a> {
2097+
// type Item: 'a;
2098+
// }
2099+
// ```
2100+
//
2101+
// but if we just have `type Item;`, then it would be
2102+
// `'static`. However, we don't get all of this logic correct.
2103+
//
2104+
// Instead, we do something hacky: if there are no lifetime parameters
2105+
// to the trait, then we simply use a default object lifetime
2106+
// bound of `'static`, because there is no other possibility. On the other hand,
2107+
// if there ARE lifetime parameters, then we require the user to give an
2108+
// explicit bound for now.
2109+
//
2110+
// This is intended to leave room for us to implement the
2111+
// correct behavior in the future.
2112+
let has_lifetime_parameter = generic_args
2113+
.args
2114+
.iter()
2115+
.any(|arg| match arg {
2116+
GenericArg::Lifetime(_) => true,
2117+
_ => false,
2118+
});
2119+
2120+
// Resolve lifetimes found in the type `XX` from `Item = XX` bindings.
20482121
for b in &generic_args.bindings {
2049-
self.visit_assoc_type_binding(b);
2122+
let scope = Scope::ObjectLifetimeDefault {
2123+
lifetime: if has_lifetime_parameter {
2124+
None
2125+
} else {
2126+
Some(Region::Static)
2127+
},
2128+
s: self.scope,
2129+
};
2130+
self.with(scope, |_, this| this.visit_assoc_type_binding(b));
20502131
}
20512132
}
20522133

@@ -2347,6 +2428,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
23472428
}
23482429

23492430
fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) {
2431+
debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs);
2432+
23502433
if lifetime_refs.is_empty() {
23512434
return;
23522435
}
@@ -2539,6 +2622,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
25392622
}
25402623

25412624
fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
2625+
debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref);
25422626
let mut late_depth = 0;
25432627
let mut scope = self.scope;
25442628
let lifetime = loop {
@@ -2638,6 +2722,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
26382722
hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
26392723
self.resolve_lifetime_ref(lt);
26402724
}
2725+
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
2726+
self.tcx.sess.delay_span_bug(
2727+
lt.span,
2728+
"lowering generated `ImplicitObjectLifetimeDefault` \
2729+
outside of an object type",
2730+
)
2731+
}
26412732
hir::LifetimeName::Error => {
26422733
// No need to do anything, error already reported.
26432734
}

0 commit comments

Comments
 (0)