Skip to content

Commit b3124e5

Browse files
committed
Insert necessary parentheses in ToTokens for Expr
1 parent 1b6a450 commit b3124e5

File tree

7 files changed

+990
-101
lines changed

7 files changed

+990
-101
lines changed

src/classify.rs

Lines changed: 192 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,19 @@ 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")]
67
use proc_macro2::{Delimiter, TokenStream, TokenTree};
78
use std::ops::ControlFlow;
89

9-
#[cfg(feature = "parsing")]
10+
#[cfg(feature = "full")]
1011
pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool {
1112
match expr {
1213
Expr::Macro(expr) => !expr.mac.delimiter.is_brace(),
1314
_ => requires_comma_to_be_match_arm(expr),
1415
}
1516
}
1617

18+
#[cfg(feature = "full")]
1719
pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool {
1820
match expr {
1921
Expr::If(_)
@@ -58,7 +60,196 @@ pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool {
5860
}
5961
}
6062

63+
#[cfg(all(feature = "printing", feature = "full"))]
64+
pub(crate) fn confusable_with_adjacent_block(mut expr: &Expr) -> bool {
65+
let mut stack = Vec::new();
66+
67+
while let Some(next) = match expr {
68+
Expr::Assign(e) => {
69+
stack.push(&e.right);
70+
Some(&e.left)
71+
}
72+
Expr::Await(e) => Some(&e.base),
73+
Expr::Binary(e) => {
74+
stack.push(&e.right);
75+
Some(&e.left)
76+
}
77+
Expr::Break(e) => {
78+
if let Some(Expr::Block(_)) = e.expr.as_deref() {
79+
return true;
80+
}
81+
stack.pop()
82+
}
83+
Expr::Call(e) => Some(&e.func),
84+
Expr::Cast(e) => Some(&e.expr),
85+
Expr::Closure(e) => Some(&e.body),
86+
Expr::Field(e) => Some(&e.base),
87+
Expr::Index(e) => Some(&e.expr),
88+
Expr::Let(e) => Some(&e.expr),
89+
Expr::MethodCall(e) => Some(&e.receiver),
90+
Expr::Range(e) => {
91+
if let Some(Expr::Block(_)) = e.end.as_deref() {
92+
return true;
93+
}
94+
match (&e.start, &e.end) {
95+
(Some(start), end) => {
96+
stack.extend(end);
97+
Some(start)
98+
}
99+
(None, Some(end)) => Some(end),
100+
(None, None) => stack.pop(),
101+
}
102+
}
103+
Expr::Reference(e) => Some(&e.expr),
104+
Expr::Return(e) => {
105+
if e.expr.is_none() && stack.is_empty() {
106+
return true;
107+
}
108+
stack.pop()
109+
}
110+
Expr::Struct(_) => return true,
111+
Expr::Try(e) => Some(&e.expr),
112+
Expr::Unary(e) => Some(&e.expr),
113+
Expr::Yield(e) => {
114+
if e.expr.is_none() && stack.is_empty() {
115+
return true;
116+
}
117+
stack.pop()
118+
}
119+
120+
Expr::Array(_)
121+
| Expr::Async(_)
122+
| Expr::Block(_)
123+
| Expr::Const(_)
124+
| Expr::Continue(_)
125+
| Expr::ForLoop(_)
126+
| Expr::Group(_)
127+
| Expr::If(_)
128+
| Expr::Infer(_)
129+
| Expr::Lit(_)
130+
| Expr::Loop(_)
131+
| Expr::Macro(_)
132+
| Expr::Match(_)
133+
| Expr::Paren(_)
134+
| Expr::Path(_)
135+
| Expr::Repeat(_)
136+
| Expr::TryBlock(_)
137+
| Expr::Tuple(_)
138+
| Expr::Unsafe(_)
139+
| Expr::Verbatim(_)
140+
| Expr::While(_) => stack.pop(),
141+
} {
142+
expr = next;
143+
}
144+
145+
false
146+
}
147+
148+
#[cfg(feature = "printing")]
149+
pub(crate) fn confusable_with_trailing_lt(mut expr: &Expr) -> bool {
150+
loop {
151+
match expr {
152+
Expr::Binary(e) => expr = &e.right,
153+
Expr::Cast(e) => return type_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 type_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+
},
216+
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+
}
227+
}
228+
}
229+
230+
fn last_type_in_path(path: &Path) -> ControlFlow<bool, &Type> {
231+
match &path.segments.last().unwrap().arguments {
232+
PathArguments::None => ControlFlow::Break(true),
233+
PathArguments::AngleBracketed(_) => ControlFlow::Break(false),
234+
PathArguments::Parenthesized(arg) => match &arg.output {
235+
ReturnType::Default => ControlFlow::Break(false),
236+
ReturnType::Type(_, ret) => ControlFlow::Continue(ret),
237+
},
238+
}
239+
}
240+
241+
fn last_type_in_bounds(
242+
bounds: &Punctuated<TypeParamBound, Token![+]>,
243+
) -> ControlFlow<bool, &Type> {
244+
match bounds.last().unwrap() {
245+
TypeParamBound::Trait(t) => last_type_in_path(&t.path),
246+
TypeParamBound::Lifetime(_) | TypeParamBound::Verbatim(_) => ControlFlow::Break(false),
247+
}
248+
}
249+
}
250+
61251
/// Whether the expression's last token is `}`.
252+
#[cfg(feature = "full")]
62253
pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool {
63254
loop {
64255
match expr {

0 commit comments

Comments
 (0)