support unknown trait bounds in type parameters
This commit is contained in:
parent
86a1bb46be
commit
cdd84953d0
|
@ -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();
|
||||||
|
|
|
@ -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,
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue