Skip to content

Commit dd4ecd1

Browse files
authored
Rollup merge of #121326 - fmease:detect-empty-leading-where-clauses-on-ty-aliases, r=compiler-errors
Detect empty leading where clauses on type aliases 1. commit: refactor the AST of type alias where clauses * I could no longer bear the look of `.0.1` and `.1.0` * Arguably moving `split` out of `TyAlias` into a substruct might not make that much sense from a semantic standpoint since it reprs an index into `TyAlias.predicates` but it's alright and it cleans up the usage sites of `TyAlias` 2. commit: fix an oversight: An empty leading where clause is still a leading where clause * semantically reject empty leading where clauses on lazy type aliases * e.g., on `#![feature(lazy_type_alias)] type X where = ();` * make empty leading where clauses on assoc types trigger lint `deprecated_where_clause_location` * e.g., `impl Trait for () { type X where = (); }`
2 parents 1a1876c + cce8128 commit dd4ecd1

File tree

18 files changed

+247
-149
lines changed

18 files changed

+247
-149
lines changed

compiler/rustc_ast/src/ast.rs

+22-10
Original file line numberDiff line numberDiff line change
@@ -403,9 +403,10 @@ impl Default for Generics {
403403
/// A where-clause in a definition.
404404
#[derive(Clone, Encodable, Decodable, Debug)]
405405
pub struct WhereClause {
406-
/// `true` if we ate a `where` token: this can happen
407-
/// if we parsed no predicates (e.g. `struct Foo where {}`).
408-
/// This allows us to pretty-print accurately.
406+
/// `true` if we ate a `where` token.
407+
///
408+
/// This can happen if we parsed no predicates, e.g., `struct Foo where {}`.
409+
/// This allows us to pretty-print accurately and provide correct suggestion diagnostics.
409410
pub has_where_token: bool,
410411
pub predicates: ThinVec<WherePredicate>,
411412
pub span: Span,
@@ -3007,18 +3008,29 @@ pub struct Trait {
30073008
///
30083009
/// If there is no where clause, then this is `false` with `DUMMY_SP`.
30093010
#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
3010-
pub struct TyAliasWhereClause(pub bool, pub Span);
3011+
pub struct TyAliasWhereClause {
3012+
pub has_where_token: bool,
3013+
pub span: Span,
3014+
}
3015+
3016+
/// The span information for the two where clauses on a `TyAlias`.
3017+
#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
3018+
pub struct TyAliasWhereClauses {
3019+
/// Before the equals sign.
3020+
pub before: TyAliasWhereClause,
3021+
/// After the equals sign.
3022+
pub after: TyAliasWhereClause,
3023+
/// The index in `TyAlias.generics.where_clause.predicates` that would split
3024+
/// into predicates from the where clause before the equals sign and the ones
3025+
/// from the where clause after the equals sign.
3026+
pub split: usize,
3027+
}
30113028

30123029
#[derive(Clone, Encodable, Decodable, Debug)]
30133030
pub struct TyAlias {
30143031
pub defaultness: Defaultness,
30153032
pub generics: Generics,
3016-
/// The span information for the two where clauses (before equals, after equals)
3017-
pub where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
3018-
/// The index in `generics.where_clause.predicates` that would split into
3019-
/// predicates from the where clause before the equals and the predicates
3020-
/// from the where clause after the equals
3021-
pub where_predicates_split: usize,
3033+
pub where_clauses: TyAliasWhereClauses,
30223034
pub bounds: GenericBounds,
30233035
pub ty: Option<P<Ty>>,
30243036
}

compiler/rustc_ast/src/mut_visit.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1079,8 +1079,8 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
10791079
}) => {
10801080
visit_defaultness(defaultness, vis);
10811081
vis.visit_generics(generics);
1082-
vis.visit_span(&mut where_clauses.0.1);
1083-
vis.visit_span(&mut where_clauses.1.1);
1082+
vis.visit_span(&mut where_clauses.before.span);
1083+
vis.visit_span(&mut where_clauses.after.span);
10841084
visit_bounds(bounds, vis);
10851085
visit_opt(ty, |ty| vis.visit_ty(ty));
10861086
}
@@ -1163,8 +1163,8 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
11631163
}) => {
11641164
visit_defaultness(defaultness, visitor);
11651165
visitor.visit_generics(generics);
1166-
visitor.visit_span(&mut where_clauses.0.1);
1167-
visitor.visit_span(&mut where_clauses.1.1);
1166+
visitor.visit_span(&mut where_clauses.before.span);
1167+
visitor.visit_span(&mut where_clauses.after.span);
11681168
visit_bounds(bounds, visitor);
11691169
visit_opt(ty, |ty| visitor.visit_ty(ty));
11701170
}
@@ -1257,8 +1257,8 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
12571257
}) => {
12581258
visit_defaultness(defaultness, visitor);
12591259
visitor.visit_generics(generics);
1260-
visitor.visit_span(&mut where_clauses.0.1);
1261-
visitor.visit_span(&mut where_clauses.1.1);
1260+
visitor.visit_span(&mut where_clauses.before.span);
1261+
visitor.visit_span(&mut where_clauses.after.span);
12621262
visit_bounds(bounds, visitor);
12631263
visit_opt(ty, |ty| visitor.visit_ty(ty));
12641264
}

