blob: 602a269bb827be32e2ecfd7ac97854c5654c7887 [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 let api_type = match lang {
168 Lang::Cxx => Api::CxxType,
169 Lang::Rust => Api::RustType,
170 };
171 let api_function = match lang {
172 Lang::Cxx => Api::CxxFunction,
173 Lang::Rust => Api::RustFunction,
174 };
175
Joel Galensone1e969d2020-04-21 12:50:20 -0700176 let mut items = Vec::new();
177 for foreign in &foreign_mod.items {
178 match foreign {
David Tolnay52759782020-05-03 23:59:40 -0700179 ForeignItem::Type(foreign) => match parse_extern_type(foreign) {
180 Ok(ety) => items.push(api_type(ety)),
181 Err(err) => cx.push(err),
182 },
183 ForeignItem::Fn(foreign) => match parse_extern_fn(foreign, lang) {
184 Ok(efn) => items.push(api_function(efn)),
185 Err(err) => cx.push(err),
186 },
David Tolnay7db73692019-10-20 14:51:12 -0400187 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700188 match foreign.mac.parse_body() {
189 Ok(include) => items.push(Api::Include(include)),
190 Err(err) => cx.push(err),
191 }
David Tolnay7db73692019-10-20 14:51:12 -0400192 }
David Tolnay52759782020-05-03 23:59:40 -0700193 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400194 }
195 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700196
197 let mut types = items.iter().filter_map(|item| match item {
198 Api::CxxType(ty) | Api::RustType(ty) => Some(ty),
199 _ => None,
200 });
201 if let (Some(single_type), None) = (types.next(), types.next()) {
202 let single_type = single_type.ident.clone();
203 for item in &mut items {
204 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
205 if let Some(receiver) = &mut efn.receiver {
206 if receiver.ty == "Self" {
207 receiver.ty = single_type.clone();
208 }
209 }
210 }
211 }
212 }
213
David Tolnay52759782020-05-03 23:59:40 -0700214 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400215}
216
217fn parse_lang(abi: Abi) -> Result<Lang> {
218 let name = match &abi.name {
219 Some(name) => name,
220 None => {
221 return Err(Error::new_spanned(
222 abi,
223 "ABI name is required, extern \"C\" or extern \"Rust\"",
224 ));
225 }
226 };
227 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700228 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400229 "Rust" => Ok(Lang::Rust),
230 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
231 }
232}
233
234fn parse_extern_type(foreign_type: &ForeignItemType) -> Result<ExternType> {
235 let doc = attrs::parse_doc(&foreign_type.attrs)?;
236 let type_token = foreign_type.type_token;
237 let ident = foreign_type.ident.clone();
238 Ok(ExternType {
239 doc,
240 type_token,
241 ident,
242 })
243}
244
David Tolnaya1f29c42020-04-22 18:01:38 -0700245fn parse_extern_fn(foreign_fn: &ForeignItemFn, lang: Lang) -> Result<ExternFn> {
David Tolnay7db73692019-10-20 14:51:12 -0400246 let generics = &foreign_fn.sig.generics;
247 if !generics.params.is_empty() || generics.where_clause.is_some() {
248 return Err(Error::new_spanned(
249 foreign_fn,
250 "extern function with generic parameters is not supported yet",
251 ));
252 }
253 if let Some(variadic) = &foreign_fn.sig.variadic {
254 return Err(Error::new_spanned(
255 variadic,
256 "variadic function is not supported yet",
257 ));
258 }
259
260 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700261 let mut args = Punctuated::new();
262 for arg in foreign_fn.sig.inputs.pairs() {
263 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400264 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700265 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700266 if let Some((ampersand, lifetime)) = &arg.reference {
267 receiver = Some(Receiver {
268 ampersand: *ampersand,
269 lifetime: lifetime.clone(),
270 mutability: arg.mutability,
271 var: arg.self_token,
272 ty: Token![Self](arg.self_token.span).into(),
273 shorthand: true,
274 });
275 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700276 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700277 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400278 }
279 FnArg::Typed(arg) => {
280 let ident = match arg.pat.as_ref() {
281 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700282 Pat::Wild(pat) => {
283 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
284 }
David Tolnay7db73692019-10-20 14:51:12 -0400285 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
286 };
287 let ty = parse_type(&arg.ty)?;
288 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700289 args.push_value(Var { ident, ty });
290 if let Some(comma) = comma {
291 args.push_punct(*comma);
292 }
David Tolnay7db73692019-10-20 14:51:12 -0400293 continue;
294 }
295 if let Type::Ref(reference) = ty {
296 if let Type::Ident(ident) = reference.inner {
297 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700298 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700299 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400300 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700301 var: Token![self](ident.span()),
302 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700303 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400304 });
305 continue;
306 }
307 }
308 return Err(Error::new_spanned(arg, "unsupported method receiver"));
309 }
310 }
311 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700312
David Tolnaye3a48152020-04-08 19:38:05 -0700313 let mut throws_tokens = None;
314 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
315 let throws = throws_tokens.is_some();
David Tolnay7db73692019-10-20 14:51:12 -0400316 let doc = attrs::parse_doc(&foreign_fn.attrs)?;
317 let fn_token = foreign_fn.sig.fn_token;
318 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700319 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400320 let semi_token = foreign_fn.semi_token;
David Tolnayd95b1192020-03-18 20:07:46 -0700321
David Tolnay7db73692019-10-20 14:51:12 -0400322 Ok(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,
336 })
337}
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}