Skip to content

Commit 7458385

Browse files
committed
Save colon span to suggest bounds.
1 parent 03bbb98 commit 7458385

File tree

13 files changed

+63
-53
lines changed

13 files changed

+63
-53
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ pub struct GenericParam {
397397
pub bounds: GenericBounds,
398398
pub is_placeholder: bool,
399399
pub kind: GenericParamKind,
400+
pub colon_span: Option<Span>,
400401
}
401402

402403
impl GenericParam {

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -867,9 +867,12 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
867867
mut param: GenericParam,
868868
vis: &mut T,
869869
) -> SmallVec<[GenericParam; 1]> {
870-
let GenericParam { id, ident, attrs, bounds, kind, is_placeholder: _ } = &mut param;
870+
let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param;
871871
vis.visit_id(id);
872872
vis.visit_ident(ident);
873+
if let Some(ref mut colon_span) = colon_span {
874+
vis.visit_span(colon_span);
875+
}
873876
visit_thin_attrs(attrs, vis);
874877
visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
875878
match kind {

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
707707
span: self.lower_span(ident.span),
708708
pure_wrt_drop: false,
709709
kind: hir::GenericParamKind::Lifetime { kind },
710+
colon_span: None,
710711
})
711712
}
712713

@@ -1304,6 +1305,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13041305
pure_wrt_drop: false,
13051306
span: self.lower_span(span),
13061307
kind: hir::GenericParamKind::Type { default: None, synthetic: true },
1308+
colon_span: None,
13071309
});
13081310
if let Some(preds) = self.lower_generic_bound_predicate(
13091311
ident,
@@ -1396,6 +1398,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13961398
span,
13971399
pure_wrt_drop: false,
13981400
kind: hir::GenericParamKind::Lifetime { kind },
1401+
colon_span: None,
13991402
}
14001403
},
14011404
));
@@ -1735,6 +1738,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
17351738
span,
17361739
pure_wrt_drop: false,
17371740
kind: hir::GenericParamKind::Lifetime { kind },
1741+
colon_span: None,
17381742
}
17391743
}));
17401744
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
@@ -2006,6 +2010,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20062010
span: self.lower_span(param.span()),
20072011
pure_wrt_drop: self.sess.contains_name(&param.attrs, sym::may_dangle),
20082012
kind,
2013+
colon_span: param.colon_span.map(|s| self.lower_span(s)),
20092014
}
20102015
}
20112016

compiler/rustc_builtin_macros/src/derive.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ fn dummy_annotatable() -> Annotatable {
9595
bounds: Default::default(),
9696
is_placeholder: false,
9797
kind: GenericParamKind::Lifetime,
98+
colon_span: None,
9899
})
99100
}
100101

compiler/rustc_expand/src/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ impl<'a> ExtCtxt<'a> {
113113
bounds,
114114
kind: ast::GenericParamKind::Type { default },
115115
is_placeholder: false,
116+
colon_span: None,
116117
}
117118
}
118119

compiler/rustc_expand/src/placeholders.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ pub fn placeholder(
149149
ident,
150150
is_placeholder: true,
151151
kind: ast::GenericParamKind::Lifetime,
152+
colon_span: None,
152153
}
153154
}]),
154155
AstFragmentKind::Params => AstFragment::Params(smallvec![ast::Param {

compiler/rustc_hir/src/hir.rs

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_error_messages::MultiSpan;
1717
use rustc_index::vec::IndexVec;
1818
use rustc_macros::HashStable_Generic;
1919
use rustc_span::hygiene::MacroKind;
20-
use rustc_span::source_map::{SourceMap, Spanned};
20+
use rustc_span::source_map::Spanned;
2121
use rustc_span::symbol::{kw, sym, Ident, Symbol};
2222
use rustc_span::{def_id::LocalDefId, BytePos, Span, DUMMY_SP};
2323
use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -499,6 +499,7 @@ pub struct GenericParam<'hir> {
499499
pub span: Span,
500500
pub pure_wrt_drop: bool,
501501
pub kind: GenericParamKind<'hir>,
502+
pub colon_span: Option<Span>,
502503
}
503504

504505
impl<'hir> GenericParam<'hir> {
@@ -515,40 +516,6 @@ impl<'hir> GenericParam<'hir> {
515516
pub fn is_elided_lifetime(&self) -> bool {
516517
matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided })
517518
}
518-
519-
/// Returns the span of `:` after a generic parameter.
520-
///
521-
/// For example:
522-
///
523-
/// ```text
524-
/// fn a<T:>()
525-
/// ^
526-
/// | here
527-
/// here |
528-
/// v
529-
/// fn b<T :>()
530-
///
531-
/// fn c<T
532-
///
533-
/// :>()
534-
/// ^
535-
/// |
536-
/// here
537-
/// ```
538-
pub fn colon_span_for_suggestions(&self, source_map: &SourceMap) -> Option<Span> {
539-
let sp = source_map
540-
.span_extend_while(self.span.shrink_to_hi(), |c| c.is_whitespace() || c == ':')
541-
.ok()?;
542-
543-
let snippet = source_map.span_to_snippet(sp).ok()?;
544-
let offset = snippet.find(':')?;
545-
546-
let colon_sp = sp
547-
.with_lo(BytePos(sp.lo().0 + offset as u32))
548-
.with_hi(BytePos(sp.lo().0 + (offset + ':'.len_utf8()) as u32));
549-
550-
Some(colon_sp)
551-
}
552519
}
553520

554521
#[derive(Default)]

compiler/rustc_middle/src/ty/diagnostics.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,19 @@ pub fn suggest_constraining_type_params<'a>(
363363
continue;
364364
}
365365

