Lint elided lifetimes in path on the AST.
This commit is contained in:
parent
ca57bada05
commit
a9e13fa553
24 changed files with 279 additions and 154 deletions
|
@ -1835,7 +1835,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// Output lifetime like `'_`:
|
||||
for (span, node_id) in lifetimes_to_define {
|
||||
let param = this.fresh_lifetime_to_generic_param(span, node_id);
|
||||
lifetime_params.push((span, hir::LifetimeName::Implicit(false)));
|
||||
lifetime_params.push((span, hir::LifetimeName::Implicit));
|
||||
generic_params.push(param);
|
||||
}
|
||||
let generic_params = this.arena.alloc_from_iter(generic_params);
|
||||
|
@ -2017,7 +2017,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
});
|
||||
let param_name = match lt.name {
|
||||
hir::LifetimeName::Param(param_name) => param_name,
|
||||
hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => {
|
||||
hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
|
||||
hir::ParamName::Plain(lt.name.ident())
|
||||
}
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
|
||||
|
@ -2397,7 +2397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
|
||||
|
||||
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span, false),
|
||||
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2416,12 +2416,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&'s mut self,
|
||||
span: Span,
|
||||
count: usize,
|
||||
param_mode: ParamMode,
|
||||
) -> impl Iterator<Item = hir::Lifetime> + Captures<'a> + Captures<'s> + Captures<'hir> {
|
||||
(0..count).map(move |_| self.elided_path_lifetime(span, param_mode))
|
||||
(0..count).map(move |_| self.elided_path_lifetime(span))
|
||||
}
|
||||
|
||||
fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Lifetime {
|
||||
fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
|
||||
match self.anonymous_lifetime_mode {
|
||||
AnonymousLifetimeMode::CreateParameter => {
|
||||
// We should have emitted E0726 when processing this path above
|
||||
|
@ -2437,7 +2436,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
|
||||
// later, at which point a suitable error will be emitted.
|
||||
AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
|
||||
self.new_implicit_lifetime(span, param_mode == ParamMode::Explicit)
|
||||
self.new_implicit_lifetime(span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2480,11 +2479,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
r
|
||||
}
|
||||
|
||||
fn new_implicit_lifetime(&mut self, span: Span, missing: bool) -> hir::Lifetime {
|
||||
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
|
||||
hir::Lifetime {
|
||||
hir_id: self.next_id(),
|
||||
span: self.lower_span(span),
|
||||
name: hir::LifetimeName::Implicit(missing),
|
||||
name: hir::LifetimeName::Implicit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2587,7 +2586,7 @@ fn lifetimes_from_impl_trait_bounds(
|
|||
|
||||
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
|
||||
let name = match lifetime.name {
|
||||
hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => {
|
||||
hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
|
||||
if self.collect_elided_lifetimes {
|
||||
// Use `'_` for both implicit and underscore lifetimes in
|
||||
// `type Foo<'_> = impl SomeTrait<'_>;`.
|
||||
|
|
|
@ -290,47 +290,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
|
||||
};
|
||||
generic_args.args = self
|
||||
.elided_path_lifetimes(elided_lifetime_span, expected_lifetimes, param_mode)
|
||||
.elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
|
||||
.map(GenericArg::Lifetime)
|
||||
.chain(generic_args.args.into_iter())
|
||||
.collect();
|
||||
// In create-parameter mode we error here because we don't want to support
|
||||
// deprecated impl elision in new features like impl elision and `async fn`,
|
||||
// both of which work using the `CreateParameter` mode:
|
||||
//
|
||||
// impl Foo for std::cell::Ref<u32> // note lack of '_
|
||||
// async fn foo(_: std::cell::Ref<u32>) { ... }
|
||||
if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) =
|
||||
(param_mode, self.anonymous_lifetime_mode)
|
||||
{
|
||||
let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
|
||||
let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
|
||||
let no_bindings = generic_args.bindings.is_empty();
|
||||
let (incl_angl_brckt, suggestion) = if no_non_lt_args && no_bindings {
|
||||
// If there are no generic args, our suggestion can include the angle brackets.
|
||||
(true, format!("<{}>", anon_lt_suggestion))
|
||||
} else {
|
||||
// Otherwise we'll insert a `'_, ` right after the opening bracket.
|
||||
(false, format!("{}, ", anon_lt_suggestion))
|
||||
};
|
||||
let insertion_sp = elided_lifetime_span.shrink_to_hi();
|
||||
let mut err = struct_span_err!(
|
||||
self.sess,
|
||||
path_span,
|
||||
E0726,
|
||||
"implicit elided lifetime not allowed here"
|
||||
);
|
||||
rustc_errors::add_elided_lifetime_in_path_suggestion(
|
||||
&self.sess.source_map(),
|
||||
&mut err,
|
||||
expected_lifetimes,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_sp,
|
||||
suggestion,
|
||||
);
|
||||
err.note("assuming a `'static` lifetime...");
|
||||
err.emit();
|
||||
// Late resolver should have issued the error.
|
||||
self.sess
|
||||
.delay_span_bug(elided_lifetime_span, "implicit lifetime not allowed here");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -575,7 +575,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
|
||||
}
|
||||
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => {
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
|
||||
// In this case, the user left off the lifetime; so
|
||||
// they wrote something like:
|
||||
//
|
||||
|
|
|
@ -1511,35 +1511,17 @@ pub fn add_elided_lifetime_in_path_suggestion(
|
|||
path_span: Span,
|
||||
incl_angl_brckt: bool,
|
||||
insertion_span: Span,
|
||||
anon_lts: String,
|
||||
) {
|
||||
let (replace_span, suggestion) = if incl_angl_brckt {
|
||||
(insertion_span, anon_lts)
|
||||
} else {
|
||||
// When possible, prefer a suggestion that replaces the whole
|
||||
// `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
|
||||
// at a point (which makes for an ugly/confusing label)
|
||||
if let Ok(snippet) = source_map.span_to_snippet(path_span) {
|
||||
// But our spans can get out of whack due to macros; if the place we think
|
||||
// we want to insert `'_` isn't even within the path expression's span, we
|
||||
// should bail out of making any suggestion rather than panicking on a
|
||||
// subtract-with-overflow or string-slice-out-out-bounds (!)
|
||||
// FIXME: can we do better?
|
||||
if insertion_span.lo().0 < path_span.lo().0 {
|
||||
return;
|
||||
}
|
||||
let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
|
||||
if insertion_index > snippet.len() {
|
||||
return;
|
||||
}
|
||||
let (before, after) = snippet.split_at(insertion_index);
|
||||
(path_span, format!("{}{}{}", before, anon_lts, after))
|
||||
} else {
|
||||
(insertion_span, anon_lts)
|
||||
}
|
||||
};
|
||||
diag.span_suggestion(
|
||||
replace_span,
|
||||
diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n)));
|
||||
if source_map.span_to_snippet(insertion_span).is_err() {
|
||||
// Do not try to suggest anything if generated by a proc-macro.
|
||||
return;
|
||||
}
|
||||
let anon_lts = vec!["'_"; n].join(", ");
|
||||
let suggestion =
|
||||
if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) };
|
||||
diag.span_suggestion_verbose(
|
||||
insertion_span.shrink_to_hi(),
|
||||
&format!("indicate the anonymous lifetime{}", pluralize!(n)),
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
|
|
|
@ -95,7 +95,7 @@ pub enum LifetimeName {
|
|||
/// User wrote nothing (e.g., the lifetime in `&u32`).
|
||||
///
|
||||
/// The bool indicates whether the user should have written something.
|
||||
Implicit(bool),
|
||||
Implicit,
|
||||
|
||||
/// Implicit lifetime in a context like `dyn Foo`. This is
|
||||
/// distinguished from implicit lifetimes elsewhere because the
|
||||
|
@ -125,7 +125,7 @@ impl LifetimeName {
|
|||
pub fn ident(&self) -> Ident {
|
||||
match *self {
|
||||
LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| LifetimeName::Implicit(_)
|
||||
| LifetimeName::Implicit
|
||||
| LifetimeName::Error => Ident::empty(),
|
||||
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
|
||||
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
|
||||
|
@ -136,7 +136,7 @@ impl LifetimeName {
|
|||
pub fn is_elided(&self) -> bool {
|
||||
match self {
|
||||
LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| LifetimeName::Implicit(_)
|
||||
| LifetimeName::Implicit
|
||||
| LifetimeName::Underscore => true,
|
||||
|
||||
// It might seem surprising that `Fresh(_)` counts as
|
||||
|
|
|
@ -528,7 +528,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
|
|||
| LifetimeName::Param(ParamName::Error)
|
||||
| LifetimeName::Static
|
||||
| LifetimeName::Error
|
||||
| LifetimeName::Implicit(_)
|
||||
| LifetimeName::Implicit
|
||||
| LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| LifetimeName::Underscore => {}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ use crate::passes::{EarlyLintPassObject, LateLintPassObject};
|
|||
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_errors::{struct_span_err, Applicability, MultiSpan, SuggestionStyle};
|
||||
use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err};
|
||||
use rustc_errors::{Applicability, MultiSpan, SuggestionStyle};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{CrateNum, DefId};
|
||||
|
@ -665,6 +666,21 @@ pub trait LintContext: Sized {
|
|||
) => {
|
||||
db.span_note(span_def, "the macro is defined here");
|
||||
}
|
||||
BuiltinLintDiagnostics::ElidedLifetimesInPaths(
|
||||
n,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_span,
|
||||
) => {
|
||||
add_elided_lifetime_in_path_suggestion(
|
||||
sess.source_map(),
|
||||
&mut db,
|
||||
n,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_span,
|
||||
);
|
||||
}
|
||||
BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
|
||||
db.span_suggestion(span, ¬e, sugg, Applicability::MaybeIncorrect);
|
||||
}
|
||||
|
|
|
@ -284,6 +284,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
|||
ast_visit::walk_path(self, p);
|
||||
}
|
||||
|
||||
fn visit_path_segment(&mut self, path_span: Span, s: &'a ast::PathSegment) {
|
||||
self.check_id(s.id);
|
||||
ast_visit::walk_path_segment(self, path_span, s);
|
||||
}
|
||||
|
||||
fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
|
||||
run_early_pass!(self, check_attribute, attr);
|
||||
}
|
||||
|
|
|
@ -418,6 +418,7 @@ pub enum BuiltinLintDiagnostics {
|
|||
AbsPathWithModule(Span),
|
||||
ProcMacroDeriveResolutionFallback(Span),
|
||||
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
|
||||
ElidedLifetimesInPaths(usize, Span, bool, Span),
|
||||
UnknownCrateTypes(Span, String, String),
|
||||
UnusedImports(String, Vec<(Span, String)>, Option<Span>),
|
||||
RedundantImport(Vec<(Span, bool)>, Ident),
|
||||
|
|
|
@ -521,11 +521,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
// while the current crate doesn't have a valid `crate_name`.
|
||||
if crate_name != kw::Empty {
|
||||
// `crate_name` should not be interpreted as relative.
|
||||
module_path.push(Segment {
|
||||
ident: Ident { name: kw::PathRoot, span: source.ident.span },
|
||||
id: Some(self.r.next_node_id()),
|
||||
has_generic_args: false,
|
||||
});
|
||||
module_path.push(Segment::from_ident_and_id(
|
||||
Ident { name: kw::PathRoot, span: source.ident.span },
|
||||
self.r.next_node_id(),
|
||||
));
|
||||
source.ident.name = crate_name;
|
||||
}
|
||||
if rename.is_none() {
|
||||
|
|
|
@ -1402,7 +1402,7 @@ impl<'a> Resolver<'a> {
|
|||
let mut allow_super = true;
|
||||
let mut second_binding = None;
|
||||
|
||||
for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
|
||||
for (i, &Segment { ident, id, .. }) in path.iter().enumerate() {
|
||||
debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
|
||||
let record_segment_res = |this: &mut Self, res| {
|
||||
if finalize.is_some() {
|
||||
|
|
|
@ -21,10 +21,11 @@ use rustc_hir::def::Namespace::{self, *};
|
|||
use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc_hir::{PrimTy, TraitCandidate};
|
||||
use rustc_middle::ty::DefIdTree;
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{BytePos, Span};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
|
@ -1167,6 +1168,134 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
self.resolve_anonymous_lifetime(<, true);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
fn resolve_elided_lifetimes_in_path(
|
||||
&mut self,
|
||||
path_id: NodeId,
|
||||
partial_res: PartialRes,
|
||||
path: &[Segment],
|
||||
source: PathSource<'_>,
|
||||
finalize: Finalize,
|
||||
) {
|
||||
let Some(path_span) = finalize.path_span() else {
|
||||
return;
|
||||
};
|
||||
let proj_start = path.len() - partial_res.unresolved_segments();
|
||||
for (i, segment) in path.iter().enumerate() {
|
||||
if segment.has_lifetime_args {
|
||||
continue;
|
||||
}
|
||||
let Some(segment_id) = segment.id else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Figure out if this is a type/trait segment,
|
||||
// which may need lifetime elision performed.
|
||||
let type_def_id = match partial_res.base_res() {
|
||||
Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
|
||||
self.r.parent(def_id).unwrap()
|
||||
}
|
||||
Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
|
||||
self.r.parent(def_id).unwrap()
|
||||
}
|
||||
Res::Def(DefKind::Struct, def_id)
|
||||
| Res::Def(DefKind::Union, def_id)
|
||||
| Res::Def(DefKind::Enum, def_id)
|
||||
| Res::Def(DefKind::TyAlias, def_id)
|
||||
| Res::Def(DefKind::Trait, def_id)
|
||||
if i + 1 == proj_start =>
|
||||
{
|
||||
def_id
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let expected_lifetimes = self.r.item_generics_num_lifetimes(type_def_id);
|
||||
if expected_lifetimes == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let missing = match source {
|
||||
PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true,
|
||||
PathSource::Expr(..)
|
||||
| PathSource::Pat
|
||||
| PathSource::Struct
|
||||
| PathSource::TupleStruct(..) => false,
|
||||
};
|
||||
let mut error = false;
|
||||
for rib in self.lifetime_ribs.iter().rev() {
|
||||
match rib.kind {
|
||||
// In create-parameter mode we error here because we don't want to support
|
||||
// deprecated impl elision in new features like impl elision and `async fn`,
|
||||
// both of which work using the `CreateParameter` mode:
|
||||
//
|
||||
// impl Foo for std::cell::Ref<u32> // note lack of '_
|
||||
// async fn foo(_: std::cell::Ref<u32>) { ... }
|
||||
LifetimeRibKind::AnonymousCreateParameter => {
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
// `PassThrough` is the normal case.
|
||||
// `new_error_lifetime`, which would usually be used in the case of `ReportError`,
|
||||
// is unsuitable here, as these can occur from missing lifetime parameters in a
|
||||
// `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
|
||||
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
|
||||
// later, at which point a suitable error will be emitted.
|
||||
LifetimeRibKind::AnonymousPassThrough
|
||||
| LifetimeRibKind::AnonymousReportError
|
||||
| LifetimeRibKind::Item => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if !missing {
|
||||
continue;
|
||||
}
|
||||
|
||||
let elided_lifetime_span = if segment.has_generic_args {
|
||||
// If there are brackets, but not generic arguments, then use the opening bracket
|
||||
segment.args_span.with_hi(segment.args_span.lo() + BytePos(1))
|
||||
} else {
|
||||
// If there are no brackets, use the identifier span.
|
||||
// HACK: we use find_ancestor_inside to properly suggest elided spans in paths
|
||||
// originating from macros, since the segment's span might be from a macro arg.
|
||||
segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
|
||||
};
|
||||
if error {
|
||||
let sess = self.r.session;
|
||||
let mut err = rustc_errors::struct_span_err!(
|
||||
sess,
|
||||
path_span,
|
||||
E0726,
|
||||
"implicit elided lifetime not allowed here"
|
||||
);
|
||||
rustc_errors::add_elided_lifetime_in_path_suggestion(
|
||||
sess.source_map(),
|
||||
&mut err,
|
||||
expected_lifetimes,
|
||||
path_span,
|
||||
!segment.has_generic_args,
|
||||
elided_lifetime_span,
|
||||
);
|
||||
err.note("assuming a `'static` lifetime...");
|
||||
err.emit();
|
||||
} else {
|
||||
self.r.lint_buffer.buffer_lint_with_diagnostic(
|
||||
lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
|
||||
segment_id,
|
||||
elided_lifetime_span,
|
||||
"hidden lifetime parameters in types are deprecated",
|
||||
lint::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
|
||||
expected_lifetimes,
|
||||
path_span,
|
||||
!segment.has_generic_args,
|
||||
elided_lifetime_span,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
|
||||
/// label and reports an error if the label is not found or is unreachable.
|
||||
fn resolve_label(&self, mut label: Ident) -> Option<NodeId> {
|
||||
|
@ -2528,6 +2657,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
self.r.record_partial_res(id, partial_res);
|
||||
}
|
||||
|
||||
self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize);
|
||||
partial_res
|
||||
}
|
||||
|
||||
|
|
|
@ -1986,38 +1986,6 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn report_elided_lifetime_in_ty(&self, lifetime_refs: &[&hir::Lifetime]) {
|
||||
let Some(missing_lifetime) = lifetime_refs.iter().find(|lt| {
|
||||
lt.name == hir::LifetimeName::Implicit(true)
|
||||
}) else { return };
|
||||
|
||||
let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
|
||||
spans.sort();
|
||||
let mut spans_dedup = spans.clone();
|
||||
spans_dedup.dedup();
|
||||
let spans_with_counts: Vec<_> = spans_dedup
|
||||
.into_iter()
|
||||
.map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count()))
|
||||
.collect();
|
||||
|
||||
self.tcx.struct_span_lint_hir(
|
||||
rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
|
||||
missing_lifetime.hir_id,
|
||||
spans,
|
||||
|lint| {
|
||||
let mut db = lint.build("hidden lifetime parameters in types are deprecated");
|
||||
self.add_missing_lifetime_specifiers_label(
|
||||
&mut db,
|
||||
spans_with_counts,
|
||||
&FxHashSet::from_iter([kw::UnderscoreLifetime]),
|
||||
Vec::new(),
|
||||
&[],
|
||||
);
|
||||
db.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
|
||||
// generics. We are disallowing this until we can decide on how we want to handle non-'static
|
||||
// lifetimes in const generics. See issue #74052 for discussion.
|
||||
|
@ -2452,9 +2420,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
|||
);
|
||||
let is_allowed_lifetime = matches!(
|
||||
lifetime_ref.name,
|
||||
hir::LifetimeName::Implicit(_)
|
||||
| hir::LifetimeName::Static
|
||||
| hir::LifetimeName::Underscore
|
||||
hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
|
||||
);
|
||||
|
||||
if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
|
||||
|
|
|
@ -921,7 +921,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
});
|
||||
match lifetime.name {
|
||||
LifetimeName::Implicit(_) => {
|
||||
LifetimeName::Implicit => {
|
||||
// For types like `dyn Foo`, we should
|
||||
// generate a special form of elided.
|
||||
span_bug!(ty.span, "object-lifetime-default expected, not implicit",);
|
||||
|
@ -2955,9 +2955,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
let error = loop {
|
||||
match *scope {
|
||||
// Do not assign any resolution, it will be inferred.
|
||||
Scope::Body { .. } => break Ok(()),
|
||||
Scope::Body { .. } => return,
|
||||
|
||||
Scope::Root => break Err(None),
|
||||
Scope::Root => break None,
|
||||
|
||||
Scope::Binder { s, ref lifetimes, scope_type, .. } => {
|
||||
// collect named lifetimes for suggestions
|
||||
|
@ -2984,7 +2984,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
|
||||
self.insert_lifetime(lifetime_ref, lifetime);
|
||||
}
|
||||
break Ok(());
|
||||
return;
|
||||
}
|
||||
|
||||
Scope::Elision { elide: Elide::Exact(l), .. } => {
|
||||
|
@ -2992,7 +2992,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
for lifetime_ref in lifetime_refs {
|
||||
self.insert_lifetime(lifetime_ref, lifetime);
|
||||
}
|
||||
break Ok(());
|
||||
return;
|
||||
}
|
||||
|
||||
Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => {
|
||||
|
@ -3017,10 +3017,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
_ => break,
|
||||
}
|
||||
}
|
||||
break Err(Some(&e[..]));
|
||||
break Some(&e[..]);
|
||||
}
|
||||
|
||||
Scope::Elision { elide: Elide::Forbid, .. } => break Err(None),
|
||||
Scope::Elision { elide: Elide::Forbid, .. } => break None,
|
||||
|
||||
Scope::ObjectLifetimeDefault { s, .. }
|
||||
| Scope::Supertrait { s, .. }
|
||||
|
@ -3030,14 +3030,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let error = match error {
|
||||
Ok(()) => {
|
||||
self.report_elided_lifetime_in_ty(lifetime_refs);
|
||||
return;
|
||||
}
|
||||
Err(error) => error,
|
||||
};
|
||||
|
||||
// If we specifically need the `scope_for_path` map, then we're in the
|
||||
// diagnostic pass and we don't want to emit more errors.
|
||||
if self.map.scope_for_path.is_some() {
|
||||
|
@ -3174,7 +3166,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
))
|
||||
.emit();
|
||||
}
|
||||
hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit(_) => {
|
||||
hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
|
||||
self.resolve_lifetime_ref(lt);
|
||||
}
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
|
||||
|
|
|
@ -28,7 +28,7 @@ pub use rustc_hir::def::{Namespace, PerNS};
|
|||
use rustc_arena::{DroplessArena, TypedArena};
|
||||
use rustc_ast::node_id::NodeMap;
|
||||
use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
|
||||
use rustc_ast::{Crate, Expr, ExprKind, LitKind, Path};
|
||||
use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
|
||||
use rustc_ast_lowering::ResolverAstLowering;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
|
@ -283,6 +283,9 @@ pub struct Segment {
|
|||
/// Signals whether this `PathSegment` has generic arguments. Used to avoid providing
|
||||
/// nonsensical suggestions.
|
||||
has_generic_args: bool,
|
||||
/// Signals whether this `PathSegment` has lifetime arguments.
|
||||
has_lifetime_args: bool,
|
||||
args_span: Span,
|
||||
}
|
||||
|
||||
impl Segment {
|
||||
|
@ -291,7 +294,23 @@ impl Segment {
|
|||
}
|
||||
|
||||
fn from_ident(ident: Ident) -> Segment {
|
||||
Segment { ident, id: None, has_generic_args: false }
|
||||
Segment {
|
||||
ident,
|
||||
id: None,
|
||||
has_generic_args: false,
|
||||
has_lifetime_args: false,
|
||||
args_span: DUMMY_SP,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_ident_and_id(ident: Ident, id: NodeId) -> Segment {
|
||||
Segment {
|
||||
ident,
|
||||
id: Some(id),
|
||||
has_generic_args: false,
|
||||
has_lifetime_args: false,
|
||||
args_span: DUMMY_SP,
|
||||
}
|
||||
}
|
||||
|
||||
fn names_to_string(segments: &[Segment]) -> String {
|
||||
|
@ -301,7 +320,28 @@ impl Segment {
|
|||
|
||||
impl<'a> From<&'a ast::PathSegment> for Segment {
|
||||
fn from(seg: &'a ast::PathSegment) -> Segment {
|
||||
Segment { ident: seg.ident, id: Some(seg.id), has_generic_args: seg.args.is_some() }
|
||||
let has_generic_args = seg.args.is_some();
|
||||
let (args_span, has_lifetime_args) = if let Some(args) = seg.args.as_deref() {
|
||||
match args {
|
||||
GenericArgs::AngleBracketed(args) => {
|
||||
let found_lifetimes = args
|
||||
.args
|
||||
.iter()
|
||||
.any(|arg| matches!(arg, AngleBracketedArg::Arg(GenericArg::Lifetime(_))));
|
||||
(args.span, found_lifetimes)
|
||||
}
|
||||
GenericArgs::Parenthesized(args) => (args.span, true),
|
||||
}
|
||||
} else {
|
||||
(DUMMY_SP, false)
|
||||
};
|
||||
Segment {
|
||||
ident: seg.ident,
|
||||
id: Some(seg.id),
|
||||
has_generic_args,
|
||||
has_lifetime_args,
|
||||
args_span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here
|
|||
--> $DIR/async-fn-path-elision.rs:5:20
|
||||
|
|
||||
LL | async fn error(lt: HasLifetime) {
|
||||
| ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
|
||||
| ^^^^^^^^^^^ expected lifetime parameter
|
||||
|
|
||||
= note: assuming a `'static` lifetime...
|
||||
help: indicate the anonymous lifetime
|
||||
|
|
||||
LL | async fn error(lt: HasLifetime<'_>) {
|
||||
| ++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here
|
|||
--> $DIR/path-elided.rs:7:18
|
||||
|
|
||||
LL | impl MyTrait for Foo {
|
||||
| ^^^- help: indicate the anonymous lifetime: `<'_>`
|
||||
| ^^^ expected lifetime parameter
|
||||
|
|
||||
= note: assuming a `'static` lifetime...
|
||||
help: indicate the anonymous lifetime
|
||||
|
|
||||
LL | impl MyTrait for Foo<'_> {
|
||||
| ++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here
|
|||
--> $DIR/trait-elided.rs:5:6
|
||||
|
|
||||
LL | impl MyTrait for u32 {}
|
||||
| ^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
|
||||
| ^^^^^^^ expected lifetime parameter
|
||||
|
|
||||
= note: assuming a `'static` lifetime...
|
||||
help: indicate the anonymous lifetime
|
||||
|
|
||||
LL | impl MyTrait<'_> for u32 {}
|
||||
| ++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -44,9 +44,13 @@ error[E0726]: implicit elided lifetime not allowed here
|
|||
--> $DIR/issue-10412.rs:7:13
|
||||
|
|
||||
LL | impl<'self> Serializable<str> for &'self str {
|
||||
| ^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Serializable<'_, str>`
|
||||
| ^^^^^^^^^^^^^^^^^ expected lifetime parameter
|
||||
|
|
||||
= note: assuming a `'static` lifetime...
|
||||
help: indicate the anonymous lifetime
|
||||
|
|
||||
LL | impl<'self> Serializable<'_, str> for &'self str {
|
||||
| +++
|
||||
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/issue-10412.rs:7:13
|
||||
|
|
|
@ -2,13 +2,17 @@ error: hidden lifetime parameters in types are deprecated
|
|||
--> $DIR/issue-91763.rs:8:20
|
||||
|
|
||||
LL | fn f() -> Ptr<Thing>;
|
||||
| ^ expected named lifetime parameter
|
||||
| ^ expected lifetime parameter
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-91763.rs:3:9
|
||||
|
|
||||
LL | #![deny(elided_lifetimes_in_paths)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: indicate the anonymous lifetime
|
||||
|
|
||||
LL | fn f() -> Ptr<Thing><'_>;
|
||||
| ++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@ warning: hidden lifetime parameters in types are deprecated
|
|||
--> $DIR/allowed-by-default-lint.rs:9:12
|
||||
|
|
||||
LL | fn foo(x: &Foo) {}
|
||||
| ^^^ expected named lifetime parameter
|
||||
| ^^^ expected lifetime parameter
|
||||
|
|
||||
= note: requested on the command line with `--force-warn elided-lifetimes-in-paths`
|
||||
help: consider using the `'_` lifetime
|
||||
help: indicate the anonymous lifetime
|
||||
|
|
||||
LL | fn foo(x: &Foo<'_>) {}
|
||||
| ~~~~~~~
|
||||
| ++++
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
|
|
|
@ -19,9 +19,9 @@ pub struct CheaterDetectionMechanism {}
|
|||
impl fmt::Debug for CheaterDetectionMechanism {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
//~^ WARN hidden lifetime parameters in types are deprecated
|
||||
//~| NOTE expected named lifetime parameter
|
||||
//~| NOTE expected lifetime parameter
|
||||
//~| NOTE explicit anonymous lifetimes aid
|
||||
//~| HELP consider using the `'_` lifetime
|
||||
//~| HELP indicate the anonymous lifetime
|
||||
fmt.debug_struct("CheaterDetectionMechanism").finish()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@ warning: hidden lifetime parameters in types are deprecated
|
|||
--> $DIR/reasons.rs:20:34
|
||||
|
|
||||
LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
| ^^^^^^^^^ expected named lifetime parameter
|
||||
| -----^^^^^^^^^
|
||||
| |
|
||||
| expected lifetime parameter
|
||||
|
|
||||
= note: explicit anonymous lifetimes aid reasoning about ownership
|
||||
note: the lint level is defined here
|
||||
|
@ -10,10 +12,10 @@ note: the lint level is defined here
|
|||
|
|
||||
LL | #![warn(elided_lifetimes_in_paths,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: consider using the `'_` lifetime
|
||||
help: indicate the anonymous lifetime
|
||||
|
|
||||
LL | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
| ~~~~~~~~~~~~~
|
||||
| ++++
|
||||
|
||||
warning: variable `Social_exchange_psychology` should have a snake case name
|
||||
--> $DIR/reasons.rs:30:9
|
||||
|
|
|
@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here
|
|||
--> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:13:16
|
||||
|
|
||||
LL | impl Trait for Ref {}
|
||||
| ^^^- help: indicate the anonymous lifetime: `<'_>`
|
||||
| ^^^ expected lifetime parameter
|
||||
|
|
||||
= note: assuming a `'static` lifetime...
|
||||
help: indicate the anonymous lifetime
|
||||
|
|
||||
LL | impl Trait for Ref<'_> {}
|
||||
| ++++
|
||||
|
||||
error: incompatible lifetime on type
|
||||
--> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:21
|
||||
|
|
Loading…
Add table
Reference in a new issue