Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 447498f

Browse files
committedFeb 25, 2024·
Fix bad span for explicit lifetime suggestion
1 parent 43fdd49 commit 447498f

File tree

11 files changed

+194
-82
lines changed

11 files changed

+194
-82
lines changed
 

‎compiler/rustc_ast_lowering/src/lib.rs

+36-27
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ use rustc_errors::{DiagCtxt, DiagnosticArgFromDisplay, StashKey};
5555
use rustc_hir as hir;
5656
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
5757
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
58-
use rustc_hir::{ConstArg, GenericArg, ItemLocalMap, ParamName, TraitCandidate};
58+
use rustc_hir::{
59+
ConstArg, GenericArg, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate,
60+
};
5961
use rustc_index::{Idx, IndexSlice, IndexVec};
6062
use rustc_macros::extension;
6163
use rustc_middle::span_bug;
@@ -813,7 +815,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
813815
LifetimeRes::Param { .. } => {
814816
(hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
815817
}
816-
LifetimeRes::Fresh { param, .. } => {
818+
LifetimeRes::Fresh { param, kind, .. } => {
817819
// Late resolution delegates to us the creation of the `LocalDefId`.
818820
let _def_id = self.create_def(
819821
self.current_hir_id_owner.def_id,
@@ -824,7 +826,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
824826
);
825827
debug!(?_def_id);
826828

827-
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
829+
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind))
828830
}
829831
LifetimeRes::Static | LifetimeRes::Error => return None,
830832
res => panic!(
@@ -1628,13 +1630,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16281630

16291631
for lifetime in captured_lifetimes_to_duplicate {
16301632
let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
1631-
let old_def_id = match res {
1632-
LifetimeRes::Param { param: old_def_id, binder: _ } => old_def_id,
1633+
let (old_def_id, missing_kind) = match res {
1634+
LifetimeRes::Param { param: old_def_id, binder: _ } => (old_def_id, None),
16331635

1634-
LifetimeRes::Fresh { param, binder: _ } => {
1636+
LifetimeRes::Fresh { param, kind, .. } => {
16351637
debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
16361638
if let Some(old_def_id) = self.orig_opt_local_def_id(param) {
1637-
old_def_id
1639+
(old_def_id, Some(kind))
16381640
} else {
16391641
self.dcx()
16401642
.span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime");
@@ -1674,6 +1676,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16741676
duplicated_lifetime_node_id,
16751677
duplicated_lifetime_def_id,
16761678
self.lower_ident(lifetime.ident),
1679+
missing_kind,
16771680
));
16781681

16791682
// Now make an arg that we can use for the generic params of the opaque tykind.
@@ -1691,27 +1694,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16911694
let bounds = this
16921695
.with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
16931696

1694-
let generic_params = this.arena.alloc_from_iter(
1695-
synthesized_lifetime_definitions.iter().map(|&(new_node_id, new_def_id, ident)| {
1696-
let hir_id = this.lower_node_id(new_node_id);
1697-
let (name, kind) = if ident.name == kw::UnderscoreLifetime {
1698-
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
1699-
} else {
1700-
(hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
1701-
};
1697+
let generic_params =
1698+
this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map(
1699+
|&(new_node_id, new_def_id, ident, missing_kind)| {
1700+
let hir_id = this.lower_node_id(new_node_id);
1701+
let (name, kind) = if ident.name == kw::UnderscoreLifetime {
1702+
(
1703+
hir::ParamName::Fresh,
1704+
hir::LifetimeParamKind::Elided(
1705+
missing_kind.unwrap_or(MissingLifetimeKind::Underscore),
1706+
),
1707+
)
1708+
} else {
1709+
(hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
1710+
};
17021711

1703-
hir::GenericParam {
1704-
hir_id,
1705-
def_id: new_def_id,
1706-
name,
1707-
span: ident.span,
1708-
pure_wrt_drop: false,
1709-
kind: hir::GenericParamKind::Lifetime { kind },
1710-
colon_span: None,
1711-
source: hir::GenericParamSource::Generics,
1712-
}
1713-
}),
1714-
);
1712+
hir::GenericParam {
1713+
hir_id,
1714+
def_id: new_def_id,
1715+
name,
1716+
span: ident.span,
1717+
pure_wrt_drop: false,
1718+
kind: hir::GenericParamKind::Lifetime { kind },
1719+
colon_span: None,
1720+
source: hir::GenericParamSource::Generics,
1721+
}
1722+
},
1723+
));
17151724
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
17161725

17171726
let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args);

‎compiler/rustc_hir/src/def.rs

+2
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,8 @@ pub enum LifetimeRes {
802802
param: NodeId,
803803
/// Id of the introducing place. See `Param`.
804804
binder: NodeId,
805+
/// Kind of elided lifetime
806+
kind: hir::MissingLifetimeKind,
805807
},
806808
/// This variant is used for anonymous lifetimes that we did not resolve during
807809
/// late resolution. Those lifetimes will be inferred by typechecking.

‎compiler/rustc_hir/src/hir.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,18 @@ impl GenericBound<'_> {
456456

457457
pub type GenericBounds<'hir> = &'hir [GenericBound<'hir>];
458458

459+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic, Debug)]
460+
pub enum MissingLifetimeKind {
461+
/// An explicit `'_`.
462+
Underscore,
463+
/// An elided lifetime `&' ty`.
464+
Ampersand,
465+
/// An elided lifetime in brackets with written brackets.
466+
Comma,
467+
/// An elided lifetime with elided brackets.
468+
Brackets,
469+
}
470+
459471
#[derive(Copy, Clone, Debug, HashStable_Generic)]
460472
pub enum LifetimeParamKind {
461473
// Indicates that the lifetime definition was explicitly declared (e.g., in
@@ -464,7 +476,7 @@ pub enum LifetimeParamKind {
464476

465477
// Indication that the lifetime was elided (e.g., in both cases in
466478
// `fn foo(x: &u8) -> &'_ u8 { x }`).
467-
Elided,
479+
Elided(MissingLifetimeKind),
468480

469481
// Indication that the lifetime name was somehow in error.
470482
Error,
@@ -512,7 +524,7 @@ impl<'hir> GenericParam<'hir> {
512524
///
513525
/// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information.
514526
pub fn is_elided_lifetime(&self) -> bool {
515-
matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided })
527+
matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided(_) })
516528
}
517529
}
518530

‎compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1305,7 +1305,7 @@ fn compare_number_of_generics<'tcx>(
13051305
.iter()
13061306
.filter(|p| match p.kind {
13071307
hir::GenericParamKind::Lifetime {
1308-
kind: hir::LifetimeParamKind::Elided,
1308+
kind: hir::LifetimeParamKind::Elided(_),
13091309
} => {
13101310
// A fn can have an arbitrary number of extra elided lifetimes for the
13111311
// same signature.

‎compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs

+82-15
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use rustc_errors::{AddToDiagnostic, Applicability, DiagnosticBuilder, ErrorGuara
1313
use rustc_hir::def_id::DefId;
1414
use rustc_hir::intravisit::{walk_ty, Visitor};
1515
use rustc_hir::{
16-
self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, Node,
17-
TyKind,
16+
self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName,
17+
LifetimeParamKind, MissingLifetimeKind, Node, TyKind,
1818
};
1919
use rustc_middle::ty::{
2020
self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
@@ -356,20 +356,87 @@ pub fn suggest_new_region_bound(
356356
// introducing a new lifetime `'a` or making use of one from existing named lifetimes if any
357357
if let Some(id) = scope_def_id
358358
&& let Some(generics) = tcx.hir().get_generics(id)
359-
&& let mut spans_suggs = generics
360-
.params
361-
.iter()
362-
.filter(|p| p.is_elided_lifetime())
363-
.map(|p| {
364-
if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) {
365-
// Ampersand (elided without '_)
366-
(p.span.shrink_to_hi(), format!("{name} "))
367-
} else {
368-
// Underscore (elided with '_)
369-
(p.span, name.to_string())
359+
&& let mut spans_suggs = {
360+
fn finish_bracket(
361+
suggs: &mut Vec<(Span, String)>,
362+
name: &str,
363+
bracket_span: &mut Option<Span>,
364+
brackets: &mut usize,
365+
) {
366+
if let Some(span) = bracket_span.take() {
367+
let sugg: String = std::iter::once("<")
368+
.chain(
369+
std::iter::repeat(name)
370+
.take(*brackets)
371+
.intersperse(", "),
372+
)
373+
.chain([">"])
374+
.collect();
375+
suggs.push((span.shrink_to_hi(), sugg));
376+
*brackets = 0;
370377
}
371-
})
372-
.collect::<Vec<_>>()
378+
}
379+
let mut spans_suggs = Vec::new();
380+
let mut bracket_span = None::<Span>;
381+
let mut brackets = 0;
382+
for p in generics.params {
383+
if let GenericParamKind::Lifetime {
384+
kind: LifetimeParamKind::Elided(kind),
385+
} = p.kind
386+
{
387+
match kind {
388+
MissingLifetimeKind::Underscore => {
389+
finish_bracket(
390+
&mut spans_suggs,
391+
name,
392+
&mut bracket_span,
393+
&mut brackets,
394+
);
395+
spans_suggs.push((p.span, name.to_string()));
396+
}
397+
MissingLifetimeKind::Ampersand => {
398+
finish_bracket(
399+
&mut spans_suggs,
400+
name,
401+
&mut bracket_span,
402+
&mut brackets,
403+
);
404+
spans_suggs
405+
.push((p.span.shrink_to_hi(), format!("{name} ")));
406+
}
407+
MissingLifetimeKind::Comma => {
408+
finish_bracket(
409+
&mut spans_suggs,
410+
name,
411+
&mut bracket_span,
412+
&mut brackets,
413+
);
414+
spans_suggs
415+
.push((p.span.shrink_to_hi(), format!("{name}, ")));
416+
}
417+
MissingLifetimeKind::Brackets => {
418+
if bracket_span.is_some_and(|span| span != p.span) {
419+
finish_bracket(
420+
&mut spans_suggs,
421+
name,
422+
&mut bracket_span,
423+
&mut brackets,
424+
);
425+
}
426+
bracket_span = Some(p.span);
427+
brackets += 1;
428+
}
429+
}
430+
}
431+
}
432+
finish_bracket(
433+
&mut spans_suggs,
434+
name,
435+
&mut bracket_span,
436+
&mut brackets,
437+
);
438+
spans_suggs
439+
}
373440
&& spans_suggs.len() > 1
374441
{
375442
let use_lt = if existing_lt_name == None {

‎compiler/rustc_infer/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#![feature(extend_one)]
2424
#![feature(let_chains)]
2525
#![feature(if_let_guard)]
26+
#![feature(iter_intersperse)]
2627
#![feature(iterator_try_collect)]
2728
#![cfg_attr(bootstrap, feature(min_specialization))]
2829
#![feature(try_blocks)]

‎compiler/rustc_resolve/src/late.rs

+21-23
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_errors::{
2222
use rustc_hir::def::Namespace::{self, *};
2323
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
2424
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
25-
use rustc_hir::{PrimTy, TraitCandidate};
25+
use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate};
2626
use rustc_middle::middle::resolve_bound_vars::Set1;
2727
use rustc_middle::{bug, span_bug};
2828
use rustc_session::config::{CrateType, ResolveDocLinks};
@@ -43,9 +43,7 @@ type Res = def::Res<NodeId>;
4343

4444
type IdentMap<T> = FxHashMap<Ident, T>;
4545

46-
use diagnostics::{
47-
ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime, MissingLifetimeKind,
48-
};
46+
use diagnostics::{ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime};
4947

5048
#[derive(Copy, Clone, Debug)]
5149
struct BindingInfo {
@@ -1630,22 +1628,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
16301628
fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
16311629
debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
16321630

1633-
let missing_lifetime = MissingLifetime {
1634-
id: lifetime.id,
1635-
span: lifetime.ident.span,
1636-
kind: if elided {
1637-
MissingLifetimeKind::Ampersand
1638-
} else {
1639-
MissingLifetimeKind::Underscore
1640-
},
1641-
count: 1,
1642-
};
1631+
let kind =
1632+
if elided { MissingLifetimeKind::Ampersand } else { MissingLifetimeKind::Underscore };
1633+
let missing_lifetime =
1634+
MissingLifetime { id: lifetime.id, span: lifetime.ident.span, kind, count: 1 };
16431635
let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
16441636
for (i, rib) in self.lifetime_ribs.iter().enumerate().rev() {
16451637
debug!(?rib.kind);
16461638
match rib.kind {
16471639
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
1648-
let res = self.create_fresh_lifetime(lifetime.ident, binder);
1640+
let res = self.create_fresh_lifetime(lifetime.ident, binder, kind);
16491641
self.record_lifetime_res(lifetime.id, res, elision_candidate);
16501642
return;
16511643
}
@@ -1737,13 +1729,18 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
17371729
}
17381730

17391731
#[instrument(level = "debug", skip(self))]
1740-
fn create_fresh_lifetime(&mut self, ident: Ident, binder: NodeId) -> LifetimeRes {
1732+
fn create_fresh_lifetime(
1733+
&mut self,
1734+
ident: Ident,
1735+
binder: NodeId,
1736+
kind: MissingLifetimeKind,
1737+
) -> LifetimeRes {
17411738
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
17421739
debug!(?ident.span);
17431740

17441741
// Leave the responsibility to create the `LocalDefId` to lowering.
17451742
let param = self.r.next_node_id();
1746-
let res = LifetimeRes::Fresh { param, binder };
1743+
let res = LifetimeRes::Fresh { param, binder, kind };
17471744
self.record_lifetime_param(param, res);
17481745

17491746
// Record the created lifetime parameter so lowering can pick it up and add it to HIR.
@@ -1837,14 +1834,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
18371834
};
18381835
let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span);
18391836

1837+
let kind = if segment.has_generic_args {
1838+
MissingLifetimeKind::Comma
1839+
} else {
1840+
MissingLifetimeKind::Brackets
1841+
};
18401842
let missing_lifetime = MissingLifetime {
18411843
id: node_ids.start,
18421844
span: elided_lifetime_span,
1843-
kind: if segment.has_generic_args {
1844-
MissingLifetimeKind::Comma
1845-
} else {
1846-
MissingLifetimeKind::Brackets
1847-
},
1845+
kind,
18481846
count: expected_lifetimes,
18491847
};
18501848
let mut should_lint = true;
@@ -1890,7 +1888,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
18901888
// Group all suggestions into the first record.
18911889
let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
18921890
for id in node_ids {
1893-
let res = self.create_fresh_lifetime(ident, binder);
1891+
let res = self.create_fresh_lifetime(ident, binder, kind);
18941892
self.record_lifetime_res(
18951893
id,
18961894
res,

0 commit comments

Comments
 (0)
Please sign in to comment.