From 051eb7ca7cfe439c2155005937b80219a5e81c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 9 Aug 2023 16:44:06 +0200 Subject: [PATCH] Unlock trailing where-clauses for lazy type aliases --- compiler/rustc_ast_passes/messages.ftl | 7 +- .../rustc_ast_passes/src/ast_validation.rs | 99 ++++++++++--------- compiler/rustc_ast_passes/src/errors.rs | 30 +++++- .../leading-where-clause.fixed | 15 +++ .../lazy-type-alias/leading-where-clause.rs | 16 +++ .../leading-where-clause.stderr | 16 +++ .../lazy-type-alias/trailing-where-clause.rs | 13 +++ .../trailing-where-clause.stderr | 22 +++++ .../where-clause-placement-type-alias.stderr | 6 +- 9 files changed, 175 insertions(+), 49 deletions(-) create mode 100644 tests/ui/lazy-type-alias/leading-where-clause.fixed create mode 100644 tests/ui/lazy-type-alias/leading-where-clause.rs create mode 100644 tests/ui/lazy-type-alias/leading-where-clause.stderr create mode 100644 tests/ui/lazy-type-alias/trailing-where-clause.rs create mode 100644 tests/ui/lazy-type-alias/trailing-where-clause.stderr diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 2f0ac0c2b1987..f323bb4c254e0 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 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 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 af594a00705f5..79fc9e4382fa3 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, 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 ab8015c4a43b6..a6f217d4780fd 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 0000000000000..07ebc09b30ee6 --- /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 where String: From; +//~^^^ 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 0000000000000..4a6542934720d --- /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 +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.stderr b/tests/ui/lazy-type-alias/leading-where-clause.stderr new file mode 100644 index 0000000000000..8ddf0ce6c6558 --- /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, + | |____________________^ + | + = note: see issue #89122 for more information +help: move it to the end of the type declaration + | +LL + +LL ~ = T where String: From; + | + +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 0000000000000..ac9598fe5f6aa --- /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 +where + String: From; + +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 0000000000000..d7606ba6b2a9c --- /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`: + > + >> + >> + > + > + > +note: required by a bound on the type alias `Alias` + --> $DIR/trailing-where-clause.rs:8:13 + | +LL | String: From; + | ^^^^^^^ 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 b3c155a48ddbc..d341148b04cb5 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 for more information + = note: see issue #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 for more information + = note: see issue #112792 for more information + = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable error: aborting due to 2 previous errors