Skip to content

Clean up HIR-based lifetime resolution #99728

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 27, 2022
Prev Previous commit
Next Next commit
Replace LifetimeRes::Anonymous by LifetimeRes::Infer.
  • Loading branch information
cjgillot committed Jul 26, 2022
commit 10be0dd8dfc46eda4dc4d1555df31de2e8b7551a
20 changes: 1 addition & 19 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1883,25 +1883,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
hir::LifetimeName::Param(param, ParamName::Fresh)
}
LifetimeRes::Anonymous { binder } => {
let mut l_name = None;
if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
if !captured_lifetimes.binders_to_ignore.contains(&binder) {
let p_id = self.next_node_id();
let p_def_id = self.create_def(
captured_lifetimes.parent_def_id,
p_id,
DefPathData::LifetimeNs(kw::UnderscoreLifetime),
);
captured_lifetimes
.captures
.insert(p_def_id, (span, p_id, ParamName::Fresh, res));
l_name = Some(hir::LifetimeName::Param(p_def_id, ParamName::Fresh));
}
self.captured_lifetimes = Some(captured_lifetimes);
};
l_name.unwrap_or(hir::LifetimeName::Underscore)
}
LifetimeRes::Infer => hir::LifetimeName::Infer,
LifetimeRes::Static => hir::LifetimeName::Static,
LifetimeRes::Error => hir::LifetimeName::Error,
res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/diagnostics/region_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {

hir::LifetimeName::Param(_, hir::ParamName::Fresh)
| hir::LifetimeName::ImplicitObjectLifetimeDefault
| hir::LifetimeName::Underscore => {
| hir::LifetimeName::Infer => {
// In this case, the user left off the lifetime; so
// they wrote something like:
//
Expand Down
7 changes: 2 additions & 5 deletions compiler/rustc_hir/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -738,11 +738,8 @@ pub enum LifetimeRes {
binder: NodeId,
},
/// This variant is used for anonymous lifetimes that we did not resolve during
/// late resolution. Shifting the work to the HIR lifetime resolver.
Anonymous {
/// Id of the introducing place. See `Param`.
binder: NodeId,
},
/// late resolution. Those lifetimes will be inferred by typechecking.
Infer,
/// Explicit `'static` lifetime.
Static,
/// Resolution failure.
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ pub enum LifetimeName {
Error,

/// User wrote an anonymous lifetime, either `'_` or nothing.
Underscore,
/// The semantics of this lifetime should be inferred by typechecking code.
Infer,

/// User wrote `'static`.
Static,
Expand All @@ -118,7 +119,7 @@ impl LifetimeName {
pub fn ident(&self) -> Ident {
match *self {
LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Error => Ident::empty(),
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Infer => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
LifetimeName::Param(_, param_name) => param_name.ident(),
}
Expand All @@ -127,7 +128,7 @@ impl LifetimeName {
pub fn is_anonymous(&self) -> bool {
match *self {
LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Underscore
| LifetimeName::Infer
| LifetimeName::Param(_, ParamName::Fresh)
| LifetimeName::Error => true,
LifetimeName::Static | LifetimeName::Param(..) => false,
Expand All @@ -136,7 +137,7 @@ impl LifetimeName {

pub fn is_elided(&self) -> bool {
match self {
LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Underscore => true,
LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true,

// It might seem surprising that `Fresh` counts as
// *not* elided -- but this is because, as far as the code
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
| LifetimeName::Static
| LifetimeName::Error
| LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Underscore => {}
| LifetimeName::Infer => {}
}
}

Expand Down
108 changes: 37 additions & 71 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
let previous_state = replace(&mut this.in_func_body, true);
// Resolve the function body, potentially inside the body of an async closure
this.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Anonymous { binder: fn_id }),
LifetimeRibKind::Elided(LifetimeRes::Infer),
|this| this.visit_block(body),
);

Expand Down Expand Up @@ -893,9 +893,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
this.with_lifetime_rib(
match binder {
ClosureBinder::NotPresent => {
LifetimeRibKind::Elided(LifetimeRes::Anonymous {
binder: fn_id,
})
LifetimeRibKind::Elided(LifetimeRes::Infer)
}
ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError,
},
Expand All @@ -907,7 +905,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
let previous_state = replace(&mut this.in_func_body, true);
// Resolve the function body, potentially inside the body of an async closure
this.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Anonymous { binder: fn_id }),
LifetimeRibKind::Elided(LifetimeRes::Infer),
|this| this.visit_expr(body),
);

Expand Down Expand Up @@ -1645,35 +1643,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {

if !missing {
// Do not create a parameter for patterns and expressions.
for rib in self.lifetime_ribs.iter().rev() {
match rib.kind {
LifetimeRibKind::Elided(res @ LifetimeRes::Anonymous { .. }) => {
for id in node_ids {
self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named);
}
break;
}
// `LifetimeRes::Error`, which would usually be used in the case of
// `ReportError`, is unsuitable here, as we don't emit an error yet. Instead,
// we simply resolve to an implicit lifetime, which will be checked later, at
// which point a suitable error will be emitted.
LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
// FIXME(cjgillot) This resolution is wrong, but this does not matter
// since these cases are erroneous anyway. Lifetime resolution should
// emit a "missing lifetime specifier" diagnostic.
let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID };
for id in node_ids {
self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named);
}
break;
}
LifetimeRibKind::AnonymousCreateParameter { .. }
| LifetimeRibKind::Elided(_)
| LifetimeRibKind::ElisionFailure
| LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ConstGeneric
| LifetimeRibKind::AnonConst => {}
}
for id in node_ids {
self.record_lifetime_res(
id,
LifetimeRes::Infer,
LifetimeElisionCandidate::Named,
);
}
continue;
}
Expand Down Expand Up @@ -1814,15 +1789,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
)
}
match res {
LifetimeRes::Param { .. }
| LifetimeRes::Fresh { .. }
| LifetimeRes::Anonymous { .. }
| LifetimeRes::Static => {
LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => {
if let Some(ref mut candidates) = self.lifetime_elision_candidates {
candidates.insert(res, candidate);
}
}
LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {}
LifetimeRes::Infer | LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {}
}
}

Expand Down Expand Up @@ -2245,26 +2217,23 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
this.visit_ty(ty);
});
this.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Anonymous { binder: item.id }),
|this| {
if let Some(expr) = expr {
let constant_item_kind = match item.kind {
ItemKind::Const(..) => ConstantItemKind::Const,
ItemKind::Static(..) => ConstantItemKind::Static,
_ => unreachable!(),
};
// We already forbid generic params because of the above item rib,
// so it doesn't matter whether this is a trivial constant.
this.with_constant_rib(
IsRepeatExpr::No,
HasGenericParams::Yes,
Some((item.ident, constant_item_kind)),
|this| this.visit_expr(expr),
);
}
},
);
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
if let Some(expr) = expr {
let constant_item_kind = match item.kind {
ItemKind::Const(..) => ConstantItemKind::Const,
ItemKind::Static(..) => ConstantItemKind::Static,
_ => unreachable!(),
};
// We already forbid generic params because of the above item rib,
// so it doesn't matter whether this is a trivial constant.
this.with_constant_rib(
IsRepeatExpr::No,
HasGenericParams::Yes,
Some((item.ident, constant_item_kind)),
|this| this.visit_expr(expr),
);
}
});
});
}

