Skip to content

Commit eea91c3

Browse files
authored
Rollup merge of #70519 - estebank:constraints-before-args-spans, r=Centril
Tweak output of type params and constraints in the wrong order r? @Centril @varkor
2 parents 83f8c02 + 17a9523 commit eea91c3

File tree

8 files changed

+146
-61
lines changed

8 files changed

+146
-61
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3564,6 +3564,7 @@ dependencies = [
35643564
name = "rustc_ast_passes"
35653565
version = "0.0.0"
35663566
dependencies = [
3567+
"itertools 0.8.0",
35673568
"log",
35683569
"rustc_ast",
35693570
"rustc_ast_pretty",

src/librustc_ast/ast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ pub enum GenericBound {
300300
impl GenericBound {
301301
pub fn span(&self) -> Span {
302302
match self {
303-
&GenericBound::Trait(ref t, ..) => t.span,
304-
&GenericBound::Outlives(ref l) => l.ident.span,
303+
GenericBound::Trait(ref t, ..) => t.span,
304+
GenericBound::Outlives(ref l) => l.ident.span,
305305
}
306306
}
307307
}

src/librustc_ast_passes/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ name = "rustc_ast_passes"
99
path = "lib.rs"
1010

1111
[dependencies]
12+
itertools = "0.8"
1213
log = "0.4"
1314
rustc_ast_pretty = { path = "../librustc_ast_pretty" }
1415
rustc_attr = { path = "../librustc_attr" }

src/librustc_ast_passes/ast_validation.rs

+54-14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// This pass is supposed to perform only simple checks not requiring name resolution
77
// or type checking or some other kind of complex analysis.
88

9+
use itertools::{Either, Itertools};
910
use rustc_ast::ast::*;
1011
use rustc_ast::attr;
1112
use rustc_ast::expand::is_proc_macro_attr;
@@ -14,7 +15,7 @@ use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
1415
use rustc_ast::walk_list;
1516
use rustc_ast_pretty::pprust;
1617
use rustc_data_structures::fx::FxHashMap;
17-
use rustc_errors::{error_code, struct_span_err, Applicability};
18+
use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
1819
use rustc_parse::validate_attr;
1920
use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
2021
use rustc_session::lint::LintBuffer;
@@ -640,31 +641,70 @@ impl<'a> AstValidator<'a> {
640641
}
641642
}
642643

644+
fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
645+
// Lifetimes always come first.
646+
let lt_sugg = data.args.iter().filter_map(|arg| match arg {
647+
AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
648+
Some(pprust::to_string(|s| s.print_generic_arg(lt)))
649+
}
650+
_ => None,
651+
});
652+
let args_sugg = data.args.iter().filter_map(|a| match a {
653+
AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
654+
None
655+
}
656+
AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
657+
});
658+
// Constraints always come last.
659+
let constraint_sugg = data.args.iter().filter_map(|a| match a {
660+
AngleBracketedArg::Arg(_) => None,
661+
AngleBracketedArg::Constraint(c) => {
662+
Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
663+
}
664+
});
665+
format!(
666+
"<{}>",
667+
lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
668+
)
669+
}
670+
643671
/// Enforce generic args coming before constraints in `<...>` of a path segment.
644672
fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
645673
// Early exit in case it's partitioned as it should be.
646674
if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
647675
return;
648676
}
649677
// Find all generic argument coming after the first constraint...
650-
let mut misplaced_args = Vec::new();
651-
let mut first = None;
652-
for arg in &data.args {
653-
match (arg, first) {
654-
(AngleBracketedArg::Arg(a), Some(_)) => misplaced_args.push(a.span()),
655-
(AngleBracketedArg::Constraint(c), None) => first = Some(c.span),
656-
(AngleBracketedArg::Arg(_), None) | (AngleBracketedArg::Constraint(_), Some(_)) => {
657-
}
658-
}
659-
}
678+
let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
679+
data.args.iter().partition_map(|arg| match arg {
680+
AngleBracketedArg::Constraint(c) => Either::Left(c.span),
681+
AngleBracketedArg::Arg(a) => Either::Right(a.span()),
682+
});
683+
let args_len = arg_spans.len();
684+
let constraint_len = constraint_spans.len();
660685
// ...and then error:
661686
self.err_handler()
662687
.struct_span_err(
663-
misplaced_args.clone(),
688+
arg_spans.clone(),
664689
"generic arguments must come before the first constraint",
665690
)
666-
.span_label(first.unwrap(), "the first constraint is provided here")
667-
.span_labels(misplaced_args, "generic argument")
691+
.span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
692+
.span_label(
693+
*arg_spans.iter().last().unwrap(),
694+
&format!("generic argument{}", pluralize!(args_len)),
695+
)
696+
.span_labels(constraint_spans, "")
697+
.span_labels(arg_spans, "")
698+
.span_suggestion_verbose(
699+
data.span,
700+
&format!(
701+
"move the constraint{} after the generic argument{}",
702+
pluralize!(constraint_len),
703+
pluralize!(args_len)
704+
),
705+
self.correct_generic_order_suggestion(&data),
706+
Applicability::MachineApplicable,
707+
)
668708
.emit();
669709
}
670710
}

src/librustc_ast_pretty/pprust.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,7 @@ impl<'a> State<'a> {
869869
}
870870
}
871871

872-
fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
872+
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
873873
self.print_ident(constraint.ident);
874874
self.s.space();
875875
match &constraint.kind {
@@ -883,7 +883,7 @@ impl<'a> State<'a> {
883883
}
884884
}
885885

886-
crate fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
886+
pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
887887
match generic_arg {
888888
GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
889889
GenericArg::Type(ty) => self.print_type(ty),

src/librustc_errors/diagnostic_builder.rs

+14
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,20 @@ impl<'a> DiagnosticBuilder<'a> {
315315
self
316316
}
317317

318+
pub fn span_suggestion_verbose(
319+
&mut self,
320+
sp: Span,
321+
msg: &str,
322+
suggestion: String,
323+
applicability: Applicability,
324+
) -> &mut Self {
325+
if !self.0.allow_suggestions {
326+
return self;
327+
}
328+
self.0.diagnostic.span_suggestion_verbose(sp, msg, suggestion, applicability);
329+
self
330+
}
331+
318332
pub fn span_suggestion_hidden(
319333
&mut self,
320334
sp: Span,

src/test/ui/parser/issue-32214.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ error: generic arguments must come before the first constraint
44
LL | pub fn test<W, I: Trait<Item=(), W> >() {}
55
| ------- ^ generic argument
66
| |
7-
| the first constraint is provided here
7+
| constraint
8+
|
9+
help: move the constraint after the generic argument
10+
|
11+
LL | pub fn test<W, I: Trait<W, Item = ()> >() {}
12+
| ^^^^^^^^^^^^^^
813

914
error: aborting due to previous error
1015

src/test/ui/suggestions/suggest-move-types.stderr

+66-42
Original file line numberDiff line numberDiff line change
@@ -4,79 +4,103 @@ error: generic arguments must come before the first constraint
44
LL | struct A<T, M: One<A=(), T>> {
55
| ---- ^ generic argument
66
| |
7-
| the first constraint is provided here
7+
| constraint
8+
|
9+
help: move the constraint after the generic argument
10+
|
11+
LL | struct A<T, M: One<T, A = ()>> {
12+
| ^^^^^^^^^^^
813

914
error: generic arguments must come before the first constraint
1015
--> $DIR/suggest-move-types.rs:33:43
1116
|
1217
LL | struct Al<'a, T, M: OneWithLifetime<A=(), T, 'a>> {
13-
| ---- ^ ^^ generic argument
14-
| | |
15-
| | generic argument
16-
| the first constraint is provided here
18+
| ---- ^ ^^ generic arguments
19+
| |
20+
| constraint
21+
|
22+
help: move the constraint after the generic arguments
23+
|
24+
LL | struct Al<'a, T, M: OneWithLifetime<'a, T, A = ()>> {
25+
| ^^^^^^^^^^^^^^^
1726

1827
error: generic arguments must come before the first constraint
1928
--> $DIR/suggest-move-types.rs:40:46
2029
|
2130
LL | struct B<T, U, V, M: Three<A=(), B=(), C=(), T, U, V>> {
22-
| ---- ^ ^ ^ generic argument
23-
| | | |
24-
| | | generic argument
25-
| | generic argument
26-
| the first constraint is provided here
31+
| ---- ---- ---- ^ ^ ^ generic arguments
32+
| |
33+
| constraints
34+
|
35+
help: move the constraints after the generic arguments
36+
|
37+
LL | struct B<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2739

2840
error: generic arguments must come before the first constraint
2941
--> $DIR/suggest-move-types.rs:48:71
3042
|
3143
LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> {
32-
| ---- ^ ^ ^ ^^ ^^ ^^ generic argument
33-
| | | | | | |
34-
| | | | | | generic argument
35-
| | | | | generic argument
36-
| | | | generic argument
37-
| | | generic argument
38-
| | generic argument
39-
| the first constraint is provided here
44+
| ---- ---- ---- ^ ^ ^ ^^ ^^ ^^ generic arguments
45+
| |
46+
| constraints
47+
|
48+
help: move the constraints after the generic arguments
49+
|
50+
LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
51+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4052

4153
error: generic arguments must come before the first constraint
42-
--> $DIR/suggest-move-types.rs:57:49
54+
--> $DIR/suggest-move-types.rs:57:28
4355
|
4456
LL | struct C<T, U, V, M: Three<T, A=(), B=(), C=(), U, V>> {
45-
| ---- ^ ^ generic argument
46-
| | |
47-
| | generic argument
48-
| the first constraint is provided here
57+
| ^ ---- ---- ---- ^ ^ generic arguments
58+
| |
59+
| constraints
60+
|
61+
help: move the constraints after the generic arguments
62+
|
63+
LL | struct C<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
64+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4965

5066
error: generic arguments must come before the first constraint
51-
--> $DIR/suggest-move-types.rs:65:78
67+
--> $DIR/suggest-move-types.rs:65:53
5268
|
5369
LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=(), U, 'b, V, 'c>> {
54-
| ---- ^ ^^ ^ ^^ generic argument
55-
| | | | |
56-
| | | | generic argument
57-
| | | generic argument
58-
| | generic argument
59-
| the first constraint is provided here
70+
| ^ ^^ ---- ---- ---- ^ ^^ ^ ^^ generic arguments
71+
| |
72+
| constraints
73+
|
74+
help: move the constraints after the generic arguments
75+
|
76+
LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
77+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6078

6179
error: generic arguments must come before the first constraint
62-
--> $DIR/suggest-move-types.rs:74:43
80+
--> $DIR/suggest-move-types.rs:74:28
6381
|
6482
LL | struct D<T, U, V, M: Three<T, A=(), B=(), U, C=(), V>> {
65-
| ---- ^ ^ generic argument
66-
| | |
67-
| | generic argument
68-
| the first constraint is provided here
83+
| ^ ---- ---- ^ ---- ^ generic arguments
84+
| |
85+
| constraints
86+
|
87+
help: move the constraints after the generic arguments
88+
|
89+
LL | struct D<T, U, V, M: Three<T, U, V, A = (), B = (), C = ()>> {
90+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6991

7092
error: generic arguments must come before the first constraint
71-
--> $DIR/suggest-move-types.rs:82:72
93+
--> $DIR/suggest-move-types.rs:82:53
7294
|
7395
LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, 'b, C=(), V, 'c>> {
74-
| ---- ^ ^^ ^ ^^ generic argument
75-
| | | | |
76-
| | | | generic argument
77-
| | | generic argument
78-
| | generic argument
79-
| the first constraint is provided here
96+
| ^ ^^ ---- ---- ^ ^^ ---- ^ ^^ generic arguments
97+
| |
98+
| constraints
99+
|
100+
help: move the constraints after the generic arguments
101+
|
102+
LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<'a, 'b, 'c, T, U, V, A = (), B = (), C = ()>> {
103+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
80104

81105
error[E0747]: type provided when a lifetime was expected
82106
--> $DIR/suggest-move-types.rs:33:43

0 commit comments

Comments
 (0)