1use rustc_ast::util::parser::AssocOp;
2use rustc_ast::{BinOpKind, Expr, ExprKind, token};
3use rustc_errors::{Applicability, Diag, PResult};
4use rustc_span::{Span, Spanned, respan, sym};
5
6use crate::parser::Parser;
7use crate::{diagnostics, exp};
8
9impl<'a> Parser<'a> {
10 pub(super) fn recover_from_alpha_logic_op(&self) -> Option<Spanned<AssocOp>> {
12 if self.may_recover()
13 && let Some(ident) = self.token.non_raw_ident()
14 {
15 let (op, sub): (_, fn(_) -> _) = match ident.name {
16 sym::and => (BinOpKind::And, diagnostics::InvalidLogicalOperatorSub::Conjunction),
17 sym::or => (BinOpKind::Or, diagnostics::InvalidLogicalOperatorSub::Disjunction),
18 _ => return None,
19 };
20
21 self.dcx().emit_err(diagnostics::InvalidLogicalOperator {
22 span: self.token.span,
23 incorrect: ident.name,
24 sub: sub(self.token.span),
25 });
26
27 Some(respan(self.token.span, AssocOp::Binary(op)))
28 } else {
29 None
30 }
31 }
32
33 pub(super) fn reject_dotdotdot_expr_op(&self) {
35 if self.token == token::DotDotDot {
36 self.dcx().emit_err(diagnostics::DotDotDotExprOp { span: self.token.span });
37 }
38 }
39
40 pub(super) fn reject_larrow_expr_op(&self) {
42 if self.token == token::LArrow {
43 self.dcx().emit_err(diagnostics::LArrowExprOp { span: self.token.span });
44 }
45 }
46
47 pub(super) fn recover_from_strict_eq_op(&mut self, op: Spanned<AssocOp>) {
49 if let AssocOp::Binary(bop @ BinOpKind::Eq | bop @ BinOpKind::Ne) = op.node
50 && self.token == token::Eq
51 && self.prev_token.span.hi() == self.token.span.lo()
52 {
53 let sp = op.span.to(self.token.span);
54 let sugg = bop.as_str().into();
55 let invalid = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}=", sugg))
})format!("{sugg}=");
56 self.dcx().emit_err(diagnostics::InvalidComparisonOperator {
57 span: sp,
58 invalid: invalid.clone(),
59 sub: diagnostics::InvalidComparisonOperatorSub::Correctable {
60 span: sp,
61 invalid,
62 correct: sugg,
63 },
64 });
65 self.bump();
66 }
67 }
68
69 pub(super) fn recover_from_diamond_ne_op(&mut self) {
71 if let (token::Lt, token::Gt) = (self.prev_token.kind, self.token.kind)
72 && self.prev_token.span.hi() == self.token.span.lo()
73 {
74 let sp = self.prev_token.span.to(self.token.span);
75 self.dcx().emit_err(diagnostics::InvalidComparisonOperator {
76 span: sp,
77 invalid: "<>".into(),
78 sub: diagnostics::InvalidComparisonOperatorSub::Correctable {
79 span: sp,
80 invalid: "<>".into(),
81 correct: "!=".into(),
82 },
83 });
84 self.bump();
85 }
86 }
87
88 pub(super) fn recover_from_spaceship_cmp_op(&mut self) {
90 if let (token::Le, token::Gt) = (self.prev_token.kind, self.token.kind)
91 && self.prev_token.span.hi() == self.token.span.lo()
92 {
93 let sp = self.prev_token.span.to(self.token.span);
94 self.dcx().emit_err(diagnostics::InvalidComparisonOperator {
95 span: sp,
96 invalid: "<=>".into(),
97 sub: diagnostics::InvalidComparisonOperatorSub::Spaceship(sp),
98 });
99 self.bump();
100 }
101 }
102
103 pub(super) fn recover_from_postfix_inc_op(
105 &mut self,
106 lhs: &Expr,
107 starts_stmt: bool,
108 ) -> PResult<'a, ()> {
109 if let (token::Plus, token::Plus) = (self.prev_token.kind, self.token.kind)
110 && self.prev_token.span.hi() == self.token.span.lo()
111 {
112 let op_span = self.prev_token.span.to(self.token.span);
113 self.bump(); Err(self.report_inc_dec_op(lhs, starts_stmt, IncOrDec::Inc, UnaryFixity::Post, op_span))
115 } else {
116 Ok(())
117 }
118 }
119
120 pub(super) fn recover_from_postfix_dec_op(
122 &mut self,
123 lhs: &Expr,
124 starts_stmt: bool,
125 ) -> PResult<'a, ()> {
126 if let (token::Minus, token::Minus) = (self.prev_token.kind, self.token.kind)
127 && self.prev_token.span.hi() == self.token.span.lo()
128 && !self.look_ahead(1, |tok| tok.can_begin_expr())
129 {
130 let op_span = self.prev_token.span.to(self.token.span);
131 self.bump(); Err(self.report_inc_dec_op(lhs, starts_stmt, IncOrDec::Dec, UnaryFixity::Post, op_span))
133 } else {
134 Ok(())
135 }
136 }
137
138 pub(super) fn report_inc_dec_op(
140 &mut self,
141 base: &Expr,
142 starts_stmt: bool,
143 op: IncOrDec,
144 fixity: UnaryFixity,
145 op_span: Span,
146 ) -> Diag<'a> {
147 let mut err = {
154 let fixity = match fixity {
155 UnaryFixity::Pre => "prefix",
156 UnaryFixity::Post => "postfix",
157 };
158 let op = match op {
159 IncOrDec::Inc => "increment",
160 IncOrDec::Dec => "decrement",
161 };
162 self.dcx()
163 .struct_span_err(op_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Rust has no {0} {1} operator",
fixity, op))
})format!("Rust has no {fixity} {op} operator"))
164 .with_span_label(op_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("not a valid {0} operator", fixity))
})format!("not a valid {fixity} operator"))
165 };
166
167 let op = match op {
168 IncOrDec::Inc => "+= 1",
169 IncOrDec::Dec => "-= 1",
170 };
171 let (pre_span, post_span) = match fixity {
172 UnaryFixity::Pre => (op_span, base.span.shrink_to_hi()),
173 UnaryFixity::Post => (base.span.shrink_to_lo(), op_span),
174 };
175
176 if starts_stmt {
177 let mut patches = Vec::new();
178 if !pre_span.is_empty() {
179 patches.push((pre_span, String::new()));
180 }
181 patches.push((post_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0}", op))
})format!(" {op}")));
182 err.multipart_suggestion(
183 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use `{0}` instead", op))
})format!("use `{op}` instead"),
184 patches,
185 Applicability::MachineApplicable,
186 );
187 } else {
188 let Ok(base_src) = self.span_to_snippet(base.span) else {
189 err.help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use `{0}` instead", op))
})format!("use `{op}` instead"));
190 return err;
191 };
192 match fixity {
193 UnaryFixity::Pre => {
194 err.multipart_suggestion(
195 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use `{0}` instead", op))
})format!("use `{op}` instead"),
196 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(pre_span, "{ ".into()),
(post_span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0}; {1} }}", op,
base_src))
}))]))vec![(pre_span, "{ ".into()), (post_span, format!(" {op}; {base_src} }}"))],
197 Applicability::MachineApplicable,
198 );
199 }
200 UnaryFixity::Post => {
201 if !#[allow(non_exhaustive_omitted_patterns)] match base.kind {
ExprKind::Binary(..) => true,
_ => false,
}matches!(base.kind, ExprKind::Binary(..)) {
204 let tmp_var = if base_src.trim() == "tmp" { "tmp_" } else { "tmp" };
205 err.multipart_suggestion(
206 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use `{0}` instead", op))
})format!("use `{op}` instead"),
207 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(pre_span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{ let {0} = ", tmp_var))
})),
(post_span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("; {0} {1}; {2} }}",
base_src, op, tmp_var))
}))]))vec![
208 (pre_span, format!("{{ let {tmp_var} = ")),
209 (post_span, format!("; {base_src} {op}; {tmp_var} }}")),
210 ],
211 Applicability::HasPlaceholders,
212 );
213 }
214 }
215 }
216 }
217 err
218 }
219
220 pub(super) fn recover_from_c_array(&mut self, lo: Span) -> Option<Box<Expr>> {
222 if !self.may_recover()
223 || self.token.kind != token::OpenBrace
224 || self.look_ahead(1, |t| !#[allow(non_exhaustive_omitted_patterns)] match t.kind {
token::Literal(_) => true,
_ => false,
}matches!(t.kind, token::Literal(_)))
225 || self.look_ahead(2, |t| t != &token::Comma)
226 || self.look_ahead(3, |t| !t.can_begin_expr())
227 {
228 return None;
229 }
230
231 let mut snapshot = self.create_snapshot_for_diagnostic();
232 match snapshot.parse_expr_array_or_repeat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)) {
233 Ok(arr) => {
234 let guar = self.dcx().emit_err(diagnostics::ArrayBracketsInsteadOfBraces {
235 span: arr.span,
236 sub: diagnostics::ArrayBracketsInsteadOfBracesSugg {
237 left: lo,
238 right: snapshot.prev_token.span,
239 },
240 });
241
242 self.restore_snapshot(snapshot);
243 Some(self.mk_expr_err(arr.span, guar))
244 }
245 Err(e) => {
246 e.cancel();
247 None
248 }
249 }
250 }
251}
252
253#[derive(#[automatically_derived]
impl ::core::marker::Copy for IncOrDec { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for IncOrDec { }
#[automatically_derived]
impl ::core::clone::Clone for IncOrDec {
#[inline]
fn clone(&self) -> Self { *self }
}Clone)]
254pub(super) enum IncOrDec {
255 Inc,
256 Dec,
257}
258
259#[derive(#[automatically_derived]
impl ::core::marker::Copy for UnaryFixity { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for UnaryFixity { }
#[automatically_derived]
impl ::core::clone::Clone for UnaryFixity {
#[inline]
fn clone(&self) -> Self { *self }
}Clone)]
260pub(super) enum UnaryFixity {
261 Pre,
262 Post,
263}