Skip to content

Commit 5ce9b80

Browse files
committed
Refactor out error case & apply suggestions.
This is almost entirely refactoring and message changing, with the single behavioral change of panicking for unexpected output.
1 parent 940f657 commit 5ce9b80

File tree

1 file changed

+42
-20
lines changed

1 file changed

+42
-20
lines changed

src/librustc_parse/parser/expr.rs

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -551,8 +551,8 @@ impl<'a> Parser<'a> {
551551
// Save the state of the parser before parsing type normally, in case there is a
552552
// LessThan comparison after this cast.
553553
let parser_snapshot_before_type = self.clone();
554-
let type_result = match self.parse_ty_no_plus() {
555-
Ok(rhs) => Ok(mk_expr(self, rhs)),
554+
let cast_expr = match self.parse_ty_no_plus() {
555+
Ok(rhs) => mk_expr(self, rhs),
556556
Err(mut type_err) => {
557557
// Rewind to before attempting to parse the type with generics, to recover
558558
// from situations like `x as usize < y` in which we first tried to parse
@@ -606,41 +606,63 @@ impl<'a> Parser<'a> {
606606
)
607607
.emit();
608608

609-
Ok(expr)
609+
expr
610610
}
611611
Err(mut path_err) => {
612612
// Couldn't parse as a path, return original error and parser state.
613613
path_err.cancel();
614614
mem::replace(self, parser_snapshot_after_type);
615-
Err(type_err)
615+
return Err(type_err);
616616
}
617617
}
618618
}
619619
};
620620

621-
// Disallow postfix operators such as `.`, `?` or index (`[]`) after casts.
622-
// Parses the postfix operator and emits an error.
623-
let expr = type_result?;
624-
let span = expr.span;
621+
self.parse_and_disallow_postfix_after_cast(cast_expr)
622+
}
625623

626-
// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`.
627-
let with_postfix = self.parse_dot_or_call_expr_with_(expr, span)?;
628-
if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) {
624+
/// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast,
625+
/// then emits an error and returns the newly parsed tree.
626+
/// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`.
627+
fn parse_and_disallow_postfix_after_cast(
628+
&mut self,
629+
cast_expr: P<Expr>,
630+
) -> PResult<'a, P<Expr>> {
631+
use std::collections::hash_map::DefaultHasher;
632+
use std::hash::Hasher;
633+
// Hash the memory location of expr before parsing any following postfix operators.
634+
// This will be compared with the hash of the output expression.
635+
// If they different we can assume we parsed another expression because the existing expression is not reallocated.
636+
let mut before_hasher = DefaultHasher::new();
637+
std::ptr::hash(&*cast_expr, &mut before_hasher);
638+
let before_hash = before_hasher.finish();
639+
let span = cast_expr.span;
640+
let with_postfix = self.parse_dot_or_call_expr_with_(cast_expr, span)?;
641+
642+
let mut after_hasher = DefaultHasher::new();
643+
std::ptr::hash(&*with_postfix, &mut after_hasher);
644+
let after_hash = after_hasher.finish();
645+
646+
// Check if an illegal postfix operator has been added after the cast.
647+
// If the resulting expression is not a cast, or has a different memory location, it is an illegal postfix operator.
648+
if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) || after_hash != before_hash {
629649
let expr_str = self.span_to_snippet(span);
630650

631651
let msg = format!(
632-
"casts followed by {} are not supported",
652+
"casts cannot be followed by {}",
633653
match with_postfix.kind {
634-
ExprKind::Index(_, _) => "index operators",
635-
ExprKind::Try(_) => "try operators",
636-
ExprKind::Field(_, _) => "field access expressions",
637-
ExprKind::MethodCall(_, _) => "method call expressions",
638-
ExprKind::Await(_) => "awaits",
639-
_ => "expressions",
654+
ExprKind::Index(_, _) => "indexing",
655+
ExprKind::Try(_) => "?",
656+
ExprKind::Field(_, _) => "a field access",
657+
ExprKind::MethodCall(_, _) => "a method call",
658+
ExprKind::Call(_, _) => "a function call",
659+
ExprKind::Await(_) => "`.await`",
660+
ref kind =>
661+
unreachable!("parse_dot_or_call_expr_with_ shouldn't produce a {:?}", kind),
640662
}
641663
);
642-
let mut err = self.struct_span_err(with_postfix.span, &msg);
643-
let suggestion = "try surrounding the expression with parentheses";
664+
let mut err = self.struct_span_err(span, &msg);
665+
let suggestion = "try surrounding the expression in parentheses";
644666
if let Ok(expr_str) = expr_str {
645667
err.span_suggestion(
646668
span,

0 commit comments

Comments
 (0)