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::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);

View file

@ -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<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)]
pub(crate) enum TypeDelimiter {
Group(syn::token::Group),
@ -214,13 +439,13 @@ impl ParseTypes<TypeTuple> 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<GenericArgument> for ParsedGenericArgument {
ty = &**elem;
}
if let Type::Path(TypePath { qself: None, path }) = ty {
if let Some(ident) = path.get_ident() {
if let Some(&param_index) =
parser.generics.param_name_to_index_map.get(ident)
{
if let Some((param_index, ident)) = parser.get_named_param(path) {
match parser.generics.params[param_index] {
ParsedGenericParam::Type(_)
| ParsedGenericParam::SizeType(_) => {}
ParsedGenericParam::Type(_) | ParsedGenericParam::SizeType(_) => {}
ParsedGenericParam::Const(_) => {
return Ok(Self::Const(Expr::Path(ExprPath {
attrs: vec![],
qself: None,
path: path.clone(),
})));
}
return Ok(Self::Const(ParsedExpr::NamedParamConst(
ParsedExprNamedParamConst {
ident: ident.clone(),
param_index,
},
)));
}
}
}
@ -267,7 +488,7 @@ impl ParseTypes<GenericArgument> 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<ParsedGenericArgument> 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<Expr>,
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<Expr>,
value: ParsedExpr,
gt_token: Token![>],
}
}
@ -518,7 +739,7 @@ impl From<ParsedTypeConstUsize> 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,13 +765,17 @@ impl From<ParsedTypeConstUsize> for Type {
}
impl MakeHdlTypeExpr for ParsedTypeConstUsize {
fn make_hdl_type_expr(&self, _context: &MakeHdlTypeExprContext) -> Expr {
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(),
})
}
}
}
impl ToTokens for ParsedTypeConstUsize {
@ -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<Box<Expr>>,
const_len: Option<Box<ParsedExpr>>,
#[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))]
type_len: Box<ParsedType>,
gt_token: Token![>],
@ -1024,7 +1249,7 @@ make_parsed_type_or_const! {
uint_type: known_items::UIntType,
lt_token: Token![<],
#[const]
const_width: Option<Box<Expr>>,
const_width: Option<Box<ParsedExpr>>,
#[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))]
type_width: Box<ParsedType>,
gt_token: Token![>],
@ -1038,7 +1263,7 @@ make_parsed_type_or_const! {
uint_type: known_items::SIntType,
lt_token: Token![<],
#[const]
const_width: Option<Box<Expr>>,
const_width: Option<Box<ParsedExpr>>,
#[type(default = |span| ParsedType::DynSize(known_items::DynSize(span)))]
type_width: Box<ParsedType>,
gt_token: Token![>],
@ -1207,17 +1432,7 @@ impl ParseTypes<Path> for ParsedType {
},
args,
};
if let Some(ident) = named.path.get_ident() {
if let Some(&param_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",
);
}
if let Some((param_index, ident)) = parser.get_named_param(&named.path) {
return Ok(Self::NamedParam(
match parser.generics().params[param_index] {
ParsedGenericParam::Type(_) => {
@ -1241,7 +1456,6 @@ impl ParseTypes<Path> for ParsedType {
},
));
}
}
let named = match ParsedTypeArray::try_from_named(named, parser)? {
Ok(v) => return Ok(Self::Array(v)),
Err(named) => named,
@ -1489,6 +1703,18 @@ impl<'a> TypesParser<'a> {
pub(crate) fn parse<T: ParseTypes<I>, I>(&mut self, input: &mut I) -> Result<T, ParseFailed> {
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 {
@ -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 {
let make_next_target_args = |next_arg: Option<GenericArgument>| {
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,9 +2716,9 @@ impl ParsedGenerics {
default,
..
}) => {
if bounds.KnownSize.is_none() {
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()=>
@ -2478,80 +2726,42 @@ impl ParsedGenerics {
}])
.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),
)
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),*)
}
}
}
.to_tokens(tokens);
}
{
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_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<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]> {
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<MaybeParsed<ParsedFieldsNamed, FieldsNamed>> for FieldsNamed {
#[derive(Debug)]
pub(crate) struct MakeHdlTypeExprContext {
pub(crate) type_arg_values: Vec<Expr>,
pub(crate) named_param_values: Vec<Expr>,
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()
}
}

View file

@ -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<T: Type, Len: Size> std::fmt::Debug for ArrayType<T, Len> {
}
}
pub type Array<
T = CanonicalType,
const LEN: usize = { <DynSize as crate::util::GenericConstUsize>::VALUE },
> = ArrayType<T, ConstUsize<LEN>>;
pub type Array<T = CanonicalType, const LEN: usize = DYN_SIZE> = ArrayType<T, ConstUsize<LEN>>;
#[allow(non_upper_case_globals)]
pub const Array: ArrayWithoutGenerics = ArrayWithoutGenerics;
@ -214,21 +211,10 @@ pub struct ArrayWithoutLen<T: Type> {
element: T,
}
impl<T: Type> Index<usize> for ArrayWithoutLen<T> {
type Output = Array<T>;
impl<T: Type, L: SizeType> Index<L> for ArrayWithoutLen<T> {
type Output = ArrayType<T, L::Size>;
fn index(&self, len: usize) -> &Self::Output {
Interned::<_>::into_inner(Intern::intern_sized(Array::new_dyn(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)))
fn index(&self, len: L) -> &Self::Output {
Interned::<_>::into_inner(Intern::intern_sized(ArrayType::new(self.element, len)))
}
}

View file

@ -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<SizeType = Self>;
}
pub trait Size:
sealed::SizeSealed + Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static
{
@ -76,7 +83,14 @@ pub trait Size:
+ TryFrom<Vec<Expr<Element>>>
+ Into<Vec<Expr<Element>>>;
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 try_from_usize(v: usize) -> Option<Self::SizeType>;
#[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<Element: Type> = Box<[Expr<Element>]>;
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::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>
where
ConstUsize<VALUE>: KnownSize,
@ -138,9 +167,7 @@ macro_rules! impl_int {
}
}
pub type $pretty_name<
const WIDTH: usize = { <DynSize as crate::util::GenericConstUsize>::VALUE },
> = $name<ConstUsize<WIDTH>>;
pub type $pretty_name<const WIDTH: usize = DYN_SIZE> = $name<ConstUsize<WIDTH>>;
#[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<usize> for $generic_name {
type Output = $name;
impl<Width: SizeType> Index<Width> for $generic_name {
type Output = $name<Width::Size>;
fn index(&self, width: usize) -> &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 {
fn index(&self, width: Width) -> &Self::Output {
Interned::<_>::into_inner(Intern::intern_sized($name::new(width)))
}
}

View file

@ -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<T: IntType, Len: Size> {
pub struct S<T, Len: Size, T2> {
pub a: T,
b: UInt<3>,
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)]