Expand Down Expand Up @@ -2521,7 +2490,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
self.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Anonymous { binder: item.id }),
LifetimeRibKind::Elided(LifetimeRes::Infer),
|this| {
this.with_constant_rib(
IsRepeatExpr::No,
Expand Down Expand Up @@ -2694,17 +2663,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
self.with_lifetime_rib(
LifetimeRibKind::Elided(LifetimeRes::Anonymous { binder: item.id }),
|this| {
this.with_constant_rib(
IsRepeatExpr::No,
HasGenericParams::Yes,
None,
|this| this.visit_expr(expr),
)
},
);
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
this.with_constant_rib(
IsRepeatExpr::No,
HasGenericParams::Yes,
None,
|this| this.visit_expr(expr),
)
});
}
}
AssocItemKind::Fn(box Fn { generics, .. }) => {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_resolve/src/late/lifetimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// `Box<dyn Debug + 'static>`.
self.resolve_object_lifetime_default(lifetime)
}
LifetimeName::Underscore => {
LifetimeName::Infer => {
// If the user writes `'_`, we use the *ordinary* elision
// rules. So the `'_` in e.g., `Box<dyn Debug + '_>` will be
// resolved the same as the `'_` in `&'_ Foo`.
Expand Down Expand Up @@ -1135,7 +1135,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
#[tracing::instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
match lifetime_ref.name {
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Underscore => {
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Infer => {
self.resolve_elided_lifetimes(&[lifetime_ref])
}
hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
Expand Down
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_lints/src/manual_async_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
// - There's only one output lifetime bound using `+ '_`
// - All input lifetimes are explicitly bound to the output
input_lifetimes.is_empty()
|| (output_lifetimes.len() == 1 && matches!(output_lifetimes[0], LifetimeName::Underscore))
|| (output_lifetimes.len() == 1 && matches!(output_lifetimes[0], LifetimeName::Infer))
|| input_lifetimes
.iter()
.all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt))
Expand Down
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_lints/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ impl fmt::Display for RefPrefix {
name.fmt(f)?;
f.write_char(' ')?;
},
LifetimeName::Underscore => f.write_str("'_ ")?,
LifetimeName::Infer => f.write_str("'_ ")?,
LifetimeName::Static => f.write_str("'static ")?,
_ => (),
}
Expand Down