Parse loop labels missing a leading '
When encountering the following typo: ```rust a: loop { break 'a; } ``` provide an appropriate suggestion.
This commit is contained in:
parent
74ddaf000c
commit
8c5dafdcb8
@ -585,7 +585,7 @@ fn parse_assoc_op_cast(
|
|||||||
lhs_span: Span,
|
lhs_span: Span,
|
||||||
expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
|
expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
|
||||||
) -> PResult<'a, P<Expr>> {
|
) -> PResult<'a, P<Expr>> {
|
||||||
let mk_expr = |this: &mut Self, rhs: P<Ty>| {
|
let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| {
|
||||||
this.mk_expr(
|
this.mk_expr(
|
||||||
this.mk_expr_sp(&lhs, lhs_span, rhs.span),
|
this.mk_expr_sp(&lhs, lhs_span, rhs.span),
|
||||||
expr_kind(lhs, rhs),
|
expr_kind(lhs, rhs),
|
||||||
@ -597,13 +597,49 @@ fn parse_assoc_op_cast(
|
|||||||
// LessThan comparison after this cast.
|
// LessThan comparison after this cast.
|
||||||
let parser_snapshot_before_type = self.clone();
|
let parser_snapshot_before_type = self.clone();
|
||||||
let cast_expr = match self.parse_ty_no_plus() {
|
let cast_expr = match self.parse_ty_no_plus() {
|
||||||
Ok(rhs) => mk_expr(self, rhs),
|
Ok(rhs) => mk_expr(self, lhs, rhs),
|
||||||
Err(mut type_err) => {
|
Err(mut type_err) => {
|
||||||
// Rewind to before attempting to parse the type with generics, to recover
|
// Rewind to before attempting to parse the type with generics, to recover
|
||||||
// from situations like `x as usize < y` in which we first tried to parse
|
// from situations like `x as usize < y` in which we first tried to parse
|
||||||
// `usize < y` as a type with generic arguments.
|
// `usize < y` as a type with generic arguments.
|
||||||
let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
|
let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
|
||||||
|
|
||||||
|
// Check for typo of `'a: loop { break 'a }` with a missing `'`.
|
||||||
|
match (&lhs.kind, &self.token.kind) {
|
||||||
|
(
|
||||||
|
// `foo: `
|
||||||
|
ExprKind::Path(None, ast::Path { segments, .. }),
|
||||||
|
TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
|
||||||
|
) if segments.len() == 1 => {
|
||||||
|
let snapshot = self.clone();
|
||||||
|
let label = Label {
|
||||||
|
ident: Ident::from_str_and_span(
|
||||||
|
&format!("'{}", segments[0].ident),
|
||||||
|
segments[0].ident.span,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
match self.parse_labeled_expr(label, AttrVec::new(), false) {
|
||||||
|
Ok(expr) => {
|
||||||
|
type_err.cancel();
|
||||||
|
self.struct_span_err(label.ident.span, "malformed loop label")
|
||||||
|
.span_suggestion(
|
||||||
|
label.ident.span,
|
||||||
|
"use the correct loop label format",
|
||||||
|
label.ident.to_string(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
return Ok(expr);
|
||||||
|
}
|
||||||
|
Err(mut err) => {
|
||||||
|
err.cancel();
|
||||||
|
*self = snapshot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
match self.parse_path(PathStyle::Expr) {
|
match self.parse_path(PathStyle::Expr) {
|
||||||
Ok(path) => {
|
Ok(path) => {
|
||||||
let (op_noun, op_verb) = match self.token.kind {
|
let (op_noun, op_verb) = match self.token.kind {
|
||||||
@ -630,7 +666,8 @@ fn parse_assoc_op_cast(
|
|||||||
op_noun,
|
op_noun,
|
||||||
);
|
);
|
||||||
let span_after_type = parser_snapshot_after_type.token.span;
|
let span_after_type = parser_snapshot_after_type.token.span;
|
||||||
let expr = mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path)));
|
let expr =
|
||||||
|
mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
|
||||||
|
|
||||||
let expr_str = self
|
let expr_str = self
|
||||||
.span_to_snippet(expr.span)
|
.span_to_snippet(expr.span)
|
||||||
@ -1067,7 +1104,7 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
|
|||||||
} else if self.eat_keyword(kw::While) {
|
} else if self.eat_keyword(kw::While) {
|
||||||
self.parse_while_expr(None, self.prev_token.span, attrs)
|
self.parse_while_expr(None, self.prev_token.span, attrs)
|
||||||
} else if let Some(label) = self.eat_label() {
|
} else if let Some(label) = self.eat_label() {
|
||||||
self.parse_labeled_expr(label, attrs)
|
self.parse_labeled_expr(label, attrs, true)
|
||||||
} else if self.eat_keyword(kw::Loop) {
|
} else if self.eat_keyword(kw::Loop) {
|
||||||
self.parse_loop_expr(None, self.prev_token.span, attrs)
|
self.parse_loop_expr(None, self.prev_token.span, attrs)
|
||||||
} else if self.eat_keyword(kw::Continue) {
|
} else if self.eat_keyword(kw::Continue) {
|
||||||
@ -1228,7 +1265,12 @@ fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse `'label: $expr`. The label is already parsed.
|
/// Parse `'label: $expr`. The label is already parsed.
|
||||||
fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
fn parse_labeled_expr(
|
||||||
|
&mut self,
|
||||||
|
label: Label,
|
||||||
|
attrs: AttrVec,
|
||||||
|
consume_colon: bool,
|
||||||
|
) -> PResult<'a, P<Expr>> {
|
||||||
let lo = label.ident.span;
|
let lo = label.ident.span;
|
||||||
let label = Some(label);
|
let label = Some(label);
|
||||||
let ate_colon = self.eat(&token::Colon);
|
let ate_colon = self.eat(&token::Colon);
|
||||||
@ -1247,7 +1289,7 @@ fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<
|
|||||||
self.parse_expr()
|
self.parse_expr()
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
if !ate_colon {
|
if !ate_colon && consume_colon {
|
||||||
self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
|
self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,11 +7,10 @@ fn main() {
|
|||||||
'b: for _ in 0..1 {
|
'b: for _ in 0..1 {
|
||||||
break b; //~ ERROR cannot find value `b` in this scope
|
break b; //~ ERROR cannot find value `b` in this scope
|
||||||
}
|
}
|
||||||
c: for _ in 0..1 { //~ ERROR expected identifier, found keyword `for`
|
c: for _ in 0..1 { //~ ERROR malformed loop label
|
||||||
//~^ ERROR expected `<`, found reserved identifier `_`
|
|
||||||
break 'c;
|
break 'c;
|
||||||
}
|
}
|
||||||
d: for _ in 0..1 {
|
d: for _ in 0..1 { //~ ERROR malformed loop label
|
||||||
break ;
|
break d; //~ ERROR cannot find value `d` in this scope
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,14 @@
|
|||||||
error: expected identifier, found keyword `for`
|
error: malformed loop label
|
||||||
--> $DIR/label_misspelled_2.rs:10:8
|
--> $DIR/label_misspelled_2.rs:10:5
|
||||||
|
|
|
|
||||||
LL | c: for _ in 0..1 {
|
LL | c: for _ in 0..1 {
|
||||||
| ^^^ expected identifier, found keyword
|
| ^ help: use the correct loop label format: `'c`
|
||||||
|
|
||||||
error: expected `<`, found reserved identifier `_`
|
error: malformed loop label
|
||||||
--> $DIR/label_misspelled_2.rs:10:12
|
--> $DIR/label_misspelled_2.rs:13:5
|
||||||
|
|
|
|
||||||
LL | c: for _ in 0..1 {
|
LL | d: for _ in 0..1 {
|
||||||
| - ^ expected `<`
|
| ^ help: use the correct loop label format: `'d`
|
||||||
| |
|
|
||||||
| tried to parse a type due to this type ascription
|
|
||||||
|
|
|
||||||
= note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
|
|
||||||
= note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
|
|
||||||
|
|
||||||
error[E0425]: cannot find value `b` in this scope
|
error[E0425]: cannot find value `b` in this scope
|
||||||
--> $DIR/label_misspelled_2.rs:8:15
|
--> $DIR/label_misspelled_2.rs:8:15
|
||||||
@ -26,6 +21,17 @@ LL | break b;
|
|||||||
| not found in this scope
|
| not found in this scope
|
||||||
| help: use the similarly named label: `'b`
|
| help: use the similarly named label: `'b`
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error[E0425]: cannot find value `d` in this scope
|
||||||
|
--> $DIR/label_misspelled_2.rs:14:15
|
||||||
|
|
|
||||||
|
LL | d: for _ in 0..1 {
|
||||||
|
| - a label with a similar name exists
|
||||||
|
LL | break d;
|
||||||
|
| ^
|
||||||
|
| |
|
||||||
|
| not found in this scope
|
||||||
|
| help: use the similarly named label: `'d`
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0425`.
|
For more information about this error, try `rustc --explain E0425`.
|
||||||
|
Loading…
Reference in New Issue
Block a user