blob: b794ba9255ea7cbb9870db760524879cd9a1217a [file] [log] [blame]
David Tolnay52759782020-05-03 23:59:40 -07001use crate::syntax::report::Errors;
David Tolnayeebe9b72020-04-14 16:32:18 -07002use crate::syntax::Atom::*;
David Tolnay7db73692019-10-20 14:51:12 -04003use crate::syntax::{
Joel Galensonc03402a2020-04-23 17:31:09 -07004 attrs, error, Api, Doc, Enum, ExternFn, ExternType, Lang, Receiver, Ref, Signature, Slice,
5 Struct, Ty1, Type, Var, Variant,
David Tolnay7db73692019-10-20 14:51:12 -04006};
David Tolnayc071b892020-03-18 16:59:53 -07007use quote::{format_ident, quote};
Joel Galenson88547732020-05-05 08:23:42 -07008use std::collections::HashSet;
Joel Galenson8ef1bc82020-05-05 08:45:49 -07009use std::u32;
David Tolnaye3a48152020-04-08 19:38:05 -070010use syn::punctuated::Punctuated;
David Tolnay7db73692019-10-20 14:51:12 -040011use syn::{
Joel Galensonc03402a2020-04-23 17:31:09 -070012 Abi, Error, Expr, ExprLit, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
13 GenericArgument, Ident, Item, ItemEnum, ItemForeignMod, ItemStruct, Lit, Pat, PathArguments,
14 Result, ReturnType, Token, Type as RustType, TypeBareFn, TypePath, TypeReference, TypeSlice,
15 Variant as RustVariant,
David Tolnay7db73692019-10-20 14:51:12 -040016};
17
David Tolnaye3a48152020-04-08 19:38:05 -070018pub mod kw {
19 syn::custom_keyword!(Result);
20}
21
David Tolnay52759782020-05-03 23:59:40 -070022pub fn parse_items(cx: &mut Errors, items: Vec<Item>) -> Vec<Api> {
David Tolnay7db73692019-10-20 14:51:12 -040023 let mut apis = Vec::new();
24 for item in items {
25 match item {
David Tolnay52759782020-05-03 23:59:40 -070026 Item::Struct(item) => match parse_struct(item) {
27 Ok(strct) => apis.push(strct),
28 Err(err) => cx.push(err),
29 },
30 Item::Enum(item) => match parse_enum(item) {
31 Ok(enm) => apis.push(enm),
32 Err(err) => cx.push(err),
33 },
34 Item::ForeignMod(foreign_mod) => parse_foreign_mod(cx, foreign_mod, &mut apis),
35 Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
36 _ => cx.error(item, "unsupported item"),
David Tolnay7db73692019-10-20 14:51:12 -040037 }
38 }
David Tolnay52759782020-05-03 23:59:40 -070039 apis
David Tolnay7db73692019-10-20 14:51:12 -040040}
41
42fn parse_struct(item: ItemStruct) -> Result<Api> {
43 let generics = &item.generics;
44 if !generics.params.is_empty() || generics.where_clause.is_some() {
45 let struct_token = item.struct_token;
46 let ident = &item.ident;
47 let where_clause = &generics.where_clause;
48 let span = quote!(#struct_token #ident #generics #where_clause);
49 return Err(Error::new_spanned(
50 span,
51 "struct with generic parameters is not supported yet",
52 ));
53 }
54
55 let mut doc = Doc::new();
56 let mut derives = Vec::new();
57 attrs::parse(&item.attrs, &mut doc, Some(&mut derives))?;
David Tolnay09462ac2020-03-20 14:58:41 -070058
59 let fields = match item.fields {
60 Fields::Named(fields) => fields,
61 Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
62 Fields::Unnamed(_) => {
63 return Err(Error::new_spanned(item, "tuple structs are not supported"))
64 }
65 };
66
67 Ok(Api::Struct(Struct {
68 doc,
69 derives,
70 struct_token: item.struct_token,
71 ident: item.ident,
72 brace_token: fields.brace_token,
73 fields: fields
74 .named
75 .into_iter()
76 .map(|field| {
77 Ok(Var {
78 ident: field.ident.unwrap(),
79 ty: parse_type(&field.ty)?,
David Tolnay7db73692019-10-20 14:51:12 -040080 })
David Tolnay09462ac2020-03-20 14:58:41 -070081 })
82 .collect::<Result<_>>()?,
83 }))
David Tolnay7db73692019-10-20 14:51:12 -040084}
85
Joel Galensonc03402a2020-04-23 17:31:09 -070086fn parse_enum(item: ItemEnum) -> Result<Api> {
87 let generics = &item.generics;
88 if !generics.params.is_empty() || generics.where_clause.is_some() {
89 let enum_token = item.enum_token;
90 let ident = &item.ident;
91 let where_clause = &generics.where_clause;
92 let span = quote!(#enum_token #ident #generics #where_clause);
93 return Err(Error::new_spanned(
94 span,
95 "enums with generic parameters are not allowed",
96 ));
97 }
98
David Tolnayd7984c22020-04-30 20:09:31 -070099 let doc = attrs::parse_doc(&item.attrs)?;
Joel Galensonc03402a2020-04-23 17:31:09 -0700100
Joel Galenson88547732020-05-05 08:23:42 -0700101 let mut variants = Vec::new();
102 let mut discriminants = HashSet::new();
103 let mut prev_discriminant = None;
104 for variant in item.variants {
105 match variant.fields {
Joel Galensonc03402a2020-04-23 17:31:09 -0700106 Fields::Unit => {}
107 _ => {
108 return Err(Error::new_spanned(
109 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700110 "enums with data are not supported yet",
Joel Galenson88547732020-05-05 08:23:42 -0700111 ));
Joel Galensonc03402a2020-04-23 17:31:09 -0700112 }
113 }
David Tolnay4301f3c2020-05-05 10:29:52 -0700114 if variant.discriminant.is_none() && prev_discriminant == Some(u32::MAX) {
David Tolnaya3f64072020-05-05 10:24:24 -0700115 let msg = format!("discriminant overflow on value after {}", u32::MAX);
116 return Err(Error::new_spanned(variant, msg));
Joel Galenson88547732020-05-05 08:23:42 -0700117 }
118 let discriminant =
119 parse_discriminant(&variant)?.unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
120 if !discriminants.insert(discriminant) {
121 let msg = format!("discriminant value `{}` already exists", discriminant);
122 return Err(Error::new_spanned(variant, msg));
123 }
124 variants.push(Variant {
125 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700126 discriminant,
Joel Galenson88547732020-05-05 08:23:42 -0700127 });
128 prev_discriminant = Some(discriminant);
Joel Galensonc03402a2020-04-23 17:31:09 -0700129 }
130
131 Ok(Api::Enum(Enum {
132 doc,
133 enum_token: item.enum_token,
134 ident: item.ident,
135 brace_token: item.brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700136 variants,
Joel Galensonc03402a2020-04-23 17:31:09 -0700137 }))
138}
139
Joel Galenson88547732020-05-05 08:23:42 -0700140fn parse_discriminant(variant: &RustVariant) -> Result<Option<u32>> {
Joel Galensonc03402a2020-04-23 17:31:09 -0700141 match &variant.discriminant {
Joel Galenson88547732020-05-05 08:23:42 -0700142 None => Ok(None),
Joel Galensonc03402a2020-04-23 17:31:09 -0700143 Some((
144 _,
145 Expr::Lit(ExprLit {
146 lit: Lit::Int(n), ..
147 }),
David Tolnayd7984c22020-04-30 20:09:31 -0700148 )) => match n.base10_parse() {
Joel Galenson88547732020-05-05 08:23:42 -0700149 Ok(val) => Ok(Some(val)),
Joel Galensonc03402a2020-04-23 17:31:09 -0700150 Err(_) => Err(Error::new_spanned(
151 variant,
152 "cannot parse enum discriminant as an integer",
153 )),
154 },
155 _ => Err(Error::new_spanned(
156 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700157 "enums with non-integer literal discriminants are not supported yet",
Joel Galensonc03402a2020-04-23 17:31:09 -0700158 )),
159 }
160}
161
David Tolnay52759782020-05-03 23:59:40 -0700162fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
163 let lang = match parse_lang(foreign_mod.abi) {
164 Ok(lang) => lang,
165 Err(err) => return cx.push(err),
166 };
David Tolnay7db73692019-10-20 14:51:12 -0400167
Joel Galensone1e969d2020-04-21 12:50:20 -0700168 let mut items = Vec::new();
169 for foreign in &foreign_mod.items {
170 match foreign {
David Tolnay295ef6b2020-05-07 16:10:22 -0700171 ForeignItem::Type(foreign) => match parse_extern_type(foreign, lang) {
172 Ok(ety) => items.push(ety),
David Tolnay52759782020-05-03 23:59:40 -0700173 Err(err) => cx.push(err),
174 },
175 ForeignItem::Fn(foreign) => match parse_extern_fn(foreign, lang) {
David Tolnay295ef6b2020-05-07 16:10:22 -0700176 Ok(efn) => items.push(efn),
David Tolnay52759782020-05-03 23:59:40 -0700177 Err(err) => cx.push(err),
178 },
David Tolnay7db73692019-10-20 14:51:12 -0400179 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700180 match foreign.mac.parse_body() {
181 Ok(include) => items.push(Api::Include(include)),
182 Err(err) => cx.push(err),
183 }
David Tolnay7db73692019-10-20 14:51:12 -0400184 }
David Tolnay52759782020-05-03 23:59:40 -0700185 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400186 }
187 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700188
189 let mut types = items.iter().filter_map(|item| match item {
190 Api::CxxType(ty) | Api::RustType(ty) => Some(ty),
191 _ => None,
192 });
193 if let (Some(single_type), None) = (types.next(), types.next()) {
194 let single_type = single_type.ident.clone();
195 for item in &mut items {
196 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
197 if let Some(receiver) = &mut efn.receiver {
198 if receiver.ty == "Self" {
199 receiver.ty = single_type.clone();
200 }
201 }
202 }
203 }
204 }
205
David Tolnay52759782020-05-03 23:59:40 -0700206 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400207}
208
209fn parse_lang(abi: Abi) -> Result<Lang> {
210 let name = match &abi.name {
211 Some(name) => name,
212 None => {
213 return Err(Error::new_spanned(
214 abi,
215 "ABI name is required, extern \"C\" or extern \"Rust\"",
216 ));
217 }
218 };
219 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700220 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400221 "Rust" => Ok(Lang::Rust),
222 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
223 }
224}
225
David Tolnay295ef6b2020-05-07 16:10:22 -0700226fn parse_extern_type(foreign_type: &ForeignItemType, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400227 let doc = attrs::parse_doc(&foreign_type.attrs)?;
228 let type_token = foreign_type.type_token;
229 let ident = foreign_type.ident.clone();
David Tolnay295ef6b2020-05-07 16:10:22 -0700230 let api_type = match lang {
231 Lang::Cxx => Api::CxxType,
232 Lang::Rust => Api::RustType,
233 };
234 Ok(api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400235 doc,
236 type_token,
237 ident,
David Tolnay295ef6b2020-05-07 16:10:22 -0700238 }))
David Tolnay7db73692019-10-20 14:51:12 -0400239}
240
David Tolnay295ef6b2020-05-07 16:10:22 -0700241fn parse_extern_fn(foreign_fn: &ForeignItemFn, lang: Lang) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400242 let generics = &foreign_fn.sig.generics;
243 if !generics.params.is_empty() || generics.where_clause.is_some() {
244 return Err(Error::new_spanned(
245 foreign_fn,
246 "extern function with generic parameters is not supported yet",
247 ));
248 }
249 if let Some(variadic) = &foreign_fn.sig.variadic {
250 return Err(Error::new_spanned(
251 variadic,
252 "variadic function is not supported yet",
253 ));
254 }
255
256 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700257 let mut args = Punctuated::new();
258 for arg in foreign_fn.sig.inputs.pairs() {
259 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400260 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700261 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700262 if let Some((ampersand, lifetime)) = &arg.reference {
263 receiver = Some(Receiver {
264 ampersand: *ampersand,
265 lifetime: lifetime.clone(),
266 mutability: arg.mutability,
267 var: arg.self_token,
268 ty: Token![Self](arg.self_token.span).into(),
269 shorthand: true,
270 });
271 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700272 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700273 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400274 }
275 FnArg::Typed(arg) => {
276 let ident = match arg.pat.as_ref() {
277 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700278 Pat::Wild(pat) => {
279 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
280 }
David Tolnay7db73692019-10-20 14:51:12 -0400281 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
282 };
283 let ty = parse_type(&arg.ty)?;
284 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700285 args.push_value(Var { ident, ty });
286 if let Some(comma) = comma {
287 args.push_punct(*comma);
288 }
David Tolnay7db73692019-10-20 14:51:12 -0400289 continue;
290 }
291 if let Type::Ref(reference) = ty {
292 if let Type::Ident(ident) = reference.inner {
293 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700294 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700295 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400296 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700297 var: Token![self](ident.span()),
298 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700299 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400300 });
301 continue;
302 }
303 }
304 return Err(Error::new_spanned(arg, "unsupported method receiver"));
305 }
306 }
307 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700308
David Tolnaye3a48152020-04-08 19:38:05 -0700309 let mut throws_tokens = None;
310 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
311 let throws = throws_tokens.is_some();
David Tolnay7db73692019-10-20 14:51:12 -0400312 let doc = attrs::parse_doc(&foreign_fn.attrs)?;
313 let fn_token = foreign_fn.sig.fn_token;
314 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700315 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400316 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700317 let api_function = match lang {
318 Lang::Cxx => Api::CxxFunction,
319 Lang::Rust => Api::RustFunction,
320 };
David Tolnayd95b1192020-03-18 20:07:46 -0700321
David Tolnay295ef6b2020-05-07 16:10:22 -0700322 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700323 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400324 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400325 ident,
David Tolnay16448732020-03-18 12:39:36 -0700326 sig: Signature {
327 fn_token,
328 receiver,
329 args,
330 ret,
331 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700332 paren_token,
333 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700334 },
David Tolnay7db73692019-10-20 14:51:12 -0400335 semi_token,
David Tolnay295ef6b2020-05-07 16:10:22 -0700336 }))
David Tolnay7db73692019-10-20 14:51:12 -0400337}
338
339fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700340 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700341 RustType::Reference(ty) => parse_type_reference(ty),
342 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700343 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700344 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700345 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
346 _ => Err(Error::new_spanned(ty, "unsupported type")),
347 }
348}
349
350fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
351 let inner = parse_type(&ty.elem)?;
352 let which = match &inner {
353 Type::Ident(ident) if ident == "str" => {
354 if ty.mutability.is_some() {
355 return Err(Error::new_spanned(ty, "unsupported type"));
356 } else {
357 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400358 }
359 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700360 Type::Slice(slice) => match &slice.inner {
361 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
362 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700363 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700364 _ => Type::Ref,
365 };
366 Ok(which(Box::new(Ref {
367 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700368 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700369 mutability: ty.mutability,
370 inner,
371 })))
372}
373
374fn parse_type_path(ty: &TypePath) -> Result<Type> {
375 let path = &ty.path;
376 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
377 let segment = &path.segments[0];
378 let ident = segment.ident.clone();
379 match &segment.arguments {
380 PathArguments::None => return Ok(Type::Ident(ident)),
381 PathArguments::AngleBracketed(generic) => {
382 if ident == "UniquePtr" && generic.args.len() == 1 {
383 if let GenericArgument::Type(arg) = &generic.args[0] {
384 let inner = parse_type(arg)?;
385 return Ok(Type::UniquePtr(Box::new(Ty1 {
386 name: ident,
387 langle: generic.lt_token,
388 inner,
389 rangle: generic.gt_token,
390 })));
391 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700392 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700393 if let GenericArgument::Type(arg) = &generic.args[0] {
394 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700395 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700396 name: ident,
397 langle: generic.lt_token,
398 inner,
399 rangle: generic.gt_token,
400 })));
401 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700402 } else if ident == "Box" && generic.args.len() == 1 {
403 if let GenericArgument::Type(arg) = &generic.args[0] {
404 let inner = parse_type(arg)?;
405 return Ok(Type::RustBox(Box::new(Ty1 {
406 name: ident,
407 langle: generic.lt_token,
408 inner,
409 rangle: generic.gt_token,
410 })));
411 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700412 } else if ident == "Vec" && generic.args.len() == 1 {
413 if let GenericArgument::Type(arg) = &generic.args[0] {
414 let inner = parse_type(arg)?;
415 return Ok(Type::RustVec(Box::new(Ty1 {
416 name: ident,
417 langle: generic.lt_token,
418 inner,
419 rangle: generic.gt_token,
420 })));
421 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700422 }
423 }
424 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700425 }
David Tolnay7db73692019-10-20 14:51:12 -0400426 }
427 Err(Error::new_spanned(ty, "unsupported type"))
428}
429
David Tolnayeebe9b72020-04-14 16:32:18 -0700430fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
431 let inner = parse_type(&ty.elem)?;
432 Ok(Type::Slice(Box::new(Slice {
433 bracket: ty.bracket_token,
434 inner,
435 })))
436}
437
David Tolnayc071b892020-03-18 16:59:53 -0700438fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
439 if ty.lifetimes.is_some() {
440 return Err(Error::new_spanned(
441 ty,
442 "function pointer with lifetime parameters is not supported yet",
443 ));
444 }
445 if ty.variadic.is_some() {
446 return Err(Error::new_spanned(
447 ty,
448 "variadic function pointer is not supported yet",
449 ));
450 }
451 let args = ty
452 .inputs
453 .iter()
454 .enumerate()
455 .map(|(i, arg)| {
456 let ty = parse_type(&arg.ty)?;
457 let ident = match &arg.name {
458 Some(ident) => ident.0.clone(),
459 None => format_ident!("_{}", i),
460 };
461 Ok(Var { ident, ty })
462 })
463 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700464 let mut throws_tokens = None;
465 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
466 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700467 Ok(Type::Fn(Box::new(Signature {
468 fn_token: ty.fn_token,
469 receiver: None,
470 args,
471 ret,
472 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700473 paren_token: ty.paren_token,
474 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700475 })))
476}
477
David Tolnaye3a48152020-04-08 19:38:05 -0700478fn parse_return_type(
479 ty: &ReturnType,
480 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
481) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700482 let mut ret = match ty {
483 ReturnType::Default => return Ok(None),
484 ReturnType::Type(_, ret) => ret.as_ref(),
485 };
486 if let RustType::Path(ty) = ret {
487 let path = &ty.path;
488 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
489 let segment = &path.segments[0];
490 let ident = segment.ident.clone();
491 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
492 if ident == "Result" && generic.args.len() == 1 {
493 if let GenericArgument::Type(arg) = &generic.args[0] {
494 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700495 *throws_tokens =
496 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700497 }
498 }
499 }
500 }
501 }
502 match parse_type(ret)? {
503 Type::Void(_) => Ok(None),
504 ty => Ok(Some(ty)),
505 }
506}