Skip to content

Commit cce8128

Browse files
committed
Detect empty leading where-clauses on type aliases
1 parent 2b80605 commit cce8128

11 files changed

+177
-67
lines changed

compiler/rustc_ast_passes/messages.ftl

+2-1
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,5 @@ ast_passes_where_clause_after_type_alias = where clauses are not allowed after t
280280
281281
ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases
282282
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
283-
.suggestion = move it to the end of the type declaration
283+
.remove_suggestion = remove this `where`
284+
.move_suggestion = move it to the end of the type declaration

compiler/rustc_ast_passes/src/ast_validation.rs

+35-28
Original file line numberDiff line numberDiff line change
@@ -138,38 +138,42 @@ impl<'a> AstValidator<'a> {
138138
&mut self,
139139
ty_alias: &TyAlias,
140140
) -> Result<(), errors::WhereClauseBeforeTypeAlias> {
141-
let before_predicates =
142-
ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_clauses.split).0;
143-
144-
if ty_alias.ty.is_none() || before_predicates.is_empty() {
141+
if ty_alias.ty.is_none() || !ty_alias.where_clauses.before.has_where_token {
145142
return Ok(());
146143
}
147144

148-
let mut state = State::new();
149-
if !ty_alias.where_clauses.after.has_where_token {
150-
state.space();
151-
state.word_space("where");
152-
} else {
153-
state.word_space(",");
154-
}
155-
let mut first = true;
156-
for p in before_predicates {
157-
if !first {
158-
state.word_space(",");
145+
let (before_predicates, after_predicates) =
146+
ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_clauses.split);
147+
let span = ty_alias.where_clauses.before.span;
148+
149+
let sugg = if !before_predicates.is_empty() || !ty_alias.where_clauses.after.has_where_token
150+
{
151+
let mut state = State::new();
152+
153+
if !ty_alias.where_clauses.after.has_where_token {
154+
state.space();
155+
state.word_space("where");
159156
}
160-
first = false;
161-
state.print_where_predicate(p);
162-
}
163157

164-
let span = ty_alias.where_clauses.before.span;
165-
Err(errors::WhereClauseBeforeTypeAlias {
166-
span,
167-
sugg: errors::WhereClauseBeforeTypeAliasSugg {
158+
let mut first = after_predicates.is_empty();
159+
for p in before_predicates {
160+
if !first {
161+
state.word_space(",");
162+
}
163+
first = false;
164+
state.print_where_predicate(p);
165+
}
166+
167+
errors::WhereClauseBeforeTypeAliasSugg::Move {
168168
left: span,
169169
snippet: state.s.eof(),
170170
right: ty_alias.where_clauses.after.span.shrink_to_hi(),
171-
},
172-
})
171+
}
172+
} else {
173+
errors::WhereClauseBeforeTypeAliasSugg::Remove { span }
174+
};
175+
176+
Err(errors::WhereClauseBeforeTypeAlias { span, sugg })
173177
}
174178

175179
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
@@ -1476,15 +1480,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14761480
if let AssocItemKind::Type(ty_alias) = &item.kind
14771481
&& let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
14781482
{
1483+
let sugg = match err.sugg {
1484+
errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None,
1485+
errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => {
1486+
Some((right, snippet))
1487+
}
1488+
};
14791489
self.lint_buffer.buffer_lint_with_diagnostic(
14801490
DEPRECATED_WHERE_CLAUSE_LOCATION,
14811491
item.id,
14821492
err.span,
14831493
fluent::ast_passes_deprecated_where_clause_location,
1484-
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
1485-
err.sugg.right,
1486-
err.sugg.snippet,
1487-
),
1494+
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(sugg),
14881495
);
14891496
}
14901497

compiler/rustc_ast_passes/src/errors.rs

+19-11
Original file line numberDiff line numberDiff line change
@@ -515,17 +515,25 @@ pub struct WhereClauseBeforeTypeAlias {
515515
}
516516

517517
#[derive(Subdiagnostic)]
518-
#[multipart_suggestion(
519-
ast_passes_suggestion,
520-
applicability = "machine-applicable",
521-
style = "verbose"
522-
)]
523-
pub struct WhereClauseBeforeTypeAliasSugg {
524-
#[suggestion_part(code = "")]
525-
pub left: Span,
526-
pub snippet: String,
527-
#[suggestion_part(code = "{snippet}")]
528-
pub right: Span,
518+
519+
pub enum WhereClauseBeforeTypeAliasSugg {
520+
#[suggestion(ast_passes_remove_suggestion, applicability = "machine-applicable", code = "")]
521+
Remove {
522+
#[primary_span]
523+
span: Span,
524+
},
525+
#[multipart_suggestion(
526+
ast_passes_move_suggestion,
527+
applicability = "machine-applicable",
528+
style = "verbose"
529+
)]
530+
Move {
531+
#[suggestion_part(code = "")]
532+
left: Span,
533+
snippet: String,
534+
#[suggestion_part(code = "{snippet}")]
535+
right: Span,
536+
},
529537
}
530538

