Skip to content

Commit 2972bb3

Browse files
committed
parse: improve recovery for assoc eq constraints.
1 parent f91de44 commit 2972bb3

7 files changed

+111
-1
lines changed

src/librustc_parse/parser/path.rs

+43-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::maybe_whole;
44
use rustc_ast::ast::{self, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs};
55
use rustc_ast::ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
66
use rustc_ast::ast::{Ident, Path, PathSegment, QSelf};
7+
use rustc_ast::ptr::P;
78
use rustc_ast::token::{self, Token};
89
use rustc_errors::{pluralize, Applicability, PResult};
910
use rustc_span::source_map::{BytePos, Span};
@@ -405,7 +406,8 @@ impl<'a> Parser<'a> {
405406
let lo = self.token.span;
406407
let ident = self.parse_ident()?;
407408
let kind = if self.eat(&token::Eq) {
408-
AssocTyConstraintKind::Equality { ty: self.parse_ty()? }
409+
let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
410+
AssocTyConstraintKind::Equality { ty }
409411
} else if self.eat(&token::Colon) {
410412
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
411413
AssocTyConstraintKind::Bound { bounds }
@@ -427,6 +429,46 @@ impl<'a> Parser<'a> {
427429
}
428430
}
429431

432+
/// Parse the term to the right of an associated item equality constraint.
433+
/// That is, parse `<term>` in `Item = <term>`.
434+
/// Right now, this only admits types in `<term>`.
435+
fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
436+
let arg = self.parse_generic_arg()?;
437+
let span = ident.span.to(self.prev_token.span);
438+
match arg {
439+
Some(GenericArg::Type(ty)) => return Ok(ty),
440+
Some(GenericArg::Const(expr)) => {
441+
self.struct_span_err(span, "cannot constrain an associated constant to a value")
442+
.span_label(ident.span, "the value constrains this associated constant")
443+
.span_label(expr.value.span, "the value is given in this expression")
444+
.emit();
445+
}
446+
Some(GenericArg::Lifetime(lt)) => {
447+
self.struct_span_err(span, "associated lifetimes are not supported")
448+
.span_label(lt.ident.span, "the lifetime is given here")
449+
.help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
450+
.emit();
451+
}
452+
None => {
453+
self.struct_span_err(span, "missing type to the right of `=`")
454+
.span_suggestion(
455+
span,
456+
"to constrain the associated type, add a type after `=`",
457+
format!("{} = TheType", ident),
458+
Applicability::HasPlaceholders,
459+
)
460+
.span_suggestion(
461+
eq,
462+
&format!("remove the `=` if `{}` is a type", ident),
463+
String::new(),
464+
Applicability::MaybeIncorrect,
465+
)
466+
.emit();
467+
}
468+
}
469+
Ok(self.mk_ty(span, ast::TyKind::Err))
470+
}
471+
430472
/// Parse a generic argument in a path segment.
431473
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
432474
fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#[cfg(FALSE)]
2+
fn syntax() {
3+
bar::<Item = 42>(); //~ ERROR cannot constrain an associated constant to a value
4+
bar::<Item = { 42 }>(); //~ ERROR cannot constrain an associated constant to a value
5+
}
6+
7+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: cannot constrain an associated constant to a value
2+
--> $DIR/recover-assoc-const-constraint.rs:3:11
3+
|
4+
LL | bar::<Item = 42>();
5+
| ----^^^--
6+
| | |
7+
| | the value is given in this expression
8+
| the value constrains this associated constant
9+
10+
error: cannot constrain an associated constant to a value
11+
--> $DIR/recover-assoc-const-constraint.rs:4:11
12+
|
13+
LL | bar::<Item = { 42 }>();
14+
| ----^^^------
15+
| | |
16+
| | the value is given in this expression
17+
| the value constrains this associated constant
18+
19+
error: aborting due to 2 previous errors
20+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[cfg(FALSE)]
2+
fn syntax() {
3+
bar::<Item = >(); //~ ERROR missing type to the right of `=`
4+
}
5+
6+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: missing type to the right of `=`
2+
--> $DIR/recover-assoc-eq-missing-term.rs:3:11
3+
|
4+
LL | bar::<Item = >();
5+
| ^^^^^^
6+
|
7+
help: to constrain the associated type, add a type after `=`
8+
|
9+
LL | bar::<Item = TheType >();
10+
| ^^^^^^^^^^^^^^
11+
help: remove the `=` if `Item` is a type
12+
|
13+
LL | bar::<Item >();
14+
| --
15+
16+
error: aborting due to previous error
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[cfg(FALSE)]
2+
fn syntax() {
3+
bar::<Item = 'a>(); //~ ERROR associated lifetimes are not supported
4+
}
5+
6+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: associated lifetimes are not supported
2+
--> $DIR/recover-assoc-lifetime-constraint.rs:3:11
3+
|
4+
LL | bar::<Item = 'a>();
5+
| ^^^^^^^--
6+
| |
7+
| the lifetime is given here
8+
|
9+
= help: if you meant to specify a trait object, write `dyn Trait + 'lifetime`
10+
11+
error: aborting due to previous error
12+

0 commit comments

Comments
 (0)