@@ -12,8 +12,8 @@ use syn::parse::{ParseStream, Parser};
12
12
use syn:: punctuated:: Punctuated ;
13
13
use syn:: {
14
14
Abi , Attribute , Error , Fields , FnArg , ForeignItem , ForeignItemFn , ForeignItemType ,
15
- GenericArgument , Ident , ItemEnum , ItemStruct , LitStr , Pat , PathArguments , Result , ReturnType ,
16
- Token , Type as RustType , TypeBareFn , TypePath , TypeReference , TypeSlice ,
15
+ GenericArgument , Ident , ItemEnum , ItemStruct , ItemType , LitStr , Pat , PathArguments , Result ,
16
+ ReturnType , Token , Type as RustType , TypeBareFn , TypePath , TypeReference , TypeSlice ,
17
17
} ;
18
18
19
19
pub mod kw {
@@ -32,6 +32,10 @@ pub fn parse_items(cx: &mut Errors, items: Vec<Item>, trusted: bool) -> Vec<Api>
32
32
Ok ( enm) => apis. push ( enm) ,
33
33
Err ( err) => cx. push ( err) ,
34
34
} ,
35
+ Item :: Type ( item) => match parse_alias ( cx, item, AliasKind :: Shared ) {
36
+ Ok ( alias) => apis. push ( alias) ,
37
+ Err ( err) => cx. push ( err) ,
38
+ } ,
35
39
Item :: ForeignMod ( foreign_mod) => parse_foreign_mod ( cx, foreign_mod, & mut apis, trusted) ,
36
40
Item :: Use ( item) => cx. error ( item, error:: USE_NOT_ALLOWED ) ,
37
41
Item :: Other ( item) => cx. error ( item, "unsupported item" ) ,
@@ -170,6 +174,33 @@ fn parse_enum(cx: &mut Errors, item: ItemEnum) -> Result<Api> {
170
174
} ) )
171
175
}
172
176
177
+ fn parse_alias ( cx : & mut Errors , item : ItemType , kind : AliasKind ) -> Result < Api > {
178
+ let generics = & item. generics ;
179
+ if !generics. params . is_empty ( ) || generics. where_clause . is_some ( ) {
180
+ // TODO: Add ui test for this
181
+ let type_token = item. type_token ;
182
+ let ident = & item. ident ;
183
+ let where_clause = & generics. where_clause ;
184
+ let span = quote ! ( #type_token #ident #generics #where_clause) ;
185
+ return Err ( Error :: new_spanned (
186
+ span,
187
+ "aliases with generic parameters are not allowed" ,
188
+ ) ) ;
189
+ }
190
+
191
+ let doc = attrs:: parse_doc ( cx, & item. attrs ) ;
192
+
193
+ Ok ( Api :: TypeAlias ( TypeAlias {
194
+ kind,
195
+ doc,
196
+ type_token : item. type_token ,
197
+ ident : item. ident ,
198
+ eq_token : item. eq_token ,
199
+ ty : * item. ty ,
200
+ semi_token : item. semi_token ,
201
+ } ) )
202
+ }
203
+
173
204
fn parse_foreign_mod (
174
205
cx : & mut Errors ,
175
206
foreign_mod : ItemForeignMod ,
@@ -383,37 +414,27 @@ fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> R
383
414
384
415
fn parse_extern_verbatim ( cx : & mut Errors , tokens : & TokenStream , lang : Lang ) -> Result < Api > {
385
416
// type Alias = crate::path::to::Type;
386
- let parse = |input : ParseStream | -> Result < TypeAlias > {
387
- let attrs = input. call ( Attribute :: parse_outer) ?;
388
- let type_token: Token ! [ type ] = match input. parse ( ) ? {
389
- Some ( type_token) => type_token,
390
- None => {
391
- let span = input. cursor ( ) . token_stream ( ) ;
392
- return Err ( Error :: new_spanned ( span, "unsupported foreign item" ) ) ;
393
- }
394
- } ;
395
- let ident: Ident = input. parse ( ) ?;
396
- let eq_token: Token ! [ =] = input. parse ( ) ?;
397
- let ty: RustType = input. parse ( ) ?;
398
- let semi_token: Token ! [ ; ] = input. parse ( ) ?;
399
- let doc = attrs:: parse_doc ( cx, & attrs) ;
400
-
401
- Ok ( TypeAlias {
402
- kind : AliasKind :: OpaqueCpp ,
403
- doc,
404
- type_token,
405
- ident,
406
- eq_token,
407
- ty,
408
- semi_token,
409
- } )
417
+ let parse = |input : ParseStream | -> Result < ItemType > {
418
+ // Test whether this is a type alias. This ends up parsing attributes twice but lets us emit
419
+ // more useful errors that differentiate between an unsupported item and other alias parsing
420
+ // errors.
421
+ // TODO: Add ui test to verify this
422
+ let fork = input. fork ( ) ;
423
+ fork. call ( Attribute :: parse_outer) ?;
424
+ fork. parse :: < Token ! [ type ] > ( ) . map_err ( |_| {
425
+ let span = fork. cursor ( ) . token_stream ( ) ;
426
+ Error :: new_spanned ( span, "unsupported foreign item" )
427
+ } ) ?;
428
+
429
+ // Reuse alias parsing from syn
430
+ input. parse ( )
410
431
} ;
411
432
412
- let type_alias = parse. parse2 ( tokens. clone ( ) ) ?;
433
+ let item = parse. parse2 ( tokens. clone ( ) ) ?;
413
434
match lang {
414
- Lang :: Cxx => Ok ( Api :: TypeAlias ( type_alias ) ) ,
435
+ Lang :: Cxx => parse_alias ( cx , item , AliasKind :: OpaqueCpp ) ,
415
436
Lang :: Rust => {
416
- let ( type_token, semi_token) = ( type_alias . type_token , type_alias . semi_token ) ;
437
+ let ( type_token, semi_token) = ( item . type_token , item . semi_token ) ;
417
438
let span = quote ! ( #type_token #semi_token) ;
418
439
let msg = "type alias in extern \" Rust\" block is not supported" ;
419
440
Err ( Error :: new_spanned ( span, msg) )
0 commit comments