1*69942c0aSMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT
2*69942c0aSMiguel Ojeda
3808c999fSMiguel Ojeda #[cfg(feature = "full")]
4808c999fSMiguel Ojeda use crate::expr::Expr;
5808c999fSMiguel Ojeda #[cfg(any(feature = "printing", feature = "full"))]
6808c999fSMiguel Ojeda use crate::generics::TypeParamBound;
7808c999fSMiguel Ojeda #[cfg(any(feature = "printing", feature = "full"))]
8808c999fSMiguel Ojeda use crate::path::{Path, PathArguments};
9808c999fSMiguel Ojeda #[cfg(any(feature = "printing", feature = "full"))]
10808c999fSMiguel Ojeda use crate::punctuated::Punctuated;
11808c999fSMiguel Ojeda #[cfg(any(feature = "printing", feature = "full"))]
12808c999fSMiguel Ojeda use crate::ty::{ReturnType, Type};
13808c999fSMiguel Ojeda #[cfg(feature = "full")]
14808c999fSMiguel Ojeda use proc_macro2::{Delimiter, TokenStream, TokenTree};
15808c999fSMiguel Ojeda #[cfg(any(feature = "printing", feature = "full"))]
16808c999fSMiguel Ojeda use std::ops::ControlFlow;
17808c999fSMiguel Ojeda
18808c999fSMiguel Ojeda #[cfg(feature = "full")]
requires_semi_to_be_stmt(expr: &Expr) -> bool19808c999fSMiguel Ojeda pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool {
20808c999fSMiguel Ojeda match expr {
21808c999fSMiguel Ojeda Expr::Macro(expr) => !expr.mac.delimiter.is_brace(),
22808c999fSMiguel Ojeda _ => requires_comma_to_be_match_arm(expr),
23808c999fSMiguel Ojeda }
24808c999fSMiguel Ojeda }
25808c999fSMiguel Ojeda
26808c999fSMiguel Ojeda #[cfg(feature = "full")]
requires_comma_to_be_match_arm(expr: &Expr) -> bool27808c999fSMiguel Ojeda pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool {
28808c999fSMiguel Ojeda match expr {
29808c999fSMiguel Ojeda Expr::If(_)
30808c999fSMiguel Ojeda | Expr::Match(_)
31808c999fSMiguel Ojeda | Expr::Block(_) | Expr::Unsafe(_) // both under ExprKind::Block in rustc
32808c999fSMiguel Ojeda | Expr::While(_)
33808c999fSMiguel Ojeda | Expr::Loop(_)
34808c999fSMiguel Ojeda | Expr::ForLoop(_)
35808c999fSMiguel Ojeda | Expr::TryBlock(_)
36808c999fSMiguel Ojeda | Expr::Const(_) => false,
37808c999fSMiguel Ojeda
38808c999fSMiguel Ojeda Expr::Array(_)
39808c999fSMiguel Ojeda | Expr::Assign(_)
40808c999fSMiguel Ojeda | Expr::Async(_)
41808c999fSMiguel Ojeda | Expr::Await(_)
42808c999fSMiguel Ojeda | Expr::Binary(_)
43808c999fSMiguel Ojeda | Expr::Break(_)
44808c999fSMiguel Ojeda | Expr::Call(_)
45808c999fSMiguel Ojeda | Expr::Cast(_)
46808c999fSMiguel Ojeda | Expr::Closure(_)
47808c999fSMiguel Ojeda | Expr::Continue(_)
48808c999fSMiguel Ojeda | Expr::Field(_)
49808c999fSMiguel Ojeda | Expr::Group(_)
50808c999fSMiguel Ojeda | Expr::Index(_)
51808c999fSMiguel Ojeda | Expr::Infer(_)
52808c999fSMiguel Ojeda | Expr::Let(_)
53808c999fSMiguel Ojeda | Expr::Lit(_)
54808c999fSMiguel Ojeda | Expr::Macro(_)
55808c999fSMiguel Ojeda | Expr::MethodCall(_)
56808c999fSMiguel Ojeda | Expr::Paren(_)
57808c999fSMiguel Ojeda | Expr::Path(_)
58808c999fSMiguel Ojeda | Expr::Range(_)
59808c999fSMiguel Ojeda | Expr::RawAddr(_)
60808c999fSMiguel Ojeda | Expr::Reference(_)
61808c999fSMiguel Ojeda | Expr::Repeat(_)
62808c999fSMiguel Ojeda | Expr::Return(_)
63808c999fSMiguel Ojeda | Expr::Struct(_)
64808c999fSMiguel Ojeda | Expr::Try(_)
65808c999fSMiguel Ojeda | Expr::Tuple(_)
66808c999fSMiguel Ojeda | Expr::Unary(_)
67808c999fSMiguel Ojeda | Expr::Yield(_)
68808c999fSMiguel Ojeda | Expr::Verbatim(_) => true,
69808c999fSMiguel Ojeda }
70808c999fSMiguel Ojeda }
71808c999fSMiguel Ojeda
72808c999fSMiguel Ojeda #[cfg(feature = "printing")]
trailing_unparameterized_path(mut ty: &Type) -> bool73808c999fSMiguel Ojeda pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool {
74808c999fSMiguel Ojeda loop {
75808c999fSMiguel Ojeda match ty {
76808c999fSMiguel Ojeda Type::BareFn(t) => match &t.output {
77808c999fSMiguel Ojeda ReturnType::Default => return false,
78808c999fSMiguel Ojeda ReturnType::Type(_, ret) => ty = ret,
79808c999fSMiguel Ojeda },
80808c999fSMiguel Ojeda Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
81808c999fSMiguel Ojeda ControlFlow::Break(trailing_path) => return trailing_path,
82808c999fSMiguel Ojeda ControlFlow::Continue(t) => ty = t,
83808c999fSMiguel Ojeda },
84808c999fSMiguel Ojeda Type::Path(t) => match last_type_in_path(&t.path) {
85808c999fSMiguel Ojeda ControlFlow::Break(trailing_path) => return trailing_path,
86808c999fSMiguel Ojeda ControlFlow::Continue(t) => ty = t,
87808c999fSMiguel Ojeda },
88808c999fSMiguel Ojeda Type::Ptr(t) => ty = &t.elem,
89808c999fSMiguel Ojeda Type::Reference(t) => ty = &t.elem,
90808c999fSMiguel Ojeda Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
91808c999fSMiguel Ojeda ControlFlow::Break(trailing_path) => return trailing_path,
92808c999fSMiguel Ojeda ControlFlow::Continue(t) => ty = t,
93808c999fSMiguel Ojeda },
94808c999fSMiguel Ojeda
95808c999fSMiguel Ojeda Type::Array(_)
96808c999fSMiguel Ojeda | Type::Group(_)
97808c999fSMiguel Ojeda | Type::Infer(_)
98808c999fSMiguel Ojeda | Type::Macro(_)
99808c999fSMiguel Ojeda | Type::Never(_)
100808c999fSMiguel Ojeda | Type::Paren(_)
101808c999fSMiguel Ojeda | Type::Slice(_)
102808c999fSMiguel Ojeda | Type::Tuple(_)
103808c999fSMiguel Ojeda | Type::Verbatim(_) => return false,
104808c999fSMiguel Ojeda }
105808c999fSMiguel Ojeda }
106808c999fSMiguel Ojeda
107808c999fSMiguel Ojeda fn last_type_in_path(path: &Path) -> ControlFlow<bool, &Type> {
108808c999fSMiguel Ojeda match &path.segments.last().unwrap().arguments {
109808c999fSMiguel Ojeda PathArguments::None => ControlFlow::Break(true),
110808c999fSMiguel Ojeda PathArguments::AngleBracketed(_) => ControlFlow::Break(false),
111808c999fSMiguel Ojeda PathArguments::Parenthesized(arg) => match &arg.output {
112808c999fSMiguel Ojeda ReturnType::Default => ControlFlow::Break(false),
113808c999fSMiguel Ojeda ReturnType::Type(_, ret) => ControlFlow::Continue(ret),
114808c999fSMiguel Ojeda },
115808c999fSMiguel Ojeda }
116808c999fSMiguel Ojeda }
117808c999fSMiguel Ojeda
118808c999fSMiguel Ojeda fn last_type_in_bounds(
119808c999fSMiguel Ojeda bounds: &Punctuated<TypeParamBound, Token![+]>,
120808c999fSMiguel Ojeda ) -> ControlFlow<bool, &Type> {
121808c999fSMiguel Ojeda match bounds.last().unwrap() {
122808c999fSMiguel Ojeda TypeParamBound::Trait(t) => last_type_in_path(&t.path),
123808c999fSMiguel Ojeda TypeParamBound::Lifetime(_)
124808c999fSMiguel Ojeda | TypeParamBound::PreciseCapture(_)
125808c999fSMiguel Ojeda | TypeParamBound::Verbatim(_) => ControlFlow::Break(false),
126808c999fSMiguel Ojeda }
127808c999fSMiguel Ojeda }
128808c999fSMiguel Ojeda }
129808c999fSMiguel Ojeda
130808c999fSMiguel Ojeda /// Whether the expression's first token is the label of a loop/block.
131808c999fSMiguel Ojeda #[cfg(all(feature = "printing", feature = "full"))]
expr_leading_label(mut expr: &Expr) -> bool132808c999fSMiguel Ojeda pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool {
133808c999fSMiguel Ojeda loop {
134808c999fSMiguel Ojeda match expr {
135808c999fSMiguel Ojeda Expr::Block(e) => return e.label.is_some(),
136808c999fSMiguel Ojeda Expr::ForLoop(e) => return e.label.is_some(),
137808c999fSMiguel Ojeda Expr::Loop(e) => return e.label.is_some(),
138808c999fSMiguel Ojeda Expr::While(e) => return e.label.is_some(),
139808c999fSMiguel Ojeda
140808c999fSMiguel Ojeda Expr::Assign(e) => expr = &e.left,
141808c999fSMiguel Ojeda Expr::Await(e) => expr = &e.base,
142808c999fSMiguel Ojeda Expr::Binary(e) => expr = &e.left,
143808c999fSMiguel Ojeda Expr::Call(e) => expr = &e.func,
144808c999fSMiguel Ojeda Expr::Cast(e) => expr = &e.expr,
145808c999fSMiguel Ojeda Expr::Field(e) => expr = &e.base,
146808c999fSMiguel Ojeda Expr::Index(e) => expr = &e.expr,
147808c999fSMiguel Ojeda Expr::MethodCall(e) => expr = &e.receiver,
148808c999fSMiguel Ojeda Expr::Range(e) => match &e.start {
149808c999fSMiguel Ojeda Some(start) => expr = start,
150808c999fSMiguel Ojeda None => return false,
151808c999fSMiguel Ojeda },
152808c999fSMiguel Ojeda Expr::Try(e) => expr = &e.expr,
153808c999fSMiguel Ojeda
154808c999fSMiguel Ojeda Expr::Array(_)
155808c999fSMiguel Ojeda | Expr::Async(_)
156808c999fSMiguel Ojeda | Expr::Break(_)
157808c999fSMiguel Ojeda | Expr::Closure(_)
158808c999fSMiguel Ojeda | Expr::Const(_)
159808c999fSMiguel Ojeda | Expr::Continue(_)
160808c999fSMiguel Ojeda | Expr::Group(_)
161808c999fSMiguel Ojeda | Expr::If(_)
162808c999fSMiguel Ojeda | Expr::Infer(_)
163808c999fSMiguel Ojeda | Expr::Let(_)
164808c999fSMiguel Ojeda | Expr::Lit(_)
165808c999fSMiguel Ojeda | Expr::Macro(_)
166808c999fSMiguel Ojeda | Expr::Match(_)
167808c999fSMiguel Ojeda | Expr::Paren(_)
168808c999fSMiguel Ojeda | Expr::Path(_)
169808c999fSMiguel Ojeda | Expr::RawAddr(_)
170808c999fSMiguel Ojeda | Expr::Reference(_)
171808c999fSMiguel Ojeda | Expr::Repeat(_)
172808c999fSMiguel Ojeda | Expr::Return(_)
173808c999fSMiguel Ojeda | Expr::Struct(_)
174808c999fSMiguel Ojeda | Expr::TryBlock(_)
175808c999fSMiguel Ojeda | Expr::Tuple(_)
176808c999fSMiguel Ojeda | Expr::Unary(_)
177808c999fSMiguel Ojeda | Expr::Unsafe(_)
178808c999fSMiguel Ojeda | Expr::Verbatim(_)
179808c999fSMiguel Ojeda | Expr::Yield(_) => return false,
180808c999fSMiguel Ojeda }
181808c999fSMiguel Ojeda }
182808c999fSMiguel Ojeda }
183808c999fSMiguel Ojeda
184808c999fSMiguel Ojeda /// Whether the expression's last token is `}`.
185808c999fSMiguel Ojeda #[cfg(feature = "full")]
expr_trailing_brace(mut expr: &Expr) -> bool186808c999fSMiguel Ojeda pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool {
187808c999fSMiguel Ojeda loop {
188808c999fSMiguel Ojeda match expr {
189808c999fSMiguel Ojeda Expr::Async(_)
190808c999fSMiguel Ojeda | Expr::Block(_)
191808c999fSMiguel Ojeda | Expr::Const(_)
192808c999fSMiguel Ojeda | Expr::ForLoop(_)
193808c999fSMiguel Ojeda | Expr::If(_)
194808c999fSMiguel Ojeda | Expr::Loop(_)
195808c999fSMiguel Ojeda | Expr::Match(_)
196808c999fSMiguel Ojeda | Expr::Struct(_)
197808c999fSMiguel Ojeda | Expr::TryBlock(_)
198808c999fSMiguel Ojeda | Expr::Unsafe(_)
199808c999fSMiguel Ojeda | Expr::While(_) => return true,
200808c999fSMiguel Ojeda
201808c999fSMiguel Ojeda Expr::Assign(e) => expr = &e.right,
202808c999fSMiguel Ojeda Expr::Binary(e) => expr = &e.right,
203808c999fSMiguel Ojeda Expr::Break(e) => match &e.expr {
204808c999fSMiguel Ojeda Some(e) => expr = e,
205808c999fSMiguel Ojeda None => return false,
206808c999fSMiguel Ojeda },
207808c999fSMiguel Ojeda Expr::Cast(e) => return type_trailing_brace(&e.ty),
208808c999fSMiguel Ojeda Expr::Closure(e) => expr = &e.body,
209808c999fSMiguel Ojeda Expr::Let(e) => expr = &e.expr,
210808c999fSMiguel Ojeda Expr::Macro(e) => return e.mac.delimiter.is_brace(),
211808c999fSMiguel Ojeda Expr::Range(e) => match &e.end {
212808c999fSMiguel Ojeda Some(end) => expr = end,
213808c999fSMiguel Ojeda None => return false,
214808c999fSMiguel Ojeda },
215808c999fSMiguel Ojeda Expr::RawAddr(e) => expr = &e.expr,
216808c999fSMiguel Ojeda Expr::Reference(e) => expr = &e.expr,
217808c999fSMiguel Ojeda Expr::Return(e) => match &e.expr {
218808c999fSMiguel Ojeda Some(e) => expr = e,
219808c999fSMiguel Ojeda None => return false,
220808c999fSMiguel Ojeda },
221808c999fSMiguel Ojeda Expr::Unary(e) => expr = &e.expr,
222808c999fSMiguel Ojeda Expr::Verbatim(e) => return tokens_trailing_brace(e),
223808c999fSMiguel Ojeda Expr::Yield(e) => match &e.expr {
224808c999fSMiguel Ojeda Some(e) => expr = e,
225808c999fSMiguel Ojeda None => return false,
226808c999fSMiguel Ojeda },
227808c999fSMiguel Ojeda
228808c999fSMiguel Ojeda Expr::Array(_)
229808c999fSMiguel Ojeda | Expr::Await(_)
230808c999fSMiguel Ojeda | Expr::Call(_)
231808c999fSMiguel Ojeda | Expr::Continue(_)
232808c999fSMiguel Ojeda | Expr::Field(_)
233808c999fSMiguel Ojeda | Expr::Group(_)
234808c999fSMiguel Ojeda | Expr::Index(_)
235808c999fSMiguel Ojeda | Expr::Infer(_)
236808c999fSMiguel Ojeda | Expr::Lit(_)
237808c999fSMiguel Ojeda | Expr::MethodCall(_)
238808c999fSMiguel Ojeda | Expr::Paren(_)
239808c999fSMiguel Ojeda | Expr::Path(_)
240808c999fSMiguel Ojeda | Expr::Repeat(_)
241808c999fSMiguel Ojeda | Expr::Try(_)
242808c999fSMiguel Ojeda | Expr::Tuple(_) => return false,
243808c999fSMiguel Ojeda }
244808c999fSMiguel Ojeda }
245808c999fSMiguel Ojeda
246808c999fSMiguel Ojeda fn type_trailing_brace(mut ty: &Type) -> bool {
247808c999fSMiguel Ojeda loop {
248808c999fSMiguel Ojeda match ty {
249808c999fSMiguel Ojeda Type::BareFn(t) => match &t.output {
250808c999fSMiguel Ojeda ReturnType::Default => return false,
251808c999fSMiguel Ojeda ReturnType::Type(_, ret) => ty = ret,
252808c999fSMiguel Ojeda },
253808c999fSMiguel Ojeda Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
254808c999fSMiguel Ojeda ControlFlow::Break(trailing_brace) => return trailing_brace,
255808c999fSMiguel Ojeda ControlFlow::Continue(t) => ty = t,
256808c999fSMiguel Ojeda },
257808c999fSMiguel Ojeda Type::Macro(t) => return t.mac.delimiter.is_brace(),
258808c999fSMiguel Ojeda Type::Path(t) => match last_type_in_path(&t.path) {
259808c999fSMiguel Ojeda Some(t) => ty = t,
260808c999fSMiguel Ojeda None => return false,
261808c999fSMiguel Ojeda },
262808c999fSMiguel Ojeda Type::Ptr(t) => ty = &t.elem,
263808c999fSMiguel Ojeda Type::Reference(t) => ty = &t.elem,
264808c999fSMiguel Ojeda Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
265808c999fSMiguel Ojeda ControlFlow::Break(trailing_brace) => return trailing_brace,
266808c999fSMiguel Ojeda ControlFlow::Continue(t) => ty = t,
267808c999fSMiguel Ojeda },
268808c999fSMiguel Ojeda Type::Verbatim(t) => return tokens_trailing_brace(t),
269808c999fSMiguel Ojeda
270808c999fSMiguel Ojeda Type::Array(_)
271808c999fSMiguel Ojeda | Type::Group(_)
272808c999fSMiguel Ojeda | Type::Infer(_)
273808c999fSMiguel Ojeda | Type::Never(_)
274808c999fSMiguel Ojeda | Type::Paren(_)
275808c999fSMiguel Ojeda | Type::Slice(_)
276808c999fSMiguel Ojeda | Type::Tuple(_) => return false,
277808c999fSMiguel Ojeda }
278808c999fSMiguel Ojeda }
279808c999fSMiguel Ojeda }
280808c999fSMiguel Ojeda
281808c999fSMiguel Ojeda fn last_type_in_path(path: &Path) -> Option<&Type> {
282808c999fSMiguel Ojeda match &path.segments.last().unwrap().arguments {
283808c999fSMiguel Ojeda PathArguments::None | PathArguments::AngleBracketed(_) => None,
284808c999fSMiguel Ojeda PathArguments::Parenthesized(arg) => match &arg.output {
285808c999fSMiguel Ojeda ReturnType::Default => None,
286808c999fSMiguel Ojeda ReturnType::Type(_, ret) => Some(ret),
287808c999fSMiguel Ojeda },
288808c999fSMiguel Ojeda }
289808c999fSMiguel Ojeda }
290808c999fSMiguel Ojeda
291808c999fSMiguel Ojeda fn last_type_in_bounds(
292808c999fSMiguel Ojeda bounds: &Punctuated<TypeParamBound, Token![+]>,
293808c999fSMiguel Ojeda ) -> ControlFlow<bool, &Type> {
294808c999fSMiguel Ojeda match bounds.last().unwrap() {
295808c999fSMiguel Ojeda TypeParamBound::Trait(t) => match last_type_in_path(&t.path) {
296808c999fSMiguel Ojeda Some(t) => ControlFlow::Continue(t),
297808c999fSMiguel Ojeda None => ControlFlow::Break(false),
298808c999fSMiguel Ojeda },
299808c999fSMiguel Ojeda TypeParamBound::Lifetime(_) | TypeParamBound::PreciseCapture(_) => {
300808c999fSMiguel Ojeda ControlFlow::Break(false)
301808c999fSMiguel Ojeda }
302808c999fSMiguel Ojeda TypeParamBound::Verbatim(t) => ControlFlow::Break(tokens_trailing_brace(t)),
303808c999fSMiguel Ojeda }
304808c999fSMiguel Ojeda }
305808c999fSMiguel Ojeda
306808c999fSMiguel Ojeda fn tokens_trailing_brace(tokens: &TokenStream) -> bool {
307808c999fSMiguel Ojeda if let Some(TokenTree::Group(last)) = tokens.clone().into_iter().last() {
308808c999fSMiguel Ojeda last.delimiter() == Delimiter::Brace
309808c999fSMiguel Ojeda } else {
310808c999fSMiguel Ojeda false
311808c999fSMiguel Ojeda }
312808c999fSMiguel Ojeda }
313808c999fSMiguel Ojeda }
314