Rollup merge of #92118 - jackh726:type-alias-position-error, r=petrochenkov

Parse and suggest moving where clauses after equals for type aliases

~Mostly the same as #90076, but doesn't make any syntax changes.~ Whether or not we want to land the syntax changes, we should  parse the invalid where clause position and suggest moving.

r? `@nikomatsakis`
cc `@petrochenkov` you might have thoughts on implementation
This commit is contained in:
Matthias Krüger 2021-12-29 10:17:08 +01:00 committed by GitHub
commit bee14712ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 158 additions and 28 deletions

View file

@ -2780,11 +2780,16 @@ impl<'a> State<'a> {
self.word_space(",");
}
match *predicate {
self.print_where_predicate(predicate);
}
}
pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
match predicate {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
ref bound_generic_params,
ref bounded_ty,
ref bounds,
bound_generic_params,
bounded_ty,
bounds,
..
}) => {
self.print_formal_generic_params(bound_generic_params);
@ -2792,17 +2797,13 @@ impl<'a> State<'a> {
self.print_type_bounds(":", bounds);
}
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
ref lifetime,
ref bounds,
lifetime,
bounds,
..
}) => {
self.print_lifetime_bounds(*lifetime, bounds);
}
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
ref lhs_ty,
ref rhs_ty,
..
}) => {
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
self.print_type(lhs_ty);
self.space();
self.word_space("=");
@ -2810,7 +2811,6 @@ impl<'a> State<'a> {
}
}
}
}
crate fn print_use_tree(&mut self, tree: &ast::UseTree) {
match tree.kind {

View file

@ -794,6 +794,44 @@ impl<'a> Parser<'a> {
))
}
/// Emits an error that the where clause at the end of a type alias is not
/// allowed and suggests moving it.
fn error_ty_alias_where(
&self,
before_where_clause_present: bool,
before_where_clause_span: Span,
after_predicates: &[WherePredicate],
after_where_clause_span: Span,
) {
let mut err =
self.struct_span_err(after_where_clause_span, "where clause not allowed here");
if !after_predicates.is_empty() {
let mut state = crate::pprust::State::new();
if !before_where_clause_present {
state.space();
state.word_space("where");
} else {
state.word_space(",");
}
let mut first = true;
for p in after_predicates.iter() {
if !first {
state.word_space(",");
}
first = false;
state.print_where_predicate(p);
}
let suggestion = state.s.eof();
err.span_suggestion(
before_where_clause_span.shrink_to_hi(),
"move it here",
suggestion,
Applicability::MachineApplicable,
);
}
err.emit()
}
/// Parses a `type` alias with the following grammar:
/// ```
/// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
@ -806,9 +844,24 @@ impl<'a> Parser<'a> {
// Parse optional colon and param bounds.
let bounds =
if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
generics.where_clause = self.parse_where_clause()?;
let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
if self.token.is_keyword(kw::Where) {
let after_where_clause = self.parse_where_clause()?;
self.error_ty_alias_where(
generics.where_clause.has_where_token,
generics.where_clause.span,
&after_where_clause.predicates,
after_where_clause.span,
);
generics.where_clause.predicates.extend(after_where_clause.predicates.into_iter());
}
self.expect_semi()?;
Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty }))))

View file

@ -0,0 +1,37 @@
// check-fail
#![feature(generic_associated_types)]
// Fine, but lints as unused
type Foo where u32: Copy = ();
// Not fine.
type Bar = () where u32: Copy;
//~^ ERROR where clause not allowed here
type Baz = () where;
//~^ ERROR where clause not allowed here
trait Trait {
// Fine.
type Assoc where u32: Copy;
// Fine.
type Assoc2 where u32: Copy, i32: Copy;
}
impl Trait for u32 {
// Fine.
type Assoc where u32: Copy = ();
// Not fine, suggests moving `i32: Copy`
type Assoc2 where u32: Copy = () where i32: Copy;
//~^ ERROR where clause not allowed here
}
impl Trait for i32 {
// Not fine, suggests moving `u32: Copy`
type Assoc = () where u32: Copy;
//~^ ERROR where clause not allowed here
// Not fine, suggests moving both.
type Assoc2 = () where u32: Copy, i32: Copy;
//~^ ERROR where clause not allowed here
}
fn main() {}

View file

@ -0,0 +1,40 @@
error: where clause not allowed here
--> $DIR/type-alias-where.rs:8:15
|
LL | type Bar = () where u32: Copy;
| - ^^^^^^^^^^^^^^^
| |
| help: move it here: `where u32: Copy`
error: where clause not allowed here
--> $DIR/type-alias-where.rs:10:15
|
LL | type Baz = () where;
| ^^^^^
error: where clause not allowed here
--> $DIR/type-alias-where.rs:24:38
|
LL | type Assoc2 where u32: Copy = () where i32: Copy;
| - ^^^^^^^^^^^^^^^
| |
| help: move it here: `, i32: Copy`
error: where clause not allowed here
--> $DIR/type-alias-where.rs:30:21
|
LL | type Assoc = () where u32: Copy;
| - ^^^^^^^^^^^^^^^
| |
| help: move it here: `where u32: Copy`
error: where clause not allowed here
--> $DIR/type-alias-where.rs:33:22
|
LL | type Assoc2 = () where u32: Copy, i32: Copy;
| - ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: move it here: `where u32: Copy, i32: Copy`
error: aborting due to 5 previous errors