Skip to content

Commit 2176200

Browse files
committed
Recover field accesses in patterns
1 parent 5148007 commit 2176200

File tree

3 files changed

+41
-16
lines changed

3 files changed

+41
-16
lines changed

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ impl From<P<Expr>> for LhsExpr {
9494
}
9595

9696
#[derive(Debug)]
97-
enum DestructuredFloat {
97+
pub(crate) enum DestructuredFloat {
9898
/// 1e2
9999
Single(Symbol, Span),
100100
/// 1.
@@ -1101,7 +1101,7 @@ impl<'a> Parser<'a> {
11011101
// we should break everything including floats into more basic proc-macro style
11021102
// tokens in the lexer (probably preferable).
11031103
// See also `TokenKind::break_two_token_op` which does similar splitting of `>>` into `>`.
1104-
fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {
1104+
pub(crate) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {
11051105
#[derive(Debug)]
11061106
enum FloatComponent {
11071107
IdentLike(String),

compiler/rustc_parse/src/parser/pat.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::errors::{
1010
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
1111
UnexpectedVertVertInPattern,
1212
};
13-
use crate::parser::expr::could_be_unclosed_char_literal;
13+
use crate::parser::expr::{could_be_unclosed_char_literal, DestructuredFloat};
1414
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
1515
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
1616
use rustc_ast::ptr::P;
@@ -357,14 +357,27 @@ impl<'a> Parser<'a> {
357357
return None;
358358
}
359359

360-
// Check for `.hello()`, but allow `.Hello()` to be recovered as `, Hello()` in `parse_seq_to_before_tokens()`.
361-
let has_trailing_method = self.check_noexpect(&token::Dot)
360+
// Returns `true` iff `token` is `x.y` float
361+
let is_float_literal = |that: &Self, token: &Token| -> bool {
362+
use token::{Lit, LitKind};
363+
364+
if let token::Literal(Lit { kind: LitKind::Float, symbol, suffix: None }) = token.kind {
365+
if let DestructuredFloat::MiddleDot(..) = that.break_up_float(symbol, token.span) {
366+
return true;
367+
}
368+
}
369+
370+
false
371+
};
372+
373+
// Check for `.hello` or `.0`
374+
let has_dot_expr = self.check_noexpect(&token::Dot)
362375
&& self.look_ahead(1, |tok| {
363-
tok.ident()
364-
.and_then(|(ident, _)| ident.name.as_str().chars().next())
365-
.is_some_and(char::is_lowercase)
366-
})
367-
&& self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Parenthesis));
376+
tok.is_ident()
377+
|| tok.is_integer_lit()
378+
// `0.0` get lexed as a float literal
379+
|| is_float_literal(&self, &tok)
380+
});
368381

369382
// Check for operators.
370383
// `|` is excluded as it is used in pattern alternatives and lambdas,
@@ -376,7 +389,7 @@ impl<'a> Parser<'a> {
376389
|| (self.token.kind == token::OpenDelim(Delimiter::Bracket)
377390
&& self.look_ahead(1, |tok| tok.kind != token::CloseDelim(Delimiter::Bracket)));
378391

379-
if !has_trailing_method && !has_trailing_operator {
392+
if !has_dot_expr && !has_trailing_operator {
380393
// Nothing to recover here.
381394
return None;
382395
}
@@ -412,7 +425,7 @@ impl<'a> Parser<'a> {
412425
&& self.look_ahead(1, Token::is_range_separator);
413426

414427
// Check that `parse_expr_assoc_with` didn't eat a rhs.
415-
let is_method_call = has_trailing_method && non_assoc_span == expr.span;
428+
let is_method_call = false && non_assoc_span == expr.span;
416429

417430
return Some(self.dcx().emit_err(UnexpectedExpressionInPattern {
418431
span: expr.span,

tests/ui/parser/bad-name.stderr

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1-
error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.`
2-
--> $DIR/bad-name.rs:4:8
1+
error: field expressions cannot have generic arguments
2+
--> $DIR/bad-name.rs:4:12
33
|
44
LL | let x.y::<isize>.z foo;
5-
| ^ expected one of `:`, `;`, `=`, `@`, or `|`
5+
| ^^^^^^^
66

7-
error: aborting due to 1 previous error
7+
error: expected a pattern, found an expression
8+
--> $DIR/bad-name.rs:4:7
9+
|
10+
LL | let x.y::<isize>.z foo;
11+
| ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
12+
13+
error: expected one of `(`, `.`, `::`, `:`, `;`, `=`, `?`, `|`, or an operator, found `foo`
14+
--> $DIR/bad-name.rs:4:22
15+
|
16+
LL | let x.y::<isize>.z foo;
17+
| ^^^ expected one of 9 possible tokens
18+
19+
error: aborting due to 3 previous errors
820

0 commit comments

Comments
 (0)