366+
// If user has provided a colon, don't suggest adding another:
367+
//
368+
// fn foo<T:>(t: T) { ... }
369+
// - insert: consider restricting this type parameter with `T: Foo`
370+
if let Some(colon_span) = param.colon_span {
371+
suggestions.push((
372+
colon_span.shrink_to_hi(),
373+
format!(" {}", constraint),
374+
SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
375+
));
376+
continue;
377+
}
378+
366379
// If user hasn't provided any bounds, suggest adding a new one:
367380
//
368381
// fn foo<T>(t: T) { ... }

compiler/rustc_parse/src/parser/generics.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ impl<'a> Parser<'a> {
3030
let ident = self.parse_ident()?;
3131

3232
// Parse optional colon and param bounds.
33+
let mut colon_span = None;
3334
let bounds = if self.eat(&token::Colon) {
34-
self.parse_generic_bounds(Some(self.prev_token.span))?
35+
colon_span = Some(self.prev_token.span);
36+
self.parse_generic_bounds(colon_span)?
3537
} else {
3638
Vec::new()
3739
};
@@ -45,6 +47,7 @@ impl<'a> Parser<'a> {
4547
bounds,
4648
kind: GenericParamKind::Type { default },
4749
is_placeholder: false,
50+
colon_span,
4851
})
4952
}
5053

@@ -69,6 +72,7 @@ impl<'a> Parser<'a> {
6972
bounds: Vec::new(),
7073
kind: GenericParamKind::Const { ty, kw_span: const_span, default },
7174
is_placeholder: false,
75+
colon_span: None,
7276
})
7377
}
7478

@@ -97,10 +101,10 @@ impl<'a> Parser<'a> {
97101
let param = if this.check_lifetime() {
98102
let lifetime = this.expect_lifetime();
99103
// Parse lifetime parameter.
100-
let bounds = if this.eat(&token::Colon) {
101-
this.parse_lt_param_bounds()
104+
let (colon_span, bounds) = if this.eat(&token::Colon) {
105+
(Some(this.prev_token.span), this.parse_lt_param_bounds())
102106
} else {
103-
Vec::new()
107+
(None, Vec::new())
104108
};
105109
Some(ast::GenericParam {
106110
ident: lifetime.ident,
@@ -109,6 +113,7 @@ impl<'a> Parser<'a> {
109113
bounds,
110114
kind: ast::GenericParamKind::Lifetime,
111115
is_placeholder: false,
116+
colon_span,
112117
})
113118
} else if this.check_keyword(kw::Const) {
114119
// Parse const parameter.

compiler/rustc_typeck/src/check/method/suggest.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1868,18 +1868,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18681868
// instead we suggest `T: Foo + Bar` in that case.
18691869
match hir.get(id) {
18701870
Node::GenericParam(param) => {
1871-
let impl_trait = matches!(
1872-
param.kind,
1873-
hir::GenericParamKind::Type { synthetic: true, .. },
1874-
);
1871+
enum Introducer {
1872+
Plus,
1873+
Colon,
1874+
Nothing,
1875+
}
18751876
let ast_generics = hir.get_generics(id.owner).unwrap();
1876-
let (sp, has_bounds) = if let Some(span) =
1877+
let (sp, mut introducer) = if let Some(span) =
18771878
ast_generics.bounds_span_for_suggestions(def_id)
18781879
{
1879-
(span, true)
1880+
(span, Introducer::Plus)
1881+
} else if let Some(colon_span) = param.colon_span {
1882+
(colon_span.shrink_to_hi(), Introducer::Nothing)
18801883
} else {
1881-
(hir.span(id).shrink_to_hi(), false)
1884+
(param.span.shrink_to_hi(), Introducer::Colon)
18821885
};
1886+
if matches!(
1887+
param.kind,
1888+
hir::GenericParamKind::Type { synthetic: true, .. },
1889+
) {
1890+
introducer = Introducer::Plus
1891+
}
18831892
let trait_def_ids: FxHashSet<DefId> = ast_generics
18841893
.bounds_for_param(def_id)
18851894
.flat_map(|bp| bp.bounds.iter())
@@ -1895,7 +1904,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18951904
candidates.iter().map(|t| {
18961905
format!(
18971906
"{} {}",
1898-
if has_bounds || impl_trait { " +" } else { ":" },
1907+
match introducer {
1908+
Introducer::Plus => " +",
1909+
Introducer::Colon => ":",
1910+
Introducer::Nothing => "",
1911+
},
18991912
self.tcx.def_path_str(t.def_id),
19001913
)
19011914
}),

src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ where
7070
}
7171

7272
#[rustfmt::skip]
73-
fn existing_colon<T: Copy:>(t: T) {
73+
fn existing_colon<T: Copy>(t: T) {
7474
//~^ HELP consider restricting type parameter `T`
7575
[t, t]; //~ use of moved value: `t`
7676
}

src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ LL | [t, t];
171171
|
172172
help: consider restricting type parameter `T`
173173
|
174-
LL | fn existing_colon<T: Copy:>(t: T) {
175-
| ++++++
174+
LL | fn existing_colon<T: Copy>(t: T) {
175+
| ++++
176176

177177
error: aborting due to 11 previous errors
178178

src/test/ui/traits/issue-95898.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ LL | t.clone();
77
= help: items from traits can only be used if the type parameter is bounded by the trait
88
help: the following trait defines an item `clone`, perhaps you need to restrict type parameter `T` with it:
99
|
10-
LL | fn foo<T: Clone:>(t: T) {
11-
| +++++++
10+
LL | fn foo<T: Clone>(t: T) {
11+
| +++++
1212

1313
error: aborting due to previous error
1414

0 commit comments

Comments
 (0)