blob: a009e19eb343b4e85fd24992b22cb388ee6be45b [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 Tolnay302b1752020-11-10 18:43:24 -0800330 let mut namespace = namespace.clone();
Adrian Taylorc8713432020-10-21 18:20:55 -0700331 attrs::parse(
332 cx,
333 &foreign_type.attrs,
334 attrs::Parser {
335 doc: Some(&mut doc),
David Tolnayd7a3a182020-11-01 20:45:14 -0800336 namespace: Some(&mut namespace),
Adrian Taylorc8713432020-10-21 18:20:55 -0700337 ..Default::default()
338 },
339 );
David Tolnay7db73692019-10-20 14:51:12 -0400340 let type_token = foreign_type.type_token;
341 let ident = foreign_type.ident.clone();
David Tolnayc8361022020-08-25 21:57:53 -0700342 let semi_token = foreign_type.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700343 let api_type = match lang {
344 Lang::Cxx => Api::CxxType,
345 Lang::Rust => Api::RustType,
346 };
David Tolnayf5ead102020-11-24 17:08:05 -0800347 api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400348 doc,
349 type_token,
David Tolnay17a934c2020-11-02 00:40:04 -0800350 name: Pair::new(namespace, ident),
David Tolnayc8361022020-08-25 21:57:53 -0700351 semi_token,
David Tolnay00f236a2020-08-29 19:07:18 -0700352 trusted,
David Tolnayf5ead102020-11-24 17:08:05 -0800353 })
David Tolnay7db73692019-10-20 14:51:12 -0400354}
355
Adrian Taylorc8713432020-10-21 18:20:55 -0700356fn parse_extern_fn(
357 cx: &mut Errors,
358 foreign_fn: &ForeignItemFn,
359 lang: Lang,
David Tolnay556738d2020-11-15 13:58:44 -0800360 trusted: bool,
David Tolnay302b1752020-11-10 18:43:24 -0800361 namespace: &Namespace,
Adrian Taylorc8713432020-10-21 18:20:55 -0700362) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400363 let generics = &foreign_fn.sig.generics;
David Tolnay9938b642020-11-15 18:11:40 -0800364 if generics.where_clause.is_some()
365 || generics.params.iter().any(|param| match param {
366 GenericParam::Lifetime(lifetime) => !lifetime.bounds.is_empty(),
367 GenericParam::Type(_) | GenericParam::Const(_) => true,
368 })
369 {
David Tolnay7db73692019-10-20 14:51:12 -0400370 return Err(Error::new_spanned(
371 foreign_fn,
372 "extern function with generic parameters is not supported yet",
373 ));
374 }
375 if let Some(variadic) = &foreign_fn.sig.variadic {
376 return Err(Error::new_spanned(
377 variadic,
378 "variadic function is not supported yet",
379 ));
380 }
David Tolnay8de461f2020-11-19 13:46:14 -0800381 if foreign_fn.sig.asyncness.is_some() {
382 return Err(Error::new_spanned(
383 foreign_fn,
384 "async function is not directly supported yet, but see https://cxx.rs/async.html for a working approach",
385 ));
386 }
David Tolnay80ef0682020-11-19 13:56:07 -0800387 if foreign_fn.sig.constness.is_some() {
388 return Err(Error::new_spanned(
389 foreign_fn,
390 "const extern function is not supported",
391 ));
392 }
393 if let Some(abi) = &foreign_fn.sig.abi {
394 return Err(Error::new_spanned(
395 abi,
396 "explicit ABI on extern function is not supported",
397 ));
398 }
David Tolnay7db73692019-10-20 14:51:12 -0400399
David Tolnay938ca852020-10-09 19:25:08 -0700400 let mut doc = Doc::new();
401 let mut cxx_name = None;
402 let mut rust_name = None;
David Tolnay302b1752020-11-10 18:43:24 -0800403 let mut namespace = namespace.clone();
David Tolnay938ca852020-10-09 19:25:08 -0700404 attrs::parse(
405 cx,
406 &foreign_fn.attrs,
407 attrs::Parser {
408 doc: Some(&mut doc),
409 cxx_name: Some(&mut cxx_name),
410 rust_name: Some(&mut rust_name),
David Tolnayd7a3a182020-11-01 20:45:14 -0800411 namespace: Some(&mut namespace),
David Tolnay938ca852020-10-09 19:25:08 -0700412 ..Default::default()
413 },
414 );
415
David Tolnay7db73692019-10-20 14:51:12 -0400416 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700417 let mut args = Punctuated::new();
418 for arg in foreign_fn.sig.inputs.pairs() {
419 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400420 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700421 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700422 if let Some((ampersand, lifetime)) = &arg.reference {
423 receiver = Some(Receiver {
David Tolnay9c76c392020-11-15 16:07:08 -0800424 pinned: false,
David Tolnaya1f29c42020-04-22 18:01:38 -0700425 ampersand: *ampersand,
426 lifetime: lifetime.clone(),
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800427 mutable: arg.mutability.is_some(),
David Tolnaya1f29c42020-04-22 18:01:38 -0700428 var: arg.self_token,
Adrian Taylorc8713432020-10-21 18:20:55 -0700429 ty: ResolvableName::make_self(arg.self_token.span),
David Tolnaya1f29c42020-04-22 18:01:38 -0700430 shorthand: true,
David Tolnay9c76c392020-11-15 16:07:08 -0800431 pin_tokens: None,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800432 mutability: arg.mutability,
David Tolnaya1f29c42020-04-22 18:01:38 -0700433 });
434 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700435 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700436 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400437 }
438 FnArg::Typed(arg) => {
439 let ident = match arg.pat.as_ref() {
440 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700441 Pat::Wild(pat) => {
442 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
443 }
David Tolnay7db73692019-10-20 14:51:12 -0400444 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
445 };
David Tolnay313cc0a2020-11-24 21:47:01 -0800446 let ty = parse_type(&arg.ty)?;
David Tolnay7db73692019-10-20 14:51:12 -0400447 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700448 args.push_value(Var { ident, ty });
449 if let Some(comma) = comma {
450 args.push_punct(*comma);
451 }
David Tolnay7db73692019-10-20 14:51:12 -0400452 continue;
453 }
454 if let Type::Ref(reference) = ty {
455 if let Type::Ident(ident) = reference.inner {
456 receiver = Some(Receiver {
David Tolnay9c76c392020-11-15 16:07:08 -0800457 pinned: reference.pinned,
David Tolnayfb6e3862020-04-20 01:33:23 -0700458 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700459 lifetime: reference.lifetime,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800460 mutable: reference.mutable,
Adrian Taylorc8713432020-10-21 18:20:55 -0700461 var: Token![self](ident.rust.span()),
David Tolnay05e11cc2020-04-20 02:13:56 -0700462 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700463 shorthand: false,
David Tolnay9c76c392020-11-15 16:07:08 -0800464 pin_tokens: reference.pin_tokens,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800465 mutability: reference.mutability,
David Tolnay7db73692019-10-20 14:51:12 -0400466 });
467 continue;
468 }
469 }
470 return Err(Error::new_spanned(arg, "unsupported method receiver"));
471 }
472 }
473 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700474
David Tolnaye3a48152020-04-08 19:38:05 -0700475 let mut throws_tokens = None;
David Tolnay313cc0a2020-11-24 21:47:01 -0800476 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
David Tolnaye3a48152020-04-08 19:38:05 -0700477 let throws = throws_tokens.is_some();
David Tolnaybdb576c2020-09-06 23:45:55 -0700478 let unsafety = foreign_fn.sig.unsafety;
David Tolnay7db73692019-10-20 14:51:12 -0400479 let fn_token = foreign_fn.sig.fn_token;
David Tolnay17a934c2020-11-02 00:40:04 -0800480 let name = Pair::new_from_differing_names(
David Tolnayd7a3a182020-11-01 20:45:14 -0800481 namespace,
Adrian Taylor0f8ab222020-10-29 21:31:56 -0700482 cxx_name.unwrap_or(foreign_fn.sig.ident.clone()),
483 rust_name.unwrap_or(foreign_fn.sig.ident.clone()),
484 );
David Tolnay9938b642020-11-15 18:11:40 -0800485 let generics = generics.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700486 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400487 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700488 let api_function = match lang {
489 Lang::Cxx => Api::CxxFunction,
490 Lang::Rust => Api::RustFunction,
491 };
David Tolnayd95b1192020-03-18 20:07:46 -0700492
David Tolnay295ef6b2020-05-07 16:10:22 -0700493 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700494 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400495 doc,
David Tolnay17a934c2020-11-02 00:40:04 -0800496 name,
David Tolnay16448732020-03-18 12:39:36 -0700497 sig: Signature {
David Tolnaybdb576c2020-09-06 23:45:55 -0700498 unsafety,
David Tolnay16448732020-03-18 12:39:36 -0700499 fn_token,
David Tolnay9938b642020-11-15 18:11:40 -0800500 generics,
David Tolnay16448732020-03-18 12:39:36 -0700501 receiver,
502 args,
503 ret,
504 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700505 paren_token,
506 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700507 },
David Tolnay7db73692019-10-20 14:51:12 -0400508 semi_token,
David Tolnay556738d2020-11-15 13:58:44 -0800509 trusted,
David Tolnay295ef6b2020-05-07 16:10:22 -0700510 }))
David Tolnay7db73692019-10-20 14:51:12 -0400511}
512
Adrian Taylorc8713432020-10-21 18:20:55 -0700513fn parse_extern_verbatim(
514 cx: &mut Errors,
515 tokens: &TokenStream,
516 lang: Lang,
David Tolnay302b1752020-11-10 18:43:24 -0800517 namespace: &Namespace,
Adrian Taylorc8713432020-10-21 18:20:55 -0700518) -> Result<Api> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700519 // type Alias = crate::path::to::Type;
David Tolnay3e628882020-05-10 15:30:14 -0700520 let parse = |input: ParseStream| -> Result<TypeAlias> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700521 let attrs = input.call(Attribute::parse_outer)?;
522 let type_token: Token![type] = match input.parse()? {
523 Some(type_token) => type_token,
524 None => {
525 let span = input.cursor().token_stream();
526 return Err(Error::new_spanned(span, "unsupported foreign item"));
527 }
528 };
529 let ident: Ident = input.parse()?;
530 let eq_token: Token![=] = input.parse()?;
531 let ty: RustType = input.parse()?;
532 let semi_token: Token![;] = input.parse()?;
Adrian Taylorc8713432020-10-21 18:20:55 -0700533 let mut doc = Doc::new();
David Tolnay302b1752020-11-10 18:43:24 -0800534 let mut namespace = namespace.clone();
Adrian Taylorc8713432020-10-21 18:20:55 -0700535 attrs::parse(
536 cx,
537 &attrs,
538 attrs::Parser {
539 doc: Some(&mut doc),
David Tolnayd7a3a182020-11-01 20:45:14 -0800540 namespace: Some(&mut namespace),
Adrian Taylorc8713432020-10-21 18:20:55 -0700541 ..Default::default()
542 },
543 );
David Tolnaye2f9ec42020-05-07 16:19:33 -0700544
545 Ok(TypeAlias {
Bryan Henry890083d2020-09-13 10:34:31 -0700546 doc,
David Tolnaye2f9ec42020-05-07 16:19:33 -0700547 type_token,
David Tolnay17a934c2020-11-02 00:40:04 -0800548 name: Pair::new(namespace, ident),
David Tolnaye2f9ec42020-05-07 16:19:33 -0700549 eq_token,
550 ty,
551 semi_token,
552 })
David Tolnay3e628882020-05-10 15:30:14 -0700553 };
David Tolnaye2f9ec42020-05-07 16:19:33 -0700554
555 let type_alias = parse.parse2(tokens.clone())?;
556 match lang {
557 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
558 Lang::Rust => {
559 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
560 let span = quote!(#type_token #semi_token);
561 let msg = "type alias in extern \"Rust\" block is not supported";
562 Err(Error::new_spanned(span, msg))
563 }
564 }
565}
566
David Tolnay313cc0a2020-11-24 21:47:01 -0800567fn parse_impl(imp: ItemImpl) -> Result<Api> {
David Tolnay7e69f892020-10-03 22:20:22 -0700568 if !imp.items.is_empty() {
569 let mut span = Group::new(Delimiter::Brace, TokenStream::new());
570 span.set_span(imp.brace_token.span);
571 return Err(Error::new_spanned(span, "expected an empty impl block"));
572 }
573
574 let self_ty = &imp.self_ty;
575 if let Some((bang, path, for_token)) = &imp.trait_ {
576 let span = quote!(#bang #path #for_token #self_ty);
577 return Err(Error::new_spanned(
578 span,
579 "unexpected impl, expected something like `impl UniquePtr<T> {}`",
580 ));
581 }
582
583 let generics = &imp.generics;
584 if !generics.params.is_empty() || generics.where_clause.is_some() {
585 return Err(Error::new_spanned(
586 imp,
587 "generic parameters on an impl is not supported",
588 ));
589 }
590
591 Ok(Api::Impl(Impl {
592 impl_token: imp.impl_token,
David Tolnay313cc0a2020-11-24 21:47:01 -0800593 ty: parse_type(&self_ty)?,
David Tolnay7e69f892020-10-03 22:20:22 -0700594 brace_token: imp.brace_token,
595 }))
596}
597
David Tolnayb0cd3272020-10-27 21:32:54 -0700598fn parse_include(input: ParseStream) -> Result<Include> {
David Tolnay91e87fa2020-05-11 19:10:23 -0700599 if input.peek(LitStr) {
David Tolnayb0cd3272020-10-27 21:32:54 -0700600 let lit: LitStr = input.parse()?;
601 let span = lit.span();
602 return Ok(Include {
603 path: lit.value(),
604 kind: IncludeKind::Quoted,
605 begin_span: span,
606 end_span: span,
607 });
David Tolnay91e87fa2020-05-11 19:10:23 -0700608 }
609
610 if input.peek(Token![<]) {
611 let mut path = String::new();
David Tolnayb0cd3272020-10-27 21:32:54 -0700612
David Tolnay2cc2e3a2020-10-28 13:12:35 -0700613 let langle: Token![<] = input.parse()?;
David Tolnay91e87fa2020-05-11 19:10:23 -0700614 while !input.is_empty() && !input.peek(Token![>]) {
615 let token: TokenTree = input.parse()?;
616 match token {
617 TokenTree::Ident(token) => path += &token.to_string(),
618 TokenTree::Literal(token)
619 if token
620 .to_string()
621 .starts_with(|ch: char| ch.is_ascii_digit()) =>
622 {
623 path += &token.to_string();
624 }
625 TokenTree::Punct(token) => path.push(token.as_char()),
626 _ => return Err(Error::new(token.span(), "unexpected token in include path")),
627 }
628 }
David Tolnayb0cd3272020-10-27 21:32:54 -0700629 let rangle: Token![>] = input.parse()?;
David Tolnayb0cd3272020-10-27 21:32:54 -0700630
631 return Ok(Include {
632 path,
633 kind: IncludeKind::Bracketed,
David Tolnay2cc2e3a2020-10-28 13:12:35 -0700634 begin_span: langle.span,
635 end_span: rangle.span,
David Tolnayb0cd3272020-10-27 21:32:54 -0700636 });
David Tolnay91e87fa2020-05-11 19:10:23 -0700637 }
638
639 Err(input.error("expected \"quoted/path/to\" or <bracketed/path/to>"))
640}
641
David Tolnay313cc0a2020-11-24 21:47:01 -0800642fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700643 match ty {
David Tolnay313cc0a2020-11-24 21:47:01 -0800644 RustType::Reference(ty) => parse_type_reference(ty),
645 RustType::Path(ty) => parse_type_path(ty),
David Tolnay313cc0a2020-11-24 21:47:01 -0800646 RustType::Array(ty) => parse_type_array(ty),
647 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700648 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
649 _ => Err(Error::new_spanned(ty, "unsupported type")),
650 }
651}
652
David Tolnay313cc0a2020-11-24 21:47:01 -0800653fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
David Tolnaye0dca7b2020-11-25 17:18:57 -0800654 if let RustType::Slice(slice) = ty.elem.as_ref() {
655 let inner = parse_type(&slice.elem)?;
David Tolnay69db8142020-11-25 17:49:25 -0800656 return Ok(Type::SliceRef(Box::new(SliceRef {
657 ampersand: ty.and_token,
658 lifetime: ty.lifetime.clone(),
659 mutable: ty.mutability.is_some(),
660 bracket: slice.bracket_token,
661 inner,
662 mutability: ty.mutability,
663 })));
David Tolnaye0dca7b2020-11-25 17:18:57 -0800664 }
665
David Tolnay313cc0a2020-11-24 21:47:01 -0800666 let inner = parse_type(&ty.elem)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700667 let which = match &inner {
Adrian Taylorc8713432020-10-21 18:20:55 -0700668 Type::Ident(ident) if ident.rust == "str" => {
David Tolnayb40b9db2020-03-18 13:50:31 -0700669 if ty.mutability.is_some() {
670 return Err(Error::new_spanned(ty, "unsupported type"));
671 } else {
672 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400673 }
674 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700675 _ => Type::Ref,
676 };
677 Ok(which(Box::new(Ref {
David Tolnayb27f7872020-11-15 15:07:04 -0800678 pinned: false,
David Tolnayb40b9db2020-03-18 13:50:31 -0700679 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700680 lifetime: ty.lifetime.clone(),
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800681 mutable: ty.mutability.is_some(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700682 inner,
David Tolnayb27f7872020-11-15 15:07:04 -0800683 pin_tokens: None,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800684 mutability: ty.mutability,
David Tolnayb40b9db2020-03-18 13:50:31 -0700685 })))
686}
687
David Tolnay313cc0a2020-11-24 21:47:01 -0800688fn parse_type_path(ty: &TypePath) -> Result<Type> {
David Tolnayb40b9db2020-03-18 13:50:31 -0700689 let path = &ty.path;
690 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
691 let segment = &path.segments[0];
692 let ident = segment.ident.clone();
693 match &segment.arguments {
David Tolnayda71ef62020-11-02 00:36:00 -0800694 PathArguments::None => return Ok(Type::Ident(ResolvableName::new(ident))),
David Tolnayb40b9db2020-03-18 13:50:31 -0700695 PathArguments::AngleBracketed(generic) => {
696 if ident == "UniquePtr" && generic.args.len() == 1 {
697 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800698 let inner = parse_type(arg)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700699 return Ok(Type::UniquePtr(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800700 name: ident,
David Tolnayb40b9db2020-03-18 13:50:31 -0700701 langle: generic.lt_token,
702 inner,
703 rangle: generic.gt_token,
704 })));
705 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700706 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700707 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800708 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700709 return Ok(Type::CxxVector(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800710 name: ident,
Myron Ahneba35cf2020-02-05 19:41:51 +0700711 langle: generic.lt_token,
712 inner,
713 rangle: generic.gt_token,
714 })));
715 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700716 } else if ident == "Box" && generic.args.len() == 1 {
717 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800718 let inner = parse_type(arg)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700719 return Ok(Type::RustBox(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800720 name: ident,
David Tolnayb40b9db2020-03-18 13:50:31 -0700721 langle: generic.lt_token,
722 inner,
723 rangle: generic.gt_token,
724 })));
725 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700726 } else if ident == "Vec" && generic.args.len() == 1 {
727 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800728 let inner = parse_type(arg)?;
Myron Ahneba35cf2020-02-05 19:41:51 +0700729 return Ok(Type::RustVec(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800730 name: ident,
Myron Ahneba35cf2020-02-05 19:41:51 +0700731 langle: generic.lt_token,
732 inner,
733 rangle: generic.gt_token,
734 })));
735 }
David Tolnaycbc2a4b2020-11-15 15:08:44 -0800736 } else if ident == "Pin" && generic.args.len() == 1 {
737 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800738 let inner = parse_type(arg)?;
David Tolnayc94035a2020-11-15 16:49:18 -0800739 let pin_token = kw::Pin(ident.span());
David Tolnaycbc2a4b2020-11-15 15:08:44 -0800740 if let Type::Ref(mut inner) = inner {
David Tolnaycbc2a4b2020-11-15 15:08:44 -0800741 inner.pinned = true;
742 inner.pin_tokens =
743 Some((pin_token, generic.lt_token, generic.gt_token));
744 return Ok(Type::Ref(inner));
745 }
746 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700747 }
748 }
749 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700750 }
David Tolnay7db73692019-10-20 14:51:12 -0400751 }
752 Err(Error::new_spanned(ty, "unsupported type"))
753}
754
David Tolnay313cc0a2020-11-24 21:47:01 -0800755fn parse_type_array(ty: &TypeArray) -> Result<Type> {
756 let inner = parse_type(&ty.elem)?;
David Tolnayd9f97842020-11-24 21:00:05 -0800757
758 let len_expr = if let Expr::Lit(lit) = &ty.len {
759 lit
760 } else {
761 let msg = "unsupported expression, array length must be an integer literal";
762 return Err(Error::new_spanned(&ty.len, msg));
763 };
764
765 let len_token = if let Lit::Int(int) = &len_expr.lit {
766 int.clone()
767 } else {
768 let msg = "array length must be an integer literal";
769 return Err(Error::new_spanned(len_expr, msg));
770 };
771
David Tolnay581f72d2020-11-25 15:48:59 -0800772 let len = len_token.base10_parse::<usize>()?;
773 if len == 0 {
774 let msg = "array with zero size is not supported";
775 return Err(Error::new_spanned(ty, msg));
776 }
777
David Tolnayd9f97842020-11-24 21:00:05 -0800778 let bracket = ty.bracket_token;
779 let semi_token = ty.semi_token;
David Tolnayd9f97842020-11-24 21:00:05 -0800780
781 Ok(Type::Array(Box::new(Array {
782 bracket,
783 inner,
784 semi_token,
785 len,
786 len_token,
787 })))
David Tolnay2d0df232020-11-24 20:50:32 -0800788}
789
David Tolnay313cc0a2020-11-24 21:47:01 -0800790fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
David Tolnayc071b892020-03-18 16:59:53 -0700791 if ty.lifetimes.is_some() {
792 return Err(Error::new_spanned(
793 ty,
794 "function pointer with lifetime parameters is not supported yet",
795 ));
796 }
797 if ty.variadic.is_some() {
798 return Err(Error::new_spanned(
799 ty,
800 "variadic function pointer is not supported yet",
801 ));
802 }
803 let args = ty
804 .inputs
805 .iter()
806 .enumerate()
807 .map(|(i, arg)| {
David Tolnay313cc0a2020-11-24 21:47:01 -0800808 let ty = parse_type(&arg.ty)?;
David Tolnayc071b892020-03-18 16:59:53 -0700809 let ident = match &arg.name {
810 Some(ident) => ident.0.clone(),
811 None => format_ident!("_{}", i),
812 };
813 Ok(Var { ident, ty })
814 })
815 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700816 let mut throws_tokens = None;
David Tolnay313cc0a2020-11-24 21:47:01 -0800817 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
David Tolnaye3a48152020-04-08 19:38:05 -0700818 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700819 Ok(Type::Fn(Box::new(Signature {
David Tolnaybdb576c2020-09-06 23:45:55 -0700820 unsafety: ty.unsafety,
David Tolnayc071b892020-03-18 16:59:53 -0700821 fn_token: ty.fn_token,
David Tolnay9938b642020-11-15 18:11:40 -0800822 generics: Generics::default(),
David Tolnayc071b892020-03-18 16:59:53 -0700823 receiver: None,
824 args,
825 ret,
826 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700827 paren_token: ty.paren_token,
828 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700829 })))
830}
831
David Tolnaye3a48152020-04-08 19:38:05 -0700832fn parse_return_type(
833 ty: &ReturnType,
834 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
835) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700836 let mut ret = match ty {
837 ReturnType::Default => return Ok(None),
838 ReturnType::Type(_, ret) => ret.as_ref(),
839 };
840 if let RustType::Path(ty) = ret {
841 let path = &ty.path;
842 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
843 let segment = &path.segments[0];
844 let ident = segment.ident.clone();
845 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
846 if ident == "Result" && generic.args.len() == 1 {
847 if let GenericArgument::Type(arg) = &generic.args[0] {
848 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700849 *throws_tokens =
850 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700851 }
852 }
853 }
854 }
855 }
David Tolnay313cc0a2020-11-24 21:47:01 -0800856 match parse_type(ret)? {
David Tolnayc071b892020-03-18 16:59:53 -0700857 Type::Void(_) => Ok(None),
858 ty => Ok(Some(ty)),
859 }
860}