@@ -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