Skip to content

Commit

Permalink
parse: improve recovery for assoc eq constraints.
Browse files Browse the repository at this point in the history
  • Loading branch information
Centril committed Mar 27, 2020
1 parent f91de44 commit 2972bb3
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 1 deletion.
44 changes: 43 additions & 1 deletion src/librustc_parse/parser/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::maybe_whole;
use rustc_ast::ast::{self, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs};
use rustc_ast::ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
use rustc_ast::ast::{Ident, Path, PathSegment, QSelf};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token};
use rustc_errors::{pluralize, Applicability, PResult};
use rustc_span::source_map::{BytePos, Span};
Expand Down Expand Up @@ -405,7 +406,8 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
let ident = self.parse_ident()?;
let kind = if self.eat(&token::Eq) {
AssocTyConstraintKind::Equality { ty: self.parse_ty()? }
let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
AssocTyConstraintKind::Equality { ty }
} else if self.eat(&token::Colon) {
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
AssocTyConstraintKind::Bound { bounds }
Expand All @@ -427,6 +429,46 @@ impl<'a> Parser<'a> {
}
}

/// Parse the term to the right of an associated item equality constraint.
/// That is, parse `<term>` in `Item = <term>`.
/// Right now, this only admits types in `<term>`.
fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
let arg = self.parse_generic_arg()?;
let span = ident.span.to(self.prev_token.span);
match arg {
Some(GenericArg::Type(ty)) => return Ok(ty),
Some(GenericArg::Const(expr)) => {
self.struct_span_err(span, "cannot constrain an associated constant to a value")
.span_label(ident.span, "the value constrains this associated constant")
.span_label(expr.value.span, "the value is given in this expression")
.emit();
}
Some(GenericArg::Lifetime(lt)) => {
self.struct_span_err(span, "associated lifetimes are not supported")
.span_label(lt.ident.span, "the lifetime is given here")
.help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
.emit();
}
None => {
self.struct_span_err(span, "missing type to the right of `=`")
.span_suggestion(
span,
"to constrain the associated type, add a type after `=`",
format!("{} = TheType", ident),
Applicability::HasPlaceholders,
)
.span_suggestion(
eq,
&format!("remove the `=` if `{}` is a type", ident),
String::new(),
Applicability::MaybeIncorrect,
)
.emit();
}
}
Ok(self.mk_ty(span, ast::TyKind::Err))
}

/// Parse a generic argument in a path segment.
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
Expand Down
7 changes: 7 additions & 0 deletions src/test/ui/parser/recover-assoc-const-constraint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[cfg(FALSE)]
fn syntax() {
bar::<Item = 42>(); //~ ERROR cannot constrain an associated constant to a value
bar::<Item = { 42 }>(); //~ ERROR cannot constrain an associated constant to a value
}

fn main() {}
20 changes: 20 additions & 0 deletions src/test/ui/parser/recover-assoc-const-constraint.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: cannot constrain an associated constant to a value
--> $DIR/recover-assoc-const-constraint.rs:3:11
|
LL | bar::<Item = 42>();
| ----^^^--
| | |
| | the value is given in this expression
| the value constrains this associated constant

error: cannot constrain an associated constant to a value
--> $DIR/recover-assoc-const-constraint.rs:4:11
|
LL | bar::<Item = { 42 }>();
| ----^^^------
| | |
| | the value is given in this expression
| the value constrains this associated constant

error: aborting due to 2 previous errors

6 changes: 6 additions & 0 deletions src/test/ui/parser/recover-assoc-eq-missing-term.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[cfg(FALSE)]
fn syntax() {
bar::<Item = >(); //~ ERROR missing type to the right of `=`
}

fn main() {}
17 changes: 17 additions & 0 deletions src/test/ui/parser/recover-assoc-eq-missing-term.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error: missing type to the right of `=`
--> $DIR/recover-assoc-eq-missing-term.rs:3:11
|
LL | bar::<Item = >();
| ^^^^^^
|
help: to constrain the associated type, add a type after `=`
|
LL | bar::<Item = TheType >();
| ^^^^^^^^^^^^^^
help: remove the `=` if `Item` is a type
|
LL | bar::<Item >();
| --

error: aborting due to previous error

6 changes: 6 additions & 0 deletions src/test/ui/parser/recover-assoc-lifetime-constraint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[cfg(FALSE)]
fn syntax() {
bar::<Item = 'a>(); //~ ERROR associated lifetimes are not supported
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/parser/recover-assoc-lifetime-constraint.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error: associated lifetimes are not supported
--> $DIR/recover-assoc-lifetime-constraint.rs:3:11
|
LL | bar::<Item = 'a>();
| ^^^^^^^--
| |
| the lifetime is given here
|
= help: if you meant to specify a trait object, write `dyn Trait + 'lifetime`

error: aborting due to previous error

0 comments on commit 2972bb3

Please sign in to comment.