about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2023-08-09 16:44:06 +0200
committerLeón Orell Valerian Liehr <me@fmease.dev>2023-08-10 16:13:08 +0200
commit051eb7ca7cfe439c2155005937b80219a5e81c49 (patch)
tree7622583db45a9aaef5e40c6a9d549d44c9fc426e
parent617821ab32b7a7563f561812385e2fba7b1d2981 (diff)
downloadrust-051eb7ca7cfe439c2155005937b80219a5e81c49.tar.gz
rust-051eb7ca7cfe439c2155005937b80219a5e81c49.zip
Unlock trailing where-clauses for lazy type aliases
-rw-r--r--compiler/rustc_ast_passes/messages.ftl7
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs99
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs30
-rw-r--r--tests/ui/lazy-type-alias/leading-where-clause.fixed15
-rw-r--r--tests/ui/lazy-type-alias/leading-where-clause.rs16
-rw-r--r--tests/ui/lazy-type-alias/leading-where-clause.stderr16
-rw-r--r--tests/ui/lazy-type-alias/trailing-where-clause.rs13
-rw-r--r--tests/ui/lazy-type-alias/trailing-where-clause.stderr22
-rw-r--r--tests/ui/where-clauses/where-clause-placement-type-alias.stderr6
9 files changed, 175 insertions, 49 deletions
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 2f0ac0c2b19..f323bb4c254 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -239,5 +239,10 @@ ast_passes_visibility_not_permitted =
     .individual_impl_items = place qualifiers on individual impl items instead
     .individual_foreign_items = place qualifiers on individual foreign items instead
 
-ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases
+ast_passes_where_clause_after_type_alias = where clauses are not allowed after the type for type aliases
+    .note = see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+    .help = add `#![feature(lazy_type_alias)]` to the crate attributes to enable
+
+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
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index af594a00705..79fc9e4382f 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -136,40 +136,42 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn check_gat_where(
+    fn check_type_alias_where_clause_location(
         &mut self,
-        id: NodeId,
-        before_predicates: &[WherePredicate],
-        where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
-    ) {
-        if !before_predicates.is_empty() {
-            let mut state = State::new();
-            if !where_clauses.1.0 {
-                state.space();
-                state.word_space("where");
-            } else {
+        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() {
+            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 mut first = true;
-            for p in before_predicates.iter() {
-                if !first {
-                    state.word_space(",");
-                }
-                first = false;
-                state.print_where_predicate(p);
-            }
-            let suggestion = state.s.eof();
-            self.lint_buffer.buffer_lint_with_diagnostic(
-                DEPRECATED_WHERE_CLAUSE_LOCATION,
-                id,
-                where_clauses.0.1,
-                fluent::ast_passes_deprecated_where_clause_location,
-                BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
-                    where_clauses.1.1.shrink_to_hi(),
-                    suggestion,
-                ),
-            );
+            first = false;
+            state.print_where_predicate(p);
         }
+
+        let span = ty_alias.where_clauses.0.1;
+        Err(errors::WhereClauseBeforeTypeAlias {
+            span,
+            sugg: errors::WhereClauseBeforeTypeAliasSugg {
+                left: span,
+                snippet: state.s.eof(),
+                right: ty_alias.where_clauses.1.1.shrink_to_hi(),
+            },
+        })
     }
 
     fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
@@ -1009,7 +1011,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     replace_span: self.ending_semi_or_hi(item.span),
                 });
             }
-            ItemKind::TyAlias(box TyAlias { defaultness, where_clauses, bounds, ty, .. }) => {
+            ItemKind::TyAlias(
+                ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. },
+            ) => {
                 self.check_defaultness(item.span, *defaultness);
                 if ty.is_none() {
                     self.session.emit_err(errors::TyAliasWithoutBody {
@@ -1018,9 +1022,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     });
                 }
                 self.check_type_no_bounds(bounds, "this context");
-                if where_clauses.1.0 {
-                    self.err_handler()
-                        .emit_err(errors::WhereAfterTypeAlias { span: where_clauses.1.1 });
+
+                if self.session.features_untracked().lazy_type_alias {
+                    if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
+                        self.err_handler().emit_err(err);
+                    }
+                } else if where_clauses.1.0 {
+                    self.err_handler().emit_err(errors::WhereClauseAfterTypeAlias {
+                        span: where_clauses.1.1,
+                        help: self.session.is_nightly_build().then_some(()),
+                    });
                 }
             }
             _ => {}
@@ -1313,18 +1324,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
         }
 
-        if let AssocItemKind::Type(box TyAlias {
-            generics,
-            where_clauses,
-            where_predicates_split,
-            ty: Some(_),
-            ..
-        }) = &item.kind
+        if let AssocItemKind::Type(ty_alias) = &item.kind
+            && let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
         {
-            self.check_gat_where(
+            self.lint_buffer.buffer_lint_with_diagnostic(
+                DEPRECATED_WHERE_CLAUSE_LOCATION,
                 item.id,
-                generics.where_clause.predicates.split_at(*where_predicates_split).0,
-                *where_clauses,
+                err.span,
+                fluent::ast_passes_deprecated_where_clause_location,
+                BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
+                    err.sugg.right,
+                    err.sugg.snippet,
+                ),
             );
         }
 
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index ab8015c4a43..a6f217d4780 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -496,11 +496,37 @@ pub struct FieldlessUnion {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_where_after_type_alias)]
+#[diag(ast_passes_where_clause_after_type_alias)]
 #[note]
