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,
)*
$(
#[unknown]
$Unknown:ident,
)?
}
) => {
#[derive(Clone, Debug)]
$vis enum $enum_type {
$($Variant(known_items::$Variant),)*
$($Unknown(syn::TypeParamBound),)?
}
$(impl From<known_items::$Variant> for $enum_type {
@ -2086,28 +2091,54 @@ macro_rules! impl_bounds {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
$(Self::$Variant(v) => v.to_tokens(tokens),)*
$(Self::$Unknown(v) => v.to_tokens(tokens),)?
}
}
}
impl $enum_type {
$vis fn parse_path(path: Path) -> Result<Self, Path> {
#![allow(unreachable_code)]
$(let path = match known_items::$Variant::parse_path(path) {
Ok(v) => return Ok(Self::$Variant(v)),
Err(path) => path,
};)*
$(return Ok(Self::$Unknown(syn::TraitBound {
paren_token: None,
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path,
}.into()));)?
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 {
fn parse(input: ParseStream) -> syn::Result<Self> {
Self::parse_path(Path::parse_mod_style(input)?).map_err(|path| {
syn::Error::new_spanned(
path,
Self::parse_type_param_bound(input.parse()?)
.map_err(|type_param_bound| syn::Error::new_spanned(
type_param_bound,
format_args!("expected one of: {}", [$(stringify!($Variant)),*].join(", ")),
)
})
))
}
}
@ -2115,6 +2146,7 @@ macro_rules! impl_bounds {
#[allow(non_snake_case)]
$vis struct $struct_type {
$($vis $Variant: Option<known_items::$Variant>,)*
$($vis $Unknown: Vec<syn::TypeParamBound>,)?
}
impl ToTokens for $struct_type {
@ -2126,42 +2158,63 @@ macro_rules! impl_bounds {
separator = Some(<Token![+]>::default());
v.to_tokens(tokens);
})*
$(for v in &self.$Unknown {
separator.to_tokens(tokens);
separator = Some(<Token![+]>::default());
v.to_tokens(tokens);
})*
}
}
const _: () = {
#[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 {
type Item = $enum_type;
type IntoIter = Iter;
fn into_iter(self) -> Self::IntoIter {
Iter(self)
Iter {
$($Variant: self.$Variant,)*
$($Unknown: self.$Unknown.into_iter(),)?
}
}
}
impl Iterator for Iter {
type Item = $enum_type;
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));
}
)*
$(
if let Some(value) = self.$Unknown.next() {
return Some($enum_type::$Unknown(value));
}
)?
None
}
#[allow(unused_mut, unused_variables)]
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));
}
)*
$(
if let Some(value) = self.$Unknown.next() {
init = f(init, $enum_type::$Unknown(value));
}
)?
init
}
}
@ -2173,6 +2226,9 @@ macro_rules! impl_bounds {
$($enum_type::$Variant(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 {
self.$Variant = Some(v);
})*
$(self.$Unknown.extend(v.$Unknown);)*
});
}
}
@ -2244,6 +2301,8 @@ impl_bounds! {
Size,
StaticType,
Type,
#[unknown]
Unknown,
}
}
@ -2257,6 +2316,8 @@ impl_bounds! {
ResetType,
StaticType,
Type,
#[unknown]
Unknown,
}
}
@ -2270,6 +2331,7 @@ impl From<ParsedTypeBound> for ParsedBound {
ParsedTypeBound::ResetType(v) => ParsedBound::ResetType(v),
ParsedTypeBound::StaticType(v) => ParsedBound::StaticType(v),
ParsedTypeBound::Type(v) => ParsedBound::Type(v),
ParsedTypeBound::Unknown(v) => ParsedBound::Unknown(v),
}
}
}
@ -2284,6 +2346,7 @@ impl From<ParsedTypeBounds> for ParsedBounds {
ResetType,
StaticType,
Type,
Unknown,
} = value;
Self {
BoolOrIntType,
@ -2295,6 +2358,7 @@ impl From<ParsedTypeBounds> for ParsedBounds {
Size: None,
StaticType,
Type,
Unknown,
}
}
}
@ -2330,6 +2394,7 @@ impl ParsedTypeBound {
ParsedTypeBound::Type(known_items::Type(span)),
]),
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,
StaticType: None,
Type: None,
Unknown: vec![],
}
}
}
@ -2391,6 +2457,7 @@ impl ParsedBounds {
fn categorize(self, errors: &mut Errors, span: Span) -> ParsedBoundsCategory {
let mut type_bounds = None;
let mut size_type_bounds = None;
let mut unknown_bounds = vec![];
self.into_iter().for_each(|bound| match bound.categorize() {
ParsedBoundCategory::Type(bound) => {
type_bounds
@ -2402,15 +2469,37 @@ impl ParsedBounds {
.get_or_insert_with(ParsedSizeTypeBounds::default)
.extend([bound]);
}
ParsedBoundCategory::Unknown(bound) => unknown_bounds.push(bound),
});
match (type_bounds, size_type_bounds) {
(None, None) => ParsedBoundsCategory::Type(ParsedTypeBounds {
match (type_bounds, size_type_bounds, unknown_bounds.is_empty()) {
(None, None, true) => ParsedBoundsCategory::Type(ParsedTypeBounds {
Type: Some(known_items::Type(span)),
..Default::default()
}),
(None, Some(bounds)) => ParsedBoundsCategory::SizeType(bounds),
(Some(bounds), None) => ParsedBoundsCategory::Type(bounds),
(Some(type_bounds), Some(size_type_bounds)) => {
(None, None, false) => {
errors.error(
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(
size_type_bounds
.Size
@ -2427,6 +2516,7 @@ impl ParsedBounds {
pub(crate) enum ParsedBoundCategory {
Type(ParsedTypeBound),
SizeType(ParsedSizeTypeBound),
Unknown(syn::TypeParamBound),
}
impl ParsedBound {
@ -2441,12 +2531,14 @@ impl ParsedBound {
Self::Size(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::Size(v)),
Self::StaticType(v) => ParsedBoundCategory::Type(ParsedTypeBound::StaticType(v)),
Self::Type(v) => ParsedBoundCategory::Type(ParsedTypeBound::Type(v)),
Self::Unknown(v) => ParsedBoundCategory::Unknown(v),
}
}
fn implied_bounds(self) -> ParsedBounds {
match self.categorize() {
ParsedBoundCategory::Type(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::IntType(_)
| ParsedTypeBound::ResetType(_) => {
errors.error(bound, "bound on mask type not implemented");
errors.error(bound, "bounds on mask types are not implemented");
}
ParsedTypeBound::StaticType(bound) => {
if bounds.StaticType.is_none() {
@ -3337,6 +3429,12 @@ impl ParsedGenerics {
}
}
ParsedTypeBound::Type(_) => {}
ParsedTypeBound::Unknown(_) => {
errors.error(
bound,
"unknown bounds on mask types are not implemented",
);
}
}
}
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)]
pub fn check_skipped_generics<T, #[hdl(skip)] U, const N: usize, #[hdl(skip)] const M: usize>(v: U)
where
T: StaticType,
T: StaticType + UnknownTrait,
ConstUsize<N>: KnownSize,
U: std::fmt::Display,
{