Save colon span to suggest bounds.
This commit is contained in:
parent
03bbb98019
commit
74583852e8
@ -397,6 +397,7 @@ pub struct GenericParam {
|
||||
pub bounds: GenericBounds,
|
||||
pub is_placeholder: bool,
|
||||
pub kind: GenericParamKind,
|
||||
pub colon_span: Option<Span>,
|
||||
}
|
||||
|
||||
impl GenericParam {
|
||||
|
@ -867,9 +867,12 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
|
||||
mut param: GenericParam,
|
||||
vis: &mut T,
|
||||
) -> SmallVec<[GenericParam; 1]> {
|
||||
let GenericParam { id, ident, attrs, bounds, kind, is_placeholder: _ } = &mut param;
|
||||
let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param;
|
||||
vis.visit_id(id);
|
||||
vis.visit_ident(ident);
|
||||
if let Some(ref mut colon_span) = colon_span {
|
||||
vis.visit_span(colon_span);
|
||||
}
|
||||
visit_thin_attrs(attrs, vis);
|
||||
visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
|
||||
match kind {
|
||||
|
@ -707,6 +707,7 @@ fn lifetime_res_to_generic_param(
|
||||
span: self.lower_span(ident.span),
|
||||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind },
|
||||
colon_span: None,
|
||||
})
|
||||
}
|
||||
|
||||
@ -1304,6 +1305,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
|
||||
pure_wrt_drop: false,
|
||||
span: self.lower_span(span),
|
||||
kind: hir::GenericParamKind::Type { default: None, synthetic: true },
|
||||
colon_span: None,
|
||||
});
|
||||
if let Some(preds) = self.lower_generic_bound_predicate(
|
||||
ident,
|
||||
@ -1396,6 +1398,7 @@ fn lower_opaque_impl_trait(
|
||||
span,
|
||||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind },
|
||||
colon_span: None,
|
||||
}
|
||||
},
|
||||
));
|
||||
@ -1735,6 +1738,7 @@ fn lower_async_fn_ret_ty(
|
||||
span,
|
||||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind },
|
||||
colon_span: None,
|
||||
}
|
||||
}));
|
||||
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
|
||||
@ -2006,6 +2010,7 @@ fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hi
|
||||
span: self.lower_span(param.span()),
|
||||
pure_wrt_drop: self.sess.contains_name(¶m.attrs, sym::may_dangle),
|
||||
kind,
|
||||
colon_span: param.colon_span.map(|s| self.lower_span(s)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,6 +95,7 @@ fn dummy_annotatable() -> Annotatable {
|
||||
bounds: Default::default(),
|
||||
is_placeholder: false,
|
||||
kind: GenericParamKind::Lifetime,
|
||||
colon_span: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -113,6 +113,7 @@ pub fn typaram(
|
||||
bounds,
|
||||
kind: ast::GenericParamKind::Type { default },
|
||||
is_placeholder: false,
|
||||
colon_span: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,6 +149,7 @@ fn mac_placeholder() -> ast::MacCall {
|
||||
ident,
|
||||
is_placeholder: true,
|
||||
kind: ast::GenericParamKind::Lifetime,
|
||||
colon_span: None,
|
||||
}
|
||||
}]),
|
||||
AstFragmentKind::Params => AstFragment::Params(smallvec![ast::Param {
|
||||
|
@ -17,7 +17,7 @@
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{def_id::LocalDefId, BytePos, Span, DUMMY_SP};
|
||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||
@ -499,6 +499,7 @@ pub struct GenericParam<'hir> {
|
||||
pub span: Span,
|
||||
pub pure_wrt_drop: bool,
|
||||
pub kind: GenericParamKind<'hir>,
|
||||
pub colon_span: Option<Span>,
|
||||
}
|
||||
|
||||
impl<'hir> GenericParam<'hir> {
|
||||
@ -515,40 +516,6 @@ pub fn is_impl_trait(&self) -> bool {
|
||||
pub fn is_elided_lifetime(&self) -> bool {
|
||||
matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided })
|
||||
}
|
||||
|
||||
/// Returns the span of `:` after a generic parameter.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```text
|
||||
/// fn a<T:>()
|
||||
/// ^
|
||||
/// | here
|
||||
/// here |
|
||||
/// v
|
||||
/// fn b<T :>()
|
||||
///
|
||||
/// fn c<T
|
||||
///
|
||||
/// :>()
|
||||
/// ^
|
||||
/// |
|
||||
/// here
|
||||
/// ```
|
||||
pub fn colon_span_for_suggestions(&self, source_map: &SourceMap) -> Option<Span> {
|
||||
let sp = source_map
|
||||
.span_extend_while(self.span.shrink_to_hi(), |c| c.is_whitespace() || c == ':')
|
||||
.ok()?;
|
||||
|
||||
let snippet = source_map.span_to_snippet(sp).ok()?;
|
||||
let offset = snippet.find(':')?;
|
||||
|
||||
let colon_sp = sp
|
||||
.with_lo(BytePos(sp.lo().0 + offset as u32))
|
||||
.with_hi(BytePos(sp.lo().0 + (offset + ':'.len_utf8()) as u32));
|
||||
|
||||
Some(colon_sp)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -363,6 +363,19 @@ pub fn suggest_constraining_type_params<'a>(
|
||||
continue;
|
||||
}
|
||||
|
||||
// If user has provided a colon, don't suggest adding another:
|
||||
//
|
||||
// fn foo<T:>(t: T) { ... }
|
||||
// - insert: consider restricting this type parameter with `T: Foo`
|
||||
if let Some(colon_span) = param.colon_span {
|
||||
suggestions.push((
|
||||
colon_span.shrink_to_hi(),
|
||||
format!(" {}", constraint),
|
||||
SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// If user hasn't provided any bounds, suggest adding a new one:
|
||||
//
|
||||
// fn foo<T>(t: T) { ... }
|
||||
|
@ -30,8 +30,10 @@ fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, Gen
|
||||
let ident = self.parse_ident()?;
|
||||
|
||||
// Parse optional colon and param bounds.
|
||||
let mut colon_span = None;
|
||||
let bounds = if self.eat(&token::Colon) {
|
||||
self.parse_generic_bounds(Some(self.prev_token.span))?
|
||||
colon_span = Some(self.prev_token.span);
|
||||
self.parse_generic_bounds(colon_span)?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
@ -45,6 +47,7 @@ fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, Gen
|
||||
bounds,
|
||||
kind: GenericParamKind::Type { default },
|
||||
is_placeholder: false,
|
||||
colon_span,
|
||||
})
|
||||
}
|
||||
|
||||
@ -69,6 +72,7 @@ fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, Gen
|
||||
bounds: Vec::new(),
|
||||
kind: GenericParamKind::Const { ty, kw_span: const_span, default },
|
||||
is_placeholder: false,
|
||||
colon_span: None,
|
||||
})
|
||||
}
|
||||
|
||||
@ -97,10 +101,10 @@ pub(super) fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericPar
|
||||
let param = if this.check_lifetime() {
|
||||
let lifetime = this.expect_lifetime();
|
||||
// Parse lifetime parameter.
|
||||
let bounds = if this.eat(&token::Colon) {
|
||||
this.parse_lt_param_bounds()
|
||||
let (colon_span, bounds) = if this.eat(&token::Colon) {
|
||||
(Some(this.prev_token.span), this.parse_lt_param_bounds())
|
||||
} else {
|
||||
Vec::new()
|
||||
(None, Vec::new())
|
||||
};
|
||||
Some(ast::GenericParam {
|
||||
ident: lifetime.ident,
|
||||
@ -109,6 +113,7 @@ pub(super) fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericPar
|
||||
bounds,
|
||||
kind: ast::GenericParamKind::Lifetime,
|
||||
is_placeholder: false,
|
||||
colon_span,
|
||||
})
|
||||
} else if this.check_keyword(kw::Const) {
|
||||
// Parse const parameter.
|
||||
|
@ -1868,18 +1868,27 @@ fn suggest_traits_to_import(
|
||||
// instead we suggest `T: Foo + Bar` in that case.
|
||||
match hir.get(id) {
|
||||
Node::GenericParam(param) => {
|
||||
let impl_trait = matches!(
|
||||
param.kind,
|
||||
hir::GenericParamKind::Type { synthetic: true, .. },
|
||||
);
|
||||
enum Introducer {
|
||||
Plus,
|
||||
Colon,
|
||||
Nothing,
|
||||
}
|
||||
let ast_generics = hir.get_generics(id.owner).unwrap();
|
||||
let (sp, has_bounds) = if let Some(span) =
|
||||
let (sp, mut introducer) = if let Some(span) =
|
||||
ast_generics.bounds_span_for_suggestions(def_id)
|
||||
{
|
||||
(span, true)
|
||||
(span, Introducer::Plus)
|
||||
} else if let Some(colon_span) = param.colon_span {
|
||||
(colon_span.shrink_to_hi(), Introducer::Nothing)
|
||||
} else {
|
||||
(hir.span(id).shrink_to_hi(), false)
|
||||
(param.span.shrink_to_hi(), Introducer::Colon)
|
||||
};
|
||||
if matches!(
|
||||
param.kind,
|
||||
hir::GenericParamKind::Type { synthetic: true, .. },
|
||||
) {
|
||||
introducer = Introducer::Plus
|
||||
}
|
||||
let trait_def_ids: FxHashSet<DefId> = ast_generics
|
||||
.bounds_for_param(def_id)
|
||||
.flat_map(|bp| bp.bounds.iter())
|
||||
@ -1895,7 +1904,11 @@ fn suggest_traits_to_import(
|
||||
candidates.iter().map(|t| {
|
||||
format!(
|
||||
"{} {}",
|
||||
if has_bounds || impl_trait { " +" } else { ":" },
|
||||
match introducer {
|
||||
Introducer::Plus => " +",
|
||||
Introducer::Colon => ":",
|
||||
Introducer::Nothing => "",
|
||||
},
|
||||
self.tcx.def_path_str(t.def_id),
|
||||
)
|
||||
}),
|
||||
|
@ -70,7 +70,7 @@ where
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn existing_colon<T: Copy:>(t: T) {
|
||||
fn existing_colon<T: Copy>(t: T) {
|
||||
//~^ HELP consider restricting type parameter `T`
|
||||
[t, t]; //~ use of moved value: `t`
|
||||
}
|
||||
|
@ -171,8 +171,8 @@ LL | [t, t];
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | fn existing_colon<T: Copy:>(t: T) {
|
||||
| ++++++
|
||||
LL | fn existing_colon<T: Copy>(t: T) {
|
||||
| ++++
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
|
@ -7,8 +7,8 @@ LL | t.clone();
|
||||
= help: items from traits can only be used if the type parameter is bounded by the trait
|
||||
help: the following trait defines an item `clone`, perhaps you need to restrict type parameter `T` with it:
|
||||
|
|
||||
LL | fn foo<T: Clone:>(t: T) {
|
||||
| +++++++
|
||||
LL | fn foo<T: Clone>(t: T) {
|
||||
| +++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user