-pub struct WhereAfterTypeAlias {
+pub struct WhereClauseAfterTypeAlias {
     #[primary_span]
     pub span: Span,
+    #[help]
+    pub help: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_where_clause_before_type_alias)]
+#[note]
+pub struct WhereClauseBeforeTypeAlias {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sugg: WhereClauseBeforeTypeAliasSugg,
+}
+
+#[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,
 }
 
 #[derive(Diagnostic)]
diff --git a/tests/ui/lazy-type-alias/leading-where-clause.fixed b/tests/ui/lazy-type-alias/leading-where-clause.fixed
new file mode 100644
index 00000000000..07ebc09b30e
--- /dev/null
+++ b/tests/ui/lazy-type-alias/leading-where-clause.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+// Check that we *reject* leading where-clauses on lazy type aliases.
+
+type Alias<T>
+
+= T where String: From<T>;
+//~^^^ ERROR where clauses are not allowed before the type for type aliases
+
+fn main() {
+    let _: Alias<&str>;
+}
diff --git a/tests/ui/lazy-type-alias/leading-where-clause.rs b/tests/ui/lazy-type-alias/leading-where-clause.rs
new file mode 100644
index 00000000000..4a654293472
--- /dev/null
+++ b/tests/ui/lazy-type-alias/leading-where-clause.rs
@@ -0,0 +1,16 @@
+// run-rustfix
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+// Check that we *reject* leading where-clauses on lazy type aliases.
+
+type Alias<T>
+where
+    String: From<T>,
+= T;
+//~^^^ ERROR where clauses are not allowed before the type for type aliases
+
+fn main() {
+    let _: Alias<&str>;
+}
diff --git a/tests/ui/lazy-type-alias/leading-where-clause.stderr b/tests/ui/lazy-type-alias/leading-where-clause.stderr
new file mode 100644
index 00000000000..8ddf0ce6c65
--- /dev/null
+++ b/tests/ui/lazy-type-alias/leading-where-clause.stderr
@@ -0,0 +1,16 @@
+error: where clauses are not allowed before the type for type aliases
+  --> $DIR/leading-where-clause.rs:9: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 where String: From<T>;
+   |
+
+error: aborting due to previous error
+
diff --git a/tests/ui/lazy-type-alias/trailing-where-clause.rs b/tests/ui/lazy-type-alias/trailing-where-clause.rs
new file mode 100644
index 00000000000..ac9598fe5f6
--- /dev/null
+++ b/tests/ui/lazy-type-alias/trailing-where-clause.rs
@@ -0,0 +1,13 @@
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+// Check that we allow & respect trailing where-clauses on lazy type aliases.
+
+type Alias<T> = T
+where
+    String: From<T>;
+
+fn main() {
+    let _: Alias<&str>;
+    let _: Alias<()>; //~ ERROR the trait bound `String: From<()>` is not satisfied
+}
diff --git a/tests/ui/lazy-type-alias/trailing-where-clause.stderr b/tests/ui/lazy-type-alias/trailing-where-clause.stderr
new file mode 100644
index 00000000000..d7606ba6b2a
--- /dev/null
+++ b/tests/ui/lazy-type-alias/trailing-where-clause.stderr
@@ -0,0 +1,22 @@
+error[E0277]: the trait bound `String: From<()>` is not satisfied
+  --> $DIR/trailing-where-clause.rs:12:12
+   |
+LL |     let _: Alias<()>;
+   |            ^^^^^^^^^ the trait `From<()>` is not implemented for `String`
+   |
+   = help: the following other types implement trait `From<T>`:
+             <String as From<char>>
+             <String as From<Box<str>>>
+             <String as From<Cow<'a, str>>>
+             <String as From<&str>>
+             <String as From<&mut str>>
+             <String as From<&String>>
+note: required by a bound on the type alias `Alias`
+  --> $DIR/trailing-where-clause.rs:8:13
+   |
+LL |     String: From<T>;
+   |             ^^^^^^^ required by this bound
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/where-clauses/where-clause-placement-type-alias.stderr b/tests/ui/where-clauses/where-clause-placement-type-alias.stderr
index b3c155a48dd..d341148b04c 100644
--- a/tests/ui/where-clauses/where-clause-placement-type-alias.stderr
+++ b/tests/ui/where-clauses/where-clause-placement-type-alias.stderr
@@ -4,7 +4,8 @@ error: where clauses are not allowed after the type for type aliases
 LL | type Bar = () where u32: Copy;
    |               ^^^^^^^^^^^^^^^
    |
-   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+   = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+   = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable
 
 error: where clauses are not allowed after the type for type aliases
   --> $DIR/where-clause-placement-type-alias.rs:8:15
@@ -12,7 +13,8 @@ error: where clauses are not allowed after the type for type aliases
 LL | type Baz = () where;
    |               ^^^^^
    |
-   = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+   = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+   = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors