diff --git a/savefile-derive/src/common.rs b/savefile-derive/src/common.rs index 3d0a2d3..c2db990 100644 --- a/savefile-derive/src/common.rs +++ b/savefile-derive/src/common.rs @@ -1,7 +1,8 @@ -use proc_macro2::{Span, TokenStream}; +use proc_macro2::{Ident, Span, TokenStream}; use quote::ToTokens; use syn::spanned::Spanned; -use syn::{Expr, GenericParam, Generics, Lit, Type, WhereClause}; +use syn::{Error, Expr, ExprLit, GenericParam, Generics, Lit, LitStr, Meta, MetaNameValue, RangeLimits, Type, WhereClause}; +use syn::token::Token; pub(crate) fn get_extra_where_clauses( gen2: &Generics, @@ -45,7 +46,7 @@ pub(crate) struct AttrsResult { pub(crate) version_from: u32, //0 means no lower bound pub(crate) version_to: u32, //u32::MAX means no upper bound pub(crate) ignore: bool, - pub(crate) default_fn: Option, + pub(crate) default_fn: Option, pub(crate) default_val: Option, pub(crate) deserialize_types: Vec, pub(crate) introspect_key: bool, @@ -120,124 +121,224 @@ pub(crate) fn parse_attr_tag(attrs: &[syn::Attribute]) -> AttrsResult { let mut introspect_key = false; let mut deser_types = Vec::new(); for attr in attrs.iter() { - match attr.parse_meta() { - Ok(ref meta) => match meta { - syn::Meta::Path(x) => { - let x = path_to_string(x); - if x == "savefile_ignore" { - ignore = true; - } - if x == "savefile_introspect_key" { - introspect_key = true; - } - if x == "savefile_introspect_ignore" { - introspect_ignore = true; - } + { + //Ok(ref meta) => match meta { + + + //let x = path_to_string(x); + if attr.path().is_ident("savefile_ignore") { + ignore = true; } - &syn::Meta::List(ref _x) => {} - &syn::Meta::NameValue(ref x) => { - let path = path_to_string(&x.path); - if path == "savefile_default_val" { - match &x.lit { - &syn::Lit::Str(ref litstr) => { - default_val = - Some(quote! { str::parse(#litstr).expect("Expected valid literal string") }) + if attr.path().is_ident("savefile_introspect_key") { + introspect_key = true; + } + if attr.path().is_ident("savefile_introspect_ignore") { + introspect_ignore = true; + } + + if attr.path().is_ident("savefile_default_val") { + match &attr.meta { + Meta::NameValue(nv) => { + let val = &nv.value; + match val { + Expr::Lit(x) => { + match &x.lit { + Lit::Str(lit) => { + let s = lit.value(); + default_val = Some(quote! { str::parse(#s).expect("Expected valid literal string") }); + } + _ => { + default_val = Some(quote! { #val }); + } + } + } + _ => { + default_val = Some(quote! { #val }); + } } - _ => { - let lv = &x.lit; - default_val = Some(quote! {#lv}); + } + Meta::Path(_) | + Meta::List(_) => { + abort!( + attr.path().span(), + "Invalid default value" + ) + } + } + } + + if attr.path().is_ident("savefile_default_fn") { + + let args: Result = attr.parse_args(); + match &attr.meta { + Meta::NameValue(nv) => { + match &nv.value { + Expr::Path(path) => { + default_fn = Some(path.path.to_token_stream()); + } + Expr::Lit(lit) => { + match &lit.lit { + Lit::Str(litstr) => { + default_fn = Some(Ident::new(litstr.value().as_str(), lit.lit.span().clone()).to_token_stream()); + } + _=> { + abort!( + attr.path().span(), + "Invalid savefile_default_fn value" + ) + } + } + } + _ => { + abort!( + attr.path().span(), + "Invalid savefile_default_fn value" + ) + } } - }; - }; - if path == "savefile_default_fn" { - let default_fn_str_lit = match &x.lit { - &syn::Lit::Str(ref litstr) => litstr, - _ => { - abort!(x.lit.span(), "Unexpected attribute value, please specify savefile_default_fn method names within quotes."); + } + _ => { + abort!( + attr.path().span(), + "Invalid savefile_default_fn value" + ) + } + + } + } + if attr.path().is_ident("savefile_versions_as") { + let mut rhs = None; + match &attr.meta { + Meta::Path(_) | + Meta::List(_) => {} + Meta::NameValue(nv) => { + match &nv.value { + Expr::Lit(lit)=> { + match &lit.lit { + Lit::Str(litstr) => { + rhs = Some(litstr.value()); + } + _ =>{} + } + } _ => { + + } } - }; - default_fn = Some(syn::Ident::new( - &default_fn_str_lit.value(), - proc_macro2::Span::call_site(), - )); - }; + } + } - if path == "savefile_ignore" { - ignore = true; + if rhs.is_none() { + abort!( + attr.span(), + "Invalid savefile_versions_as-attribute value, should be string", + ) }; - if path == "savefile_introspect_ignore" { - introspect_ignore = true; - }; - if path == "savefile_versions_as" { - match &x.lit { - &syn::Lit::Str(ref litstr2) => { - let output2: Vec = - litstr2.value().splitn(3, ':').map(|x| x.to_string()).collect(); - if output2.len() != 3 && output2.len() != 2 { - abort!(litstr2.span(), "The #savefile_versions_as tag must contain a version range and a deserialization type, such as : #[savefile_versions_as=0..3:MyStructType]"); - } - let litstr = &output2[0]; + let litstr2 = rhs.unwrap(); - let convert_fun: String; - let version_type: String; + let output2: Vec = + litstr2.splitn(3, ':').map(|x| x.to_string()).collect(); + if output2.len() != 3 && output2.len() != 2 { + abort!(litstr2.span(), "The #savefile_versions_as tag must contain a version range and a deserialization type, such as : #[savefile_versions_as=0..3:MyStructType]"); + } + let litstr = &output2[0]; - if output2.len() == 2 { - convert_fun = "".to_string(); - version_type = output2[1].to_string(); - } else { - convert_fun = output2[1].to_string(); - version_type = output2[2].to_string(); - } + let convert_fun: String; + let version_type: String; - let output: Vec = litstr.split("..").map(|x| x.to_string()).collect(); - if output.len() != 2 { - abort!(litstr2.span(), "savefile_versions_as tag must contain a (possibly half-open) range, such as 0..3 or 2.. (fields present in all versions to date should not use the savefile_versions_as-attribute)"); - } - let (a, b) = (output[0].to_string(), output[1].to_string()); + if output2.len() == 2 { + convert_fun = "".to_string(); + version_type = output2[1].to_string(); + } else { + convert_fun = output2[1].to_string(); + version_type = output2[2].to_string(); + } - let from_ver = if a.trim() == "" { - 0 - } else if let Ok(a_u32) = a.parse::() { - a_u32 - } else { - abort!(litstr2.span(), "The from version in the version tag must be an integer. Use #[savefile_versions_as=0..3:MyStructType] for example"); - }; + let output: Vec = litstr.split("..").map(|x| x.to_string()).collect(); + if output.len() != 2 { + abort!(litstr2.span(), "savefile_versions_as tag must contain a (possibly half-open) range, such as 0..3 or 2.. (fields present in all versions to date should not use the savefile_versions_as-attribute)"); + } + let (a, b) = (output[0].to_string(), output[1].to_string()); - let to_ver = if b.trim() == "" { - std::u32::MAX - } else if let Ok(b_u32) = b.parse::() { - b_u32 - } else { - abort!(litstr2.span(), "The to version in the version tag must be an integer. Use #[savefile_versions_as=0..3:MyStructType] for example"); - }; - if to_ver < from_ver { - abort!(litstr2.span(), "Version ranges must specify lower number first."); - } + let from_ver = if a.trim() == "" { + 0 + } else if let Ok(a_u32) = a.parse::() { + a_u32 + } else { + abort!(litstr2.span(), "The from version in the version tag must be an integer. Use #[savefile_versions_as=0..3:MyStructType] for example"); + }; - let item = VersionRange { - from: from_ver, - to: to_ver, - convert_fun: convert_fun.to_string(), - serialized_type: version_type.to_string(), - }; - if deser_types.iter().any(overlap(&item)) { - abort!( + let to_ver = if b.trim() == "" { + std::u32::MAX + } else if let Ok(b_u32) = b.parse::() { + b_u32 + } else { + abort!(litstr2.span(), "The to version in the version tag must be an integer. Use #[savefile_versions_as=0..3:MyStructType] for example"); + }; + if to_ver < from_ver { + abort!(litstr2.span(), "Version ranges must specify lower number first."); + } + + let item = VersionRange { + from: from_ver, + to: to_ver, + convert_fun: convert_fun.to_string(), + serialized_type: version_type.to_string(), + }; + if deser_types.iter().any(overlap(&item)) { + abort!( litstr2.span(), "#savefile_versions_as attributes may not specify overlapping ranges" ); + } + deser_types.push(item); + } + + if attr.path().is_ident("savefile_versions") { + + let mut rhs = None; + match &attr.meta { + Meta::Path(_) | + Meta::List(_) => { + } + Meta::NameValue(nv) => { + rhs = Some(&nv.value); + } + } + + if rhs.is_none() { + abort!( + attr.span(), + "Invalid savefile_versions_as-attribute value." + ) + }; + let rhs = rhs.unwrap(); + + + match rhs { + Expr::Range(val) => { + let mut range_start : Option = None; + let mut range_end : Option = None; + if let Some(start) = &val.start { + range_start = Some(parse_integer(&*start)); + } + if let Some(end) = &val.end { + range_end = Some(parse_integer(&*end)); + } + match val.limits { + RangeLimits::HalfOpen(_) => {} + RangeLimits::Closed(_) => { + if let Some(end) = &mut range_end { + *end += 1; } - deser_types.push(item); } - _ => abort!( - x.path.span(), - "Unexpected datatype for value of attribute savefile_versions_as" - ), } + field_from_version = range_start; + field_to_version = range_end; } + Expr::Lit(lit) => { - if path == "savefile_versions" { - match &x.lit { - &syn::Lit::Str(ref litstr) => { + match &lit.lit { + Lit::Str(litstr) => { let output: Vec = litstr.value().split("..").map(|x| x.to_string()).collect(); if output.len() != 2 { abort!(litstr.span(), "savefile_versions tag must contain a (possibly half-open) range, such as 0..3 or 2.. (fields present in all versions to date should not use the savefile_versions-attribute)"); @@ -273,6 +374,35 @@ pub(crate) fn parse_attr_tag(attrs: &[syn::Attribute]) -> AttrsResult { "savefile_versions ranges must specify lower number first." ); } + } + _ => { + abort!(lit.lit.span(), "Invalid savefile_versions-attribute value[1]"); + } + } + } + _ => { + abort!(rhs.span(), "Invalid savefile_versions-attribute value [2]") + } + } + + } +/* + if path == "savefile_versions_as" { + match &x.lit { + &syn::Lit::Str(ref litstr2) => { + + } + _ => abort!( + x.path.span(), + "Unexpected datatype for value of attribute savefile_versions_as" + ), + } + } + + if path == "savefile_versions" { + match &x.lit { + &syn::Lit::Str(ref litstr) => { + } _ => abort!( x.lit.span(), @@ -280,11 +410,11 @@ pub(crate) fn parse_attr_tag(attrs: &[syn::Attribute]) -> AttrsResult { ), } } - } - }, - Err(e) => { - abort!(attr.span(), "Unparsable attribute: {:?} ({:?})", e, attr.tokens); - } + }*/ + //}, + /*Err(e) => { + abort!(attr.span(), "Unparsable attribute: {:?} ({})", e, attr.to_token_stream()); + }*/ } } @@ -315,6 +445,38 @@ pub(crate) fn parse_attr_tag(attrs: &[syn::Attribute]) -> AttrsResult { } } +fn parse_integer(p0: &Expr) -> u32 { + match p0 { + Expr::Lit(lit) => { + match &lit.lit { + Lit::Int(i) => { + match i.base10_parse() { + Ok(val) => val, + Err(_) => { + abort!( + p0.span(), + "Expected an integer" + ) + } + + } + } + _ => abort!( + p0.span(), + "Expected an integer" + ) + + } + } + _ => { + abort!( + p0.span(), + "Expected an integer" + ) + } + } +} + pub(crate) struct FieldInfo<'a> { pub(crate) field_span: Span, pub(crate) ident: Option, diff --git a/savefile-derive/src/lib.rs b/savefile-derive/src/lib.rs index ad46868..5399e94 100644 --- a/savefile-derive/src/lib.rs +++ b/savefile-derive/src/lib.rs @@ -252,9 +252,9 @@ pub fn savefile_abi_exportable( } for attr in &parsed.attrs { - let name_segs: Vec<_> = attr.path.segments.iter().map(|x| &x.ident).collect(); + let name_segs: Vec<_> = attr.path().segments.iter().map(|x| &x.ident).collect(); if name_segs == ["async_trait"] || name_segs == ["async_trait", "async_trait"] { - abort!(attr.path.segments.span(), "async_trait-attribute macro detected. The {} macro must go _before_ the #[savefile_abi_exportable(..)] macro!", + abort!(attr.path().segments.span(), "async_trait-attribute macro detected. The {} macro must go _before_ the #[savefile_abi_exportable(..)] macro!", attr.to_token_stream()); } } @@ -318,6 +318,15 @@ pub fn savefile_abi_exportable( abort!(lif.span(), "Savefile does not support lifetimes"); } } + TypeParamBound::PreciseCapture(c) => { + abort!(c.span(), "Savefile does not support precise captures"); + } + TypeParamBound::Verbatim(v) => { + abort!(v.span(), "Savefile does not support verbatim bounds"); + } + x => { + abort!(x.span(), "Savefile does not support this syntax"); + } } } @@ -342,7 +351,7 @@ pub fn savefile_abi_exportable( c.ident ); } - TraitItem::Method(method) => { + TraitItem::Fn(method) => { let mut is_ok = true; let mut async_trait_life_time = 0; let mut life0_life_time = 0; @@ -384,6 +393,9 @@ pub fn savefile_abi_exportable( is_ok = false; } } + x => { + abort!(x.span(), "Savefile does not support this syntax",); + } } } } @@ -403,8 +415,8 @@ pub fn savefile_abi_exportable( } } } - WherePredicate::Eq(_) => { - is_ok = false; + x => { + abort!(x.span(), "Savefile does not support this syntax"); } } } @@ -461,85 +473,95 @@ pub fn savefile_abi_exportable( method_name ) }); + let unsupported = || { + abort!( + method.sig.span(), + "Method '{}' has an unsupported 'self'-parameter. Try '&self', '&mut self', or 'self: Pin<&mut Self>'. Not supported: {}", + method_name, self_arg.to_token_stream() + ); + }; + + let mut parse_receiver_ty = |typ: &Type| { + if let Type::Path(path) = typ { + if !is_well_known(&path.path.segments, ["std", "pin", "Pin"]) { + unsupported(); + } + let seg = &path.path.segments.last().unwrap(); + let PathArguments::AngleBracketed(args) = &seg.arguments else { + unsupported(); + unreachable!(); + }; + if args.args.len() != 1 { + unsupported(); + } + let arg = &args.args[0]; + let GenericArgument::Type(Type::Reference(typref)) = arg else { + unsupported(); + unreachable!(); + }; + if typref.mutability.is_none() { + abort!( + method.sig.span(), + "Method '{}' has an unsupported 'self'-parameter. Non-mutable references in Pin are presently not supported: {}", + method_name, self_arg.to_token_stream() + ); + } + let Type::Path(typepath) = &*typref.elem else { + unsupported(); + unreachable!(); + }; + if typepath.path.segments.len() != 1 { + unsupported(); + unreachable!() + }; + if typepath.path.segments[0].ident != "Self" { + unsupported(); + } + receiver_is_mut = true; + receiver_is_pin = true; + } else { + unsupported(); + } + }; match self_arg { FnArg::Receiver(recv) => { - if let Some(reference) = &recv.reference { - if let Some(reference) = &reference.1 { - if reference.ident != "life0" { - abort!( + + if recv.colon_token.is_some() { + parse_receiver_ty(&*recv.ty); + } else { + if let Some(reference) = &recv.reference { + if let Some(reference) = &reference.1 { + if reference.ident != "life0" { + abort!( reference.span(), "Method '{}' has a lifetime \"'{}\" for 'self' argument. This is not supported by savefile-abi", method_name, reference.ident, ); - } else { - life0_life_time += 1; + } else { + life0_life_time += 1; + } } - } - if recv.mutability.is_some() { - receiver_is_mut = true; - } - } else { - abort!( + if recv.mutability.is_some() { + receiver_is_mut = true; + } + } else { + abort!( self_arg.span(), "Method '{}' takes 'self' by value. This is not supported by savefile-abi. Use &self", method_name ); + } } } FnArg::Typed(pat) => { - let unsupported = || { - abort!( - method.sig.span(), - "Method '{}' has an unsupported 'self'-parameter. Try '&self', '&mut self', or 'self: Pin<&mut Self>'. Not supported: {}", - method_name, self_arg.to_token_stream() - ); - }; + match &*pat.pat { Pat::Ident(ident) if ident.ident == "self" => { if ident.by_ref.is_some() || ident.mutability.is_some() { unsupported(); } - if let Type::Path(path) = &*pat.ty { - if !is_well_known(&path.path.segments, ["std", "pin", "Pin"]) { - unsupported(); - } - let seg = &path.path.segments.last().unwrap(); - let PathArguments::AngleBracketed(args) = &seg.arguments else { - unsupported(); - unreachable!(); - }; - if args.args.len() != 1 { - unsupported(); - } - let arg = &args.args[0]; - let GenericArgument::Type(Type::Reference(typref)) = arg else { - unsupported(); - unreachable!(); - }; - if typref.mutability.is_none() { - abort!( - method.sig.span(), - "Method '{}' has an unsupported 'self'-parameter. Non-mutable references in Pin are presently not supported: {}", - method_name, self_arg.to_token_stream() - ); - } - let Type::Path(typepath) = &*typref.elem else { - unsupported(); - unreachable!(); - }; - if typepath.path.segments.len() != 1 { - unsupported(); - unreachable!() - }; - if typepath.path.segments[0].ident != "Self" { - unsupported(); - } - receiver_is_mut = true; - receiver_is_pin = true; - } else { - unsupported(); - } + parse_receiver_ty(&*pat.ty); } _ => { abort!( @@ -1125,77 +1147,68 @@ fn get_enum_size(attrs: &[syn::Attribute], actual_variants: usize) -> EnumSize { let mut size_u8: Option = None; let mut repr_c_seen = false; let mut have_seen_explicit_size = false; + for attr in attrs.iter() { - if let Ok(ref meta) = attr.parse_meta() { - match meta { - &syn::Meta::NameValue(ref _x) => {} - &syn::Meta::Path(ref _x) => {} - &syn::Meta::List(ref metalist) => { - let path = path_to_string(&metalist.path); - if path == "repr" { - for x in &metalist.nested { - let size_str: String = match *x { - syn::NestedMeta::Meta(ref inner_x) => match inner_x { - &syn::Meta::NameValue(ref _x) => { - continue; - } - &syn::Meta::Path(ref path) => path_to_string(path), - &syn::Meta::List(ref _metalist) => { - continue; - } - }, - syn::NestedMeta::Lit(ref lit) => match lit { - &syn::Lit::Str(ref litstr) => litstr.value(), - _ => { - continue; - //panic!("Unsupported repr-attribute: repr({:?})", x.clone().into_token_stream()); - } - }, - }; - match size_str.as_ref() { - "C" => repr_c_seen = true, - "u8" => { - size_u8 = Some(1); - have_seen_explicit_size = true; - } - "i8" => { - size_u8 = Some(1); - have_seen_explicit_size = true; - } - "u16" => { - size_u8 = Some(2); - have_seen_explicit_size = true; - } - "i16" => { - size_u8 = Some(2); - have_seen_explicit_size = true; - } - "u32" => { - size_u8 = Some(4); - have_seen_explicit_size = true; - } - "i32" => { - size_u8 = Some(4); - have_seen_explicit_size = true; - } - "u64" | "i64" => { - abort!( - metalist.path.span(), - "Savefile does not support enums with more than 2^32 variants." - ) - } - _ => abort!( - metalist.path.span(), - "Unsupported repr(X) attribute on enum: {}", - size_str - ), - } - } - } + let path = attr.path(); + + if path.is_ident("repr") { + if let Err(err) = attr.parse_nested_meta(|meta| { + + //for x in &metalist.nested { + if meta.path.segments.len() != 1 { + abort!( + meta.path.span(), + "Unsupported repr(X) attribute on enum: {}", + meta.path.to_token_stream()); } - } + match meta.path.segments[0].ident.to_string().as_str() { + "C" => repr_c_seen = true, + "u8" => { + size_u8 = Some(1); + have_seen_explicit_size = true; + } + "i8" => { + size_u8 = Some(1); + have_seen_explicit_size = true; + } + "u16" => { + size_u8 = Some(2); + have_seen_explicit_size = true; + } + "i16" => { + size_u8 = Some(2); + have_seen_explicit_size = true; + } + "u32" => { + size_u8 = Some(4); + have_seen_explicit_size = true; + } + "i32" => { + size_u8 = Some(4); + have_seen_explicit_size = true; + } + "u64" | "i64" => { + abort!( + meta.path.span(), + "Savefile does not support enums with more than 2^32 variants." + ) + } + _ => abort!( + meta.path.span(), + "Unsupported repr(X) attribute on enum: {}", + meta.path.to_token_stream() + ), + }; + Ok(()) + }) { + abort!( + attr.span(), + "Unsupported repr(X) attribute: {}", + attr.to_token_stream()); + }; } } + let discriminant_size = size_u8.unwrap_or_else(|| { if actual_variants <= 256 { 1 @@ -1214,6 +1227,8 @@ fn get_enum_size(attrs: &[syn::Attribute], actual_variants: usize) -> EnumSize { explicit_size: have_seen_explicit_size, } } + + #[proc_macro_error] #[proc_macro_derive( Packed, @@ -1234,7 +1249,11 @@ fn derive_reprc_new(input: DeriveInput) -> TokenStream { let mut opt_in_fast = false; for attr in input.attrs.iter() { - match attr.parse_meta() { + if attr.path().is_ident("savefile_unsafe_and_fast") || + attr.path().is_ident("savefile_require_fast") { + opt_in_fast = true; + } + /*match attr.parse_meta() { Ok(ref meta) => match meta { &syn::Meta::Path(ref x) => { let x = path_to_string(x); @@ -1245,7 +1264,7 @@ fn derive_reprc_new(input: DeriveInput) -> TokenStream { _ => {} }, _ => {} - } + }*/ } /*if !opt_in_fast { diff --git a/savefile-derive/src/savefile_abi.rs b/savefile-derive/src/savefile_abi.rs index 56c9fa2..d065d09 100644 --- a/savefile-derive/src/savefile_abi.rs +++ b/savefile-derive/src/savefile_abi.rs @@ -7,7 +7,6 @@ use std::hash::{Hash, Hasher}; use std::sync::atomic::AtomicU64; use syn::punctuated::Punctuated; use syn::spanned::Spanned; -use syn::token::Colon2; use syn::{ GenericArgument, Lifetime, Path, PathArguments, PathSegment, ReturnType, TraitBoundModifier, Type, TypeParamBound, TypeTuple, @@ -95,8 +94,8 @@ fn compile_time_abi_check_size(typ: &Type) -> Option<(usize, usize)> { } } GenericArgument::Const(_) => {} - GenericArgument::Binding(_) => {} GenericArgument::Constraint(_) => {} + _ => {} } } } @@ -648,6 +647,13 @@ fn parse_type( ); } } + x => { + abort!( + x.span(), + "{}: Savefile does not support this syntax", + location + ); + } }) .filter_map(|x| x) .filter(|seg| { @@ -770,18 +776,22 @@ fn parse_type( let output = &arg.args[0]; match output { - GenericArgument::Binding(t) => { + GenericArgument::AssocType(t) => { if t.ident != "Output" { - abort!(seg.ident.span(), "{}: Futures must have a a single binding, named Output (Future).", location); + abort!(seg.ident.span(), "{}: Futures must have a a associated type, named Output (Future).", location); } return ArgType::Future(false, t.ty.to_token_stream(), send, sync, unpin); } GenericArgument::Lifetime(_) | GenericArgument::Const(_) | GenericArgument::Type(_) + | GenericArgument::AssocConst(_) | GenericArgument::Constraint(_) => { abort!(output.span(), "{}: Futures must have a a single associated type binding, named 'Output' (Future).", location); } + x => { + abort!(bound.span(), "{}: Savefile does not support this syntax", location); + } } } PathArguments::None | PathArguments::Parenthesized(_) => { @@ -801,6 +811,9 @@ fn parse_type( location ); } + x => { + abort!(bound.span(), "{}: Savefile does not support this syntax", location); + } } abort!( trait_obj.span(), @@ -906,11 +919,11 @@ fn parse_type( GenericArgument::Const(_) => { abort!(arg.span(), "Savefile does not support const in this location."); } - GenericArgument::Binding(_) => { + GenericArgument::AssocType(_) => { abort!(arg.span(), "Savefile does not support the syntax expressed here."); } - GenericArgument::Constraint(_) => { - abort!(arg.span(), "Savefile does not support constraints at this position."); + x=> { + abort!(x.span(), "Savefile does not support the syntax expressed here."); } } abort!( @@ -979,12 +992,18 @@ fn parse_type( GenericArgument::Const(_) => { abort!(arg.span(), "Savefile does not support const in this location."); } - GenericArgument::Binding(_) => { + GenericArgument::AssocType(_) => { + abort!(arg.span(), "Savefile does not support the syntax expressed here."); + } + GenericArgument::AssocConst(_) => { abort!(arg.span(), "Savefile does not support the syntax expressed here."); } GenericArgument::Constraint(_) => { abort!(arg.span(), "Savefile does not support constraints at this position."); } + x => { + abort!(x.span(), "{}: Savefile does not support this syntax", location); + } } } let mut i = argtypes.into_iter();