@@ -91,6 +91,18 @@ impl From<P<Expr>> for LhsExpr {
91
91
}
92
92
}
93
93
94
+ #[derive(Debug)]
95
+ enum DestructuredFloat {
96
+ /// 1e2
97
+ Single(Symbol, Span),
98
+ /// 1.
99
+ TrailingDot(Symbol, Span, Span),
100
+ /// 1.2 | 1.2e3
101
+ MiddleDot(Symbol, Span, Span, Symbol, Span),
102
+ /// Invalid
103
+ Error,
104
+ }
105
+
94
106
impl<'a> Parser<'a> {
95
107
/// Parses an expression.
96
108
#[inline]
@@ -1013,13 +1025,8 @@ impl<'a> Parser<'a> {
1013
1025
// support pushing "future tokens" (would be also helpful to `break_and_eat`), or
1014
1026
// we should break everything including floats into more basic proc-macro style
1015
1027
// tokens in the lexer (probably preferable).
1016
- fn parse_expr_tuple_field_access_float(
1017
- &mut self,
1018
- lo: Span,
1019
- base: P<Expr>,
1020
- float: Symbol,
1021
- suffix: Option<Symbol>,
1022
- ) -> P<Expr> {
1028
+ // See also `TokenKind::break_two_token_op` which does similar splitting of `>>` into `>`.
1029
+ fn break_up_float(&mut self, float: Symbol) -> DestructuredFloat {
1023
1030
#[derive(Debug)]
1024
1031
enum FloatComponent {
1025
1032
IdentLike(String),
@@ -1056,7 +1063,7 @@ impl<'a> Parser<'a> {
1056
1063
match &*components {
1057
1064
// 1e2
1058
1065
[IdentLike(i)] => {
1059
- self.parse_expr_tuple_field_access(lo, base, Symbol::intern(&i), suffix, None )
1066
+ DestructuredFloat::Single( Symbol::intern(&i), span )
1060
1067
}
1061
1068
// 1.
1062
1069
[IdentLike(i), Punct('.')] => {
@@ -1068,11 +1075,8 @@ impl<'a> Parser<'a> {
1068
1075
} else {
1069
1076
(span, span)
1070
1077
};
1071
- assert!(suffix.is_none());
1072
1078
let symbol = Symbol::intern(&i);
1073
- self.token = Token::new(token::Ident(symbol, false), ident_span);
1074
- let next_token = (Token::new(token::Dot, dot_span), self.token_spacing);
1075
- self.parse_expr_tuple_field_access(lo, base, symbol, None, Some(next_token))
1079
+ DestructuredFloat::TrailingDot(symbol, ident_span, dot_span)
1076
1080
}
1077
1081
// 1.2 | 1.2e3
1078
1082
[IdentLike(i1), Punct('.'), IdentLike(i2)] => {
@@ -1088,16 +1092,8 @@ impl<'a> Parser<'a> {
1088
1092
(span, span, span)
1089
1093
};
1090
1094
let symbol1 = Symbol::intern(&i1);
1091
- self.token = Token::new(token::Ident(symbol1, false), ident1_span);
1092
- // This needs to be `Spacing::Alone` to prevent regressions.
1093
- // See issue #76399 and PR #76285 for more details
1094
- let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone);
1095
- let base1 =
1096
- self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1));
1097
1095
let symbol2 = Symbol::intern(&i2);
1098
- let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
1099
- self.bump_with((next_token2, self.token_spacing)); // `.`
1100
- self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None)
1096
+ DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span)
1101
1097
}
1102
1098
// 1e+ | 1e- (recovered)
1103
1099
[IdentLike(_), Punct('+' | '-')] |
@@ -1109,12 +1105,83 @@ impl<'a> Parser<'a> {
1109
1105
[IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
1110
1106
// See the FIXME about `TokenCursor` above.
1111
1107
self.error_unexpected_after_dot();
1112
- base
1108
+ DestructuredFloat::Error
1113
1109
}
1114
1110
_ => panic!("unexpected components in a float token: {:?}", components),
1115
1111
}
1116
1112
}
1117
1113
1114
+ fn parse_expr_tuple_field_access_float(
1115
+ &mut self,
1116
+ lo: Span,
1117
+ base: P<Expr>,
1118
+ float: Symbol,
1119
+ suffix: Option<Symbol>,
1120
+ ) -> P<Expr> {
1121
+ match self.break_up_float(float) {
1122
+ // 1e2
1123
+ DestructuredFloat::Single(sym, _sp) => {
1124
+ self.parse_expr_tuple_field_access(lo, base, sym, suffix, None)
1125
+ }
1126
+ // 1.
1127
+ DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {
1128
+ assert!(suffix.is_none());
1129
+ self.token = Token::new(token::Ident(sym, false), ident_span);
1130
+ let next_token = (Token::new(token::Dot, dot_span), self.token_spacing);
1131
+ self.parse_expr_tuple_field_access(lo, base, sym, None, Some(next_token))
1132
+ }
1133
+ // 1.2 | 1.2e3
1134
+ DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span) => {
1135
+ self.token = Token::new(token::Ident(symbol1, false), ident1_span);
1136
+ // This needs to be `Spacing::Alone` to prevent regressions.
1137
+ // See issue #76399 and PR #76285 for more details
1138
+ let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone);
1139
+ let base1 =
1140
+ self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1));
1141
+ let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
1142
+ self.bump_with((next_token2, self.token_spacing)); // `.`
1143
+ self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None)
1144
+ }
1145
+ DestructuredFloat::Error => base,
1146
+ }
1147
+ }
1148
+
1149
+ fn parse_field_name_maybe_tuple(&mut self) -> PResult<'a, ThinVec<Ident>> {
1150
+ let token::Literal(token::Lit { kind: token::Float, symbol, suffix }) = self.token.kind
1151
+ else {
1152
+ return Ok(thin_vec![self.parse_field_name()?]);
1153
+ };
1154
+ Ok(match self.break_up_float(symbol) {
1155
+ // 1e2
1156
+ DestructuredFloat::Single(sym, sp) => {
1157
+ self.bump();
1158
+ thin_vec![Ident::new(sym, sp)]
1159
+ }
1160
+ // 1.
1161
+ DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
1162
+ assert!(suffix.is_none());
1163
+ // Analogous to `Self::break_and_eat`
1164
+ self.token_cursor.break_last_token = true;
1165
+ // This might work, in cases like `1. 2`, and might not,
1166
+ // in cases like `offset_of!(Ty, 1.)`. It depends on what comes
1167
+ // after the float-like token, and therefore we have to make
1168
+ // the other parts of the parser think that there is a dot literal.
1169
+ self.token = Token::new(token::Ident(sym, false), sym_span);
1170
+ self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));
1171
+ thin_vec![Ident::new(sym, sym_span)]
1172
+ }
1173
+ // 1.2 | 1.2e3
1174
+ DestructuredFloat::MiddleDot(symbol1, ident1_span, _dot_span, symbol2, ident2_span) => {
1175
+ self.bump();
1176
+ thin_vec![Ident::new(symbol1, ident1_span), Ident::new(symbol2, ident2_span)]
1177
+ }
1178
+ DestructuredFloat::Error => {
1179
+ self.bump();
1180
+ thin_vec![Ident::new(symbol, self.prev_token.span)]
1181
+ }
1182
+ })
1183
+ }
1184
+
1118
1185
fn parse_expr_tuple_field_access(
1119
1186
&mut self,
1120
1187
lo: Span,
@@ -1821,10 +1888,11 @@ impl<'a> Parser<'a> {
1821
1888
let (fields, _trailing, _recovered) = self.parse_seq_to_before_end(
1822
1889
&TokenKind::CloseDelim(Delimiter::Parenthesis),
1823
1890
seq_sep,
1824
- Parser::parse_field_name ,
1891
+ Parser::parse_field_name_maybe_tuple ,
1825
1892
)?;
1893
+ let fields = fields.into_iter().flatten().collect::<Vec<_>>();
1826
1894
let span = lo.to(self.token.span);
1827
- Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec(). into())))
1895
+ Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.into())))
1828
1896
}
1829
1897
1830
1898
/// Returns a string literal if the next token is a string literal.
0 commit comments