compiler/rustc_ast_lowering/src/item.rs

+10-9
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,20 @@ pub(super) struct ItemLowerer<'a, 'hir> {
3333
/// clause if it exists.
3434
fn add_ty_alias_where_clause(
3535
generics: &mut ast::Generics,
36-
mut where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
36+
mut where_clauses: TyAliasWhereClauses,
3737
prefer_first: bool,
3838
) {
3939
if !prefer_first {
40-
where_clauses = (where_clauses.1, where_clauses.0);
41-
}
42-
if where_clauses.0.0 || !where_clauses.1.0 {
43-
generics.where_clause.has_where_token = where_clauses.0.0;
44-
generics.where_clause.span = where_clauses.0.1;
45-
} else {
46-
generics.where_clause.has_where_token = where_clauses.1.0;
47-
generics.where_clause.span = where_clauses.1.1;
40+
(where_clauses.before, where_clauses.after) = (where_clauses.after, where_clauses.before);
4841
}
42+
let where_clause =
43+
if where_clauses.before.has_where_token || !where_clauses.after.has_where_token {
44+
where_clauses.before
45+
} else {
46+
where_clauses.after
47+
};
48+
generics.where_clause.has_where_token = where_clause.has_where_token;
49+
generics.where_clause.span = where_clause.span;
4950
}
5051

5152
impl<'a, 'hir> ItemLowerer<'a, 'hir> {

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

+45-39
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_predicates_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.1.0 {
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.0.1;
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(),
170-
right: ty_alias.where_clauses.1.1.shrink_to_hi(),
171-
},
172-
})
170+
right: ty_alias.where_clauses.after.span.shrink_to_hi(),
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)) {
@@ -457,8 +461,7 @@ impl<'a> AstValidator<'a> {
457461
fn check_foreign_ty_genericless(
458462
&self,
459463
generics: &Generics,
460-
before_where_clause: &TyAliasWhereClause,
461-
after_where_clause: &TyAliasWhereClause,
464+
where_clauses: &TyAliasWhereClauses,
462465
) {
463466
let cannot_have = |span, descr, remove_descr| {
464467
self.dcx().emit_err(errors::ExternTypesCannotHave {
@@ -473,14 +476,14 @@ impl<'a> AstValidator<'a> {
473476
cannot_have(generics.span, "generic parameters", "generic parameters");
474477
}
475478

476-
let check_where_clause = |where_clause: &TyAliasWhereClause| {
477-
if let TyAliasWhereClause(true, where_clause_span) = where_clause {
478-
cannot_have(*where_clause_span, "`where` clauses", "`where` clause");
479+
let check_where_clause = |where_clause: TyAliasWhereClause| {
480+
if where_clause.has_where_token {
481+
cannot_have(where_clause.span, "`where` clauses", "`where` clause");
479482
}
480483
};
481484

482-
check_where_clause(before_where_clause);
483-
check_where_clause(after_where_clause);
485+
check_where_clause(where_clauses.before);
486+
check_where_clause(where_clauses.after);
484487
}
485488

486489
fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
@@ -1122,9 +1125,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11221125
if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
11231126
self.dcx().emit_err(err);
11241127
}
1125-
} else if where_clauses.1.0 {
1128+
} else if where_clauses.after.has_where_token {
11261129
self.dcx().emit_err(errors::WhereClauseAfterTypeAlias {
1127-
span: where_clauses.1.1,
1130+
span: where_clauses.after.span,
11281131
help: self.session.is_nightly_build().then_some(()),
11291132
});
11301133
}
@@ -1154,7 +1157,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11541157
self.check_defaultness(fi.span, *defaultness);
11551158
self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
11561159
self.check_type_no_bounds(bounds, "`extern` blocks");
1157-
self.check_foreign_ty_genericless(generics, &where_clauses.0, &where_clauses.1);
1160+
self.check_foreign_ty_genericless(generics, where_clauses);
11581161
self.check_foreign_item_ascii_only(fi.ident);
11591162
}
11601163
ForeignItemKind::Static(_, _, body) => {
@@ -1477,15 +1480,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14771480
if let AssocItemKind::Type(ty_alias) = &item.kind
14781481
&& let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
14791482
{
1483+
let sugg = match err.sugg {
1484+
errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None,
1485+
errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => {
1486+
Some((right, snippet))
1487+
}
1488+
};
14801489
self.lint_buffer.buffer_lint_with_diagnostic(
14811490
DEPRECATED_WHERE_CLAUSE_LOCATION,
14821491
item.id,
14831492
err.span,
14841493
fluent::ast_passes_deprecated_where_clause_location,
1485-
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
1486-
err.sugg.right,
1487-
err.sugg.snippet,
1488-
),
1494+
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(sugg),
14891495
);
14901496
}
14911497

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_ast_pretty/src/pprust/state/item.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,13 @@ impl<'a> State<'a> {
4343
defaultness,
4444
generics,
4545
where_clauses,
46-
where_predicates_split,
4746
bounds,
4847
ty,
4948
}) => {
5049
self.print_associated_type(
5150
ident,
5251
generics,
5352
*where_clauses,
54-
*where_predicates_split,
5553
bounds,
5654
ty.as_deref(),
5755
vis,
@@ -108,15 +106,14 @@ impl<'a> State<'a> {
108106
&mut self,
109107
ident: Ident,
110108
generics: &ast::Generics,
111-
where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
112-
where_predicates_split: usize,
109+
where_clauses: ast::TyAliasWhereClauses,
113110
bounds: &ast::GenericBounds,
114111
ty: Option<&ast::Ty>,
115112
vis: &ast::Visibility,
116113
defaultness: ast::Defaultness,
117114
) {
118115
let (before_predicates, after_predicates) =
119-
generics.where_clause.predicates.split_at(where_predicates_split);
116+
generics.where_clause.predicates.split_at(where_clauses.split);
120117
self.head("");
121118
self.print_visibility(vis);
122119
self.print_defaultness(defaultness);
@@ -127,13 +124,13 @@ impl<'a> State<'a> {
127124
self.word_nbsp(":");
128125
self.print_type_bounds(bounds);
129126
}
130-
self.print_where_clause_parts(where_clauses.0.0, before_predicates);
127+
self.print_where_clause_parts(where_clauses.before.has_where_token, before_predicates);
131128
if let Some(ty) = ty {
132129
self.space();
133130
self.word_space("=");
134131
self.print_type(ty);
135132
}
136-
self.print_where_clause_parts(where_clauses.1.0, after_predicates);
133+
self.print_where_clause_parts(where_clauses.after.has_where_token, after_predicates);
137134
self.word(";");
138135
self.end(); // end inner head-block
139136
self.end(); // end outer head-block
@@ -249,15 +246,13 @@ impl<'a> State<'a> {
249246
defaultness,
250247
generics,
251248
where_clauses,
252-
where_predicates_split,
253249
bounds,
254250
ty,
255251
}) => {
256252
self.print_associated_type(
257253
item.ident,
258254
generics,
259255
*where_clauses,
260-
*where_predicates_split,
261256
bounds,
262257
ty.as_deref(),
263258
&item.vis,
@@ -536,15 +531,13 @@ impl<'a> State<'a> {
536531
defaultness,
537532
generics,
538533
where_clauses,
539-
where_predicates_split,
540534
bounds,
541535
ty,
542536
}) => {
543537
self.print_associated_type(
544538
ident,
545539
generics,
546540
*where_clauses,
547-
*where_predicates_split,
548541
bounds,
549542
ty.as_deref(),
550543
vis,

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -601,11 +601,7 @@ impl<'a> TraitDef<'a> {
601601
kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
602602
defaultness: ast::Defaultness::Final,
603603
generics: Generics::default(),
604-
where_clauses: (
605-
ast::TyAliasWhereClause::default(),
606-
ast::TyAliasWhereClause::default(),
607-
),
608-
where_predicates_split: 0,
604+
where_clauses: ast::TyAliasWhereClauses::default(),
609605
bounds: Vec::new(),
610606
ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
611607
})),

0 commit comments

Comments
 (0)