@@ -81,8 +81,17 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
8181    } 
8282} 
8383
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+ 
8493/// 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 < ' _ > >  { 
8695    loop  { 
8796        match  & expr. kind  { 
8897            AddrOf ( _,  _,  e) 
@@ -111,10 +120,14 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
111120            | Struct ( ..) 
112121            | TryBlock ( ..) 
113122            | 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+             } 
115128
116129            MacCall ( mac)  => { 
117-                 break  ( mac. args . delim  == Delimiter :: Brace ) . then_some ( expr ) ; 
130+                 break  ( mac. args . delim  == Delimiter :: Brace ) . then_some ( TrailingBrace :: MacCall ( mac ) ) ; 
118131            } 
119132
120133            InlineAsm ( _)  | OffsetOf ( _,  _)  | IncludedBytes ( _)  | FormatArgs ( _)  => { 
@@ -131,7 +144,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
131144            | MethodCall ( _) 
132145            | Tup ( _) 
133146            | Lit ( _) 
134-             | Cast ( _,  _) 
135147            | Type ( _,  _) 
136148            | Await ( _,  _) 
137149            | Field ( _,  _) 
@@ -148,3 +160,78 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
148160        } 
149161    } 
150162} 
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