Skip to content

Commit a072900

Browse files
committed
Compute lifetimes in scope at diagnostic time.
1 parent cb0584f commit a072900

File tree

9 files changed

+101
-94
lines changed

9 files changed

+101
-94
lines changed

compiler/rustc_ast_lowering/src/index.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
313313
});
314314
}
315315

316+
fn visit_assoc_type_binding(&mut self, type_binding: &'hir TypeBinding<'hir>) {
317+
self.insert(type_binding.span, type_binding.hir_id, Node::TypeBinding(type_binding));
318+
self.with_parent(type_binding.hir_id, |this| {
319+
intravisit::walk_assoc_type_binding(this, type_binding)
320+
})
321+
}
322+
316323
fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
317324
// Do not visit the duplicate information in TraitItemRef. We want to
318325
// map the actual nodes, not the duplicate ones in the *Ref.

compiler/rustc_hir/src/hir.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3302,6 +3302,7 @@ pub enum Node<'hir> {
33023302
Stmt(&'hir Stmt<'hir>),
33033303
PathSegment(&'hir PathSegment<'hir>),
33043304
Ty(&'hir Ty<'hir>),
3305+
TypeBinding(&'hir TypeBinding<'hir>),
33053306
TraitRef(&'hir TraitRef<'hir>),
33063307
Binding(&'hir Pat<'hir>),
33073308
Pat(&'hir Pat<'hir>),
@@ -3347,6 +3348,7 @@ impl<'hir> Node<'hir> {
33473348
| Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
33483349
Node::Lifetime(lt) => Some(lt.name.ident()),
33493350
Node::GenericParam(p) => Some(p.name.ident()),
3351+
Node::TypeBinding(b) => Some(b.ident),
33503352
Node::Param(..)
33513353
| Node::AnonConst(..)
33523354
| Node::Expr(..)

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ impl<'a> State<'a> {
8585
Node::Stmt(a) => self.print_stmt(&a),
8686
Node::PathSegment(a) => self.print_path_segment(&a),
8787
Node::Ty(a) => self.print_type(&a),
88+
Node::TypeBinding(a) => self.print_type_binding(&a),
8889
Node::TraitRef(a) => self.print_trait_ref(&a),
8990
Node::Binding(a) | Node::Pat(a) => self.print_pat(&a),
9091
Node::Arm(a) => self.print_arm(&a),
@@ -1703,21 +1704,7 @@ impl<'a> State<'a> {
17031704

17041705
for binding in generic_args.bindings.iter() {
17051706
start_or_comma(self);
1706-
self.print_ident(binding.ident);
1707-
self.print_generic_args(binding.gen_args, false, false);
1708-
self.space();
1709-
match generic_args.bindings[0].kind {
1710-
hir::TypeBindingKind::Equality { ref term } => {
1711-
self.word_space("=");
1712-
match term {
1713-
Term::Ty(ref ty) => self.print_type(ty),
1714-
Term::Const(ref c) => self.print_anon_const(c),
1715-
}
1716-
}
1717-
hir::TypeBindingKind::Constraint { bounds } => {
1718-
self.print_bounds(":", bounds);
1719-
}
1720-
}
1707+
self.print_type_binding(binding);
17211708
}
17221709

17231710
if !empty.get() {
@@ -1726,6 +1713,24 @@ impl<'a> State<'a> {
17261713
}
17271714
}
17281715

1716+
pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
1717+
self.print_ident(binding.ident);
1718+
self.print_generic_args(binding.gen_args, false, false);
1719+
self.space();
1720+
match binding.kind {
1721+
hir::TypeBindingKind::Equality { ref term } => {
1722+
self.word_space("=");
1723+
match term {
1724+
Term::Ty(ref ty) => self.print_type(ty),
1725+
Term::Const(ref c) => self.print_anon_const(c),
1726+
}
1727+
}
1728+
hir::TypeBindingKind::Constraint { bounds } => {
1729+
self.print_bounds(":", bounds);
1730+
}
1731+
}
1732+
}
1733+
17291734
pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
17301735
self.maybe_print_comment(pat.span.lo());
17311736
self.ann.pre(self, AnnNode::Pat(pat));

compiler/rustc_middle/src/hir/map/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ impl<'hir> Map<'hir> {
298298
Node::Stmt(_)
299299
| Node::PathSegment(_)
300300
| Node::Ty(_)
301+
| Node::TypeBinding(_)
301302
| Node::Infer(_)
302303
| Node::TraitRef(_)
303304
| Node::Pat(_)
@@ -323,7 +324,8 @@ impl<'hir> Map<'hir> {
323324
}
324325

325326
pub fn get_parent_node(self, hir_id: HirId) -> HirId {
326-
self.find_parent_node(hir_id).unwrap()
327+
self.find_parent_node(hir_id)
328+
.unwrap_or_else(|| bug!("No parent for node {:?}", self.node_to_string(hir_id)))
327329
}
328330

329331
/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
@@ -973,6 +975,7 @@ impl<'hir> Map<'hir> {
973975
.with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi()))
974976
}
975977
Node::Ty(ty) => ty.span,
978+
Node::TypeBinding(tb) => tb.span,
976979
Node::TraitRef(tr) => tr.path.span,
977980
Node::Binding(pat) => pat.span,
978981
Node::Pat(pat) => pat.span,
@@ -1205,6 +1208,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
12051208
Some(Node::Stmt(_)) => node_str("stmt"),
12061209
Some(Node::PathSegment(_)) => node_str("path segment"),
12071210
Some(Node::Ty(_)) => node_str("type"),
1211+
Some(Node::TypeBinding(_)) => node_str("type binding"),
12081212
Some(Node::TraitRef(_)) => node_str("trait ref"),
12091213
Some(Node::Binding(_)) => node_str("local"),
12101214
Some(Node::Pat(_)) => node_str("pat"),

compiler/rustc_middle/src/middle/resolve_lifetime.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ pub enum Region {
2323
pub enum LifetimeScopeForPath {
2424
/// Contains all lifetime names that are in scope and could possibly be used in generics
2525
/// arguments of path.
26-
NonElided(Vec<LocalDefId>),
27-
26+
NonElided,
2827
/// Information that allows us to suggest args of the form `<'_>` in case
2928
/// no generic arguments were provided for a path.
3029
Elided,

compiler/rustc_resolve/src/late/lifetimes.rs

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -517,30 +517,16 @@ fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::
517517

518518
#[tracing::instrument(level = "debug")]
519519
fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath {
520-
let mut available_lifetimes = vec![];
521520
loop {
522521
match scope {
523-
Scope::Binder { lifetimes, s, .. } => {
524-
available_lifetimes.extend(lifetimes.keys());
525-
scope = s;
526-
}
527-
Scope::Body { s, .. } => {
528-
scope = s;
529-
}
530-
Scope::Elision { elide, s } => {
531-
if let Elide::Exact(_) = elide {
532-
return LifetimeScopeForPath::Elided;
533-
} else {
534-
scope = s;
535-
}
536-
}
537-
Scope::ObjectLifetimeDefault { s, .. } => {
538-
scope = s;
539-
}
540-
Scope::Root => {
541-
return LifetimeScopeForPath::NonElided(available_lifetimes);
542-
}
543-
Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => {
522+
Scope::Elision { elide: Elide::Exact(_), .. } => return LifetimeScopeForPath::Elided,
523+
Scope::Root => return LifetimeScopeForPath::NonElided,
524+
Scope::Binder { s, .. }
525+
| Scope::Body { s, .. }
526+
| Scope::ObjectLifetimeDefault { s, .. }
527+
| Scope::Supertrait { s, .. }
528+
| Scope::TraitRefBoundary { s, .. }
529+
| Scope::Elision { s, .. } => {
544530
scope = s;
545531
}
546532
}
@@ -2170,6 +2156,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
21702156

21712157
// Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
21722158
Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None,
2159+
2160+
Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => None,
2161+
21732162
// Everything else (only closures?) doesn't
21742163
// actually enjoy elision in return types.
21752164
_ => {

compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
249249
| hir::Node::Stmt(..)
250250
| hir::Node::PathSegment(..)
251251
| hir::Node::Ty(..)
252+
| hir::Node::TypeBinding(..)
252253
| hir::Node::TraitRef(..)
253254
| hir::Node::Binding(..)
254255
| hir::Node::Pat(..)

compiler/rustc_typeck/src/collect/type_of.rs

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -450,21 +450,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
450450
.discr_type()
451451
.to_ty(tcx),
452452

453-
Node::TraitRef(trait_ref @ &TraitRef {
454-
path, ..
455-
}) if let Some((binding, seg)) =
456-
path
457-
.segments
458-
.iter()
459-
.find_map(|seg| {
460-
seg.args?.bindings
461-
.iter()
462-
.find_map(|binding| if binding.opt_const()?.hir_id == hir_id {
463-
Some((binding, seg))
464-
} else {
465-
None
466-
})
467-
}) =>
453+
Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
454+
if let Node::TraitRef(trait_ref) = tcx.hir().get(
455+
tcx.hir().get_parent_node(binding_id)
456+
) =>
468457
{
469458
let Some(trait_def_id) = trait_ref.trait_def_id() else {
470459
return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");

compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,52 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
291291
}
292292

293293
// Creates lifetime name suggestions from the lifetime parameter names
294-
fn get_lifetime_args_suggestions_from_param_names(&self, num_params_to_take: usize) -> String {
294+
fn get_lifetime_args_suggestions_from_param_names(
295+
&self,
296+
path_hir_id: Option<hir::HirId>,
297+
num_params_to_take: usize,
298+
) -> String {
299+
debug!(?path_hir_id);
300+
301+
if let Some(path_hir_id) = path_hir_id {
302+
// We first try to get lifetime name suggestions from scope or elision information.
303+
// If none is available we use the parameter definitions
304+
if let Some(LifetimeScopeForPath::Elided) = self.tcx.lifetime_scope(path_hir_id) {
305+
// Use suggestions of the form `<'_, '_>` in case lifetime can be elided
306+
return ["'_"].repeat(num_params_to_take).join(",");
307+
}
308+
309+
let mut ret = Vec::new();
310+
for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
311+
debug!(?id);
312+
let params = if let Some(generics) = node.generics() {
313+
generics.params
314+
} else if let hir::Node::Ty(ty) = node
315+
&& let hir::TyKind::BareFn(bare_fn) = ty.kind
316+
{
317+
bare_fn.generic_params
318+
} else {
319+
&[]
320+
};
321+
ret.extend(params.iter().filter_map(|p| {
322+
let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
323+
= p.kind
324+
else { return None };
325+
let hir::ParamName::Plain(name) = p.name else { return None };
326+
Some(name.to_string())
327+
}));
328+
if ret.len() >= num_params_to_take {
329+
return ret[..num_params_to_take].join(", ");
330+
}
331+
// We cannot refer to lifetimes defined in an outer function.
332+
if let hir::Node::Item(_) = node {
333+
break;
334+
}
335+
}
336+
}
337+
338+
// We could not gather enough lifetime parameters in the scope.
339+
// We use the parameter names from the target type's definition instead.
295340
self.gen_params
296341
.params
297342
.iter()
@@ -501,44 +546,10 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
501546
let num_params_to_take = num_missing_args;
502547
let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
503548

504-
// we first try to get lifetime name suggestions from scope or elision information. If none is
505-
// available we use the parameter definitions
506-
let suggested_args = if let Some(hir_id) = self.path_segment.hir_id {
507-
if let Some(lifetimes_in_scope) = self.tcx.lifetime_scope(hir_id) {
508-
match lifetimes_in_scope {
509-
LifetimeScopeForPath::NonElided(param_names) => {
510-
debug!("NonElided(param_names: {:?})", param_names);
511-
512-
if param_names.len() >= num_params_to_take {
513-
// use lifetime parameters in scope for suggestions
514-
param_names
515-
.iter()
516-
.take(num_params_to_take)
517-
.map(|def_id| {
518-
self.tcx.item_name(def_id.to_def_id()).to_ident_string()
519-
})
520-
.collect::<Vec<_>>()
521-
.join(", ")
522-
} else {
523-
// Not enough lifetime arguments in scope -> create suggestions from
524-
// lifetime parameter names in definition. An error for the incorrect
525-
// lifetime scope will be output later.
526-
self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
527-
}
528-
}
529-
LifetimeScopeForPath::Elided => {
530-
debug!("Elided");
531-
// use suggestions of the form `<'_, '_>` in case lifetime can be elided
532-
["'_"].repeat(num_params_to_take).join(",")
533-
}
534-
}
535-
} else {
536-
self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
537-
}
538-
} else {
539-
self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
540-
};
541-
549+
let suggested_args = self.get_lifetime_args_suggestions_from_param_names(
550+
self.path_segment.hir_id,
551+
num_params_to_take,
552+
);
542553
debug!("suggested_args: {:?}", &suggested_args);
543554

544555
match self.angle_brackets {

0 commit comments

Comments
 (0)