support unknown trait bounds in type parameters
This commit is contained in:
		
							parent
							
								
									86a1bb46be
								
							
						
					
					
						commit
						cdd84953d0
					
				
					 2 changed files with 119 additions and 17 deletions
				
			
		|  | @ -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(); | ||||
|  |  | |||
|  | @ -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, | ||||
| { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue