Skip to content

Commit a9e13fa

Browse files
committed
Lint elided lifetimes in path on the AST.
1 parent ca57bad commit a9e13fa

File tree

24 files changed

+279
-154
lines changed

24 files changed

+279
-154
lines changed

compiler/rustc_ast_lowering/src/lib.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -1835,7 +1835,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18351835
// Output lifetime like `'_`:
18361836
for (span, node_id) in lifetimes_to_define {
18371837
let param = this.fresh_lifetime_to_generic_param(span, node_id);
1838-
lifetime_params.push((span, hir::LifetimeName::Implicit(false)));
1838+
lifetime_params.push((span, hir::LifetimeName::Implicit));
18391839
generic_params.push(param);
18401840
}
18411841
let generic_params = this.arena.alloc_from_iter(generic_params);
@@ -2017,7 +2017,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20172017
});
20182018
let param_name = match lt.name {
20192019
hir::LifetimeName::Param(param_name) => param_name,
2020-
hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => {
2020+
hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
20212021
hir::ParamName::Plain(lt.name.ident())
20222022
}
20232023
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
@@ -2397,7 +2397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23972397

23982398
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
23992399

2400-
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span, false),
2400+
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
24012401
}
24022402
}
24032403

@@ -2416,12 +2416,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24162416
&'s mut self,
24172417
span: Span,
24182418
count: usize,
2419-
param_mode: ParamMode,
24202419
) -> impl Iterator<Item = hir::Lifetime> + Captures<'a> + Captures<'s> + Captures<'hir> {
2421-
(0..count).map(move |_| self.elided_path_lifetime(span, param_mode))
2420+
(0..count).map(move |_| self.elided_path_lifetime(span))
24222421
}
24232422

2424-
fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Lifetime {
2423+
fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
24252424
match self.anonymous_lifetime_mode {
24262425
AnonymousLifetimeMode::CreateParameter => {
24272426
// We should have emitted E0726 when processing this path above
@@ -2437,7 +2436,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24372436
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
24382437
// later, at which point a suitable error will be emitted.
24392438
AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
2440-
self.new_implicit_lifetime(span, param_mode == ParamMode::Explicit)
2439+
self.new_implicit_lifetime(span)
24412440
}
24422441
}
24432442
}
@@ -2480,11 +2479,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24802479
r
24812480
}
24822481

2483-
fn new_implicit_lifetime(&mut self, span: Span, missing: bool) -> hir::Lifetime {
2482+
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
24842483
hir::Lifetime {
24852484
hir_id: self.next_id(),
24862485
span: self.lower_span(span),
2487-
name: hir::LifetimeName::Implicit(missing),
2486+
name: hir::LifetimeName::Implicit,
24882487
}
24892488
}
24902489
}
@@ -2587,7 +2586,7 @@ fn lifetimes_from_impl_trait_bounds(
25872586

25882587
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
25892588
let name = match lifetime.name {
2590-
hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => {
2589+
hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
25912590
if self.collect_elided_lifetimes {
25922591
// Use `'_` for both implicit and underscore lifetimes in
25932592
// `type Foo<'_> = impl SomeTrait<'_>;`.

compiler/rustc_ast_lowering/src/path.rs

+4-35
Original file line numberDiff line numberDiff line change
@@ -290,47 +290,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
290290
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
291291
};
292292
generic_args.args = self
293-
.elided_path_lifetimes(elided_lifetime_span, expected_lifetimes, param_mode)
293+
.elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
294294
.map(GenericArg::Lifetime)
295295
.chain(generic_args.args.into_iter())
296296
.collect();
297-
// In create-parameter mode we error here because we don't want to support
298-
// deprecated impl elision in new features like impl elision and `async fn`,
299-
// both of which work using the `CreateParameter` mode:
300-
//
301-
// impl Foo for std::cell::Ref<u32> // note lack of '_
302-
// async fn foo(_: std::cell::Ref<u32>) { ... }
303297
if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) =
304298
(param_mode, self.anonymous_lifetime_mode)
305299
{
306-
let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
307-
let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
308-
let no_bindings = generic_args.bindings.is_empty();
309-
let (incl_angl_brckt, suggestion) = if no_non_lt_args && no_bindings {
310-
// If there are no generic args, our suggestion can include the angle brackets.
311-
(true, format!("<{}>", anon_lt_suggestion))
312-
} else {
313-
// Otherwise we'll insert a `'_, ` right after the opening bracket.
314-
(false, format!("{}, ", anon_lt_suggestion))
315-
};
316-
let insertion_sp = elided_lifetime_span.shrink_to_hi();
317-
let mut err = struct_span_err!(
318-
self.sess,
319-
path_span,
320-
E0726,
321-
"implicit elided lifetime not allowed here"
322-
);
323-
rustc_errors::add_elided_lifetime_in_path_suggestion(
324-
&self.sess.source_map(),
325-
&mut err,
326-
expected_lifetimes,
327-
path_span,
328-
incl_angl_brckt,
329-
insertion_sp,
330-
suggestion,
331-
);
332-
err.note("assuming a `'static` lifetime...");
333-
err.emit();
300+
// Late resolver should have issued the error.
301+
self.sess
302+
.delay_span_bug(elided_lifetime_span, "implicit lifetime not allowed here");
334303
}
335304
}
336305

compiler/rustc_borrowck/src/diagnostics/region_name.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
575575
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
576576
}
577577

578-
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => {
578+
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
579579
// In this case, the user left off the lifetime; so
580580
// they wrote something like:
581581
//

compiler/rustc_errors/src/lib.rs

+10-28
Original file line numberDiff line numberDiff line change
@@ -1511,35 +1511,17 @@ pub fn add_elided_lifetime_in_path_suggestion(
15111511
path_span: Span,
15121512
incl_angl_brckt: bool,
15131513
insertion_span: Span,
1514-
anon_lts: String,
15151514
) {
1516-
let (replace_span, suggestion) = if incl_angl_brckt {
1517-
(insertion_span, anon_lts)
1518-
} else {
1519-
// When possible, prefer a suggestion that replaces the whole
1520-
// `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
1521-
// at a point (which makes for an ugly/confusing label)
1522-
if let Ok(snippet) = source_map.span_to_snippet(path_span) {
1523-
// But our spans can get out of whack due to macros; if the place we think
1524-
// we want to insert `'_` isn't even within the path expression's span, we
1525-
// should bail out of making any suggestion rather than panicking on a
1526-
// subtract-with-overflow or string-slice-out-out-bounds (!)
1527-
// FIXME: can we do better?
1528-
if insertion_span.lo().0 < path_span.lo().0 {
1529-
return;
1530-
}
1531-
let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
1532-
if insertion_index > snippet.len() {
1533-
return;
1534-
}
1535-
let (before, after) = snippet.split_at(insertion_index);
1536-
(path_span, format!("{}{}{}", before, anon_lts, after))
1537-
} else {
1538-
(insertion_span, anon_lts)
1539-
}
1540-
};
1541-
diag.span_suggestion(
1542-
replace_span,
1515+
diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n)));
1516+
if source_map.span_to_snippet(insertion_span).is_err() {
1517+
// Do not try to suggest anything if generated by a proc-macro.
1518+
return;
1519+
}
1520+
let anon_lts = vec!["'_"; n].join(", ");
1521+
let suggestion =
1522+
if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) };
1523+
diag.span_suggestion_verbose(
1524+
insertion_span.shrink_to_hi(),
15431525
&format!("indicate the anonymous lifetime{}", pluralize!(n)),
15441526
suggestion,
15451527
Applicability::MachineApplicable,

compiler/rustc_hir/src/hir.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pub enum LifetimeName {
9595
/// User wrote nothing (e.g., the lifetime in `&u32`).
9696
///
9797
/// The bool indicates whether the user should have written something.
98-
Implicit(bool),
98+
Implicit,
9999

100100
/// Implicit lifetime in a context like `dyn Foo`. This is
101101
/// distinguished from implicit lifetimes elsewhere because the
@@ -125,7 +125,7 @@ impl LifetimeName {
125125
pub fn ident(&self) -> Ident {
126126
match *self {
127127
LifetimeName::ImplicitObjectLifetimeDefault
128-
| LifetimeName::Implicit(_)
128+
| LifetimeName::Implicit
129129
| LifetimeName::Error => Ident::empty(),
130130
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
131131
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
@@ -136,7 +136,7 @@ impl LifetimeName {
136136
pub fn is_elided(&self) -> bool {
137137
match self {
138138
LifetimeName::ImplicitObjectLifetimeDefault
139-
| LifetimeName::Implicit(_)
139+
| LifetimeName::Implicit
140140
| LifetimeName::Underscore => true,
141141

142142
// It might seem surprising that `Fresh(_)` counts as

compiler/rustc_hir/src/intravisit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
528528
| LifetimeName::Param(ParamName::Error)
529529
| LifetimeName::Static
530530
| LifetimeName::Error
531-
| LifetimeName::Implicit(_)
531+
| LifetimeName::Implicit
532532
| LifetimeName::ImplicitObjectLifetimeDefault
533533
| LifetimeName::Underscore => {}
534534
}

compiler/rustc_lint/src/context.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ use crate::passes::{EarlyLintPassObject, LateLintPassObject};
2121
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
2222
use rustc_data_structures::fx::FxHashMap;
2323
use rustc_data_structures::sync;
24-
use rustc_errors::{struct_span_err, Applicability, MultiSpan, SuggestionStyle};
24+
use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err};
25+
use rustc_errors::{Applicability, MultiSpan, SuggestionStyle};
2526
use rustc_hir as hir;
2627
use rustc_hir::def::Res;
2728
use rustc_hir::def_id::{CrateNum, DefId};
@@ -665,6 +666,21 @@ pub trait LintContext: Sized {
665666
) => {
666667
db.span_note(span_def, "the macro is defined here");
667668
}
669+
BuiltinLintDiagnostics::ElidedLifetimesInPaths(
670+
n,
671+
path_span,
672+
incl_angl_brckt,
673+
insertion_span,
674+
) => {
675+
add_elided_lifetime_in_path_suggestion(
676+
sess.source_map(),
677+
&mut db,
678+
n,
679+
path_span,
680+
incl_angl_brckt,
681+
insertion_span,
682+
);
683+
}
668684
BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
669685
db.span_suggestion(span, &note, sugg, Applicability::MaybeIncorrect);
670686
}

compiler/rustc_lint/src/early.rs

+5
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
284284
ast_visit::walk_path(self, p);
285285
}
286286

287+
fn visit_path_segment(&mut self, path_span: Span, s: &'a ast::PathSegment) {
288+
self.check_id(s.id);
289+
ast_visit::walk_path_segment(self, path_span, s);
290+
}
291+
287292
fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
288293
run_early_pass!(self, check_attribute, attr);
289294
}

compiler/rustc_lint_defs/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ pub enum BuiltinLintDiagnostics {
418418
AbsPathWithModule(Span),
419419
ProcMacroDeriveResolutionFallback(Span),
420420
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
421+
ElidedLifetimesInPaths(usize, Span, bool, Span),
421422
UnknownCrateTypes(Span, String, String),
422423
UnusedImports(String, Vec<(Span, String)>, Option<Span>),
423424
RedundantImport(Vec<(Span, bool)>, Ident),

compiler/rustc_resolve/src/build_reduced_graph.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -521,11 +521,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
521521
// while the current crate doesn't have a valid `crate_name`.
522522
if crate_name != kw::Empty {
523523
// `crate_name` should not be interpreted as relative.
524-
module_path.push(Segment {
525-
ident: Ident { name: kw::PathRoot, span: source.ident.span },
526-
id: Some(self.r.next_node_id()),
527-
has_generic_args: false,
528-
});
524+
module_path.push(Segment::from_ident_and_id(
525+
Ident { name: kw::PathRoot, span: source.ident.span },
526+
self.r.next_node_id(),
527+
));
529528
source.ident.name = crate_name;
530529
}
531530
if rename.is_none() {

compiler/rustc_resolve/src/ident.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1402,7 +1402,7 @@ impl<'a> Resolver<'a> {
14021402
let mut allow_super = true;
14031403
let mut second_binding = None;
14041404

1405-
for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
1405+
for (i, &Segment { ident, id, .. }) in path.iter().enumerate() {
14061406
debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
14071407
let record_segment_res = |this: &mut Self, res| {
14081408
if finalize.is_some() {

0 commit comments

Comments
 (0)