From 343805f80b14982495fd4c208b906e7bc694a4f0 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 3 Oct 2024 23:04:14 -0700 Subject: [PATCH] fix #[hdl] to work with unusual identifier hygiene from macros --- .../src/hdl_bundle.rs | 109 +++++++++--------- .../fayalite-proc-macros-impl/src/hdl_enum.rs | 96 +++++++-------- .../src/hdl_type_common.rs | 39 +++++-- crates/fayalite/src/ty.rs | 4 +- crates/fayalite/tests/hdl_types.rs | 66 +++++++++++ 5 files changed, 202 insertions(+), 112 deletions(-) diff --git a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs index 30cf90f..f3a589a 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs @@ -431,6 +431,7 @@ impl ToTokens for ParsedBundle { builder_ident, mask_type_builder_ident, } = self; + let span = ident.span(); let ItemOptions { outline_generated: _, target, @@ -440,7 +441,7 @@ impl ToTokens for ParsedBundle { } = &options.body; let target = get_target(target, ident); let mut item_attrs = attrs.clone(); - item_attrs.push(common_derives(ident.span())); + item_attrs.push(common_derives(span)); ItemStruct { attrs: item_attrs, vis: vis.clone(), @@ -462,19 +463,19 @@ impl ToTokens for ParsedBundle { .map(|ParsedField { ident, ty, .. }| { let ident = ident.as_ref().unwrap(); let expr = ty.make_hdl_type_expr(context); - quote_spanned! {ident.span()=> + quote_spanned! {span=> #ident: #expr, } }) .collect(); - parse_quote_spanned! {ident.span()=> + parse_quote_spanned! {span=> #target { #(#fields)* } } }) } - let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span()); + let mut wrapped_in_const = WrappedInConst::new(tokens, span); let tokens = wrapped_in_const.inner(); let builder = Builder { vis: vis.clone(), @@ -488,9 +489,8 @@ impl ToTokens for ParsedBundle { let unfilled_builder_ty = builder.builder_struct_ty(|_| BuilderFieldState::Unfilled); let filled_builder_ty = builder.builder_struct_ty(|_| BuilderFieldState::Filled); let mut mask_type_fields = FieldsNamed::from(fields.clone()); - for Field { ident, ty, .. } in &mut mask_type_fields.named { - let ident = ident.as_ref().unwrap(); - *ty = parse_quote_spanned! {ident.span()=> + for Field { ty, .. } in &mut mask_type_fields.named { + *ty = parse_quote_spanned! {span=> <#ty as ::fayalite::ty::Type>::MaskType }; } @@ -509,8 +509,8 @@ impl ToTokens for ParsedBundle { mask_type_builder.builder_struct_ty(|_| BuilderFieldState::Filled); ItemStruct { attrs: vec![ - common_derives(ident.span()), - parse_quote_spanned! {ident.span()=> + common_derives(span), + parse_quote_spanned! {span=> #[allow(non_camel_case_types, dead_code)] }, ], @@ -523,16 +523,15 @@ impl ToTokens for ParsedBundle { } .to_tokens(tokens); let mut mask_type_match_variant_fields = mask_type_fields; - for Field { ident, ty, .. } in &mut mask_type_match_variant_fields.named { - let ident = ident.as_ref().unwrap(); - *ty = parse_quote_spanned! {ident.span()=> + for Field { ty, .. } in &mut mask_type_match_variant_fields.named { + *ty = parse_quote_spanned! {span=> ::fayalite::expr::Expr<#ty> }; } ItemStruct { attrs: vec![ - common_derives(ident.span()), - parse_quote_spanned! {ident.span()=> + common_derives(span), + parse_quote_spanned! {span=> #[allow(non_camel_case_types, dead_code)] }, ], @@ -545,16 +544,15 @@ impl ToTokens for ParsedBundle { } .to_tokens(tokens); let mut match_variant_fields = FieldsNamed::from(fields.clone()); - for Field { ident, ty, .. } in &mut match_variant_fields.named { - let ident = ident.as_ref().unwrap(); - *ty = parse_quote_spanned! {ident.span()=> + for Field { ty, .. } in &mut match_variant_fields.named { + *ty = parse_quote_spanned! {span=> ::fayalite::expr::Expr<#ty> }; } ItemStruct { attrs: vec![ - common_derives(ident.span()), - parse_quote_spanned! {ident.span()=> + common_derives(span), + parse_quote_spanned! {span=> #[allow(non_camel_case_types, dead_code)] }, ], @@ -566,17 +564,20 @@ impl ToTokens for ParsedBundle { semi_token: None, } .to_tokens(tokens); + let this_token = Ident::new("__this", span); + let fields_token = Ident::new("__fields", span); + let self_token = Token![self](span); let match_variant_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| { let ident: &Ident = field.ident().as_ref().unwrap(); let ident_str = ident.to_string(); - quote_spanned! {ident.span()=> - #ident: ::fayalite::expr::Expr::field(__this, #ident_str), + quote_spanned! {span=> + #ident: ::fayalite::expr::Expr::field(#this_token, #ident_str), } })); let mask_type_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| { let ident: &Ident = field.ident().as_ref().unwrap(); - quote_spanned! {ident.span()=> - #ident: ::fayalite::ty::Type::mask_type(&self.#ident), + quote_spanned! {span=> + #ident: ::fayalite::ty::Type::mask_type(&#self_token.#ident), } })); let from_canonical_body_fields = @@ -585,13 +586,13 @@ impl ToTokens for ParsedBundle { let ident: &Ident = field.ident().as_ref().unwrap(); let ident_str = ident.to_string(); let flipped = flip.is_some(); - quote_spanned! {ident.span()=> + quote_spanned! {span=> #ident: { let ::fayalite::bundle::BundleField { name: __name, flipped: __flipped, ty: __ty, - } = __fields[#index]; + } = #fields_token[#index]; ::fayalite::__std::assert_eq!(&*__name, #ident_str); ::fayalite::__std::assert_eq!(__flipped, #flipped); ::fayalite::ty::Type::from_canonical(__ty) @@ -604,17 +605,17 @@ impl ToTokens for ParsedBundle { let ident: &Ident = field.ident().as_ref().unwrap(); let ident_str = ident.to_string(); let flipped = flip.is_some(); - quote_spanned! {ident.span()=> + quote_spanned! {span=> ::fayalite::bundle::BundleField { name: ::fayalite::intern::Intern::intern(#ident_str), flipped: #flipped, - ty: ::fayalite::ty::Type::canonical(&self.#ident), + ty: ::fayalite::ty::Type::canonical(&#self_token.#ident), }, } }, )); let fields_len = fields.named().into_iter().len(); - quote_spanned! {ident.span()=> + quote_spanned! {span=> #[automatically_derived] impl #impl_generics ::fayalite::ty::Type for #mask_type_ident #type_generics #where_clause @@ -630,7 +631,7 @@ impl ToTokens for ParsedBundle { ::MatchVariantAndInactiveScope, >; fn match_variants( - __this: ::fayalite::expr::Expr, + #this_token: ::fayalite::expr::Expr, __source_location: ::fayalite::source_location::SourceLocation, ) -> ::MatchVariantsIter { let __retval = #mask_type_match_variant_ident { @@ -638,19 +639,19 @@ impl ToTokens for ParsedBundle { }; ::fayalite::__std::iter::once(::fayalite::ty::MatchVariantWithoutScope(__retval)) } - fn mask_type(&self) -> ::MaskType { - *self + fn mask_type(&#self_token) -> ::MaskType { + *#self_token } - fn canonical(&self) -> ::fayalite::ty::CanonicalType { - ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(self))) + fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType { + ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(#self_token))) } #[track_caller] fn from_canonical(__canonical_type: ::fayalite::ty::CanonicalType) -> Self { let ::fayalite::ty::CanonicalType::Bundle(__bundle) = __canonical_type else { ::fayalite::__std::panic!("expected bundle"); }; - let __fields = ::fayalite::bundle::BundleType::fields(&__bundle); - ::fayalite::__std::assert_eq!(__fields.len(), #fields_len, "bundle has wrong number of fields"); + let #fields_token = ::fayalite::bundle::BundleType::fields(&__bundle); + ::fayalite::__std::assert_eq!(#fields_token.len(), #fields_len, "bundle has wrong number of fields"); Self { #(#from_canonical_body_fields)* } @@ -665,7 +666,7 @@ impl ToTokens for ParsedBundle { { type Builder = #unfilled_mask_type_builder_ty; type FilledBuilder = #filled_mask_type_builder_ty; - fn fields(&self) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> { + fn fields(&#self_token) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> { ::fayalite::intern::Intern::intern(&[#(#fields_body_fields)*][..]) } } @@ -680,8 +681,8 @@ impl ToTokens for ParsedBundle { impl #impl_generics ::fayalite::ty::TypeWithDeref for #mask_type_ident #type_generics #where_clause { - fn expr_deref(__this: &::fayalite::expr::Expr) -> &::MatchVariant { - let __this = *__this; + fn expr_deref(#this_token: &::fayalite::expr::Expr) -> &::MatchVariant { + let #this_token = *#this_token; let __retval = #mask_type_match_variant_ident { #(#match_variant_body_fields)* }; @@ -703,7 +704,7 @@ impl ToTokens for ParsedBundle { ::MatchVariantAndInactiveScope, >; fn match_variants( - __this: ::fayalite::expr::Expr, + #this_token: ::fayalite::expr::Expr, __source_location: ::fayalite::source_location::SourceLocation, ) -> ::MatchVariantsIter { let __retval = #match_variant_ident { @@ -711,21 +712,21 @@ impl ToTokens for ParsedBundle { }; ::fayalite::__std::iter::once(::fayalite::ty::MatchVariantWithoutScope(__retval)) } - fn mask_type(&self) -> ::MaskType { + fn mask_type(&#self_token) -> ::MaskType { #mask_type_ident { #(#mask_type_body_fields)* } } - fn canonical(&self) -> ::fayalite::ty::CanonicalType { - ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(self))) + fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType { + ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(#self_token))) } #[track_caller] fn from_canonical(__canonical_type: ::fayalite::ty::CanonicalType) -> Self { let ::fayalite::ty::CanonicalType::Bundle(__bundle) = __canonical_type else { ::fayalite::__std::panic!("expected bundle"); }; - let __fields = ::fayalite::bundle::BundleType::fields(&__bundle); - ::fayalite::__std::assert_eq!(__fields.len(), #fields_len, "bundle has wrong number of fields"); + let #fields_token = ::fayalite::bundle::BundleType::fields(&__bundle); + ::fayalite::__std::assert_eq!(#fields_token.len(), #fields_len, "bundle has wrong number of fields"); Self { #(#from_canonical_body_fields)* } @@ -740,7 +741,7 @@ impl ToTokens for ParsedBundle { { type Builder = #unfilled_builder_ty; type FilledBuilder = #filled_builder_ty; - fn fields(&self) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> { + fn fields(&#self_token) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> { ::fayalite::intern::Intern::intern(&[#(#fields_body_fields)*][..]) } } @@ -755,8 +756,8 @@ impl ToTokens for ParsedBundle { impl #impl_generics ::fayalite::ty::TypeWithDeref for #target #type_generics #where_clause { - fn expr_deref(__this: &::fayalite::expr::Expr) -> &::MatchVariant { - let __this = *__this; + fn expr_deref(#this_token: &::fayalite::expr::Expr) -> &::MatchVariant { + let #this_token = *#this_token; let __retval = #match_variant_ident { #(#match_variant_body_fields)* }; @@ -772,7 +773,7 @@ impl ToTokens for ParsedBundle { let static_type_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| { let ident: &Ident = field.ident().as_ref().unwrap(); let ty = field.ty(); - quote_spanned! {ident.span()=> + quote_spanned! {span=> #ident: <#ty as ::fayalite::ty::StaticType>::TYPE, } })); @@ -780,28 +781,26 @@ impl ToTokens for ParsedBundle { Vec::from_iter(fields.named().into_iter().map(|field| { let ident: &Ident = field.ident().as_ref().unwrap(); let ty = field.ty(); - quote_spanned! {ident.span()=> + quote_spanned! {span=> #ident: <#ty as ::fayalite::ty::StaticType>::MASK_TYPE, } })); - let type_properties = format_ident!("__type_properties", span = ident.span()); + let type_properties = format_ident!("__type_properties", span = span); let type_properties_fields = Vec::from_iter(fields.named().into_iter().zip(field_flips).map(|(field, field_flip)| { - let ident: &Ident = field.ident().as_ref().unwrap(); let flipped = field_flip.is_some(); let ty = field.ty(); - quote_spanned! {ident.span()=> + quote_spanned! {span=> let #type_properties = #type_properties.field(#flipped, <#ty as ::fayalite::ty::StaticType>::TYPE_PROPERTIES); } })); let type_properties_mask_fields = Vec::from_iter(fields.named().into_iter().zip(field_flips).map(|(field, field_flip)| { - let ident: &Ident = field.ident().as_ref().unwrap(); let flipped = field_flip.is_some(); let ty = field.ty(); - quote_spanned! {ident.span()=> + quote_spanned! {span=> let #type_properties = #type_properties.field(#flipped, <#ty as ::fayalite::ty::StaticType>::MASK_TYPE_PROPERTIES); } })); - quote_spanned! {ident.span()=> + quote_spanned! {span=> #[automatically_derived] impl #static_impl_generics ::fayalite::ty::StaticType for #mask_type_ident #static_type_generics #static_where_clause diff --git a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs index 50fb138..adddd74 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs @@ -204,6 +204,7 @@ impl ToTokens for ParsedEnum { variants, match_variant_ident, } = self; + let span = ident.span(); let ItemOptions { outline_generated: _, target, @@ -213,8 +214,8 @@ impl ToTokens for ParsedEnum { } = &options.body; let target = get_target(target, ident); let mut struct_attrs = attrs.clone(); - struct_attrs.push(common_derives(ident.span())); - struct_attrs.push(parse_quote_spanned! {ident.span()=> + struct_attrs.push(common_derives(span)); + struct_attrs.push(parse_quote_spanned! {span=> #[allow(non_snake_case)] }); let struct_fields = Punctuated::from_iter(variants.pairs().map_pair_value_ref( @@ -238,8 +239,8 @@ impl ToTokens for ParsedEnum { colon_token = Token![:](paren_token.span.open()); ty.clone().into() } else { - colon_token = Token![:](ident.span()); - parse_quote_spanned! {ident.span()=> + colon_token = Token![:](span); + parse_quote_spanned! {span=> () } }; @@ -282,30 +283,30 @@ impl ToTokens for ParsedEnum { }) = field { let expr = ty.make_hdl_type_expr(context); - quote_spanned! {ident.span()=> + quote_spanned! {span=> #ident: #expr, } } else { - quote_spanned! {ident.span()=> + quote_spanned! {span=> #ident: (), } } }) .collect(); - parse_quote_spanned! {ident.span()=> + parse_quote_spanned! {span=> #target { #(#fields)* } } }) } - let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span()); + let mut wrapped_in_const = WrappedInConst::new(tokens, span); let tokens = wrapped_in_const.inner(); { - let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span()); + let mut wrapped_in_const = WrappedInConst::new(tokens, span); let tokens = wrapped_in_const.inner(); let mut enum_attrs = attrs.clone(); - enum_attrs.push(parse_quote_spanned! {ident.span()=> + enum_attrs.push(parse_quote_spanned! {span=> #[allow(dead_code)] }); ItemEnum { @@ -354,7 +355,7 @@ impl ToTokens for ParsedEnum { .to_tokens(tokens); } let mut enum_attrs = attrs.clone(); - enum_attrs.push(parse_quote_spanned! {ident.span()=> + enum_attrs.push(parse_quote_spanned! {span=> #[allow(dead_code, non_camel_case_types)] }); ItemEnum { @@ -389,7 +390,7 @@ impl ToTokens for ParsedEnum { mutability: FieldMutability::None, ident: None, colon_token: None, - ty: parse_quote_spanned! {ident.span()=> + ty: parse_quote_spanned! {span=> ::fayalite::expr::Expr<#ty> }, }, @@ -403,21 +404,22 @@ impl ToTokens for ParsedEnum { )), } .to_tokens(tokens); + let self_token = Token![self](span); for (index, ParsedVariant { ident, field, .. }) in variants.iter().enumerate() { if let Some(ParsedVariantField { ty, .. }) = field { - quote_spanned! {ident.span()=> + quote_spanned! {span=> #[automatically_derived] impl #impl_generics #target #type_generics #where_clause { #[allow(non_snake_case, dead_code)] #vis fn #ident<__V: ::fayalite::expr::ToExpr>( - self, + #self_token, v: __V, ) -> ::fayalite::expr::Expr { ::fayalite::expr::ToExpr::to_expr( &::fayalite::expr::ops::EnumLiteral::new_by_index( - self, + #self_token, #index, ::fayalite::__std::option::Option::Some( ::fayalite::expr::Expr::canonical( @@ -430,16 +432,16 @@ impl ToTokens for ParsedEnum { } } } else { - quote_spanned! {ident.span()=> + quote_spanned! {span=> #[automatically_derived] impl #impl_generics #target #type_generics #where_clause { #[allow(non_snake_case, dead_code)] - #vis fn #ident(self) -> ::fayalite::expr::Expr { + #vis fn #ident(#self_token) -> ::fayalite::expr::Expr { ::fayalite::expr::ToExpr::to_expr( &::fayalite::expr::ops::EnumLiteral::new_by_index( - self, + #self_token, #index, ::fayalite::__std::option::Option::None, ), @@ -450,46 +452,48 @@ impl ToTokens for ParsedEnum { } .to_tokens(tokens); } + let variants_token = Ident::new("variants", span); let from_canonical_body_fields = Vec::from_iter(variants.iter().enumerate().map( |(index, ParsedVariant { ident, field, .. })| { let ident_str = ident.to_string(); let val = if field.is_some() { let missing_value_msg = format!("expected variant {ident} to have a field"); - quote_spanned! {ident.span()=> + quote_spanned! {span=> ::fayalite::ty::Type::from_canonical(ty.expect(#missing_value_msg)) } } else { - quote_spanned! {ident.span()=> + quote_spanned! {span=> ::fayalite::__std::assert!(ty.is_none()); } }; - quote_spanned! {ident.span()=> + quote_spanned! {span=> #ident: { let ::fayalite::enum_::EnumVariant { name, ty, - } = variants[#index]; + } = #variants_token[#index]; ::fayalite::__std::assert_eq!(&*name, #ident_str); #val }, } }, )); + let variant_access_token = Ident::new("variant_access", span); let match_active_scope_match_arms = Vec::from_iter(variants.iter().enumerate().map( |(index, ParsedVariant { ident, field, .. })| { if field.is_some() { - quote_spanned! {ident.span()=> + quote_spanned! {span=> #index => #match_variant_ident::#ident( ::fayalite::expr::ToExpr::to_expr( &::fayalite::expr::ops::VariantAccess::new_by_index( - variant_access.base(), - variant_access.variant_index(), + #variant_access_token.base(), + #variant_access_token.variant_index(), ), ), ), } } else { - quote_spanned! {ident.span()=> + quote_spanned! {span=> #index => #match_variant_ident::#ident, } } @@ -507,16 +511,16 @@ impl ToTokens for ParsedEnum { match field { Some(ParsedVariantField { options, .. }) => { let FieldOptions {} = options.body; - quote_spanned! {ident.span()=> + quote_spanned! {span=> ::fayalite::enum_::EnumVariant { name: ::fayalite::intern::Intern::intern(#ident_str), ty: ::fayalite::__std::option::Option::Some( - ::fayalite::ty::Type::canonical(&self.#ident), + ::fayalite::ty::Type::canonical(&#self_token.#ident), ), }, } } - None => quote_spanned! {ident.span()=> + None => quote_spanned! {span=> ::fayalite::enum_::EnumVariant { name: ::fayalite::intern::Intern::intern(#ident_str), ty: ::fayalite::__std::option::Option::None, @@ -526,7 +530,7 @@ impl ToTokens for ParsedEnum { }, )); let variants_len = variants.len(); - quote_spanned! {ident.span()=> + quote_spanned! {span=> #[automatically_derived] impl #impl_generics ::fayalite::ty::Type for #target #type_generics #where_clause @@ -544,11 +548,11 @@ impl ToTokens for ParsedEnum { ) -> ::MatchVariantsIter { ::fayalite::module::enum_match_variants_helper(this, source_location) } - fn mask_type(&self) -> ::MaskType { + fn mask_type(&#self_token) -> ::MaskType { ::fayalite::int::Bool } - fn canonical(&self) -> ::fayalite::ty::CanonicalType { - ::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(self))) + fn canonical(&#self_token) -> ::fayalite::ty::CanonicalType { + ::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(#self_token))) } #[track_caller] #[allow(non_snake_case)] @@ -556,8 +560,8 @@ impl ToTokens for ParsedEnum { let ::fayalite::ty::CanonicalType::Enum(enum_) = canonical_type else { ::fayalite::__std::panic!("expected enum"); }; - let variants = ::fayalite::enum_::EnumType::variants(&enum_); - ::fayalite::__std::assert_eq!(variants.len(), #variants_len, "enum has wrong number of variants"); + let #variants_token = ::fayalite::enum_::EnumType::variants(&enum_); + ::fayalite::__std::assert_eq!(#variants_token.len(), #variants_len, "enum has wrong number of variants"); Self { #(#from_canonical_body_fields)* } @@ -573,16 +577,16 @@ impl ToTokens for ParsedEnum { fn match_activate_scope( v: ::MatchVariantAndInactiveScope, ) -> (::MatchVariant, ::MatchActiveScope) { - let (variant_access, scope) = v.activate(); + let (#variant_access_token, scope) = v.activate(); ( - match variant_access.variant_index() { + match #variant_access_token.variant_index() { #(#match_active_scope_match_arms)* #variants_len.. => ::fayalite::__std::panic!("invalid variant index"), }, scope, ) } - fn variants(&self) -> ::fayalite::intern::Interned<[::fayalite::enum_::EnumVariant]> { + fn variants(&#self_token) -> ::fayalite::intern::Interned<[::fayalite::enum_::EnumVariant]> { ::fayalite::intern::Intern::intern(&[ #(#variants_body_variants)* ][..]) @@ -597,34 +601,34 @@ impl ToTokens for ParsedEnum { let static_type_body_variants = Vec::from_iter(variants.iter().map(|ParsedVariant { ident, field, .. }| { if let Some(_) = field { - quote_spanned! {ident.span()=> + quote_spanned! {span=> #ident: ::fayalite::ty::StaticType::TYPE, } } else { - quote_spanned! {ident.span()=> + quote_spanned! {span=> #ident: (), } } })); - let type_properties = format_ident!("__type_properties", span = ident.span()); + let type_properties = format_ident!("__type_properties", span = span); let type_properties_variants = - Vec::from_iter(variants.iter().map(|ParsedVariant { ident, field, .. }| { + Vec::from_iter(variants.iter().map(|ParsedVariant { field, .. }| { let variant = if let Some(ParsedVariantField { ty, .. }) = field { - quote_spanned! {ident.span()=> + quote_spanned! {span=> ::fayalite::__std::option::Option::Some( <#ty as ::fayalite::ty::StaticType>::TYPE_PROPERTIES, ) } } else { - quote_spanned! {ident.span()=> + quote_spanned! {span=> ::fayalite::__std::option::Option::None } }; - quote_spanned! {ident.span()=> + quote_spanned! {span=> let #type_properties = #type_properties.variant(#variant); } })); - quote_spanned! {ident.span()=> + quote_spanned! {span=> #[automatically_derived] impl #static_impl_generics ::fayalite::ty::StaticType for #target #static_type_generics diff --git a/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs b/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs index efbe7f3..e7561fe 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs @@ -1896,6 +1896,7 @@ pub(crate) mod known_items { impl_known_item!(::fayalite::array::ArrayType); impl_known_item!(::fayalite::bundle::BundleType); impl_known_item!(::fayalite::enum_::EnumType); + impl_known_item!(::fayalite::int::BoolOrIntType); impl_known_item!(::fayalite::int::DynSize); impl_known_item!(::fayalite::int::IntType); impl_known_item!(::fayalite::int::KnownSize); @@ -2085,6 +2086,7 @@ macro_rules! impl_bounds { impl_bounds! { #[struct = ParsedBounds] pub(crate) enum ParsedBound { + BoolOrIntType, BundleType, EnumType, IntType, @@ -2098,6 +2100,7 @@ impl_bounds! { impl_bounds! { #[struct = ParsedTypeBounds] pub(crate) enum ParsedTypeBound { + BoolOrIntType, BundleType, EnumType, IntType, @@ -2109,6 +2112,7 @@ impl_bounds! { impl From for ParsedBound { fn from(value: ParsedTypeBound) -> Self { match value { + ParsedTypeBound::BoolOrIntType(v) => ParsedBound::BoolOrIntType(v), ParsedTypeBound::BundleType(v) => ParsedBound::BundleType(v), ParsedTypeBound::EnumType(v) => ParsedBound::EnumType(v), ParsedTypeBound::IntType(v) => ParsedBound::IntType(v), @@ -2121,6 +2125,7 @@ impl From for ParsedBound { impl From for ParsedBounds { fn from(value: ParsedTypeBounds) -> Self { let ParsedTypeBounds { + BoolOrIntType, BundleType, EnumType, IntType, @@ -2128,6 +2133,7 @@ impl From for ParsedBounds { Type, } = value; Self { + BoolOrIntType, BundleType, EnumType, IntType, @@ -2143,6 +2149,10 @@ impl ParsedTypeBound { fn implied_bounds(self) -> ParsedTypeBounds { let span = self.span(); match self { + Self::BoolOrIntType(v) => ParsedTypeBounds::from_iter([ + ParsedTypeBound::from(v), + ParsedTypeBound::Type(known_items::Type(span)), + ]), Self::BundleType(v) => ParsedTypeBounds::from_iter([ ParsedTypeBound::from(v), ParsedTypeBound::Type(known_items::Type(span)), @@ -2153,6 +2163,7 @@ impl ParsedTypeBound { ]), Self::IntType(v) => ParsedTypeBounds::from_iter([ ParsedTypeBound::from(v), + ParsedTypeBound::BoolOrIntType(known_items::BoolOrIntType(span)), ParsedTypeBound::Type(known_items::Type(span)), ]), Self::StaticType(v) => ParsedTypeBounds::from_iter([ @@ -2185,6 +2196,7 @@ impl From for ParsedBounds { fn from(value: ParsedSizeTypeBounds) -> Self { let ParsedSizeTypeBounds { KnownSize, Size } = value; Self { + BoolOrIntType: None, BundleType: None, EnumType: None, IntType: None, @@ -2260,6 +2272,7 @@ pub(crate) enum ParsedBoundCategory { impl ParsedBound { fn categorize(self) -> ParsedBoundCategory { match self { + Self::BoolOrIntType(v) => ParsedBoundCategory::Type(ParsedTypeBound::BoolOrIntType(v)), Self::BundleType(v) => ParsedBoundCategory::Type(ParsedTypeBound::BundleType(v)), Self::EnumType(v) => ParsedBoundCategory::Type(ParsedTypeBound::EnumType(v)), Self::IntType(v) => ParsedBoundCategory::Type(ParsedTypeBound::IntType(v)), @@ -2575,6 +2588,7 @@ impl ParsedGenerics { } }) .collect(); + let param_token = Ident::new("__param", ident.span()); for (param_count, (generics_accumulation_type, next_param)) in generics_accumulation_types .iter() .zip(&self.params) @@ -2623,7 +2637,7 @@ impl ParsedGenerics { next_generics.split_for_impl(); let next_turbofish = next_type_generics.as_turbofish(); let mut param: Expr = parse_quote_spanned! {ident.span()=> - __param + #param_token }; let mut generics = next_generics.clone(); let mut index_type = param_ident.clone(); @@ -2638,7 +2652,7 @@ impl ParsedGenerics { is_const: false, }); param = parse_quote_spanned! {ident.span()=> - ::fayalite::ty::TypeOrDefault::get(__param, || #default_expr) + ::fayalite::ty::TypeOrDefault::get(#param_token, || #default_expr) }; let context = MakeHdlTypeExprContext { named_param_values: self_members[..param_count] @@ -2703,7 +2717,7 @@ impl ParsedGenerics { { type Output = #next_target #next_type_generics; - fn index(&self, __param: #index_type) -> &Self::Output { + fn index(&self, #param_token: #index_type) -> &Self::Output { ::fayalite::intern::Interned::<_>::into_inner( ::fayalite::intern::Intern::intern_sized(#output_expr), ) @@ -2724,7 +2738,7 @@ impl ParsedGenerics { .iter() .cloned() .chain([parse_quote_spanned! {ident.span()=> - __param + #param_token }]) .collect(), is_const: false, @@ -2763,7 +2777,7 @@ impl ParsedGenerics { { type Output = #next_target #next_target_args; - fn index(&self, __param: #param_ident) -> &Self::Output { + fn index(&self, #param_token: #param_ident) -> &Self::Output { ::fayalite::intern::Interned::<_>::into_inner( ::fayalite::intern::Intern::intern_sized(#output_expr), ) @@ -2791,7 +2805,7 @@ impl ParsedGenerics { .iter() .cloned() .chain([parse_quote_spanned! {ident.span()=> - __param + #param_token }]) .collect(), is_const: false, @@ -2833,7 +2847,7 @@ impl ParsedGenerics { { type Output = #next_target #next_target_args; - fn index(&self, __param: __Param) -> &Self::Output { + fn index(&self, #param_token: __Param) -> &Self::Output { ::fayalite::intern::Interned::<_>::into_inner( ::fayalite::intern::Intern::intern_sized(#output_expr), ) @@ -3145,16 +3159,21 @@ impl ParsedGenerics { .Type .get_or_insert_with(|| known_items::Type(bound.span())); match bound { - ParsedTypeBound::BundleType(_) + ParsedTypeBound::BoolOrIntType(_) + | ParsedTypeBound::BundleType(_) | ParsedTypeBound::EnumType(_) | ParsedTypeBound::IntType(_) => { errors.error(bound, "bound on mask type not implemented"); } ParsedTypeBound::StaticType(bound) => { if bounds.StaticType.is_none() { - errors.error(bound, "StaticType bound on mask type without corresponding StaticType bound on original type is not implemented"); + errors.error( + bound, + "StaticType bound on mask type without corresponding \ + StaticType bound on original type is not implemented", + ); } - }, + } ParsedTypeBound::Type(_) => {} } } diff --git a/crates/fayalite/src/ty.rs b/crates/fayalite/src/ty.rs index c7081eb..380d2e6 100644 --- a/crates/fayalite/src/ty.rs +++ b/crates/fayalite/src/ty.rs @@ -210,7 +210,9 @@ impl sealed::BaseTypeSealed for CanonicalType {} impl BaseType for CanonicalType {} -pub trait TypeOrDefault: sealed::TypeOrDefaultSealed { +pub trait TypeOrDefault: + sealed::TypeOrDefaultSealed + Copy + Eq + Hash + fmt::Debug +{ type Type: Type; fn get D>(self, default: F) -> Self::Type; } diff --git a/crates/fayalite/tests/hdl_types.rs b/crates/fayalite/tests/hdl_types.rs index d043013..3f11de3 100644 --- a/crates/fayalite/tests/hdl_types.rs +++ b/crates/fayalite/tests/hdl_types.rs @@ -29,3 +29,69 @@ pub enum E { pub struct S2 { pub v: E, } + +// check that #[hdl] properly handles hygiene +macro_rules! types_in_macros { + ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident, $f:ident, $A:ident, $B:ident, $C:ident, $D:ident, $E:ident, $F:ident) => { + #[hdl] + struct $F {} + #[hdl] + struct $A<$B, $C: Size, const $D: usize, $E = $F> { + $a: $B, + $b: UIntType<$C>, + $c: SInt<$D>, + $d: HdlOption<$E>, + $e: $E, + $f: $F, + } + #[allow(non_camel_case_types)] + #[hdl] + enum $B<$C: Size, const $D: usize, $E = $F> { + $a($A<(), $C, $D, $E>), + $b(UIntType<$C>), + $c(SInt<$D>), + $d, + $e($E), + $f($F), + } + }; + // ensure every identifier has different hygiene + () => { + types_in_macros!(a); + }; + ($a:ident) => { + types_in_macros!($a, b); + }; + ($a:ident, $b:ident) => { + types_in_macros!($a, $b, c); + }; + ($a:ident, $b:ident, $c:ident) => { + types_in_macros!($a, $b, $c, d); + }; + ($a:ident, $b:ident, $c:ident, $d:ident) => { + types_in_macros!($a, $b, $c, $d, e); + }; + ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident) => { + types_in_macros!($a, $b, $c, $d, $e, f); + }; + ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident, $f:ident) => { + types_in_macros!($a, $b, $c, $d, $e, $f, A); + }; + ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident, $f:ident, $A:ident) => { + types_in_macros!($a, $b, $c, $d, $e, $f, $A, B); + }; + ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident, $f:ident, $A:ident, $B:ident) => { + types_in_macros!($a, $b, $c, $d, $e, $f, $A, $B, C); + }; + ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident, $f:ident, $A:ident, $B:ident, $C:ident) => { + types_in_macros!($a, $b, $c, $d, $e, $f, $A, $B, $C, D); + }; + ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident, $f:ident, $A:ident, $B:ident, $C:ident, $D:ident) => { + types_in_macros!($a, $b, $c, $d, $e, $f, $A, $B, $C, $D, E); + }; + ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident, $f:ident, $A:ident, $B:ident, $C:ident, $D:ident, $E:ident) => { + types_in_macros!($a, $b, $c, $d, $e, $f, $A, $B, $C, $D, $E, F); + }; +} + +types_in_macros!();