blob: e46cdb4df7ac371ebce60ec2bb7290bd0dbb8c4e [file] [log] [blame]
David Tolnay17e137f2020-05-08 15:55:28 -07001use crate::syntax::discriminant::DiscriminantSet;
David Tolnayc598a272020-08-29 15:10:18 -07002use crate::syntax::file::{Item, ItemForeignMod};
David Tolnay52759782020-05-03 23:59:40 -07003use crate::syntax::report::Errors;
David Tolnayeebe9b72020-04-14 16:32:18 -07004use crate::syntax::Atom::*;
David Tolnay7db73692019-10-20 14:51:12 -04005use crate::syntax::{
Xiangpeng Hao78762352020-11-12 10:24:18 +08006 attrs, error, Api, Array, Doc, Enum, ExternFn, ExternType, Impl, Include, IncludeKind, Lang,
David Tolnaye0dca7b2020-11-25 17:18:57 -08007 Namespace, Pair, Receiver, Ref, ResolvableName, Signature, SliceRef, Struct, Ty1, Type,
8 TypeAlias, Var, Variant,
David Tolnay7db73692019-10-20 14:51:12 -04009};
David Tolnay9a69d8a2020-11-16 09:16:41 -080010use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree};
David Tolnaye2e303f2020-05-10 20:52:00 -070011use quote::{format_ident, quote, quote_spanned};
David Tolnaye2f9ec42020-05-07 16:19:33 -070012use syn::parse::{ParseStream, Parser};
David Tolnaye3a48152020-04-08 19:38:05 -070013use syn::punctuated::Punctuated;
David Tolnay7db73692019-10-20 14:51:12 -040014use syn::{
Xiangpeng Hao78762352020-11-12 10:24:18 +080015 Abi, Attribute, Error, Expr, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
16 GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, Lit, LitStr,
17 Pat, PathArguments, Result, ReturnType, Token, Type as RustType, TypeArray, TypeBareFn,
David Tolnaye0dca7b2020-11-25 17:18:57 -080018 TypePath, TypeReference,
David Tolnay7db73692019-10-20 14:51:12 -040019};
20
David Tolnaye3a48152020-04-08 19:38:05 -070021pub mod kw {
David Tolnayb27f7872020-11-15 15:07:04 -080022 syn::custom_keyword!(Pin);
David Tolnaye3a48152020-04-08 19:38:05 -070023 syn::custom_keyword!(Result);
24}
25
David Tolnayd7a3a182020-11-01 20:45:14 -080026pub fn parse_items(
27 cx: &mut Errors,
28 items: Vec<Item>,
29 trusted: bool,
30 namespace: &Namespace,
31) -> Vec<Api> {
David Tolnay7db73692019-10-20 14:51:12 -040032 let mut apis = Vec::new();
33 for item in items {
34 match item {
David Tolnay302b1752020-11-10 18:43:24 -080035 Item::Struct(item) => match parse_struct(cx, item, namespace) {
David Tolnay52759782020-05-03 23:59:40 -070036 Ok(strct) => apis.push(strct),
37 Err(err) => cx.push(err),
38 },
David Tolnay302b1752020-11-10 18:43:24 -080039 Item::Enum(item) => match parse_enum(cx, item, namespace) {
David Tolnay52759782020-05-03 23:59:40 -070040 Ok(enm) => apis.push(enm),
41 Err(err) => cx.push(err),
42 },
Adrian Taylorc8713432020-10-21 18:20:55 -070043 Item::ForeignMod(foreign_mod) => {
David Tolnayd7a3a182020-11-01 20:45:14 -080044 parse_foreign_mod(cx, foreign_mod, &mut apis, trusted, namespace)
Adrian Taylorc8713432020-10-21 18:20:55 -070045 }
David Tolnay313cc0a2020-11-24 21:47:01 -080046 Item::Impl(item) => match parse_impl(item) {
David Tolnay7e69f892020-10-03 22:20:22 -070047 Ok(imp) => apis.push(imp),
48 Err(err) => cx.push(err),
49 },
David Tolnay52759782020-05-03 23:59:40 -070050 Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
David Tolnay00a83852020-08-29 15:06:16 -070051 Item::Other(item) => cx.error(item, "unsupported item"),
David Tolnay7db73692019-10-20 14:51:12 -040052 }
53 }
David Tolnay52759782020-05-03 23:59:40 -070054 apis
David Tolnay7db73692019-10-20 14:51:12 -040055}
56
David Tolnay302b1752020-11-10 18:43:24 -080057fn parse_struct(cx: &mut Errors, item: ItemStruct, namespace: &Namespace) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -040058 let generics = &item.generics;
59 if !generics.params.is_empty() || generics.where_clause.is_some() {
60 let struct_token = item.struct_token;
61 let ident = &item.ident;
62 let where_clause = &generics.where_clause;
63 let span = quote!(#struct_token #ident #generics #where_clause);
64 return Err(Error::new_spanned(
65 span,
66 "struct with generic parameters is not supported yet",
67 ));
68 }
69
70 let mut doc = Doc::new();
71 let mut derives = Vec::new();
David Tolnay302b1752020-11-10 18:43:24 -080072 let mut namespace = namespace.clone();
David Tolnayb129ea72020-05-10 14:29:30 -070073 attrs::parse(
David Tolnay3e628882020-05-10 15:30:14 -070074 cx,
David Tolnayb129ea72020-05-10 14:29:30 -070075 &item.attrs,
76 attrs::Parser {
77 doc: Some(&mut doc),
78 derives: Some(&mut derives),
David Tolnayd7a3a182020-11-01 20:45:14 -080079 namespace: Some(&mut namespace),
David Tolnayddf69e22020-05-10 22:08:20 -070080 ..Default::default()
David Tolnayb129ea72020-05-10 14:29:30 -070081 },
David Tolnay3e628882020-05-10 15:30:14 -070082 );
David Tolnay09462ac2020-03-20 14:58:41 -070083
David Tolnay302b1752020-11-10 18:43:24 -080084 let named_fields = match item.fields {
David Tolnay09462ac2020-03-20 14:58:41 -070085 Fields::Named(fields) => fields,
86 Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
87 Fields::Unnamed(_) => {
David Tolnay2c4b35f2020-10-04 21:22:30 -070088 return Err(Error::new_spanned(item, "tuple structs are not supported"));
David Tolnay09462ac2020-03-20 14:58:41 -070089 }
90 };
91
David Tolnay38c11212020-11-25 15:50:19 -080092 let mut fields = Vec::new();
93 for field in named_fields.named {
94 let ident = field.ident.unwrap();
95 let ty = match parse_type(&field.ty) {
96 Ok(ty) => ty,
97 Err(err) => {
98 cx.push(err);
99 continue;
100 }
101 };
102 fields.push(Var { ident, ty });
103 }
David Tolnay302b1752020-11-10 18:43:24 -0800104
David Tolnay09462ac2020-03-20 14:58:41 -0700105 Ok(Api::Struct(Struct {
106 doc,
107 derives,
108 struct_token: item.struct_token,
David Tolnay302b1752020-11-10 18:43:24 -0800109 name: Pair::new(namespace, item.ident),
110 brace_token: named_fields.brace_token,
111 fields,
David Tolnay09462ac2020-03-20 14:58:41 -0700112 }))
David Tolnay7db73692019-10-20 14:51:12 -0400113}
114
David Tolnay302b1752020-11-10 18:43:24 -0800115fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Result<Api> {
Joel Galensonc03402a2020-04-23 17:31:09 -0700116 let generics = &item.generics;
117 if !generics.params.is_empty() || generics.where_clause.is_some() {
118 let enum_token = item.enum_token;
119 let ident = &item.ident;
120 let where_clause = &generics.where_clause;
121 let span = quote!(#enum_token #ident #generics #where_clause);
122 return Err(Error::new_spanned(
123 span,
124 "enums with generic parameters are not allowed",
125 ));
126 }
127
David Tolnayddf69e22020-05-10 22:08:20 -0700128 let mut doc = Doc::new();
David Tolnayfbc46692020-11-27 11:33:29 -0800129 let mut derives = Vec::new();
David Tolnayddf69e22020-05-10 22:08:20 -0700130 let mut repr = None;
David Tolnay302b1752020-11-10 18:43:24 -0800131 let mut namespace = namespace.clone();
David Tolnayddf69e22020-05-10 22:08:20 -0700132 attrs::parse(
133 cx,
134 &item.attrs,
135 attrs::Parser {
136 doc: Some(&mut doc),
David Tolnayfbc46692020-11-27 11:33:29 -0800137 derives: Some(&mut derives),
David Tolnayddf69e22020-05-10 22:08:20 -0700138 repr: Some(&mut repr),
David Tolnayd7a3a182020-11-01 20:45:14 -0800139 namespace: Some(&mut namespace),
David Tolnayddf69e22020-05-10 22:08:20 -0700140 ..Default::default()
141 },
142 );
Joel Galensonc03402a2020-04-23 17:31:09 -0700143
Joel Galenson88547732020-05-05 08:23:42 -0700144 let mut variants = Vec::new();
David Tolnayddf69e22020-05-10 22:08:20 -0700145 let mut discriminants = DiscriminantSet::new(repr);
Joel Galenson88547732020-05-05 08:23:42 -0700146 for variant in item.variants {
147 match variant.fields {
Joel Galensonc03402a2020-04-23 17:31:09 -0700148 Fields::Unit => {}
149 _ => {
David Tolnay0435a812020-05-10 21:58:15 -0700150 cx.error(variant, "enums with data are not supported yet");
151 break;
Joel Galensonc03402a2020-04-23 17:31:09 -0700152 }
153 }
David Tolnay17e137f2020-05-08 15:55:28 -0700154 let expr = variant.discriminant.as_ref().map(|(_, expr)| expr);
155 let try_discriminant = match &expr {
156 Some(lit) => discriminants.insert(lit),
157 None => discriminants.insert_next(),
158 };
159 let discriminant = match try_discriminant {
160 Ok(discriminant) => discriminant,
David Tolnay0435a812020-05-10 21:58:15 -0700161 Err(err) => {
162 cx.error(variant, err);
163 break;
164 }
David Tolnay17e137f2020-05-08 15:55:28 -0700165 };
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700166 let expr = variant.discriminant.map(|(_, expr)| expr);
Joel Galenson88547732020-05-05 08:23:42 -0700167 variants.push(Variant {
168 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700169 discriminant,
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700170 expr,
Joel Galenson88547732020-05-05 08:23:42 -0700171 });
Joel Galensonc03402a2020-04-23 17:31:09 -0700172 }
173
David Tolnaye2e303f2020-05-10 20:52:00 -0700174 let enum_token = item.enum_token;
175 let brace_token = item.brace_token;
176
David Tolnay58eee392020-11-20 20:37:58 -0800177 let explicit_repr = repr.is_some();
David Tolnay0435a812020-05-10 21:58:15 -0700178 let mut repr = U8;
179 match discriminants.inferred_repr() {
180 Ok(inferred) => repr = inferred,
David Tolnaye2e303f2020-05-10 20:52:00 -0700181 Err(err) => {
182 let span = quote_spanned!(brace_token.span=> #enum_token {});
David Tolnay0435a812020-05-10 21:58:15 -0700183 cx.error(span, err);
184 variants.clear();
David Tolnaye2e303f2020-05-10 20:52:00 -0700185 }
David Tolnay0435a812020-05-10 21:58:15 -0700186 }
David Tolnaye2e303f2020-05-10 20:52:00 -0700187
David Tolnay9a69d8a2020-11-16 09:16:41 -0800188 let ident = Ident::new(repr.as_ref(), Span::call_site());
189 let repr_type = Type::Ident(ResolvableName::new(ident));
190
Joel Galensonc03402a2020-04-23 17:31:09 -0700191 Ok(Api::Enum(Enum {
192 doc,
David Tolnayfbc46692020-11-27 11:33:29 -0800193 derives,
David Tolnaye2e303f2020-05-10 20:52:00 -0700194 enum_token,
David Tolnay17a934c2020-11-02 00:40:04 -0800195 name: Pair::new(namespace, item.ident),
David Tolnaye2e303f2020-05-10 20:52:00 -0700196 brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700197 variants,
David Tolnaye2e303f2020-05-10 20:52:00 -0700198 repr,
David Tolnay9a69d8a2020-11-16 09:16:41 -0800199 repr_type,
David Tolnay58eee392020-11-20 20:37:58 -0800200 explicit_repr,
Joel Galensonc03402a2020-04-23 17:31:09 -0700201 }))
202}
203
David Tolnay805dca32020-08-29 19:09:55 -0700204fn parse_foreign_mod(
205 cx: &mut Errors,
206 foreign_mod: ItemForeignMod,
207 out: &mut Vec<Api>,
208 trusted: bool,
David Tolnayd7a3a182020-11-01 20:45:14 -0800209 namespace: &Namespace,
David Tolnay805dca32020-08-29 19:09:55 -0700210) {
David Tolnay3a451732020-08-29 18:54:55 -0700211 let lang = match parse_lang(&foreign_mod.abi) {
David Tolnay52759782020-05-03 23:59:40 -0700212 Ok(lang) => lang,
213 Err(err) => return cx.push(err),
214 };
David Tolnay7db73692019-10-20 14:51:12 -0400215
David Tolnay3a451732020-08-29 18:54:55 -0700216 match lang {
217 Lang::Rust => {
David Tolnay805dca32020-08-29 19:09:55 -0700218 if foreign_mod.unsafety.is_some() {
David Tolnay3a451732020-08-29 18:54:55 -0700219 let unsafety = foreign_mod.unsafety;
David Tolnay7be5b1f2020-11-11 10:48:32 -0800220 let abi = &foreign_mod.abi;
David Tolnay3a451732020-08-29 18:54:55 -0700221 let span = quote!(#unsafety #abi);
222 cx.error(span, "extern \"Rust\" block does not need to be unsafe");
223 }
224 }
225 Lang::Cxx => {}
226 }
227
David Tolnay805dca32020-08-29 19:09:55 -0700228 let trusted = trusted || foreign_mod.unsafety.is_some();
229
David Tolnay7feb2642020-11-10 18:49:04 -0800230 let mut namespace = namespace.clone();
231 attrs::parse(
232 cx,
233 &foreign_mod.attrs,
234 attrs::Parser {
235 namespace: Some(&mut namespace),
236 ..Default::default()
237 },
238 );
239
Joel Galensone1e969d2020-04-21 12:50:20 -0700240 let mut items = Vec::new();
241 for foreign in &foreign_mod.items {
242 match foreign {
Adrian Taylorc8713432020-10-21 18:20:55 -0700243 ForeignItem::Type(foreign) => {
David Tolnayf5ead102020-11-24 17:08:05 -0800244 let ety = parse_extern_type(cx, foreign, lang, trusted, &namespace);
245 items.push(ety);
Adrian Taylorc8713432020-10-21 18:20:55 -0700246 }
David Tolnay556738d2020-11-15 13:58:44 -0800247 ForeignItem::Fn(foreign) => {
248 match parse_extern_fn(cx, foreign, lang, trusted, &namespace) {
249 Ok(efn) => items.push(efn),
250 Err(err) => cx.push(err),
251 }
252 }
David Tolnay7db73692019-10-20 14:51:12 -0400253 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay91e87fa2020-05-11 19:10:23 -0700254 match foreign.mac.parse_body_with(parse_include) {
David Tolnay52759782020-05-03 23:59:40 -0700255 Ok(include) => items.push(Api::Include(include)),
256 Err(err) => cx.push(err),
257 }
David Tolnay7db73692019-10-20 14:51:12 -0400258 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700259 ForeignItem::Verbatim(tokens) => {
David Tolnay7feb2642020-11-10 18:49:04 -0800260 match parse_extern_verbatim(cx, tokens, lang, &namespace) {
Adrian Taylorc8713432020-10-21 18:20:55 -0700261 Ok(api) => items.push(api),
262 Err(err) => cx.push(err),
263 }
264 }
David Tolnay52759782020-05-03 23:59:40 -0700265 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400266 }
267 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700268
David Tolnay7be5b1f2020-11-11 10:48:32 -0800269 if !trusted
270 && items.iter().any(|api| match api {
271 Api::CxxFunction(efn) => efn.unsafety.is_none(),
272 _ => false,
273 })
274 {
275 cx.error(
276 foreign_mod.abi,
277 "block must be declared `unsafe extern \"C++\"` if it contains any safe-to-call C++ functions",
278 );
279 }
280
David Tolnaya1f29c42020-04-22 18:01:38 -0700281 let mut types = items.iter().filter_map(|item| match item {
David Tolnay17a934c2020-11-02 00:40:04 -0800282 Api::CxxType(ety) | Api::RustType(ety) => Some(&ety.name),
283 Api::TypeAlias(alias) => Some(&alias.name),
David Tolnaya1f29c42020-04-22 18:01:38 -0700284 _ => None,
285 });
286 if let (Some(single_type), None) = (types.next(), types.next()) {
David Tolnaye5a015a2020-05-07 21:54:26 -0700287 let single_type = single_type.clone();
David Tolnaya1f29c42020-04-22 18:01:38 -0700288 for item in &mut items {
289 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
290 if let Some(receiver) = &mut efn.receiver {
Adrian Taylorc8713432020-10-21 18:20:55 -0700291 if receiver.ty.is_self() {
Adrian Taylor565ddf02020-10-29 21:12:36 -0700292 receiver.ty = ResolvableName::new(single_type.rust.clone());
David Tolnaya1f29c42020-04-22 18:01:38 -0700293 }
294 }
295 }
296 }
297 }
298
David Tolnay52759782020-05-03 23:59:40 -0700299 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400300}
301
David Tolnay3a451732020-08-29 18:54:55 -0700302fn parse_lang(abi: &Abi) -> Result<Lang> {
David Tolnay7db73692019-10-20 14:51:12 -0400303 let name = match &abi.name {
304 Some(name) => name,
305 None => {
306 return Err(Error::new_spanned(
307 abi,
David Tolnayc72a9f62020-11-11 10:56:26 -0800308 "ABI name is required, extern \"C++\" or extern \"Rust\"",
David Tolnay7db73692019-10-20 14:51:12 -0400309 ));
310 }
311 };
312 match name.value().as_str() {
David Tolnayea25ac82020-11-11 10:35:23 -0800313 "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400314 "Rust" => Ok(Lang::Rust),
David Tolnay2757ca82020-11-14 15:12:06 -0800315 _ => Err(Error::new_spanned(
316 abi,
317 "unrecognized ABI, requires either \"C++\" or \"Rust\"",
318 )),
David Tolnay7db73692019-10-20 14:51:12 -0400319 }
320}
321
David Tolnay00f236a2020-08-29 19:07:18 -0700322fn parse_extern_type(
323 cx: &mut Errors,
324 foreign_type: &ForeignItemType,
325 lang: Lang,
326 trusted: bool,
David Tolnay302b1752020-11-10 18:43:24 -0800327 namespace: &Namespace,
David Tolnayf5ead102020-11-24 17:08:05 -0800328) -> Api {
Adrian Taylorc8713432020-10-21 18:20:55 -0700329 let mut doc = Doc::new();
David Tolnay16e26202020-11-27 19:28:37 -0800330 let mut derives = Vec::new();
David Tolnay302b1752020-11-10 18:43:24 -0800331 let mut namespace = namespace.clone();
Adrian Taylorc8713432020-10-21 18:20:55 -0700332 attrs::parse(
333 cx,
334 &foreign_type.attrs,
335 attrs::Parser {
336 doc: Some(&mut doc),
David Tolnay16e26202020-11-27 19:28:37 -0800337 derives: Some(&mut derives),
David Tolnayd7a3a182020-11-01 20:45:14 -0800338 namespace: Some(&mut namespace),
Adrian Taylorc8713432020-10-21 18:20:55 -0700339 ..Default::default()
340 },
341 );
David Tolnay7db73692019-10-20 14:51:12 -0400342 let type_token = foreign_type.type_token;
343 let ident = foreign_type.ident.clone();
David Tolnayc8361022020-08-25 21:57:53 -0700344 let semi_token = foreign_type.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700345 let api_type = match lang {
346 Lang::Cxx => Api::CxxType,
347 Lang::Rust => Api::RustType,
348 };
David Tolnayf5ead102020-11-24 17:08:05 -0800349 api_type(ExternType {
David Tolnay16e26202020-11-27 19:28:37 -0800350 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400351 doc,
David Tolnay16e26202020-11-27 19:28:37 -0800352 derives,
David Tolnay7db73692019-10-20 14:51:12 -0400353 type_token,
David Tolnay17a934c2020-11-02 00:40:04 -0800354 name: Pair::new(namespace, ident),
David Tolnayc8361022020-08-25 21:57:53 -0700355 semi_token,
David Tolnay00f236a2020-08-29 19:07:18 -0700356 trusted,
David Tolnayf5ead102020-11-24 17:08:05 -0800357 })
David Tolnay7db73692019-10-20 14:51:12 -0400358}
359
Adrian Taylorc8713432020-10-21 18:20:55 -0700360fn parse_extern_fn(
361 cx: &mut Errors,
362 foreign_fn: &ForeignItemFn,
363 lang: Lang,
David Tolnay556738d2020-11-15 13:58:44 -0800364 trusted: bool,
David Tolnay302b1752020-11-10 18:43:24 -0800365 namespace: &Namespace,
Adrian Taylorc8713432020-10-21 18:20:55 -0700366) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400367 let generics = &foreign_fn.sig.generics;
David Tolnay9938b642020-11-15 18:11:40 -0800368 if generics.where_clause.is_some()
369 || generics.params.iter().any(|param| match param {
370 GenericParam::Lifetime(lifetime) => !lifetime.bounds.is_empty(),
371 GenericParam::Type(_) | GenericParam::Const(_) => true,
372 })
373 {
David Tolnay7db73692019-10-20 14:51:12 -0400374 return Err(Error::new_spanned(
375 foreign_fn,
376 "extern function with generic parameters is not supported yet",
377 ));
378 }
379 if let Some(variadic) = &foreign_fn.sig.variadic {
380 return Err(Error::new_spanned(
381 variadic,
382 "variadic function is not supported yet",
383 ));
384 }
David Tolnay8de461f2020-11-19 13:46:14 -0800385 if foreign_fn.sig.asyncness.is_some() {
386 return Err(Error::new_spanned(
387 foreign_fn,
388 "async function is not directly supported yet, but see https://cxx.rs/async.html for a working approach",
389 ));
390 }
David Tolnay80ef0682020-11-19 13:56:07 -0800391 if foreign_fn.sig.constness.is_some() {
392 return Err(Error::new_spanned(
393 foreign_fn,
394 "const extern function is not supported",
395 ));
396 }
397 if let Some(abi) = &foreign_fn.sig.abi {
398 return Err(Error::new_spanned(
399 abi,
400 "explicit ABI on extern function is not supported",
401 ));
402 }
David Tolnay7db73692019-10-20 14:51:12 -0400403
David Tolnay938ca852020-10-09 19:25:08 -0700404 let mut doc = Doc::new();
405 let mut cxx_name = None;
406 let mut rust_name = None;
David Tolnay302b1752020-11-10 18:43:24 -0800407 let mut namespace = namespace.clone();
David Tolnay938ca852020-10-09 19:25:08 -0700408 attrs::parse(
409 cx,
410 &foreign_fn.attrs,
411 attrs::Parser {
412 doc: Some(&mut doc),
413 cxx_name: Some(&mut cxx_name),
414 rust_name: Some(&mut rust_name),
David Tolnayd7a3a182020-11-01 20:45:14 -0800415 namespace: Some(&mut namespace),
David Tolnay938ca852020-10-09 19:25:08 -0700416 ..Default::default()
417 },
418 );
419
David Tolnay7db73692019-10-20 14:51:12 -0400420 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700421 let mut args = Punctuated::new();
422 for arg in foreign_fn.sig.inputs.pairs() {
423 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400424 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700425 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700426 if let Some((ampersand, lifetime)) = &arg.reference {
427 receiver = Some(Receiver {
David Tolnay9c76c392020-11-15 16:07:08 -0800428 pinned: false,
David Tolnaya1f29c42020-04-22 18:01:38 -0700429 ampersand: *ampersand,
430 lifetime: lifetime.clone(),
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800431 mutable: arg.mutability.is_some(),
David Tolnaya1f29c42020-04-22 18:01:38 -0700432 var: arg.self_token,
Adrian Taylorc8713432020-10-21 18:20:55 -0700433 ty: ResolvableName::make_self(arg.self_token.span),
David Tolnaya1f29c42020-04-22 18:01:38 -0700434 shorthand: true,
David Tolnay9c76c392020-11-15 16:07:08 -0800435 pin_tokens: None,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800436 mutability: arg.mutability,
David Tolnaya1f29c42020-04-22 18:01:38 -0700437 });
438 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700439 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700440 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400441 }
442 FnArg::Typed(arg) => {
443 let ident = match arg.pat.as_ref() {
444 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700445 Pat::Wild(pat) => {
446 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
447 }
David Tolnay7db73692019-10-20 14:51:12 -0400448 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
449 };
David Tolnay313cc0a2020-11-24 21:47:01 -0800450 let ty = parse_type(&arg.ty)?;
David Tolnay7db73692019-10-20 14:51:12 -0400451 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700452 args.push_value(Var { ident, ty });
453 if let Some(comma) = comma {
454 args.push_punct(*comma);
455 }
David Tolnay7db73692019-10-20 14:51:12 -0400456 continue;
457 }
458 if let Type::Ref(reference) = ty {
459 if let Type::Ident(ident) = reference.inner {
460 receiver = Some(Receiver {
David Tolnay9c76c392020-11-15 16:07:08 -0800461 pinned: reference.pinned,
David Tolnayfb6e3862020-04-20 01:33:23 -0700462 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700463 lifetime: reference.lifetime,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800464 mutable: reference.mutable,
Adrian Taylorc8713432020-10-21 18:20:55 -0700465 var: Token![self](ident.rust.span()),
David Tolnay05e11cc2020-04-20 02:13:56 -0700466 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700467 shorthand: false,
David Tolnay9c76c392020-11-15 16:07:08 -0800468 pin_tokens: reference.pin_tokens,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800469 mutability: reference.mutability,
David Tolnay7db73692019-10-20 14:51:12 -0400470 });
471 continue;
472 }
473 }
474 return Err(Error::new_spanned(arg, "unsupported method receiver"));
475 }
476 }
477 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700478
David Tolnaye3a48152020-04-08 19:38:05 -0700479 let mut throws_tokens = None;
David Tolnay313cc0a2020-11-24 21:47:01 -0800480 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
David Tolnaye3a48152020-04-08 19:38:05 -0700481 let throws = throws_tokens.is_some();
David Tolnaybdb576c2020-09-06 23:45:55 -0700482 let unsafety = foreign_fn.sig.unsafety;
David Tolnay7db73692019-10-20 14:51:12 -0400483 let fn_token = foreign_fn.sig.fn_token;
David Tolnay17a934c2020-11-02 00:40:04 -0800484 let name = Pair::new_from_differing_names(
David Tolnayd7a3a182020-11-01 20:45:14 -0800485 namespace,
Adrian Taylor0f8ab222020-10-29 21:31:56 -0700486 cxx_name.unwrap_or(foreign_fn.sig.ident.clone()),
487 rust_name.unwrap_or(foreign_fn.sig.ident.clone()),
488 );
David Tolnay9938b642020-11-15 18:11:40 -0800489 let generics = generics.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700490 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400491 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700492 let api_function = match lang {
493 Lang::Cxx => Api::CxxFunction,
494 Lang::Rust => Api::RustFunction,
495 };
David Tolnayd95b1192020-03-18 20:07:46 -0700496
David Tolnay295ef6b2020-05-07 16:10:22 -0700497 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700498 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400499 doc,
David Tolnay17a934c2020-11-02 00:40:04 -0800500 name,
David Tolnay16448732020-03-18 12:39:36 -0700501 sig: Signature {
David Tolnaybdb576c2020-09-06 23:45:55 -0700502 unsafety,
David Tolnay16448732020-03-18 12:39:36 -0700503 fn_token,
David Tolnay9938b642020-11-15 18:11:40 -0800504 generics,
David Tolnay16448732020-03-18 12:39:36 -0700505 receiver,
506 args,
507 ret,
508 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700509 paren_token,
510 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700511 },
David Tolnay7db73692019-10-20 14:51:12 -0400512 semi_token,
David Tolnay556738d2020-11-15 13:58:44 -0800513 trusted,
David Tolnay295ef6b2020-05-07 16:10:22 -0700514 }))
David Tolnay7db73692019-10-20 14:51:12 -0400515}
516
Adrian Taylorc8713432020-10-21 18:20:55 -0700517fn parse_extern_verbatim(
518 cx: &mut Errors,
519 tokens: &TokenStream,
520 lang: Lang,
David Tolnay302b1752020-11-10 18:43:24 -0800521 namespace: &Namespace,
Adrian Taylorc8713432020-10-21 18:20:55 -0700522) -> Result<Api> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700523 // type Alias = crate::path::to::Type;
David Tolnay3e628882020-05-10 15:30:14 -0700524 let parse = |input: ParseStream| -> Result<TypeAlias> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700525 let attrs = input.call(Attribute::parse_outer)?;
526 let type_token: Token![type] = match input.parse()? {
527 Some(type_token) => type_token,
528 None => {
529 let span = input.cursor().token_stream();
530 return Err(Error::new_spanned(span, "unsupported foreign item"));
531 }
532 };
533 let ident: Ident = input.parse()?;
534 let eq_token: Token![=] = input.parse()?;
535 let ty: RustType = input.parse()?;
536 let semi_token: Token![;] = input.parse()?;
Adrian Taylorc8713432020-10-21 18:20:55 -0700537 let mut doc = Doc::new();
David Tolnay302b1752020-11-10 18:43:24 -0800538 let mut namespace = namespace.clone();
Adrian Taylorc8713432020-10-21 18:20:55 -0700539 attrs::parse(
540 cx,
541 &attrs,
542 attrs::Parser {
543 doc: Some(&mut doc),
David Tolnayd7a3a182020-11-01 20:45:14 -0800544 namespace: Some(&mut namespace),
Adrian Taylorc8713432020-10-21 18:20:55 -0700545 ..Default::default()
546 },
547 );
David Tolnaye2f9ec42020-05-07 16:19:33 -0700548
549 Ok(TypeAlias {
Bryan Henry890083d2020-09-13 10:34:31 -0700550 doc,
David Tolnaye2f9ec42020-05-07 16:19:33 -0700551 type_token,
David Tolnay17a934c2020-11-02 00:40:04 -0800552 name: Pair::new(namespace, ident),
David Tolnaye2f9ec42020-05-07 16:19:33 -0700553 eq_token,
554 ty,
555 semi_token,
556 })
David Tolnay3e628882020-05-10 15:30:14 -0700557 };
David Tolnaye2f9ec42020-05-07 16:19:33 -0700558
559 let type_alias = parse.parse2(tokens.clone())?;
560 match lang {
561 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
562 Lang::Rust => {
563 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
564 let span = quote!(#type_token #semi_token);
565 let msg = "type alias in extern \"Rust\" block is not supported";
566 Err(Error::new_spanned(span, msg))
567 }
568 }
569}
570
David Tolnay313cc0a2020-11-24 21:47:01 -0800571fn parse_impl(imp: ItemImpl) -> Result<Api> {
David Tolnay7e69f892020-10-03 22:20:22 -0700572 if !imp.items.is_empty() {
573 let mut span = Group::new(Delimiter::Brace, TokenStream::new());
574 span.set_span(imp.brace_token.span);
575 return Err(Error::new_spanned(span, "expected an empty impl block"));
576 }
577
578 let self_ty = &imp.self_ty;
579 if let Some((bang, path, for_token)) = &imp.trait_ {
580 let span = quote!(#bang #path #for_token #self_ty);
581 return Err(Error::new_spanned(
582 span,
583 "unexpected impl, expected something like `impl UniquePtr<T> {}`",
584 ));
585 }
586
587 let generics = &imp.generics;
588 if !generics.params.is_empty() || generics.where_clause.is_some() {
589 return Err(Error::new_spanned(
590 imp,
591 "generic parameters on an impl is not supported",
592 ));
593 }
594
595 Ok(Api::Impl(Impl {
596 impl_token: imp.impl_token,
David Tolnay313cc0a2020-11-24 21:47:01 -0800597 ty: parse_type(&self_ty)?,
David Tolnay7e69f892020-10-03 22:20:22 -0700598 brace_token: imp.brace_token,
599 }))
600}
601
David Tolnayb0cd3272020-10-27 21:32:54 -0700602fn parse_include(input: ParseStream) -> Result<Include> {
David Tolnay91e87fa2020-05-11 19:10:23 -0700603 if input.peek(LitStr) {
David Tolnayb0cd3272020-10-27 21:32:54 -0700604 let lit: LitStr = input.parse()?;
605 let span = lit.span();
606 return Ok(Include {
607 path: lit.value(),
608 kind: IncludeKind::Quoted,
609 begin_span: span,
610 end_span: span,
611 });
David Tolnay91e87fa2020-05-11 19:10:23 -0700612 }
613
614 if input.peek(Token![<]) {
615 let mut path = String::new();
David Tolnayb0cd3272020-10-27 21:32:54 -0700616
David Tolnay2cc2e3a2020-10-28 13:12:35 -0700617 let langle: Token![<] = input.parse()?;
David Tolnay91e87fa2020-05-11 19:10:23 -0700618 while !input.is_empty() && !input.peek(Token![>]) {
619 let token: TokenTree = input.parse()?;
620 match token {
621 TokenTree::Ident(token) => path += &token.to_string(),
622 TokenTree::Literal(token)
623 if token
624 .to_string()
625 .starts_with(|ch: char| ch.is_ascii_digit()) =>
626 {
627 path += &token.to_string();
628 }
629 TokenTree::Punct(token) => path.push(token.as_char()),
630 _ => return Err(Error::new(token.span(), "unexpected token in include path")),
631 }
632 }
David Tolnayb0cd3272020-10-27 21:32:54 -0700633 let rangle: Token![>] = input.parse()?;
David Tolnayb0cd3272020-10-27 21:32:54 -0700634
635 return Ok(Include {
636 path,
637 kind: IncludeKind::Bracketed,
David Tolnay2cc2e3a2020-10-28 13:12:35 -0700638 begin_span: langle.span,
639 end_span: rangle.span,
David Tolnayb0cd3272020-10-27 21:32:54 -0700640 });
David Tolnay91e87fa2020-05-11 19:10:23 -0700641 }
642
643 Err(input.error("expected \"quoted/path/to\" or <bracketed/path/to>"))
644}
645
David Tolnay313cc0a2020-11-24 21:47:01 -0800646fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700647 match ty {
David Tolnay313cc0a2020-11-24 21:47:01 -0800648 RustType::Reference(ty) => parse_type_reference(ty),
649 RustType::Path(ty) => parse_type_path(ty),
David Tolnay313cc0a2020-11-24 21:47:01 -0800650 RustType::Array(ty) => parse_type_array(ty),
651 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700652 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
653 _ => Err(Error::new_spanned(ty, "unsupported type")),
654 }
655}
656
David Tolnay313cc0a2020-11-24 21:47:01 -0800657fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
David Tolnaye0dca7b2020-11-25 17:18:57 -0800658 if let RustType::Slice(slice) = ty.elem.as_ref() {
659 let inner = parse_type(&slice.elem)?;
David Tolnay69db8142020-11-25 17:49:25 -0800660 return Ok(Type::SliceRef(Box::new(SliceRef {
661 ampersand: ty.and_token,
662 lifetime: ty.lifetime.clone(),
663 mutable: ty.mutability.is_some(),
664 bracket: slice.bracket_token,
665 inner,
666 mutability: ty.mutability,
667 })));
David Tolnaye0dca7b2020-11-25 17:18:57 -0800668 }
669
David Tolnay313cc0a2020-11-24 21:47:01 -0800670 let inner = parse_type(&ty.elem)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700671 let which = match &inner {
Adrian Taylorc8713432020-10-21 18:20:55 -0700672 Type::Ident(ident) if ident.rust == "str" => {
David Tolnayb40b9db2020-03-18 13:50:31 -0700673 if ty.mutability.is_some() {
674 return Err(Error::new_spanned(ty, "unsupported type"));
675 } else {
676 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400677 }
678 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700679 _ => Type::Ref,
680 };
681 Ok(which(Box::new(Ref {
David Tolnayb27f7872020-11-15 15:07:04 -0800682 pinned: false,
David Tolnayb40b9db2020-03-18 13:50:31 -0700683 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700684 lifetime: ty.lifetime.clone(),
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800685 mutable: ty.mutability.is_some(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700686 inner,
David Tolnayb27f7872020-11-15 15:07:04 -0800687 pin_tokens: None,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800688 mutability: ty.mutability,
David Tolnayb40b9db2020-03-18 13:50:31 -0700689 })))
690}
691
David Tolnay313cc0a2020-11-24 21:47:01 -0800692fn parse_type_path(ty: &TypePath) -> Result<Type> {
David Tolnayb40b9db2020-03-18 13:50:31 -0700693 let path = &ty.path;
694 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
695 let segment = &path.segments[0];
696 let ident = segment.ident.clone();
697 match &segment.arguments {
David Tolnayda71ef62020-11-02 00:36:00 -0800698 PathArguments::None => return Ok(Type::Ident(ResolvableName::new(ident))),
David Tolnayb40b9db2020-03-18 13:50:31 -0700699 PathArguments::AngleBracketed(generic) => {
700 if ident == "UniquePtr" && generic.args.len() == 1 {
701 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800702 let inner = parse_type(arg)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700703 return Ok(Type::UniquePtr(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800704 name: ident,
David Tolnayb40b9db2020-03-18 13:50:31 -0700705 langle: generic.lt_token,
706 inner,
707 rangle: generic.gt_token,
708 })));
709 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700710 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700711 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800712 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700713 return Ok(Type::CxxVector(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800714 name: ident,
Myron Ahneba35cf2020-02-05 19:41:51 +0700715 langle: generic.lt_token,
716 inner,
717 rangle: generic.gt_token,
718 })));
719 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700720 } else if ident == "Box" && generic.args.len() == 1 {
721 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800722 let inner = parse_type(arg)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700723 return Ok(Type::RustBox(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800724 name: ident,
David Tolnayb40b9db2020-03-18 13:50:31 -0700725 langle: generic.lt_token,
726 inner,
727 rangle: generic.gt_token,
728 })));
729 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700730 } else if ident == "Vec" && generic.args.len() == 1 {
731 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800732 let inner = parse_type(arg)?;
Myron Ahneba35cf2020-02-05 19:41:51 +0700733 return Ok(Type::RustVec(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800734 name: ident,
Myron Ahneba35cf2020-02-05 19:41:51 +0700735 langle: generic.lt_token,
736 inner,
737 rangle: generic.gt_token,
738 })));
739 }
David Tolnaycbc2a4b2020-11-15 15:08:44 -0800740 } else if ident == "Pin" && generic.args.len() == 1 {
741 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800742 let inner = parse_type(arg)?;
David Tolnayc94035a2020-11-15 16:49:18 -0800743 let pin_token = kw::Pin(ident.span());
David Tolnaycbc2a4b2020-11-15 15:08:44 -0800744 if let Type::Ref(mut inner) = inner {
David Tolnaycbc2a4b2020-11-15 15:08:44 -0800745 inner.pinned = true;
746 inner.pin_tokens =
747 Some((pin_token, generic.lt_token, generic.gt_token));
748 return Ok(Type::Ref(inner));
749 }
750 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700751 }
752 }
753 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700754 }
David Tolnay7db73692019-10-20 14:51:12 -0400755 }
756 Err(Error::new_spanned(ty, "unsupported type"))
757}
758
David Tolnay313cc0a2020-11-24 21:47:01 -0800759fn parse_type_array(ty: &TypeArray) -> Result<Type> {
760 let inner = parse_type(&ty.elem)?;
David Tolnayd9f97842020-11-24 21:00:05 -0800761
762 let len_expr = if let Expr::Lit(lit) = &ty.len {
763 lit
764 } else {
765 let msg = "unsupported expression, array length must be an integer literal";
766 return Err(Error::new_spanned(&ty.len, msg));
767 };
768
769 let len_token = if let Lit::Int(int) = &len_expr.lit {
770 int.clone()
771 } else {
772 let msg = "array length must be an integer literal";
773 return Err(Error::new_spanned(len_expr, msg));
774 };
775
David Tolnay581f72d2020-11-25 15:48:59 -0800776 let len = len_token.base10_parse::<usize>()?;
777 if len == 0 {
778 let msg = "array with zero size is not supported";
779 return Err(Error::new_spanned(ty, msg));
780 }
781
David Tolnayd9f97842020-11-24 21:00:05 -0800782 let bracket = ty.bracket_token;
783 let semi_token = ty.semi_token;
David Tolnayd9f97842020-11-24 21:00:05 -0800784
785 Ok(Type::Array(Box::new(Array {
786 bracket,
787 inner,
788 semi_token,
789 len,
790 len_token,
791 })))
David Tolnay2d0df232020-11-24 20:50:32 -0800792}
793
David Tolnay313cc0a2020-11-24 21:47:01 -0800794fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
David Tolnayc071b892020-03-18 16:59:53 -0700795 if ty.lifetimes.is_some() {
796 return Err(Error::new_spanned(
797 ty,
798 "function pointer with lifetime parameters is not supported yet",
799 ));
800 }
801 if ty.variadic.is_some() {
802 return Err(Error::new_spanned(
803 ty,
804 "variadic function pointer is not supported yet",
805 ));
806 }
807 let args = ty
808 .inputs
809 .iter()
810 .enumerate()
811 .map(|(i, arg)| {
David Tolnay313cc0a2020-11-24 21:47:01 -0800812 let ty = parse_type(&arg.ty)?;
David Tolnayc071b892020-03-18 16:59:53 -0700813 let ident = match &arg.name {
814 Some(ident) => ident.0.clone(),
815 None => format_ident!("_{}", i),
816 };
817 Ok(Var { ident, ty })
818 })
819 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700820 let mut throws_tokens = None;
David Tolnay313cc0a2020-11-24 21:47:01 -0800821 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
David Tolnaye3a48152020-04-08 19:38:05 -0700822 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700823 Ok(Type::Fn(Box::new(Signature {
David Tolnaybdb576c2020-09-06 23:45:55 -0700824 unsafety: ty.unsafety,
David Tolnayc071b892020-03-18 16:59:53 -0700825 fn_token: ty.fn_token,
David Tolnay9938b642020-11-15 18:11:40 -0800826 generics: Generics::default(),
David Tolnayc071b892020-03-18 16:59:53 -0700827 receiver: None,
828 args,
829 ret,
830 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700831 paren_token: ty.paren_token,
832 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700833 })))
834}
835
David Tolnaye3a48152020-04-08 19:38:05 -0700836fn parse_return_type(
837 ty: &ReturnType,
838 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
839) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700840 let mut ret = match ty {
841 ReturnType::Default => return Ok(None),
842 ReturnType::Type(_, ret) => ret.as_ref(),
843 };
844 if let RustType::Path(ty) = ret {
845 let path = &ty.path;
846 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
847 let segment = &path.segments[0];
848 let ident = segment.ident.clone();
849 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
850 if ident == "Result" && generic.args.len() == 1 {
851 if let GenericArgument::Type(arg) = &generic.args[0] {
852 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700853 *throws_tokens =
854 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700855 }
856 }
857 }
858 }
859 }
David Tolnay313cc0a2020-11-24 21:47:01 -0800860 match parse_type(ret)? {
David Tolnayc071b892020-03-18 16:59:53 -0700861 Type::Void(_) => Ok(None),
862 ty => Ok(Some(ty)),
863 }
864}