support unknown trait bounds in type parameters
All checks were successful
/ deps (pull_request) Successful in 19s
/ test (pull_request) Successful in 3m34s
/ deps (push) Successful in 14s
/ test (push) Successful in 3m58s

This commit is contained in:
Jacob Lifshay 2025-02-13 18:35:30 -08:00
parent 86a1bb46be
commit cdd84953d0
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
2 changed files with 119 additions and 17 deletions

View file

@ -2069,11 +2069,16 @@ macro_rules! impl_bounds {
$( $(
$Variant:ident, $Variant:ident,
)* )*
$(
#[unknown]
$Unknown:ident,
)?
} }
) => { ) => {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
$vis enum $enum_type { $vis enum $enum_type {
$($Variant(known_items::$Variant),)* $($Variant(known_items::$Variant),)*
$($Unknown(syn::TypeParamBound),)?
} }
$(impl From<known_items::$Variant> for $enum_type { $(impl From<known_items::$Variant> for $enum_type {
@ -2086,28 +2091,54 @@ macro_rules! impl_bounds {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
match self { match self {
$(Self::$Variant(v) => v.to_tokens(tokens),)* $(Self::$Variant(v) => v.to_tokens(tokens),)*
$(Self::$Unknown(v) => v.to_tokens(tokens),)?
} }
} }
} }
impl $enum_type { impl $enum_type {
$vis fn parse_path(path: Path) -> Result<Self, Path> { $vis fn parse_path(path: Path) -> Result<Self, Path> {
#![allow(unreachable_code)]
$(let path = match known_items::$Variant::parse_path(path) { $(let path = match known_items::$Variant::parse_path(path) {
Ok(v) => return Ok(Self::$Variant(v)), Ok(v) => return Ok(Self::$Variant(v)),
Err(path) => path, Err(path) => path,
};)* };)*
$(return Ok(Self::$Unknown(syn::TraitBound {
paren_token: None,
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path,
}.into()));)?
Err(path) Err(path)
} }
$vis fn parse_type_param_bound(mut type_param_bound: syn::TypeParamBound) -> Result<Self, syn::TypeParamBound> {
#![allow(unreachable_code)]
if let syn::TypeParamBound::Trait(mut trait_bound) = type_param_bound {
if let syn::TraitBound {
paren_token: _,
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: _,
} = trait_bound {
match Self::parse_path(trait_bound.path) {
Ok(retval) => return Ok(retval),
Err(path) => trait_bound.path = path,
}
}
type_param_bound = trait_bound.into();
}
$(return Ok(Self::$Unknown(type_param_bound));)?
Err(type_param_bound)
}
} }
impl Parse for $enum_type { impl Parse for $enum_type {
fn parse(input: ParseStream) -> syn::Result<Self> { fn parse(input: ParseStream) -> syn::Result<Self> {
Self::parse_path(Path::parse_mod_style(input)?).map_err(|path| { Self::parse_type_param_bound(input.parse()?)
syn::Error::new_spanned( .map_err(|type_param_bound| syn::Error::new_spanned(
path, type_param_bound,
format_args!("expected one of: {}", [$(stringify!($Variant)),*].join(", ")), format_args!("expected one of: {}", [$(stringify!($Variant)),*].join(", ")),
) ))
})
} }
} }
@ -2115,6 +2146,7 @@ macro_rules! impl_bounds {
#[allow(non_snake_case)] #[allow(non_snake_case)]
$vis struct $struct_type { $vis struct $struct_type {
$($vis $Variant: Option<known_items::$Variant>,)* $($vis $Variant: Option<known_items::$Variant>,)*
$($vis $Unknown: Vec<syn::TypeParamBound>,)?
} }
impl ToTokens for $struct_type { impl ToTokens for $struct_type {
@ -2126,42 +2158,63 @@ macro_rules! impl_bounds {
separator = Some(<Token![+]>::default()); separator = Some(<Token![+]>::default());
v.to_tokens(tokens); v.to_tokens(tokens);
})* })*
$(for v in &self.$Unknown {
separator.to_tokens(tokens);
separator = Some(<Token![+]>::default());
v.to_tokens(tokens);
})*
} }
} }
const _: () = { const _: () = {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
$vis struct Iter($vis $struct_type); #[allow(non_snake_case)]
$vis struct Iter {
$($Variant: Option<known_items::$Variant>,)*
$($Unknown: std::vec::IntoIter<syn::TypeParamBound>,)?
}
impl IntoIterator for $struct_type { impl IntoIterator for $struct_type {
type Item = $enum_type; type Item = $enum_type;
type IntoIter = Iter; type IntoIter = Iter;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
Iter(self) Iter {
$($Variant: self.$Variant,)*
$($Unknown: self.$Unknown.into_iter(),)?
}
} }
} }
impl Iterator for Iter { impl Iterator for Iter {
type Item = $enum_type; type Item = $enum_type;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
$( $(
if let Some(value) = self.0.$Variant.take() { if let Some(value) = self.$Variant.take() {
return Some($enum_type::$Variant(value)); return Some($enum_type::$Variant(value));
} }
)* )*
$(
if let Some(value) = self.$Unknown.next() {
return Some($enum_type::$Unknown(value));
}
)?
None None
} }
#[allow(unused_mut, unused_variables)] #[allow(unused_mut, unused_variables)]
fn fold<B, F: FnMut(B, Self::Item) -> B>(mut self, mut init: B, mut f: F) -> B { fn fold<B, F: FnMut(B, Self::Item) -> B>(mut self, mut init: B, mut f: F) -> B {
$( $(
if let Some(value) = self.0.$Variant.take() { if let Some(value) = self.$Variant.take() {
init = f(init, $enum_type::$Variant(value)); init = f(init, $enum_type::$Variant(value));
} }
)* )*
$(
if let Some(value) = self.$Unknown.next() {
init = f(init, $enum_type::$Unknown(value));
}
)?
init init
} }
} }
@ -2173,6 +2226,9 @@ macro_rules! impl_bounds {
$($enum_type::$Variant(v) => { $($enum_type::$Variant(v) => {
self.$Variant = Some(v); self.$Variant = Some(v);
})* })*
$($enum_type::$Unknown(v) => {
self.$Unknown.push(v);
})?
}); });
} }
} }
@ -2191,6 +2247,7 @@ macro_rules! impl_bounds {
$(if let Some(v) = v.$Variant { $(if let Some(v) = v.$Variant {
self.$Variant = Some(v); self.$Variant = Some(v);
})* })*
$(self.$Unknown.extend(v.$Unknown);)*
}); });
} }
} }
@ -2244,6 +2301,8 @@ impl_bounds! {
Size, Size,
StaticType, StaticType,
Type, Type,
#[unknown]
Unknown,
} }
} }
@ -2257,6 +2316,8 @@ impl_bounds! {
ResetType, ResetType,
StaticType, StaticType,
Type, Type,
#[unknown]
Unknown,
} }
} }
@ -2270,6 +2331,7 @@ impl From<ParsedTypeBound> for ParsedBound {
ParsedTypeBound::ResetType(v) => ParsedBound::ResetType(v), ParsedTypeBound::ResetType(v) => ParsedBound::ResetType(v),
ParsedTypeBound::StaticType(v) => ParsedBound::StaticType(v), ParsedTypeBound::StaticType(v) => ParsedBound::StaticType(v),
ParsedTypeBound::Type(v) => ParsedBound::Type(v), ParsedTypeBound::Type(v) => ParsedBound::Type(v),
ParsedTypeBound::Unknown(v) => ParsedBound::Unknown(v),
} }
} }
} }
@ -2284,6 +2346,7 @@ impl From<ParsedTypeBounds> for ParsedBounds {
ResetType, ResetType,
StaticType, StaticType,
Type, Type,
Unknown,
} = value; } = value;
Self { Self {
BoolOrIntType, BoolOrIntType,
@ -2295,6 +2358,7 @@ impl From<ParsedTypeBounds> for ParsedBounds {
Size: None, Size: None,
StaticType, StaticType,
Type, Type,
Unknown,
} }
} }
} }
@ -2330,6 +2394,7 @@ impl ParsedTypeBound {
ParsedTypeBound::Type(known_items::Type(span)), ParsedTypeBound::Type(known_items::Type(span)),
]), ]),
Self::Type(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::from(v)]), Self::Type(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::from(v)]),
Self::Unknown(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::Unknown(v)]),
} }
} }
} }
@ -2364,6 +2429,7 @@ impl From<ParsedSizeTypeBounds> for ParsedBounds {
Size, Size,
StaticType: None, StaticType: None,
Type: None, Type: None,
Unknown: vec![],
} }
} }
} }
@ -2391,6 +2457,7 @@ impl ParsedBounds {
fn categorize(self, errors: &mut Errors, span: Span) -> ParsedBoundsCategory { fn categorize(self, errors: &mut Errors, span: Span) -> ParsedBoundsCategory {
let mut type_bounds = None; let mut type_bounds = None;
let mut size_type_bounds = None; let mut size_type_bounds = None;
let mut unknown_bounds = vec![];
self.into_iter().for_each(|bound| match bound.categorize() { self.into_iter().for_each(|bound| match bound.categorize() {
ParsedBoundCategory::Type(bound) => { ParsedBoundCategory::Type(bound) => {
type_bounds type_bounds
@ -2402,15 +2469,37 @@ impl ParsedBounds {
.get_or_insert_with(ParsedSizeTypeBounds::default) .get_or_insert_with(ParsedSizeTypeBounds::default)
.extend([bound]); .extend([bound]);
} }
ParsedBoundCategory::Unknown(bound) => unknown_bounds.push(bound),
}); });
match (type_bounds, size_type_bounds) { match (type_bounds, size_type_bounds, unknown_bounds.is_empty()) {
(None, None) => ParsedBoundsCategory::Type(ParsedTypeBounds { (None, None, true) => ParsedBoundsCategory::Type(ParsedTypeBounds {
Type: Some(known_items::Type(span)), Type: Some(known_items::Type(span)),
..Default::default() ..Default::default()
}), }),
(None, Some(bounds)) => ParsedBoundsCategory::SizeType(bounds), (None, None, false) => {
(Some(bounds), None) => ParsedBoundsCategory::Type(bounds), errors.error(
(Some(type_bounds), Some(size_type_bounds)) => { unknown_bounds.remove(0),
"unknown bounds: must use at least one known bound (such as `Type`) with any unknown bounds",
);
ParsedBoundsCategory::Type(ParsedTypeBounds {
Unknown: unknown_bounds,
..Default::default()
})
}
(None, Some(bounds), true) => ParsedBoundsCategory::SizeType(bounds),
(None, Some(bounds), false) => {
// TODO: implement
errors.error(
unknown_bounds.remove(0),
"unknown bounds with `Size` bounds are not implemented",
);
ParsedBoundsCategory::SizeType(bounds)
}
(Some(bounds), None, _) => ParsedBoundsCategory::Type(ParsedTypeBounds {
Unknown: unknown_bounds,
..bounds
}),
(Some(type_bounds), Some(size_type_bounds), _) => {
errors.error( errors.error(
size_type_bounds size_type_bounds
.Size .Size
@ -2427,6 +2516,7 @@ impl ParsedBounds {
pub(crate) enum ParsedBoundCategory { pub(crate) enum ParsedBoundCategory {
Type(ParsedTypeBound), Type(ParsedTypeBound),
SizeType(ParsedSizeTypeBound), SizeType(ParsedSizeTypeBound),
Unknown(syn::TypeParamBound),
} }
impl ParsedBound { impl ParsedBound {
@ -2441,12 +2531,14 @@ impl ParsedBound {
Self::Size(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::Size(v)), Self::Size(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::Size(v)),
Self::StaticType(v) => ParsedBoundCategory::Type(ParsedTypeBound::StaticType(v)), Self::StaticType(v) => ParsedBoundCategory::Type(ParsedTypeBound::StaticType(v)),
Self::Type(v) => ParsedBoundCategory::Type(ParsedTypeBound::Type(v)), Self::Type(v) => ParsedBoundCategory::Type(ParsedTypeBound::Type(v)),
Self::Unknown(v) => ParsedBoundCategory::Unknown(v),
} }
} }
fn implied_bounds(self) -> ParsedBounds { fn implied_bounds(self) -> ParsedBounds {
match self.categorize() { match self.categorize() {
ParsedBoundCategory::Type(v) => v.implied_bounds().into(), ParsedBoundCategory::Type(v) => v.implied_bounds().into(),
ParsedBoundCategory::SizeType(v) => v.implied_bounds().into(), ParsedBoundCategory::SizeType(v) => v.implied_bounds().into(),
ParsedBoundCategory::Unknown(v) => ParsedBounds::from_iter([ParsedBound::Unknown(v)]),
} }
} }
} }
@ -3325,7 +3417,7 @@ impl ParsedGenerics {
| ParsedTypeBound::EnumType(_) | ParsedTypeBound::EnumType(_)
| ParsedTypeBound::IntType(_) | ParsedTypeBound::IntType(_)
| ParsedTypeBound::ResetType(_) => { | ParsedTypeBound::ResetType(_) => {
errors.error(bound, "bound on mask type not implemented"); errors.error(bound, "bounds on mask types are not implemented");
} }
ParsedTypeBound::StaticType(bound) => { ParsedTypeBound::StaticType(bound) => {
if bounds.StaticType.is_none() { if bounds.StaticType.is_none() {
@ -3337,6 +3429,12 @@ impl ParsedGenerics {
} }
} }
ParsedTypeBound::Type(_) => {} ParsedTypeBound::Type(_) => {}
ParsedTypeBound::Unknown(_) => {
errors.error(
bound,
"unknown bounds on mask types are not implemented",
);
}
} }
} }
bounds.add_implied_bounds(); bounds.add_implied_bounds();

View file

@ -191,10 +191,14 @@ circuit check_array_repeat:
}; };
} }
pub trait UnknownTrait {}
impl<T: ?Sized> UnknownTrait for T {}
#[hdl_module(outline_generated)] #[hdl_module(outline_generated)]
pub fn check_skipped_generics<T, #[hdl(skip)] U, const N: usize, #[hdl(skip)] const M: usize>(v: U) pub fn check_skipped_generics<T, #[hdl(skip)] U, const N: usize, #[hdl(skip)] const M: usize>(v: U)
where where
T: StaticType, T: StaticType + UnknownTrait,
ConstUsize<N>: KnownSize, ConstUsize<N>: KnownSize,
U: std::fmt::Display, U: std::fmt::Display,
{ {