Skip to content

Commit 3df1b60

Browse files
committed
Add parsing for shared type aliases
1 parent ae43dd5 commit 3df1b60

File tree

2 files changed

+53
-30
lines changed

2 files changed

+53
-30
lines changed

syntax/file.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use quote::quote;
33
use syn::parse::{Error, Parse, ParseStream, Result};
44
use syn::{
55
braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemStruct,
6-
ItemUse, LitStr, Token, Visibility,
6+
ItemType, ItemUse, LitStr, Token, Visibility,
77
};
88

99
pub struct Module {
@@ -20,6 +20,7 @@ pub struct Module {
2020
pub enum Item {
2121
Struct(ItemStruct),
2222
Enum(ItemEnum),
23+
Type(ItemType),
2324
ForeignMod(ItemForeignMod),
2425
Use(ItemUse),
2526
Other(RustItem),
@@ -92,6 +93,7 @@ impl Parse for Item {
9293
match item {
9394
RustItem::Struct(item) => Ok(Item::Struct(ItemStruct { attrs, ..item })),
9495
RustItem::Enum(item) => Ok(Item::Enum(ItemEnum { attrs, ..item })),
96+
RustItem::Type(item) => Ok(Item::Type(ItemType { attrs, ..item })),
9597
RustItem::ForeignMod(item) => Ok(Item::ForeignMod(ItemForeignMod {
9698
attrs: item.attrs,
9799
unsafety,

syntax/parse.rs

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use syn::parse::{ParseStream, Parser};
1212
use syn::punctuated::Punctuated;
1313
use syn::{
1414
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,
1717
};
1818

1919
pub mod kw {
@@ -32,6 +32,10 @@ pub fn parse_items(cx: &mut Errors, items: Vec<Item>, trusted: bool) -> Vec<Api>
3232
Ok(enm) => apis.push(enm),
3333
Err(err) => cx.push(err),
3434
},
35+
Item::Type(item) => match parse_alias(cx, item, AliasKind::Shared) {
36+
Ok(alias) => apis.push(alias),
37+
Err(err) => cx.push(err),
38+
},
3539
Item::ForeignMod(foreign_mod) => parse_foreign_mod(cx, foreign_mod, &mut apis, trusted),
3640
Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
3741
Item::Other(item) => cx.error(item, "unsupported item"),
@@ -170,6 +174,33 @@ fn parse_enum(cx: &mut Errors, item: ItemEnum) -> Result<Api> {
170174
}))
171175
}
172176

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+
173204
fn parse_foreign_mod(
174205
cx: &mut Errors,
175206
foreign_mod: ItemForeignMod,
@@ -383,37 +414,27 @@ fn parse_extern_fn(cx: &mut Errors, foreign_fn: &ForeignItemFn, lang: Lang) -> R
383414

384415
fn parse_extern_verbatim(cx: &mut Errors, tokens: &TokenStream, lang: Lang) -> Result<Api> {
385416
// 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()
410431
};
411432

412-
let type_alias = parse.parse2(tokens.clone())?;
433+
let item = parse.parse2(tokens.clone())?;
413434
match lang {
414-
Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
435+
Lang::Cxx => parse_alias(cx, item, AliasKind::OpaqueCpp),
415436
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);
417438
let span = quote!(#type_token #semi_token);
418439
let msg = "type alias in extern \"Rust\" block is not supported";
419440
Err(Error::new_spanned(span, msg))

0 commit comments

Comments
 (0)