blob: fc51ee91033988619bb3e795b369c117fdfe1fef [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;
David Tolnaye3a48152020-04-08 19:38:05 -07009use syn::punctuated::Punctuated;
David Tolnay7db73692019-10-20 14:51:12 -040010use syn::{
Joel Galensonc03402a2020-04-23 17:31:09 -070011 Abi, Error, Expr, ExprLit, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
12 GenericArgument, Ident, Item, ItemEnum, ItemForeignMod, ItemStruct, Lit, Pat, PathArguments,
13 Result, ReturnType, Token, Type as RustType, TypeBareFn, TypePath, TypeReference, TypeSlice,
14 Variant as RustVariant,
David Tolnay7db73692019-10-20 14:51:12 -040015};
16
David Tolnaye3a48152020-04-08 19:38:05 -070017pub mod kw {
18 syn::custom_keyword!(Result);
19}
20
David Tolnay52759782020-05-03 23:59:40 -070021pub fn parse_items(cx: &mut Errors, items: Vec<Item>) -> Vec<Api> {
David Tolnay7db73692019-10-20 14:51:12 -040022 let mut apis = Vec::new();
23 for item in items {
24 match item {
David Tolnay52759782020-05-03 23:59:40 -070025 Item::Struct(item) => match parse_struct(item) {
26 Ok(strct) => apis.push(strct),
27 Err(err) => cx.push(err),
28 },
29 Item::Enum(item) => match parse_enum(item) {
30 Ok(enm) => apis.push(enm),
31 Err(err) => cx.push(err),
32 },
33 Item::ForeignMod(foreign_mod) => parse_foreign_mod(cx, foreign_mod, &mut apis),
34 Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
35 _ => cx.error(item, "unsupported item"),
David Tolnay7db73692019-10-20 14:51:12 -040036 }
37 }
David Tolnay52759782020-05-03 23:59:40 -070038 apis
David Tolnay7db73692019-10-20 14:51:12 -040039}
40
41fn parse_struct(item: ItemStruct) -> Result<Api> {
42 let generics = &item.generics;
43 if !generics.params.is_empty() || generics.where_clause.is_some() {
44 let struct_token = item.struct_token;
45 let ident = &item.ident;
46 let where_clause = &generics.where_clause;
47 let span = quote!(#struct_token #ident #generics #where_clause);
48 return Err(Error::new_spanned(
49 span,
50 "struct with generic parameters is not supported yet",
51 ));
52 }
53
54 let mut doc = Doc::new();
55 let mut derives = Vec::new();
56 attrs::parse(&item.attrs, &mut doc, Some(&mut derives))?;
David Tolnay09462ac2020-03-20 14:58:41 -070057
58 let fields = match item.fields {
59 Fields::Named(fields) => fields,
60 Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
61 Fields::Unnamed(_) => {
62 return Err(Error::new_spanned(item, "tuple structs are not supported"))
63 }
64 };
65
66 Ok(Api::Struct(Struct {
67 doc,
68 derives,
69 struct_token: item.struct_token,
70 ident: item.ident,
71 brace_token: fields.brace_token,
72 fields: fields
73 .named
74 .into_iter()
75 .map(|field| {
76 Ok(Var {
77 ident: field.ident.unwrap(),
78 ty: parse_type(&field.ty)?,
David Tolnay7db73692019-10-20 14:51:12 -040079 })
David Tolnay09462ac2020-03-20 14:58:41 -070080 })
81 .collect::<Result<_>>()?,
82 }))
David Tolnay7db73692019-10-20 14:51:12 -040083}
84
Joel Galensonc03402a2020-04-23 17:31:09 -070085fn parse_enum(item: ItemEnum) -> Result<Api> {
86 let generics = &item.generics;
87 if !generics.params.is_empty() || generics.where_clause.is_some() {
88 let enum_token = item.enum_token;
89 let ident = &item.ident;
90 let where_clause = &generics.where_clause;
91 let span = quote!(#enum_token #ident #generics #where_clause);
92 return Err(Error::new_spanned(
93 span,
94 "enums with generic parameters are not allowed",
95 ));
96 }
97
David Tolnayd7984c22020-04-30 20:09:31 -070098 let doc = attrs::parse_doc(&item.attrs)?;
Joel Galensonc03402a2020-04-23 17:31:09 -070099
Joel Galenson88547732020-05-05 08:23:42 -0700100 let mut variants = Vec::new();
101 let mut discriminants = HashSet::new();
102 let mut prev_discriminant = None;
103 for variant in item.variants {
104 match variant.fields {
Joel Galensonc03402a2020-04-23 17:31:09 -0700105 Fields::Unit => {}
106 _ => {
107 return Err(Error::new_spanned(
108 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700109 "enums with data are not supported yet",
Joel Galenson88547732020-05-05 08:23:42 -0700110 ));
Joel Galensonc03402a2020-04-23 17:31:09 -0700111 }
112 }
Joel Galenson88547732020-05-05 08:23:42 -0700113 if variant.discriminant.is_none() && prev_discriminant.unwrap_or(0) == u32::MAX {
114 return Err(Error::new_spanned(variant, "overflowed on value"));
115 }
116 let discriminant =
117 parse_discriminant(&variant)?.unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
118 if !discriminants.insert(discriminant) {
119 let msg = format!("discriminant value `{}` already exists", discriminant);
120 return Err(Error::new_spanned(variant, msg));
121 }
122 variants.push(Variant {
123 ident: variant.ident,
124 discriminant: discriminant,
125 });
126 prev_discriminant = Some(discriminant);
Joel Galensonc03402a2020-04-23 17:31:09 -0700127 }
128
129 Ok(Api::Enum(Enum {
130 doc,
131 enum_token: item.enum_token,
132 ident: item.ident,
133 brace_token: item.brace_token,
Joel Galenson88547732020-05-05 08:23:42 -0700134 variants: variants,
Joel Galensonc03402a2020-04-23 17:31:09 -0700135 }))
136}
137
Joel Galenson88547732020-05-05 08:23:42 -0700138fn parse_discriminant(variant: &RustVariant) -> Result<Option<u32>> {
Joel Galensonc03402a2020-04-23 17:31:09 -0700139 match &variant.discriminant {
Joel Galenson88547732020-05-05 08:23:42 -0700140 None => Ok(None),
Joel Galensonc03402a2020-04-23 17:31:09 -0700141 Some((
142 _,
143 Expr::Lit(ExprLit {
144 lit: Lit::Int(n), ..
145 }),
David Tolnayd7984c22020-04-30 20:09:31 -0700146 )) => match n.base10_parse() {
Joel Galenson88547732020-05-05 08:23:42 -0700147 Ok(val) => Ok(Some(val)),
Joel Galensonc03402a2020-04-23 17:31:09 -0700148 Err(_) => Err(Error::new_spanned(
149 variant,
150 "cannot parse enum discriminant as an integer",
151 )),
152 },
153 _ => Err(Error::new_spanned(
154 variant,
David Tolnayd7984c22020-04-30 20:09:31 -0700155 "enums with non-integer literal discriminants are not supported yet",
Joel Galensonc03402a2020-04-23 17:31:09 -0700156 )),
157 }
158}
159
David Tolnay52759782020-05-03 23:59:40 -0700160fn parse_foreign_mod(cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>) {
161 let lang = match parse_lang(foreign_mod.abi) {
162 Ok(lang) => lang,
163 Err(err) => return cx.push(err),
164 };
David Tolnay7db73692019-10-20 14:51:12 -0400165 let api_type = match lang {
166 Lang::Cxx => Api::CxxType,
167 Lang::Rust => Api::RustType,
168 };
169 let api_function = match lang {
170 Lang::Cxx => Api::CxxFunction,
171 Lang::Rust => Api::RustFunction,
172 };
173
Joel Galensone1e969d2020-04-21 12:50:20 -0700174 let mut items = Vec::new();
175 for foreign in &foreign_mod.items {
176 match foreign {
David Tolnay52759782020-05-03 23:59:40 -0700177 ForeignItem::Type(foreign) => match parse_extern_type(foreign) {
178 Ok(ety) => items.push(api_type(ety)),
179 Err(err) => cx.push(err),
180 },
181 ForeignItem::Fn(foreign) => match parse_extern_fn(foreign, lang) {
182 Ok(efn) => items.push(api_function(efn)),
183 Err(err) => cx.push(err),
184 },
David Tolnay7db73692019-10-20 14:51:12 -0400185 ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
David Tolnay52759782020-05-03 23:59:40 -0700186 match foreign.mac.parse_body() {
187 Ok(include) => items.push(Api::Include(include)),
188 Err(err) => cx.push(err),
189 }
David Tolnay7db73692019-10-20 14:51:12 -0400190 }
David Tolnay52759782020-05-03 23:59:40 -0700191 _ => cx.error(foreign, "unsupported foreign item"),
David Tolnay7db73692019-10-20 14:51:12 -0400192 }
193 }
David Tolnaya1f29c42020-04-22 18:01:38 -0700194
195 let mut types = items.iter().filter_map(|item| match item {
196 Api::CxxType(ty) | Api::RustType(ty) => Some(ty),
197 _ => None,
198 });
199 if let (Some(single_type), None) = (types.next(), types.next()) {
200 let single_type = single_type.ident.clone();
201 for item in &mut items {
202 if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
203 if let Some(receiver) = &mut efn.receiver {
204 if receiver.ty == "Self" {
205 receiver.ty = single_type.clone();
206 }
207 }
208 }
209 }
210 }
211
David Tolnay52759782020-05-03 23:59:40 -0700212 out.extend(items);
David Tolnay7db73692019-10-20 14:51:12 -0400213}
214
215fn parse_lang(abi: Abi) -> Result<Lang> {
216 let name = match &abi.name {
217 Some(name) => name,
218 None => {
219 return Err(Error::new_spanned(
220 abi,
221 "ABI name is required, extern \"C\" or extern \"Rust\"",
222 ));
223 }
224 };
225 match name.value().as_str() {
David Tolnay0b76aea2020-03-18 12:54:24 -0700226 "C" | "C++" => Ok(Lang::Cxx),
David Tolnay7db73692019-10-20 14:51:12 -0400227 "Rust" => Ok(Lang::Rust),
228 _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
229 }
230}
231
232fn parse_extern_type(foreign_type: &ForeignItemType) -> Result<ExternType> {
233 let doc = attrs::parse_doc(&foreign_type.attrs)?;
234 let type_token = foreign_type.type_token;
235 let ident = foreign_type.ident.clone();
236 Ok(ExternType {
237 doc,
238 type_token,
239 ident,
240 })
241}
242
David Tolnaya1f29c42020-04-22 18:01:38 -0700243fn parse_extern_fn(foreign_fn: &ForeignItemFn, lang: Lang) -> Result<ExternFn> {
David Tolnay7db73692019-10-20 14:51:12 -0400244 let generics = &foreign_fn.sig.generics;
245 if !generics.params.is_empty() || generics.where_clause.is_some() {
246 return Err(Error::new_spanned(
247 foreign_fn,
248 "extern function with generic parameters is not supported yet",
249 ));
250 }
251 if let Some(variadic) = &foreign_fn.sig.variadic {
252 return Err(Error::new_spanned(
253 variadic,
254 "variadic function is not supported yet",
255 ));
256 }
257
258 let mut receiver = None;
David Tolnaye3a48152020-04-08 19:38:05 -0700259 let mut args = Punctuated::new();
260 for arg in foreign_fn.sig.inputs.pairs() {
261 let (arg, comma) = arg.into_tuple();
David Tolnay7db73692019-10-20 14:51:12 -0400262 match arg {
David Tolnay1dd11a12020-04-22 12:31:48 -0700263 FnArg::Receiver(arg) => {
David Tolnaya1f29c42020-04-22 18:01:38 -0700264 if let Some((ampersand, lifetime)) = &arg.reference {
265 receiver = Some(Receiver {
266 ampersand: *ampersand,
267 lifetime: lifetime.clone(),
268 mutability: arg.mutability,
269 var: arg.self_token,
270 ty: Token![Self](arg.self_token.span).into(),
271 shorthand: true,
272 });
273 continue;
Joel Galensone1e969d2020-04-21 12:50:20 -0700274 }
David Tolnay1dd11a12020-04-22 12:31:48 -0700275 return Err(Error::new_spanned(arg, "unsupported signature"));
David Tolnay7db73692019-10-20 14:51:12 -0400276 }
277 FnArg::Typed(arg) => {
278 let ident = match arg.pat.as_ref() {
279 Pat::Ident(pat) => pat.ident.clone(),
Joel Galensonba676072020-04-27 15:55:45 -0700280 Pat::Wild(pat) => {
281 Ident::new(&format!("_{}", args.len()), pat.underscore_token.span)
282 }
David Tolnay7db73692019-10-20 14:51:12 -0400283 _ => return Err(Error::new_spanned(arg, "unsupported signature")),
284 };
285 let ty = parse_type(&arg.ty)?;
286 if ident != "self" {
David Tolnaye3a48152020-04-08 19:38:05 -0700287 args.push_value(Var { ident, ty });
288 if let Some(comma) = comma {
289 args.push_punct(*comma);
290 }
David Tolnay7db73692019-10-20 14:51:12 -0400291 continue;
292 }
293 if let Type::Ref(reference) = ty {
294 if let Type::Ident(ident) = reference.inner {
295 receiver = Some(Receiver {
David Tolnayfb6e3862020-04-20 01:33:23 -0700296 ampersand: reference.ampersand,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700297 lifetime: reference.lifetime,
David Tolnay7db73692019-10-20 14:51:12 -0400298 mutability: reference.mutability,
David Tolnay05e11cc2020-04-20 02:13:56 -0700299 var: Token![self](ident.span()),
300 ty: ident,
David Tolnay62d360c2020-04-22 16:26:21 -0700301 shorthand: false,
David Tolnay7db73692019-10-20 14:51:12 -0400302 });
303 continue;
304 }
305 }
306 return Err(Error::new_spanned(arg, "unsupported method receiver"));
307 }
308 }
309 }
David Tolnay59b7ede2020-03-16 00:30:23 -0700310
David Tolnaye3a48152020-04-08 19:38:05 -0700311 let mut throws_tokens = None;
312 let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
313 let throws = throws_tokens.is_some();
David Tolnay7db73692019-10-20 14:51:12 -0400314 let doc = attrs::parse_doc(&foreign_fn.attrs)?;
315 let fn_token = foreign_fn.sig.fn_token;
316 let ident = foreign_fn.sig.ident.clone();
David Tolnaye3a48152020-04-08 19:38:05 -0700317 let paren_token = foreign_fn.sig.paren_token;
David Tolnay7db73692019-10-20 14:51:12 -0400318 let semi_token = foreign_fn.semi_token;
David Tolnayd95b1192020-03-18 20:07:46 -0700319
David Tolnay7db73692019-10-20 14:51:12 -0400320 Ok(ExternFn {
David Tolnay6cde49f2020-03-16 12:25:45 -0700321 lang,
David Tolnay7db73692019-10-20 14:51:12 -0400322 doc,
David Tolnay7db73692019-10-20 14:51:12 -0400323 ident,
David Tolnay16448732020-03-18 12:39:36 -0700324 sig: Signature {
325 fn_token,
326 receiver,
327 args,
328 ret,
329 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700330 paren_token,
331 throws_tokens,
David Tolnay16448732020-03-18 12:39:36 -0700332 },
David Tolnay7db73692019-10-20 14:51:12 -0400333 semi_token,
334 })
335}
336
337fn parse_type(ty: &RustType) -> Result<Type> {
David Tolnay59b7ede2020-03-16 00:30:23 -0700338 match ty {
David Tolnayb40b9db2020-03-18 13:50:31 -0700339 RustType::Reference(ty) => parse_type_reference(ty),
340 RustType::Path(ty) => parse_type_path(ty),
David Tolnayeebe9b72020-04-14 16:32:18 -0700341 RustType::Slice(ty) => parse_type_slice(ty),
David Tolnayc071b892020-03-18 16:59:53 -0700342 RustType::BareFn(ty) => parse_type_fn(ty),
David Tolnayb40b9db2020-03-18 13:50:31 -0700343 RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
344 _ => Err(Error::new_spanned(ty, "unsupported type")),
345 }
346}
347
348fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
349 let inner = parse_type(&ty.elem)?;
350 let which = match &inner {
351 Type::Ident(ident) if ident == "str" => {
352 if ty.mutability.is_some() {
353 return Err(Error::new_spanned(ty, "unsupported type"));
354 } else {
355 Type::Str
David Tolnay7db73692019-10-20 14:51:12 -0400356 }
357 }
David Tolnayeebe9b72020-04-14 16:32:18 -0700358 Type::Slice(slice) => match &slice.inner {
359 Type::Ident(ident) if ident == U8 && ty.mutability.is_none() => Type::SliceRefU8,
360 _ => Type::Ref,
David Tolnayeb952ba2020-04-14 15:02:24 -0700361 },
David Tolnayb40b9db2020-03-18 13:50:31 -0700362 _ => Type::Ref,
363 };
364 Ok(which(Box::new(Ref {
365 ampersand: ty.and_token,
David Tolnay0bd50fa2020-04-22 15:31:33 -0700366 lifetime: ty.lifetime.clone(),
David Tolnayb40b9db2020-03-18 13:50:31 -0700367 mutability: ty.mutability,
368 inner,
369 })))
370}
371
372fn parse_type_path(ty: &TypePath) -> Result<Type> {
373 let path = &ty.path;
374 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
375 let segment = &path.segments[0];
376 let ident = segment.ident.clone();
377 match &segment.arguments {
378 PathArguments::None => return Ok(Type::Ident(ident)),
379 PathArguments::AngleBracketed(generic) => {
380 if ident == "UniquePtr" && generic.args.len() == 1 {
381 if let GenericArgument::Type(arg) = &generic.args[0] {
382 let inner = parse_type(arg)?;
383 return Ok(Type::UniquePtr(Box::new(Ty1 {
384 name: ident,
385 langle: generic.lt_token,
386 inner,
387 rangle: generic.gt_token,
388 })));
389 }
David Tolnaye1dcdf72020-04-24 17:40:55 -0700390 } else if ident == "CxxVector" && generic.args.len() == 1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700391 if let GenericArgument::Type(arg) = &generic.args[0] {
392 let inner = parse_type(arg)?;
David Tolnay4377a9e2020-04-24 15:20:26 -0700393 return Ok(Type::CxxVector(Box::new(Ty1 {
Myron Ahneba35cf2020-02-05 19:41:51 +0700394 name: ident,
395 langle: generic.lt_token,
396 inner,
397 rangle: generic.gt_token,
398 })));
399 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700400 } else if ident == "Box" && generic.args.len() == 1 {
401 if let GenericArgument::Type(arg) = &generic.args[0] {
402 let inner = parse_type(arg)?;
403 return Ok(Type::RustBox(Box::new(Ty1 {
404 name: ident,
405 langle: generic.lt_token,
406 inner,
407 rangle: generic.gt_token,
408 })));
409 }
Myron Ahneba35cf2020-02-05 19:41:51 +0700410 } else if ident == "Vec" && generic.args.len() == 1 {
411 if let GenericArgument::Type(arg) = &generic.args[0] {
412 let inner = parse_type(arg)?;
413 return Ok(Type::RustVec(Box::new(Ty1 {
414 name: ident,
415 langle: generic.lt_token,
416 inner,
417 rangle: generic.gt_token,
418 })));
419 }
David Tolnayb40b9db2020-03-18 13:50:31 -0700420 }
421 }
422 PathArguments::Parenthesized(_) => {}
David Tolnayfb134ed2020-03-15 23:17:48 -0700423 }
David Tolnay7db73692019-10-20 14:51:12 -0400424 }
425 Err(Error::new_spanned(ty, "unsupported type"))
426}
427
David Tolnayeebe9b72020-04-14 16:32:18 -0700428fn parse_type_slice(ty: &TypeSlice) -> Result<Type> {
429 let inner = parse_type(&ty.elem)?;
430 Ok(Type::Slice(Box::new(Slice {
431 bracket: ty.bracket_token,
432 inner,
433 })))
434}
435
David Tolnayc071b892020-03-18 16:59:53 -0700436fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
437 if ty.lifetimes.is_some() {
438 return Err(Error::new_spanned(
439 ty,
440 "function pointer with lifetime parameters is not supported yet",
441 ));
442 }
443 if ty.variadic.is_some() {
444 return Err(Error::new_spanned(
445 ty,
446 "variadic function pointer is not supported yet",
447 ));
448 }
449 let args = ty
450 .inputs
451 .iter()
452 .enumerate()
453 .map(|(i, arg)| {
454 let ty = parse_type(&arg.ty)?;
455 let ident = match &arg.name {
456 Some(ident) => ident.0.clone(),
457 None => format_ident!("_{}", i),
458 };
459 Ok(Var { ident, ty })
460 })
461 .collect::<Result<_>>()?;
David Tolnaye3a48152020-04-08 19:38:05 -0700462 let mut throws_tokens = None;
463 let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
464 let throws = throws_tokens.is_some();
David Tolnayc071b892020-03-18 16:59:53 -0700465 Ok(Type::Fn(Box::new(Signature {
466 fn_token: ty.fn_token,
467 receiver: None,
468 args,
469 ret,
470 throws,
David Tolnaye3a48152020-04-08 19:38:05 -0700471 paren_token: ty.paren_token,
472 throws_tokens,
David Tolnayc071b892020-03-18 16:59:53 -0700473 })))
474}
475
David Tolnaye3a48152020-04-08 19:38:05 -0700476fn parse_return_type(
477 ty: &ReturnType,
478 throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
479) -> Result<Option<Type>> {
David Tolnayc071b892020-03-18 16:59:53 -0700480 let mut ret = match ty {
481 ReturnType::Default => return Ok(None),
482 ReturnType::Type(_, ret) => ret.as_ref(),
483 };
484 if let RustType::Path(ty) = ret {
485 let path = &ty.path;
486 if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
487 let segment = &path.segments[0];
488 let ident = segment.ident.clone();
489 if let PathArguments::AngleBracketed(generic) = &segment.arguments {
490 if ident == "Result" && generic.args.len() == 1 {
491 if let GenericArgument::Type(arg) = &generic.args[0] {
492 ret = arg;
David Tolnaye3a48152020-04-08 19:38:05 -0700493 *throws_tokens =
494 Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
David Tolnayc071b892020-03-18 16:59:53 -0700495 }
496 }
497 }
498 }
499 }
500 match parse_type(ret)? {
501 Type::Void(_) => Ok(None),
502 ty => Ok(Some(ty)),
503 }
504}