1#[cfg(feature = "full")]
2use crate::expr::Expr;
3#[cfg(any(feature = "printing", feature = "full"))]
4use crate::generics::TypeParamBound;
5#[cfg(any(feature = "printing", feature = "full"))]
6use crate::path::{Path, PathArguments};
7#[cfg(any(feature = "printing", feature = "full"))]
8use crate::punctuated::Punctuated;
9#[cfg(any(feature = "printing", feature = "full"))]
10use crate::ty::{ReturnType, Type};
11#[cfg(feature = "full")]
12use proc_macro2::{Delimiter, TokenStream, TokenTree};
13#[cfg(any(feature = "printing", feature = "full"))]
14use std::ops::ControlFlow;
15
16#[cfg(feature = "full")]
17pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool {
18 match expr {
19 Expr::Macro(expr) => !expr.mac.delimiter.is_brace(),
20 _ => requires_comma_to_be_match_arm(expr),
21 }
22}
23
24#[cfg(feature = "full")]
25pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool {
26 match expr {
27 Expr::If(_)
28 | Expr::Match(_)
29 | Expr::Block(_) | Expr::Unsafe(_) | Expr::While(_)
31 | Expr::Loop(_)
32 | Expr::ForLoop(_)
33 | Expr::TryBlock(_)
34 | Expr::Const(_) => false,
35
36 Expr::Array(_)
37 | Expr::Assign(_)
38 | Expr::Async(_)
39 | Expr::Await(_)
40 | Expr::Binary(_)
41 | Expr::Break(_)
42 | Expr::Call(_)
43 | Expr::Cast(_)
44 | Expr::Closure(_)
45 | Expr::Continue(_)
46 | Expr::Field(_)
47 | Expr::Group(_)
48 | Expr::Index(_)
49 | Expr::Infer(_)
50 | Expr::Let(_)
51 | Expr::Lit(_)
52 | Expr::Macro(_)
53 | Expr::MethodCall(_)
54 | Expr::Paren(_)
55 | Expr::Path(_)
56 | Expr::Range(_)
57 | Expr::RawAddr(_)
58 | Expr::Reference(_)
59 | Expr::Repeat(_)
60 | Expr::Return(_)
61 | Expr::Struct(_)
62 | Expr::Try(_)
63 | Expr::Tuple(_)
64 | Expr::Unary(_)
65 | Expr::Yield(_)
66 | Expr::Verbatim(_) => true,
67 }
68}
69
70#[cfg(feature = "printing")]
71pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool {
72 loop {
73 match ty {
74 Type::BareFn(t) => match &t.output {
75 ReturnType::Default => return false,
76 ReturnType::Type(_, ret) => ty = ret,
77 },
78 Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
79 ControlFlow::Break(trailing_path) => return trailing_path,
80 ControlFlow::Continue(t) => ty = t,
81 },
82 Type::Path(t) => match last_type_in_path(&t.path) {
83 ControlFlow::Break(trailing_path) => return trailing_path,
84 ControlFlow::Continue(t) => ty = t,
85 },
86 Type::Ptr(t) => ty = &t.elem,
87 Type::Reference(t) => ty = &t.elem,
88 Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
89 ControlFlow::Break(trailing_path) => return trailing_path,
90 ControlFlow::Continue(t) => ty = t,
91 },
92
93 Type::Array(_)
94 | Type::Group(_)
95 | Type::Infer(_)
96 | Type::Macro(_)
97 | Type::Never(_)
98 | Type::Paren(_)
99 | Type::Slice(_)
100 | Type::Tuple(_)
101 | Type::Verbatim(_) => return false,
102 }
103 }
104
105 fn last_type_in_path(path: &Path) -> ControlFlow<bool, &Type> {
106 match &path.segments.last().unwrap().arguments {
107 PathArguments::None => ControlFlow::Break(true),
108 PathArguments::AngleBracketed(_) => ControlFlow::Break(false),
109 PathArguments::Parenthesized(arg) => match &arg.output {
110 ReturnType::Default => ControlFlow::Break(false),
111 ReturnType::Type(_, ret) => ControlFlow::Continue(ret),
112 },
113 }
114 }
115
116 fn last_type_in_bounds(
117 bounds: &Punctuated<TypeParamBound, Token![+]>,
118 ) -> ControlFlow<bool, &Type> {
119 match bounds.last().unwrap() {
120 TypeParamBound::Trait(t) => last_type_in_path(&t.path),
121 TypeParamBound::Lifetime(_)
122 | TypeParamBound::PreciseCapture(_)
123 | TypeParamBound::Verbatim(_) => ControlFlow::Break(false),
124 }
125 }
126}
127
128#[cfg(all(feature = "printing", feature = "full"))]
130pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool {
131 loop {
132 match expr {
133 Expr::Block(e) => return e.label.is_some(),
134 Expr::ForLoop(e) => return e.label.is_some(),
135 Expr::Loop(e) => return e.label.is_some(),
136 Expr::While(e) => return e.label.is_some(),
137
138 Expr::Assign(e) => expr = &e.left,
139 Expr::Await(e) => expr = &e.base,
140 Expr::Binary(e) => expr = &e.left,
141 Expr::Call(e) => expr = &e.func,
142 Expr::Cast(e) => expr = &e.expr,
143 Expr::Field(e) => expr = &e.base,
144 Expr::Index(e) => expr = &e.expr,
145 Expr::MethodCall(e) => expr = &e.receiver,
146 Expr::Range(e) => match &e.start {
147 Some(start) => expr = start,
148 None => return false,
149 },
150 Expr::Try(e) => expr = &e.expr,
151
152 Expr::Array(_)
153 | Expr::Async(_)
154 | Expr::Break(_)
155 | Expr::Closure(_)
156 | Expr::Const(_)
157 | Expr::Continue(_)
158 | Expr::Group(_)
159 | Expr::If(_)
160 | Expr::Infer(_)
161 | Expr::Let(_)
162 | Expr::Lit(_)
163 | Expr::Macro(_)
164 | Expr::Match(_)
165 | Expr::Paren(_)
166 | Expr::Path(_)
167 | Expr::RawAddr(_)
168 | Expr::Reference(_)
169 | Expr::Repeat(_)
170 | Expr::Return(_)
171 | Expr::Struct(_)
172 | Expr::TryBlock(_)
173 | Expr::Tuple(_)
174 | Expr::Unary(_)
175 | Expr::Unsafe(_)
176 | Expr::Verbatim(_)
177 | Expr::Yield(_) => return false,
178 }
179 }
180}
181
182#[cfg(feature = "full")]
184pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool {
185 loop {
186 match expr {
187 Expr::Async(_)
188 | Expr::Block(_)
189 | Expr::Const(_)
190 | Expr::ForLoop(_)
191 | Expr::If(_)
192 | Expr::Loop(_)
193 | Expr::Match(_)
194 | Expr::Struct(_)
195 | Expr::TryBlock(_)
196 | Expr::Unsafe(_)
197 | Expr::While(_) => return true,
198
199 Expr::Assign(e) => expr = &e.right,
200 Expr::Binary(e) => expr = &e.right,
201 Expr::Break(e) => match &e.expr {
202 Some(e) => expr = e,
203 None => return false,
204 },
205 Expr::Cast(e) => return type_trailing_brace(&e.ty),
206 Expr::Closure(e) => expr = &e.body,
207 Expr::Let(e) => expr = &e.expr,
208 Expr::Macro(e) => return e.mac.delimiter.is_brace(),
209 Expr::Range(e) => match &e.end {
210 Some(end) => expr = end,
211 None => return false,
212 },
213 Expr::RawAddr(e) => expr = &e.expr,
214 Expr::Reference(e) => expr = &e.expr,
215 Expr::Return(e) => match &e.expr {
216 Some(e) => expr = e,
217 None => return false,
218 },
219 Expr::Unary(e) => expr = &e.expr,
220 Expr::Verbatim(e) => return tokens_trailing_brace(e),
221 Expr::Yield(e) => match &e.expr {
222 Some(e) => expr = e,
223 None => return false,
224 },
225
226 Expr::Array(_)
227 | Expr::Await(_)
228 | Expr::Call(_)
229 | Expr::Continue(_)
230 | Expr::Field(_)
231 | Expr::Group(_)
232 | Expr::Index(_)
233 | Expr::Infer(_)
234 | Expr::Lit(_)
235 | Expr::MethodCall(_)
236 | Expr::Paren(_)
237 | Expr::Path(_)
238 | Expr::Repeat(_)
239 | Expr::Try(_)
240 | Expr::Tuple(_) => return false,
241 }
242 }
243
244 fn type_trailing_brace(mut ty: &Type) -> bool {
245 loop {
246 match ty {
247 Type::BareFn(t) => match &t.output {
248 ReturnType::Default => return false,
249 ReturnType::Type(_, ret) => ty = ret,
250 },
251 Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
252 ControlFlow::Break(trailing_brace) => return trailing_brace,
253 ControlFlow::Continue(t) => ty = t,
254 },
255 Type::Macro(t) => return t.mac.delimiter.is_brace(),
256 Type::Path(t) => match last_type_in_path(&t.path) {
257 Some(t) => ty = t,
258 None => return false,
259 },
260 Type::Ptr(t) => ty = &t.elem,
261 Type::Reference(t) => ty = &t.elem,
262 Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
263 ControlFlow::Break(trailing_brace) => return trailing_brace,
264 ControlFlow::Continue(t) => ty = t,
265 },
266 Type::Verbatim(t) => return tokens_trailing_brace(t),
267
268 Type::Array(_)
269 | Type::Group(_)
270 | Type::Infer(_)
271 | Type::Never(_)
272 | Type::Paren(_)
273 | Type::Slice(_)
274 | Type::Tuple(_) => return false,
275 }
276 }
277 }
278
279 fn last_type_in_path(path: &Path) -> Option<&Type> {
280 match &path.segments.last().unwrap().arguments {
281 PathArguments::None | PathArguments::AngleBracketed(_) => None,
282 PathArguments::Parenthesized(arg) => match &arg.output {
283 ReturnType::Default => None,
284 ReturnType::Type(_, ret) => Some(ret),
285 },
286 }
287 }
288
289 fn last_type_in_bounds(
290 bounds: &Punctuated<TypeParamBound, Token![+]>,
291 ) -> ControlFlow<bool, &Type> {
292 match bounds.last().unwrap() {
293 TypeParamBound::Trait(t) => match last_type_in_path(&t.path) {
294 Some(t) => ControlFlow::Continue(t),
295 None => ControlFlow::Break(false),
296 },
297 TypeParamBound::Lifetime(_) | TypeParamBound::PreciseCapture(_) => {
298 ControlFlow::Break(false)
299 }
300 TypeParamBound::Verbatim(t) => ControlFlow::Break(tokens_trailing_brace(t)),
301 }
302 }
303
304 fn tokens_trailing_brace(tokens: &TokenStream) -> bool {
305 if let Some(TokenTree::Group(last)) = tokens.clone().into_iter().last() {
306 last.delimiter() == Delimiter::Brace
307 } else {
308 false
309 }
310 }
311}