Skip to content

Commit

Permalink
Unlock trailing where-clauses for lazy type aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
fmease committed Aug 10, 2023
1 parent 617821a commit 051eb7c
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 49 deletions.
7 changes: 6 additions & 1 deletion compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
99 changes: 55 additions & 44 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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 {
Expand All @@ -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(()),
});
}
}
_ => {}
Expand Down Expand Up @@ -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,
),
);
}

Expand Down
30 changes: 28 additions & 2 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
15 changes: 15 additions & 0 deletions tests/ui/lazy-type-alias/leading-where-clause.fixed
Original file line number Diff line number Diff line change
@@ -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>;
}
16 changes: 16 additions & 0 deletions tests/ui/lazy-type-alias/leading-where-clause.rs
Original file line number Diff line number Diff line change
@@ -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>;
}
16 changes: 16 additions & 0 deletions tests/ui/lazy-type-alias/leading-where-clause.stderr
Original file line number Diff line number Diff line change
@@ -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

13 changes: 13 additions & 0 deletions tests/ui/lazy-type-alias/trailing-where-clause.rs
Original file line number Diff line number Diff line change
@@ -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
}
22 changes: 22 additions & 0 deletions tests/ui/lazy-type-alias/trailing-where-clause.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ 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
|
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

0 comments on commit 051eb7c

Please sign in to comment.