531539
#[derive(Diagnostic)]

compiler/rustc_lint/src/context/diagnostics.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -428,15 +428,22 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiagnostics, diag:
428428
diag.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration");
429429
}
430430
}
431-
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(new_span, suggestion) => {
432-
diag.multipart_suggestion(
433-
"move it to the end of the type declaration",
434-
vec![(diag.span.primary_span().unwrap(), "".to_string()), (new_span, suggestion)],
435-
Applicability::MachineApplicable,
436-
);
437-
diag.note(
438-
"see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
439-
);
431+
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(sugg) => {
432+
let left_sp = diag.span.primary_span().unwrap();
433+
match sugg {
434+
Some((right_sp, sugg)) => diag.multipart_suggestion(
435+
"move it to the end of the type declaration",
436+
vec![(left_sp, String::new()), (right_sp, sugg)],
437+
Applicability::MachineApplicable,
438+
),
439+
None => diag.span_suggestion(
440+
left_sp,
441+
"remove this `where`",
442+
"",
443+
Applicability::MachineApplicable,
444+
),
445+
};
446+
diag.note("see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information");
440447
}
441448
BuiltinLintDiagnostics::SingleUseLifetime {
442449
param_span,

compiler/rustc_lint_defs/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ pub enum BuiltinLintDiagnostics {
597597
UnicodeTextFlow(Span, String),
598598
UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
599599
UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
600-
DeprecatedWhereclauseLocation(Span, String),
600+
DeprecatedWhereclauseLocation(Option<(Span, String)>),
601601
SingleUseLifetime {
602602
/// Span of the parameter which declares this lifetime.
603603
param_span: Span,

tests/ui/lazy-type-alias/leading-where-clause.fixed

+13-5
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,22 @@
22

33
#![feature(lazy_type_alias)]
44
#![allow(incomplete_features)]
5+
#![crate_type = "lib"]
56

67
// Check that we *reject* leading where-clauses on lazy type aliases.
78

8-
type Alias<T>
9+
pub type Leading0<T>
910

1011
= T where String: From<T>;
11-
//~^^^ ERROR where clauses are not allowed before the type for type aliases
1212

13-
fn main() {
14-
let _: Alias<&str>;
15-
}
13+
pub type Leading1<T, U>
14+
15+
= (T, U)
16+
where
17+
U: Copy, String: From<T>;
18+
19+
pub type EmptyLeading0 = () where;
20+
//~^ ERROR where clauses are not allowed before the type for type aliases
21+
22+
pub type EmptyLeading1<T> = T where T: Copy;
23+
//~^ ERROR where clauses are not allowed before the type for type aliases

tests/ui/lazy-type-alias/leading-where-clause.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,24 @@
22

33
#![feature(lazy_type_alias)]
44
#![allow(incomplete_features)]
5+
#![crate_type = "lib"]
56

67
// Check that we *reject* leading where-clauses on lazy type aliases.
78

8-
type Alias<T>
9-
where
9+
pub type Leading0<T>
10+
where //~ ERROR where clauses are not allowed before the type for type aliases
1011
String: From<T>,
1112
= T;
12-
//~^^^ ERROR where clauses are not allowed before the type for type aliases
1313

14-
fn main() {
15-
let _: Alias<&str>;
16-
}
14+
pub type Leading1<T, U>
15+
where //~ ERROR where clauses are not allowed before the type for type aliases
16+
String: From<T>,
17+
= (T, U)
18+
where
19+
U: Copy;
20+
21+
pub type EmptyLeading0 where = ();
22+
//~^ ERROR where clauses are not allowed before the type for type aliases
23+
24+
pub type EmptyLeading1<T> where = T where T: Copy;
25+
//~^ ERROR where clauses are not allowed before the type for type aliases

tests/ui/lazy-type-alias/leading-where-clause.stderr

+39-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: where clauses are not allowed before the type for type aliases
2-
--> $DIR/leading-where-clause.rs:9:1
2+
--> $DIR/leading-where-clause.rs:10:1
33
|
44
LL | / where
55
LL | | String: From<T>,
@@ -12,5 +12,42 @@ LL +
1212
LL ~ = T where String: From<T>;
1313
|
1414

15-
error: aborting due to 1 previous error
15+
error: where clauses are not allowed before the type for type aliases
16+
--> $DIR/leading-where-clause.rs:15:1
17+
|
18+
LL | / where
19+
LL | | String: From<T>,
20+
| |____________________^
21+
|
22+
= note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
23+
help: move it to the end of the type declaration
24+
|
25+
LL +
26+
LL | = (T, U)
27+
LL | where
28+
LL ~ U: Copy, String: From<T>;
29+
|
30+
31+
error: where clauses are not allowed before the type for type aliases
32+
--> $DIR/leading-where-clause.rs:21:24
33+
|
34+
LL | pub type EmptyLeading0 where = ();
35+
| ^^^^^
36+
|
37+
= note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
38+
help: move it to the end of the type declaration
39+
|
40+
LL - pub type EmptyLeading0 where = ();
41+
LL + pub type EmptyLeading0 = () where;
42+
|
43+
44+
error: where clauses are not allowed before the type for type aliases
45+
--> $DIR/leading-where-clause.rs:24:27
46+
|
47+
LL | pub type EmptyLeading1<T> where = T where T: Copy;
48+
| ^^^^^ help: remove this `where`
49+
|
50+
= note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
51+
52+
error: aborting due to 4 previous errors
1653

tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ trait Trait {
88
type Assoc where u32: Copy;
99
// Fine.
1010
type Assoc2 where u32: Copy, i32: Copy;
11+
//
12+
type Assoc3;
1113
}
1214

1315
impl Trait for u32 {
@@ -17,6 +19,8 @@ impl Trait for u32 {
1719
// Not fine, suggests moving `u32: Copy`
1820
type Assoc2 = () where i32: Copy, u32: Copy;
1921
//~^ WARNING where clause not allowed here
22+
type Assoc3 = () where;
23+
//~^ WARNING where clause not allowed here
2024
}
2125

2226
impl Trait for i32 {
@@ -25,6 +29,8 @@ impl Trait for i32 {
2529
// Not fine, suggests moving both.
2630
type Assoc2 = () where u32: Copy, i32: Copy;
2731
//~^ WARNING where clause not allowed here
32+
type Assoc3 = () where;
33+
//~^ WARNING where clause not allowed here
2834
}
2935

3036
fn main() {}

tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ trait Trait {
88
type Assoc where u32: Copy;
99
// Fine.
1010
type Assoc2 where u32: Copy, i32: Copy;
11+
//
12+
type Assoc3;
1113
}
1214

1315
impl Trait for u32 {
@@ -17,6 +19,8 @@ impl Trait for u32 {
1719
// Not fine, suggests moving `u32: Copy`
1820
type Assoc2 where u32: Copy = () where i32: Copy;
1921
//~^ WARNING where clause not allowed here
22+
type Assoc3 where = ();
23+
//~^ WARNING where clause not allowed here
2024
}
2125

2226
impl Trait for i32 {
@@ -25,6 +29,8 @@ impl Trait for i32 {
2529
// Not fine, suggests moving both.
2630
type Assoc2 where u32: Copy, i32: Copy = ();
2731
//~^ WARNING where clause not allowed here
32+
type Assoc3 where = () where;
33+
//~^ WARNING where clause not allowed here
2834
}
2935

3036
fn main() {}

tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr

+25-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
warning: where clause not allowed here
2-
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:15:16
2+
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:17:16
33
|
44
LL | type Assoc where u32: Copy = ();
55
| ^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL + type Assoc = () where u32: Copy;
1313
|
1414

1515
warning: where clause not allowed here
16-
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:18:17
16+
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:20:17
1717
|
1818
LL | type Assoc2 where u32: Copy = () where i32: Copy;
1919
| ^^^^^^^^^^^^^^^
@@ -26,7 +26,20 @@ LL + type Assoc2 = () where i32: Copy, u32: Copy;
2626
|
2727

2828
warning: where clause not allowed here
29-
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:26:17
29+
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:22:17
30+
|
31+
LL | type Assoc3 where = ();
32+
| ^^^^^
33+
|
34+
= note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
35+
help: move it to the end of the type declaration
36+
|
37+
LL - type Assoc3 where = ();
38+
LL + type Assoc3 = () where;
39+
|
40+
41+
warning: where clause not allowed here
42+
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:30:17
3043
|
3144
LL | type Assoc2 where u32: Copy, i32: Copy = ();
3245
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -38,5 +51,13 @@ LL - type Assoc2 where u32: Copy, i32: Copy = ();
3851
LL + type Assoc2 = () where u32: Copy, i32: Copy;
3952
|
4053

41-
warning: 3 warnings emitted
54+
warning: where clause not allowed here
55+
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:32:17
56+
|
57+
LL | type Assoc3 where = () where;
58+
| ^^^^^ help: remove this `where`
59+
|
60+
= note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
61+
62+
warning: 5 warnings emitted
4263

0 commit comments

Comments
 (0)