about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-02-29 20:50:02 +0100
committerGitHub <noreply@github.com>2024-02-29 20:50:02 +0100
commitdd4ecd1cf4a59650747e7aeabaed9b24656fc88a (patch)
tree22dffc1b7306ffa5aed5f3e4002429e7e48ff8cf
parent1a1876c9790f168fb51afa335a7ba3e6fc267d75 (diff)
parentcce81289e6baea01c3cd67a6b85fffb3504d0a0b (diff)
downloadrust-dd4ecd1cf4a59650747e7aeabaed9b24656fc88a.tar.gz
rust-dd4ecd1cf4a59650747e7aeabaed9b24656fc88a.zip
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 = (); }`
-rw-r--r--compiler/rustc_ast/src/ast.rs32
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs12
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs19
-rw-r--r--compiler/rustc_ast_passes/messages.ftl3
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs84
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs30
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs15
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs6
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs25
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs2
-rw-r--r--compiler/rustc_parse/src/parser/item.rs17
-rw-r--r--src/tools/rustfmt/src/items.rs30
-rw-r--r--tests/ui/lazy-type-alias/leading-where-clause.fixed18
-rw-r--r--tests/ui/lazy-type-alias/leading-where-clause.rs21
-rw-r--r--tests/ui/lazy-type-alias/leading-where-clause.stderr41
-rw-r--r--tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed6
-rw-r--r--tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs6
-rw-r--r--tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr29
18 files changed, 247 insertions, 149 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 4ae18b4cf48..31dd358ad51 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -403,9 +403,10 @@ impl Default for Generics {
 /// A where-clause in a definition.
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct WhereClause {
-    /// `true` if we ate a `where` token: this can happen
-    /// if we parsed no predicates (e.g. `struct Foo where {}`).
-    /// This allows us to pretty-print accurately.
+    /// `true` if we ate a `where` token.
+    ///
+    /// This can happen if we parsed no predicates, e.g., `struct Foo where {}`.
+    /// This allows us to pretty-print accurately and provide correct suggestion diagnostics.
     pub has_where_token: bool,
     pub predicates: ThinVec<WherePredicate>,
     pub span: Span,
@@ -3007,18 +3008,29 @@ pub struct Trait {
 ///
 /// If there is no where clause, then this is `false` with `DUMMY_SP`.
 #[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
-pub struct TyAliasWhereClause(pub bool, pub Span);
+pub struct TyAliasWhereClause {
+    pub has_where_token: bool,
+    pub span: Span,
+}
+
+/// The span information for the two where clauses on a `TyAlias`.
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
+pub struct TyAliasWhereClauses {
+    /// Before the equals sign.
+    pub before: TyAliasWhereClause,
+    /// After the equals sign.
+    pub after: TyAliasWhereClause,
+    /// The index in `TyAlias.generics.where_clause.predicates` that would split
+    /// into predicates from the where clause before the equals sign and the ones
+    /// from the where clause after the equals sign.
+    pub split: usize,
+}
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct TyAlias {
     pub defaultness: Defaultness,
     pub generics: Generics,
-    /// The span information for the two where clauses (before equals, after equals)
-    pub where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
-    /// The index in `generics.where_clause.predicates` that would split into
-    /// predicates from the where clause before the equals and the predicates
-    /// from the where clause after the equals
-    pub where_predicates_split: usize,
+    pub where_clauses: TyAliasWhereClauses,
     pub bounds: GenericBounds,
     pub ty: Option<P<Ty>>,
 }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 60bc21c6441..2faf3228d55 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1079,8 +1079,8 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
         }) => {
             visit_defaultness(defaultness, vis);
             vis.visit_generics(generics);
-            vis.visit_span(&mut where_clauses.0.1);
-            vis.visit_span(&mut where_clauses.1.1);
+            vis.visit_span(&mut where_clauses.before.span);
+            vis.visit_span(&mut where_clauses.after.span);
             visit_bounds(bounds, vis);
             visit_opt(ty, |ty| vis.visit_ty(ty));
         }
@@ -1163,8 +1163,8 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
         }) => {
             visit_defaultness(defaultness, visitor);
             visitor.visit_generics(generics);
-            visitor.visit_span(&mut where_clauses.0.1);
-            visitor.visit_span(&mut where_clauses.1.1);
+            visitor.visit_span(&mut where_clauses.before.span);
+            visitor.visit_span(&mut where_clauses.after.span);
             visit_bounds(bounds, visitor);
             visit_opt(ty, |ty| visitor.visit_ty(ty));
         }
@@ -1257,8 +1257,8 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
         }) => {
             visit_defaultness(defaultness, visitor);
             visitor.visit_generics(generics);
-            visitor.visit_span(&mut where_clauses.0.1);
-            visitor.visit_span(&mut where_clauses.1.1);
+            visitor.visit_span(&mut where_clauses.before.span);
+            visitor.visit_span(&mut where_clauses.after.span);
             visit_bounds(bounds, visitor);
             visit_opt(ty, |ty| visitor.visit_ty(ty));
         }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 87ed47648c8..01b1e6fcaff 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -33,19 +33,20 @@ pub(super) struct ItemLowerer<'a, 'hir> {
 /// clause if it exists.
 fn add_ty_alias_where_clause(
     generics: &mut ast::Generics,
-    mut where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
+    mut where_clauses: TyAliasWhereClauses,
     prefer_first: bool,
 ) {
     if !prefer_first {
-        where_clauses = (where_clauses.1, where_clauses.0);
-    }
-    if where_clauses.0.0 || !where_clauses.1.0 {
-        generics.where_clause.has_where_token = where_clauses.0.0;
-        generics.where_clause.span = where_clauses.0.1;
-    } else {
-        generics.where_clause.has_where_token = where_clauses.1.0;
-        generics.where_clause.span = where_clauses.1.1;
+        (where_clauses.before, where_clauses.after) = (where_clauses.after, where_clauses.before);
     }
+    let where_clause =
+        if where_clauses.before.has_where_token || !where_clauses.after.has_where_token {
+            where_clauses.before
+        } else {
+            where_clauses.after
+        };
+    generics.where_clause.has_where_token = where_clause.has_where_token;
+    generics.where_clause.span = where_clause.span;
 }
 
 impl<'a, 'hir> ItemLowerer<'a, 'hir> {
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 6586ca5d36f..28a13d275a5 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -280,4 +280,5 @@ ast_passes_where_clause_after_type_alias = where clauses are not allowed after t
 
 ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases
     .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
-    .suggestion = move it to the end of the type declaration
+    .remove_suggestion = remove this `where`
+    .move_suggestion = move it to the end of the type declaration
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 8c9ad836087..b56d695c671 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -138,38 +138,42 @@ impl<'a> AstValidator<'a> {
         &mut self,
         ty_alias: &TyAlias,
     ) -> Result<(), errors::WhereClauseBeforeTypeAlias> {
-        let before_predicates =
-            ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_predicates_split).0;
-
-        if ty_alias.ty.is_none() || before_predicates.is_empty() {
+        if ty_alias.ty.is_none() || !ty_alias.where_clauses.before.has_where_token {
             return Ok(());
         }
 
-        let mut state = State::new();
-        if !ty_alias.where_clauses.1.0 {
-            state.space();
-            state.word_space("where");
-        } else {
-            state.word_space(",");
-        }
-        let mut first = true;
-        for p in before_predicates {
-            if !first {
-                state.word_space(",");
+        let (before_predicates, after_predicates) =
+            ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_clauses.split);
+        let span = ty_alias.where_clauses.before.span;
+
+        let sugg = if !before_predicates.is_empty() || !ty_alias.where_clauses.after.has_where_token
+        {
+            let mut state = State::new();
+
+            if !ty_alias.where_clauses.after.has_where_token {
+                state.space();
+                state.word_space("where");
             }
-            first = false;
-            state.print_where_predicate(p);
-        }
 
-        let span = ty_alias.where_clauses.0.1;
-        Err(errors::WhereClauseBeforeTypeAlias {
-            span,
-            sugg: errors::WhereClauseBeforeTypeAliasSugg {
+            let mut first = after_predicates.is_empty();
+            for p in before_predicates {
+                if !first {
+                    state.word_space(",");
+                }
+                first = false;
+                state.print_where_predicate(p);
+            }
+
+            errors::WhereClauseBeforeTypeAliasSugg::Move {
                 left: span,
                 snippet: state.s.eof(),
-                right: ty_alias.where_clauses.1.1.shrink_to_hi(),
-            },
-        })
+                right: ty_alias.where_clauses.after.span.shrink_to_hi(),
+            }
+        } else {
+            errors::WhereClauseBeforeTypeAliasSugg::Remove { span }
+        };
+
+        Err(errors::WhereClauseBeforeTypeAlias { span, sugg })
     }
 
     fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
@@ -457,8 +461,7 @@ impl<'a> AstValidator<'a> {
     fn check_foreign_ty_genericless(
         &self,
         generics: &Generics,
-        before_where_clause: &TyAliasWhereClause,
-        after_where_clause: &TyAliasWhereClause,
+        where_clauses: &TyAliasWhereClauses,
     ) {
         let cannot_have = |span, descr, remove_descr| {
             self.dcx().emit_err(errors::ExternTypesCannotHave {
@@ -473,14 +476,14 @@ impl<'a> AstValidator<'a> {
             cannot_have(generics.span, "generic parameters", "generic parameters");
         }
 
-        let check_where_clause = |where_clause: &TyAliasWhereClause| {
-            if let TyAliasWhereClause(true, where_clause_span) = where_clause {
-                cannot_have(*where_clause_span, "`where` clauses", "`where` clause");
+        let check_where_clause = |where_clause: TyAliasWhereClause| {
+            if where_clause.has_where_token {
+                cannot_have(where_clause.span, "`where` clauses", "`where` clause");
             }
         };
 
-        check_where_clause(before_where_clause);
-        check_where_clause(after_where_clause);
+        check_where_clause(where_clauses.before);
+        check_where_clause(where_clauses.after);
     }
 
     fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
@@ -1122,9 +1125,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
                         self.dcx().emit_err(err);
                     }
-                } else if where_clauses.1.0 {
+                } else if where_clauses.after.has_where_token {
                     self.dcx().emit_err(errors::WhereClauseAfterTypeAlias {
-                        span: where_clauses.1.1,
+                        span: where_clauses.after.span,
                         help: self.session.is_nightly_build().then_some(()),
                     });
                 }
@@ -1154,7 +1157,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.check_defaultness(fi.span, *defaultness);
                 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
                 self.check_type_no_bounds(bounds, "`extern` blocks");
-                self.check_foreign_ty_genericless(generics, &where_clauses.0, &where_clauses.1);
+                self.check_foreign_ty_genericless(generics, where_clauses);
                 self.check_foreign_item_ascii_only(fi.ident);
             }
             ForeignItemKind::Static(_, _, body) => {
@@ -1477,15 +1480,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         if let AssocItemKind::Type(ty_alias) = &item.kind
             && let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
         {
+            let sugg = match err.sugg {
+                errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None,
+                errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => {
+                    Some((right, snippet))
+                }
+            };
             self.lint_buffer.buffer_lint_with_diagnostic(
                 DEPRECATED_WHERE_CLAUSE_LOCATION,
                 item.id,
                 err.span,
                 fluent::ast_passes_deprecated_where_clause_location,
-                BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
-                    err.sugg.right,
-                    err.sugg.snippet,
-                ),
+                BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(sugg),
             );
         }
 
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 0f37093f057..19eed070911 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -515,17 +515,25 @@ pub struct WhereClauseBeforeTypeAlias {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(
-    ast_passes_suggestion,
-    applicability = "machine-applicable",
-    style = "verbose"
-)]
-pub struct WhereClauseBeforeTypeAliasSugg {
-    #[suggestion_part(code = "")]
-    pub left: Span,
-    pub snippet: String,
-    #[suggestion_part(code = "{snippet}")]
-    pub right: Span,
+
+pub enum WhereClauseBeforeTypeAliasSugg {
+    #[suggestion(ast_passes_remove_suggestion, applicability = "machine-applicable", code = "")]
+    Remove {
+        #[primary_span]
+        span: Span,
+    },
+    #[multipart_suggestion(
+        ast_passes_move_suggestion,
+        applicability = "machine-applicable",
+        style = "verbose"
+    )]
+    Move {
+        #[suggestion_part(code = "")]
+        left: Span,
+        snippet: String,
+        #[suggestion_part(code = "{snippet}")]
+        right: Span,
+    },
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 584f01e16c2..13f27c1c95c 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -43,7 +43,6 @@ impl<'a> State<'a> {
                 defaultness,
                 generics,
                 where_clauses,
-                where_predicates_split,
                 bounds,
                 ty,
             }) => {
@@ -51,7 +50,6 @@ impl<'a> State<'a> {
                     ident,
                     generics,
                     *where_clauses,
-                    *where_predicates_split,
                     bounds,
                     ty.as_deref(),
                     vis,
@@ -108,15 +106,14 @@ impl<'a> State<'a> {
         &mut self,
         ident: Ident,
         generics: &ast::Generics,
-        where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
-        where_predicates_split: usize,
+        where_clauses: ast::TyAliasWhereClauses,
         bounds: &ast::GenericBounds,
         ty: Option<&ast::Ty>,
         vis: &ast::Visibility,
         defaultness: ast::Defaultness,
     ) {
         let (before_predicates, after_predicates) =
-            generics.where_clause.predicates.split_at(where_predicates_split);
+            generics.where_clause.predicates.split_at(where_clauses.split);
         self.head("");
         self.print_visibility(vis);
         self.print_defaultness(defaultness);
@@ -127,13 +124,13 @@ impl<'a> State<'a> {
             self.word_nbsp(":");
             self.print_type_bounds(bounds);
         }
-        self.print_where_clause_parts(where_clauses.0.0, before_predicates);
+        self.print_where_clause_parts(where_clauses.before.has_where_token, before_predicates);
         if let Some(ty) = ty {
             self.space();
             self.word_space("=");
             self.print_type(ty);
         }
-        self.print_where_clause_parts(where_clauses.1.0, after_predicates);
+        self.print_where_clause_parts(where_clauses.after.has_where_token, after_predicates);
         self.word(";");
         self.end(); // end inner head-block
         self.end(); // end outer head-block
@@ -249,7 +246,6 @@ impl<'a> State<'a> {
                 defaultness,
                 generics,
                 where_clauses,
-                where_predicates_split,
                 bounds,
                 ty,
             }) => {
@@ -257,7 +253,6 @@ impl<'a> State<'a> {
                     item.ident,
                     generics,
                     *where_clauses,
-                    *where_predicates_split,
                     bounds,
                     ty.as_deref(),
                     &item.vis,
@@ -536,7 +531,6 @@ impl<'a> State<'a> {
                 defaultness,
                 generics,
                 where_clauses,
-                where_predicates_split,
                 bounds,
                 ty,
             }) => {
@@ -544,7 +538,6 @@ impl<'a> State<'a> {
                     ident,
                     generics,
                     *where_clauses,
-                    *where_predicates_split,
                     bounds,
                     ty.as_deref(),
                     vis,
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 3ee4fded749..eb664b571ba 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -601,11 +601,7 @@ impl<'a> TraitDef<'a> {
                 kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
                     defaultness: ast::Defaultness::Final,
                     generics: Generics::default(),
-                    where_clauses: (
-                        ast::TyAliasWhereClause::default(),
-                        ast::TyAliasWhereClause::default(),
-                    ),
-                    where_predicates_split: 0,
+                    where_clauses: ast::TyAliasWhereClauses::default(),
                     bounds: Vec::new(),
                     ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
                 })),
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index 71aef50391d..14e4c79563b 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -428,15 +428,22 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiagnostics, diag:
                 diag.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration");
             }
         }
-        BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(new_span, suggestion) => {
-            diag.multipart_suggestion(
-                "move it to the end of the type declaration",
-                vec![(diag.span.primary_span().unwrap(), "".to_string()), (new_span, suggestion)],
-                Applicability::MachineApplicable,
-            );
-            diag.note(
-                        "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
-                    );
+        BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(sugg) => {
+            let left_sp = diag.span.primary_span().unwrap();
+            match sugg {
+                Some((right_sp, sugg)) => diag.multipart_suggestion(
+                    "move it to the end of the type declaration",
+                    vec![(left_sp, String::new()), (right_sp, sugg)],
+                    Applicability::MachineApplicable,
+                ),
+                None => diag.span_suggestion(
+                    left_sp,
+                    "remove this `where`",
+                    "",
+                    Applicability::MachineApplicable,
+                ),
+            };
+            diag.note("see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information");
         }
         BuiltinLintDiagnostics::SingleUseLifetime {
             param_span,
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index fc590001c0d..198008d4d0d 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -597,7 +597,7 @@ pub enum BuiltinLintDiagnostics {
     UnicodeTextFlow(Span, String),
     UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
     UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
-    DeprecatedWhereclauseLocation(Span, String),
+    DeprecatedWhereclauseLocation(Option<(Span, String)>),
     SingleUseLifetime {
         /// Span of the parameter which declares this lifetime.
         param_span: Span,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index a678194372e..d8587f1340a 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -971,11 +971,17 @@ impl<'a> Parser<'a> {
 
         let after_where_clause = self.parse_where_clause()?;
 
-        let where_clauses = (
-            TyAliasWhereClause(before_where_clause.has_where_token, before_where_clause.span),
-            TyAliasWhereClause(after_where_clause.has_where_token, after_where_clause.span),
-        );
-        let where_predicates_split = before_where_clause.predicates.len();
+        let where_clauses = TyAliasWhereClauses {
+            before: TyAliasWhereClause {
+                has_where_token: before_where_clause.has_where_token,
+                span: before_where_clause.span,
+            },
+            after: TyAliasWhereClause {
+                has_where_token: after_where_clause.has_where_token,
+                span: after_where_clause.span,
+            },
+            split: before_where_clause.predicates.len(),
+        };
         let mut predicates = before_where_clause.predicates;
         predicates.extend(after_where_clause.predicates);
         let where_clause = WhereClause {
@@ -994,7 +1000,6 @@ impl<'a> Parser<'a> {
                 defaultness,
                 generics,
                 where_clauses,
-                where_predicates_split,
                 bounds,
                 ty,
             })),
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index b57be8c1054..f6f51fbd8ea 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -1651,8 +1651,7 @@ struct TyAliasRewriteInfo<'c, 'g>(
     &'c RewriteContext<'c>,
     Indent,
     &'g ast::Generics,
-    (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
-    usize,
+    ast::TyAliasWhereClauses,
     symbol::Ident,
     Span,
 );
@@ -1672,7 +1671,6 @@ pub(crate) fn rewrite_type_alias<'a, 'b>(
         ref bounds,
         ref ty,
         where_clauses,
-        where_predicates_split,
     } = *ty_alias_kind;
     let ty_opt = ty.as_ref();
     let (ident, vis) = match visitor_kind {
@@ -1680,15 +1678,7 @@ pub(crate) fn rewrite_type_alias<'a, 'b>(
         AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
         ForeignItem(i) => (i.ident, &i.vis),
     };
-    let rw_info = &TyAliasRewriteInfo(
-        context,
-        indent,
-        generics,
-        where_clauses,
-        where_predicates_split,
-        ident,
-        span,
-    );
+    let rw_info = &TyAliasRewriteInfo(context, indent, generics, where_clauses, ident, span);
     let op_ty = opaque_ty(ty);
     // Type Aliases are formatted slightly differently depending on the context
     // in which they appear, whether they are opaque, and whether they are associated.
@@ -1724,19 +1714,11 @@ fn rewrite_ty<R: Rewrite>(
     vis: &ast::Visibility,
 ) -> Option<String> {
     let mut result = String::with_capacity(128);
-    let TyAliasRewriteInfo(
-        context,
-        indent,
-        generics,
-        where_clauses,
-        where_predicates_split,
-        ident,
-        span,
-    ) = *rw_info;
+    let TyAliasRewriteInfo(context, indent, generics, where_clauses, ident, span) = *rw_info;
     let (before_where_predicates, after_where_predicates) = generics
         .where_clause
         .predicates
-        .split_at(where_predicates_split);
+        .split_at(where_clauses.split);
     if !after_where_predicates.is_empty() {
         return None;
     }
@@ -1771,7 +1753,7 @@ fn rewrite_ty<R: Rewrite>(
     let where_clause_str = rewrite_where_clause(
         context,
         before_where_predicates,
-        where_clauses.0.1,
+        where_clauses.before.span,
         context.config.brace_style(),
         Shape::legacy(where_budget, indent),
         false,
@@ -1795,7 +1777,7 @@ fn rewrite_ty<R: Rewrite>(
         let comment_span = context
             .snippet_provider
             .opt_span_before(span, "=")
-            .map(|op_lo| mk_sp(where_clauses.0.1.hi(), op_lo));
+            .map(|op_lo| mk_sp(where_clauses.before.span.hi(), op_lo));
 
         let lhs = match comment_span {
             Some(comment_span)
diff --git a/tests/ui/lazy-type-alias/leading-where-clause.fixed b/tests/ui/lazy-type-alias/leading-where-clause.fixed
index 885556c1efe..ca0ab7b5c7d 100644
--- a/tests/ui/lazy-type-alias/leading-where-clause.fixed
+++ b/tests/ui/lazy-type-alias/leading-where-clause.fixed
@@ -2,14 +2,22 @@
 
 #![feature(lazy_type_alias)]
 #![allow(incomplete_features)]
+#![crate_type = "lib"]
 
 // Check that we *reject* leading where-clauses on lazy type aliases.
 
-type Alias<T>
+pub type Leading0<T>
 
 = T where String: From<T>;
-//~^^^ ERROR where clauses are not allowed before the type for type aliases
 
-fn main() {
-    let _: Alias<&str>;
-}
+pub type Leading1<T, U>
+
+= (T, U)
+where
+    U: Copy, String: From<T>;
+
+pub type EmptyLeading0  = () where;
+//~^ ERROR where clauses are not allowed before the type for type aliases
+
+pub type EmptyLeading1<T>  = T where T: Copy;
+//~^ ERROR where clauses are not allowed before the type for type aliases
diff --git a/tests/ui/lazy-type-alias/leading-where-clause.rs b/tests/ui/lazy-type-alias/leading-where-clause.rs
index a0a09a2a08e..460f7e3a999 100644
--- a/tests/ui/lazy-type-alias/leading-where-clause.rs
+++ b/tests/ui/lazy-type-alias/leading-where-clause.rs
@@ -2,15 +2,24 @@
 
 #![feature(lazy_type_alias)]
 #![allow(incomplete_features)]
+#![crate_type = "lib"]
 
 // Check that we *reject* leading where-clauses on lazy type aliases.
 
-type Alias<T>
-where
+pub type Leading0<T>
+where //~ ERROR where clauses are not allowed before the type for type aliases
     String: From<T>,
 = T;
-//~^^^ ERROR where clauses are not allowed before the type for type aliases
 
-fn main() {
-    let _: Alias<&str>;
-}
+pub type Leading1<T, U>
+where //~ ERROR where clauses are not allowed before the type for type aliases
+    String: From<T>,
+= (T, U)
+where
+    U: Copy;
+
+pub type EmptyLeading0 where = ();
+//~^ ERROR where clauses are not allowed before the type for type aliases
+
+pub type EmptyLeading1<T> where = T where T: Copy;
+//~^ ERROR where clauses are not allowed before the type for type aliases
diff --git a/tests/ui/lazy-type-alias/leading-where-clause.stderr b/tests/ui/lazy-type-alias/leading-where-clause.stderr
index 6b0613787e8..344c318d0ef 100644
--- a/tests/ui/lazy-type-alias/leading-where-clause.stderr
+++ b/tests/ui/lazy-type-alias/leading-where-clause.stderr
@@ -1,5 +1,5 @@
 error: where clauses are not allowed before the type for type aliases
-  --> $DIR/leading-where-clause.rs:9:1
+  --> $DIR/leading-where-clause.rs:10:1
    |
 LL | / where
 LL | |     String: From<T>,
@@ -12,5 +12,42 @@ LL +
 LL ~ = T where String: From<T>;
    |
 
-error: aborting due to 1 previous error
+error: where clauses are not allowed before the type for type aliases
+  --> $DIR/leading-where-clause.rs:15:1
+   |
+LL | / where
+LL | |     String: From<T>,
+   | |____________________^
+   |
+   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+help: move it to the end of the type declaration
+   |
+LL + 
+LL | = (T, U)
+LL | where
+LL ~     U: Copy, String: From<T>;
+   |
+
+error: where clauses are not allowed before the type for type aliases
+  --> $DIR/leading-where-clause.rs:21:24
+   |
+LL | pub type EmptyLeading0 where = ();
+   |                        ^^^^^
+   |
+   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+help: move it to the end of the type declaration
+   |
+LL - pub type EmptyLeading0 where = ();
+LL + pub type EmptyLeading0  = () where;
+   |
+
+error: where clauses are not allowed before the type for type aliases
+  --> $DIR/leading-where-clause.rs:24:27
+   |
+LL | pub type EmptyLeading1<T> where = T where T: Copy;
+   |                           ^^^^^ help: remove this `where`
+   |
+   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed
index b53d9d61d67..9b935b16678 100644
--- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed
+++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed
@@ -8,6 +8,8 @@ trait Trait {
     type Assoc where u32: Copy;
     // Fine.
     type Assoc2 where u32: Copy, i32: Copy;
+    //
+    type Assoc3;
 }
 
 impl Trait for u32 {
@@ -17,6 +19,8 @@ impl Trait for u32 {
     // Not fine, suggests moving `u32: Copy`
     type Assoc2  = () where i32: Copy, u32: Copy;
     //~^ WARNING where clause not allowed here
+    type Assoc3  = () where;
+    //~^ WARNING where clause not allowed here
 }
 
 impl Trait for i32 {
@@ -25,6 +29,8 @@ impl Trait for i32 {
     // Not fine, suggests moving both.
     type Assoc2  = () where u32: Copy, i32: Copy;
     //~^ WARNING where clause not allowed here
+    type Assoc3  = () where;
+    //~^ WARNING where clause not allowed here
 }
 
 fn main() {}
diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs
index 18955dd8bcc..b7a8ab3d4f7 100644
--- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs
+++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs
@@ -8,6 +8,8 @@ trait Trait {
     type Assoc where u32: Copy;
     // Fine.
     type Assoc2 where u32: Copy, i32: Copy;
+    //
+    type Assoc3;
 }
 
 impl Trait for u32 {
@@ -17,6 +19,8 @@ impl Trait for u32 {
     // Not fine, suggests moving `u32: Copy`
     type Assoc2 where u32: Copy = () where i32: Copy;
     //~^ WARNING where clause not allowed here
+    type Assoc3 where = ();
+    //~^ WARNING where clause not allowed here
 }
 
 impl Trait for i32 {
@@ -25,6 +29,8 @@ impl Trait for i32 {
     // Not fine, suggests moving both.
     type Assoc2 where u32: Copy, i32: Copy = ();
     //~^ WARNING where clause not allowed here
+    type Assoc3 where = () where;
+    //~^ WARNING where clause not allowed here
 }
 
 fn main() {}
diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr
index 6ff9d2dd73b..5809ff8f803 100644
--- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr
+++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr
@@ -1,5 +1,5 @@
 warning: where clause not allowed here
-  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:15:16
+  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:17:16
    |
 LL |     type Assoc where u32: Copy = ();
    |                ^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL +     type Assoc  = () where u32: Copy;
    |
 
 warning: where clause not allowed here
-  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:18:17
+  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:20:17
    |
 LL |     type Assoc2 where u32: Copy = () where i32: Copy;
    |                 ^^^^^^^^^^^^^^^
@@ -26,7 +26,20 @@ LL +     type Assoc2  = () where i32: Copy, u32: Copy;
    |
 
 warning: where clause not allowed here
-  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:26:17
+  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:22:17
+   |
+LL |     type Assoc3 where = ();
+   |                 ^^^^^
+   |
+   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+help: move it to the end of the type declaration
+   |
+LL -     type Assoc3 where = ();
+LL +     type Assoc3  = () where;
+   |
+
+warning: where clause not allowed here
+  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:30:17
    |
 LL |     type Assoc2 where u32: Copy, i32: Copy = ();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -38,5 +51,13 @@ LL -     type Assoc2 where u32: Copy, i32: Copy = ();
 LL +     type Assoc2  = () where u32: Copy, i32: Copy;
    |
 
-warning: 3 warnings emitted
+warning: where clause not allowed here
+  --> $DIR/where-clause-placement-assoc-type-in-impl.rs:32:17
+   |
+LL |     type Assoc3 where = () where;
+   |                 ^^^^^ help: remove this `where`
+   |
+   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+
+warning: 5 warnings emitted