From 9887d70f4105515de5e93944a80af399a67c4514 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 19 Sep 2024 18:45:04 -0700 Subject: [PATCH] fix handling of const and size type generics when generating Index impls --- crates/fayalite-proc-macros-impl/src/fold.rs | 1 + .../src/hdl_type_common.rs | 634 +++++++++++++----- crates/fayalite/src/array.rs | 26 +- crates/fayalite/src/int.rs | 52 +- crates/fayalite/tests/hdl_types.rs | 18 +- 5 files changed, 519 insertions(+), 212 deletions(-) diff --git a/crates/fayalite-proc-macros-impl/src/fold.rs b/crates/fayalite-proc-macros-impl/src/fold.rs index 61e425a..7f2e580 100644 --- a/crates/fayalite-proc-macros-impl/src/fold.rs +++ b/crates/fayalite-proc-macros-impl/src/fold.rs @@ -230,6 +230,7 @@ forward_fold!(syn::Path => fold_path); forward_fold!(syn::Type => fold_type); forward_fold!(syn::TypePath => fold_type_path); forward_fold!(syn::WherePredicate => fold_where_predicate); +no_op_fold!(proc_macro2::Span); no_op_fold!(syn::parse::Nothing); no_op_fold!(syn::token::Brace); no_op_fold!(syn::token::Bracket); 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 bc0b074..88da9a7 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs @@ -8,11 +8,12 @@ use syn::{ punctuated::{Pair, Punctuated}, spanned::Spanned, token::{Brace, Bracket, Paren}, - AngleBracketedGenericArguments, Attribute, ConstParam, Expr, ExprIndex, ExprPath, ExprTuple, - Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, GenericArgument, GenericParam, - Generics, Ident, ImplGenerics, Index, ItemStruct, Path, PathArguments, PathSegment, - PredicateType, QSelf, Token, Turbofish, Type, TypeGenerics, TypeGroup, TypeParam, TypeParen, - TypePath, TypeTuple, Visibility, WhereClause, WherePredicate, + AngleBracketedGenericArguments, Attribute, Block, ConstParam, Expr, ExprBlock, ExprGroup, + ExprIndex, ExprParen, ExprPath, ExprTuple, Field, FieldMutability, Fields, FieldsNamed, + FieldsUnnamed, GenericArgument, GenericParam, Generics, Ident, ImplGenerics, Index, ItemStruct, + Path, PathArguments, PathSegment, PredicateType, QSelf, Stmt, Token, Turbofish, Type, + TypeGenerics, TypeGroup, TypeParam, TypeParen, TypePath, TypeTuple, Visibility, WhereClause, + WherePredicate, }; crate::options! { @@ -113,6 +114,230 @@ macro_rules! parse_failed { }}; } +#[derive(Copy, Clone, Debug)] +pub(crate) enum ExprDelimiter { + Group(syn::token::Group), + Brace(Brace), + Paren(Paren), +} + +impl_fold! { + enum ExprDelimiter<> { + Group(syn::token::Group), + Brace(Brace), + Paren(Paren), + } +} + +impl ExprDelimiter { + pub(crate) fn surround(self, tokens: &mut TokenStream, f: F) { + match self { + ExprDelimiter::Group(v) => v.surround(tokens, f), + ExprDelimiter::Brace(v) => v.surround(tokens, f), + ExprDelimiter::Paren(v) => v.surround(tokens, f), + } + } +} + +#[derive(Debug, Clone)] +pub(crate) struct ParsedExprDelimited { + pub(crate) delim: ExprDelimiter, + pub(crate) expr: Box, +} + +impl_fold! { + struct ParsedExprDelimited<> { + delim: ExprDelimiter, + expr: Box, + } +} + +impl From for Expr { + fn from(value: ParsedExprDelimited) -> Self { + let ParsedExprDelimited { delim, expr } = value; + let expr = expr.into(); + match delim { + ExprDelimiter::Group(group_token) => Expr::Group(ExprGroup { + attrs: vec![], + group_token, + expr: Box::new(expr), + }), + ExprDelimiter::Brace(brace_token) => Expr::Block(ExprBlock { + attrs: vec![], + label: None, + block: Block { + brace_token, + stmts: vec![Stmt::Expr(expr, None)], + }, + }), + ExprDelimiter::Paren(paren_token) => Expr::Paren(ExprParen { + attrs: vec![], + paren_token, + expr: Box::new(expr), + }), + } + } +} + +impl ToTokens for ParsedExprDelimited { + fn to_tokens(&self, tokens: &mut TokenStream) { + let Self { delim, expr } = self; + delim.surround(tokens, |tokens| expr.to_tokens(tokens)); + } +} + +#[derive(Debug, Clone)] +pub(crate) struct ParsedExprNamedParamConst { + pub(crate) ident: Ident, + pub(crate) param_index: usize, +} + +impl_fold! { + struct ParsedExprNamedParamConst<> { + ident: Ident, + param_index: usize, + } +} + +impl ToTokens for ParsedExprNamedParamConst { + fn to_tokens(&self, tokens: &mut TokenStream) { + let Self { + ident, + param_index: _, + } = self; + ident.to_tokens(tokens); + } +} + +impl From for Expr { + fn from(value: ParsedExprNamedParamConst) -> Self { + Expr::Path(ExprPath { + attrs: vec![], + qself: None, + path: value.ident.into(), + }) + } +} + +#[derive(Clone, Debug)] +pub(crate) enum ParsedExpr { + Delimited(ParsedExprDelimited), + NamedParamConst(ParsedExprNamedParamConst), + Other(Box), +} + +impl ParsedExpr { + pub(crate) fn named_param_const(mut self: &Self) -> Option<&ParsedExprNamedParamConst> { + loop { + match self { + ParsedExpr::Delimited(ParsedExprDelimited { expr, .. }) => self = &**expr, + ParsedExpr::NamedParamConst(retval) => return Some(retval), + ParsedExpr::Other(_) => return None, + } + } + } +} + +impl_fold! { + enum ParsedExpr<> { + Delimited(ParsedExprDelimited), + NamedParamConst(ParsedExprNamedParamConst), + Other(Box), + } +} + +impl ToTokens for ParsedExpr { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + ParsedExpr::Delimited(v) => v.to_tokens(tokens), + ParsedExpr::NamedParamConst(v) => v.to_tokens(tokens), + ParsedExpr::Other(v) => v.to_tokens(tokens), + } + } +} + +impl From for Expr { + fn from(value: ParsedExpr) -> Self { + match value { + ParsedExpr::Delimited(expr) => expr.into(), + ParsedExpr::NamedParamConst(expr) => expr.into(), + ParsedExpr::Other(expr) => *expr, + } + } +} + +impl From> for Expr { + fn from(value: Box) -> Self { + (*value).into() + } +} + +impl ParseTypes for ParsedExpr { + fn parse_types(input: &mut Expr, parser: &mut TypesParser<'_>) -> Result { + match input { + Expr::Block(ExprBlock { + attrs, + label: None, + block: Block { brace_token, stmts }, + }) if attrs.is_empty() && stmts.len() == 1 => { + if let Stmt::Expr(expr, None) = &mut stmts[0] { + return Ok(ParsedExpr::Delimited(ParsedExprDelimited { + delim: ExprDelimiter::Brace(*brace_token), + expr: Box::new(parser.parse(expr)?), + })); + } + } + Expr::Group(ExprGroup { + attrs, + group_token, + expr, + }) if attrs.is_empty() => { + return Ok(ParsedExpr::Delimited(ParsedExprDelimited { + delim: ExprDelimiter::Group(*group_token), + expr: parser.parse(expr)?, + })) + } + Expr::Paren(ExprParen { + attrs, + paren_token, + expr, + }) if attrs.is_empty() => { + return Ok(ParsedExpr::Delimited(ParsedExprDelimited { + delim: ExprDelimiter::Paren(*paren_token), + expr: parser.parse(expr)?, + })) + } + Expr::Path(ExprPath { + attrs, + qself: None, + path, + }) if attrs.is_empty() => { + if let Some((param_index, ident)) = parser.get_named_param(path) { + return Ok(Self::NamedParamConst( + match parser.generics().params[param_index] { + ParsedGenericParam::Const(_) => ParsedExprNamedParamConst { + ident: ident.clone(), + param_index, + }, + ParsedGenericParam::Type(ParsedTypeParam { ref ident, .. }) + | ParsedGenericParam::SizeType(ParsedSizeTypeParam { + ref ident, .. + }) => { + parser + .errors + .error(ident, "type provided when a constant was expected"); + return Err(ParseFailed); + } + }, + )); + } + } + _ => {} + } + Ok(ParsedExpr::Other(Box::new(input.clone()))) + } +} + #[derive(Copy, Clone, Debug)] pub(crate) enum TypeDelimiter { Group(syn::token::Group), @@ -214,13 +439,13 @@ impl ParseTypes for ParsedTypeTuple { #[derive(Debug, Clone)] pub(crate) enum ParsedGenericArgument { Type(ParsedType), - Const(Expr), + Const(ParsedExpr), } impl_fold! { enum ParsedGenericArgument<> { Type(ParsedType), - Const(Expr), + Const(ParsedExpr), } } @@ -246,20 +471,16 @@ impl ParseTypes for ParsedGenericArgument { ty = &**elem; } if let Type::Path(TypePath { qself: None, path }) = ty { - if let Some(ident) = path.get_ident() { - if let Some(¶m_index) = - parser.generics.param_name_to_index_map.get(ident) - { - match parser.generics.params[param_index] { - ParsedGenericParam::Type(_) - | ParsedGenericParam::SizeType(_) => {} - ParsedGenericParam::Const(_) => { - return Ok(Self::Const(Expr::Path(ExprPath { - attrs: vec![], - qself: None, - path: path.clone(), - }))); - } + if let Some((param_index, ident)) = parser.get_named_param(path) { + match parser.generics.params[param_index] { + ParsedGenericParam::Type(_) | ParsedGenericParam::SizeType(_) => {} + ParsedGenericParam::Const(_) => { + return Ok(Self::Const(ParsedExpr::NamedParamConst( + ParsedExprNamedParamConst { + ident: ident.clone(), + param_index, + }, + ))); } } } @@ -267,7 +488,7 @@ impl ParseTypes for ParsedGenericArgument { } Ok(Self::Type(parser.parse(ty)?)) } - GenericArgument::Const(expr) => Ok(Self::Const(expr.clone())), + GenericArgument::Const(expr) => Ok(Self::Const(parser.parse(expr)?)), _ => parse_failed!(parser, arg, "expected type or const generic argument"), } } @@ -277,7 +498,7 @@ impl From for GenericArgument { fn from(value: ParsedGenericArgument) -> Self { match value { ParsedGenericArgument::Type(ty) => Self::Type(ty.into()), - ParsedGenericArgument::Const(expr) => Self::Const(expr), + ParsedGenericArgument::Const(expr) => Self::Const(expr.into()), } } } @@ -496,7 +717,7 @@ impl ToTokens for ParsedTypeNamedParam { pub(crate) struct ParsedTypeConstUsize { pub(crate) const_usize: known_items::ConstUsize, pub(crate) lt_token: Token![<], - pub(crate) value: Box, + pub(crate) value: ParsedExpr, pub(crate) gt_token: Token![>], } @@ -504,7 +725,7 @@ impl_fold! { struct ParsedTypeConstUsize<> { const_usize: known_items::ConstUsize, lt_token: Token![<], - value: Box, + value: ParsedExpr, gt_token: Token![>], } } @@ -518,7 +739,7 @@ impl From for Path { gt_token, } = value; let path = const_usize.path; - let args = Punctuated::from_iter([GenericArgument::Const(*value)]); + let args = Punctuated::from_iter([GenericArgument::Const(value.into())]); let args = AngleBracketedGenericArguments { colon2_token: Some(Token![::](lt_token.span)), lt_token, @@ -544,12 +765,16 @@ impl From for Type { } impl MakeHdlTypeExpr for ParsedTypeConstUsize { - fn make_hdl_type_expr(&self, _context: &MakeHdlTypeExprContext) -> Expr { - Expr::Path(ExprPath { - attrs: vec![], - qself: None, - path: self.clone().into(), - }) + fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { + if let Some(named_param_const) = self.value.named_param_const() { + named_param_const.make_hdl_type_expr(context) + } else { + Expr::Path(ExprPath { + attrs: vec![], + qself: None, + path: self.clone().into(), + }) + } } } @@ -606,7 +831,7 @@ impl ParsedTypeConstUsize { Ok(Ok(Self { const_usize, lt_token, - value: Box::new(value), + value, gt_token, })) } @@ -694,7 +919,7 @@ macro_rules! make_parsed_type_or_const { let $type_arg = Box::new(ParsedType::ConstUsize(ParsedTypeConstUsize { const_usize: known_items::ConstUsize($span), lt_token: Token![<]($span), - value: Box::new($const_arg.clone()), + value: $const_arg.clone(), gt_token: Token![>]($span), })); ($type_arg, Some(Box::new($const_arg))) @@ -887,7 +1112,7 @@ macro_rules! make_parsed_type_or_const { let mut args = Punctuated::new(); $( args.push(( - ($(|| GenericArgument::Const(*$const_arg),)? + ($(|| GenericArgument::Const($const_arg.into()),)? || GenericArgument::Type($type_arg.into()), ).0)()); $(args.push_punct($separator);)? @@ -1010,7 +1235,7 @@ make_parsed_type_or_const! { #[separator] comma_token: Token![,], #[const] - const_len: Option>, + const_len: Option>, #[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))] type_len: Box, gt_token: Token![>], @@ -1024,7 +1249,7 @@ make_parsed_type_or_const! { uint_type: known_items::UIntType, lt_token: Token![<], #[const] - const_width: Option>, + const_width: Option>, #[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))] type_width: Box, gt_token: Token![>], @@ -1038,7 +1263,7 @@ make_parsed_type_or_const! { uint_type: known_items::SIntType, lt_token: Token![<], #[const] - const_width: Option>, + const_width: Option>, #[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))] type_width: Box, gt_token: Token![>], @@ -1207,40 +1432,29 @@ impl ParseTypes for ParsedType { }, args, }; - if let Some(ident) = named.path.get_ident() { - if let Some(¶m_index) = parser.generics().param_name_to_index_map.get(ident) { - if parser - .cur_param_index - .is_some_and(|cur_param_index| param_index >= cur_param_index) - { - parser.errors.error( - parser.generics().params[param_index].ident(), - "cannot use forward declared identifier in generic parameter defaults", - ); - } - return Ok(Self::NamedParam( - match parser.generics().params[param_index] { - ParsedGenericParam::Type(_) => { - ParsedTypeNamedParam::Type(ParsedTypeNamedParamType { - ident: ident.clone(), - param_index, - }) - } - ParsedGenericParam::SizeType(_) => { - ParsedTypeNamedParam::SizeType(ParsedTypeNamedParamSizeType { - ident: ident.clone(), - param_index, - }) - } - ParsedGenericParam::Const(ParsedConstParam { ref ident, .. }) => { - parser - .errors - .error(ident, "constant provided when a type was expected"); - return Err(ParseFailed); - } - }, - )); - } + if let Some((param_index, ident)) = parser.get_named_param(&named.path) { + return Ok(Self::NamedParam( + match parser.generics().params[param_index] { + ParsedGenericParam::Type(_) => { + ParsedTypeNamedParam::Type(ParsedTypeNamedParamType { + ident: ident.clone(), + param_index, + }) + } + ParsedGenericParam::SizeType(_) => { + ParsedTypeNamedParam::SizeType(ParsedTypeNamedParamSizeType { + ident: ident.clone(), + param_index, + }) + } + ParsedGenericParam::Const(ParsedConstParam { ref ident, .. }) => { + parser + .errors + .error(ident, "constant provided when a type was expected"); + return Err(ParseFailed); + } + }, + )); } let named = match ParsedTypeArray::try_from_named(named, parser)? { Ok(v) => return Ok(Self::Array(v)), @@ -1489,6 +1703,18 @@ impl<'a> TypesParser<'a> { pub(crate) fn parse, I>(&mut self, input: &mut I) -> Result { T::parse_types(input, self) } + pub(crate) fn get_named_param<'b>(&mut self, path: &'b Path) -> Option<(usize, &'b Ident)> { + let ident = path.get_ident()?; + let param_index = *self.generics().param_name_to_index_map.get(ident)?; + if self + .cur_param_index + .is_some_and(|cur_param_index| param_index >= cur_param_index) + { + self.errors + .error(path, "cannot use forward declared identifier here"); + } + Some((param_index, ident)) + } } pub(crate) trait ParseTypes: Sized { @@ -2311,7 +2537,7 @@ impl ParsedGenerics { ) { if self.params.is_empty() { let target_expr = target_expr(&MakeHdlTypeExprContext { - type_arg_values: vec![], + named_param_values: vec![], is_const: true, }); quote_spanned! {ident.span()=> @@ -2364,36 +2590,40 @@ impl ParsedGenerics { .clone() .into() }; - let next_generics = if is_last { - &final_generics - } else { - &generics_accumulation_types[next_param_count].generics + let make_next_target_args = |next_arg: Option| { + let generics = if is_last { + &final_generics + } else { + &generics_accumulation_types[next_param_count].generics + }; + let type_generics = generics.split_for_impl().1; + let turbofish = type_generics.as_turbofish(); + let mut retval: AngleBracketedGenericArguments = parse_quote! { #turbofish }; + if let Some(next_arg) = next_arg { + *retval.args.last_mut().unwrap() = next_arg; + } + retval }; let (cur_impl_generics, cur_type_generics, cur_where_clause) = cur_generics.split_for_impl(); - let (_next_impl_generics, next_type_generics, _next_where_clause) = - next_generics.split_for_impl(); - let next_turbofish = next_type_generics.as_turbofish(); - let mut next_target_expr = |context: &MakeHdlTypeExprContext| -> Expr { - if is_last { - target_expr(context) - } else { - let args = &context.type_arg_values[..next_param_count]; - parse_quote_spanned! {ident.span()=> - #next_target #next_turbofish(#(#args),*) - } - } - }; match next_param { ParsedGenericParam::Type(ParsedTypeParam { ident: param_ident, default, .. }) => { - let mut generics = next_generics.clone(); + let next_generics = if is_last { + &final_generics + } else { + &generics_accumulation_types[next_param_count].generics + }; + let (_next_impl_generics, next_type_generics, _next_where_clause) = + next_generics.split_for_impl(); + let next_turbofish = next_type_generics.as_turbofish(); let mut param: Expr = parse_quote_spanned! {ident.span()=> __param }; + let mut generics = next_generics.clone(); let mut index_type = param_ident.clone(); if let Some((_, default)) = default { index_type = format_ident!("__Param", span = ident.span()); @@ -2402,24 +2632,34 @@ impl ParsedGenerics { #index_type: ::fayalite::ty::TypeOrDefault<#default, Type = #param_ident> }); let default_expr = default.make_hdl_type_expr(&MakeHdlTypeExprContext { - type_arg_values: self_members[..param_count].to_vec(), + named_param_values: self_members[..param_count].to_vec(), is_const: false, }); param = parse_quote_spanned! {ident.span()=> ::fayalite::ty::TypeOrDefault::get(__param, || #default_expr) }; - let output_expr = next_target_expr(&MakeHdlTypeExprContext { - type_arg_values: self_members[..param_count] + let context = MakeHdlTypeExprContext { + named_param_values: self_members[..param_count] .iter() .cloned() .chain([default_expr]) .collect(), is_const: false, - }); - let mut next_target_args: AngleBracketedGenericArguments = - parse_quote! { #next_type_generics }; - *next_target_args.args.last_mut().unwrap() = - GenericArgument::Type(default.clone().into()); + }; + let output_expr = { + let next_turbofish = next_type_generics.as_turbofish(); + if is_last { + target_expr(&context) + } else { + let args = &context.named_param_values[..next_param_count]; + parse_quote_spanned! {ident.span()=> + #next_target #next_turbofish(#(#args),*) + } + } + }; + let next_target_args = make_next_target_args(Some(GenericArgument::Type( + default.clone().into(), + ))); quote_spanned! {ident.span()=> impl #cur_impl_generics ::fayalite::ty::FillInDefaultedGenerics for #cur_target #cur_type_generics @@ -2436,14 +2676,22 @@ impl ParsedGenerics { .to_tokens(tokens); } let (impl_generics, _type_generics, where_clause) = generics.split_for_impl(); - let output_expr = next_target_expr(&MakeHdlTypeExprContext { - type_arg_values: self_members[..param_count] + let context = MakeHdlTypeExprContext { + named_param_values: self_members[..param_count] .iter() .cloned() .chain([param]) .collect(), is_const: false, - }); + }; + let output_expr = if is_last { + target_expr(&context) + } else { + let args = &context.named_param_values[..next_param_count]; + parse_quote_spanned! {ident.span()=> + #next_target #next_turbofish(#(#args),*) + } + }; quote_spanned! {ident.span()=> #[allow(non_upper_case_globals)] #[automatically_derived] @@ -2468,46 +2716,9 @@ impl ParsedGenerics { default, .. }) => { - if bounds.KnownSize.is_none() { - let output_expr = next_target_expr(&MakeHdlTypeExprContext { - type_arg_values: self_members[..param_count] - .iter() - .cloned() - .chain([parse_quote_spanned! {ident.span()=> - __param - }]) - .collect(), - is_const: false, - }); - let mut next_target_args: AngleBracketedGenericArguments = - parse_quote! { #next_type_generics }; - *next_target_args.args.last_mut().unwrap() = parse_quote_spanned! {ident.span()=> - ::fayalite::int::DynSize - }; - quote_spanned! {ident.span()=> - #[allow(non_upper_case_globals)] - #[automatically_derived] - impl #cur_impl_generics ::fayalite::__std::ops::Index<::fayalite::__std::primitive::usize> - for #cur_target #cur_type_generics - #cur_where_clause - { - type Output = #next_target #next_target_args; - - fn index( - &self, - __param: ::fayalite::__std::primitive::usize, - ) -> &Self::Output { - ::fayalite::intern::Interned::<_>::into_inner( - ::fayalite::intern::Intern::intern_sized(#output_expr), - ) - } - } - } - .to_tokens(tokens); - } { - let output_expr = next_target_expr(&MakeHdlTypeExprContext { - type_arg_values: self_members[..param_count] + let context = MakeHdlTypeExprContext { + named_param_values: self_members[..param_count] .iter() .cloned() .chain([parse_quote_spanned! {ident.span()=> @@ -2515,43 +2726,42 @@ impl ParsedGenerics { }]) .collect(), is_const: false, - }); + }; + let next_target_args = + make_next_target_args(Some(parse_quote_spanned! {ident.span()=> + <#param_ident as ::fayalite::int::SizeType>::Size + })); + let output_expr = if is_last { + target_expr(&context) + } else { + let args = &context.named_param_values[..next_param_count]; + parse_quote_spanned! {ident.span()=> + #next_target #next_target_args(#(#args),*) + } + }; let mut next_generics = cur_generics.clone(); next_generics .params .push(parse_quote_spanned! {ident.span()=> - const #param_ident: ::fayalite::__std::primitive::usize + #param_ident: ::fayalite::int::SizeType }); - let known_size = bounds - .KnownSize - .clone() - .unwrap_or_else(|| known_items::KnownSize(ident.span())); next_generics.make_where_clause().predicates.push( parse_quote_spanned! {ident.span()=> - ::fayalite::util::ConstUsize<#param_ident>: #known_size + <#param_ident as ::fayalite::int::SizeType>::Size: #bounds }, ); - let (next_impl_generics, next_type_generics, next_where_clause) = + let (next_impl_generics, _next_type_generics, next_where_clause) = next_generics.split_for_impl(); - let mut next_target_args: AngleBracketedGenericArguments = - parse_quote! { #next_type_generics }; - *next_target_args.args.last_mut().unwrap() = parse_quote_spanned! {ident.span()=> - ::fayalite::util::ConstUsize<#param_ident> - }; quote_spanned! {ident.span()=> #[allow(non_upper_case_globals)] #[automatically_derived] - impl #next_impl_generics ::fayalite::__std::ops::Index< - ::fayalite::util::ConstUsize<#param_ident>, - > for #cur_target #cur_type_generics + impl #next_impl_generics ::fayalite::__std::ops::Index<#param_ident> + for #cur_target #cur_type_generics #next_where_clause { type Output = #next_target #next_target_args; - fn index( - &self, - __param: ::fayalite::util::ConstUsize<#param_ident>, - ) -> &Self::Output { + fn index(&self, __param: #param_ident) -> &Self::Output { ::fayalite::intern::Interned::<_>::into_inner( ::fayalite::intern::Intern::intern_sized(#output_expr), ) @@ -2565,7 +2775,71 @@ impl ParsedGenerics { todo!(); } } - ParsedGenericParam::Const(_) => todo!(), + ParsedGenericParam::Const(ParsedConstParam { + attrs: _, + options: _, + const_token, + ident: param_ident, + colon_token, + ty: ParsedConstGenericType::Usize(ty), + bounds: ParsedConstParamWhereBounds { bounds, .. }, + }) => { + let context = MakeHdlTypeExprContext { + named_param_values: self_members[..param_count] + .iter() + .cloned() + .chain([parse_quote_spanned! {ident.span()=> + __param + }]) + .collect(), + is_const: false, + }; + let next_target_args = + make_next_target_args(Some(parse_quote! { #param_ident })); + let output_expr = if is_last { + target_expr(&context) + } else { + let args = &context.named_param_values[..next_param_count]; + parse_quote_spanned! {ident.span()=> + #next_target #next_target_args(#(#args),*) + } + }; + let mut next_generics = cur_generics.clone(); + next_generics + .params + .push(parse_quote! { #const_token #param_ident #colon_token #ty }); + next_generics + .params + .push(parse_quote_spanned! {ident.span()=> + __Param: ::fayalite::int::SizeType< + Size = ::fayalite::util::ConstUsize<#param_ident>, + > + }); + next_generics.make_where_clause().predicates.push( + parse_quote_spanned! {ident.span()=> + ::fayalite::util::ConstUsize<#param_ident>: ::fayalite::int::Size + #bounds + }, + ); + let (next_impl_generics, _next_type_generics, next_where_clause) = + next_generics.split_for_impl(); + quote_spanned! {ident.span()=> + #[allow(non_upper_case_globals)] + #[automatically_derived] + impl #next_impl_generics ::fayalite::__std::ops::Index<__Param> + for #cur_target #cur_type_generics + #next_where_clause + { + type Output = #next_target #next_target_args; + + fn index(&self, __param: __Param) -> &Self::Output { + ::fayalite::intern::Interned::<_>::into_inner( + ::fayalite::intern::Intern::intern_sized(#output_expr), + ) + } + } + } + .to_tokens(tokens); + } }; } } @@ -3145,7 +3419,8 @@ impl ToTokens for ParsedGenericsWhereClause<'_> { let mut where_token = |span: Span| -> Option { mem::replace(&mut need_where_token, false).then(|| Token![where](span)) }; - for param in self.generics.params.iter().take(self.param_count) { + for param in self.generics.params.pairs().take(self.param_count) { + let (param, comma_token) = param.into_tuple(); match param { ParsedGenericParam::Type(ParsedTypeParam { ident, @@ -3156,7 +3431,7 @@ impl ToTokens for ParsedGenericsWhereClause<'_> { if let Some(static_type) = &bounds.StaticType { where_token(static_type.span).to_tokens(tokens); quote_spanned! {static_type.span=> - <#ident as ::fayalite::ty::Type>::MaskType #colon_token #static_type, + <#ident as ::fayalite::ty::Type>::MaskType #colon_token #static_type #comma_token } .to_tokens(tokens); } @@ -3182,6 +3457,7 @@ impl ToTokens for ParsedGenericsWhereClause<'_> { gt_token.to_tokens(tokens); colon_token.to_tokens(tokens); bounds.to_tokens(tokens); + comma_token.to_tokens(tokens); } } } @@ -3649,7 +3925,7 @@ impl From> for FieldsNamed { #[derive(Debug)] pub(crate) struct MakeHdlTypeExprContext { - pub(crate) type_arg_values: Vec, + pub(crate) named_param_values: Vec, pub(crate) is_const: bool, } @@ -3694,6 +3970,28 @@ impl MakeHdlTypeExpr for known_items::DynSize { } } +impl MakeHdlTypeExpr for ParsedExprDelimited { + fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { + self.expr.make_hdl_type_expr(context) + } +} + +impl MakeHdlTypeExpr for ParsedExprNamedParamConst { + fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { + context.named_param_values[self.param_index].clone() + } +} + +impl MakeHdlTypeExpr for ParsedExpr { + fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { + match self { + ParsedExpr::Delimited(expr) => expr.make_hdl_type_expr(context), + ParsedExpr::NamedParamConst(expr) => expr.make_hdl_type_expr(context), + ParsedExpr::Other(expr) => (**expr).clone(), + } + } +} + impl MakeHdlTypeExpr for ParsedTypeDelimited { fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { self.elem.make_hdl_type_expr(context) @@ -3743,7 +4041,7 @@ impl MakeHdlTypeExpr for ParsedGenericArgument { fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { match self { ParsedGenericArgument::Type(v) => v.make_hdl_type_expr(context), - ParsedGenericArgument::Const(v) => v.clone(), + ParsedGenericArgument::Const(v) => v.make_hdl_type_expr(context), } } } @@ -3759,13 +4057,13 @@ impl MakeHdlTypeExpr for ParsedTypeNamedParam { impl MakeHdlTypeExpr for ParsedTypeNamedParamType { fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { - context.type_arg_values[self.param_index].clone() + context.named_param_values[self.param_index].clone() } } impl MakeHdlTypeExpr for ParsedTypeNamedParamSizeType { fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { - context.type_arg_values[self.param_index].clone() + context.named_param_values[self.param_index].clone() } } diff --git a/crates/fayalite/src/array.rs b/crates/fayalite/src/array.rs index 35c065c..d543322 100644 --- a/crates/fayalite/src/array.rs +++ b/crates/fayalite/src/array.rs @@ -3,7 +3,7 @@ use crate::{ expr::{ops::ArrayIndex, Expr, ToExpr}, - int::{DynSize, KnownSize, Size}, + int::{DynSize, KnownSize, Size, SizeType, DYN_SIZE}, intern::{Intern, Interned, LazyInterned}, module::transform::visit::{Fold, Folder, Visit, Visitor}, source_location::SourceLocation, @@ -27,10 +27,7 @@ impl std::fmt::Debug for ArrayType { } } -pub type Array< - T = CanonicalType, - const LEN: usize = { ::VALUE }, -> = ArrayType>; +pub type Array = ArrayType>; #[allow(non_upper_case_globals)] pub const Array: ArrayWithoutGenerics = ArrayWithoutGenerics; @@ -214,21 +211,10 @@ pub struct ArrayWithoutLen { element: T, } -impl Index for ArrayWithoutLen { - type Output = Array; +impl Index for ArrayWithoutLen { + type Output = ArrayType; - fn index(&self, len: usize) -> &Self::Output { - Interned::<_>::into_inner(Intern::intern_sized(Array::new_dyn(self.element, len))) - } -} - -impl Index> for ArrayWithoutLen -where - ConstUsize: KnownSize, -{ - type Output = Array; - - fn index(&self, len: ConstUsize) -> &Self::Output { - Interned::<_>::into_inner(Intern::intern_sized(Array::new(self.element, len))) + fn index(&self, len: L) -> &Self::Output { + Interned::<_>::into_inner(Intern::intern_sized(ArrayType::new(self.element, len))) } } diff --git a/crates/fayalite/src/int.rs b/crates/fayalite/src/int.rs index 8f28834..2950086 100644 --- a/crates/fayalite/src/int.rs +++ b/crates/fayalite/src/int.rs @@ -25,6 +25,7 @@ use std::{ mod sealed { pub trait BoolOrIntTypeSealed {} pub trait SizeSealed {} + pub trait SizeTypeSealed {} } pub const DYN_SIZE: usize = !0; @@ -59,6 +60,12 @@ macro_rules! known_widths { known_widths!([2 2 2 2 2 2 2 2 2]); +pub trait SizeType: + sealed::SizeTypeSealed + Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static +{ + type Size: Size; +} + pub trait Size: sealed::SizeSealed + Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static { @@ -76,7 +83,14 @@ pub trait Size: + TryFrom>> + Into>>; const KNOWN_VALUE: Option; - type SizeType: Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static; + type SizeType: SizeType + + Copy + + Ord + + std::hash::Hash + + std::fmt::Debug + + Send + + Sync + + 'static; fn as_usize(size_type: Self::SizeType) -> usize; fn try_from_usize(v: usize) -> Option; #[track_caller] @@ -85,6 +99,12 @@ pub trait Size: } } +impl sealed::SizeTypeSealed for usize {} + +impl SizeType for usize { + type Size = DynSize; +} + impl Size for DynSize { type ArrayMatch = Box<[Expr]>; const KNOWN_VALUE: Option = None; @@ -101,6 +121,15 @@ impl Size for DynSize { impl sealed::SizeSealed for ConstUsize {} +impl sealed::SizeTypeSealed for ConstUsize {} + +impl SizeType for ConstUsize +where + ConstUsize: KnownSize, +{ + type Size = ConstUsize; +} + impl Size for ConstUsize where ConstUsize: KnownSize, @@ -138,9 +167,7 @@ macro_rules! impl_int { } } - pub type $pretty_name< - const WIDTH: usize = { ::VALUE }, - > = $name>; + pub type $pretty_name = $name>; #[allow(non_upper_case_globals)] pub const $pretty_name: $generic_name = $generic_name; @@ -269,21 +296,10 @@ macro_rules! impl_int { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] pub struct $generic_name; - impl Index for $generic_name { - type Output = $name; + impl Index for $generic_name { + type Output = $name; - fn index(&self, width: usize) -> &Self::Output { - Interned::<_>::into_inner(Intern::intern_sized($name::new_dyn(width))) - } - } - - impl Index> for $generic_name - where - ConstUsize: KnownSize, - { - type Output = $pretty_name; - - fn index(&self, width: ConstUsize) -> &Self::Output { + fn index(&self, width: Width) -> &Self::Output { Interned::<_>::into_inner(Intern::intern_sized($name::new(width))) } } diff --git a/crates/fayalite/tests/hdl_types.rs b/crates/fayalite/tests/hdl_types.rs index 99a12ef..62d9c68 100644 --- a/crates/fayalite/tests/hdl_types.rs +++ b/crates/fayalite/tests/hdl_types.rs @@ -1,16 +1,22 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use fayalite::{ - array::ArrayType, - hdl, - int::{IntType, Size, UInt}, -}; +use fayalite::prelude::*; #[hdl(outline_generated)] -pub struct S { +pub struct S { pub a: T, b: UInt<3>, pub(crate) c: ArrayType, Len>, + pub d: T2, +} + +//#[cfg(todo)] +#[hdl(outline_generated)] +pub struct S3 { + pub a: T, + b: UInt<3>, + pub(crate) c: Array, LEN>, + pub d: S, ()>, } #[hdl(outline_generated)]