Skip to content

Commit dbd70e5

Browse files
committed
Detect empty leading where-clauses on type aliases
1 parent 8d0d4ce commit dbd70e5

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)) {
@@ -1475,15 +1479,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14751479
if let AssocItemKind::Type(ty_alias) = &item.kind
14761480
&& let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
14771481
{
1482+
let sugg = match err.sugg {
1483+
errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None,
1484+
errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => {
1485+
Some((right, snippet))
1486+
}
1487+
};
14781488
self.lint_buffer.buffer_lint_with_diagnostic(
14791489
DEPRECATED_WHERE_CLAUSE_LOCATION,
14801490
item.id,
14811491
err.span,
14821492
fluent::ast_passes_deprecated_where_clause_location,
1483-
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
1484-
err.sugg.right,
1485-
err.sugg.snippet,
1486-
),
1493+
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(sugg),
14871494
);
14881495
}
14891496

compiler/rustc_ast_passes/src/errors.rs

+19-11
Original file line numberDiff line numberDiff line change
@@ -509,17 +509,25 @@ pub struct WhereClauseBeforeTypeAlias {
509509
}
510510

511511
#[derive(Subdiagnostic)]
512-
#[multipart_suggestion(
513-
ast_passes_suggestion,
514-
applicability = "machine-applicable",
515-
style = "verbose"
516-
)]
517-
pub struct WhereClauseBeforeTypeAliasSugg {
518-
#[suggestion_part(code = "")]
519-
pub left: Span,
520-
pub snippet: String,
521-
#[suggestion_part(code = "{snippet}")]
522-
pub right: Span,
512+
513+
pub enum WhereClauseBeforeTypeAliasSugg {
514+
#[suggestion(ast_passes_remove_suggestion, applicability = "machine-applicable", code = "")]
515+
Remove {
516+
#[primary_span]
517+
span: Span,
518+
},
519+
#[multipart_suggestion(
520+
ast_passes_move_suggestion,
521+
applicability = "machine-applicable",
522+
style = "verbose"
523+
)]
524+
Move {
525+
#[suggestion_part(code = "")]
526+
left: Span,
527+
snippet: String,
528+
#[suggestion_part(code = "{snippet}")]
529+
right: Span,
530+
},
523531
}
524532

525533
#[derive(Diagnostic)]

compiler/rustc_lint/src/context/diagnostics.rs

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

compiler/rustc_lint_defs/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ pub enum BuiltinLintDiagnostics {
593593
UnicodeTextFlow(Span, String),
594594
UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
595595
UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
596-
DeprecatedWhereclauseLocation(Span, String),
596+
DeprecatedWhereclauseLocation(Option<(Span, String)>),
597597
SingleUseLifetime {
598598
/// Span of the parameter which declares this lifetime.
599599
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)