Skip to content

Commit 9809f71

Browse files
committed
Incorporate parenthesization of casts into FixupContext
1 parent ff022f5 commit 9809f71

File tree

5 files changed

+99
-132
lines changed

5 files changed

+99
-132
lines changed

src/classify.rs

Lines changed: 31 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,16 @@ use crate::generics::TypeParamBound;
33
use crate::path::{Path, PathArguments};
44
use crate::punctuated::Punctuated;
55
use crate::ty::{ReturnType, Type};
6-
#[cfg(feature = "full")]
76
use proc_macro2::{Delimiter, TokenStream, TokenTree};
87
use std::ops::ControlFlow;
98

10-
#[cfg(feature = "full")]
119
pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool {
1210
match expr {
1311
Expr::Macro(expr) => !expr.mac.delimiter.is_brace(),
1412
_ => requires_comma_to_be_match_arm(expr),
1513
}
1614
}
1715

18-
#[cfg(feature = "full")]
1916
pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool {
2017
match expr {
2118
Expr::If(_)
@@ -60,7 +57,7 @@ pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool {
6057
}
6158
}
6259

63-
#[cfg(all(feature = "printing", feature = "full"))]
60+
#[cfg(feature = "printing")]
6461
pub(crate) fn confusable_with_adjacent_block(mut expr: &Expr) -> bool {
6562
let mut stack = Vec::new();
6663

@@ -146,84 +143,37 @@ pub(crate) fn confusable_with_adjacent_block(mut expr: &Expr) -> bool {
146143
}
147144

148145
#[cfg(feature = "printing")]
149-
pub(crate) fn confusable_with_adjacent_lt(mut expr: &Expr) -> bool {
146+
pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool {
150147
loop {
151-
match expr {
152-
Expr::Binary(e) => expr = &e.right,
153-
Expr::Cast(e) => return trailing_unparameterized_path(&e.ty),
154-
Expr::Reference(e) => expr = &e.expr,
155-
Expr::Unary(e) => expr = &e.expr,
156-
157-
Expr::Array(_)
158-
| Expr::Assign(_)
159-
| Expr::Async(_)
160-
| Expr::Await(_)
161-
| Expr::Block(_)
162-
| Expr::Break(_)
163-
| Expr::Call(_)
164-
| Expr::Closure(_)
165-
| Expr::Const(_)
166-
| Expr::Continue(_)
167-
| Expr::Field(_)
168-
| Expr::ForLoop(_)
169-
| Expr::Group(_)
170-
| Expr::If(_)
171-
| Expr::Index(_)
172-
| Expr::Infer(_)
173-
| Expr::Let(_)
174-
| Expr::Lit(_)
175-
| Expr::Loop(_)
176-
| Expr::Macro(_)
177-
| Expr::Match(_)
178-
| Expr::MethodCall(_)
179-
| Expr::Paren(_)
180-
| Expr::Path(_)
181-
| Expr::Range(_)
182-
| Expr::Repeat(_)
183-
| Expr::Return(_)
184-
| Expr::Struct(_)
185-
| Expr::Try(_)
186-
| Expr::TryBlock(_)
187-
| Expr::Tuple(_)
188-
| Expr::Unsafe(_)
189-
| Expr::Verbatim(_)
190-
| Expr::While(_)
191-
| Expr::Yield(_) => return false,
192-
}
193-
}
194-
195-
fn trailing_unparameterized_path(mut ty: &Type) -> bool {
196-
loop {
197-
match ty {
198-
Type::BareFn(t) => match &t.output {
199-
ReturnType::Default => return false,
200-
ReturnType::Type(_, ret) => ty = ret,
201-
},
202-
Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
203-
ControlFlow::Break(trailing_path) => return trailing_path,
204-
ControlFlow::Continue(t) => ty = t,
205-
},
206-
Type::Path(t) => match last_type_in_path(&t.path) {
207-
ControlFlow::Break(trailing_path) => return trailing_path,
208-
ControlFlow::Continue(t) => ty = t,
209-
},
210-
Type::Ptr(t) => ty = &t.elem,
211-
Type::Reference(t) => ty = &t.elem,
212-
Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
213-
ControlFlow::Break(trailing_path) => return trailing_path,
214-
ControlFlow::Continue(t) => ty = t,
215-
},
148+
match ty {
149+
Type::BareFn(t) => match &t.output {
150+
ReturnType::Default => return false,
151+
ReturnType::Type(_, ret) => ty = ret,
152+
},
153+
Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
154+
ControlFlow::Break(trailing_path) => return trailing_path,
155+
ControlFlow::Continue(t) => ty = t,
156+
},
157+
Type::Path(t) => match last_type_in_path(&t.path) {
158+
ControlFlow::Break(trailing_path) => return trailing_path,
159+
ControlFlow::Continue(t) => ty = t,
160+
},
161+
Type::Ptr(t) => ty = &t.elem,
162+
Type::Reference(t) => ty = &t.elem,
163+
Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
164+
ControlFlow::Break(trailing_path) => return trailing_path,
165+
ControlFlow::Continue(t) => ty = t,
166+
},
216167

217-
Type::Array(_)
218-
| Type::Group(_)
219-
| Type::Infer(_)
220-
| Type::Macro(_)
221-
| Type::Never(_)
222-
| Type::Paren(_)
223-
| Type::Slice(_)
224-
| Type::Tuple(_)
225-
| Type::Verbatim(_) => return false,
226-
}
168+
Type::Array(_)
169+
| Type::Group(_)
170+
| Type::Infer(_)
171+
| Type::Macro(_)
172+
| Type::Never(_)
173+
| Type::Paren(_)
174+
| Type::Slice(_)
175+
| Type::Tuple(_)
176+
| Type::Verbatim(_) => return false,
227177
}
228178
}
229179

@@ -249,7 +199,7 @@ pub(crate) fn confusable_with_adjacent_lt(mut expr: &Expr) -> bool {
249199
}
250200

251201
/// Whether the expression's first token is the label of a loop/block.
252-
#[cfg(all(feature = "printing", feature = "full"))]
202+
#[cfg(feature = "printing")]
253203
pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool {
254204
loop {
255205
match expr {
@@ -302,7 +252,6 @@ pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool {
302252
}
303253

304254
/// Whether the expression's last token is `}`.
305-
#[cfg(feature = "full")]
306255
pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool {
307256
loop {
308257
match expr {

src/expr.rs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2981,6 +2981,7 @@ pub(crate) mod printing {
29812981
use crate::attr::Attribute;
29822982
#[cfg(feature = "full")]
29832983
use crate::attr::FilterAttrs;
2984+
#[cfg(feature = "full")]
29842985
use crate::classify;
29852986
#[cfg(feature = "full")]
29862987
use crate::expr::{
@@ -2996,6 +2997,7 @@ pub(crate) mod printing {
29962997
};
29972998
#[cfg(feature = "full")]
29982999
use crate::fixup::FixupContext;
3000+
#[cfg(feature = "full")]
29993001
use crate::op::BinOp;
30003002
use crate::path;
30013003
use crate::precedence::Precedence;
@@ -3222,17 +3224,23 @@ pub(crate) mod printing {
32223224
outer_attrs_to_tokens(&e.attrs, tokens);
32233225

32243226
#[cfg(feature = "full")]
3225-
let left_fixup = fixup.leftmost_subexpression_with_begin_operator(match &e.op {
3226-
BinOp::Sub(_)
3227-
| BinOp::Mul(_)
3228-
| BinOp::And(_)
3229-
| BinOp::Or(_)
3230-
| BinOp::BitAnd(_)
3231-
| BinOp::BitOr(_)
3232-
| BinOp::Shl(_)
3233-
| BinOp::Lt(_) => true,
3234-
_ => false,
3235-
});
3227+
let left_fixup = fixup.leftmost_subexpression_with_begin_operator(
3228+
match &e.op {
3229+
BinOp::Sub(_)
3230+
| BinOp::Mul(_)
3231+
| BinOp::And(_)
3232+
| BinOp::Or(_)
3233+
| BinOp::BitAnd(_)
3234+
| BinOp::BitOr(_)
3235+
| BinOp::Shl(_)
3236+
| BinOp::Lt(_) => true,
3237+
_ => false,
3238+
},
3239+
match &e.op {
3240+
BinOp::Shl(_) | BinOp::Lt(_) => true,
3241+
_ => false,
3242+
},
3243+
);
32363244
let left_prec = leading_precedence(
32373245
&e.left,
32383246
#[cfg(feature = "full")]
@@ -3246,21 +3254,12 @@ pub(crate) mod printing {
32463254
);
32473255

32483256
let binop_prec = Precedence::of_binop(&e.op);
3249-
let (mut left_needs_group, right_needs_group) = match binop_prec {
3257+
let (left_needs_group, right_needs_group) = match binop_prec {
32503258
Precedence::Assign => (left_prec <= Precedence::Range, right_prec < binop_prec),
32513259
Precedence::Compare => (left_prec <= binop_prec, right_prec <= binop_prec),
32523260
_ => (left_prec < binop_prec, right_prec <= binop_prec),
32533261
};
32543262

3255-
// These cases require parenthesization independently of precedence.
3256-
if let BinOp::Lt(_) | BinOp::Shl(_) = &e.op {
3257-
// `x as i32 < y` has the parser thinking that `i32 < y` is the
3258-
// beginning of a path type. It starts trying to parse `x as (i32 <
3259-
// y ...` instead of `(x as i32) < ...`. We need to convince it
3260-
// _not_ to do that.
3261-
left_needs_group |= classify::confusable_with_adjacent_lt(&e.left);
3262-
}
3263-
32643263
print_subexpression(
32653264
&e.left,
32663265
left_needs_group,
@@ -3341,7 +3340,7 @@ pub(crate) mod printing {
33413340
Precedence::Unambiguous
33423341
};
33433342
#[cfg(feature = "full")]
3344-
let func_fixup = fixup.leftmost_subexpression_with_begin_operator(true);
3343+
let func_fixup = fixup.leftmost_subexpression_with_begin_operator(true, false);
33453344
let func_precedence = leading_precedence(
33463345
&e.func,
33473346
#[cfg(feature = "full")]
@@ -3550,7 +3549,7 @@ pub(crate) mod printing {
35503549
) {
35513550
outer_attrs_to_tokens(&e.attrs, tokens);
35523551
#[cfg(feature = "full")]
3553-
let obj_fixup = fixup.leftmost_subexpression_with_begin_operator(true);
3552+
let obj_fixup = fixup.leftmost_subexpression_with_begin_operator(true, false);
35543553
let obj_precedence = leading_precedence(
35553554
&e.expr,
35563555
#[cfg(feature = "full")]

src/fixup.rs

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,15 @@ pub(crate) struct FixupContext {
101101
// let _ = return + 1; // no paren because '+' cannot begin expr
102102
//
103103
next_operator_can_begin_expr: bool,
104+
105+
// This is the difference between:
106+
//
107+
// let _ = x as u8 + T;
108+
//
109+
// let _ = (x as u8) < T;
110+
//
111+
// Without parens, the latter would want to parse `u8<T...` as a type.
112+
next_operator_can_begin_generics: bool,
104113
}
105114

106115
impl FixupContext {
@@ -114,6 +123,7 @@ impl FixupContext {
114123
parenthesize_exterior_struct_lit: false,
115124
parenthesize_exterior_jump: false,
116125
next_operator_can_begin_expr: false,
126+
next_operator_can_begin_generics: false,
117127
};
118128

119129
/// Create the initial fixup for printing an expression in statement
@@ -189,9 +199,11 @@ impl FixupContext {
189199
pub fn leftmost_subexpression_with_begin_operator(
190200
self,
191201
next_operator_can_begin_expr: bool,
202+
next_operator_can_begin_generics: bool,
192203
) -> Self {
193204
FixupContext {
194205
next_operator_can_begin_expr,
206+
next_operator_can_begin_generics,
195207
..self.leftmost_subexpression()
196208
}
197209
}
@@ -245,38 +257,48 @@ impl FixupContext {
245257
/// Determines the effective precedence of a left subexpression. Some
246258
/// expressions have lower precedence when adjacent to particular operators.
247259
pub fn leading_precedence(self, expr: &Expr) -> Precedence {
248-
if self.next_operator_can_begin_expr {
249-
match expr {
250-
// Decrease precedence of value-less jumps when followed by an
251-
// operator that would otherwise get interpreted as beginning a
252-
// value for the jump.
253-
Expr::Break(_) | Expr::Return(_) | Expr::Yield(_) => return Precedence::Jump,
254-
_ => {}
260+
match expr {
261+
// Decrease precedence of value-less jumps when followed by an
262+
// operator that would otherwise get interpreted as beginning a
263+
// value for the jump.
264+
Expr::Break(_) | Expr::Return(_) | Expr::Yield(_)
265+
if self.next_operator_can_begin_expr =>
266+
{
267+
Precedence::Jump
268+
}
269+
Expr::Cast(cast)
270+
if self.next_operator_can_begin_generics
271+
&& classify::trailing_unparameterized_path(&cast.ty) =>
272+
{
273+
Precedence::MIN
255274
}
275+
_ => Precedence::of(expr),
256276
}
257-
Precedence::of(expr)
258277
}
259278

260279
/// Determines the effective precedence of a right subexpression. Some
261280
/// expressions have higher precedence on the right side of a binary
262281
/// operator than on the left.
263282
pub fn trailing_precedence(self, expr: &Expr) -> Precedence {
264-
if !self.parenthesize_exterior_jump {
265-
match expr {
266-
// Increase precedence of expressions that extend to the end of
267-
// current statement or group.
268-
Expr::Break(_)
269-
| Expr::Closure(_)
270-
| Expr::Let(_)
271-
| Expr::Return(_)
272-
| Expr::Yield(_) => {
273-
return Precedence::Prefix;
274-
}
275-
Expr::Range(e) if e.start.is_none() => return Precedence::Prefix,
276-
_ => {}
283+
match expr {
284+
// Increase precedence of expressions that extend to the end of
285+
// current statement or group.
286+
Expr::Break(_) | Expr::Closure(_) | Expr::Let(_) | Expr::Return(_) | Expr::Yield(_)
287+
if !self.parenthesize_exterior_jump =>
288+
{
289+
Precedence::Prefix
290+
}
291+
Expr::Range(e) if e.start.is_none() && !self.parenthesize_exterior_jump => {
292+
Precedence::Prefix
293+
}
294+
Expr::Cast(cast)
295+
if self.next_operator_can_begin_generics
296+
&& classify::trailing_unparameterized_path(&cast.ty) =>
297+
{
298+
Precedence::MIN
277299
}
300+
_ => Precedence::of(expr),
278301
}
279-
Precedence::of(expr)
280302
}
281303
}
282304

src/lib.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,7 @@ mod bigint;
329329
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
330330
pub mod buffer;
331331

332-
#[cfg(any(
333-
all(feature = "parsing", feature = "full"),
334-
all(feature = "printing", any(feature = "full", feature = "derive")),
335-
))]
332+
#[cfg(all(any(feature = "parsing", feature = "printing"), feature = "full"))]
336333
mod classify;
337334

338335
mod custom_keyword;

tests/test_expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ fn test_fixup() {
660660
quote! { 0 + (0 + 0) },
661661
quote! { (a = b) = c },
662662
quote! { (x as i32) < 0 },
663-
quote! { (1 + x as i32) < 0 },
663+
quote! { 1 + (x as i32) < 0 },
664664
quote! { (1 + 1).abs() },
665665
quote! { (lo..hi)[..] },
666666
quote! { (a..b)..(c..d) },

0 commit comments

Comments
 (0)