Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unlock trailing where-clauses for lazy type aliases #114662

Merged
merged 1 commit into from Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion compiler/rustc_ast_passes/messages.ftl
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
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
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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`.
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