@@ -81,8 +81,17 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
81
81
}
82
82
}
83
83
84
+ pub enum TrailingBrace < ' a > {
85
+ /// Trailing brace in a macro call, like the one in `x as *const brace! {}`.
86
+ /// We will suggest changing the macro call to a different delimiter.
87
+ MacCall ( & ' a ast:: MacCall ) ,
88
+ /// Trailing brace in any other expression, such as `a + B {}`. We will
89
+ /// suggest wrapping the innermost expression in parentheses: `a + (B {})`.
90
+ Expr ( & ' a ast:: Expr ) ,
91
+ }
92
+
84
93
/// If an expression ends with `}`, returns the innermost expression ending in the `}`
85
- pub fn expr_trailing_brace ( mut expr : & ast:: Expr ) -> Option < & ast :: Expr > {
94
+ pub fn expr_trailing_brace ( mut expr : & ast:: Expr ) -> Option < TrailingBrace < ' _ > > {
86
95
loop {
87
96
match & expr. kind {
88
97
AddrOf ( _, _, e)
@@ -111,10 +120,14 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
111
120
| Struct ( ..)
112
121
| TryBlock ( ..)
113
122
| While ( ..)
114
- | ConstBlock ( _) => break Some ( expr) ,
123
+ | ConstBlock ( _) => break Some ( TrailingBrace :: Expr ( expr) ) ,
124
+
125
+ Cast ( _, ty) => {
126
+ break type_trailing_braced_mac_call ( ty) . map ( TrailingBrace :: MacCall ) ;
127
+ }
115
128
116
129
MacCall ( mac) => {
117
- break ( mac. args . delim == Delimiter :: Brace ) . then_some ( expr ) ;
130
+ break ( mac. args . delim == Delimiter :: Brace ) . then_some ( TrailingBrace :: MacCall ( mac ) ) ;
118
131
}
119
132
120
133
InlineAsm ( _) | OffsetOf ( _, _) | IncludedBytes ( _) | FormatArgs ( _) => {
@@ -131,7 +144,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
131
144
| MethodCall ( _)
132
145
| Tup ( _)
133
146
| Lit ( _)
134
- | Cast ( _, _)
135
147
| Type ( _, _)
136
148
| Await ( _, _)
137
149
| Field ( _, _)
@@ -148,3 +160,78 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
148
160
}
149
161
}
150
162
}
163
+
164
+ /// If the type's last token is `}`, it must be due to a braced macro call, such
165
+ /// as in `*const brace! { ... }`. Returns that trailing macro call.
166
+ fn type_trailing_braced_mac_call ( mut ty : & ast:: Ty ) -> Option < & ast:: MacCall > {
167
+ loop {
168
+ match & ty. kind {
169
+ ast:: TyKind :: MacCall ( mac) => {
170
+ break ( mac. args . delim == Delimiter :: Brace ) . then_some ( mac) ;
171
+ }
172
+
173
+ ast:: TyKind :: Ptr ( mut_ty) | ast:: TyKind :: Ref ( _, mut_ty) => {
174
+ ty = & mut_ty. ty ;
175
+ }
176
+
177
+ ast:: TyKind :: BareFn ( fn_ty) => match & fn_ty. decl . output {
178
+ ast:: FnRetTy :: Default ( _) => break None ,
179
+ ast:: FnRetTy :: Ty ( ret) => ty = ret,
180
+ } ,
181
+
182
+ ast:: TyKind :: Path ( _, path) => match path_return_type ( path) {
183
+ Some ( trailing_ty) => ty = trailing_ty,
184
+ None => break None ,
185
+ } ,
186
+
187
+ ast:: TyKind :: TraitObject ( bounds, _) | ast:: TyKind :: ImplTrait ( _, bounds, _) => {
188
+ match bounds. last ( ) {
189
+ Some ( ast:: GenericBound :: Trait ( bound, _) ) => {
190
+ match path_return_type ( & bound. trait_ref . path ) {
191
+ Some ( trailing_ty) => ty = trailing_ty,
192
+ None => break None ,
193
+ }
194
+ }
195
+ Some ( ast:: GenericBound :: Outlives ( _) ) | None => break None ,
196
+ }
197
+ }
198
+
199
+ ast:: TyKind :: Slice ( ..)
200
+ | ast:: TyKind :: Array ( ..)
201
+ | ast:: TyKind :: Never
202
+ | ast:: TyKind :: Tup ( ..)
203
+ | ast:: TyKind :: Paren ( ..)
204
+ | ast:: TyKind :: Typeof ( ..)
205
+ | ast:: TyKind :: Infer
206
+ | ast:: TyKind :: ImplicitSelf
207
+ | ast:: TyKind :: CVarArgs
208
+ | ast:: TyKind :: Pat ( ..)
209
+ | ast:: TyKind :: Dummy
210
+ | ast:: TyKind :: Err ( ..) => break None ,
211
+
212
+ // These end in brace, but cannot occur in a let-else statement.
213
+ // They are only parsed as fields of a data structure. For the
214
+ // purpose of denying trailing braces in the expression of a
215
+ // let-else, we can disregard these.
216
+ ast:: TyKind :: AnonStruct ( ..) | ast:: TyKind :: AnonUnion ( ..) => break None ,
217
+ }
218
+ }
219
+ }
220
+
221
+ /// Returns the trailing return type in the given path, if it has one.
222
+ ///
223
+ /// ```ignore (illustrative)
224
+ /// ::std::ops::FnOnce(&str) -> fn() -> *const c_void
225
+ /// ^^^^^^^^^^^^^^^^^^^^^
226
+ /// ```
227
+ fn path_return_type ( path : & ast:: Path ) -> Option < & ast:: Ty > {
228
+ let last_segment = path. segments . last ( ) ?;
229
+ let args = last_segment. args . as_ref ( ) ?;
230
+ match & * * args {
231
+ ast:: GenericArgs :: Parenthesized ( args) => match & args. output {
232
+ ast:: FnRetTy :: Default ( _) => None ,
233
+ ast:: FnRetTy :: Ty ( ret) => Some ( ret) ,
234
+ } ,
235
+ ast:: GenericArgs :: AngleBracketed ( _) => None ,
236
+ }
237
+ }
0 commit comments