blob: 018e71abb531a0dc15fbb10314dc617553f347dc [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 Tolnayd60c07b2020-10-29 13:18:49 -07007 Namespace, Pair, Receiver, Ref, ResolvableName, Signature, Slice, Struct, Ty1, Type, TypeAlias,
8 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,
18 TypePath, TypeReference, TypeSlice,
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();
129 let mut repr = None;
David Tolnay302b1752020-11-10 18:43:24 -0800130 let mut namespace = namespace.clone();
David Tolnayddf69e22020-05-10 22:08:20 -0700131 attrs::parse(
132 cx,
133 &item.attrs,
134 attrs::Parser {
135 doc: Some(&mut doc),
136 repr: Some(&mut repr),
David Tolnayd7a3a182020-11-01 20:45:14 -0800137 namespace: Some(&mut namespace),
David Tolnayddf69e22020-05-10 22:08:20 -0700138 ..Default::default()
139 },
140 );
Joel Galensonc03402a2020-04-23 17:31:09 -0700141
Joel Galenson88547732020-05-05 08:23:42 -0700142 let mut variants = Vec::new();
David Tolnayddf69e22020-05-10 22:08:20 -0700143 let mut discriminants = DiscriminantSet::new(repr);
Joel Galenson88547732020-05-05 08:23:42 -0700144 for variant in item.variants {
145 match variant.fields {
Joel Galensonc03402a2020-04-23 17:31:09 -0700146 Fields::Unit => {}
147 _ => {
David Tolnay0435a812020-05-10 21:58:15 -0700148 cx.error(variant, "enums with data are not supported yet");
149 break;
Joel Galensonc03402a2020-04-23 17:31:09 -0700150 }
151 }
David Tolnay17e137f2020-05-08 15:55:28 -0700152 let expr = variant.discriminant.as_ref().map(|(_, expr)| expr);
153 let try_discriminant = match &expr {
154 Some(lit) => discriminants.insert(lit),
155 None => discriminants.insert_next(),
156 };
157 let discriminant = match try_discriminant {
158 Ok(discriminant) => discriminant,
David Tolnay0435a812020-05-10 21:58:15 -0700159 Err(err) => {
160 cx.error(variant, err);
161 break;
162 }
David Tolnay17e137f2020-05-08 15:55:28 -0700163 };
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700164 let expr = variant.discriminant.map(|(_, expr)| expr);
Joel Galenson88547732020-05-05 08:23:42 -0700165 variants.push(Variant {
166 ident: variant.ident,
David Tolnay7ae018f2020-05-05 10:11:30 -0700167 discriminant,
David Tolnay2b8bf6d2020-05-10 17:37:16 -0700168 expr,
Joel Galenson88547732020-05-05 08:23:42 -0700169 });
Joel Galensonc03402a2020-04-23 17:31:09 -0700170 }
171
David Tolnaye2e303f2020-05-10 20:52:00 -0700172 let enum_token = item.enum_token;
173 let brace_token = item.brace_token;
174
David Tolnay58eee392020-11-20 20:37:58 -0800175 let explicit_repr = repr.is_some();
David Tolnay0435a812020-05-10 21:58:15 -0700176 let mut repr = U8;
177 match discriminants.inferred_repr() {
178 Ok(inferred) => repr = inferred,
David Tolnaye2e303f2020-05-10 20:52:00 -0700179 Err(err) => {
180 let span = quote_spanned!(brace_token.span=> #enum_token {});
David Tolnay0435a812020-05-10 21:58:15 -0700181 cx.error(span, err);
182 variants.clear();
David Tolnaye2e303f2020-05-10 20:52:00 -0700183 }
David Tolnay0435a812020-05-10 21:58:15 -0700184 }
David Tolnaye2e303f2020-05-10 20:52:00 -0700185
David Tolnay9a69d8a2020-11-16 09:16:41 -0800186 let ident = Ident::new(repr.as_ref(), Span::call_site());
187 let repr_type = Type::Ident(ResolvableName::new(ident));
188
Joel Galensonc03402a2020-04-23 17:31:09 -0700189 Ok(Api::Enum(Enum {
190 doc,
David Tolnaye2e303f2020-05-10 20:52:00 -0700191 enum_token,
David Tolnay17a934c2020-11-02 00:40:04 -0800192 name: Pair::new(namespace, item.ident),
David Tolnaye2e303f2020-05-10 20:52:00 -0700193 brace_token,
David Tolnay7ae018f2020-05-05 10:11:30 -0700194 variants,
David Tolnaye2e303f2020-05-10 20:52:00 -0700195 repr,
David Tolnay9a69d8a2020-11-16 09:16:41 -0800196 repr_type,
David Tolnay58eee392020-11-20 20:37:58 -0800197 explicit_repr,
Joel Galensonc03402a2020-04-23 17:31:09 -0700198 }))
199}
200
David Tolnay805dca32020-08-29 19:09:55 -0700201fn parse_foreign_mod(
202 cx: &mut Errors,
203 foreign_mod: ItemForeignMod,
204 out: &mut Vec<Api>,
205 trusted: bool,
David Tolnayd7a3a182020-11-01 20:45:14 -0800206 namespace: &Namespace,
David Tolnay805dca32020-08-29 19:09:55 -0700207) {
David Tolnay3a451732020-08-29 18:54:55 -0700208 let lang = match parse_lang(&foreign_mod.abi) {
David Tolnay52759782020-05-03 23:59:40 -0700209 Ok(lang) => lang,
210 Err(err) => return cx.push(err),
211 };
David Tolnay7db73692019-10-20 14:51:12 -0400212
David Tolnay3a451732020-08-29 18:54:55 -0700213 match lang {
214 Lang::Rust => {
David Tolnay805dca32020-08-29 19:09:55 -0700215 if foreign_mod.unsafety.is_some() {
David Tolnay3a451732020-08-29 18:54:55 -0700216 let unsafety = foreign_mod.unsafety;
David Tolnay7be5b1f2020-11-11 10:48:32 -0800217 let abi = &foreign_mod.abi;
David Tolnay3a451732020-08-29 18:54:55 -0700218 let span = quote!(#unsafety #abi);
219 cx.error(span, "extern \"Rust\" block does not need to be unsafe");
220 }
221 }
222 Lang::Cxx => {}
223 }
224
David Tolnay805dca32020-08-29 19:09:55 -0700225 let trusted = trusted || foreign_mod.unsafety.is_some();
226
David Tolnay7feb2642020-11-10 18:49:04 -0800227 let mut namespace = namespace.clone();
228 attrs::parse(
229 cx,
230 &foreign_mod.attrs,
231 attrs::Parser {
232 namespace: Some(&mut namespace),
233 ..Default::default()
234 },
235 );
236
Joel Galensone1e969d2020-04-21 12:50:20 -0700237 let mut items = Vec::new();
238 for foreign in &foreign_mod.items {
239 match foreign {
Adrian Taylorc8713432020-10-21 18:20:55 -0700240 ForeignItem::Type(foreign) => {
David Tolnayf5ead102020-11-24 17:08:05 -0800241 let ety = parse_extern_type(cx, foreign, lang, trusted, &namespace);
242 items.push(ety);
Adrian Taylorc8713432020-10-21 18:20:55 -0700243 }
David Tolnay556738d2020-11-15 13:58:44 -0800244 ForeignItem::Fn(foreign) => {
245 match parse_extern_fn(cx, foreign, lang, trusted, &namespace) {
246 Ok(efn) => items.push(efn),
247 Err(err) => cx.push(err),
248 }
249 }
David Tolnay7db73692019-10-20 14:51:12 -0400250 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay91e87fa2020-05-11 19:10:23 -0700251 match foreign.mac.parse_body_with(parse_include) {
David Tolnay52759782020-05-03 23:59:40 -0700252 Ok(include) => items.push(Api::Include(include)),
253 Err(err) => cx.push(err),
254 }
David Tolnay7db73692019-10-20 14:51:12 -0400255 }
Adrian Taylorc8713432020-10-21 18:20:55 -0700256 ForeignItem::Verbatim(tokens) => {
David Tolnay7feb2642020-11-10 18:49:04 -0800257 match parse_extern_verbatim(cx, tokens, lang, &namespace) {
Adrian Taylorc8713432020-10-21 18:20:55 -0700258 Ok(api) => items.push(api),
259 Err(err) => cx.push(err),
260 }
261 }
David Tolnay52759782020-05-03 23:59:40 -0700262 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400263 }
264 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700265
David Tolnay7be5b1f2020-11-11 10:48:32 -0800266 if !trusted
267 && items.iter().any(|api| match api {
268 Api::CxxFunction(efn) => efn.unsafety.is_none(),
269 _ => false,
270 })
271 {
272 cx.error(
273 foreign_mod.abi,
274 "block must be declared `unsafe extern \"C++\"` if it contains any safe-to-call C++ functions",
275 );
276 }
277
David Tolnaya1f29c42020-04-22 18:01:38 -0700278 let mut types = items.iter().filter_map(|item| match item {
David Tolnay17a934c2020-11-02 00:40:04 -0800279 Api::CxxType(ety) | Api::RustType(ety) => Some(&ety.name),
280 Api::TypeAlias(alias) => Some(&alias.name),
David Tolnaya1f29c42020-04-22 18:01:38 -0700281 _ => None,
282 });
283 if let (Some(single_type), None) = (types.next(), types.next()) {
David Tolnaye5a015a2020-05-07 21:54:26 -0700284 let single_type = single_type.clone();
David Tolnaya1f29c42020-04-22 18:01:38 -0700285 for item in &mut items {
286 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
287 if let Some(receiver) = &mut efn.receiver {
Adrian Taylorc8713432020-10-21 18:20:55 -0700288 if receiver.ty.is_self() {
Adrian Taylor565ddf02020-10-29 21:12:36 -0700289 receiver.ty = ResolvableName::new(single_type.rust.clone());
David Tolnaya1f29c42020-04-22 18:01:38 -0700290 }
291 }
292 }
293 }
294 }
295
David Tolnay52759782020-05-03 23:59:40 -0700296 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400297}
298
David Tolnay3a451732020-08-29 18:54:55 -0700299fn parse_lang(abi: &Abi) -> Result<Lang> {
David Tolnay7db73692019-10-20 14:51:12 -0400300 let name = match &abi.name {
301 Some(name) => name,
302 None => {
303 return Err(Error::new_spanned(
304 abi,
David Tolnayc72a9f62020-11-11 10:56:26 -0800305 "ABI name is required, extern \"C++\" or extern \"Rust\"",
David Tolnay7db73692019-10-20 14:51:12 -0400306 ));
307 }
308 };
309 match name.value().as_str() {
David Tolnayea25ac82020-11-11 10:35:23 -0800310 "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400311 "Rust" => Ok(Lang::Rust),
David Tolnay2757ca82020-11-14 15:12:06 -0800312 _ => Err(Error::new_spanned(
313 abi,
314 "unrecognized ABI, requires either \"C++\" or \"Rust\"",
315 )),
David Tolnay7db73692019-10-20 14:51:12 -0400316 }
317}
318
David Tolnay00f236a2020-08-29 19:07:18 -0700319fn parse_extern_type(
320 cx: &mut Errors,
321 foreign_type: &ForeignItemType,
322 lang: Lang,
323 trusted: bool,
David Tolnay302b1752020-11-10 18:43:24 -0800324 namespace: &Namespace,
David Tolnayf5ead102020-11-24 17:08:05 -0800325) -> Api {
Adrian Taylorc8713432020-10-21 18:20:55 -0700326 let mut doc = Doc::new();
David Tolnay302b1752020-11-10 18:43:24 -0800327 let mut namespace = namespace.clone();
Adrian Taylorc8713432020-10-21 18:20:55 -0700328 attrs::parse(
329 cx,
330 &foreign_type.attrs,
331 attrs::Parser {
332 doc: Some(&mut doc),
David Tolnayd7a3a182020-11-01 20:45:14 -0800333 namespace: Some(&mut namespace),
Adrian Taylorc8713432020-10-21 18:20:55 -0700334 ..Default::default()
335 },
336 );
David Tolnay7db73692019-10-20 14:51:12 -0400337 let type_token = foreign_type.type_token;
338 let ident = foreign_type.ident.clone();
David Tolnayc8361022020-08-25 21:57:53 -0700339 let semi_token = foreign_type.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700340 let api_type = match lang {
341 Lang::Cxx => Api::CxxType,
342 Lang::Rust => Api::RustType,
343 };
David Tolnayf5ead102020-11-24 17:08:05 -0800344 api_type(ExternType {
David Tolnay7db73692019-10-20 14:51:12 -0400345 doc,
346 type_token,
David Tolnay17a934c2020-11-02 00:40:04 -0800347 name: Pair::new(namespace, ident),
David Tolnayc8361022020-08-25 21:57:53 -0700348 semi_token,
David Tolnay00f236a2020-08-29 19:07:18 -0700349 trusted,
David Tolnayf5ead102020-11-24 17:08:05 -0800350 })
David Tolnay7db73692019-10-20 14:51:12 -0400351}
352
Adrian Taylorc8713432020-10-21 18:20:55 -0700353fn parse_extern_fn(
354 cx: &mut Errors,
355 foreign_fn: &ForeignItemFn,
356 lang: Lang,
David Tolnay556738d2020-11-15 13:58:44 -0800357 trusted: bool,
David Tolnay302b1752020-11-10 18:43:24 -0800358 namespace: &Namespace,
Adrian Taylorc8713432020-10-21 18:20:55 -0700359) -> Result<Api> {
David Tolnay7db73692019-10-20 14:51:12 -0400360 let generics = &foreign_fn.sig.generics;
David Tolnay9938b642020-11-15 18:11:40 -0800361 if generics.where_clause.is_some()
362 || generics.params.iter().any(|param| match param {
363 GenericParam::Lifetime(lifetime) => !lifetime.bounds.is_empty(),
364 GenericParam::Type(_) | GenericParam::Const(_) => true,
365 })
366 {
David Tolnay7db73692019-10-20 14:51:12 -0400367 return Err(Error::new_spanned(
368 foreign_fn,
369 "extern function with generic parameters is not supported yet",
370 ));
371 }
372 if let Some(variadic) = &foreign_fn.sig.variadic {
373 return Err(Error::new_spanned(
374 variadic,
375 "variadic function is not supported yet",
376 ));
377 }
David Tolnay8de461f2020-11-19 13:46:14 -0800378 if foreign_fn.sig.asyncness.is_some() {
379 return Err(Error::new_spanned(
380 foreign_fn,
381 "async function is not directly supported yet, but see https://cxx.rs/async.html for a working approach",
382 ));
383 }
David Tolnay80ef0682020-11-19 13:56:07 -0800384 if foreign_fn.sig.constness.is_some() {
385 return Err(Error::new_spanned(
386 foreign_fn,
387 "const extern function is not supported",
388 ));
389 }
390 if let Some(abi) = &foreign_fn.sig.abi {
391 return Err(Error::new_spanned(
392 abi,
393 "explicit ABI on extern function is not supported",
394 ));
395 }
David Tolnay7db73692019-10-20 14:51:12 -0400396
David Tolnay938ca852020-10-09 19:25:08 -0700397 let mut doc = Doc::new();
398 let mut cxx_name = None;
399 let mut rust_name = None;
David Tolnay302b1752020-11-10 18:43:24 -0800400 let mut namespace = namespace.clone();
David Tolnay938ca852020-10-09 19:25:08 -0700401 attrs::parse(
402 cx,
403 &foreign_fn.attrs,
404 attrs::Parser {
405 doc: Some(&mut doc),
406 cxx_name: Some(&mut cxx_name),
407 rust_name: Some(&mut rust_name),
David Tolnayd7a3a182020-11-01 20:45:14 -0800408 namespace: Some(&mut namespace),
David Tolnay938ca852020-10-09 19:25:08 -0700409 ..Default::default()
410 },
411 );
412
David Tolnay7db73692019-10-20 14:51:12 -0400413 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700414 let mut args = Punctuated::new();
415 for arg in foreign_fn.sig.inputs.pairs() {
416 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400417 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700418 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700419 if let Some((ampersand, lifetime)) = &arg.reference {
420 receiver = Some(Receiver {
David Tolnay9c76c392020-11-15 16:07:08 -0800421 pinned: false,
David Tolnaya1f29c42020-04-22 18:01:38 -0700422 ampersand: *ampersand,
423 lifetime: lifetime.clone(),
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800424 mutable: arg.mutability.is_some(),
David Tolnaya1f29c42020-04-22 18:01:38 -0700425 var: arg.self_token,
Adrian Taylorc8713432020-10-21 18:20:55 -0700426 ty: ResolvableName::make_self(arg.self_token.span),
David Tolnaya1f29c42020-04-22 18:01:38 -0700427 shorthand: true,
David Tolnay9c76c392020-11-15 16:07:08 -0800428 pin_tokens: None,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800429 mutability: arg.mutability,
David Tolnaya1f29c42020-04-22 18:01:38 -0700430 });
431 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700432 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700433 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400434 }
435 FnArg::Typed(arg) => {
436 let ident = match arg.pat.as_ref() {
437 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700438 Pat::Wild(pat) => {
439 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
440 }
David Tolnay7db73692019-10-20 14:51:12 -0400441 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
442 };
David Tolnay313cc0a2020-11-24 21:47:01 -0800443 let ty = parse_type(&arg.ty)?;
David Tolnay7db73692019-10-20 14:51:12 -0400444 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700445 args.push_value(Var { ident, ty });
446 if let Some(comma) = comma {
447 args.push_punct(*comma);
448 }
David Tolnay7db73692019-10-20 14:51:12 -0400449 continue;
450 }
451 if let Type::Ref(reference) = ty {
452 if let Type::Ident(ident) = reference.inner {
453 receiver = Some(Receiver {
David Tolnay9c76c392020-11-15 16:07:08 -0800454 pinned: reference.pinned,
David Tolnayfb6e3862020-04-20 01:33:23 -0700455 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700456 lifetime: reference.lifetime,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800457 mutable: reference.mutable,
Adrian Taylorc8713432020-10-21 18:20:55 -0700458 var: Token![self](ident.rust.span()),
David Tolnay05e11cc2020-04-20 02:13:56 -0700459 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700460 shorthand: false,
David Tolnay9c76c392020-11-15 16:07:08 -0800461 pin_tokens: reference.pin_tokens,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800462 mutability: reference.mutability,
David Tolnay7db73692019-10-20 14:51:12 -0400463 });
464 continue;
465 }
466 }
467 return Err(Error::new_spanned(arg, "unsupported method receiver"));
468 }
469 }
470 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700471
David Tolnaye3a48152020-04-08 19:38:05 -0700472 let mut throws_tokens = None;
David Tolnay313cc0a2020-11-24 21:47:01 -0800473 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
David Tolnaye3a48152020-04-08 19:38:05 -0700474 let throws = throws_tokens.is_some();
David Tolnaybdb576c2020-09-06 23:45:55 -0700475 let unsafety = foreign_fn.sig.unsafety;
David Tolnay7db73692019-10-20 14:51:12 -0400476 let fn_token = foreign_fn.sig.fn_token;
David Tolnay17a934c2020-11-02 00:40:04 -0800477 let name = Pair::new_from_differing_names(
David Tolnayd7a3a182020-11-01 20:45:14 -0800478 namespace,
Adrian Taylor0f8ab222020-10-29 21:31:56 -0700479 cxx_name.unwrap_or(foreign_fn.sig.ident.clone()),
480 rust_name.unwrap_or(foreign_fn.sig.ident.clone()),
481 );
David Tolnay9938b642020-11-15 18:11:40 -0800482 let generics = generics.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700483 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400484 let semi_token = foreign_fn.semi_token;
David Tolnay295ef6b2020-05-07 16:10:22 -0700485 let api_function = match lang {
486 Lang::Cxx => Api::CxxFunction,
487 Lang::Rust => Api::RustFunction,
488 };
David Tolnayd95b1192020-03-18 20:07:46 -0700489
David Tolnay295ef6b2020-05-07 16:10:22 -0700490 Ok(api_function(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700491 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400492 doc,
David Tolnay17a934c2020-11-02 00:40:04 -0800493 name,
David Tolnay16448732020-03-18 12:39:36 -0700494 sig: Signature {
David Tolnaybdb576c2020-09-06 23:45:55 -0700495 unsafety,
David Tolnay16448732020-03-18 12:39:36 -0700496 fn_token,
David Tolnay9938b642020-11-15 18:11:40 -0800497 generics,
David Tolnay16448732020-03-18 12:39:36 -0700498 receiver,
499 args,
500 ret,
501 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700502 paren_token,
503 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700504 },
David Tolnay7db73692019-10-20 14:51:12 -0400505 semi_token,
David Tolnay556738d2020-11-15 13:58:44 -0800506 trusted,
David Tolnay295ef6b2020-05-07 16:10:22 -0700507 }))
David Tolnay7db73692019-10-20 14:51:12 -0400508}
509
Adrian Taylorc8713432020-10-21 18:20:55 -0700510fn parse_extern_verbatim(
511 cx: &mut Errors,
512 tokens: &TokenStream,
513 lang: Lang,
David Tolnay302b1752020-11-10 18:43:24 -0800514 namespace: &Namespace,
Adrian Taylorc8713432020-10-21 18:20:55 -0700515) -> Result<Api> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700516 // type Alias = crate::path::to::Type;
David Tolnay3e628882020-05-10 15:30:14 -0700517 let parse = |input: ParseStream| -> Result<TypeAlias> {
David Tolnaye2f9ec42020-05-07 16:19:33 -0700518 let attrs = input.call(Attribute::parse_outer)?;
519 let type_token: Token![type] = match input.parse()? {
520 Some(type_token) => type_token,
521 None => {
522 let span = input.cursor().token_stream();
523 return Err(Error::new_spanned(span, "unsupported foreign item"));
524 }
525 };
526 let ident: Ident = input.parse()?;
527 let eq_token: Token![=] = input.parse()?;
528 let ty: RustType = input.parse()?;
529 let semi_token: Token![;] = input.parse()?;
Adrian Taylorc8713432020-10-21 18:20:55 -0700530 let mut doc = Doc::new();
David Tolnay302b1752020-11-10 18:43:24 -0800531 let mut namespace = namespace.clone();
Adrian Taylorc8713432020-10-21 18:20:55 -0700532 attrs::parse(
533 cx,
534 &attrs,
535 attrs::Parser {
536 doc: Some(&mut doc),
David Tolnayd7a3a182020-11-01 20:45:14 -0800537 namespace: Some(&mut namespace),
Adrian Taylorc8713432020-10-21 18:20:55 -0700538 ..Default::default()
539 },
540 );
David Tolnaye2f9ec42020-05-07 16:19:33 -0700541
542 Ok(TypeAlias {
Bryan Henry890083d2020-09-13 10:34:31 -0700543 doc,
David Tolnaye2f9ec42020-05-07 16:19:33 -0700544 type_token,
David Tolnay17a934c2020-11-02 00:40:04 -0800545 name: Pair::new(namespace, ident),
David Tolnaye2f9ec42020-05-07 16:19:33 -0700546 eq_token,
547 ty,
548 semi_token,
549 })
David Tolnay3e628882020-05-10 15:30:14 -0700550 };
David Tolnaye2f9ec42020-05-07 16:19:33 -0700551
552 let type_alias = parse.parse2(tokens.clone())?;
553 match lang {
554 Lang::Cxx => Ok(Api::TypeAlias(type_alias)),
555 Lang::Rust => {
556 let (type_token, semi_token) = (type_alias.type_token, type_alias.semi_token);
557 let span = quote!(#type_token #semi_token);
558 let msg = "type alias in extern \"Rust\" block is not supported";
559 Err(Error::new_spanned(span, msg))
560 }
561 }
562}
563
David Tolnay313cc0a2020-11-24 21:47:01 -0800564fn parse_impl(imp: ItemImpl) -> Result<Api> {
David Tolnay7e69f892020-10-03 22:20:22 -0700565 if !imp.items.is_empty() {
566 let mut span = Group::new(Delimiter::Brace, TokenStream::new());
567 span.set_span(imp.brace_token.span);
568 return Err(Error::new_spanned(span, "expected an empty impl block"));
569 }
570
571 let self_ty = &imp.self_ty;
572 if let Some((bang, path, for_token)) = &imp.trait_ {
573 let span = quote!(#bang #path #for_token #self_ty);
574 return Err(Error::new_spanned(
575 span,
576 "unexpected impl, expected something like `impl UniquePtr<T> {}`",
577 ));
578 }
579
580 let generics = &imp.generics;
581 if !generics.params.is_empty() || generics.where_clause.is_some() {
582 return Err(Error::new_spanned(
583 imp,
584 "generic parameters on an impl is not supported",
585 ));
586 }
587
588 Ok(Api::Impl(Impl {
589 impl_token: imp.impl_token,
David Tolnay313cc0a2020-11-24 21:47:01 -0800590 ty: parse_type(&self_ty)?,
David Tolnay7e69f892020-10-03 22:20:22 -0700591 brace_token: imp.brace_token,
592 }))
593}
594
David Tolnayb0cd3272020-10-27 21:32:54 -0700595fn parse_include(input: ParseStream) -> Result<Include> {
David Tolnay91e87fa2020-05-11 19:10:23 -0700596 if input.peek(LitStr) {
David Tolnayb0cd3272020-10-27 21:32:54 -0700597 let lit: LitStr = input.parse()?;
598 let span = lit.span();
599 return Ok(Include {
600 path: lit.value(),
601 kind: IncludeKind::Quoted,
602 begin_span: span,
603 end_span: span,
604 });
David Tolnay91e87fa2020-05-11 19:10:23 -0700605 }
606
607 if input.peek(Token![<]) {
608 let mut path = String::new();
David Tolnayb0cd3272020-10-27 21:32:54 -0700609
David Tolnay2cc2e3a2020-10-28 13:12:35 -0700610 let langle: Token![<] = input.parse()?;
David Tolnay91e87fa2020-05-11 19:10:23 -0700611 while !input.is_empty() && !input.peek(Token![>]) {
612 let token: TokenTree = input.parse()?;
613 match token {
614 TokenTree::Ident(token) => path += &token.to_string(),
615 TokenTree::Literal(token)
616 if token
617 .to_string()
618 .starts_with(|ch: char| ch.is_ascii_digit()) =>
619 {
620 path += &token.to_string();
621 }
622 TokenTree::Punct(token) => path.push(token.as_char()),
623 _ => return Err(Error::new(token.span(), "unexpected token in include path")),
624 }
625 }
David Tolnayb0cd3272020-10-27 21:32:54 -0700626 let rangle: Token![>] = input.parse()?;
David Tolnayb0cd3272020-10-27 21:32:54 -0700627
628 return Ok(Include {
629 path,
630 kind: IncludeKind::Bracketed,
David Tolnay2cc2e3a2020-10-28 13:12:35 -0700631 begin_span: langle.span,
632 end_span: rangle.span,
David Tolnayb0cd3272020-10-27 21:32:54 -0700633 });
David Tolnay91e87fa2020-05-11 19:10:23 -0700634 }
635
636 Err(input.error("expected \"quoted/path/to\" or <bracketed/path/to>"))
637}
638
David Tolnay313cc0a2020-11-24 21:47:01 -0800639fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700640 match ty {
David Tolnay313cc0a2020-11-24 21:47:01 -0800641 RustType::Reference(ty) => parse_type_reference(ty),
642 RustType::Path(ty) => parse_type_path(ty),
643 RustType::Slice(ty) => parse_type_slice(ty),
644 RustType::Array(ty) => parse_type_array(ty),
645 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700646 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
647 _ => Err(Error::new_spanned(ty, "unsupported type")),
648 }
649}
650
David Tolnay313cc0a2020-11-24 21:47:01 -0800651fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
652 let inner = parse_type(&ty.elem)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700653 let which = match &inner {
Adrian Taylorc8713432020-10-21 18:20:55 -0700654 Type::Ident(ident) if ident.rust == "str" => {
David Tolnayb40b9db2020-03-18 13:50:31 -0700655 if ty.mutability.is_some() {
656 return Err(Error::new_spanned(ty, "unsupported type"));
657 } else {
658 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400659 }
660 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700661 Type::Slice(slice) => match &slice.inner {
David Tolnayc5629f02020-11-23 18:32:46 -0800662 Type::Ident(ident) if ident.rust == U8 => Type::SliceRefU8,
David Tolnayeebe9b72020-04-14 16:32:18 -0700663 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700664 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700665 _ => Type::Ref,
666 };
667 Ok(which(Box::new(Ref {
David Tolnayb27f7872020-11-15 15:07:04 -0800668 pinned: false,
David Tolnayb40b9db2020-03-18 13:50:31 -0700669 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700670 lifetime: ty.lifetime.clone(),
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800671 mutable: ty.mutability.is_some(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700672 inner,
David Tolnayb27f7872020-11-15 15:07:04 -0800673 pin_tokens: None,
David Tolnay9c4ac2e2020-11-15 21:14:03 -0800674 mutability: ty.mutability,
David Tolnayb40b9db2020-03-18 13:50:31 -0700675 })))
676}
677
David Tolnay313cc0a2020-11-24 21:47:01 -0800678fn parse_type_path(ty: &TypePath) -> Result<Type> {
David Tolnayb40b9db2020-03-18 13:50:31 -0700679 let path = &ty.path;
680 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
681 let segment = &path.segments[0];
682 let ident = segment.ident.clone();
683 match &segment.arguments {
David Tolnayda71ef62020-11-02 00:36:00 -0800684 PathArguments::None => return Ok(Type::Ident(ResolvableName::new(ident))),
David Tolnayb40b9db2020-03-18 13:50:31 -0700685 PathArguments::AngleBracketed(generic) => {
686 if ident == "UniquePtr" && generic.args.len() == 1 {
687 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800688 let inner = parse_type(arg)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700689 return Ok(Type::UniquePtr(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800690 name: ident,
David Tolnayb40b9db2020-03-18 13:50:31 -0700691 langle: generic.lt_token,
692 inner,
693 rangle: generic.gt_token,
694 })));
695 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700696 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700697 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800698 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700699 return Ok(Type::CxxVector(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800700 name: ident,
Myron Ahneba35cf2020-02-05 19:41:51 +0700701 langle: generic.lt_token,
702 inner,
703 rangle: generic.gt_token,
704 })));
705 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700706 } else if ident == "Box" && generic.args.len() == 1 {
707 if let GenericArgument::Type(arg) = &generic.args[0] {
David Tolnay313cc0a2020-11-24 21:47:01 -0800708 let inner = parse_type(arg)?;
David Tolnayb40b9db2020-03-18 13:50:31 -0700709 return Ok(Type::RustBox(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800710 name: ident,
David Tolnayb40b9db2020-03-18 13:50:31 -0700711 langle: generic.lt_token,
712 inner,
713 rangle: generic.gt_token,
714 })));
715 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700716 } else if ident == "Vec" && 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)?;
Myron Ahneba35cf2020-02-05 19:41:51 +0700719 return Ok(Type::RustVec(Box::new(Ty1 {
David Tolnayda71ef62020-11-02 00:36:00 -0800720 name: ident,
Myron Ahneba35cf2020-02-05 19:41:51 +0700721 langle: generic.lt_token,
722 inner,
723 rangle: generic.gt_token,
724 })));
725 }
David Tolnaycbc2a4b2020-11-15 15:08:44 -0800726 } else if ident == "Pin" && 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)?;
David Tolnayc94035a2020-11-15 16:49:18 -0800729 let pin_token = kw::Pin(ident.span());
David Tolnaycbc2a4b2020-11-15 15:08:44 -0800730 if let Type::Ref(mut inner) = inner {
David Tolnaycbc2a4b2020-11-15 15:08:44 -0800731 inner.pinned = true;
732 inner.pin_tokens =
733 Some((pin_token, generic.lt_token, generic.gt_token));
734 return Ok(Type::Ref(inner));
735 }
736 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700737 }
738 }
739 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700740 }
David Tolnay7db73692019-10-20 14:51:12 -0400741 }
742 Err(Error::new_spanned(ty, "unsupported type"))
743}
744
David Tolnay313cc0a2020-11-24 21:47:01 -0800745fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
746 let inner = parse_type(&ty.elem)?;
David Tolnayeebe9b72020-04-14 16:32:18 -0700747 Ok(Type::Slice(Box::new(Slice {
748 bracket: ty.bracket_token,
749 inner,
750 })))
751}
752
David Tolnay313cc0a2020-11-24 21:47:01 -0800753fn parse_type_array(ty: &TypeArray) -> Result<Type> {
754 let inner = parse_type(&ty.elem)?;
David Tolnayd9f97842020-11-24 21:00:05 -0800755
756 let len_expr = if let Expr::Lit(lit) = &ty.len {
757 lit
758 } else {
759 let msg = "unsupported expression, array length must be an integer literal";
760 return Err(Error::new_spanned(&ty.len, msg));
761 };
762
763 let len_token = if let Lit::Int(int) = &len_expr.lit {
764 int.clone()
765 } else {
766 let msg = "array length must be an integer literal";
767 return Err(Error::new_spanned(len_expr, msg));
768 };
769
David Tolnay581f72d2020-11-25 15:48:59 -0800770 let len = len_token.base10_parse::<usize>()?;
771 if len == 0 {
772 let msg = "array with zero size is not supported";
773 return Err(Error::new_spanned(ty, msg));
774 }
775
David Tolnayd9f97842020-11-24 21:00:05 -0800776 let bracket = ty.bracket_token;
777 let semi_token = ty.semi_token;
David Tolnayd9f97842020-11-24 21:00:05 -0800778
779 Ok(Type::Array(Box::new(Array {
780 bracket,
781 inner,
782 semi_token,
783 len,
784 len_token,
785 })))
David Tolnay2d0df232020-11-24 20:50:32 -0800786}
787
David Tolnay313cc0a2020-11-24 21:47:01 -0800788fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
David Tolnayc071b892020-03-18 16:59:53 -0700789 if ty.lifetimes.is_some() {
790 return Err(Error::new_spanned(
791 ty,
792 "function pointer with lifetime parameters is not supported yet",
793 ));
794 }
795 if ty.variadic.is_some() {
796 return Err(Error::new_spanned(
797 ty,
798 "variadic function pointer is not supported yet",
799 ));
800 }
801 let args = ty
802 .inputs
803 .iter()
804 .enumerate()
805 .map(|(i, arg)| {
David Tolnay313cc0a2020-11-24 21:47:01 -0800806 let ty = parse_type(&arg.ty)?;
David Tolnayc071b892020-03-18 16:59:53 -0700807 let ident = match &arg.name {
808 Some(ident) => ident.0.clone(),
809 None => format_ident!("_{}", i),
810 };
811 Ok(Var { ident, ty })
812 })
813 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700814 let mut throws_tokens = None;
David Tolnay313cc0a2020-11-24 21:47:01 -0800815 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
David Tolnaye3a48152020-04-08 19:38:05 -0700816 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700817 Ok(Type::Fn(Box::new(Signature {
David Tolnaybdb576c2020-09-06 23:45:55 -0700818 unsafety: ty.unsafety,
David Tolnayc071b892020-03-18 16:59:53 -0700819 fn_token: ty.fn_token,
David Tolnay9938b642020-11-15 18:11:40 -0800820 generics: Generics::default(),
David Tolnayc071b892020-03-18 16:59:53 -0700821 receiver: None,
822 args,
823 ret,
824 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700825 paren_token: ty.paren_token,
826 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700827 })))
828}
829
David Tolnaye3a48152020-04-08 19:38:05 -0700830fn parse_return_type(
831 ty: &ReturnType,
832 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
833) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700834 let mut ret = match ty {
835 ReturnType::Default => return Ok(None),
836 ReturnType::Type(_, ret) => ret.as_ref(),
837 };
838 if let RustType::Path(ty) = ret {
839 let path = &ty.path;
840 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
841 let segment = &path.segments[0];
842 let ident = segment.ident.clone();
843 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
844 if ident == "Result" && generic.args.len() == 1 {
845 if let GenericArgument::Type(arg) = &generic.args[0] {
846 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700847 *throws_tokens =
848 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700849 }
850 }
851 }
852 }
853 }
David Tolnay313cc0a2020-11-24 21:47:01 -0800854 match parse_type(ret)? {
David Tolnayc071b892020-03-18 16:59:53 -0700855 Type::Void(_) => Ok(None),
856 ty => Ok(Some(ty)),
857 }
858}