Skip to content

Commit bece117

Browse files
authored
Rollup merge of #63376 - nikomatsakis:async-await-issue-62517, r=cramertj
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 4486c02 + 7ee1af5 commit bece117

21 files changed

+429
-13
lines changed

src/librustc/hir/intravisit.rs

+1
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

+58-3
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ enum ParenthesizedGenericArgs {
322322
/// `resolve_lifetime` module. Often we "fallthrough" to that code by generating
323323
/// an "elided" or "underscore" lifetime name. In the future, we probably want to move
324324
/// everything into HIR lowering.
325-
#[derive(Copy, Clone)]
325+
#[derive(Copy, Clone, Debug)]
326326
enum AnonymousLifetimeMode {
327327
/// For **Modern** cases, create a new anonymous region parameter
328328
/// and reference that.
@@ -715,10 +715,16 @@ impl<'a> LoweringContext<'a> {
715715
anonymous_lifetime_mode: AnonymousLifetimeMode,
716716
op: impl FnOnce(&mut Self) -> R,
717717
) -> R {
718+
debug!(
719+
"with_anonymous_lifetime_mode(anonymous_lifetime_mode={:?})",
720+
anonymous_lifetime_mode,
721+
);
718722
let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
719723
self.anonymous_lifetime_mode = anonymous_lifetime_mode;
720724
let result = op(self);
721725
self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
726+
debug!("with_anonymous_lifetime_mode: restoring anonymous_lifetime_mode={:?}",
727+
old_anonymous_lifetime_mode);
722728
result
723729
}
724730

@@ -1355,6 +1361,13 @@ impl<'a> LoweringContext<'a> {
13551361
opaque_ty_node_id: NodeId,
13561362
lower_bounds: impl FnOnce(&mut LoweringContext<'_>) -> hir::GenericBounds,
13571363
) -> hir::TyKind {
1364+
debug!(
1365+
"lower_opaque_impl_trait(fn_def_id={:?}, opaque_ty_node_id={:?}, span={:?})",
1366+
fn_def_id,
1367+
opaque_ty_node_id,
1368+
span,
1369+
);
1370+
13581371
// Make sure we know that some funky desugaring has been going on here.
13591372
// This is a first: there is code in other places like for loop
13601373
// desugaring that explicitly states that we don't want to track that.
@@ -1382,6 +1395,14 @@ impl<'a> LoweringContext<'a> {
13821395
&hir_bounds,
13831396
);
13841397

1398+
debug!(
1399+
"lower_opaque_impl_trait: lifetimes={:#?}", lifetimes,
1400+
);
1401+
1402+
debug!(
1403+
"lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs,
1404+
);
1405+
13851406
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
13861407
let opaque_ty_item = hir::OpaqueTy {
13871408
generics: hir::Generics {
@@ -1397,7 +1418,7 @@ impl<'a> LoweringContext<'a> {
13971418
origin: hir::OpaqueTyOrigin::FnReturn,
13981419
};
13991420

1400-
trace!("exist ty from impl trait def-index: {:#?}", opaque_ty_def_index);
1421+
trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_index);
14011422
let opaque_ty_id = lctx.generate_opaque_type(
14021423
opaque_ty_node_id,
14031424
opaque_ty_item,
@@ -1445,6 +1466,13 @@ impl<'a> LoweringContext<'a> {
14451466
parent_index: DefIndex,
14461467
bounds: &hir::GenericBounds,
14471468
) -> (HirVec<hir::GenericArg>, HirVec<hir::GenericParam>) {
1469+
debug!(
1470+
"lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
1471+
parent_index={:?}, \
1472+
bounds={:#?})",
1473+
opaque_ty_id, parent_index, bounds,
1474+
);
1475+
14481476
// This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
14491477
// appear in the bounds, excluding lifetimes that are created within the bounds.
14501478
// E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
@@ -1532,6 +1560,11 @@ impl<'a> LoweringContext<'a> {
15321560
}
15331561
}
15341562
hir::LifetimeName::Param(_) => lifetime.name,
1563+
1564+
// Refers to some other lifetime that is "in
1565+
// scope" within the type.
1566+
hir::LifetimeName::ImplicitObjectLifetimeDefault => return,
1567+
15351568
hir::LifetimeName::Error | hir::LifetimeName::Static => return,
15361569
};
15371570

@@ -2182,6 +2215,14 @@ impl<'a> LoweringContext<'a> {
21822215
fn_def_id: DefId,
21832216
opaque_ty_node_id: NodeId,
21842217
) -> hir::FunctionRetTy {
2218+
debug!(
2219+
"lower_async_fn_ret_ty(\
2220+
output={:?}, \
2221+
fn_def_id={:?}, \
2222+
opaque_ty_node_id={:?})",
2223+
output, fn_def_id, opaque_ty_node_id,
2224+
);
2225+
21852226
let span = output.span();
21862227

21872228
let opaque_ty_span = self.mark_span_with_reason(
@@ -2264,6 +2305,8 @@ impl<'a> LoweringContext<'a> {
22642305
),
22652306
);
22662307

2308+
debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
2309+
22672310
// Calculate all the lifetimes that should be captured
22682311
// by the opaque type. This should include all in-scope
22692312
// lifetime parameters, including those defined in-band.
@@ -2512,6 +2555,12 @@ impl<'a> LoweringContext<'a> {
25122555
hir::LifetimeName::Implicit
25132556
| hir::LifetimeName::Underscore
25142557
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
2558+
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
2559+
span_bug!(
2560+
param.ident.span,
2561+
"object-lifetime-default should not occur here",
2562+
);
2563+
}
25152564
hir::LifetimeName::Error => ParamName::Error,
25162565
};
25172566

@@ -3255,7 +3304,13 @@ impl<'a> LoweringContext<'a> {
32553304
AnonymousLifetimeMode::PassThrough => {}
32563305
}
32573306

3258-
self.new_implicit_lifetime(span)
3307+
let r = hir::Lifetime {
3308+
hir_id: self.next_id(),
3309+
span,
3310+
name: hir::LifetimeName::ImplicitObjectLifetimeDefault,
3311+
};
3312+
debug!("elided_dyn_bound: r={:?}", r);
3313+
r
32593314
}
32603315

32613316
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {

src/librustc/hir/mod.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,19 @@ pub enum LifetimeName {
221221
/// User wrote nothing (e.g., the lifetime in `&u32`).
222222
Implicit,
223223

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

245260
pub fn is_elided(&self) -> bool {
246261
match self {
247-
LifetimeName::Implicit | LifetimeName::Underscore => true,
262+
LifetimeName::ImplicitObjectLifetimeDefault
263+
| LifetimeName::Implicit
264+
| LifetimeName::Underscore => true,
248265

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

src/librustc/infer/opaque_types/mod.rs

+1
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

+92-1
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
}

src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
578578
})
579579
}
580580

581-
hir::LifetimeName::Implicit => {
581+
hir::LifetimeName::ImplicitObjectLifetimeDefault
582+
| hir::LifetimeName::Implicit => {
582583
// In this case, the user left off the lifetime; so
583584
// they wrote something like:
584585
//

0 commit comments

Comments
 (0)