fix handling of const and size type generics when generating Index impls
All checks were successful
/ test (push) Successful in 5m1s

This commit is contained in:
Jacob Lifshay 2024-09-19 18:45:04 -07:00
parent 2c1afd1cd6
commit 9887d70f41
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
5 changed files with 519 additions and 212 deletions

View file

@ -230,6 +230,7 @@ forward_fold!(syn::Path => fold_path);
forward_fold!(syn::Type => fold_type); forward_fold!(syn::Type => fold_type);
forward_fold!(syn::TypePath => fold_type_path); forward_fold!(syn::TypePath => fold_type_path);
forward_fold!(syn::WherePredicate => fold_where_predicate); forward_fold!(syn::WherePredicate => fold_where_predicate);
no_op_fold!(proc_macro2::Span);
no_op_fold!(syn::parse::Nothing); no_op_fold!(syn::parse::Nothing);
no_op_fold!(syn::token::Brace); no_op_fold!(syn::token::Brace);
no_op_fold!(syn::token::Bracket); no_op_fold!(syn::token::Bracket);

View file

@ -8,11 +8,12 @@ use syn::{
punctuated::{Pair, Punctuated}, punctuated::{Pair, Punctuated},
spanned::Spanned, spanned::Spanned,
token::{Brace, Bracket, Paren}, token::{Brace, Bracket, Paren},
AngleBracketedGenericArguments, Attribute, ConstParam, Expr, ExprIndex, ExprPath, ExprTuple, AngleBracketedGenericArguments, Attribute, Block, ConstParam, Expr, ExprBlock, ExprGroup,
Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, GenericArgument, GenericParam, ExprIndex, ExprParen, ExprPath, ExprTuple, Field, FieldMutability, Fields, FieldsNamed,
Generics, Ident, ImplGenerics, Index, ItemStruct, Path, PathArguments, PathSegment, FieldsUnnamed, GenericArgument, GenericParam, Generics, Ident, ImplGenerics, Index, ItemStruct,
PredicateType, QSelf, Token, Turbofish, Type, TypeGenerics, TypeGroup, TypeParam, TypeParen, Path, PathArguments, PathSegment, PredicateType, QSelf, Stmt, Token, Turbofish, Type,
TypePath, TypeTuple, Visibility, WhereClause, WherePredicate, TypeGenerics, TypeGroup, TypeParam, TypeParen, TypePath, TypeTuple, Visibility, WhereClause,
WherePredicate,
}; };
crate::options! { 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<F: FnOnce(&mut TokenStream)>(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<ParsedExpr>,
}
impl_fold! {
struct ParsedExprDelimited<> {
delim: ExprDelimiter,
expr: Box<ParsedExpr>,
}
}
impl From<ParsedExprDelimited> 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<ParsedExprNamedParamConst> 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<Expr>),
}
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<Expr>),
}
}
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<ParsedExpr> 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<Box<ParsedExpr>> for Expr {
fn from(value: Box<ParsedExpr>) -> Self {
(*value).into()
}
}
impl ParseTypes<Expr> for ParsedExpr {
fn parse_types(input: &mut Expr, parser: &mut TypesParser<'_>) -> Result<Self, ParseFailed> {
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)] #[derive(Copy, Clone, Debug)]
pub(crate) enum TypeDelimiter { pub(crate) enum TypeDelimiter {
Group(syn::token::Group), Group(syn::token::Group),
@ -214,13 +439,13 @@ impl ParseTypes<TypeTuple> for ParsedTypeTuple {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum ParsedGenericArgument { pub(crate) enum ParsedGenericArgument {
Type(ParsedType), Type(ParsedType),
Const(Expr), Const(ParsedExpr),
} }
impl_fold! { impl_fold! {
enum ParsedGenericArgument<> { enum ParsedGenericArgument<> {
Type(ParsedType), Type(ParsedType),
Const(Expr), Const(ParsedExpr),
} }
} }
@ -246,20 +471,16 @@ impl ParseTypes<GenericArgument> for ParsedGenericArgument {
ty = &**elem; ty = &**elem;
} }
if let Type::Path(TypePath { qself: None, path }) = ty { if let Type::Path(TypePath { qself: None, path }) = ty {
if let Some(ident) = path.get_ident() { if let Some((param_index, ident)) = parser.get_named_param(path) {
if let Some(&param_index) = match parser.generics.params[param_index] {
parser.generics.param_name_to_index_map.get(ident) ParsedGenericParam::Type(_) | ParsedGenericParam::SizeType(_) => {}
{ ParsedGenericParam::Const(_) => {
match parser.generics.params[param_index] { return Ok(Self::Const(ParsedExpr::NamedParamConst(
ParsedGenericParam::Type(_) ParsedExprNamedParamConst {
| ParsedGenericParam::SizeType(_) => {} ident: ident.clone(),
ParsedGenericParam::Const(_) => { param_index,
return Ok(Self::Const(Expr::Path(ExprPath { },
attrs: vec![], )));
qself: None,
path: path.clone(),
})));
}
} }
} }
} }
@ -267,7 +488,7 @@ impl ParseTypes<GenericArgument> for ParsedGenericArgument {
} }
Ok(Self::Type(parser.parse(ty)?)) 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"), _ => parse_failed!(parser, arg, "expected type or const generic argument"),
} }
} }
@ -277,7 +498,7 @@ impl From<ParsedGenericArgument> for GenericArgument {
fn from(value: ParsedGenericArgument) -> Self { fn from(value: ParsedGenericArgument) -> Self {
match value { match value {
ParsedGenericArgument::Type(ty) => Self::Type(ty.into()), 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) struct ParsedTypeConstUsize {
pub(crate) const_usize: known_items::ConstUsize, pub(crate) const_usize: known_items::ConstUsize,
pub(crate) lt_token: Token![<], pub(crate) lt_token: Token![<],
pub(crate) value: Box<Expr>, pub(crate) value: ParsedExpr,
pub(crate) gt_token: Token![>], pub(crate) gt_token: Token![>],
} }
@ -504,7 +725,7 @@ impl_fold! {
struct ParsedTypeConstUsize<> { struct ParsedTypeConstUsize<> {
const_usize: known_items::ConstUsize, const_usize: known_items::ConstUsize,
lt_token: Token![<], lt_token: Token![<],
value: Box<Expr>, value: ParsedExpr,
gt_token: Token![>], gt_token: Token![>],
} }
} }
@ -518,7 +739,7 @@ impl From<ParsedTypeConstUsize> for Path {
gt_token, gt_token,
} = value; } = value;
let path = const_usize.path; 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 { let args = AngleBracketedGenericArguments {
colon2_token: Some(Token![::](lt_token.span)), colon2_token: Some(Token![::](lt_token.span)),
lt_token, lt_token,
@ -544,12 +765,16 @@ impl From<ParsedTypeConstUsize> for Type {
} }
impl MakeHdlTypeExpr for ParsedTypeConstUsize { impl MakeHdlTypeExpr for ParsedTypeConstUsize {
fn make_hdl_type_expr(&self, _context: &MakeHdlTypeExprContext) -> Expr { fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr {
Expr::Path(ExprPath { if let Some(named_param_const) = self.value.named_param_const() {
attrs: vec![], named_param_const.make_hdl_type_expr(context)
qself: None, } else {
path: self.clone().into(), Expr::Path(ExprPath {
}) attrs: vec![],
qself: None,
path: self.clone().into(),
})
}
} }
} }
@ -606,7 +831,7 @@ impl ParsedTypeConstUsize {
Ok(Ok(Self { Ok(Ok(Self {
const_usize, const_usize,
lt_token, lt_token,
value: Box::new(value), value,
gt_token, gt_token,
})) }))
} }
@ -694,7 +919,7 @@ macro_rules! make_parsed_type_or_const {
let $type_arg = Box::new(ParsedType::ConstUsize(ParsedTypeConstUsize { let $type_arg = Box::new(ParsedType::ConstUsize(ParsedTypeConstUsize {
const_usize: known_items::ConstUsize($span), const_usize: known_items::ConstUsize($span),
lt_token: Token![<]($span), lt_token: Token![<]($span),
value: Box::new($const_arg.clone()), value: $const_arg.clone(),
gt_token: Token![>]($span), gt_token: Token![>]($span),
})); }));
($type_arg, Some(Box::new($const_arg))) ($type_arg, Some(Box::new($const_arg)))
@ -887,7 +1112,7 @@ macro_rules! make_parsed_type_or_const {
let mut args = Punctuated::new(); let mut args = Punctuated::new();
$( $(
args.push(( args.push((
($(|| GenericArgument::Const(*$const_arg),)? ($(|| GenericArgument::Const($const_arg.into()),)?
|| GenericArgument::Type($type_arg.into()), || GenericArgument::Type($type_arg.into()),
).0)()); ).0)());
$(args.push_punct($separator);)? $(args.push_punct($separator);)?
@ -1010,7 +1235,7 @@ make_parsed_type_or_const! {
#[separator] #[separator]
comma_token: Token![,], comma_token: Token![,],
#[const] #[const]
const_len: Option<Box<Expr>>, const_len: Option<Box<ParsedExpr>>,
#[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))] #[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))]
type_len: Box<ParsedType>, type_len: Box<ParsedType>,
gt_token: Token![>], gt_token: Token![>],
@ -1024,7 +1249,7 @@ make_parsed_type_or_const! {
uint_type: known_items::UIntType, uint_type: known_items::UIntType,
lt_token: Token![<], lt_token: Token![<],
#[const] #[const]
const_width: Option<Box<Expr>>, const_width: Option<Box<ParsedExpr>>,
#[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))] #[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))]
type_width: Box<ParsedType>, type_width: Box<ParsedType>,
gt_token: Token![>], gt_token: Token![>],
@ -1038,7 +1263,7 @@ make_parsed_type_or_const! {
uint_type: known_items::SIntType, uint_type: known_items::SIntType,
lt_token: Token![<], lt_token: Token![<],
#[const] #[const]
const_width: Option<Box<Expr>>, const_width: Option<Box<ParsedExpr>>,
#[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))] #[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))]
type_width: Box<ParsedType>, type_width: Box<ParsedType>,
gt_token: Token![>], gt_token: Token![>],
@ -1207,40 +1432,29 @@ impl ParseTypes<Path> for ParsedType {
}, },
args, args,
}; };
if let Some(ident) = named.path.get_ident() { if let Some((param_index, ident)) = parser.get_named_param(&named.path) {
if let Some(&param_index) = parser.generics().param_name_to_index_map.get(ident) { return Ok(Self::NamedParam(
if parser match parser.generics().params[param_index] {
.cur_param_index ParsedGenericParam::Type(_) => {
.is_some_and(|cur_param_index| param_index >= cur_param_index) ParsedTypeNamedParam::Type(ParsedTypeNamedParamType {
{ ident: ident.clone(),
parser.errors.error( param_index,
parser.generics().params[param_index].ident(), })
"cannot use forward declared identifier in generic parameter defaults", }
); ParsedGenericParam::SizeType(_) => {
} ParsedTypeNamedParam::SizeType(ParsedTypeNamedParamSizeType {
return Ok(Self::NamedParam( ident: ident.clone(),
match parser.generics().params[param_index] { param_index,
ParsedGenericParam::Type(_) => { })
ParsedTypeNamedParam::Type(ParsedTypeNamedParamType { }
ident: ident.clone(), ParsedGenericParam::Const(ParsedConstParam { ref ident, .. }) => {
param_index, parser
}) .errors
} .error(ident, "constant provided when a type was expected");
ParsedGenericParam::SizeType(_) => { return Err(ParseFailed);
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)? { let named = match ParsedTypeArray::try_from_named(named, parser)? {
Ok(v) => return Ok(Self::Array(v)), Ok(v) => return Ok(Self::Array(v)),
@ -1489,6 +1703,18 @@ impl<'a> TypesParser<'a> {
pub(crate) fn parse<T: ParseTypes<I>, I>(&mut self, input: &mut I) -> Result<T, ParseFailed> { pub(crate) fn parse<T: ParseTypes<I>, I>(&mut self, input: &mut I) -> Result<T, ParseFailed> {
T::parse_types(input, self) 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<I>: Sized { pub(crate) trait ParseTypes<I>: Sized {
@ -2311,7 +2537,7 @@ impl ParsedGenerics {
) { ) {
if self.params.is_empty() { if self.params.is_empty() {
let target_expr = target_expr(&MakeHdlTypeExprContext { let target_expr = target_expr(&MakeHdlTypeExprContext {
type_arg_values: vec![], named_param_values: vec![],
is_const: true, is_const: true,
}); });
quote_spanned! {ident.span()=> quote_spanned! {ident.span()=>
@ -2364,36 +2590,40 @@ impl ParsedGenerics {
.clone() .clone()
.into() .into()
}; };
let next_generics = if is_last { let make_next_target_args = |next_arg: Option<GenericArgument>| {
&final_generics let generics = if is_last {
} else { &final_generics
&generics_accumulation_types[next_param_count].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) = let (cur_impl_generics, cur_type_generics, cur_where_clause) =
cur_generics.split_for_impl(); 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 { match next_param {
ParsedGenericParam::Type(ParsedTypeParam { ParsedGenericParam::Type(ParsedTypeParam {
ident: param_ident, ident: param_ident,
default, 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()=> let mut param: Expr = parse_quote_spanned! {ident.span()=>
__param __param
}; };
let mut generics = next_generics.clone();
let mut index_type = param_ident.clone(); let mut index_type = param_ident.clone();
if let Some((_, default)) = default { if let Some((_, default)) = default {
index_type = format_ident!("__Param", span = ident.span()); index_type = format_ident!("__Param", span = ident.span());
@ -2402,24 +2632,34 @@ impl ParsedGenerics {
#index_type: ::fayalite::ty::TypeOrDefault<#default, Type = #param_ident> #index_type: ::fayalite::ty::TypeOrDefault<#default, Type = #param_ident>
}); });
let default_expr = default.make_hdl_type_expr(&MakeHdlTypeExprContext { 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, is_const: false,
}); });
param = parse_quote_spanned! {ident.span()=> param = parse_quote_spanned! {ident.span()=>
::fayalite::ty::TypeOrDefault::get(__param, || #default_expr) ::fayalite::ty::TypeOrDefault::get(__param, || #default_expr)
}; };
let output_expr = next_target_expr(&MakeHdlTypeExprContext { let context = MakeHdlTypeExprContext {
type_arg_values: self_members[..param_count] named_param_values: self_members[..param_count]
.iter() .iter()
.cloned() .cloned()
.chain([default_expr]) .chain([default_expr])
.collect(), .collect(),
is_const: false, is_const: false,
}); };
let mut next_target_args: AngleBracketedGenericArguments = let output_expr = {
parse_quote! { #next_type_generics }; let next_turbofish = next_type_generics.as_turbofish();
*next_target_args.args.last_mut().unwrap() = if is_last {
GenericArgument::Type(default.clone().into()); 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()=> quote_spanned! {ident.span()=>
impl #cur_impl_generics ::fayalite::ty::FillInDefaultedGenerics impl #cur_impl_generics ::fayalite::ty::FillInDefaultedGenerics
for #cur_target #cur_type_generics for #cur_target #cur_type_generics
@ -2436,14 +2676,22 @@ impl ParsedGenerics {
.to_tokens(tokens); .to_tokens(tokens);
} }
let (impl_generics, _type_generics, where_clause) = generics.split_for_impl(); let (impl_generics, _type_generics, where_clause) = generics.split_for_impl();
let output_expr = next_target_expr(&MakeHdlTypeExprContext { let context = MakeHdlTypeExprContext {
type_arg_values: self_members[..param_count] named_param_values: self_members[..param_count]
.iter() .iter()
.cloned() .cloned()
.chain([param]) .chain([param])
.collect(), .collect(),
is_const: false, 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()=> quote_spanned! {ident.span()=>
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
#[automatically_derived] #[automatically_derived]
@ -2468,46 +2716,9 @@ impl ParsedGenerics {
default, 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 { let context = MakeHdlTypeExprContext {
type_arg_values: self_members[..param_count] named_param_values: self_members[..param_count]
.iter() .iter()
.cloned() .cloned()
.chain([parse_quote_spanned! {ident.span()=> .chain([parse_quote_spanned! {ident.span()=>
@ -2515,43 +2726,42 @@ impl ParsedGenerics {
}]) }])
.collect(), .collect(),
is_const: false, 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(); let mut next_generics = cur_generics.clone();
next_generics next_generics
.params .params
.push(parse_quote_spanned! {ident.span()=> .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( next_generics.make_where_clause().predicates.push(
parse_quote_spanned! {ident.span()=> 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(); 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()=> quote_spanned! {ident.span()=>
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
#[automatically_derived] #[automatically_derived]
impl #next_impl_generics ::fayalite::__std::ops::Index< impl #next_impl_generics ::fayalite::__std::ops::Index<#param_ident>
::fayalite::util::ConstUsize<#param_ident>, for #cur_target #cur_type_generics
> for #cur_target #cur_type_generics
#next_where_clause #next_where_clause
{ {
type Output = #next_target #next_target_args; type Output = #next_target #next_target_args;
fn index( fn index(&self, __param: #param_ident) -> &Self::Output {
&self,
__param: ::fayalite::util::ConstUsize<#param_ident>,
) -> &Self::Output {
::fayalite::intern::Interned::<_>::into_inner( ::fayalite::intern::Interned::<_>::into_inner(
::fayalite::intern::Intern::intern_sized(#output_expr), ::fayalite::intern::Intern::intern_sized(#output_expr),
) )
@ -2565,7 +2775,71 @@ impl ParsedGenerics {
todo!(); 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<SizeType = __Param> + #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<Token![where]> { let mut where_token = |span: Span| -> Option<Token![where]> {
mem::replace(&mut need_where_token, false).then(|| Token![where](span)) 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 { match param {
ParsedGenericParam::Type(ParsedTypeParam { ParsedGenericParam::Type(ParsedTypeParam {
ident, ident,
@ -3156,7 +3431,7 @@ impl ToTokens for ParsedGenericsWhereClause<'_> {
if let Some(static_type) = &bounds.StaticType { if let Some(static_type) = &bounds.StaticType {
where_token(static_type.span).to_tokens(tokens); where_token(static_type.span).to_tokens(tokens);
quote_spanned! {static_type.span=> 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); .to_tokens(tokens);
} }
@ -3182,6 +3457,7 @@ impl ToTokens for ParsedGenericsWhereClause<'_> {
gt_token.to_tokens(tokens); gt_token.to_tokens(tokens);
colon_token.to_tokens(tokens); colon_token.to_tokens(tokens);
bounds.to_tokens(tokens); bounds.to_tokens(tokens);
comma_token.to_tokens(tokens);
} }
} }
} }
@ -3649,7 +3925,7 @@ impl From<MaybeParsed<ParsedFieldsNamed, FieldsNamed>> for FieldsNamed {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct MakeHdlTypeExprContext { pub(crate) struct MakeHdlTypeExprContext {
pub(crate) type_arg_values: Vec<Expr>, pub(crate) named_param_values: Vec<Expr>,
pub(crate) is_const: bool, 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 { impl MakeHdlTypeExpr for ParsedTypeDelimited {
fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr {
self.elem.make_hdl_type_expr(context) self.elem.make_hdl_type_expr(context)
@ -3743,7 +4041,7 @@ impl MakeHdlTypeExpr for ParsedGenericArgument {
fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr {
match self { match self {
ParsedGenericArgument::Type(v) => v.make_hdl_type_expr(context), 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 { impl MakeHdlTypeExpr for ParsedTypeNamedParamType {
fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { 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 { impl MakeHdlTypeExpr for ParsedTypeNamedParamSizeType {
fn make_hdl_type_expr(&self, context: &MakeHdlTypeExprContext) -> Expr { 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()
} }
} }

View file

@ -3,7 +3,7 @@
use crate::{ use crate::{
expr::{ops::ArrayIndex, Expr, ToExpr}, expr::{ops::ArrayIndex, Expr, ToExpr},
int::{DynSize, KnownSize, Size}, int::{DynSize, KnownSize, Size, SizeType, DYN_SIZE},
intern::{Intern, Interned, LazyInterned}, intern::{Intern, Interned, LazyInterned},
module::transform::visit::{Fold, Folder, Visit, Visitor}, module::transform::visit::{Fold, Folder, Visit, Visitor},
source_location::SourceLocation, source_location::SourceLocation,
@ -27,10 +27,7 @@ impl<T: Type, Len: Size> std::fmt::Debug for ArrayType<T, Len> {
} }
} }
pub type Array< pub type Array<T = CanonicalType, const LEN: usize = DYN_SIZE> = ArrayType<T, ConstUsize<LEN>>;
T = CanonicalType,
const LEN: usize = { <DynSize as crate::util::GenericConstUsize>::VALUE },
> = ArrayType<T, ConstUsize<LEN>>;
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub const Array: ArrayWithoutGenerics = ArrayWithoutGenerics; pub const Array: ArrayWithoutGenerics = ArrayWithoutGenerics;
@ -214,21 +211,10 @@ pub struct ArrayWithoutLen<T: Type> {
element: T, element: T,
} }
impl<T: Type> Index<usize> for ArrayWithoutLen<T> { impl<T: Type, L: SizeType> Index<L> for ArrayWithoutLen<T> {
type Output = Array<T>; type Output = ArrayType<T, L::Size>;
fn index(&self, len: usize) -> &Self::Output { fn index(&self, len: L) -> &Self::Output {
Interned::<_>::into_inner(Intern::intern_sized(Array::new_dyn(self.element, len))) Interned::<_>::into_inner(Intern::intern_sized(ArrayType::new(self.element, len)))
}
}
impl<T: Type, const LEN: usize> Index<ConstUsize<LEN>> for ArrayWithoutLen<T>
where
ConstUsize<LEN>: KnownSize,
{
type Output = Array<T, LEN>;
fn index(&self, len: ConstUsize<LEN>) -> &Self::Output {
Interned::<_>::into_inner(Intern::intern_sized(Array::new(self.element, len)))
} }
} }

View file

@ -25,6 +25,7 @@ use std::{
mod sealed { mod sealed {
pub trait BoolOrIntTypeSealed {} pub trait BoolOrIntTypeSealed {}
pub trait SizeSealed {} pub trait SizeSealed {}
pub trait SizeTypeSealed {}
} }
pub const DYN_SIZE: usize = !0; 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]); 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<SizeType = Self>;
}
pub trait Size: pub trait Size:
sealed::SizeSealed + Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static sealed::SizeSealed + Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static
{ {
@ -76,7 +83,14 @@ pub trait Size:
+ TryFrom<Vec<Expr<Element>>> + TryFrom<Vec<Expr<Element>>>
+ Into<Vec<Expr<Element>>>; + Into<Vec<Expr<Element>>>;
const KNOWN_VALUE: Option<usize>; const KNOWN_VALUE: Option<usize>;
type SizeType: Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static; type SizeType: SizeType<Size = Self>
+ Copy
+ Ord
+ std::hash::Hash
+ std::fmt::Debug
+ Send
+ Sync
+ 'static;
fn as_usize(size_type: Self::SizeType) -> usize; fn as_usize(size_type: Self::SizeType) -> usize;
fn try_from_usize(v: usize) -> Option<Self::SizeType>; fn try_from_usize(v: usize) -> Option<Self::SizeType>;
#[track_caller] #[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 { impl Size for DynSize {
type ArrayMatch<Element: Type> = Box<[Expr<Element>]>; type ArrayMatch<Element: Type> = Box<[Expr<Element>]>;
const KNOWN_VALUE: Option<usize> = None; const KNOWN_VALUE: Option<usize> = None;
@ -101,6 +121,15 @@ impl Size for DynSize {
impl<const VALUE: usize> sealed::SizeSealed for ConstUsize<VALUE> {} impl<const VALUE: usize> sealed::SizeSealed for ConstUsize<VALUE> {}
impl<const VALUE: usize> sealed::SizeTypeSealed for ConstUsize<VALUE> {}
impl<const VALUE: usize> SizeType for ConstUsize<VALUE>
where
ConstUsize<VALUE>: KnownSize,
{
type Size = ConstUsize<VALUE>;
}
impl<const VALUE: usize> Size for ConstUsize<VALUE> impl<const VALUE: usize> Size for ConstUsize<VALUE>
where where
ConstUsize<VALUE>: KnownSize, ConstUsize<VALUE>: KnownSize,
@ -138,9 +167,7 @@ macro_rules! impl_int {
} }
} }
pub type $pretty_name< pub type $pretty_name<const WIDTH: usize = DYN_SIZE> = $name<ConstUsize<WIDTH>>;
const WIDTH: usize = { <DynSize as crate::util::GenericConstUsize>::VALUE },
> = $name<ConstUsize<WIDTH>>;
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub const $pretty_name: $generic_name = $generic_name; pub const $pretty_name: $generic_name = $generic_name;
@ -269,21 +296,10 @@ macro_rules! impl_int {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
pub struct $generic_name; pub struct $generic_name;
impl Index<usize> for $generic_name { impl<Width: SizeType> Index<Width> for $generic_name {
type Output = $name; type Output = $name<Width::Size>;
fn index(&self, width: usize) -> &Self::Output { fn index(&self, width: Width) -> &Self::Output {
Interned::<_>::into_inner(Intern::intern_sized($name::new_dyn(width)))
}
}
impl<const WIDTH: usize> Index<ConstUsize<WIDTH>> for $generic_name
where
ConstUsize<WIDTH>: KnownSize,
{
type Output = $pretty_name<WIDTH>;
fn index(&self, width: ConstUsize<WIDTH>) -> &Self::Output {
Interned::<_>::into_inner(Intern::intern_sized($name::new(width))) Interned::<_>::into_inner(Intern::intern_sized($name::new(width)))
} }
} }

View file

@ -1,16 +1,22 @@
// SPDX-License-Identifier: LGPL-3.0-or-later // SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information // See Notices.txt for copyright information
use fayalite::{ use fayalite::prelude::*;
array::ArrayType,
hdl,
int::{IntType, Size, UInt},
};
#[hdl(outline_generated)] #[hdl(outline_generated)]
pub struct S<T: IntType, Len: Size> { pub struct S<T, Len: Size, T2> {
pub a: T, pub a: T,
b: UInt<3>, b: UInt<3>,
pub(crate) c: ArrayType<UInt<1>, Len>, pub(crate) c: ArrayType<UInt<1>, Len>,
pub d: T2,
}
//#[cfg(todo)]
#[hdl(outline_generated)]
pub struct S3<const LEN: usize, T> {
pub a: T,
b: UInt<3>,
pub(crate) c: Array<UInt<1>, LEN>,
pub d: S<T, ConstUsize<LEN>, ()>,
} }
#[hdl(outline_generated)] #[hdl(outline_generated)]