Add more precise span informations to generic types
This commit is contained in:
parent
ba8d7e2cb7
commit
b1c8835a0f
5 changed files with 66 additions and 53 deletions
|
@ -278,7 +278,7 @@ impl ParenthesizedArgs {
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|input| AngleBracketedArg::Arg(GenericArg::Type(input)))
|
.map(|input| AngleBracketedArg::Arg(GenericArg::Type(input)))
|
||||||
.collect();
|
.collect();
|
||||||
AngleBracketedArgs { span: self.span, args }
|
AngleBracketedArgs { span: self.inputs_span, args }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ use rustc_span::edition::Edition;
|
||||||
use rustc_span::hygiene::ExpnId;
|
use rustc_span::hygiene::ExpnId;
|
||||||
use rustc_span::source_map::{respan, DesugaringKind};
|
use rustc_span::source_map::{respan, DesugaringKind};
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
@ -2084,6 +2084,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
args: &[],
|
args: &[],
|
||||||
bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
|
bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
|
||||||
parenthesized: false,
|
parenthesized: false,
|
||||||
|
span_ext: DUMMY_SP,
|
||||||
});
|
});
|
||||||
|
|
||||||
hir::GenericBound::LangItemTrait(
|
hir::GenericBound::LangItemTrait(
|
||||||
|
@ -2788,6 +2789,7 @@ struct GenericArgsCtor<'hir> {
|
||||||
args: SmallVec<[hir::GenericArg<'hir>; 4]>,
|
args: SmallVec<[hir::GenericArg<'hir>; 4]>,
|
||||||
bindings: &'hir [hir::TypeBinding<'hir>],
|
bindings: &'hir [hir::TypeBinding<'hir>],
|
||||||
parenthesized: bool,
|
parenthesized: bool,
|
||||||
|
span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'hir> GenericArgsCtor<'hir> {
|
impl<'hir> GenericArgsCtor<'hir> {
|
||||||
|
@ -2800,6 +2802,7 @@ impl<'hir> GenericArgsCtor<'hir> {
|
||||||
args: arena.alloc_from_iter(self.args),
|
args: arena.alloc_from_iter(self.args),
|
||||||
bindings: self.bindings,
|
bindings: self.bindings,
|
||||||
parenthesized: self.parenthesized,
|
parenthesized: self.parenthesized,
|
||||||
|
span_ext: self.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use rustc_hir::GenericArg;
|
||||||
use rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS;
|
use rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS;
|
||||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::Span;
|
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||||
|
|
||||||
use smallvec::smallvec;
|
use smallvec::smallvec;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
@ -267,23 +267,34 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
|
(
|
||||||
|
GenericArgsCtor {
|
||||||
|
args: Default::default(),
|
||||||
|
bindings: &[],
|
||||||
|
parenthesized: false,
|
||||||
|
span: path_span.shrink_to_hi(),
|
||||||
|
},
|
||||||
|
param_mode == ParamMode::Optional,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let has_lifetimes =
|
let has_lifetimes =
|
||||||
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
|
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
|
||||||
let first_generic_span = generic_args
|
|
||||||
.args
|
|
||||||
.iter()
|
|
||||||
.map(|a| a.span())
|
|
||||||
.chain(generic_args.bindings.iter().map(|b| b.span))
|
|
||||||
.next();
|
|
||||||
if !generic_args.parenthesized && !has_lifetimes {
|
if !generic_args.parenthesized && !has_lifetimes {
|
||||||
|
// Note: these spans are used for diagnostics when they can't be inferred.
|
||||||
|
// See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
|
||||||
|
let elided_lifetime_span = if generic_args.span.is_empty() {
|
||||||
|
// If there are no brackets, use the identifier span.
|
||||||
|
segment.ident.span
|
||||||
|
} else if generic_args.is_empty() {
|
||||||
|
// If there are brackets, but not generic arguments, then use the opening bracket
|
||||||
|
generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
|
||||||
|
} else {
|
||||||
|
// Else use an empty span right after the opening bracket.
|
||||||
|
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
|
||||||
|
};
|
||||||
generic_args.args = self
|
generic_args.args = self
|
||||||
.elided_path_lifetimes(
|
.elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
|
||||||
first_generic_span.map_or(segment.ident.span, |s| s.shrink_to_lo()),
|
|
||||||
expected_lifetimes,
|
|
||||||
)
|
|
||||||
.map(GenericArg::Lifetime)
|
.map(GenericArg::Lifetime)
|
||||||
.chain(generic_args.args.into_iter())
|
.chain(generic_args.args.into_iter())
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -292,15 +303,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
|
let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
|
||||||
let no_bindings = generic_args.bindings.is_empty();
|
let no_bindings = generic_args.bindings.is_empty();
|
||||||
let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings {
|
let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings {
|
||||||
// If there are no (non-implicit) generic args or associated type
|
// If there are no generic args, our suggestion can include the angle brackets.
|
||||||
// bindings, our suggestion includes the angle brackets.
|
|
||||||
(true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
|
(true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
|
||||||
} else {
|
} else {
|
||||||
// Otherwise (sorry, this is kind of gross) we need to infer the
|
// Otherwise we'll insert a `'_, ` right after the opening bracket.
|
||||||
// place to splice in the `'_, ` from the generics that do exist.
|
let span = generic_args
|
||||||
let first_generic_span = first_generic_span
|
.span
|
||||||
.expect("already checked that non-lifetime args or bindings exist");
|
.with_lo(generic_args.span.lo() + BytePos(1))
|
||||||
(false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion))
|
.shrink_to_lo();
|
||||||
|
(false, span, format!("{}, ", anon_lt_suggestion))
|
||||||
};
|
};
|
||||||
match self.anonymous_lifetime_mode {
|
match self.anonymous_lifetime_mode {
|
||||||
// In create-parameter mode we error here because we don't want to support
|
// In create-parameter mode we error here because we don't want to support
|
||||||
|
@ -362,7 +373,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
hir_id: Some(id),
|
hir_id: Some(id),
|
||||||
res: Some(self.lower_res(res)),
|
res: Some(self.lower_res(res)),
|
||||||
infer_args,
|
infer_args,
|
||||||
args: if generic_args.is_empty() {
|
args: if generic_args.is_empty() && generic_args.span.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self.arena.alloc(generic_args.into_generic_args(self.arena)))
|
Some(self.arena.alloc(generic_args.into_generic_args(self.arena)))
|
||||||
|
@ -395,7 +406,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
AngleBracketedArg::Arg(_) => None,
|
AngleBracketedArg::Arg(_) => None,
|
||||||
}));
|
}));
|
||||||
let ctor = GenericArgsCtor { args, bindings, parenthesized: false };
|
let ctor = GenericArgsCtor { args, bindings, parenthesized: false, span: data.span };
|
||||||
(ctor, !has_non_lt_args && param_mode == ParamMode::Optional)
|
(ctor, !has_non_lt_args && param_mode == ParamMode::Optional)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +431,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))];
|
let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))];
|
||||||
let binding = this.output_ty_binding(output_ty.span, output_ty);
|
let binding = this.output_ty_binding(output_ty.span, output_ty);
|
||||||
(
|
(
|
||||||
GenericArgsCtor { args, bindings: arena_vec![this; binding], parenthesized: true },
|
GenericArgsCtor {
|
||||||
|
args,
|
||||||
|
bindings: arena_vec![this; binding],
|
||||||
|
parenthesized: true,
|
||||||
|
span: data.inputs_span,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -436,7 +452,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
let kind = hir::TypeBindingKind::Equality { ty };
|
let kind = hir::TypeBindingKind::Equality { ty };
|
||||||
let args = arena_vec![self;];
|
let args = arena_vec![self;];
|
||||||
let bindings = arena_vec![self;];
|
let bindings = arena_vec![self;];
|
||||||
let gen_args = self.arena.alloc(hir::GenericArgs { args, bindings, parenthesized: false });
|
let gen_args = self.arena.alloc(hir::GenericArgs {
|
||||||
|
args,
|
||||||
|
bindings,
|
||||||
|
parenthesized: false,
|
||||||
|
span_ext: DUMMY_SP,
|
||||||
|
});
|
||||||
hir::TypeBinding { hir_id: self.next_id(), gen_args, span, ident, kind }
|
hir::TypeBinding { hir_id: self.next_id(), gen_args, span, ident, kind }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub use rustc_ast::{CaptureBy, Movability, Mutability};
|
||||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||||
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
|
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
|
||||||
use rustc_macros::HashStable_Generic;
|
use rustc_macros::HashStable_Generic;
|
||||||
use rustc_span::source_map::{SourceMap, Spanned};
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::{def_id::LocalDefId, BytePos};
|
use rustc_span::{def_id::LocalDefId, BytePos};
|
||||||
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
||||||
|
@ -314,11 +314,18 @@ pub struct GenericArgs<'hir> {
|
||||||
/// This is required mostly for pretty-printing and diagnostics,
|
/// This is required mostly for pretty-printing and diagnostics,
|
||||||
/// but also for changing lifetime elision rules to be "function-like".
|
/// but also for changing lifetime elision rules to be "function-like".
|
||||||
pub parenthesized: bool,
|
pub parenthesized: bool,
|
||||||
|
/// The span encompassing arguments and the surrounding brackets `<>` or `()`
|
||||||
|
/// Foo<A, B, AssocTy = D> Fn(T, U, V) -> W
|
||||||
|
/// ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^
|
||||||
|
/// Note that this may be:
|
||||||
|
/// - empty, if there are no generic brackets (but there may be hidden lifetimes)
|
||||||
|
/// - dummy, if this was generated while desugaring
|
||||||
|
pub span_ext: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenericArgs<'_> {
|
impl GenericArgs<'_> {
|
||||||
pub const fn none() -> Self {
|
pub const fn none() -> Self {
|
||||||
Self { args: &[], bindings: &[], parenthesized: false }
|
Self { args: &[], bindings: &[], parenthesized: false, span_ext: DUMMY_SP }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inputs(&self) -> &[Ty<'_>] {
|
pub fn inputs(&self) -> &[Ty<'_>] {
|
||||||
|
@ -356,33 +363,17 @@ impl GenericArgs<'_> {
|
||||||
own_counts
|
own_counts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The span encompassing the text inside the surrounding brackets.
|
||||||
|
/// It will also include bindings if they aren't in the form `-> Ret`
|
||||||
|
/// Returns `None` if the span is empty (e.g. no brackets) or dummy
|
||||||
pub fn span(&self) -> Option<Span> {
|
pub fn span(&self) -> Option<Span> {
|
||||||
self.args
|
let span_ext = self.span_ext()?;
|
||||||
.iter()
|
Some(span_ext.with_lo(span_ext.lo() + BytePos(1)).with_hi(span_ext.hi() - BytePos(1)))
|
||||||
.filter(|arg| !arg.is_synthetic())
|
|
||||||
.map(|arg| arg.span())
|
|
||||||
.reduce(|span1, span2| span1.to(span2))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns span encompassing arguments and their surrounding `<>` or `()`
|
/// Returns span encompassing arguments and their surrounding `<>` or `()`
|
||||||
pub fn span_ext(&self, sm: &SourceMap) -> Option<Span> {
|
pub fn span_ext(&self) -> Option<Span> {
|
||||||
let mut span = self.span()?;
|
Some(self.span_ext).filter(|span| !span.is_empty())
|
||||||
|
|
||||||
let (o, c) = if self.parenthesized { ('(', ')') } else { ('<', '>') };
|
|
||||||
|
|
||||||
if let Ok(snippet) = sm.span_to_snippet(span) {
|
|
||||||
let snippet = snippet.as_bytes();
|
|
||||||
|
|
||||||
if snippet[0] != (o as u8) || snippet[snippet.len() - 1] != (c as u8) {
|
|
||||||
span = sm.span_extend_to_prev_char(span, o, true);
|
|
||||||
span = span.with_lo(span.lo() - BytePos(1));
|
|
||||||
|
|
||||||
span = sm.span_extend_to_next_char(span, c, true);
|
|
||||||
span = span.with_hi(span.hi() + BytePos(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(span)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
|
|
|
@ -695,13 +695,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if remove_entire_generics {
|
if remove_entire_generics {
|
||||||
let sm = self.tcx.sess.source_map();
|
|
||||||
|
|
||||||
let span = self
|
let span = self
|
||||||
.path_segment
|
.path_segment
|
||||||
.args
|
.args
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.span_ext(sm)
|
.span_ext()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_lo(self.path_segment.ident.span.hi());
|
.with_lo(self.path_segment.ident.span.hi());
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue