blob: 1f6cbac8e903f01b2ea53dd12eeb60d60617b8ac [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 }
Joel Galenson88547732020-05-05 08:23:42 -0700114 if variant.discriminant.is_none() && prev_discriminant.unwrap_or(0) == u32::MAX {
115 return Err(Error::new_spanned(variant, "overflowed on value"));
116 }
117 let discriminant =
118 parse_discriminant(&variant)?.unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
119 if !discriminants.insert(discriminant) {
120 let msg = format!("discriminant value `{}` already exists", discriminant);
121 return Err(Error::new_spanned(variant, msg));
122 }
123 variants.push(Variant {
124 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700125 discriminant,
Joel Galenson88547732020-05-05 08:23:42 -0700126 });
127 prev_discriminant = Some(discriminant);
Joel Galensonc03402a2020-04-23 17:31:09 -0700128 }
129
130 Ok(Api::Enum(Enum {
131 doc,
132 enum_token: item.enum_token,
133 ident: item.ident,
134 brace_token: item.brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700135 variants,
Joel Galensonc03402a2020-04-23 17:31:09 -0700136 }))
137}
138
Joel Galenson88547732020-05-05 08:23:42 -0700139fn parse_discriminant(variant: &RustVariant) -> Result<Option<u32>> {
Joel Galensonc03402a2020-04-23 17:31:09 -0700140 match &variant.discriminant {
Joel Galenson88547732020-05-05 08:23:42 -0700141 None => Ok(None),
Joel Galensonc03402a2020-04-23 17:31:09 -0700142 Some((
143 _,
144 Expr::Lit(ExprLit {
145 lit: Lit::Int(n), ..
146 }),
David Tolnayd7984c22020-04-30 20:09:31 -0700147 )) => match n.base10_parse() {
Joel Galenson88547732020-05-05 08:23:42 -0700148 Ok(val) => Ok(Some(val)),
Joel Galensonc03402a2020-04-23 17:31:09 -0700149 Err(_) => Err(Error::new_spanned(
150 variant,
151 "cannot parse enum discriminant as an integer",
152 )),
153 },
154 _ => Err(Error::new_spanned(
155 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700156 "enums with non-integer literal discriminants are not supported yet",
Joel Galensonc03402a2020-04-23 17:31:09 -0700157 )),
158 }
159}
160
David Tolnay52759782020-05-03 23:59:40 -0700161fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
162 let lang = match parse_lang(foreign_mod.abi) {
163 Ok(lang) => lang,
164 Err(err) => return cx.push(err),
165 };
David Tolnay7db73692019-10-20 14:51:12 -0400166 let api_type = match lang {
167 Lang::Cxx => Api::CxxType,
168 Lang::Rust => Api::RustType,
169 };
170 let api_function = match lang {
171 Lang::Cxx => Api::CxxFunction,
172 Lang::Rust => Api::RustFunction,
173 };
174
Joel Galensone1e969d2020-04-21 12:50:20 -0700175 let mut items = Vec::new();
176 for foreign in &foreign_mod.items {
177 match foreign {
David Tolnay52759782020-05-03 23:59:40 -0700178 ForeignItem::Type(foreign) => match parse_extern_type(foreign) {
179 Ok(ety) => items.push(api_type(ety)),
180 Err(err) => cx.push(err),
181 },
182 ForeignItem::Fn(foreign) => match parse_extern_fn(foreign, lang) {
183 Ok(efn) => items.push(api_function(efn)),
184 Err(err) => cx.push(err),
185 },
David Tolnay7db73692019-10-20 14:51:12 -0400186 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700187 match foreign.mac.parse_body() {
188 Ok(include) => items.push(Api::Include(include)),
189 Err(err) => cx.push(err),
190 }
David Tolnay7db73692019-10-20 14:51:12 -0400191 }
David Tolnay52759782020-05-03 23:59:40 -0700192 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400193 }
194 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700195
196 let mut types = items.iter().filter_map(|item| match item {
197 Api::CxxType(ty) | Api::RustType(ty) => Some(ty),
198 _ => None,
199 });
200 if let (Some(single_type), None) = (types.next(), types.next()) {
201 let single_type = single_type.ident.clone();
202 for item in &mut items {
203 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
204 if let Some(receiver) = &mut efn.receiver {
205 if receiver.ty == "Self" {
206 receiver.ty = single_type.clone();
207 }
208 }
209 }
210 }
211 }
212
David Tolnay52759782020-05-03 23:59:40 -0700213 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400214}
215
216fn parse_lang(abi: Abi) -> Result<Lang> {
217 let name = match &abi.name {
218 Some(name) => name,
219 None => {
220 return Err(Error::new_spanned(
221 abi,
222 "ABI name is required, extern \"C\" or extern \"Rust\"",
223 ));
224 }
225 };
226 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700227 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400228 "Rust" => Ok(Lang::Rust),
229 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
230 }
231}
232
233fn parse_extern_type(foreign_type: &ForeignItemType) -> Result<ExternType> {
234 let doc = attrs::parse_doc(&foreign_type.attrs)?;
235 let type_token = foreign_type.type_token;
236 let ident = foreign_type.ident.clone();
237 Ok(ExternType {
238 doc,
239 type_token,
240 ident,
241 })
242}
243
David Tolnaya1f29c42020-04-22 18:01:38 -0700244fn parse_extern_fn(foreign_fn: &ForeignItemFn, lang: Lang) -> Result<ExternFn> {
David Tolnay7db73692019-10-20 14:51:12 -0400245 let generics = &foreign_fn.sig.generics;
246 if !generics.params.is_empty() || generics.where_clause.is_some() {
247 return Err(Error::new_spanned(
248 foreign_fn,
249 "extern function with generic parameters is not supported yet",
250 ));
251 }
252 if let Some(variadic) = &foreign_fn.sig.variadic {
253 return Err(Error::new_spanned(
254 variadic,
255 "variadic function is not supported yet",
256 ));
257 }
258
259 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700260 let mut args = Punctuated::new();
261 for arg in foreign_fn.sig.inputs.pairs() {
262 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400263 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700264 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700265 if let Some((ampersand, lifetime)) = &arg.reference {
266 receiver = Some(Receiver {
267 ampersand: *ampersand,
268 lifetime: lifetime.clone(),
269 mutability: arg.mutability,
270 var: arg.self_token,
271 ty: Token![Self](arg.self_token.span).into(),
272 shorthand: true,
273 });
274 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700275 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700276 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400277 }
278 FnArg::Typed(arg) => {
279 let ident = match arg.pat.as_ref() {
280 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700281 Pat::Wild(pat) => {
282 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
283 }
David Tolnay7db73692019-10-20 14:51:12 -0400284 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
285 };
286 let ty = parse_type(&arg.ty)?;
287 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700288 args.push_value(Var { ident, ty });
289 if let Some(comma) = comma {
290 args.push_punct(*comma);
291 }
David Tolnay7db73692019-10-20 14:51:12 -0400292 continue;
293 }
294 if let Type::Ref(reference) = ty {
295 if let Type::Ident(ident) = reference.inner {
296 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700297 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700298 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400299 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700300 var: Token![self](ident.span()),
301 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700302 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400303 });
304 continue;
305 }
306 }
307 return Err(Error::new_spanned(arg, "unsupported method receiver"));
308 }
309 }
310 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700311
David Tolnaye3a48152020-04-08 19:38:05 -0700312 let mut throws_tokens = None;
313 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
314 let throws = throws_tokens.is_some();
David Tolnay7db73692019-10-20 14:51:12 -0400315 let doc = attrs::parse_doc(&foreign_fn.attrs)?;
316 let fn_token = foreign_fn.sig.fn_token;
317 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700318 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400319 let semi_token = foreign_fn.semi_token;
David Tolnayd95b1192020-03-18 20:07:46 -0700320
David Tolnay7db73692019-10-20 14:51:12 -0400321 Ok(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700322 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400323 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400324 ident,
David Tolnay16448732020-03-18 12:39:36 -0700325 sig: Signature {
326 fn_token,
327 receiver,
328 args,
329 ret,
330 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700331 paren_token,
332 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700333 },
David Tolnay7db73692019-10-20 14:51:12 -0400334 semi_token,
335 })
336}
337
338fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700339 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700340 RustType::Reference(ty) => parse_type_reference(ty),
341 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700342 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700343 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700344 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
345 _ => Err(Error::new_spanned(ty, "unsupported type")),
346 }
347}
348
349fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
350 let inner = parse_type(&ty.elem)?;
351 let which = match &inner {
352 Type::Ident(ident) if ident == "str" => {
353 if ty.mutability.is_some() {
354 return Err(Error::new_spanned(ty, "unsupported type"));
355 } else {
356 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400357 }
358 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700359 Type::Slice(slice) => match &slice.inner {
360 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
361 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700362 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700363 _ => Type::Ref,
364 };
365 Ok(which(Box::new(Ref {
366 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700367 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700368 mutability: ty.mutability,
369 inner,
370 })))
371}
372
373fn parse_type_path(ty: &TypePath) -> Result<Type> {
374 let path = &ty.path;
375 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
376 let segment = &path.segments[0];
377 let ident = segment.ident.clone();
378 match &segment.arguments {
379 PathArguments::None => return Ok(Type::Ident(ident)),
380 PathArguments::AngleBracketed(generic) => {
381 if ident == "UniquePtr" && generic.args.len() == 1 {
382 if let GenericArgument::Type(arg) = &generic.args[0] {
383 let inner = parse_type(arg)?;
384 return Ok(Type::UniquePtr(Box::new(Ty1 {
385 name: ident,
386 langle: generic.lt_token,
387 inner,
388 rangle: generic.gt_token,
389 })));
390 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700391 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700392 if let GenericArgument::Type(arg) = &generic.args[0] {
393 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700394 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700395 name: ident,
396 langle: generic.lt_token,
397 inner,
398 rangle: generic.gt_token,
399 })));
400 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700401 } else if ident == "Box" && generic.args.len() == 1 {
402 if let GenericArgument::Type(arg) = &generic.args[0] {
403 let inner = parse_type(arg)?;
404 return Ok(Type::RustBox(Box::new(Ty1 {
405 name: ident,
406 langle: generic.lt_token,
407 inner,
408 rangle: generic.gt_token,
409 })));
410 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700411 } else if ident == "Vec" && generic.args.len() == 1 {
412 if let GenericArgument::Type(arg) = &generic.args[0] {
413 let inner = parse_type(arg)?;
414 return Ok(Type::RustVec(Box::new(Ty1 {
415 name: ident,
416 langle: generic.lt_token,
417 inner,
418 rangle: generic.gt_token,
419 })));
420 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700421 }
422 }
423 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700424 }
David Tolnay7db73692019-10-20 14:51:12 -0400425 }
426 Err(Error::new_spanned(ty, "unsupported type"))
427}
428
David Tolnayeebe9b72020-04-14 16:32:18 -0700429fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
430 let inner = parse_type(&ty.elem)?;
431 Ok(Type::Slice(Box::new(Slice {
432 bracket: ty.bracket_token,
433 inner,
434 })))
435}
436
David Tolnayc071b892020-03-18 16:59:53 -0700437fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
438 if ty.lifetimes.is_some() {
439 return Err(Error::new_spanned(
440 ty,
441 "function pointer with lifetime parameters is not supported yet",
442 ));
443 }
444 if ty.variadic.is_some() {
445 return Err(Error::new_spanned(
446 ty,
447 "variadic function pointer is not supported yet",
448 ));
449 }
450 let args = ty
451 .inputs
452 .iter()
453 .enumerate()
454 .map(|(i, arg)| {
455 let ty = parse_type(&arg.ty)?;
456 let ident = match &arg.name {
457 Some(ident) => ident.0.clone(),
458 None => format_ident!("_{}", i),
459 };
460 Ok(Var { ident, ty })
461 })
462 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700463 let mut throws_tokens = None;
464 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
465 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700466 Ok(Type::Fn(Box::new(Signature {
467 fn_token: ty.fn_token,
468 receiver: None,
469 args,
470 ret,
471 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700472 paren_token: ty.paren_token,
473 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700474 })))
475}
476
David Tolnaye3a48152020-04-08 19:38:05 -0700477fn parse_return_type(
478 ty: &ReturnType,
479 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
480) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700481 let mut ret = match ty {
482 ReturnType::Default => return Ok(None),
483 ReturnType::Type(_, ret) => ret.as_ref(),
484 };
485 if let RustType::Path(ty) = ret {
486 let path = &ty.path;
487 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
488 let segment = &path.segments[0];
489 let ident = segment.ident.clone();
490 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
491 if ident == "Result" && generic.args.len() == 1 {
492 if let GenericArgument::Type(arg) = &generic.args[0] {
493 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700494 *throws_tokens =
495 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700496 }
497 }
498 }
499 }
500 }
501 match parse_type(ret)? {
502 Type::Void(_) => Ok(None),
503 ty => Ok(Some(ty)),
504 }
505}