WIP: use HdlOption[the_type_var] or UInt[123 + n] for creating types
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				/ test (push) Successful in 13s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	/ test (push) Successful in 13s
				
			This commit is contained in:
		
							parent
							
								
									cd99dbc849
								
							
						
					
					
						commit
						73f15ae8e8
					
				
					 33 changed files with 11290 additions and 8948 deletions
				
			
		| 
						 | 
					@ -7,13 +7,14 @@ jobs:
 | 
				
			||||||
      - uses: https://code.forgejo.org/actions/checkout@v3
 | 
					      - uses: https://code.forgejo.org/actions/checkout@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          fetch-depth: 0
 | 
					          fetch-depth: 0
 | 
				
			||||||
      - run: |
 | 
					# FIXME: uncomment once the code works again
 | 
				
			||||||
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.79.0
 | 
					#      - run: |
 | 
				
			||||||
          source "$HOME/.cargo/env"
 | 
					#          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.79.0
 | 
				
			||||||
          echo "$PATH" >> "$GITHUB_PATH"
 | 
					#          source "$HOME/.cargo/env"
 | 
				
			||||||
      - uses: https://github.com/Swatinem/rust-cache@v2
 | 
					#          echo "$PATH" >> "$GITHUB_PATH"
 | 
				
			||||||
        with:
 | 
					#      - uses: https://github.com/Swatinem/rust-cache@v2
 | 
				
			||||||
          save-if: ${{ github.ref == 'refs/heads/master' }}
 | 
					#        with:
 | 
				
			||||||
      - run: cargo test
 | 
					#          save-if: ${{ github.ref == 'refs/heads/master' }}
 | 
				
			||||||
      - run: cargo test --features=unstable-doc
 | 
					#      - run: cargo test
 | 
				
			||||||
      - run: cargo doc --features=unstable-doc
 | 
					#      - run: cargo test --features=unstable-doc
 | 
				
			||||||
 | 
					#      - run: cargo doc --features=unstable-doc
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										847
									
								
								crates/fayalite-proc-macros-impl/src/hdl_bundle.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										847
									
								
								crates/fayalite-proc-macros-impl/src/hdl_bundle.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,847 @@
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    hdl_type_common::{
 | 
				
			||||||
 | 
					        common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedField,
 | 
				
			||||||
 | 
					        ParsedFieldsNamed, ParsedGenerics, SplitForImpl, TypesParser, WrappedInConst,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    kw, Errors, HdlAttr, PairsIterExt,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use proc_macro2::TokenStream;
 | 
				
			||||||
 | 
					use quote::{format_ident, quote_spanned, ToTokens};
 | 
				
			||||||
 | 
					use syn::{
 | 
				
			||||||
 | 
					    parse_quote, parse_quote_spanned,
 | 
				
			||||||
 | 
					    punctuated::{Pair, Punctuated},
 | 
				
			||||||
 | 
					    spanned::Spanned,
 | 
				
			||||||
 | 
					    token::Brace,
 | 
				
			||||||
 | 
					    AngleBracketedGenericArguments, Attribute, Field, FieldMutability, Fields, FieldsNamed,
 | 
				
			||||||
 | 
					    GenericParam, Generics, Ident, ItemStruct, Path, Token, Type, Visibility,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
 | 
					pub(crate) struct ParsedBundle {
 | 
				
			||||||
 | 
					    pub(crate) attrs: Vec<Attribute>,
 | 
				
			||||||
 | 
					    pub(crate) options: HdlAttr<ItemOptions>,
 | 
				
			||||||
 | 
					    pub(crate) vis: Visibility,
 | 
				
			||||||
 | 
					    pub(crate) struct_token: Token![struct],
 | 
				
			||||||
 | 
					    pub(crate) ident: Ident,
 | 
				
			||||||
 | 
					    pub(crate) generics: MaybeParsed<ParsedGenerics, Generics>,
 | 
				
			||||||
 | 
					    pub(crate) fields: MaybeParsed<ParsedFieldsNamed, FieldsNamed>,
 | 
				
			||||||
 | 
					    pub(crate) field_flips: Vec<Option<HdlAttr<kw::flip>>>,
 | 
				
			||||||
 | 
					    pub(crate) mask_type_ident: Ident,
 | 
				
			||||||
 | 
					    pub(crate) mask_type_match_variant_ident: Ident,
 | 
				
			||||||
 | 
					    pub(crate) match_variant_ident: Ident,
 | 
				
			||||||
 | 
					    pub(crate) builder_ident: Ident,
 | 
				
			||||||
 | 
					    pub(crate) mask_type_builder_ident: Ident,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ParsedBundle {
 | 
				
			||||||
 | 
					    fn parse_field(
 | 
				
			||||||
 | 
					        errors: &mut Errors,
 | 
				
			||||||
 | 
					        field: &mut Field,
 | 
				
			||||||
 | 
					        index: usize,
 | 
				
			||||||
 | 
					    ) -> Option<HdlAttr<kw::flip>> {
 | 
				
			||||||
 | 
					        let Field {
 | 
				
			||||||
 | 
					            attrs,
 | 
				
			||||||
 | 
					            vis: _,
 | 
				
			||||||
 | 
					            mutability,
 | 
				
			||||||
 | 
					            ident,
 | 
				
			||||||
 | 
					            colon_token,
 | 
				
			||||||
 | 
					            ty,
 | 
				
			||||||
 | 
					        } = field;
 | 
				
			||||||
 | 
					        let ident = ident.get_or_insert_with(|| format_ident!("_{}", index, span = ty.span()));
 | 
				
			||||||
 | 
					        if !matches!(mutability, FieldMutability::None) {
 | 
				
			||||||
 | 
					            // FIXME: use mutability as the spanned tokens,
 | 
				
			||||||
 | 
					            // blocked on https://github.com/dtolnay/syn/issues/1717
 | 
				
			||||||
 | 
					            errors.error(&ident, "field mutability is not supported");
 | 
				
			||||||
 | 
					            *mutability = FieldMutability::None;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        *mutability = FieldMutability::None;
 | 
				
			||||||
 | 
					        colon_token.get_or_insert(Token));
 | 
				
			||||||
 | 
					        let options = errors.unwrap_or_default(HdlAttr::parse_and_take_attr(attrs));
 | 
				
			||||||
 | 
					        options
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn parse(item: ItemStruct) -> syn::Result<Self> {
 | 
				
			||||||
 | 
					        let ItemStruct {
 | 
				
			||||||
 | 
					            mut attrs,
 | 
				
			||||||
 | 
					            vis,
 | 
				
			||||||
 | 
					            struct_token,
 | 
				
			||||||
 | 
					            ident,
 | 
				
			||||||
 | 
					            mut generics,
 | 
				
			||||||
 | 
					            fields,
 | 
				
			||||||
 | 
					            semi_token,
 | 
				
			||||||
 | 
					        } = item;
 | 
				
			||||||
 | 
					        let mut errors = Errors::new();
 | 
				
			||||||
 | 
					        let mut options = errors
 | 
				
			||||||
 | 
					            .unwrap_or_default(HdlAttr::<ItemOptions>::parse_and_take_attr(&mut attrs))
 | 
				
			||||||
 | 
					            .unwrap_or_default();
 | 
				
			||||||
 | 
					        errors.ok(options.body.validate());
 | 
				
			||||||
 | 
					        let ItemOptions {
 | 
				
			||||||
 | 
					            outline_generated: _,
 | 
				
			||||||
 | 
					            connect_inexact: _,
 | 
				
			||||||
 | 
					            target: _,
 | 
				
			||||||
 | 
					            custom_bounds,
 | 
				
			||||||
 | 
					            no_static: _,
 | 
				
			||||||
 | 
					        } = options.body;
 | 
				
			||||||
 | 
					        let mut fields = match fields {
 | 
				
			||||||
 | 
					            syn::Fields::Named(fields) => fields,
 | 
				
			||||||
 | 
					            syn::Fields::Unnamed(fields) => {
 | 
				
			||||||
 | 
					                errors.error(&fields, "#[hdl] struct must use curly braces: {}");
 | 
				
			||||||
 | 
					                FieldsNamed {
 | 
				
			||||||
 | 
					                    brace_token: Brace(fields.paren_token.span),
 | 
				
			||||||
 | 
					                    named: fields.unnamed,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            syn::Fields::Unit => {
 | 
				
			||||||
 | 
					                errors.error(&fields, "#[hdl] struct must use curly braces: {}");
 | 
				
			||||||
 | 
					                FieldsNamed {
 | 
				
			||||||
 | 
					                    brace_token: Brace(semi_token.unwrap_or_default().span),
 | 
				
			||||||
 | 
					                    named: Punctuated::default(),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let mut field_flips = Vec::with_capacity(fields.named.len());
 | 
				
			||||||
 | 
					        for (index, field) in fields.named.iter_mut().enumerate() {
 | 
				
			||||||
 | 
					            field_flips.push(Self::parse_field(&mut errors, field, index));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let generics = if custom_bounds.is_some() {
 | 
				
			||||||
 | 
					            MaybeParsed::Unrecognized(generics)
 | 
				
			||||||
 | 
					        } else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) {
 | 
				
			||||||
 | 
					            MaybeParsed::Parsed(generics)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            MaybeParsed::Unrecognized(generics)
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let fields = TypesParser::maybe_run(generics.as_ref(), fields, &mut errors);
 | 
				
			||||||
 | 
					        errors.finish()?;
 | 
				
			||||||
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            attrs,
 | 
				
			||||||
 | 
					            options,
 | 
				
			||||||
 | 
					            vis,
 | 
				
			||||||
 | 
					            struct_token,
 | 
				
			||||||
 | 
					            generics,
 | 
				
			||||||
 | 
					            fields,
 | 
				
			||||||
 | 
					            field_flips,
 | 
				
			||||||
 | 
					            mask_type_ident: format_ident!("__{}__MaskType", ident),
 | 
				
			||||||
 | 
					            mask_type_match_variant_ident: format_ident!("__{}__MaskType__MatchVariant", ident),
 | 
				
			||||||
 | 
					            match_variant_ident: format_ident!("__{}__MatchVariant", ident),
 | 
				
			||||||
 | 
					            mask_type_builder_ident: format_ident!("__{}__MaskType__Builder", ident),
 | 
				
			||||||
 | 
					            builder_ident: format_ident!("__{}__Builder", ident),
 | 
				
			||||||
 | 
					            ident,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
 | 
					struct Builder {
 | 
				
			||||||
 | 
					    vis: Visibility,
 | 
				
			||||||
 | 
					    struct_token: Token![struct],
 | 
				
			||||||
 | 
					    ident: Ident,
 | 
				
			||||||
 | 
					    target: Path,
 | 
				
			||||||
 | 
					    generics: Generics,
 | 
				
			||||||
 | 
					    fields: FieldsNamed,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Copy, Clone, Eq, PartialEq, Debug)]
 | 
				
			||||||
 | 
					enum BuilderFieldState {
 | 
				
			||||||
 | 
					    Unfilled,
 | 
				
			||||||
 | 
					    Generic,
 | 
				
			||||||
 | 
					    Filled,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Builder {
 | 
				
			||||||
 | 
					    fn phantom_field_name(&self) -> Ident {
 | 
				
			||||||
 | 
					        format_ident!("__phantom", span = self.ident.span())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn phantom_field(&self) -> Field {
 | 
				
			||||||
 | 
					        let target = &self.target;
 | 
				
			||||||
 | 
					        let type_generics = self.generics.split_for_impl().1;
 | 
				
			||||||
 | 
					        Field {
 | 
				
			||||||
 | 
					            attrs: vec![],
 | 
				
			||||||
 | 
					            vis: Visibility::Inherited,
 | 
				
			||||||
 | 
					            mutability: FieldMutability::None,
 | 
				
			||||||
 | 
					            ident: Some(self.phantom_field_name()),
 | 
				
			||||||
 | 
					            colon_token: Some(Token)),
 | 
				
			||||||
 | 
					            ty: parse_quote_spanned! {self.ident.span()=>
 | 
				
			||||||
 | 
					                ::fayalite::__std::marker::PhantomData<#target #type_generics>
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn builder_struct_generics(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        mut get_field_state: impl FnMut(usize) -> BuilderFieldState,
 | 
				
			||||||
 | 
					    ) -> Generics {
 | 
				
			||||||
 | 
					        let mut retval = self.generics.clone();
 | 
				
			||||||
 | 
					        for param in retval.params.iter_mut() {
 | 
				
			||||||
 | 
					            match param {
 | 
				
			||||||
 | 
					                GenericParam::Lifetime(_) => {}
 | 
				
			||||||
 | 
					                GenericParam::Type(param) => param.default = None,
 | 
				
			||||||
 | 
					                GenericParam::Const(param) => param.default = None,
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (field_index, field) in self.fields.named.iter().enumerate() {
 | 
				
			||||||
 | 
					            match get_field_state(field_index) {
 | 
				
			||||||
 | 
					                BuilderFieldState::Unfilled | BuilderFieldState::Filled => continue,
 | 
				
			||||||
 | 
					                BuilderFieldState::Generic => {}
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if !retval.params.empty_or_trailing() {
 | 
				
			||||||
 | 
					                retval.params.push_punct(Token));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            retval.params.push_value(GenericParam::Type(
 | 
				
			||||||
 | 
					                type_var_for_field_name(field.ident.as_ref().unwrap()).into(),
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        retval
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn builder_struct_ty(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        mut get_field_state: impl FnMut(usize) -> BuilderFieldState,
 | 
				
			||||||
 | 
					    ) -> Type {
 | 
				
			||||||
 | 
					        let mut ty_arguments: AngleBracketedGenericArguments = if self.generics.params.is_empty() {
 | 
				
			||||||
 | 
					            parse_quote_spanned! {self.ident.span()=>
 | 
				
			||||||
 | 
					                <>
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            let builder_type_generics = self.generics.split_for_impl().1;
 | 
				
			||||||
 | 
					            parse_quote! { #builder_type_generics }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        for (field_index, Field { ident, ty, .. }) in self.fields.named.iter().enumerate() {
 | 
				
			||||||
 | 
					            let ident = ident.as_ref().unwrap();
 | 
				
			||||||
 | 
					            if !ty_arguments.args.empty_or_trailing() {
 | 
				
			||||||
 | 
					                ty_arguments.args.push_punct(Token));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ty_arguments
 | 
				
			||||||
 | 
					                .args
 | 
				
			||||||
 | 
					                .push_value(match get_field_state(field_index) {
 | 
				
			||||||
 | 
					                    BuilderFieldState::Unfilled => parse_quote_spanned! {self.ident.span()=>
 | 
				
			||||||
 | 
					                        ::fayalite::bundle::Unfilled<#ty>
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    BuilderFieldState::Generic => {
 | 
				
			||||||
 | 
					                        let type_var = type_var_for_field_name(ident);
 | 
				
			||||||
 | 
					                        parse_quote_spanned! {self.ident.span()=>
 | 
				
			||||||
 | 
					                            #type_var
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    BuilderFieldState::Filled => parse_quote_spanned! {self.ident.span()=>
 | 
				
			||||||
 | 
					                        ::fayalite::expr::Expr<#ty>
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let ident = &self.ident;
 | 
				
			||||||
 | 
					        parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					            #ident #ty_arguments
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn type_var_for_field_name(ident: &Ident) -> Ident {
 | 
				
			||||||
 | 
					    format_ident!("__T_{}", ident)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn field_fn_for_field_name(ident: &Ident) -> Ident {
 | 
				
			||||||
 | 
					    format_ident!("field_{}", ident)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ToTokens for Builder {
 | 
				
			||||||
 | 
					    fn to_tokens(&self, tokens: &mut TokenStream) {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            vis,
 | 
				
			||||||
 | 
					            struct_token,
 | 
				
			||||||
 | 
					            ident,
 | 
				
			||||||
 | 
					            target,
 | 
				
			||||||
 | 
					            generics: _,
 | 
				
			||||||
 | 
					            fields,
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					        let phantom_field_name = self.phantom_field_name();
 | 
				
			||||||
 | 
					        let builder_struct = ItemStruct {
 | 
				
			||||||
 | 
					            attrs: vec![parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                #[allow(non_camel_case_types, dead_code)]
 | 
				
			||||||
 | 
					            }],
 | 
				
			||||||
 | 
					            vis: vis.clone(),
 | 
				
			||||||
 | 
					            struct_token: *struct_token,
 | 
				
			||||||
 | 
					            ident: ident.clone(),
 | 
				
			||||||
 | 
					            generics: self.builder_struct_generics(|_| BuilderFieldState::Generic),
 | 
				
			||||||
 | 
					            fields: Fields::Named(FieldsNamed {
 | 
				
			||||||
 | 
					                brace_token: fields.brace_token,
 | 
				
			||||||
 | 
					                named: Punctuated::from_iter(
 | 
				
			||||||
 | 
					                    [Pair::Punctuated(
 | 
				
			||||||
 | 
					                        self.phantom_field(),
 | 
				
			||||||
 | 
					                        Token),
 | 
				
			||||||
 | 
					                    )]
 | 
				
			||||||
 | 
					                    .into_iter()
 | 
				
			||||||
 | 
					                    .chain(fields.named.pairs().map_pair_value_ref(|field| {
 | 
				
			||||||
 | 
					                        let ident = field.ident.as_ref().unwrap();
 | 
				
			||||||
 | 
					                        let type_var = type_var_for_field_name(ident);
 | 
				
			||||||
 | 
					                        Field {
 | 
				
			||||||
 | 
					                            vis: Visibility::Inherited,
 | 
				
			||||||
 | 
					                            ty: parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                                #type_var
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            ..field.clone()
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    })),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            semi_token: None,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        builder_struct.to_tokens(tokens);
 | 
				
			||||||
 | 
					        let field_idents = Vec::from_iter(
 | 
				
			||||||
 | 
					            self.fields
 | 
				
			||||||
 | 
					                .named
 | 
				
			||||||
 | 
					                .iter()
 | 
				
			||||||
 | 
					                .map(|field| field.ident.as_ref().unwrap()),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        for (
 | 
				
			||||||
 | 
					            field_index,
 | 
				
			||||||
 | 
					            Field {
 | 
				
			||||||
 | 
					                vis,
 | 
				
			||||||
 | 
					                ident: field_ident,
 | 
				
			||||||
 | 
					                ty,
 | 
				
			||||||
 | 
					                ..
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ) in self.fields.named.iter().enumerate()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            let field_ident = field_ident.as_ref().unwrap();
 | 
				
			||||||
 | 
					            let fn_ident = field_fn_for_field_name(field_ident);
 | 
				
			||||||
 | 
					            let fn_generics = self.builder_struct_generics(|i| {
 | 
				
			||||||
 | 
					                if i == field_index {
 | 
				
			||||||
 | 
					                    BuilderFieldState::Unfilled
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    BuilderFieldState::Generic
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            let (impl_generics, _, where_clause) = fn_generics.split_for_impl();
 | 
				
			||||||
 | 
					            let unfilled_ty = self.builder_struct_ty(|i| {
 | 
				
			||||||
 | 
					                if i == field_index {
 | 
				
			||||||
 | 
					                    BuilderFieldState::Unfilled
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    BuilderFieldState::Generic
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            let filled_ty = self.builder_struct_ty(|i| {
 | 
				
			||||||
 | 
					                if i == field_index {
 | 
				
			||||||
 | 
					                    BuilderFieldState::Filled
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    BuilderFieldState::Generic
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            let pat_fields =
 | 
				
			||||||
 | 
					                Vec::from_iter(self.fields.named.iter().enumerate().map(|(i, field)| {
 | 
				
			||||||
 | 
					                    let field_ident = field.ident.as_ref().unwrap();
 | 
				
			||||||
 | 
					                    if field_index == i {
 | 
				
			||||||
 | 
					                        quote_spanned! {self.ident.span()=>
 | 
				
			||||||
 | 
					                            #field_ident: _,
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        quote_spanned! {self.ident.span()=>
 | 
				
			||||||
 | 
					                            #field_ident,
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
 | 
					            quote_spanned! {self.ident.span()=>
 | 
				
			||||||
 | 
					                #[automatically_derived]
 | 
				
			||||||
 | 
					                #[allow(non_camel_case_types, dead_code)]
 | 
				
			||||||
 | 
					                impl #impl_generics #unfilled_ty
 | 
				
			||||||
 | 
					                #where_clause
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    #vis fn #fn_ident(
 | 
				
			||||||
 | 
					                        self,
 | 
				
			||||||
 | 
					                        #field_ident: impl ::fayalite::expr::ToExpr<Type = #ty>,
 | 
				
			||||||
 | 
					                    ) -> #filled_ty {
 | 
				
			||||||
 | 
					                        let Self {
 | 
				
			||||||
 | 
					                            #phantom_field_name: _,
 | 
				
			||||||
 | 
					                            #(#pat_fields)*
 | 
				
			||||||
 | 
					                        } = self;
 | 
				
			||||||
 | 
					                        let #field_ident = ::fayalite::expr::ToExpr::to_expr(&#field_ident);
 | 
				
			||||||
 | 
					                        #ident {
 | 
				
			||||||
 | 
					                            #phantom_field_name: ::fayalite::__std::marker::PhantomData,
 | 
				
			||||||
 | 
					                            #(#field_idents,)*
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .to_tokens(tokens);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let unfilled_generics = self.builder_struct_generics(|_| BuilderFieldState::Unfilled);
 | 
				
			||||||
 | 
					        let unfilled_ty = self.builder_struct_ty(|_| BuilderFieldState::Unfilled);
 | 
				
			||||||
 | 
					        let (unfilled_impl_generics, _, unfilled_where_clause) = unfilled_generics.split_for_impl();
 | 
				
			||||||
 | 
					        quote_spanned! {self.ident.span()=>
 | 
				
			||||||
 | 
					            #[automatically_derived]
 | 
				
			||||||
 | 
					            #[allow(non_camel_case_types, dead_code)]
 | 
				
			||||||
 | 
					            impl #unfilled_impl_generics ::fayalite::__std::default::Default for #unfilled_ty
 | 
				
			||||||
 | 
					            #unfilled_where_clause
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                fn default() -> Self {
 | 
				
			||||||
 | 
					                    #ident {
 | 
				
			||||||
 | 
					                        #phantom_field_name: ::fayalite::__std::marker::PhantomData,
 | 
				
			||||||
 | 
					                        #(#field_idents: ::fayalite::__std::default::Default::default(),)*
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_tokens(tokens);
 | 
				
			||||||
 | 
					        let filled_generics = self.builder_struct_generics(|_| BuilderFieldState::Filled);
 | 
				
			||||||
 | 
					        let filled_ty = self.builder_struct_ty(|_| BuilderFieldState::Filled);
 | 
				
			||||||
 | 
					        let (filled_impl_generics, _, filled_where_clause) = filled_generics.split_for_impl();
 | 
				
			||||||
 | 
					        let type_generics = self.generics.split_for_impl().1;
 | 
				
			||||||
 | 
					        quote_spanned! {self.ident.span()=>
 | 
				
			||||||
 | 
					            #[automatically_derived]
 | 
				
			||||||
 | 
					            #[allow(non_camel_case_types, dead_code)]
 | 
				
			||||||
 | 
					            impl #filled_impl_generics ::fayalite::expr::ToExpr for #filled_ty
 | 
				
			||||||
 | 
					            #filled_where_clause
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                type Type = #target #type_generics;
 | 
				
			||||||
 | 
					                fn to_expr(
 | 
				
			||||||
 | 
					                    &self,
 | 
				
			||||||
 | 
					                ) -> ::fayalite::expr::Expr<<Self as ::fayalite::expr::ToExpr>::Type> {
 | 
				
			||||||
 | 
					                    let __ty = #target {
 | 
				
			||||||
 | 
					                        #(#field_idents: ::fayalite::expr::Expr::ty(self.#field_idents),)*
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    let __field_values = [
 | 
				
			||||||
 | 
					                        #(::fayalite::expr::Expr::canonical(self.#field_idents),)*
 | 
				
			||||||
 | 
					                    ];
 | 
				
			||||||
 | 
					                    ::fayalite::expr::ToExpr::to_expr(
 | 
				
			||||||
 | 
					                        &::fayalite::expr::ops::BundleLiteral::new(
 | 
				
			||||||
 | 
					                            __ty,
 | 
				
			||||||
 | 
					                            ::fayalite::intern::Intern::intern(&__field_values[..]),
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_tokens(tokens);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ToTokens for ParsedBundle {
 | 
				
			||||||
 | 
					    fn to_tokens(&self, tokens: &mut TokenStream) {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            attrs,
 | 
				
			||||||
 | 
					            options,
 | 
				
			||||||
 | 
					            vis,
 | 
				
			||||||
 | 
					            struct_token,
 | 
				
			||||||
 | 
					            ident,
 | 
				
			||||||
 | 
					            generics,
 | 
				
			||||||
 | 
					            fields,
 | 
				
			||||||
 | 
					            field_flips,
 | 
				
			||||||
 | 
					            mask_type_ident,
 | 
				
			||||||
 | 
					            mask_type_match_variant_ident,
 | 
				
			||||||
 | 
					            match_variant_ident,
 | 
				
			||||||
 | 
					            builder_ident,
 | 
				
			||||||
 | 
					            mask_type_builder_ident,
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					        let ItemOptions {
 | 
				
			||||||
 | 
					            outline_generated: _,
 | 
				
			||||||
 | 
					            connect_inexact,
 | 
				
			||||||
 | 
					            target,
 | 
				
			||||||
 | 
					            custom_bounds: _,
 | 
				
			||||||
 | 
					            no_static,
 | 
				
			||||||
 | 
					        } = &options.body;
 | 
				
			||||||
 | 
					        let target = get_target(target, ident);
 | 
				
			||||||
 | 
					        let mut item_attrs = attrs.clone();
 | 
				
			||||||
 | 
					        item_attrs.push(common_derives(ident.span()));
 | 
				
			||||||
 | 
					        ItemStruct {
 | 
				
			||||||
 | 
					            attrs: item_attrs,
 | 
				
			||||||
 | 
					            vis: vis.clone(),
 | 
				
			||||||
 | 
					            struct_token: *struct_token,
 | 
				
			||||||
 | 
					            ident: ident.clone(),
 | 
				
			||||||
 | 
					            generics: generics.into(),
 | 
				
			||||||
 | 
					            fields: Fields::Named(fields.clone().into()),
 | 
				
			||||||
 | 
					            semi_token: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_tokens(tokens);
 | 
				
			||||||
 | 
					        let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
 | 
				
			||||||
 | 
					        if let (MaybeParsed::Parsed(generics), MaybeParsed::Parsed(fields)) = (generics, fields) {
 | 
				
			||||||
 | 
					            generics.make_runtime_generics(tokens, vis, ident, &target, |context| {
 | 
				
			||||||
 | 
					                let fields: Vec<_> = fields
 | 
				
			||||||
 | 
					                    .named
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .map(|ParsedField { ident, ty, .. }| {
 | 
				
			||||||
 | 
					                        let ident = ident.as_ref().unwrap();
 | 
				
			||||||
 | 
					                        let expr = ty.make_hdl_type_expr(context);
 | 
				
			||||||
 | 
					                        quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                            #ident: #expr,
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .collect();
 | 
				
			||||||
 | 
					                parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    #target {
 | 
				
			||||||
 | 
					                        #(#fields)*
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span());
 | 
				
			||||||
 | 
					        let tokens = wrapped_in_const.inner();
 | 
				
			||||||
 | 
					        let builder = Builder {
 | 
				
			||||||
 | 
					            vis: vis.clone(),
 | 
				
			||||||
 | 
					            struct_token: *struct_token,
 | 
				
			||||||
 | 
					            ident: builder_ident.clone(),
 | 
				
			||||||
 | 
					            target: target.clone(),
 | 
				
			||||||
 | 
					            generics: generics.into(),
 | 
				
			||||||
 | 
					            fields: fields.clone().into(),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        builder.to_tokens(tokens);
 | 
				
			||||||
 | 
					        let unfilled_builder_ty = builder.builder_struct_ty(|_| BuilderFieldState::Unfilled);
 | 
				
			||||||
 | 
					        let filled_builder_ty = builder.builder_struct_ty(|_| BuilderFieldState::Filled);
 | 
				
			||||||
 | 
					        let mut mask_type_fields = FieldsNamed::from(fields.clone());
 | 
				
			||||||
 | 
					        for Field { ident, ty, .. } in &mut mask_type_fields.named {
 | 
				
			||||||
 | 
					            let ident = ident.as_ref().unwrap();
 | 
				
			||||||
 | 
					            *ty = parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                <#ty as ::fayalite::ty::Type>::MaskType
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let mask_type_builder = Builder {
 | 
				
			||||||
 | 
					            vis: vis.clone(),
 | 
				
			||||||
 | 
					            struct_token: *struct_token,
 | 
				
			||||||
 | 
					            ident: mask_type_builder_ident.clone(),
 | 
				
			||||||
 | 
					            target: mask_type_ident.clone().into(),
 | 
				
			||||||
 | 
					            generics: generics.into(),
 | 
				
			||||||
 | 
					            fields: mask_type_fields.clone(),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        mask_type_builder.to_tokens(tokens);
 | 
				
			||||||
 | 
					        let unfilled_mask_type_builder_ty =
 | 
				
			||||||
 | 
					            mask_type_builder.builder_struct_ty(|_| BuilderFieldState::Unfilled);
 | 
				
			||||||
 | 
					        let filled_mask_type_builder_ty =
 | 
				
			||||||
 | 
					            mask_type_builder.builder_struct_ty(|_| BuilderFieldState::Filled);
 | 
				
			||||||
 | 
					        ItemStruct {
 | 
				
			||||||
 | 
					            attrs: vec![
 | 
				
			||||||
 | 
					                common_derives(ident.span()),
 | 
				
			||||||
 | 
					                parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    #[allow(non_camel_case_types, dead_code)]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            vis: vis.clone(),
 | 
				
			||||||
 | 
					            struct_token: *struct_token,
 | 
				
			||||||
 | 
					            ident: mask_type_ident.clone(),
 | 
				
			||||||
 | 
					            generics: generics.into(),
 | 
				
			||||||
 | 
					            fields: Fields::Named(mask_type_fields.clone()),
 | 
				
			||||||
 | 
					            semi_token: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_tokens(tokens);
 | 
				
			||||||
 | 
					        let mut mask_type_match_variant_fields = mask_type_fields;
 | 
				
			||||||
 | 
					        for Field { ident, ty, .. } in &mut mask_type_match_variant_fields.named {
 | 
				
			||||||
 | 
					            let ident = ident.as_ref().unwrap();
 | 
				
			||||||
 | 
					            *ty = parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                ::fayalite::expr::Expr<#ty>
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ItemStruct {
 | 
				
			||||||
 | 
					            attrs: vec![
 | 
				
			||||||
 | 
					                common_derives(ident.span()),
 | 
				
			||||||
 | 
					                parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    #[allow(non_camel_case_types, dead_code)]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            vis: vis.clone(),
 | 
				
			||||||
 | 
					            struct_token: *struct_token,
 | 
				
			||||||
 | 
					            ident: mask_type_match_variant_ident.clone(),
 | 
				
			||||||
 | 
					            generics: generics.into(),
 | 
				
			||||||
 | 
					            fields: Fields::Named(mask_type_match_variant_fields),
 | 
				
			||||||
 | 
					            semi_token: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_tokens(tokens);
 | 
				
			||||||
 | 
					        let mut match_variant_fields = FieldsNamed::from(fields.clone());
 | 
				
			||||||
 | 
					        for Field { ident, ty, .. } in &mut match_variant_fields.named {
 | 
				
			||||||
 | 
					            let ident = ident.as_ref().unwrap();
 | 
				
			||||||
 | 
					            *ty = parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                ::fayalite::expr::Expr<#ty>
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ItemStruct {
 | 
				
			||||||
 | 
					            attrs: vec![
 | 
				
			||||||
 | 
					                common_derives(ident.span()),
 | 
				
			||||||
 | 
					                parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    #[allow(non_camel_case_types, dead_code)]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            vis: vis.clone(),
 | 
				
			||||||
 | 
					            struct_token: *struct_token,
 | 
				
			||||||
 | 
					            ident: match_variant_ident.clone(),
 | 
				
			||||||
 | 
					            generics: generics.into(),
 | 
				
			||||||
 | 
					            fields: Fields::Named(match_variant_fields),
 | 
				
			||||||
 | 
					            semi_token: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_tokens(tokens);
 | 
				
			||||||
 | 
					        let match_variant_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
 | 
				
			||||||
 | 
					            let ident: &Ident = field.ident().as_ref().unwrap();
 | 
				
			||||||
 | 
					            let ident_str = ident.to_string();
 | 
				
			||||||
 | 
					            quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                #ident: ::fayalite::expr::Expr::field(__this, #ident_str),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					        let mask_type_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
 | 
				
			||||||
 | 
					            let ident: &Ident = field.ident().as_ref().unwrap();
 | 
				
			||||||
 | 
					            quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                #ident: ::fayalite::ty::Type::mask_type(&self.#ident),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					        let from_canonical_body_fields =
 | 
				
			||||||
 | 
					            Vec::from_iter(fields.named().into_iter().enumerate().zip(field_flips).map(
 | 
				
			||||||
 | 
					                |((index, field), flip)| {
 | 
				
			||||||
 | 
					                    let ident: &Ident = field.ident().as_ref().unwrap();
 | 
				
			||||||
 | 
					                    let ident_str = ident.to_string();
 | 
				
			||||||
 | 
					                    let flipped = flip.is_some();
 | 
				
			||||||
 | 
					                    quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                        #ident: {
 | 
				
			||||||
 | 
					                            let ::fayalite::bundle::BundleField {
 | 
				
			||||||
 | 
					                                name: __name,
 | 
				
			||||||
 | 
					                                flipped: __flipped,
 | 
				
			||||||
 | 
					                                ty: __ty,
 | 
				
			||||||
 | 
					                            } = __fields[#index];
 | 
				
			||||||
 | 
					                            ::fayalite::__std::assert_eq!(&*__name, #ident_str);
 | 
				
			||||||
 | 
					                            ::fayalite::__std::assert_eq!(__flipped, #flipped);
 | 
				
			||||||
 | 
					                            ::fayalite::ty::Type::from_canonical(__ty)
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					        let fields_body_fields = Vec::from_iter(fields.named().into_iter().zip(field_flips).map(
 | 
				
			||||||
 | 
					            |(field, flip)| {
 | 
				
			||||||
 | 
					                let ident: &Ident = field.ident().as_ref().unwrap();
 | 
				
			||||||
 | 
					                let ident_str = ident.to_string();
 | 
				
			||||||
 | 
					                let flipped = flip.is_some();
 | 
				
			||||||
 | 
					                quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    ::fayalite::bundle::BundleField {
 | 
				
			||||||
 | 
					                        name: ::fayalite::intern::Intern::intern(#ident_str),
 | 
				
			||||||
 | 
					                        flipped: #flipped,
 | 
				
			||||||
 | 
					                        ty: ::fayalite::ty::Type::canonical(&self.#ident),
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					        let fields_len = fields.named().into_iter().len();
 | 
				
			||||||
 | 
					        quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					            #[automatically_derived]
 | 
				
			||||||
 | 
					            impl #impl_generics ::fayalite::ty::Type for #mask_type_ident #type_generics
 | 
				
			||||||
 | 
					            #where_clause
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                type BaseType = ::fayalite::bundle::Bundle;
 | 
				
			||||||
 | 
					                type MaskType = #mask_type_ident #type_generics;
 | 
				
			||||||
 | 
					                type MatchVariant = #mask_type_match_variant_ident #type_generics;
 | 
				
			||||||
 | 
					                type MatchActiveScope = ();
 | 
				
			||||||
 | 
					                type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope<
 | 
				
			||||||
 | 
					                    <Self as ::fayalite::ty::Type>::MatchVariant,
 | 
				
			||||||
 | 
					                >;
 | 
				
			||||||
 | 
					                type MatchVariantsIter = ::fayalite::__std::iter::Once<
 | 
				
			||||||
 | 
					                    <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
 | 
				
			||||||
 | 
					                >;
 | 
				
			||||||
 | 
					                fn match_variants(
 | 
				
			||||||
 | 
					                    __this: ::fayalite::expr::Expr<Self>,
 | 
				
			||||||
 | 
					                    __module_builder: &mut ::fayalite::module::ModuleBuilder<
 | 
				
			||||||
 | 
					                        ::fayalite::module::NormalModule,
 | 
				
			||||||
 | 
					                    >,
 | 
				
			||||||
 | 
					                    __source_location: ::fayalite::source_location::SourceLocation,
 | 
				
			||||||
 | 
					                ) -> <Self as ::fayalite::ty::Type>::MatchVariantsIter {
 | 
				
			||||||
 | 
					                    let __retval = #mask_type_match_variant_ident {
 | 
				
			||||||
 | 
					                        #(#match_variant_body_fields)*
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    ::fayalite::__std::iter::once(::fayalite::ty::MatchVariantWithoutScope(__retval))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                fn mask_type(&self) -> <Self as ::fayalite::ty::Type>::MaskType {
 | 
				
			||||||
 | 
					                    *self
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                fn canonical(&self) -> ::fayalite::ty::CanonicalType {
 | 
				
			||||||
 | 
					                    ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(self)))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                #[track_caller]
 | 
				
			||||||
 | 
					                fn from_canonical(__canonical_type: ::fayalite::ty::CanonicalType) -> Self {
 | 
				
			||||||
 | 
					                    let ::fayalite::ty::CanonicalType::Bundle(__bundle) = __canonical_type else {
 | 
				
			||||||
 | 
					                        ::fayalite::__std::panic!("expected bundle");
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    let __fields = ::fayalite::bundle::BundleType::fields(&__bundle);
 | 
				
			||||||
 | 
					                    ::fayalite::__std::assert_eq!(__fields.len(), #fields_len, "bundle has wrong number of fields");
 | 
				
			||||||
 | 
					                    Self {
 | 
				
			||||||
 | 
					                        #(#from_canonical_body_fields)*
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                fn source_location() -> ::fayalite::source_location::SourceLocation {
 | 
				
			||||||
 | 
					                    ::fayalite::source_location::SourceLocation::caller()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            #[automatically_derived]
 | 
				
			||||||
 | 
					            impl #impl_generics ::fayalite::bundle::BundleType for #mask_type_ident #type_generics
 | 
				
			||||||
 | 
					            #where_clause
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                type Builder = #unfilled_mask_type_builder_ty;
 | 
				
			||||||
 | 
					                type FilledBuilder = #filled_mask_type_builder_ty;
 | 
				
			||||||
 | 
					                fn fields(&self) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> {
 | 
				
			||||||
 | 
					                    ::fayalite::intern::Intern::intern(&[#(#fields_body_fields)*][..])
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            #[automatically_derived]
 | 
				
			||||||
 | 
					            impl #impl_generics ::fayalite::ty::TypeWithDeref for #mask_type_ident #type_generics
 | 
				
			||||||
 | 
					            #where_clause
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                fn expr_deref(__this: &::fayalite::expr::Expr<Self>) -> &<Self as ::fayalite::ty::Type>::MatchVariant {
 | 
				
			||||||
 | 
					                    let __this = *__this;
 | 
				
			||||||
 | 
					                    let __retval = #mask_type_match_variant_ident {
 | 
				
			||||||
 | 
					                        #(#match_variant_body_fields)*
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    ::fayalite::intern::Interned::<_>::into_inner(::fayalite::intern::Intern::intern_sized(__retval))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            #[automatically_derived]
 | 
				
			||||||
 | 
					            impl #impl_generics ::fayalite::ty::Type for #target #type_generics
 | 
				
			||||||
 | 
					            #where_clause
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                type BaseType = ::fayalite::bundle::Bundle;
 | 
				
			||||||
 | 
					                type MaskType = #mask_type_ident #type_generics;
 | 
				
			||||||
 | 
					                type MatchVariant = #match_variant_ident #type_generics;
 | 
				
			||||||
 | 
					                type MatchActiveScope = ();
 | 
				
			||||||
 | 
					                type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope<
 | 
				
			||||||
 | 
					                    <Self as ::fayalite::ty::Type>::MatchVariant,
 | 
				
			||||||
 | 
					                >;
 | 
				
			||||||
 | 
					                type MatchVariantsIter = ::fayalite::__std::iter::Once<
 | 
				
			||||||
 | 
					                    <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
 | 
				
			||||||
 | 
					                >;
 | 
				
			||||||
 | 
					                fn match_variants(
 | 
				
			||||||
 | 
					                    __this: ::fayalite::expr::Expr<Self>,
 | 
				
			||||||
 | 
					                    __module_builder: &mut ::fayalite::module::ModuleBuilder<
 | 
				
			||||||
 | 
					                        ::fayalite::module::NormalModule,
 | 
				
			||||||
 | 
					                    >,
 | 
				
			||||||
 | 
					                    __source_location: ::fayalite::source_location::SourceLocation,
 | 
				
			||||||
 | 
					                ) -> <Self as ::fayalite::ty::Type>::MatchVariantsIter {
 | 
				
			||||||
 | 
					                    let __retval = #match_variant_ident {
 | 
				
			||||||
 | 
					                        #(#match_variant_body_fields)*
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    ::fayalite::__std::iter::once(::fayalite::ty::MatchVariantWithoutScope(__retval))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                fn mask_type(&self) -> <Self as ::fayalite::ty::Type>::MaskType {
 | 
				
			||||||
 | 
					                    #mask_type_ident {
 | 
				
			||||||
 | 
					                        #(#mask_type_body_fields)*
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                fn canonical(&self) -> ::fayalite::ty::CanonicalType {
 | 
				
			||||||
 | 
					                    ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(self)))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                #[track_caller]
 | 
				
			||||||
 | 
					                fn from_canonical(__canonical_type: ::fayalite::ty::CanonicalType) -> Self {
 | 
				
			||||||
 | 
					                    let ::fayalite::ty::CanonicalType::Bundle(__bundle) = __canonical_type else {
 | 
				
			||||||
 | 
					                        ::fayalite::__std::panic!("expected bundle");
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    let __fields = ::fayalite::bundle::BundleType::fields(&__bundle);
 | 
				
			||||||
 | 
					                    ::fayalite::__std::assert_eq!(__fields.len(), #fields_len, "bundle has wrong number of fields");
 | 
				
			||||||
 | 
					                    Self {
 | 
				
			||||||
 | 
					                        #(#from_canonical_body_fields)*
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                fn source_location() -> ::fayalite::source_location::SourceLocation {
 | 
				
			||||||
 | 
					                    ::fayalite::source_location::SourceLocation::caller()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            #[automatically_derived]
 | 
				
			||||||
 | 
					            impl #impl_generics ::fayalite::bundle::BundleType for #target #type_generics
 | 
				
			||||||
 | 
					            #where_clause
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                type Builder = #unfilled_builder_ty;
 | 
				
			||||||
 | 
					                type FilledBuilder = #filled_builder_ty;
 | 
				
			||||||
 | 
					                fn fields(&self) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> {
 | 
				
			||||||
 | 
					                    ::fayalite::intern::Intern::intern(&[#(#fields_body_fields)*][..])
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            #[automatically_derived]
 | 
				
			||||||
 | 
					            impl #impl_generics ::fayalite::ty::TypeWithDeref for #target #type_generics
 | 
				
			||||||
 | 
					            #where_clause
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                fn expr_deref(__this: &::fayalite::expr::Expr<Self>) -> &<Self as ::fayalite::ty::Type>::MatchVariant {
 | 
				
			||||||
 | 
					                    let __this = *__this;
 | 
				
			||||||
 | 
					                    let __retval = #match_variant_ident {
 | 
				
			||||||
 | 
					                        #(#match_variant_body_fields)*
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    ::fayalite::intern::Interned::<_>::into_inner(::fayalite::intern::Intern::intern_sized(__retval))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_tokens(tokens);
 | 
				
			||||||
 | 
					        if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) {
 | 
				
			||||||
 | 
					            let static_generics = generics.clone().for_static_type();
 | 
				
			||||||
 | 
					            let (static_impl_generics, static_type_generics, static_where_clause) =
 | 
				
			||||||
 | 
					                static_generics.split_for_impl();
 | 
				
			||||||
 | 
					            let static_type_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
 | 
				
			||||||
 | 
					                let ident: &Ident = field.ident().as_ref().unwrap();
 | 
				
			||||||
 | 
					                let ty = field.ty();
 | 
				
			||||||
 | 
					                quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    #ident: <#ty as ::fayalite::ty::StaticType>::TYPE,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            let static_mask_type_body_fields =
 | 
				
			||||||
 | 
					                Vec::from_iter(fields.named().into_iter().map(|field| {
 | 
				
			||||||
 | 
					                    let ident: &Ident = field.ident().as_ref().unwrap();
 | 
				
			||||||
 | 
					                    let ty = field.ty();
 | 
				
			||||||
 | 
					                    quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                        #ident: <#ty as ::fayalite::ty::StaticType>::MASK_TYPE,
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
 | 
					            let type_properties = format_ident!("__type_properties", span = ident.span());
 | 
				
			||||||
 | 
					            let type_properties_fields = Vec::from_iter(fields.named().into_iter().zip(field_flips).map(|(field, field_flip)| {
 | 
				
			||||||
 | 
					                let ident: &Ident = field.ident().as_ref().unwrap();
 | 
				
			||||||
 | 
					                let flipped = field_flip.is_some();
 | 
				
			||||||
 | 
					                let ty = field.ty();
 | 
				
			||||||
 | 
					                quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    let #type_properties = #type_properties.field(#flipped, <#ty as ::fayalite::ty::StaticType>::TYPE_PROPERTIES);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            let type_properties_mask_fields = Vec::from_iter(fields.named().into_iter().zip(field_flips).map(|(field, field_flip)| {
 | 
				
			||||||
 | 
					                let ident: &Ident = field.ident().as_ref().unwrap();
 | 
				
			||||||
 | 
					                let flipped = field_flip.is_some();
 | 
				
			||||||
 | 
					                let ty = field.ty();
 | 
				
			||||||
 | 
					                quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    let #type_properties = #type_properties.field(#flipped, <#ty as ::fayalite::ty::StaticType>::MASK_TYPE_PROPERTIES);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                #[automatically_derived]
 | 
				
			||||||
 | 
					                impl #static_impl_generics ::fayalite::ty::StaticType for #mask_type_ident #static_type_generics
 | 
				
			||||||
 | 
					                #static_where_clause
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    const TYPE: Self = Self {
 | 
				
			||||||
 | 
					                        #(#static_mask_type_body_fields)*
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    const MASK_TYPE: <Self as ::fayalite::ty::Type>::MaskType = Self {
 | 
				
			||||||
 | 
					                        #(#static_mask_type_body_fields)*
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    const TYPE_PROPERTIES: ::fayalite::ty::TypeProperties = {
 | 
				
			||||||
 | 
					                        let #type_properties = ::fayalite::bundle::BundleTypePropertiesBuilder::new();
 | 
				
			||||||
 | 
					                        #(#type_properties_mask_fields)*
 | 
				
			||||||
 | 
					                        #type_properties.finish()
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    const MASK_TYPE_PROPERTIES: ::fayalite::ty::TypeProperties = {
 | 
				
			||||||
 | 
					                        let #type_properties = ::fayalite::bundle::BundleTypePropertiesBuilder::new();
 | 
				
			||||||
 | 
					                        #(#type_properties_mask_fields)*
 | 
				
			||||||
 | 
					                        #type_properties.finish()
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                #[automatically_derived]
 | 
				
			||||||
 | 
					                impl #static_impl_generics ::fayalite::ty::StaticType for #target #static_type_generics
 | 
				
			||||||
 | 
					                #static_where_clause
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    const TYPE: Self = Self {
 | 
				
			||||||
 | 
					                        #(#static_type_body_fields)*
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    const MASK_TYPE: <Self as ::fayalite::ty::Type>::MaskType = #mask_type_ident {
 | 
				
			||||||
 | 
					                        #(#static_mask_type_body_fields)*
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    const TYPE_PROPERTIES: ::fayalite::ty::TypeProperties = {
 | 
				
			||||||
 | 
					                        let #type_properties = ::fayalite::bundle::BundleTypePropertiesBuilder::new();
 | 
				
			||||||
 | 
					                        #(#type_properties_fields)*
 | 
				
			||||||
 | 
					                        #type_properties.finish()
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    const MASK_TYPE_PROPERTIES: ::fayalite::ty::TypeProperties = {
 | 
				
			||||||
 | 
					                        let #type_properties = ::fayalite::bundle::BundleTypePropertiesBuilder::new();
 | 
				
			||||||
 | 
					                        #(#type_properties_mask_fields)*
 | 
				
			||||||
 | 
					                        #type_properties.finish()
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .to_tokens(tokens);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub(crate) fn hdl_bundle(item: ItemStruct) -> syn::Result<TokenStream> {
 | 
				
			||||||
 | 
					    let item = ParsedBundle::parse(item)?;
 | 
				
			||||||
 | 
					    let outline_generated = item.options.body.outline_generated;
 | 
				
			||||||
 | 
					    let mut contents = item.to_token_stream();
 | 
				
			||||||
 | 
					    if outline_generated.is_some() {
 | 
				
			||||||
 | 
					        contents = crate::outline_generated(contents, "hdl-bundle-");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Ok(contents)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										657
									
								
								crates/fayalite-proc-macros-impl/src/hdl_enum.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										657
									
								
								crates/fayalite-proc-macros-impl/src/hdl_enum.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,657 @@
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    hdl_type_common::{
 | 
				
			||||||
 | 
					        common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics,
 | 
				
			||||||
 | 
					        ParsedType, SplitForImpl, TypesParser, WrappedInConst,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    Errors, HdlAttr, PairsIterExt,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use proc_macro2::TokenStream;
 | 
				
			||||||
 | 
					use quote::{format_ident, quote_spanned, ToTokens};
 | 
				
			||||||
 | 
					use syn::{
 | 
				
			||||||
 | 
					    parse_quote_spanned,
 | 
				
			||||||
 | 
					    punctuated::{Pair, Punctuated},
 | 
				
			||||||
 | 
					    token::{Brace, Paren},
 | 
				
			||||||
 | 
					    Attribute, Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident,
 | 
				
			||||||
 | 
					    ItemEnum, ItemStruct, Token, Type, Variant, Visibility,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					crate::options! {
 | 
				
			||||||
 | 
					    #[options = VariantOptions]
 | 
				
			||||||
 | 
					    pub(crate) enum VariantOption {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					crate::options! {
 | 
				
			||||||
 | 
					    #[options = FieldOptions]
 | 
				
			||||||
 | 
					    pub(crate) enum FieldOption {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
 | 
					pub(crate) struct ParsedVariantField {
 | 
				
			||||||
 | 
					    pub(crate) paren_token: Paren,
 | 
				
			||||||
 | 
					    pub(crate) attrs: Vec<Attribute>,
 | 
				
			||||||
 | 
					    pub(crate) options: HdlAttr<FieldOptions>,
 | 
				
			||||||
 | 
					    pub(crate) ty: MaybeParsed<ParsedType, Type>,
 | 
				
			||||||
 | 
					    pub(crate) comma_token: Option<Token![,]>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
 | 
					pub(crate) struct ParsedVariant {
 | 
				
			||||||
 | 
					    pub(crate) attrs: Vec<Attribute>,
 | 
				
			||||||
 | 
					    pub(crate) options: HdlAttr<VariantOptions>,
 | 
				
			||||||
 | 
					    pub(crate) ident: Ident,
 | 
				
			||||||
 | 
					    pub(crate) field: Option<ParsedVariantField>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ParsedVariant {
 | 
				
			||||||
 | 
					    fn parse(
 | 
				
			||||||
 | 
					        errors: &mut Errors,
 | 
				
			||||||
 | 
					        variant: Variant,
 | 
				
			||||||
 | 
					        generics: &MaybeParsed<ParsedGenerics, Generics>,
 | 
				
			||||||
 | 
					    ) -> Self {
 | 
				
			||||||
 | 
					        let Variant {
 | 
				
			||||||
 | 
					            mut attrs,
 | 
				
			||||||
 | 
					            ident,
 | 
				
			||||||
 | 
					            fields,
 | 
				
			||||||
 | 
					            discriminant,
 | 
				
			||||||
 | 
					        } = variant;
 | 
				
			||||||
 | 
					        let options = errors
 | 
				
			||||||
 | 
					            .unwrap_or_default(HdlAttr::parse_and_take_attr(&mut attrs))
 | 
				
			||||||
 | 
					            .unwrap_or_default();
 | 
				
			||||||
 | 
					        let field = match fields {
 | 
				
			||||||
 | 
					            Fields::Unnamed(FieldsUnnamed {
 | 
				
			||||||
 | 
					                paren_token,
 | 
				
			||||||
 | 
					                unnamed,
 | 
				
			||||||
 | 
					            }) if unnamed.len() == 1 => {
 | 
				
			||||||
 | 
					                let (field, comma_token) = unnamed.into_pairs().next().unwrap().into_tuple();
 | 
				
			||||||
 | 
					                let Field {
 | 
				
			||||||
 | 
					                    mut attrs,
 | 
				
			||||||
 | 
					                    vis,
 | 
				
			||||||
 | 
					                    mutability,
 | 
				
			||||||
 | 
					                    ident: _,
 | 
				
			||||||
 | 
					                    colon_token: _,
 | 
				
			||||||
 | 
					                    ty,
 | 
				
			||||||
 | 
					                } = field;
 | 
				
			||||||
 | 
					                let options = errors
 | 
				
			||||||
 | 
					                    .unwrap_or_default(HdlAttr::parse_and_take_attr(&mut attrs))
 | 
				
			||||||
 | 
					                    .unwrap_or_default();
 | 
				
			||||||
 | 
					                if !matches!(vis, Visibility::Inherited) {
 | 
				
			||||||
 | 
					                    errors.error(
 | 
				
			||||||
 | 
					                        &vis,
 | 
				
			||||||
 | 
					                        "enum variant fields must not have a visibility specifier",
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if !matches!(mutability, FieldMutability::None) {
 | 
				
			||||||
 | 
					                    // FIXME: use mutability as the spanned tokens,
 | 
				
			||||||
 | 
					                    // blocked on https://github.com/dtolnay/syn/issues/1717
 | 
				
			||||||
 | 
					                    errors.error(&ty, "field mutability is not supported");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Some(ParsedVariantField {
 | 
				
			||||||
 | 
					                    paren_token,
 | 
				
			||||||
 | 
					                    attrs,
 | 
				
			||||||
 | 
					                    options,
 | 
				
			||||||
 | 
					                    ty: TypesParser::maybe_run(generics.as_ref(), ty, errors),
 | 
				
			||||||
 | 
					                    comma_token,
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Fields::Unit => None,
 | 
				
			||||||
 | 
					            Fields::Unnamed(fields) if fields.unnamed.is_empty() => None,
 | 
				
			||||||
 | 
					            Fields::Named(fields) if fields.named.is_empty() => None,
 | 
				
			||||||
 | 
					            Fields::Unnamed(_) | Fields::Named(_) => {
 | 
				
			||||||
 | 
					                errors.error(
 | 
				
			||||||
 | 
					                    fields,
 | 
				
			||||||
 | 
					                    "enum variant must either have no fields or a single parenthesized field",
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                None
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        if let Some((eq, _)) = discriminant {
 | 
				
			||||||
 | 
					            errors.error(eq, "custom enum discriminants are not allowed");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            attrs,
 | 
				
			||||||
 | 
					            options,
 | 
				
			||||||
 | 
					            ident,
 | 
				
			||||||
 | 
					            field,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
 | 
					pub(crate) struct ParsedEnum {
 | 
				
			||||||
 | 
					    pub(crate) attrs: Vec<Attribute>,
 | 
				
			||||||
 | 
					    pub(crate) options: HdlAttr<ItemOptions>,
 | 
				
			||||||
 | 
					    pub(crate) vis: Visibility,
 | 
				
			||||||
 | 
					    pub(crate) enum_token: Token![enum],
 | 
				
			||||||
 | 
					    pub(crate) ident: Ident,
 | 
				
			||||||
 | 
					    pub(crate) generics: MaybeParsed<ParsedGenerics, Generics>,
 | 
				
			||||||
 | 
					    pub(crate) brace_token: Brace,
 | 
				
			||||||
 | 
					    pub(crate) variants: Punctuated<ParsedVariant, Token![,]>,
 | 
				
			||||||
 | 
					    pub(crate) match_variant_ident: Ident,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ParsedEnum {
 | 
				
			||||||
 | 
					    fn parse(item: ItemEnum) -> syn::Result<Self> {
 | 
				
			||||||
 | 
					        let ItemEnum {
 | 
				
			||||||
 | 
					            mut attrs,
 | 
				
			||||||
 | 
					            vis,
 | 
				
			||||||
 | 
					            enum_token,
 | 
				
			||||||
 | 
					            ident,
 | 
				
			||||||
 | 
					            mut generics,
 | 
				
			||||||
 | 
					            brace_token,
 | 
				
			||||||
 | 
					            variants,
 | 
				
			||||||
 | 
					        } = item;
 | 
				
			||||||
 | 
					        let mut errors = Errors::new();
 | 
				
			||||||
 | 
					        let mut options = errors
 | 
				
			||||||
 | 
					            .unwrap_or_default(HdlAttr::<ItemOptions>::parse_and_take_attr(&mut attrs))
 | 
				
			||||||
 | 
					            .unwrap_or_default();
 | 
				
			||||||
 | 
					        errors.ok(options.body.validate());
 | 
				
			||||||
 | 
					        let ItemOptions {
 | 
				
			||||||
 | 
					            outline_generated: _,
 | 
				
			||||||
 | 
					            connect_inexact: _,
 | 
				
			||||||
 | 
					            target: _,
 | 
				
			||||||
 | 
					            custom_bounds,
 | 
				
			||||||
 | 
					            no_static: _,
 | 
				
			||||||
 | 
					        } = options.body;
 | 
				
			||||||
 | 
					        attrs.retain(|attr| {
 | 
				
			||||||
 | 
					            if attr.path().is_ident("repr") {
 | 
				
			||||||
 | 
					                errors.error(attr, "#[repr] is not supported on #[hdl] enums");
 | 
				
			||||||
 | 
					                false
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                true
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        let generics = if custom_bounds.is_some() {
 | 
				
			||||||
 | 
					            MaybeParsed::Unrecognized(generics)
 | 
				
			||||||
 | 
					        } else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) {
 | 
				
			||||||
 | 
					            MaybeParsed::Parsed(generics)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            MaybeParsed::Unrecognized(generics)
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let variants = Punctuated::from_iter(
 | 
				
			||||||
 | 
					            variants
 | 
				
			||||||
 | 
					                .into_pairs()
 | 
				
			||||||
 | 
					                .map_pair_value(|v| ParsedVariant::parse(&mut errors, v, &generics)),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        errors.finish()?;
 | 
				
			||||||
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            attrs,
 | 
				
			||||||
 | 
					            options,
 | 
				
			||||||
 | 
					            vis,
 | 
				
			||||||
 | 
					            enum_token,
 | 
				
			||||||
 | 
					            generics,
 | 
				
			||||||
 | 
					            brace_token,
 | 
				
			||||||
 | 
					            variants,
 | 
				
			||||||
 | 
					            match_variant_ident: format_ident!("__{}__MatchVariant", ident),
 | 
				
			||||||
 | 
					            ident,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ToTokens for ParsedEnum {
 | 
				
			||||||
 | 
					    fn to_tokens(&self, tokens: &mut TokenStream) {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            attrs,
 | 
				
			||||||
 | 
					            options,
 | 
				
			||||||
 | 
					            vis,
 | 
				
			||||||
 | 
					            enum_token,
 | 
				
			||||||
 | 
					            ident,
 | 
				
			||||||
 | 
					            generics,
 | 
				
			||||||
 | 
					            brace_token,
 | 
				
			||||||
 | 
					            variants,
 | 
				
			||||||
 | 
					            match_variant_ident,
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					        let ItemOptions {
 | 
				
			||||||
 | 
					            outline_generated: _,
 | 
				
			||||||
 | 
					            connect_inexact,
 | 
				
			||||||
 | 
					            target,
 | 
				
			||||||
 | 
					            custom_bounds: _,
 | 
				
			||||||
 | 
					            no_static,
 | 
				
			||||||
 | 
					        } = &options.body;
 | 
				
			||||||
 | 
					        let target = get_target(target, ident);
 | 
				
			||||||
 | 
					        let mut struct_attrs = attrs.clone();
 | 
				
			||||||
 | 
					        struct_attrs.push(common_derives(ident.span()));
 | 
				
			||||||
 | 
					        struct_attrs.push(parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					            #[allow(non_snake_case)]
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        let struct_fields = Punctuated::from_iter(variants.pairs().map_pair_value_ref(
 | 
				
			||||||
 | 
					            |ParsedVariant {
 | 
				
			||||||
 | 
					                 attrs: _,
 | 
				
			||||||
 | 
					                 options,
 | 
				
			||||||
 | 
					                 ident,
 | 
				
			||||||
 | 
					                 field,
 | 
				
			||||||
 | 
					             }| {
 | 
				
			||||||
 | 
					                let VariantOptions {} = options.body;
 | 
				
			||||||
 | 
					                let colon_token;
 | 
				
			||||||
 | 
					                let ty = if let Some(ParsedVariantField {
 | 
				
			||||||
 | 
					                    paren_token,
 | 
				
			||||||
 | 
					                    attrs: _,
 | 
				
			||||||
 | 
					                    options,
 | 
				
			||||||
 | 
					                    ty,
 | 
				
			||||||
 | 
					                    comma_token: _,
 | 
				
			||||||
 | 
					                }) = field
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    let FieldOptions {} = options.body;
 | 
				
			||||||
 | 
					                    colon_token = Token);
 | 
				
			||||||
 | 
					                    ty.clone().into()
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    colon_token = Token);
 | 
				
			||||||
 | 
					                    parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                        ()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                Field {
 | 
				
			||||||
 | 
					                    attrs: vec![],
 | 
				
			||||||
 | 
					                    vis: vis.clone(),
 | 
				
			||||||
 | 
					                    mutability: FieldMutability::None,
 | 
				
			||||||
 | 
					                    ident: Some(ident.clone()),
 | 
				
			||||||
 | 
					                    colon_token: Some(colon_token),
 | 
				
			||||||
 | 
					                    ty,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					        ItemStruct {
 | 
				
			||||||
 | 
					            attrs: struct_attrs,
 | 
				
			||||||
 | 
					            vis: vis.clone(),
 | 
				
			||||||
 | 
					            struct_token: Token,
 | 
				
			||||||
 | 
					            ident: ident.clone(),
 | 
				
			||||||
 | 
					            generics: generics.into(),
 | 
				
			||||||
 | 
					            fields: if struct_fields.is_empty() {
 | 
				
			||||||
 | 
					                Fields::Unit
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                Fields::Named(FieldsNamed {
 | 
				
			||||||
 | 
					                    brace_token: *brace_token,
 | 
				
			||||||
 | 
					                    named: struct_fields,
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            semi_token: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_tokens(tokens);
 | 
				
			||||||
 | 
					        let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
 | 
				
			||||||
 | 
					        if let MaybeParsed::Parsed(generics) = generics {
 | 
				
			||||||
 | 
					            generics.make_runtime_generics(tokens, vis, ident, &target, |context| {
 | 
				
			||||||
 | 
					                let fields: Vec<_> = variants
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .map(|ParsedVariant { ident, field, .. }| {
 | 
				
			||||||
 | 
					                        if let Some(ParsedVariantField {
 | 
				
			||||||
 | 
					                            ty: MaybeParsed::Parsed(ty),
 | 
				
			||||||
 | 
					                            ..
 | 
				
			||||||
 | 
					                        }) = field
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            let expr = ty.make_hdl_type_expr(context);
 | 
				
			||||||
 | 
					                            quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                                #ident: #expr,
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                                #ident: (),
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .collect();
 | 
				
			||||||
 | 
					                parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    #target {
 | 
				
			||||||
 | 
					                        #(#fields)*
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span());
 | 
				
			||||||
 | 
					        let tokens = wrapped_in_const.inner();
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span());
 | 
				
			||||||
 | 
					            let tokens = wrapped_in_const.inner();
 | 
				
			||||||
 | 
					            let mut enum_attrs = attrs.clone();
 | 
				
			||||||
 | 
					            enum_attrs.push(parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                #[allow(dead_code)]
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            ItemEnum {
 | 
				
			||||||
 | 
					                attrs: enum_attrs,
 | 
				
			||||||
 | 
					                vis: vis.clone(),
 | 
				
			||||||
 | 
					                enum_token: *enum_token,
 | 
				
			||||||
 | 
					                ident: ident.clone(),
 | 
				
			||||||
 | 
					                generics: generics.into(),
 | 
				
			||||||
 | 
					                brace_token: *brace_token,
 | 
				
			||||||
 | 
					                variants: Punctuated::from_iter(variants.pairs().map_pair_value_ref(
 | 
				
			||||||
 | 
					                    |ParsedVariant {
 | 
				
			||||||
 | 
					                         attrs,
 | 
				
			||||||
 | 
					                         options: _,
 | 
				
			||||||
 | 
					                         ident,
 | 
				
			||||||
 | 
					                         field,
 | 
				
			||||||
 | 
					                     }| Variant {
 | 
				
			||||||
 | 
					                        attrs: attrs.clone(),
 | 
				
			||||||
 | 
					                        ident: ident.clone(),
 | 
				
			||||||
 | 
					                        fields: match field {
 | 
				
			||||||
 | 
					                            Some(ParsedVariantField {
 | 
				
			||||||
 | 
					                                paren_token,
 | 
				
			||||||
 | 
					                                attrs,
 | 
				
			||||||
 | 
					                                options: _,
 | 
				
			||||||
 | 
					                                ty,
 | 
				
			||||||
 | 
					                                comma_token,
 | 
				
			||||||
 | 
					                            }) => Fields::Unnamed(FieldsUnnamed {
 | 
				
			||||||
 | 
					                                paren_token: *paren_token,
 | 
				
			||||||
 | 
					                                unnamed: Punctuated::from_iter([Pair::new(
 | 
				
			||||||
 | 
					                                    Field {
 | 
				
			||||||
 | 
					                                        attrs: attrs.clone(),
 | 
				
			||||||
 | 
					                                        vis: Visibility::Inherited,
 | 
				
			||||||
 | 
					                                        mutability: FieldMutability::None,
 | 
				
			||||||
 | 
					                                        ident: None,
 | 
				
			||||||
 | 
					                                        colon_token: None,
 | 
				
			||||||
 | 
					                                        ty: ty.clone().into(),
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                    *comma_token,
 | 
				
			||||||
 | 
					                                )]),
 | 
				
			||||||
 | 
					                            }),
 | 
				
			||||||
 | 
					                            None => Fields::Unit,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        discriminant: None,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                )),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .to_tokens(tokens);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let mut enum_attrs = attrs.clone();
 | 
				
			||||||
 | 
					        enum_attrs.push(parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					            #[allow(dead_code, non_camel_case_types)]
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        ItemEnum {
 | 
				
			||||||
 | 
					            attrs: enum_attrs,
 | 
				
			||||||
 | 
					            vis: vis.clone(),
 | 
				
			||||||
 | 
					            enum_token: *enum_token,
 | 
				
			||||||
 | 
					            ident: match_variant_ident.clone(),
 | 
				
			||||||
 | 
					            generics: generics.into(),
 | 
				
			||||||
 | 
					            brace_token: *brace_token,
 | 
				
			||||||
 | 
					            variants: Punctuated::from_iter(variants.pairs().map_pair_value_ref(
 | 
				
			||||||
 | 
					                |ParsedVariant {
 | 
				
			||||||
 | 
					                     attrs,
 | 
				
			||||||
 | 
					                     options: _,
 | 
				
			||||||
 | 
					                     ident,
 | 
				
			||||||
 | 
					                     field,
 | 
				
			||||||
 | 
					                 }| Variant {
 | 
				
			||||||
 | 
					                    attrs: attrs.clone(),
 | 
				
			||||||
 | 
					                    ident: ident.clone(),
 | 
				
			||||||
 | 
					                    fields: match field {
 | 
				
			||||||
 | 
					                        Some(ParsedVariantField {
 | 
				
			||||||
 | 
					                            paren_token,
 | 
				
			||||||
 | 
					                            attrs,
 | 
				
			||||||
 | 
					                            options: _,
 | 
				
			||||||
 | 
					                            ty,
 | 
				
			||||||
 | 
					                            comma_token,
 | 
				
			||||||
 | 
					                        }) => Fields::Unnamed(FieldsUnnamed {
 | 
				
			||||||
 | 
					                            paren_token: *paren_token,
 | 
				
			||||||
 | 
					                            unnamed: Punctuated::from_iter([Pair::new(
 | 
				
			||||||
 | 
					                                Field {
 | 
				
			||||||
 | 
					                                    attrs: attrs.clone(),
 | 
				
			||||||
 | 
					                                    vis: Visibility::Inherited,
 | 
				
			||||||
 | 
					                                    mutability: FieldMutability::None,
 | 
				
			||||||
 | 
					                                    ident: None,
 | 
				
			||||||
 | 
					                                    colon_token: None,
 | 
				
			||||||
 | 
					                                    ty: parse_quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                                        ::fayalite::expr::Expr<#ty>
 | 
				
			||||||
 | 
					                                    },
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                *comma_token,
 | 
				
			||||||
 | 
					                            )]),
 | 
				
			||||||
 | 
					                        }),
 | 
				
			||||||
 | 
					                        None => Fields::Unit,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    discriminant: None,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            )),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_tokens(tokens);
 | 
				
			||||||
 | 
					        for (index, ParsedVariant { ident, field, .. }) in variants.iter().enumerate() {
 | 
				
			||||||
 | 
					            if let Some(ParsedVariantField { ty, .. }) = field {
 | 
				
			||||||
 | 
					                quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    #[automatically_derived]
 | 
				
			||||||
 | 
					                    impl #impl_generics #target #type_generics
 | 
				
			||||||
 | 
					                    #where_clause
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        #[allow(non_snake_case, dead_code)]
 | 
				
			||||||
 | 
					                        #vis fn #ident<__V: ::fayalite::expr::ToExpr<Type = #ty>>(
 | 
				
			||||||
 | 
					                            self,
 | 
				
			||||||
 | 
					                            v: __V,
 | 
				
			||||||
 | 
					                        ) -> ::fayalite::expr::Expr<Self> {
 | 
				
			||||||
 | 
					                            ::fayalite::expr::ToExpr::to_expr(
 | 
				
			||||||
 | 
					                                &::fayalite::expr::ops::EnumLiteral::new_by_index(
 | 
				
			||||||
 | 
					                                    self,
 | 
				
			||||||
 | 
					                                    #index,
 | 
				
			||||||
 | 
					                                    ::fayalite::__std::option::Option::Some(
 | 
				
			||||||
 | 
					                                        ::fayalite::expr::Expr::canonical(
 | 
				
			||||||
 | 
					                                            ::fayalite::expr::ToExpr::to_expr(&v),
 | 
				
			||||||
 | 
					                                        ),
 | 
				
			||||||
 | 
					                                    ),
 | 
				
			||||||
 | 
					                                ),
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    #[automatically_derived]
 | 
				
			||||||
 | 
					                    impl #impl_generics #target #type_generics
 | 
				
			||||||
 | 
					                    #where_clause
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        #[allow(non_snake_case, dead_code)]
 | 
				
			||||||
 | 
					                        #vis fn #ident(self) -> ::fayalite::expr::Expr<Self> {
 | 
				
			||||||
 | 
					                            ::fayalite::expr::ToExpr::to_expr(
 | 
				
			||||||
 | 
					                                &::fayalite::expr::ops::EnumLiteral::new_by_index(
 | 
				
			||||||
 | 
					                                    self,
 | 
				
			||||||
 | 
					                                    #index,
 | 
				
			||||||
 | 
					                                    ::fayalite::__std::option::Option::None,
 | 
				
			||||||
 | 
					                                ),
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .to_tokens(tokens);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let from_canonical_body_fields = Vec::from_iter(variants.iter().enumerate().map(
 | 
				
			||||||
 | 
					            |(index, ParsedVariant { ident, field, .. })| {
 | 
				
			||||||
 | 
					                let ident_str = ident.to_string();
 | 
				
			||||||
 | 
					                let val = if field.is_some() {
 | 
				
			||||||
 | 
					                    let missing_value_msg = format!("expected variant {ident} to have a field");
 | 
				
			||||||
 | 
					                    quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                        ::fayalite::ty::Type::from_canonical(ty.expect(#missing_value_msg))
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                        ::fayalite::__std::assert!(ty.is_none());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                    #ident: {
 | 
				
			||||||
 | 
					                        let ::fayalite::enum_::EnumVariant {
 | 
				
			||||||
 | 
					                            name,
 | 
				
			||||||
 | 
					                            ty,
 | 
				
			||||||
 | 
					                        } = variants[#index];
 | 
				
			||||||
 | 
					                        ::fayalite::__std::assert_eq!(&*name, #ident_str);
 | 
				
			||||||
 | 
					                        #val
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					        let match_active_scope_match_arms = Vec::from_iter(variants.iter().enumerate().map(
 | 
				
			||||||
 | 
					            |(index, ParsedVariant { ident, field, .. })| {
 | 
				
			||||||
 | 
					                if field.is_some() {
 | 
				
			||||||
 | 
					                    quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                        #index => #match_variant_ident::#ident(
 | 
				
			||||||
 | 
					                            ::fayalite::expr::ToExpr::to_expr(
 | 
				
			||||||
 | 
					                                &::fayalite::expr::ops::VariantAccess::new_by_index(
 | 
				
			||||||
 | 
					                                    variant_access.base(),
 | 
				
			||||||
 | 
					                                    variant_access.variant_index(),
 | 
				
			||||||
 | 
					                                ),
 | 
				
			||||||
 | 
					                            ),
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                        #index => #match_variant_ident::#ident,
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					        let variants_body_variants = Vec::from_iter(variants.iter().map(
 | 
				
			||||||
 | 
					            |ParsedVariant {
 | 
				
			||||||
 | 
					                 attrs: _,
 | 
				
			||||||
 | 
					                 options,
 | 
				
			||||||
 | 
					                 ident,
 | 
				
			||||||
 | 
					                 field,
 | 
				
			||||||
 | 
					             }| {
 | 
				
			||||||
 | 
					                let VariantOptions {} = options.body;
 | 
				
			||||||
 | 
					                let ident_str = ident.to_string();
 | 
				
			||||||
 | 
					                match field {
 | 
				
			||||||
 | 
					                    Some(ParsedVariantField { options, .. }) => {
 | 
				
			||||||
 | 
					                        let FieldOptions {} = options.body;
 | 
				
			||||||
 | 
					                        quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                            ::fayalite::enum_::EnumVariant {
 | 
				
			||||||
 | 
					                                name: ::fayalite::intern::Intern::intern(#ident_str),
 | 
				
			||||||
 | 
					                                ty: ::fayalite::__std::option::Option::Some(
 | 
				
			||||||
 | 
					                                    ::fayalite::ty::Type::canonical(&self.#ident),
 | 
				
			||||||
 | 
					                                ),
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    None => quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                        ::fayalite::enum_::EnumVariant {
 | 
				
			||||||
 | 
					                            name: ::fayalite::intern::Intern::intern(#ident_str),
 | 
				
			||||||
 | 
					                            ty: ::fayalite::__std::option::Option::None,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					        let variants_len = variants.len();
 | 
				
			||||||
 | 
					        quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					            #[automatically_derived]
 | 
				
			||||||
 | 
					            impl #impl_generics ::fayalite::ty::Type for #target #type_generics
 | 
				
			||||||
 | 
					            #where_clause
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                type BaseType = ::fayalite::enum_::Enum;
 | 
				
			||||||
 | 
					                type MaskType = ::fayalite::int::Bool;
 | 
				
			||||||
 | 
					                type MatchVariant = #match_variant_ident #type_generics;
 | 
				
			||||||
 | 
					                type MatchActiveScope = ::fayalite::module::Scope;
 | 
				
			||||||
 | 
					                type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
 | 
				
			||||||
 | 
					                type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                fn match_variants(
 | 
				
			||||||
 | 
					                    this: ::fayalite::expr::Expr<Self>,
 | 
				
			||||||
 | 
					                    module_builder: &mut ::fayalite::module::ModuleBuilder<::fayalite::module::NormalModule>,
 | 
				
			||||||
 | 
					                    source_location: ::fayalite::source_location::SourceLocation,
 | 
				
			||||||
 | 
					                ) -> <Self as ::fayalite::ty::Type>::MatchVariantsIter {
 | 
				
			||||||
 | 
					                    module_builder.enum_match_variants_helper(this, source_location)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                fn mask_type(&self) -> <Self as ::fayalite::ty::Type>::MaskType {
 | 
				
			||||||
 | 
					                    ::fayalite::int::Bool
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                fn canonical(&self) -> ::fayalite::ty::CanonicalType {
 | 
				
			||||||
 | 
					                    ::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(self)))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                #[track_caller]
 | 
				
			||||||
 | 
					                #[allow(non_snake_case)]
 | 
				
			||||||
 | 
					                fn from_canonical(canonical_type: ::fayalite::ty::CanonicalType) -> Self {
 | 
				
			||||||
 | 
					                    let ::fayalite::ty::CanonicalType::Enum(enum_) = canonical_type else {
 | 
				
			||||||
 | 
					                        ::fayalite::__std::panic!("expected enum");
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    let variants = ::fayalite::enum_::EnumType::variants(&enum_);
 | 
				
			||||||
 | 
					                    ::fayalite::__std::assert_eq!(variants.len(), #variants_len, "enum has wrong number of variants");
 | 
				
			||||||
 | 
					                    Self {
 | 
				
			||||||
 | 
					                        #(#from_canonical_body_fields)*
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                fn source_location() -> ::fayalite::source_location::SourceLocation {
 | 
				
			||||||
 | 
					                    ::fayalite::source_location::SourceLocation::caller()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            #[automatically_derived]
 | 
				
			||||||
 | 
					            impl #impl_generics ::fayalite::enum_::EnumType for #target #type_generics
 | 
				
			||||||
 | 
					            #where_clause
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                fn match_activate_scope(
 | 
				
			||||||
 | 
					                    v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
 | 
				
			||||||
 | 
					                ) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) {
 | 
				
			||||||
 | 
					                    let (variant_access, scope) = v.activate();
 | 
				
			||||||
 | 
					                    (
 | 
				
			||||||
 | 
					                        match variant_access.variant_index() {
 | 
				
			||||||
 | 
					                            #(#match_active_scope_match_arms)*
 | 
				
			||||||
 | 
					                            #variants_len.. => ::fayalite::__std::panic!("invalid variant index"),
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        scope,
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                fn variants(&self) -> ::fayalite::intern::Interned<[::fayalite::enum_::EnumVariant]> {
 | 
				
			||||||
 | 
					                    ::fayalite::intern::Intern::intern(&[
 | 
				
			||||||
 | 
					                        #(#variants_body_variants)*
 | 
				
			||||||
 | 
					                    ][..])
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_tokens(tokens);
 | 
				
			||||||
 | 
					        if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) {
 | 
				
			||||||
 | 
					            let static_generics = generics.clone().for_static_type();
 | 
				
			||||||
 | 
					            let (static_impl_generics, static_type_generics, static_where_clause) =
 | 
				
			||||||
 | 
					                static_generics.split_for_impl();
 | 
				
			||||||
 | 
					            let static_type_body_variants =
 | 
				
			||||||
 | 
					                Vec::from_iter(variants.iter().map(|ParsedVariant { ident, field, .. }| {
 | 
				
			||||||
 | 
					                    if let Some(_) = field {
 | 
				
			||||||
 | 
					                        quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                            #ident: ::fayalite::ty::StaticType::TYPE,
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                            #ident: (),
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
 | 
					            let type_properties = format_ident!("__type_properties", span = ident.span());
 | 
				
			||||||
 | 
					            let type_properties_variants =
 | 
				
			||||||
 | 
					                Vec::from_iter(variants.iter().map(|ParsedVariant { ident, field, .. }| {
 | 
				
			||||||
 | 
					                    let variant = if let Some(ParsedVariantField { ty, .. }) = field {
 | 
				
			||||||
 | 
					                        quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                            ::fayalite::__std::option::Option::Some(
 | 
				
			||||||
 | 
					                                <#ty as ::fayalite::ty::StaticType>::TYPE_PROPERTIES,
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                            ::fayalite::__std::option::Option::None
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                        let #type_properties = #type_properties.variant(#variant);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }));
 | 
				
			||||||
 | 
					            quote_spanned! {ident.span()=>
 | 
				
			||||||
 | 
					                #[automatically_derived]
 | 
				
			||||||
 | 
					                impl #static_impl_generics ::fayalite::ty::StaticType
 | 
				
			||||||
 | 
					                for #target #static_type_generics
 | 
				
			||||||
 | 
					                #static_where_clause
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    const TYPE: Self = Self {
 | 
				
			||||||
 | 
					                        #(#static_type_body_variants)*
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    const MASK_TYPE: <Self as ::fayalite::ty::Type>::MaskType =
 | 
				
			||||||
 | 
					                        ::fayalite::int::Bool;
 | 
				
			||||||
 | 
					                    const TYPE_PROPERTIES: ::fayalite::ty::TypeProperties = {
 | 
				
			||||||
 | 
					                        let #type_properties = ::fayalite::enum_::EnumTypePropertiesBuilder::new();
 | 
				
			||||||
 | 
					                        #(#type_properties_variants)*
 | 
				
			||||||
 | 
					                        #type_properties.finish()
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    const MASK_TYPE_PROPERTIES: ::fayalite::ty::TypeProperties =
 | 
				
			||||||
 | 
					                        <::fayalite::int::Bool as ::fayalite::ty::StaticType>::TYPE_PROPERTIES;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .to_tokens(tokens);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub(crate) fn hdl_enum(item: ItemEnum) -> syn::Result<TokenStream> {
 | 
				
			||||||
 | 
					    let item = ParsedEnum::parse(item)?;
 | 
				
			||||||
 | 
					    let outline_generated = item.options.body.outline_generated;
 | 
				
			||||||
 | 
					    let mut contents = item.to_token_stream();
 | 
				
			||||||
 | 
					    if outline_generated.is_some() {
 | 
				
			||||||
 | 
					        contents = crate::outline_generated(contents, "hdl-enum-");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Ok(contents)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2981
									
								
								crates/fayalite-proc-macros-impl/src/hdl_type_common.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2981
									
								
								crates/fayalite-proc-macros-impl/src/hdl_type_common.rs
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -3,7 +3,10 @@
 | 
				
			||||||
#![cfg_attr(test, recursion_limit = "512")]
 | 
					#![cfg_attr(test, recursion_limit = "512")]
 | 
				
			||||||
use proc_macro2::{Span, TokenStream};
 | 
					use proc_macro2::{Span, TokenStream};
 | 
				
			||||||
use quote::{quote, ToTokens};
 | 
					use quote::{quote, ToTokens};
 | 
				
			||||||
use std::io::{ErrorKind, Write};
 | 
					use std::{
 | 
				
			||||||
 | 
					    convert::Infallible,
 | 
				
			||||||
 | 
					    io::{ErrorKind, Write},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
use syn::{
 | 
					use syn::{
 | 
				
			||||||
    bracketed, parenthesized,
 | 
					    bracketed, parenthesized,
 | 
				
			||||||
    parse::{Parse, ParseStream, Parser},
 | 
					    parse::{Parse, ParseStream, Parser},
 | 
				
			||||||
| 
						 | 
					@ -13,6 +16,9 @@ use syn::{
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod fold;
 | 
					mod fold;
 | 
				
			||||||
 | 
					mod hdl_bundle;
 | 
				
			||||||
 | 
					mod hdl_enum;
 | 
				
			||||||
 | 
					mod hdl_type_common;
 | 
				
			||||||
mod module;
 | 
					mod module;
 | 
				
			||||||
mod value_derive_common;
 | 
					mod value_derive_common;
 | 
				
			||||||
mod value_derive_enum;
 | 
					mod value_derive_enum;
 | 
				
			||||||
| 
						 | 
					@ -43,6 +49,7 @@ mod kw {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    custom_keyword!(clock_domain);
 | 
					    custom_keyword!(clock_domain);
 | 
				
			||||||
    custom_keyword!(connect_inexact);
 | 
					    custom_keyword!(connect_inexact);
 | 
				
			||||||
 | 
					    custom_keyword!(custom_bounds);
 | 
				
			||||||
    custom_keyword!(flip);
 | 
					    custom_keyword!(flip);
 | 
				
			||||||
    custom_keyword!(hdl);
 | 
					    custom_keyword!(hdl);
 | 
				
			||||||
    custom_keyword!(input);
 | 
					    custom_keyword!(input);
 | 
				
			||||||
| 
						 | 
					@ -52,6 +59,7 @@ mod kw {
 | 
				
			||||||
    custom_keyword!(memory_array);
 | 
					    custom_keyword!(memory_array);
 | 
				
			||||||
    custom_keyword!(memory_with_init);
 | 
					    custom_keyword!(memory_with_init);
 | 
				
			||||||
    custom_keyword!(no_reset);
 | 
					    custom_keyword!(no_reset);
 | 
				
			||||||
 | 
					    custom_keyword!(no_static);
 | 
				
			||||||
    custom_keyword!(outline_generated);
 | 
					    custom_keyword!(outline_generated);
 | 
				
			||||||
    custom_keyword!(output);
 | 
					    custom_keyword!(output);
 | 
				
			||||||
    custom_keyword!(reg_builder);
 | 
					    custom_keyword!(reg_builder);
 | 
				
			||||||
| 
						 | 
					@ -460,6 +468,15 @@ impl Errors {
 | 
				
			||||||
        self.push(Error::new_spanned(tokens, message));
 | 
					        self.push(Error::new_spanned(tokens, message));
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    pub(crate) fn fatal_error(
 | 
				
			||||||
 | 
					        mut self,
 | 
				
			||||||
 | 
					        tokens: impl ToTokens,
 | 
				
			||||||
 | 
					        message: impl std::fmt::Display,
 | 
				
			||||||
 | 
					    ) -> syn::Result<Infallible> {
 | 
				
			||||||
 | 
					        self.push(Error::new_spanned(tokens, message));
 | 
				
			||||||
 | 
					        self.finish()?;
 | 
				
			||||||
 | 
					        unreachable!()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    pub(crate) fn ok<T>(&mut self, v: syn::Result<T>) -> Option<T> {
 | 
					    pub(crate) fn ok<T>(&mut self, v: syn::Result<T>) -> Option<T> {
 | 
				
			||||||
        match v {
 | 
					        match v {
 | 
				
			||||||
            Ok(v) => Some(v),
 | 
					            Ok(v) => Some(v),
 | 
				
			||||||
| 
						 | 
					@ -519,6 +536,26 @@ macro_rules! impl_extra_traits_for_options {
 | 
				
			||||||
    ) => {
 | 
					    ) => {
 | 
				
			||||||
        impl Copy for $option_enum_name {}
 | 
					        impl Copy for $option_enum_name {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl PartialEq for $option_enum_name {
 | 
				
			||||||
 | 
					            fn eq(&self, other: &Self) -> bool {
 | 
				
			||||||
 | 
					                self.cmp(other).is_eq()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl Eq for $option_enum_name {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl PartialOrd for $option_enum_name {
 | 
				
			||||||
 | 
					            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
 | 
				
			||||||
 | 
					                Some(self.cmp(other))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl Ord for $option_enum_name {
 | 
				
			||||||
 | 
					            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
 | 
				
			||||||
 | 
					                self.variant().cmp(&other.variant())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        impl quote::IdentFragment for $option_enum_name {
 | 
					        impl quote::IdentFragment for $option_enum_name {
 | 
				
			||||||
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 | 
					            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 | 
				
			||||||
                let _ = f;
 | 
					                let _ = f;
 | 
				
			||||||
| 
						 | 
					@ -554,6 +591,66 @@ pub(crate) use impl_extra_traits_for_options;
 | 
				
			||||||
macro_rules! options {
 | 
					macro_rules! options {
 | 
				
			||||||
    (
 | 
					    (
 | 
				
			||||||
        #[options = $options_name:ident]
 | 
					        #[options = $options_name:ident]
 | 
				
			||||||
 | 
					        $($tt:tt)*
 | 
				
			||||||
 | 
					    ) => {
 | 
				
			||||||
 | 
					        crate::options! {
 | 
				
			||||||
 | 
					            #[options = $options_name, punct = syn::Token![,], allow_duplicates = false]
 | 
				
			||||||
 | 
					            $($tt)*
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					        #[options = $options_name:ident, punct = $Punct:ty, allow_duplicates = true]
 | 
				
			||||||
 | 
					        $(#[$($enum_meta:tt)*])*
 | 
				
			||||||
 | 
					        $enum_vis:vis enum $option_enum_name:ident {
 | 
				
			||||||
 | 
					            $($Variant:ident($key:ident $(, $value:ty)?),)*
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ) => {
 | 
				
			||||||
 | 
					        crate::options! {
 | 
				
			||||||
 | 
					            #[options = $options_name, punct = $Punct, allow_duplicates = (true)]
 | 
				
			||||||
 | 
					            $(#[$($enum_meta)*])*
 | 
				
			||||||
 | 
					            $enum_vis enum $option_enum_name {
 | 
				
			||||||
 | 
					                $($Variant($key $(, $value)?),)*
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl Extend<$option_enum_name> for $options_name {
 | 
				
			||||||
 | 
					            fn extend<T: IntoIterator<Item = $option_enum_name>>(&mut self, iter: T) {
 | 
				
			||||||
 | 
					                iter.into_iter().for_each(|v| match v {
 | 
				
			||||||
 | 
					                    $($option_enum_name::$Variant(v) => {
 | 
				
			||||||
 | 
					                        self.$key = Some(v);
 | 
				
			||||||
 | 
					                    })*
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl FromIterator<$option_enum_name> for $options_name {
 | 
				
			||||||
 | 
					            fn from_iter<T: IntoIterator<Item = $option_enum_name>>(iter: T) -> Self {
 | 
				
			||||||
 | 
					                let mut retval = Self::default();
 | 
				
			||||||
 | 
					                retval.extend(iter);
 | 
				
			||||||
 | 
					                retval
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl Extend<$options_name> for $options_name {
 | 
				
			||||||
 | 
					            fn extend<T: IntoIterator<Item = $options_name>>(&mut self, iter: T) {
 | 
				
			||||||
 | 
					                iter.into_iter().for_each(|v| {
 | 
				
			||||||
 | 
					                    $(if let Some(v) = v.$key {
 | 
				
			||||||
 | 
					                        self.$key = Some(v);
 | 
				
			||||||
 | 
					                    })*
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl FromIterator<$options_name> for $options_name {
 | 
				
			||||||
 | 
					            fn from_iter<T: IntoIterator<Item = $options_name>>(iter: T) -> Self {
 | 
				
			||||||
 | 
					                let mut retval = Self::default();
 | 
				
			||||||
 | 
					                retval.extend(iter);
 | 
				
			||||||
 | 
					                retval
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					        #[options = $options_name:ident, punct = $Punct:ty, allow_duplicates = $allow_duplicates:expr]
 | 
				
			||||||
        $(#[$($enum_meta:tt)*])*
 | 
					        $(#[$($enum_meta:tt)*])*
 | 
				
			||||||
        $enum_vis:vis enum $option_enum_name:ident {
 | 
					        $enum_vis:vis enum $option_enum_name:ident {
 | 
				
			||||||
            $($Variant:ident($key:ident $(, $value:ty)?),)*
 | 
					            $($Variant:ident($key:ident $(, $value:ty)?),)*
 | 
				
			||||||
| 
						 | 
					@ -567,8 +664,11 @@ macro_rules! options {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #[derive(Clone, Debug, Default)]
 | 
					        #[derive(Clone, Debug, Default)]
 | 
				
			||||||
 | 
					        #[allow(non_snake_case)]
 | 
				
			||||||
        $enum_vis struct $options_name {
 | 
					        $enum_vis struct $options_name {
 | 
				
			||||||
            $($enum_vis $key: Option<(crate::kw::$key, $(syn::token::Paren, $value)?)>,)*
 | 
					            $(
 | 
				
			||||||
 | 
					                $enum_vis $key: Option<(crate::kw::$key, $(syn::token::Paren, $value)?)>,
 | 
				
			||||||
 | 
					            )*
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        crate::fold::impl_fold! {
 | 
					        crate::fold::impl_fold! {
 | 
				
			||||||
| 
						 | 
					@ -577,6 +677,43 @@ macro_rules! options {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const _: () = {
 | 
				
			||||||
 | 
					            #[derive(Clone, Debug)]
 | 
				
			||||||
 | 
					            $enum_vis struct Iter($enum_vis $options_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            impl IntoIterator for $options_name {
 | 
				
			||||||
 | 
					                type Item = $option_enum_name;
 | 
				
			||||||
 | 
					                type IntoIter = Iter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                fn into_iter(self) -> Self::IntoIter {
 | 
				
			||||||
 | 
					                    Iter(self)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            impl Iterator for Iter {
 | 
				
			||||||
 | 
					                type Item = $option_enum_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                fn next(&mut self) -> Option<Self::Item> {
 | 
				
			||||||
 | 
					                    $(
 | 
				
			||||||
 | 
					                        if let Some(value) = self.0.$key.take() {
 | 
				
			||||||
 | 
					                            return Some($option_enum_name::$Variant(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.$key.take() {
 | 
				
			||||||
 | 
					                            init = f(init, $option_enum_name::$Variant(value));
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    )*
 | 
				
			||||||
 | 
					                    init
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        impl syn::parse::Parse for $options_name {
 | 
					        impl syn::parse::Parse for $options_name {
 | 
				
			||||||
            fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
 | 
					            fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
 | 
				
			||||||
                #![allow(unused_mut, unused_variables, unreachable_code)]
 | 
					                #![allow(unused_mut, unused_variables, unreachable_code)]
 | 
				
			||||||
| 
						 | 
					@ -585,7 +722,7 @@ macro_rules! options {
 | 
				
			||||||
                    let old_input = input.fork();
 | 
					                    let old_input = input.fork();
 | 
				
			||||||
                    match input.parse::<$option_enum_name>()? {
 | 
					                    match input.parse::<$option_enum_name>()? {
 | 
				
			||||||
                        $($option_enum_name::$Variant(v) => {
 | 
					                        $($option_enum_name::$Variant(v) => {
 | 
				
			||||||
                            if retval.$key.replace(v).is_some() {
 | 
					                            if retval.$key.replace(v).is_some() && !$allow_duplicates {
 | 
				
			||||||
                                return Err(old_input.error(concat!("duplicate ", stringify!($key), " option")));
 | 
					                                return Err(old_input.error(concat!("duplicate ", stringify!($key), " option")));
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        })*
 | 
					                        })*
 | 
				
			||||||
| 
						 | 
					@ -593,7 +730,7 @@ macro_rules! options {
 | 
				
			||||||
                    if input.is_empty() {
 | 
					                    if input.is_empty() {
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    input.parse::<syn::Token![,]>()?;
 | 
					                    input.parse::<$Punct>()?;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                Ok(retval)
 | 
					                Ok(retval)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -602,7 +739,7 @@ macro_rules! options {
 | 
				
			||||||
        impl quote::ToTokens for $options_name {
 | 
					        impl quote::ToTokens for $options_name {
 | 
				
			||||||
            #[allow(unused_mut, unused_variables, unused_assignments)]
 | 
					            #[allow(unused_mut, unused_variables, unused_assignments)]
 | 
				
			||||||
            fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
 | 
					            fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
 | 
				
			||||||
                let mut separator: Option<syn::Token![,]> = None;
 | 
					                let mut separator: Option<$Punct> = None;
 | 
				
			||||||
                $(if let Some(v) = &self.$key {
 | 
					                $(if let Some(v) = &self.$key {
 | 
				
			||||||
                    separator.to_tokens(tokens);
 | 
					                    separator.to_tokens(tokens);
 | 
				
			||||||
                    separator = Some(Default::default());
 | 
					                    separator = Some(Default::default());
 | 
				
			||||||
| 
						 | 
					@ -673,6 +810,20 @@ macro_rules! options {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl $option_enum_name {
 | 
				
			||||||
 | 
					            #[allow(dead_code)]
 | 
				
			||||||
 | 
					            fn variant(&self) -> usize {
 | 
				
			||||||
 | 
					                #[repr(usize)]
 | 
				
			||||||
 | 
					                enum Variant {
 | 
				
			||||||
 | 
					                    $($Variant,)*
 | 
				
			||||||
 | 
					                    __Last, // so it doesn't complain about zero-variant enums
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                match *self {
 | 
				
			||||||
 | 
					                    $(Self::$Variant(..) => Variant::$Variant as usize,)*
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -686,6 +837,15 @@ pub(crate) fn outline_generated(contents: TokenStream, prefix: &str) -> TokenStr
 | 
				
			||||||
        .suffix(".tmp.rs")
 | 
					        .suffix(".tmp.rs")
 | 
				
			||||||
        .tempfile_in(out_dir)
 | 
					        .tempfile_in(out_dir)
 | 
				
			||||||
        .unwrap();
 | 
					        .unwrap();
 | 
				
			||||||
 | 
					    struct PrintOnPanic<'a>(&'a TokenStream);
 | 
				
			||||||
 | 
					    impl Drop for PrintOnPanic<'_> {
 | 
				
			||||||
 | 
					        fn drop(&mut self) {
 | 
				
			||||||
 | 
					            if std::thread::panicking() {
 | 
				
			||||||
 | 
					                println!("{}", self.0);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let _print_on_panic = PrintOnPanic(&contents);
 | 
				
			||||||
    let contents = prettyplease::unparse(&parse_quote! { #contents });
 | 
					    let contents = prettyplease::unparse(&parse_quote! { #contents });
 | 
				
			||||||
    let hash = <sha2::Sha256 as sha2::Digest>::digest(&contents);
 | 
					    let hash = <sha2::Sha256 as sha2::Digest>::digest(&contents);
 | 
				
			||||||
    let hash = base16ct::HexDisplay(&hash[..5]);
 | 
					    let hash = base16ct::HexDisplay(&hash[..5]);
 | 
				
			||||||
| 
						 | 
					@ -728,3 +888,15 @@ pub fn value_derive(item: TokenStream) -> syn::Result<TokenStream> {
 | 
				
			||||||
        )),
 | 
					        )),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
 | 
				
			||||||
 | 
					    let item = syn::parse2::<Item>(quote! { #[hdl(#attr)] #item })?;
 | 
				
			||||||
 | 
					    match item {
 | 
				
			||||||
 | 
					        Item::Enum(item) => hdl_enum::hdl_enum(item),
 | 
				
			||||||
 | 
					        Item::Struct(item) => hdl_bundle::hdl_bundle(item),
 | 
				
			||||||
 | 
					        _ => Err(syn::Error::new(
 | 
				
			||||||
 | 
					            Span::call_site(),
 | 
				
			||||||
 | 
					            "top-level #[hdl] can only be used on structs or enums",
 | 
				
			||||||
 | 
					        )),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1290,7 +1290,10 @@ impl Visitor {
 | 
				
			||||||
                memory,
 | 
					                memory,
 | 
				
			||||||
                paren,
 | 
					                paren,
 | 
				
			||||||
                ty_expr,
 | 
					                ty_expr,
 | 
				
			||||||
            } => (paren, unwrap_or_static_type(ty_expr.as_ref(), memory.span())),
 | 
					            } => (
 | 
				
			||||||
 | 
					                paren,
 | 
				
			||||||
 | 
					                unwrap_or_static_type(ty_expr.as_ref(), memory.span()),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
            MemoryFn::MemoryArray {
 | 
					            MemoryFn::MemoryArray {
 | 
				
			||||||
                memory_array,
 | 
					                memory_array,
 | 
				
			||||||
                paren,
 | 
					                paren,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,3 +24,15 @@ pub fn value_derive(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
 | 
				
			||||||
        Err(err) => err.into_compile_error().into(),
 | 
					        Err(err) => err.into_compile_error().into(),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// intentionally not documented here, see `fayalite::hdl` for docs
 | 
				
			||||||
 | 
					#[proc_macro_attribute]
 | 
				
			||||||
 | 
					pub fn hdl(
 | 
				
			||||||
 | 
					    attr: proc_macro::TokenStream,
 | 
				
			||||||
 | 
					    item: proc_macro::TokenStream,
 | 
				
			||||||
 | 
					) -> proc_macro::TokenStream {
 | 
				
			||||||
 | 
					    match fayalite_proc_macros_impl::hdl_attr(attr.into(), item.into()) {
 | 
				
			||||||
 | 
					        Ok(retval) => retval.into(),
 | 
				
			||||||
 | 
					        Err(err) => err.into_compile_error().into(),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
					// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    expr::Target,
 | 
					    expr::target::Target,
 | 
				
			||||||
    intern::{Intern, Interned},
 | 
					    intern::{Intern, Interned},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,671 +1,239 @@
 | 
				
			||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
					// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    bundle::{BundleType, BundleValue},
 | 
					    expr::{ops::ArrayIndex, Expr, ToExpr},
 | 
				
			||||||
    expr::{
 | 
					    int::{DynSize, KnownSize, Size},
 | 
				
			||||||
        ops::{ArrayIndex, ArrayLiteral, ExprIndex},
 | 
					    intern::{Intern, Interned, LazyInterned},
 | 
				
			||||||
        Expr, ToExpr,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    intern::{Intern, Interned, InternedCompare, Memoize},
 | 
					 | 
				
			||||||
    module::{
 | 
					    module::{
 | 
				
			||||||
        transform::visit::{Fold, Folder, Visit, Visitor},
 | 
					        transform::visit::{Fold, Folder, Visit, Visitor},
 | 
				
			||||||
        ModuleBuilder, NormalModule,
 | 
					        ModuleBuilder, NormalModule,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{
 | 
					    ty::{
 | 
				
			||||||
        CanonicalType, CanonicalTypeKind, CanonicalValue, Connect, DynCanonicalType,
 | 
					        CanonicalType, MatchVariantWithoutScope, StaticType, Type, TypeProperties, TypeWithDeref,
 | 
				
			||||||
        DynCanonicalValue, DynType, DynValueTrait, MatchVariantWithoutScope, StaticType,
 | 
					 | 
				
			||||||
        StaticValue, Type, TypeEnum, Value, ValueEnum,
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    util::{ConstBool, GenericConstBool, MakeMutSlice},
 | 
					    util::ConstUsize,
 | 
				
			||||||
};
 | 
					 | 
				
			||||||
use bitvec::{slice::BitSlice, vec::BitVec};
 | 
					 | 
				
			||||||
use std::{
 | 
					 | 
				
			||||||
    any::Any,
 | 
					 | 
				
			||||||
    borrow::{Borrow, BorrowMut},
 | 
					 | 
				
			||||||
    fmt,
 | 
					 | 
				
			||||||
    hash::Hash,
 | 
					 | 
				
			||||||
    marker::PhantomData,
 | 
					 | 
				
			||||||
    ops::IndexMut,
 | 
					 | 
				
			||||||
    sync::Arc,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					use std::ops::Index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod sealed {
 | 
					#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
    pub trait Sealed {}
 | 
					pub struct ArrayType<T: Type = CanonicalType, Len: Size = DynSize> {
 | 
				
			||||||
 | 
					    element: LazyInterned<T>,
 | 
				
			||||||
 | 
					    len: Len::SizeType,
 | 
				
			||||||
 | 
					    type_properties: TypeProperties,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait ValueArrayOrSlice:
 | 
					impl<T: Type, Len: Size> std::fmt::Debug for ArrayType<T, Len> {
 | 
				
			||||||
    sealed::Sealed
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
    + BorrowMut<[<Self as ValueArrayOrSlice>::Element]>
 | 
					        write!(f, "Array<{:?}, {}>", self.element, self.len())
 | 
				
			||||||
    + AsRef<[<Self as ValueArrayOrSlice>::Element]>
 | 
					 | 
				
			||||||
    + AsMut<[<Self as ValueArrayOrSlice>::Element]>
 | 
					 | 
				
			||||||
    + Hash
 | 
					 | 
				
			||||||
    + fmt::Debug
 | 
					 | 
				
			||||||
    + Eq
 | 
					 | 
				
			||||||
    + Send
 | 
					 | 
				
			||||||
    + Sync
 | 
					 | 
				
			||||||
    + 'static
 | 
					 | 
				
			||||||
    + IndexMut<usize, Output = <Self as ValueArrayOrSlice>::Element>
 | 
					 | 
				
			||||||
    + ToOwned
 | 
					 | 
				
			||||||
    + InternedCompare
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    type Element: Value<Type = <Self as ValueArrayOrSlice>::ElementType>;
 | 
					 | 
				
			||||||
    type ElementType: Type<Value = <Self as ValueArrayOrSlice>::Element>;
 | 
					 | 
				
			||||||
    type LenType: 'static + Copy + Ord + fmt::Debug + Hash + Send + Sync;
 | 
					 | 
				
			||||||
    type Match: 'static
 | 
					 | 
				
			||||||
        + Clone
 | 
					 | 
				
			||||||
        + Eq
 | 
					 | 
				
			||||||
        + fmt::Debug
 | 
					 | 
				
			||||||
        + Hash
 | 
					 | 
				
			||||||
        + Send
 | 
					 | 
				
			||||||
        + Sync
 | 
					 | 
				
			||||||
        + BorrowMut<[Expr<Self::Element>]>;
 | 
					 | 
				
			||||||
    type MaskVA: ValueArrayOrSlice<
 | 
					 | 
				
			||||||
            Element = <Self::ElementType as Type>::MaskValue,
 | 
					 | 
				
			||||||
            ElementType = <Self::ElementType as Type>::MaskType,
 | 
					 | 
				
			||||||
            LenType = Self::LenType,
 | 
					 | 
				
			||||||
            MaskVA = Self::MaskVA,
 | 
					 | 
				
			||||||
        > + ?Sized;
 | 
					 | 
				
			||||||
    type IsStaticLen: GenericConstBool;
 | 
					 | 
				
			||||||
    const FIXED_LEN_TYPE: Option<Self::LenType>;
 | 
					 | 
				
			||||||
    fn make_match(array: Expr<Array<Self>>) -> Self::Match;
 | 
					 | 
				
			||||||
    fn len_from_len_type(v: Self::LenType) -> usize;
 | 
					 | 
				
			||||||
    #[allow(clippy::result_unit_err)]
 | 
					 | 
				
			||||||
    fn try_len_type_from_len(v: usize) -> Result<Self::LenType, ()>;
 | 
					 | 
				
			||||||
    fn len_type(&self) -> Self::LenType;
 | 
					 | 
				
			||||||
    fn len(&self) -> usize;
 | 
					 | 
				
			||||||
    fn is_empty(&self) -> bool;
 | 
					 | 
				
			||||||
    fn iter(&self) -> std::slice::Iter<Self::Element> {
 | 
					 | 
				
			||||||
        Borrow::<[_]>::borrow(self).iter()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn clone_to_arc(&self) -> Arc<Self>;
 | 
					 | 
				
			||||||
    fn arc_make_mut(v: &mut Arc<Self>) -> &mut Self;
 | 
					 | 
				
			||||||
    fn arc_to_arc_slice(self: Arc<Self>) -> Arc<[Self::Element]>;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T> sealed::Sealed for [T] {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<V: Value> ValueArrayOrSlice for [V]
 | 
					 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    V::Type: Type<Value = V>,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    type Element = V;
 | 
					 | 
				
			||||||
    type ElementType = V::Type;
 | 
					 | 
				
			||||||
    type LenType = usize;
 | 
					 | 
				
			||||||
    type Match = Box<[Expr<V>]>;
 | 
					 | 
				
			||||||
    type MaskVA = [<Self::ElementType as Type>::MaskValue];
 | 
					 | 
				
			||||||
    type IsStaticLen = ConstBool<false>;
 | 
					 | 
				
			||||||
    const FIXED_LEN_TYPE: Option<Self::LenType> = None;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn make_match(array: Expr<Array<Self>>) -> Self::Match {
 | 
					 | 
				
			||||||
        (0..array.canonical_type().len())
 | 
					 | 
				
			||||||
            .map(|index| ArrayIndex::<V::Type>::new_unchecked(array.canonical(), index).to_expr())
 | 
					 | 
				
			||||||
            .collect()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn len_from_len_type(v: Self::LenType) -> usize {
 | 
					 | 
				
			||||||
        v
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn try_len_type_from_len(v: usize) -> Result<Self::LenType, ()> {
 | 
					 | 
				
			||||||
        Ok(v)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn len_type(&self) -> Self::LenType {
 | 
					 | 
				
			||||||
        self.len()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn len(&self) -> usize {
 | 
					 | 
				
			||||||
        <[_]>::len(self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn is_empty(&self) -> bool {
 | 
					 | 
				
			||||||
        <[_]>::is_empty(self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn clone_to_arc(&self) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Arc::from(self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn arc_make_mut(v: &mut Arc<Self>) -> &mut Self {
 | 
					 | 
				
			||||||
        MakeMutSlice::make_mut_slice(v)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn arc_to_arc_slice(self: Arc<Self>) -> Arc<[Self::Element]> {
 | 
					 | 
				
			||||||
        self
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T, const N: usize> sealed::Sealed for [T; N] {}
 | 
					pub type Array<
 | 
				
			||||||
 | 
					    T = CanonicalType,
 | 
				
			||||||
 | 
					    const LEN: usize = { <DynSize as crate::util::GenericConstUsize>::VALUE },
 | 
				
			||||||
 | 
					> = ArrayType<T, ConstUsize<LEN>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<V: Value, const N: usize> ValueArrayOrSlice for [V; N]
 | 
					#[allow(non_upper_case_globals)]
 | 
				
			||||||
where
 | 
					pub const Array: ArrayWithoutGenerics = ArrayWithoutGenerics;
 | 
				
			||||||
    V::Type: Type<Value = V>,
 | 
					#[allow(non_upper_case_globals)]
 | 
				
			||||||
{
 | 
					pub const ArrayType: ArrayWithoutGenerics = ArrayWithoutGenerics;
 | 
				
			||||||
    type Element = V;
 | 
					 | 
				
			||||||
    type ElementType = V::Type;
 | 
					 | 
				
			||||||
    type LenType = ();
 | 
					 | 
				
			||||||
    type Match = [Expr<V>; N];
 | 
					 | 
				
			||||||
    type MaskVA = [<Self::ElementType as Type>::MaskValue; N];
 | 
					 | 
				
			||||||
    type IsStaticLen = ConstBool<true>;
 | 
					 | 
				
			||||||
    const FIXED_LEN_TYPE: Option<Self::LenType> = Some(());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn make_match(array: Expr<Array<Self>>) -> Self::Match {
 | 
					impl<T: Type, Len: Size> ArrayType<T, Len> {
 | 
				
			||||||
        std::array::from_fn(|index| {
 | 
					    const fn make_type_properties(element: TypeProperties, len: usize) -> TypeProperties {
 | 
				
			||||||
            ArrayIndex::<V::Type>::new_unchecked(array.canonical(), index).to_expr()
 | 
					        let TypeProperties {
 | 
				
			||||||
        })
 | 
					            is_passive,
 | 
				
			||||||
    }
 | 
					            is_storable,
 | 
				
			||||||
 | 
					            is_castable_from_bits,
 | 
				
			||||||
    fn len_from_len_type(_v: Self::LenType) -> usize {
 | 
					            bit_width,
 | 
				
			||||||
        N
 | 
					        } = element;
 | 
				
			||||||
    }
 | 
					        let Some(bit_width) = bit_width.checked_mul(len) else {
 | 
				
			||||||
 | 
					            panic!("array too big");
 | 
				
			||||||
    fn try_len_type_from_len(v: usize) -> Result<Self::LenType, ()> {
 | 
					 | 
				
			||||||
        if v == N {
 | 
					 | 
				
			||||||
            Ok(())
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            Err(())
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn len_type(&self) -> Self::LenType {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn len(&self) -> usize {
 | 
					 | 
				
			||||||
        N
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn is_empty(&self) -> bool {
 | 
					 | 
				
			||||||
        N == 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn clone_to_arc(&self) -> Arc<Self> {
 | 
					 | 
				
			||||||
        Arc::new(self.clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn arc_make_mut(v: &mut Arc<Self>) -> &mut Self {
 | 
					 | 
				
			||||||
        Arc::make_mut(v)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn arc_to_arc_slice(self: Arc<Self>) -> Arc<[Self::Element]> {
 | 
					 | 
				
			||||||
        self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug, PartialEq, Eq, Hash)]
 | 
					 | 
				
			||||||
pub struct ArrayType<VA: ValueArrayOrSlice + ?Sized> {
 | 
					 | 
				
			||||||
    element: VA::ElementType,
 | 
					 | 
				
			||||||
    len: VA::LenType,
 | 
					 | 
				
			||||||
    bit_width: usize,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub trait ArrayTypeTrait:
 | 
					 | 
				
			||||||
    Type<
 | 
					 | 
				
			||||||
        CanonicalType = ArrayType<[DynCanonicalValue]>,
 | 
					 | 
				
			||||||
        Value = Array<<Self as ArrayTypeTrait>::ValueArrayOrSlice>,
 | 
					 | 
				
			||||||
        CanonicalValue = Array<[DynCanonicalValue]>,
 | 
					 | 
				
			||||||
        MaskType = ArrayType<
 | 
					 | 
				
			||||||
            <<Self as ArrayTypeTrait>::ValueArrayOrSlice as ValueArrayOrSlice>::MaskVA,
 | 
					 | 
				
			||||||
        >,
 | 
					 | 
				
			||||||
    > + From<ArrayType<<Self as ArrayTypeTrait>::ValueArrayOrSlice>>
 | 
					 | 
				
			||||||
    + Into<ArrayType<<Self as ArrayTypeTrait>::ValueArrayOrSlice>>
 | 
					 | 
				
			||||||
    + BorrowMut<ArrayType<<Self as ArrayTypeTrait>::ValueArrayOrSlice>>
 | 
					 | 
				
			||||||
    + sealed::Sealed
 | 
					 | 
				
			||||||
    + Connect<Self>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    type ValueArrayOrSlice: ValueArrayOrSlice<Element = Self::Element, ElementType = Self::ElementType>
 | 
					 | 
				
			||||||
        + ?Sized;
 | 
					 | 
				
			||||||
    type Element: Value<Type = Self::ElementType>;
 | 
					 | 
				
			||||||
    type ElementType: Type<Value = Self::Element>;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> sealed::Sealed for ArrayType<VA> {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> ArrayTypeTrait for ArrayType<VA> {
 | 
					 | 
				
			||||||
    type ValueArrayOrSlice = VA;
 | 
					 | 
				
			||||||
    type Element = VA::Element;
 | 
					 | 
				
			||||||
    type ElementType = VA::ElementType;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> Clone for ArrayType<VA> {
 | 
					 | 
				
			||||||
    fn clone(&self) -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
            element: self.element.clone(),
 | 
					 | 
				
			||||||
            len: self.len,
 | 
					 | 
				
			||||||
            bit_width: self.bit_width,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> Copy for ArrayType<VA> where VA::ElementType: Copy {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> ArrayType<VA> {
 | 
					 | 
				
			||||||
    pub fn element(&self) -> &VA::ElementType {
 | 
					 | 
				
			||||||
        &self.element
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn len(&self) -> usize {
 | 
					 | 
				
			||||||
        VA::len_from_len_type(self.len)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn is_empty(&self) -> bool {
 | 
					 | 
				
			||||||
        self.len() == 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn bit_width(&self) -> usize {
 | 
					 | 
				
			||||||
        self.bit_width
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn into_slice_type(self) -> ArrayType<[VA::Element]> {
 | 
					 | 
				
			||||||
        ArrayType {
 | 
					 | 
				
			||||||
            len: self.len(),
 | 
					 | 
				
			||||||
            element: self.element,
 | 
					 | 
				
			||||||
            bit_width: self.bit_width,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[track_caller]
 | 
					 | 
				
			||||||
    pub fn new_with_len(element: VA::ElementType, len: usize) -> Self {
 | 
					 | 
				
			||||||
        Self::new_with_len_type(
 | 
					 | 
				
			||||||
            element,
 | 
					 | 
				
			||||||
            VA::try_len_type_from_len(len).expect("length should match"),
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[track_caller]
 | 
					 | 
				
			||||||
    pub fn new_with_len_type(element: VA::ElementType, len: VA::LenType) -> Self {
 | 
					 | 
				
			||||||
        let Some(bit_width) = VA::len_from_len_type(len).checked_mul(element.bit_width()) else {
 | 
					 | 
				
			||||||
            panic!("array is too big: bit-width overflowed");
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        ArrayType {
 | 
					        TypeProperties {
 | 
				
			||||||
            element,
 | 
					            is_passive,
 | 
				
			||||||
            len,
 | 
					            is_storable,
 | 
				
			||||||
 | 
					            is_castable_from_bits,
 | 
				
			||||||
            bit_width,
 | 
					            bit_width,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn new(element: T, len: Len::SizeType) -> Self {
 | 
				
			||||||
 | 
					        let type_properties =
 | 
				
			||||||
 | 
					            Self::make_type_properties(element.canonical().type_properties(), Len::as_usize(len));
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            element: LazyInterned::Interned(element.intern_sized()),
 | 
				
			||||||
 | 
					            len,
 | 
				
			||||||
 | 
					            type_properties,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn element(&self) -> T {
 | 
				
			||||||
 | 
					        *self.element
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn len(self) -> usize {
 | 
				
			||||||
 | 
					        Len::as_usize(self.len)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn is_empty(self) -> bool {
 | 
				
			||||||
 | 
					        self.len() == 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn type_properties(self) -> TypeProperties {
 | 
				
			||||||
 | 
					        self.type_properties
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn as_dyn_array(self) -> Array {
 | 
				
			||||||
 | 
					        Array::new_dyn(self.element().canonical(), self.len())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn can_connect<T2: Type, Len2: Size>(self, rhs: ArrayType<T2, Len2>) -> bool {
 | 
				
			||||||
 | 
					        self.len() == rhs.len()
 | 
				
			||||||
 | 
					            && self
 | 
				
			||||||
 | 
					                .element()
 | 
				
			||||||
 | 
					                .canonical()
 | 
				
			||||||
 | 
					                .can_connect(rhs.element().canonical())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized, State: ?Sized + Folder> Fold<State> for ArrayType<VA>
 | 
					impl<T: Type, Len: KnownSize> ArrayType<T, Len> {
 | 
				
			||||||
where
 | 
					    pub fn new_static(element: T) -> Self {
 | 
				
			||||||
    VA::ElementType: Fold<State>,
 | 
					        Self::new(element, Len::SizeType::default())
 | 
				
			||||||
{
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: StaticType, Len: KnownSize> StaticType for ArrayType<T, Len> {
 | 
				
			||||||
 | 
					    const TYPE: Self = Self {
 | 
				
			||||||
 | 
					        element: LazyInterned::new_lazy(&|| T::TYPE.intern_sized()),
 | 
				
			||||||
 | 
					        len: Len::SIZE,
 | 
				
			||||||
 | 
					        type_properties: Self::TYPE_PROPERTIES,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const MASK_TYPE: Self::MaskType = ArrayType::<T::MaskType, Len> {
 | 
				
			||||||
 | 
					        element: LazyInterned::new_lazy(&|| T::MASK_TYPE.intern_sized()),
 | 
				
			||||||
 | 
					        len: Len::SIZE,
 | 
				
			||||||
 | 
					        type_properties: Self::MASK_TYPE_PROPERTIES,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const TYPE_PROPERTIES: TypeProperties =
 | 
				
			||||||
 | 
					        Self::make_type_properties(T::TYPE_PROPERTIES, Len::VALUE);
 | 
				
			||||||
 | 
					    const MASK_TYPE_PROPERTIES: TypeProperties =
 | 
				
			||||||
 | 
					        Self::make_type_properties(T::MASK_TYPE_PROPERTIES, Len::VALUE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: Type> Array<T> {
 | 
				
			||||||
 | 
					    pub fn new_dyn(element: T, len: usize) -> Self {
 | 
				
			||||||
 | 
					        Self::new(element, len)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: Type + Fold<State>, Len: Size, State: Folder + ?Sized> Fold<State> for ArrayType<T, Len> {
 | 
				
			||||||
    fn fold(self, state: &mut State) -> Result<Self, State::Error> {
 | 
					    fn fold(self, state: &mut State) -> Result<Self, State::Error> {
 | 
				
			||||||
        state.fold_array_type(self)
 | 
					        state.fold_array_type(self)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn default_fold(self, state: &mut State) -> Result<Self, State::Error> {
 | 
					
 | 
				
			||||||
        Ok(Self::new_with_len_type(self.element.fold(state)?, self.len))
 | 
					    fn default_fold(self, state: &mut State) -> Result<Self, <State as Folder>::Error> {
 | 
				
			||||||
 | 
					        Ok(ArrayType::new(self.element().fold(state)?, self.len))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized, State: ?Sized + Visitor> Visit<State> for ArrayType<VA>
 | 
					impl<T: Type + Visit<State>, Len: Size, State: Visitor + ?Sized> Visit<State>
 | 
				
			||||||
where
 | 
					    for ArrayType<T, Len>
 | 
				
			||||||
    VA::ElementType: Visit<State>,
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    fn visit(&self, state: &mut State) -> Result<(), State::Error> {
 | 
					    fn visit(&self, state: &mut State) -> Result<(), State::Error> {
 | 
				
			||||||
        state.visit_array_type(self)
 | 
					        state.visit_array_type(self)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn default_visit(&self, state: &mut State) -> Result<(), State::Error> {
 | 
					    fn default_visit(&self, state: &mut State) -> Result<(), State::Error> {
 | 
				
			||||||
        self.element.visit(state)
 | 
					        self.element().visit(state)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<V: Value<Type: Type<Value = V>>, const N: usize> ArrayType<[V; N]> {
 | 
					impl<T: Type, Len: Size> Type for ArrayType<T, Len> {
 | 
				
			||||||
    pub fn new_array(element: V::Type) -> Self {
 | 
					    type BaseType = Array;
 | 
				
			||||||
        ArrayType::new_with_len_type(element, ())
 | 
					    type MaskType = ArrayType<T::MaskType, Len>;
 | 
				
			||||||
    }
 | 
					    type MatchVariant = Len::ArrayMatch<T>;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<V: StaticValue, const N: usize> StaticType for ArrayType<[V; N]> {
 | 
					 | 
				
			||||||
    fn static_type() -> Self {
 | 
					 | 
				
			||||||
        Self::new_array(StaticType::static_type())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<V: Value<Type: Type<Value = V>>> ArrayType<[V]> {
 | 
					 | 
				
			||||||
    pub fn new_slice(element: V::Type, len: usize) -> Self {
 | 
					 | 
				
			||||||
        ArrayType::new_with_len_type(element, len)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> Type for ArrayType<VA> {
 | 
					 | 
				
			||||||
    type CanonicalType = ArrayType<[DynCanonicalValue]>;
 | 
					 | 
				
			||||||
    type Value = Array<VA>;
 | 
					 | 
				
			||||||
    type CanonicalValue = Array<[DynCanonicalValue]>;
 | 
					 | 
				
			||||||
    type MaskType = ArrayType<VA::MaskVA>;
 | 
					 | 
				
			||||||
    type MaskValue = Array<VA::MaskVA>;
 | 
					 | 
				
			||||||
    type MatchVariant = VA::Match;
 | 
					 | 
				
			||||||
    type MatchActiveScope = ();
 | 
					    type MatchActiveScope = ();
 | 
				
			||||||
    type MatchVariantAndInactiveScope = MatchVariantWithoutScope<VA::Match>;
 | 
					    type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Len::ArrayMatch<T>>;
 | 
				
			||||||
    type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
 | 
					    type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn match_variants<IO: BundleValue>(
 | 
					    fn match_variants(
 | 
				
			||||||
        this: Expr<Self::Value>,
 | 
					        this: Expr<Self>,
 | 
				
			||||||
        module_builder: &mut ModuleBuilder<IO, NormalModule>,
 | 
					        module_builder: &mut ModuleBuilder<NormalModule>,
 | 
				
			||||||
        source_location: SourceLocation,
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
    ) -> Self::MatchVariantsIter
 | 
					    ) -> Self::MatchVariantsIter {
 | 
				
			||||||
    where
 | 
					        let base = Expr::as_dyn_array(this);
 | 
				
			||||||
        IO::Type: BundleType<Value = IO>,
 | 
					        let base_ty = Expr::ty(base);
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        let _ = module_builder;
 | 
					        let _ = module_builder;
 | 
				
			||||||
        let _ = source_location;
 | 
					        let _ = source_location;
 | 
				
			||||||
        std::iter::once(MatchVariantWithoutScope(VA::make_match(this)))
 | 
					        let retval = Vec::from_iter((0..base_ty.len()).map(|i| ArrayIndex::new(base, i).to_expr()));
 | 
				
			||||||
 | 
					        std::iter::once(MatchVariantWithoutScope(
 | 
				
			||||||
 | 
					            Len::ArrayMatch::<T>::try_from(retval)
 | 
				
			||||||
 | 
					                .ok()
 | 
				
			||||||
 | 
					                .expect("unreachable"),
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn mask_type(&self) -> Self::MaskType {
 | 
					    fn mask_type(&self) -> Self::MaskType {
 | 
				
			||||||
        #[derive(Clone, Hash, Eq, PartialEq)]
 | 
					        ArrayType::new(self.element().mask_type(), self.len)
 | 
				
			||||||
        struct ArrayMaskTypeMemoize<T: ArrayTypeTrait>(PhantomData<T>);
 | 
					 | 
				
			||||||
        impl<T: ArrayTypeTrait> Copy for ArrayMaskTypeMemoize<T> {}
 | 
					 | 
				
			||||||
        impl<T: ArrayTypeTrait> Memoize for ArrayMaskTypeMemoize<T> {
 | 
					 | 
				
			||||||
            type Input = ArrayType<T::ValueArrayOrSlice>;
 | 
					 | 
				
			||||||
            type InputOwned = ArrayType<T::ValueArrayOrSlice>;
 | 
					 | 
				
			||||||
            type Output = <ArrayType<T::ValueArrayOrSlice> as Type>::MaskType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            fn inner(self, input: &Self::Input) -> Self::Output {
 | 
					 | 
				
			||||||
                ArrayType::new_with_len_type(input.element.mask_type(), input.len)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        ArrayMaskTypeMemoize::<Self>(PhantomData).get(self)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn canonical(&self) -> Self::CanonicalType {
 | 
					    fn canonical(&self) -> CanonicalType {
 | 
				
			||||||
        ArrayType {
 | 
					        CanonicalType::Array(Array::new_dyn(self.element().canonical(), self.len()))
 | 
				
			||||||
            element: self.element.canonical_dyn(),
 | 
					 | 
				
			||||||
            len: self.len(),
 | 
					 | 
				
			||||||
            bit_width: self.bit_width,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn source_location(&self) -> SourceLocation {
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    fn from_canonical(canonical_type: CanonicalType) -> Self {
 | 
				
			||||||
 | 
					        let CanonicalType::Array(array) = canonical_type else {
 | 
				
			||||||
 | 
					            panic!("expected array");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        Self::new(
 | 
				
			||||||
 | 
					            T::from_canonical(array.element()),
 | 
				
			||||||
 | 
					            Len::from_usize(array.len()),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn source_location() -> SourceLocation {
 | 
				
			||||||
        SourceLocation::builtin()
 | 
					        SourceLocation::builtin()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn type_enum(&self) -> TypeEnum {
 | 
					impl<T: Type, Len: Size> TypeWithDeref for ArrayType<T, Len> {
 | 
				
			||||||
        TypeEnum::ArrayType(self.canonical())
 | 
					    fn expr_deref(this: &Expr<Self>) -> &Self::MatchVariant {
 | 
				
			||||||
    }
 | 
					        let base = Expr::as_dyn_array(*this);
 | 
				
			||||||
 | 
					        let base_ty = Expr::ty(base);
 | 
				
			||||||
    fn from_canonical_type(t: Self::CanonicalType) -> Self {
 | 
					        let retval = Vec::from_iter((0..base_ty.len()).map(|i| ArrayIndex::new(base, i).to_expr()));
 | 
				
			||||||
        Self {
 | 
					        Interned::<_>::into_inner(Intern::intern_sized(
 | 
				
			||||||
            element: VA::ElementType::from_dyn_canonical_type(t.element),
 | 
					            Len::ArrayMatch::<T>::try_from(retval)
 | 
				
			||||||
            len: VA::try_len_type_from_len(t.len).expect("length should match"),
 | 
					                .ok()
 | 
				
			||||||
            bit_width: t.bit_width,
 | 
					                .expect("unreachable"),
 | 
				
			||||||
        }
 | 
					        ))
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> {
 | 
					 | 
				
			||||||
        Some(<dyn Any>::downcast_ref::<ArrayType<[DynCanonicalValue]>>(
 | 
					 | 
				
			||||||
            this,
 | 
					 | 
				
			||||||
        )?)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<Lhs: ValueArrayOrSlice + ?Sized, Rhs: ValueArrayOrSlice + ?Sized> Connect<ArrayType<Rhs>>
 | 
					#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
 | 
				
			||||||
    for ArrayType<Lhs>
 | 
					pub struct ArrayWithoutGenerics;
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl CanonicalType for ArrayType<[DynCanonicalValue]> {
 | 
					impl<T: Type> Index<T> for ArrayWithoutGenerics {
 | 
				
			||||||
    const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::ArrayType;
 | 
					    type Output = ArrayWithoutLen<T>;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, PartialEq, Eq, Hash)]
 | 
					    fn index(&self, element: T) -> &Self::Output {
 | 
				
			||||||
pub struct Array<VA: ValueArrayOrSlice + ?Sized> {
 | 
					        Interned::<_>::into_inner(Intern::intern_sized(ArrayWithoutLen { element }))
 | 
				
			||||||
    element_ty: VA::ElementType,
 | 
					 | 
				
			||||||
    value: Arc<VA>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> Clone for Array<VA> {
 | 
					 | 
				
			||||||
    fn clone(&self) -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
            element_ty: self.element_ty.clone(),
 | 
					 | 
				
			||||||
            value: self.value.clone(),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> ToExpr for Array<VA> {
 | 
					#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 | 
				
			||||||
    type Type = ArrayType<VA>;
 | 
					pub struct ArrayWithoutLen<T: Type> {
 | 
				
			||||||
 | 
					    element: T,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					impl<T: Type> Index<usize> for ArrayWithoutLen<T> {
 | 
				
			||||||
        ArrayType::new_with_len_type(self.element_ty.clone(), self.value.len_type())
 | 
					    type Output = Array<T>;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
					    fn index(&self, len: usize) -> &Self::Output {
 | 
				
			||||||
        Expr::from_value(self)
 | 
					        Interned::<_>::into_inner(Intern::intern_sized(Array::new_dyn(self.element, len)))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> Value for Array<VA> {
 | 
					impl<T: Type, const LEN: usize> Index<ConstUsize<LEN>> for ArrayWithoutLen<T>
 | 
				
			||||||
    fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
 | 
					 | 
				
			||||||
        Array {
 | 
					 | 
				
			||||||
            element_ty: self.element_ty.canonical_dyn(),
 | 
					 | 
				
			||||||
            value: AsRef::<[_]>::as_ref(&*self.value)
 | 
					 | 
				
			||||||
                .iter()
 | 
					 | 
				
			||||||
                .map(|v| v.to_canonical_dyn())
 | 
					 | 
				
			||||||
                .collect(),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        #[derive(Hash, Eq, PartialEq)]
 | 
					 | 
				
			||||||
        struct ArrayToBitsMemoize<VA: ValueArrayOrSlice + ?Sized>(PhantomData<VA>);
 | 
					 | 
				
			||||||
        impl<VA: ValueArrayOrSlice + ?Sized> Clone for ArrayToBitsMemoize<VA> {
 | 
					 | 
				
			||||||
            fn clone(&self) -> Self {
 | 
					 | 
				
			||||||
                *self
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        impl<VA: ValueArrayOrSlice + ?Sized> Copy for ArrayToBitsMemoize<VA> {}
 | 
					 | 
				
			||||||
        impl<VA: ValueArrayOrSlice + ?Sized> Memoize for ArrayToBitsMemoize<VA> {
 | 
					 | 
				
			||||||
            type Input = Array<VA>;
 | 
					 | 
				
			||||||
            type InputOwned = Array<VA>;
 | 
					 | 
				
			||||||
            type Output = Interned<BitSlice>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            fn inner(self, input: &Self::Input) -> Self::Output {
 | 
					 | 
				
			||||||
                let mut bits = BitVec::with_capacity(input.ty().bit_width());
 | 
					 | 
				
			||||||
                for element in AsRef::<[_]>::as_ref(&*input.value).iter() {
 | 
					 | 
				
			||||||
                    bits.extend_from_bitslice(&element.to_bits());
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                Intern::intern_owned(bits)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        ArrayToBitsMemoize::<VA>(PhantomData).get(this)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl CanonicalValue for Array<[DynCanonicalValue]> {
 | 
					 | 
				
			||||||
    fn value_enum_impl(this: &Self) -> ValueEnum {
 | 
					 | 
				
			||||||
        ValueEnum::Array(this.clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        Value::to_bits_impl(this)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> Array<VA> {
 | 
					 | 
				
			||||||
    pub fn element_ty(&self) -> &VA::ElementType {
 | 
					 | 
				
			||||||
        &self.element_ty
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn len(&self) -> usize {
 | 
					 | 
				
			||||||
        VA::len_from_len_type(self.value.len_type())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn is_empty(&self) -> bool {
 | 
					 | 
				
			||||||
        self.len() == 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn value(&self) -> &Arc<VA> {
 | 
					 | 
				
			||||||
        &self.value
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn set_element(&mut self, index: usize, element: VA::Element) {
 | 
					 | 
				
			||||||
        assert_eq!(self.element_ty, element.ty());
 | 
					 | 
				
			||||||
        VA::arc_make_mut(&mut self.value)[index] = element;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn new(element_ty: VA::ElementType, value: Arc<VA>) -> Self {
 | 
					 | 
				
			||||||
        for element in value.iter() {
 | 
					 | 
				
			||||||
            assert_eq!(element_ty, element.ty());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        Self { element_ty, value }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn into_slice(self) -> Array<[VA::Element]> {
 | 
					 | 
				
			||||||
        Array {
 | 
					 | 
				
			||||||
            element_ty: self.element_ty,
 | 
					 | 
				
			||||||
            value: self.value.arc_to_arc_slice(),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized, T: Into<Arc<VA>>> From<T> for Array<VA>
 | 
					 | 
				
			||||||
where
 | 
					where
 | 
				
			||||||
    VA::Element: StaticValue,
 | 
					    ConstUsize<LEN>: KnownSize,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    fn from(value: T) -> Self {
 | 
					    type Output = Array<T, LEN>;
 | 
				
			||||||
        Self::new(StaticType::static_type(), value.into())
 | 
					
 | 
				
			||||||
    }
 | 
					    fn index(&self, len: ConstUsize<LEN>) -> &Self::Output {
 | 
				
			||||||
}
 | 
					        Interned::<_>::into_inner(Intern::intern_sized(Array::new(self.element, len)))
 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<E: ToExpr<Type = T>, T: StaticType<MaskType: StaticType>> ToExpr for [E] {
 | 
					 | 
				
			||||||
    type Type = ArrayType<[T::Value]>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					 | 
				
			||||||
        ArrayType::new_with_len_type(StaticType::static_type(), self.len())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
					 | 
				
			||||||
        let elements = Intern::intern_owned(Vec::from_iter(
 | 
					 | 
				
			||||||
            self.iter().map(|v| v.to_expr().to_canonical_dyn()),
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
        ArrayLiteral::new_unchecked(elements, self.ty()).to_expr()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<E: ToExpr<Type = T>, T: StaticType<MaskType: StaticType>> ToExpr for Vec<E> {
 | 
					 | 
				
			||||||
    type Type = ArrayType<[T::Value]>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					 | 
				
			||||||
        <[E]>::ty(self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
					 | 
				
			||||||
        <[E]>::to_expr(self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<E: ToExpr<Type = T>, T: StaticType<MaskType: StaticType>, const N: usize> ToExpr for [E; N] {
 | 
					 | 
				
			||||||
    type Type = ArrayType<[T::Value; N]>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					 | 
				
			||||||
        ArrayType::new_with_len_type(StaticType::static_type(), ())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
					 | 
				
			||||||
        let elements = Intern::intern_owned(Vec::from_iter(
 | 
					 | 
				
			||||||
            self.iter().map(|v| v.to_expr().to_canonical_dyn()),
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
        ArrayLiteral::new_unchecked(elements, self.ty()).to_expr()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					 | 
				
			||||||
pub struct ArrayIntoIter<VA: ValueArrayOrSlice> {
 | 
					 | 
				
			||||||
    array: Arc<VA>,
 | 
					 | 
				
			||||||
    indexes: std::ops::Range<usize>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> Iterator for ArrayIntoIter<VA> {
 | 
					 | 
				
			||||||
    type Item = VA::Element;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
					 | 
				
			||||||
        Some(self.array[self.indexes.next()?].clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn size_hint(&self) -> (usize, Option<usize>) {
 | 
					 | 
				
			||||||
        self.indexes.size_hint()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> std::iter::FusedIterator for ArrayIntoIter<VA> {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> ExactSizeIterator for ArrayIntoIter<VA> {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> DoubleEndedIterator for ArrayIntoIter<VA> {
 | 
					 | 
				
			||||||
    fn next_back(&mut self) -> Option<Self::Item> {
 | 
					 | 
				
			||||||
        Some(self.array[self.indexes.next_back()?].clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> Array<VA> {
 | 
					 | 
				
			||||||
    pub fn iter(&self) -> std::slice::Iter<'_, VA::Element> {
 | 
					 | 
				
			||||||
        self.value.iter()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<'a, VA: ValueArrayOrSlice> IntoIterator for &'a Array<VA> {
 | 
					 | 
				
			||||||
    type Item = &'a VA::Element;
 | 
					 | 
				
			||||||
    type IntoIter = std::slice::Iter<'a, VA::Element>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn into_iter(self) -> Self::IntoIter {
 | 
					 | 
				
			||||||
        self.value.iter()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> IntoIterator for Array<VA> {
 | 
					 | 
				
			||||||
    type Item = VA::Element;
 | 
					 | 
				
			||||||
    type IntoIter = ArrayIntoIter<VA>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn into_iter(self) -> Self::IntoIter {
 | 
					 | 
				
			||||||
        ArrayIntoIter {
 | 
					 | 
				
			||||||
            indexes: 0..self.len(),
 | 
					 | 
				
			||||||
            array: self.value,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					 | 
				
			||||||
pub struct ArrayExprIter<VA: ValueArrayOrSlice> {
 | 
					 | 
				
			||||||
    array: Expr<Array<VA>>,
 | 
					 | 
				
			||||||
    indexes: std::ops::Range<usize>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> Iterator for ArrayExprIter<VA> {
 | 
					 | 
				
			||||||
    type Item = Expr<VA::Element>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
					 | 
				
			||||||
        Some(ExprIndex::expr_index(self.array, self.indexes.next()?))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn size_hint(&self) -> (usize, Option<usize>) {
 | 
					 | 
				
			||||||
        self.indexes.size_hint()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> std::iter::FusedIterator for ArrayExprIter<VA> {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> ExactSizeIterator for ArrayExprIter<VA> {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> DoubleEndedIterator for ArrayExprIter<VA> {
 | 
					 | 
				
			||||||
    fn next_back(&mut self) -> Option<Self::Item> {
 | 
					 | 
				
			||||||
        Some(ExprIndex::expr_index(self.array, self.indexes.next_back()?))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> IntoIterator for Expr<Array<VA>> {
 | 
					 | 
				
			||||||
    type Item = Expr<VA::Element>;
 | 
					 | 
				
			||||||
    type IntoIter = ArrayExprIter<VA>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn into_iter(self) -> Self::IntoIter {
 | 
					 | 
				
			||||||
        self.iter()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> IntoIterator for &'_ Expr<Array<VA>> {
 | 
					 | 
				
			||||||
    type Item = Expr<VA::Element>;
 | 
					 | 
				
			||||||
    type IntoIter = ArrayExprIter<VA>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn into_iter(self) -> Self::IntoIter {
 | 
					 | 
				
			||||||
        self.iter()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<VA: ValueArrayOrSlice> Expr<Array<VA>> {
 | 
					 | 
				
			||||||
    pub fn len(self) -> usize {
 | 
					 | 
				
			||||||
        self.canonical_type().len()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn is_empty(self) -> bool {
 | 
					 | 
				
			||||||
        self.canonical_type().is_empty()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn iter(self) -> ArrayExprIter<VA> {
 | 
					 | 
				
			||||||
        ArrayExprIter {
 | 
					 | 
				
			||||||
            indexes: 0..self.len(),
 | 
					 | 
				
			||||||
            array: self,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -2,111 +2,61 @@
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    expr::{Expr, ToExpr},
 | 
					    expr::{Expr, ToExpr},
 | 
				
			||||||
    int::{UInt, UIntType},
 | 
					    hdl,
 | 
				
			||||||
    intern::Interned,
 | 
					    int::Bool,
 | 
				
			||||||
    reset::Reset,
 | 
					    reset::Reset,
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{
 | 
					    ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
 | 
				
			||||||
        impl_match_values_as_self, CanonicalType, CanonicalTypeKind, CanonicalValue, Connect,
 | 
					 | 
				
			||||||
        DynCanonicalType, StaticType, Type, TypeEnum, Value, ValueEnum,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    util::interned_bit,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bitvec::slice::BitSlice;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
 | 
					#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
 | 
				
			||||||
pub struct ClockType;
 | 
					pub struct Clock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ClockType {
 | 
					impl Type for Clock {
 | 
				
			||||||
    pub const fn new() -> Self {
 | 
					    type BaseType = Clock;
 | 
				
			||||||
        Self
 | 
					    type MaskType = Bool;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Type for ClockType {
 | 
					    impl_match_variant_as_self!();
 | 
				
			||||||
    type Value = Clock;
 | 
					 | 
				
			||||||
    type CanonicalType = ClockType;
 | 
					 | 
				
			||||||
    type CanonicalValue = Clock;
 | 
					 | 
				
			||||||
    type MaskType = UIntType<1>;
 | 
					 | 
				
			||||||
    type MaskValue = UInt<1>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    impl_match_values_as_self!();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn mask_type(&self) -> Self::MaskType {
 | 
					    fn mask_type(&self) -> Self::MaskType {
 | 
				
			||||||
        UIntType::new()
 | 
					        Bool
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn type_enum(&self) -> TypeEnum {
 | 
					    fn canonical(&self) -> CanonicalType {
 | 
				
			||||||
        TypeEnum::Clock(*self)
 | 
					        CanonicalType::Clock(*self)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn from_canonical_type(t: Self::CanonicalType) -> Self {
 | 
					    fn source_location() -> SourceLocation {
 | 
				
			||||||
        t
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn canonical(&self) -> Self::CanonicalType {
 | 
					 | 
				
			||||||
        *self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn source_location(&self) -> SourceLocation {
 | 
					 | 
				
			||||||
        SourceLocation::builtin()
 | 
					        SourceLocation::builtin()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> {
 | 
					    fn from_canonical(canonical_type: CanonicalType) -> Self {
 | 
				
			||||||
        Some(this)
 | 
					        let CanonicalType::Clock(retval) = canonical_type else {
 | 
				
			||||||
 | 
					            panic!("expected Clock");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        retval
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Connect<Self> for ClockType {}
 | 
					impl Clock {
 | 
				
			||||||
 | 
					    pub fn type_properties(self) -> TypeProperties {
 | 
				
			||||||
impl CanonicalType for ClockType {
 | 
					        Self::TYPE_PROPERTIES
 | 
				
			||||||
    const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::Clock;
 | 
					    }
 | 
				
			||||||
}
 | 
					    pub fn can_connect(self, _rhs: Self) -> bool {
 | 
				
			||||||
 | 
					        true
 | 
				
			||||||
impl StaticType for ClockType {
 | 
					 | 
				
			||||||
    fn static_type() -> Self {
 | 
					 | 
				
			||||||
        Self
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
 | 
					impl StaticType for Clock {
 | 
				
			||||||
pub struct Clock(pub bool);
 | 
					    const TYPE: Self = Self;
 | 
				
			||||||
 | 
					    const MASK_TYPE: Self::MaskType = Bool;
 | 
				
			||||||
impl ToExpr for Clock {
 | 
					    const TYPE_PROPERTIES: TypeProperties = TypeProperties {
 | 
				
			||||||
    type Type = ClockType;
 | 
					        is_passive: true,
 | 
				
			||||||
 | 
					        is_storable: false,
 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					        is_castable_from_bits: true,
 | 
				
			||||||
        ClockType
 | 
					        bit_width: 1,
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
 | 
					    const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
 | 
				
			||||||
    fn to_expr(&self) -> Expr<Self> {
 | 
					 | 
				
			||||||
        Expr::from_value(self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Value for Clock {
 | 
					 | 
				
			||||||
    fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
 | 
					 | 
				
			||||||
        *self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        interned_bit(this.0)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl CanonicalValue for Clock {
 | 
					 | 
				
			||||||
    fn value_enum_impl(this: &Self) -> ValueEnum {
 | 
					 | 
				
			||||||
        ValueEnum::Clock(*this)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        interned_bit(this.0)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Value)]
 | 
					 | 
				
			||||||
#[hdl(static, outline_generated)]
 | 
					 | 
				
			||||||
pub struct ClockDomain {
 | 
					 | 
				
			||||||
    pub clk: Clock,
 | 
					 | 
				
			||||||
    pub rst: Reset,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait ToClock {
 | 
					pub trait ToClock {
 | 
				
			||||||
| 
						 | 
					@ -137,10 +87,10 @@ impl ToClock for Expr<Clock> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ToClock for Clock {
 | 
					#[hdl]
 | 
				
			||||||
    fn to_clock(&self) -> Expr<Clock> {
 | 
					pub struct ClockDomain {
 | 
				
			||||||
        self.to_expr()
 | 
					    pub clk: Clock,
 | 
				
			||||||
    }
 | 
					    pub rst: Reset,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ToClock for bool {
 | 
					impl ToClock for bool {
 | 
				
			||||||
| 
						 | 
					@ -148,9 +98,3 @@ impl ToClock for bool {
 | 
				
			||||||
        self.to_expr().to_clock()
 | 
					        self.to_expr().to_clock()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ToClock for UInt<1> {
 | 
					 | 
				
			||||||
    fn to_clock(&self) -> Expr<Clock> {
 | 
					 | 
				
			||||||
        self.to_expr().to_clock()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,190 +1,155 @@
 | 
				
			||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
					// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
#![allow(clippy::type_complexity)]
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    bundle::{BundleValue, TypeHintTrait},
 | 
					 | 
				
			||||||
    expr::{ops::VariantAccess, Expr, ToExpr},
 | 
					    expr::{ops::VariantAccess, Expr, ToExpr},
 | 
				
			||||||
    int::{UInt, UIntType},
 | 
					    hdl,
 | 
				
			||||||
    intern::{Intern, Interned, MemoizeGeneric},
 | 
					    int::Bool,
 | 
				
			||||||
 | 
					    intern::{Intern, Interned},
 | 
				
			||||||
    module::{
 | 
					    module::{
 | 
				
			||||||
        EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, ModuleBuilder,
 | 
					        EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, ModuleBuilder,
 | 
				
			||||||
        NormalModule, Scope,
 | 
					        NormalModule, Scope,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{
 | 
					    ty::{CanonicalType, MatchVariantAndInactiveScope, Type, TypeProperties},
 | 
				
			||||||
        CanonicalType, CanonicalTypeKind, CanonicalValue, Connect, DynCanonicalType,
 | 
					 | 
				
			||||||
        DynCanonicalValue, DynType, MatchVariantAndInactiveScope, Type, TypeEnum, Value, ValueEnum,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView};
 | 
					 | 
				
			||||||
use hashbrown::HashMap;
 | 
					use hashbrown::HashMap;
 | 
				
			||||||
use std::{
 | 
					use std::iter::FusedIterator;
 | 
				
			||||||
    borrow::Cow,
 | 
					 | 
				
			||||||
    fmt,
 | 
					 | 
				
			||||||
    hash::{Hash, Hasher},
 | 
					 | 
				
			||||||
    iter::FusedIterator,
 | 
					 | 
				
			||||||
    marker::PhantomData,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
 | 
					#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 | 
				
			||||||
pub struct VariantType<T> {
 | 
					pub struct EnumVariant {
 | 
				
			||||||
    pub name: Interned<str>,
 | 
					    pub name: Interned<str>,
 | 
				
			||||||
    pub ty: Option<T>,
 | 
					    pub ty: Option<CanonicalType>,
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub struct FmtDebugInEnum<'a, T>(&'a VariantType<T>);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T: fmt::Debug> fmt::Debug for FmtDebugInEnum<'_, T> {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        let VariantType { name, ref ty } = *self.0;
 | 
					 | 
				
			||||||
        if let Some(ty) = ty {
 | 
					 | 
				
			||||||
            write!(f, "{name}({ty:?})")
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            write!(f, "{name}")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T: fmt::Debug> fmt::Display for FmtDebugInEnum<'_, T> {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        fmt::Debug::fmt(self, f)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T> VariantType<T> {
 | 
					 | 
				
			||||||
    pub fn map_opt_ty<U, F: FnOnce(Option<T>) -> Option<U>>(self, f: F) -> VariantType<U> {
 | 
					 | 
				
			||||||
        let Self { name, ty } = self;
 | 
					 | 
				
			||||||
        VariantType { name, ty: f(ty) }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn map_ty<U, F: FnOnce(T) -> U>(self, f: F) -> VariantType<U> {
 | 
					 | 
				
			||||||
        let Self { name, ty } = self;
 | 
					 | 
				
			||||||
        VariantType {
 | 
					 | 
				
			||||||
            name,
 | 
					 | 
				
			||||||
            ty: ty.map(f),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn as_ref_ty(&self) -> VariantType<&T> {
 | 
					 | 
				
			||||||
        VariantType {
 | 
					 | 
				
			||||||
            name: self.name,
 | 
					 | 
				
			||||||
            ty: self.ty.as_ref(),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn fmt_debug_in_enum(&self) -> FmtDebugInEnum<T> {
 | 
					 | 
				
			||||||
        FmtDebugInEnum(self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T: Type> VariantType<T> {
 | 
					 | 
				
			||||||
    pub fn canonical(&self) -> VariantType<T::CanonicalType> {
 | 
					 | 
				
			||||||
        self.as_ref_ty().map_ty(T::canonical)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn to_dyn(&self) -> VariantType<Interned<dyn DynType>> {
 | 
					 | 
				
			||||||
        self.as_ref_ty().map_ty(T::to_dyn)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn canonical_dyn(&self) -> VariantType<Interned<dyn DynCanonicalType>> {
 | 
					 | 
				
			||||||
        self.as_ref_ty().map_ty(T::canonical_dyn)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl VariantType<Interned<dyn DynCanonicalType>> {
 | 
					 | 
				
			||||||
    pub fn from_canonical_type_helper_has_value<T: Type>(self, expected_name: &str) -> T {
 | 
					 | 
				
			||||||
        assert_eq!(&*self.name, expected_name, "variant name doesn't match");
 | 
					 | 
				
			||||||
        let Some(ty) = self.ty else {
 | 
					 | 
				
			||||||
            panic!("variant {expected_name} has no value but a value is expected");
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        T::from_dyn_canonical_type(ty)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn from_canonical_type_helper_no_value(self, expected_name: &str) {
 | 
					 | 
				
			||||||
        assert_eq!(&*self.name, expected_name, "variant name doesn't match");
 | 
					 | 
				
			||||||
        assert!(
 | 
					 | 
				
			||||||
            self.ty.is_none(),
 | 
					 | 
				
			||||||
            "variant {expected_name} has a value but is expected to have no value"
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Eq)]
 | 
					#[derive(Clone, Eq)]
 | 
				
			||||||
struct DynEnumTypeImpl {
 | 
					struct EnumImpl {
 | 
				
			||||||
    variants: Interned<[VariantType<Interned<dyn DynCanonicalType>>]>,
 | 
					    variants: Interned<[EnumVariant]>,
 | 
				
			||||||
    name_indexes: HashMap<Interned<str>, usize>,
 | 
					    name_indexes: HashMap<Interned<str>, usize>,
 | 
				
			||||||
    bit_width: usize,
 | 
					    type_properties: TypeProperties,
 | 
				
			||||||
    is_storable: bool,
 | 
					 | 
				
			||||||
    is_castable_from_bits: bool,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl fmt::Debug for DynEnumTypeImpl {
 | 
					impl std::fmt::Debug for EnumImpl {
 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
        write!(f, "DynEnumType ")?;
 | 
					        f.debug_struct("Enum")
 | 
				
			||||||
        f.debug_set()
 | 
					            .field("variants", &self.variants)
 | 
				
			||||||
            .entries(
 | 
					            .field("name_indexes", &self.name_indexes)
 | 
				
			||||||
                self.variants
 | 
					            .field("type_properties", &self.type_properties)
 | 
				
			||||||
                    .iter()
 | 
					 | 
				
			||||||
                    .map(|variant| variant.fmt_debug_in_enum()),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .finish()
 | 
					            .finish()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl PartialEq for DynEnumTypeImpl {
 | 
					impl std::hash::Hash for EnumImpl {
 | 
				
			||||||
 | 
					    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
 | 
				
			||||||
 | 
					        self.variants.hash(state);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl PartialEq for EnumImpl {
 | 
				
			||||||
    fn eq(&self, other: &Self) -> bool {
 | 
					    fn eq(&self, other: &Self) -> bool {
 | 
				
			||||||
        self.variants == other.variants
 | 
					        self.variants == other.variants
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Hash for DynEnumTypeImpl {
 | 
					#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 | 
				
			||||||
    fn hash<H: Hasher>(&self, state: &mut H) {
 | 
					pub struct Enum(Interned<EnumImpl>);
 | 
				
			||||||
        self.variants.hash(state);
 | 
					
 | 
				
			||||||
 | 
					const fn discriminant_bit_width_impl(variant_count: usize) -> usize {
 | 
				
			||||||
 | 
					    match variant_count.next_power_of_two().checked_ilog2() {
 | 
				
			||||||
 | 
					        Some(x) => x as usize,
 | 
				
			||||||
 | 
					        None => 0,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
 | 
					#[derive(Clone)]
 | 
				
			||||||
pub struct DynEnumType(Interned<DynEnumTypeImpl>);
 | 
					pub struct EnumTypePropertiesBuilder {
 | 
				
			||||||
 | 
					    type_properties: TypeProperties,
 | 
				
			||||||
impl fmt::Debug for DynEnumType {
 | 
					    variant_count: usize,
 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        self.0.fmt(f)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn discriminant_bit_width_impl(variant_count: usize) -> usize {
 | 
					impl EnumTypePropertiesBuilder {
 | 
				
			||||||
    variant_count
 | 
					    #[must_use]
 | 
				
			||||||
        .next_power_of_two()
 | 
					    pub const fn new() -> Self {
 | 
				
			||||||
        .checked_ilog2()
 | 
					        Self {
 | 
				
			||||||
        .unwrap_or(0) as usize
 | 
					            type_properties: TypeProperties {
 | 
				
			||||||
}
 | 
					                is_passive: true,
 | 
				
			||||||
 | 
					                is_storable: true,
 | 
				
			||||||
impl DynEnumType {
 | 
					                is_castable_from_bits: true,
 | 
				
			||||||
    #[track_caller]
 | 
					                bit_width: 0,
 | 
				
			||||||
    pub fn new(variants: Interned<[VariantType<Interned<dyn DynCanonicalType>>]>) -> Self {
 | 
					            },
 | 
				
			||||||
        assert!(!variants.is_empty(), "zero-variant enums aren't yet supported: https://github.com/chipsalliance/firrtl-spec/issues/208");
 | 
					            variant_count: 0,
 | 
				
			||||||
        let mut name_indexes = HashMap::with_capacity(variants.len());
 | 
					 | 
				
			||||||
        let mut body_bit_width = 0usize;
 | 
					 | 
				
			||||||
        let mut is_storable = true;
 | 
					 | 
				
			||||||
        let mut is_castable_from_bits = true;
 | 
					 | 
				
			||||||
        for (index, &VariantType { name, ty }) in variants.iter().enumerate() {
 | 
					 | 
				
			||||||
            if let Some(old_index) = name_indexes.insert(name, index) {
 | 
					 | 
				
			||||||
                panic!("duplicate variant name {name:?}: at both index {old_index} and {index}");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if let Some(ty) = ty {
 | 
					 | 
				
			||||||
                assert!(
 | 
					 | 
				
			||||||
                    ty.is_passive(),
 | 
					 | 
				
			||||||
                    "variant type must be a passive type: {ty:?}"
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                body_bit_width = body_bit_width.max(ty.bit_width());
 | 
					 | 
				
			||||||
                is_storable &= ty.is_storable();
 | 
					 | 
				
			||||||
                is_castable_from_bits &= ty.is_castable_from_bits();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        let bit_width = body_bit_width
 | 
					    pub const fn clone(&self) -> Self {
 | 
				
			||||||
            .checked_add(discriminant_bit_width_impl(variants.len()))
 | 
					        Self { ..*self }
 | 
				
			||||||
            .unwrap_or_else(|| panic!("enum is too big: bit-width overflowed"));
 | 
					    }
 | 
				
			||||||
        Self(
 | 
					    #[must_use]
 | 
				
			||||||
            DynEnumTypeImpl {
 | 
					    pub const fn variant(self, field_props: Option<TypeProperties>) -> Self {
 | 
				
			||||||
                variants,
 | 
					        let Self {
 | 
				
			||||||
                name_indexes,
 | 
					            mut type_properties,
 | 
				
			||||||
                bit_width,
 | 
					            variant_count,
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					        if let Some(TypeProperties {
 | 
				
			||||||
 | 
					            is_passive,
 | 
				
			||||||
            is_storable,
 | 
					            is_storable,
 | 
				
			||||||
            is_castable_from_bits,
 | 
					            is_castable_from_bits,
 | 
				
			||||||
 | 
					            bit_width,
 | 
				
			||||||
 | 
					        }) = field_props
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            assert!(is_passive, "variant type must be a passive type");
 | 
				
			||||||
 | 
					            type_properties = TypeProperties {
 | 
				
			||||||
 | 
					                is_passive: true,
 | 
				
			||||||
 | 
					                is_storable: type_properties.is_storable & is_storable,
 | 
				
			||||||
 | 
					                is_castable_from_bits: type_properties.is_castable_from_bits
 | 
				
			||||||
 | 
					                    & is_castable_from_bits,
 | 
				
			||||||
 | 
					                bit_width: if type_properties.bit_width < bit_width {
 | 
				
			||||||
 | 
					                    bit_width
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    type_properties.bit_width
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            type_properties,
 | 
				
			||||||
 | 
					            variant_count: variant_count + 1,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub const fn finish(self) -> TypeProperties {
 | 
				
			||||||
 | 
					        assert!(
 | 
				
			||||||
 | 
					            self.variant_count != 0,
 | 
				
			||||||
 | 
					            "zero-variant enums aren't yet supported: \
 | 
				
			||||||
 | 
					            https://github.com/chipsalliance/firrtl-spec/issues/208",
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        let Some(bit_width) = self
 | 
				
			||||||
 | 
					            .type_properties
 | 
				
			||||||
 | 
					            .bit_width
 | 
				
			||||||
 | 
					            .checked_add(discriminant_bit_width_impl(self.variant_count))
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            panic!("enum is too big: bit-width overflowed");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        TypeProperties {
 | 
				
			||||||
 | 
					            bit_width,
 | 
				
			||||||
 | 
					            ..self.type_properties
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Enum {
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn new(variants: Interned<[EnumVariant]>) -> Self {
 | 
				
			||||||
 | 
					        let mut name_indexes = HashMap::with_capacity(variants.len());
 | 
				
			||||||
 | 
					        let mut type_props_builder = EnumTypePropertiesBuilder::new();
 | 
				
			||||||
 | 
					        for (index, EnumVariant { name, ty }) in variants.iter().enumerate() {
 | 
				
			||||||
 | 
					            if let Some(old_index) = name_indexes.insert(*name, index) {
 | 
				
			||||||
 | 
					                panic!("duplicate variant name {name:?}: at both index {old_index} and {index}");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            type_props_builder = type_props_builder.variant(ty.map(CanonicalType::type_properties));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Self(
 | 
				
			||||||
 | 
					            EnumImpl {
 | 
				
			||||||
 | 
					                variants,
 | 
				
			||||||
 | 
					                name_indexes,
 | 
				
			||||||
 | 
					                type_properties: type_props_builder.finish(),
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            .intern_sized(),
 | 
					            .intern_sized(),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
| 
						 | 
					@ -192,233 +157,62 @@ impl DynEnumType {
 | 
				
			||||||
    pub fn discriminant_bit_width(self) -> usize {
 | 
					    pub fn discriminant_bit_width(self) -> usize {
 | 
				
			||||||
        discriminant_bit_width_impl(self.variants().len())
 | 
					        discriminant_bit_width_impl(self.variants().len())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn is_passive(self) -> bool {
 | 
					    pub fn type_properties(self) -> TypeProperties {
 | 
				
			||||||
        true
 | 
					        self.0.type_properties
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn is_storable(self) -> bool {
 | 
					 | 
				
			||||||
        self.0.is_storable
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn is_castable_from_bits(self) -> bool {
 | 
					 | 
				
			||||||
        self.0.is_castable_from_bits
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn bit_width(self) -> usize {
 | 
					 | 
				
			||||||
        self.0.bit_width
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn name_indexes(&self) -> &HashMap<Interned<str>, usize> {
 | 
					    pub fn name_indexes(&self) -> &HashMap<Interned<str>, usize> {
 | 
				
			||||||
        &self.0.name_indexes
 | 
					        &self.0.name_indexes
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					    pub fn can_connect(self, rhs: Self) -> bool {
 | 
				
			||||||
 | 
					        if self.0.variants.len() != rhs.0.variants.len() {
 | 
				
			||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 | 
					            return false;
 | 
				
			||||||
pub struct DynEnum {
 | 
					        }
 | 
				
			||||||
    ty: DynEnumType,
 | 
					        for (
 | 
				
			||||||
    variant_index: usize,
 | 
					            &EnumVariant {
 | 
				
			||||||
    variant_value: Option<DynCanonicalValue>,
 | 
					                name: lhs_name,
 | 
				
			||||||
}
 | 
					                ty: lhs_ty,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
impl DynEnum {
 | 
					            &EnumVariant {
 | 
				
			||||||
    #[track_caller]
 | 
					                name: rhs_name,
 | 
				
			||||||
    pub fn new_by_index(
 | 
					                ty: rhs_ty,
 | 
				
			||||||
        ty: DynEnumType,
 | 
					            },
 | 
				
			||||||
        variant_index: usize,
 | 
					        ) in self.0.variants.iter().zip(rhs.0.variants.iter())
 | 
				
			||||||
        variant_value: Option<DynCanonicalValue>,
 | 
					        {
 | 
				
			||||||
    ) -> Self {
 | 
					            if lhs_name != rhs_name {
 | 
				
			||||||
        let variant = ty.variants()[variant_index];
 | 
					                return false;
 | 
				
			||||||
        assert_eq!(
 | 
					            }
 | 
				
			||||||
            variant_value.as_ref().map(|v| v.ty()),
 | 
					            match (lhs_ty, rhs_ty) {
 | 
				
			||||||
            variant.ty,
 | 
					                (None, None) => {}
 | 
				
			||||||
            "variant value doesn't match type"
 | 
					                (None, Some(_)) | (Some(_), None) => return false,
 | 
				
			||||||
        );
 | 
					                (Some(lhs_ty), Some(rhs_ty)) => {
 | 
				
			||||||
        Self {
 | 
					                    if !lhs_ty.can_connect(rhs_ty) {
 | 
				
			||||||
            ty,
 | 
					                        return false;
 | 
				
			||||||
            variant_index,
 | 
					 | 
				
			||||||
            variant_value,
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
    #[track_caller]
 | 
					 | 
				
			||||||
    pub fn new_by_name(
 | 
					 | 
				
			||||||
        ty: DynEnumType,
 | 
					 | 
				
			||||||
        variant_name: Interned<str>,
 | 
					 | 
				
			||||||
        variant_value: Option<DynCanonicalValue>,
 | 
					 | 
				
			||||||
    ) -> Self {
 | 
					 | 
				
			||||||
        let variant_index = ty.name_indexes()[&variant_name];
 | 
					 | 
				
			||||||
        Self::new_by_index(ty, variant_index, variant_value)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn variant_index(&self) -> usize {
 | 
					 | 
				
			||||||
        self.variant_index
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn variant_value(&self) -> &Option<DynCanonicalValue> {
 | 
					 | 
				
			||||||
        &self.variant_value
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn variant_with_type(&self) -> VariantType<Interned<dyn DynCanonicalType>> {
 | 
					 | 
				
			||||||
        self.ty.variants()[self.variant_index]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn variant_name(&self) -> Interned<str> {
 | 
					 | 
				
			||||||
        self.variant_with_type().name
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn variant_type(&self) -> Option<Interned<dyn DynCanonicalType>> {
 | 
					 | 
				
			||||||
        self.variant_with_type().ty
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn variant_with_value(&self) -> VariantType<&DynCanonicalValue> {
 | 
					 | 
				
			||||||
        self.variant_with_type()
 | 
					 | 
				
			||||||
            .map_opt_ty(|_| self.variant_value.as_ref())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
 | 
					 | 
				
			||||||
pub struct VariantsHint {
 | 
					 | 
				
			||||||
    pub known_variants: Interned<[VariantType<Interned<dyn TypeHintTrait>>]>,
 | 
					 | 
				
			||||||
    pub more_variants: bool,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl VariantsHint {
 | 
					 | 
				
			||||||
    pub fn new(
 | 
					 | 
				
			||||||
        known_variants: impl IntoIterator<Item = VariantType<Interned<dyn TypeHintTrait>>>,
 | 
					 | 
				
			||||||
        more_variants: bool,
 | 
					 | 
				
			||||||
    ) -> Self {
 | 
					 | 
				
			||||||
        let known_variants = Intern::intern_owned(Vec::from_iter(known_variants));
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
            known_variants,
 | 
					 | 
				
			||||||
            more_variants,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn check_variant(
 | 
					 | 
				
			||||||
        self,
 | 
					 | 
				
			||||||
        index: usize,
 | 
					 | 
				
			||||||
        variant: VariantType<&dyn DynType>,
 | 
					 | 
				
			||||||
    ) -> Result<(), String> {
 | 
					 | 
				
			||||||
        let Some(&known_variant) = self.known_variants.get(index) else {
 | 
					 | 
				
			||||||
            return if self.more_variants {
 | 
					 | 
				
			||||||
                Ok(())
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                Err(format!(
 | 
					 | 
				
			||||||
                    "too many variants: name={:?} index={index}",
 | 
					 | 
				
			||||||
                    variant.name
 | 
					 | 
				
			||||||
                ))
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        let VariantType {
 | 
					 | 
				
			||||||
            name: known_name,
 | 
					 | 
				
			||||||
            ty: type_hint,
 | 
					 | 
				
			||||||
        } = known_variant;
 | 
					 | 
				
			||||||
        let VariantType { name, ty } = variant;
 | 
					 | 
				
			||||||
        if name != known_name {
 | 
					 | 
				
			||||||
            Err(format!(
 | 
					 | 
				
			||||||
                "wrong variant name {name:?}, expected {known_name:?}"
 | 
					 | 
				
			||||||
            ))
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            match (ty, type_hint) {
 | 
					 | 
				
			||||||
                (Some(ty), Some(type_hint)) => type_hint.matches(ty),
 | 
					 | 
				
			||||||
                (None, None) => Ok(()),
 | 
					 | 
				
			||||||
                (None, Some(_)) => Err(format!(
 | 
					 | 
				
			||||||
                    "expected variant {name:?} to have type, no type provided"
 | 
					 | 
				
			||||||
                )),
 | 
					 | 
				
			||||||
                (Some(_), None) => Err(format!(
 | 
					 | 
				
			||||||
                    "expected variant {name:?} to have no type, but a type was provided"
 | 
					 | 
				
			||||||
                )),
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait EnumType:
 | 
					pub trait EnumType:
 | 
				
			||||||
    Type<
 | 
					    Type<
 | 
				
			||||||
        CanonicalType = DynEnumType,
 | 
					    BaseType = Enum,
 | 
				
			||||||
        CanonicalValue = DynEnum,
 | 
					    MaskType = Bool,
 | 
				
			||||||
        MaskType = UIntType<1>,
 | 
					 | 
				
			||||||
        MaskValue = UInt<1>,
 | 
					 | 
				
			||||||
    MatchActiveScope = Scope,
 | 
					    MatchActiveScope = Scope,
 | 
				
			||||||
    MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>,
 | 
					    MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>,
 | 
				
			||||||
    MatchVariantsIter = EnumMatchVariantsIter<Self>,
 | 
					    MatchVariantsIter = EnumMatchVariantsIter<Self>,
 | 
				
			||||||
    > + Connect<Self>
 | 
					>
 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    Self::Value: EnumValue + ToExpr<Type = Self>,
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    type Builder;
 | 
					    fn variants(&self) -> Interned<[EnumVariant]>;
 | 
				
			||||||
    fn match_activate_scope(
 | 
					    fn match_activate_scope(
 | 
				
			||||||
        v: Self::MatchVariantAndInactiveScope,
 | 
					        v: Self::MatchVariantAndInactiveScope,
 | 
				
			||||||
    ) -> (Self::MatchVariant, Self::MatchActiveScope);
 | 
					    ) -> (Self::MatchVariant, Self::MatchActiveScope);
 | 
				
			||||||
    fn builder() -> Self::Builder;
 | 
					 | 
				
			||||||
    fn variants(&self) -> Interned<[VariantType<Interned<dyn DynCanonicalType>>]>;
 | 
					 | 
				
			||||||
    fn variants_hint() -> VariantsHint;
 | 
					 | 
				
			||||||
    #[allow(clippy::result_unit_err)]
 | 
					 | 
				
			||||||
    fn variant_to_bits<VariantValue: ToExpr + Eq + Hash + Send + Sync + 'static + Clone>(
 | 
					 | 
				
			||||||
        &self,
 | 
					 | 
				
			||||||
        variant_index: usize,
 | 
					 | 
				
			||||||
        variant_value: Option<&VariantValue>,
 | 
					 | 
				
			||||||
    ) -> Result<Interned<BitSlice>, ()> {
 | 
					 | 
				
			||||||
        #[derive(Hash, Eq, PartialEq)]
 | 
					 | 
				
			||||||
        struct VariantToBitsMemoize<E, V>(PhantomData<(E, V)>);
 | 
					 | 
				
			||||||
        impl<E, V> Clone for VariantToBitsMemoize<E, V> {
 | 
					 | 
				
			||||||
            fn clone(&self) -> Self {
 | 
					 | 
				
			||||||
                *self
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        impl<E, V> Copy for VariantToBitsMemoize<E, V> {}
 | 
					 | 
				
			||||||
        impl<
 | 
					 | 
				
			||||||
                E: EnumType<Value: EnumValue<Type = E>>,
 | 
					 | 
				
			||||||
                V: ToExpr + Eq + Hash + Send + Sync + 'static + Clone,
 | 
					 | 
				
			||||||
            > MemoizeGeneric for VariantToBitsMemoize<E, V>
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            type InputRef<'a> = (&'a E, usize, Option<&'a V>);
 | 
					 | 
				
			||||||
            type InputOwned = (E, usize, Option<V>);
 | 
					 | 
				
			||||||
            type InputCow<'a> = (Cow<'a, E>, usize, Option<Cow<'a, V>>);
 | 
					 | 
				
			||||||
            type Output = Result<Interned<BitSlice>, ()>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
 | 
					 | 
				
			||||||
                (&input.0, input.1, input.2.as_ref())
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool {
 | 
					 | 
				
			||||||
                a == b
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned {
 | 
					 | 
				
			||||||
                (input.0.into_owned(), input.1, input.2.map(Cow::into_owned))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> {
 | 
					 | 
				
			||||||
                (&input.0, input.1, input.2.as_deref())
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> {
 | 
					 | 
				
			||||||
                (Cow::Owned(input.0), input.1, input.2.map(Cow::Owned))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> {
 | 
					 | 
				
			||||||
                (Cow::Borrowed(input.0), input.1, input.2.map(Cow::Borrowed))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            fn inner(self, input: Self::InputRef<'_>) -> Self::Output {
 | 
					 | 
				
			||||||
                let (ty, variant_index, variant_value) = input;
 | 
					 | 
				
			||||||
                let ty = ty.canonical();
 | 
					 | 
				
			||||||
                let mut bits = BitVec::with_capacity(ty.bit_width());
 | 
					 | 
				
			||||||
                bits.extend_from_bitslice(
 | 
					 | 
				
			||||||
                    &variant_index.view_bits::<Lsb0>()[..ty.discriminant_bit_width()],
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                if let Some(variant_value) = variant_value {
 | 
					 | 
				
			||||||
                    bits.extend_from_bitslice(&variant_value.to_expr().to_literal_bits()?);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                bits.resize(ty.bit_width(), false);
 | 
					 | 
				
			||||||
                Ok(Intern::intern_owned(bits))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        VariantToBitsMemoize::<Self, VariantValue>(PhantomData).get((
 | 
					 | 
				
			||||||
            self,
 | 
					 | 
				
			||||||
            variant_index,
 | 
					 | 
				
			||||||
            variant_value,
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait EnumValue: Value
 | 
					pub struct EnumMatchVariantAndInactiveScope<T: EnumType>(EnumMatchVariantAndInactiveScopeImpl<T>);
 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    <Self as ToExpr>::Type: EnumType<Value = Self>,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct EnumMatchVariantAndInactiveScope<T: EnumType>(EnumMatchVariantAndInactiveScopeImpl<T>)
 | 
					impl<T: EnumType> MatchVariantAndInactiveScope for EnumMatchVariantAndInactiveScope<T> {
 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    T::Value: EnumValue<Type = T>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T: EnumType> MatchVariantAndInactiveScope for EnumMatchVariantAndInactiveScope<T>
 | 
					 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    T::Value: EnumValue<Type = T>,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    type MatchVariant = T::MatchVariant;
 | 
					    type MatchVariant = T::MatchVariant;
 | 
				
			||||||
    type MatchActiveScope = Scope;
 | 
					    type MatchActiveScope = Scope;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -427,36 +221,22 @@ where
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: EnumType> EnumMatchVariantAndInactiveScope<T>
 | 
					impl<T: EnumType> EnumMatchVariantAndInactiveScope<T> {
 | 
				
			||||||
where
 | 
					    pub fn variant_access(&self) -> VariantAccess {
 | 
				
			||||||
    T::Value: EnumValue<Type = T>,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    pub fn variant_access(&self) -> Interned<VariantAccess<T, Interned<dyn DynCanonicalType>>> {
 | 
					 | 
				
			||||||
        self.0.variant_access()
 | 
					        self.0.variant_access()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn activate(
 | 
					    pub fn activate(self) -> (VariantAccess, Scope) {
 | 
				
			||||||
        self,
 | 
					 | 
				
			||||||
    ) -> (
 | 
					 | 
				
			||||||
        Interned<VariantAccess<T, Interned<dyn DynCanonicalType>>>,
 | 
					 | 
				
			||||||
        Scope,
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        self.0.activate()
 | 
					        self.0.activate()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone)]
 | 
				
			||||||
pub struct EnumMatchVariantsIter<T: EnumType>
 | 
					pub struct EnumMatchVariantsIter<T: EnumType> {
 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    T::Value: EnumValue<Type = T>,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    pub(crate) inner: EnumMatchVariantsIterImpl<T>,
 | 
					    pub(crate) inner: EnumMatchVariantsIterImpl<T>,
 | 
				
			||||||
    pub(crate) variant_index: std::ops::Range<usize>,
 | 
					    pub(crate) variant_index: std::ops::Range<usize>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: EnumType> Iterator for EnumMatchVariantsIter<T>
 | 
					impl<T: EnumType> Iterator for EnumMatchVariantsIter<T> {
 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    T::Value: EnumValue<Type = T>,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    type Item = EnumMatchVariantAndInactiveScope<T>;
 | 
					    type Item = EnumMatchVariantAndInactiveScope<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
					    fn next(&mut self) -> Option<Self::Item> {
 | 
				
			||||||
| 
						 | 
					@ -470,21 +250,15 @@ where
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: EnumType> ExactSizeIterator for EnumMatchVariantsIter<T>
 | 
					impl<T: EnumType> ExactSizeIterator for EnumMatchVariantsIter<T> {
 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    T::Value: EnumValue<Type = T>,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    fn len(&self) -> usize {
 | 
					    fn len(&self) -> usize {
 | 
				
			||||||
        self.variant_index.len()
 | 
					        self.variant_index.len()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: EnumType> FusedIterator for EnumMatchVariantsIter<T> where T::Value: EnumValue<Type = T> {}
 | 
					impl<T: EnumType> FusedIterator for EnumMatchVariantsIter<T> {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: EnumType> DoubleEndedIterator for EnumMatchVariantsIter<T>
 | 
					impl<T: EnumType> DoubleEndedIterator for EnumMatchVariantsIter<T> {
 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    T::Value: EnumValue<Type = T>,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    fn next_back(&mut self) -> Option<Self::Item> {
 | 
					    fn next_back(&mut self) -> Option<Self::Item> {
 | 
				
			||||||
        self.variant_index.next_back().map(|variant_index| {
 | 
					        self.variant_index.next_back().map(|variant_index| {
 | 
				
			||||||
            EnumMatchVariantAndInactiveScope(self.inner.for_variant_index(variant_index))
 | 
					            EnumMatchVariantAndInactiveScope(self.inner.for_variant_index(variant_index))
 | 
				
			||||||
| 
						 | 
					@ -492,129 +266,56 @@ where
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Type for DynEnumType {
 | 
					impl EnumType for Enum {
 | 
				
			||||||
    type CanonicalType = DynEnumType;
 | 
					 | 
				
			||||||
    type Value = DynEnum;
 | 
					 | 
				
			||||||
    type CanonicalValue = DynEnum;
 | 
					 | 
				
			||||||
    type MaskType = UIntType<1>;
 | 
					 | 
				
			||||||
    type MaskValue = UInt<1>;
 | 
					 | 
				
			||||||
    type MatchVariant = Option<Expr<DynCanonicalValue>>;
 | 
					 | 
				
			||||||
    type MatchActiveScope = Scope;
 | 
					 | 
				
			||||||
    type MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>;
 | 
					 | 
				
			||||||
    type MatchVariantsIter = EnumMatchVariantsIter<Self>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn match_variants<IO: BundleValue>(
 | 
					 | 
				
			||||||
        this: Expr<Self::Value>,
 | 
					 | 
				
			||||||
        module_builder: &mut ModuleBuilder<IO, NormalModule>,
 | 
					 | 
				
			||||||
        source_location: SourceLocation,
 | 
					 | 
				
			||||||
    ) -> Self::MatchVariantsIter
 | 
					 | 
				
			||||||
    where
 | 
					 | 
				
			||||||
        IO::Type: crate::bundle::BundleType<Value = IO>,
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        module_builder.enum_match_variants_helper(this, source_location)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn mask_type(&self) -> Self::MaskType {
 | 
					 | 
				
			||||||
        UIntType::new()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn canonical(&self) -> Self::CanonicalType {
 | 
					 | 
				
			||||||
        *self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn source_location(&self) -> SourceLocation {
 | 
					 | 
				
			||||||
        SourceLocation::builtin()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn type_enum(&self) -> TypeEnum {
 | 
					 | 
				
			||||||
        TypeEnum::EnumType(*self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn from_canonical_type(t: Self::CanonicalType) -> Self {
 | 
					 | 
				
			||||||
        t
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> {
 | 
					 | 
				
			||||||
        Some(this)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Connect<Self> for DynEnumType {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub struct NoBuilder;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl EnumType for DynEnumType {
 | 
					 | 
				
			||||||
    type Builder = NoBuilder;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn match_activate_scope(
 | 
					    fn match_activate_scope(
 | 
				
			||||||
        v: Self::MatchVariantAndInactiveScope,
 | 
					        v: Self::MatchVariantAndInactiveScope,
 | 
				
			||||||
    ) -> (Self::MatchVariant, Self::MatchActiveScope) {
 | 
					    ) -> (Self::MatchVariant, Self::MatchActiveScope) {
 | 
				
			||||||
        let (expr, scope) = v.0.activate();
 | 
					        let (expr, scope) = v.0.activate();
 | 
				
			||||||
        (expr.variant_type().ty.map(|_| expr.to_expr()), scope)
 | 
					        (expr.variant_type().map(|_| expr.to_expr()), scope)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    fn variants(&self) -> Interned<[EnumVariant]> {
 | 
				
			||||||
    fn builder() -> Self::Builder {
 | 
					 | 
				
			||||||
        NoBuilder
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn variants(&self) -> Interned<[VariantType<Interned<dyn DynCanonicalType>>]> {
 | 
					 | 
				
			||||||
        self.0.variants
 | 
					        self.0.variants
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn variants_hint() -> VariantsHint {
 | 
					impl Type for Enum {
 | 
				
			||||||
        VariantsHint {
 | 
					    type BaseType = Enum;
 | 
				
			||||||
            known_variants: [][..].intern(),
 | 
					    type MaskType = Bool;
 | 
				
			||||||
            more_variants: true,
 | 
					    type MatchVariant = Option<Expr<CanonicalType>>;
 | 
				
			||||||
 | 
					    type MatchActiveScope = Scope;
 | 
				
			||||||
 | 
					    type MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>;
 | 
				
			||||||
 | 
					    type MatchVariantsIter = EnumMatchVariantsIter<Self>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn match_variants(
 | 
				
			||||||
 | 
					        this: Expr<Self>,
 | 
				
			||||||
 | 
					        module_builder: &mut ModuleBuilder<NormalModule>,
 | 
				
			||||||
 | 
					        source_location: crate::source_location::SourceLocation,
 | 
				
			||||||
 | 
					    ) -> Self::MatchVariantsIter {
 | 
				
			||||||
 | 
					        module_builder.enum_match_variants_helper(this, source_location)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn mask_type(&self) -> Self::MaskType {
 | 
				
			||||||
 | 
					        Bool
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn canonical(&self) -> CanonicalType {
 | 
				
			||||||
 | 
					        CanonicalType::Enum(*self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    fn from_canonical(canonical_type: CanonicalType) -> Self {
 | 
				
			||||||
 | 
					        let CanonicalType::Enum(retval) = canonical_type else {
 | 
				
			||||||
 | 
					            panic!("expected enum");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        retval
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn source_location() -> SourceLocation {
 | 
				
			||||||
 | 
					        SourceLocation::builtin()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl CanonicalType for DynEnumType {
 | 
					#[hdl]
 | 
				
			||||||
    const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::EnumType;
 | 
					pub enum HdlOption<T: Type> {
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ToExpr for DynEnum {
 | 
					 | 
				
			||||||
    type Type = DynEnumType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					 | 
				
			||||||
        self.ty
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
					 | 
				
			||||||
        Expr::from_value(self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Value for DynEnum {
 | 
					 | 
				
			||||||
    fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
 | 
					 | 
				
			||||||
        self.clone()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        this.ty
 | 
					 | 
				
			||||||
            .variant_to_bits(this.variant_index, this.variant_value.as_ref())
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl EnumValue for DynEnum {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl CanonicalValue for DynEnum {
 | 
					 | 
				
			||||||
    fn value_enum_impl(this: &Self) -> ValueEnum {
 | 
					 | 
				
			||||||
        ValueEnum::Enum(this.clone())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        this.ty
 | 
					 | 
				
			||||||
            .variant_to_bits(this.variant_index, this.variant_value.as_ref())
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mod impl_option {
 | 
					 | 
				
			||||||
    #[allow(dead_code)]
 | 
					 | 
				
			||||||
    #[derive(crate::ty::Value)]
 | 
					 | 
				
			||||||
    #[hdl(target(std::option::Option), connect_inexact, outline_generated)]
 | 
					 | 
				
			||||||
    pub enum Option<T> {
 | 
					 | 
				
			||||||
    None,
 | 
					    None,
 | 
				
			||||||
    Some(T),
 | 
					    Some(T),
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										432
									
								
								crates/fayalite/src/expr/target.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										432
									
								
								crates/fayalite/src/expr/target.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,432 @@
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    array::Array,
 | 
				
			||||||
 | 
					    bundle::{Bundle, BundleField},
 | 
				
			||||||
 | 
					    expr::Flow,
 | 
				
			||||||
 | 
					    intern::{Intern, Interned},
 | 
				
			||||||
 | 
					    memory::{DynPortType, MemPort},
 | 
				
			||||||
 | 
					    module::{Instance, ModuleIO, TargetName},
 | 
				
			||||||
 | 
					    reg::Reg,
 | 
				
			||||||
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
 | 
					    ty::{CanonicalType, Type},
 | 
				
			||||||
 | 
					    wire::Wire,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use std::fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
 | 
					pub struct TargetPathBundleField {
 | 
				
			||||||
 | 
					    pub name: Interned<str>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for TargetPathBundleField {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, ".{}", self.name)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
 | 
					pub struct TargetPathArrayElement {
 | 
				
			||||||
 | 
					    pub index: usize,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for TargetPathArrayElement {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "[{}]", self.index)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
 | 
					pub struct TargetPathDynArrayElement {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for TargetPathDynArrayElement {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "[<dyn>]")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
 | 
					pub enum TargetPathElement {
 | 
				
			||||||
 | 
					    BundleField(TargetPathBundleField),
 | 
				
			||||||
 | 
					    ArrayElement(TargetPathArrayElement),
 | 
				
			||||||
 | 
					    DynArrayElement(TargetPathDynArrayElement),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<TargetPathBundleField> for TargetPathElement {
 | 
				
			||||||
 | 
					    fn from(value: TargetPathBundleField) -> Self {
 | 
				
			||||||
 | 
					        Self::BundleField(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<TargetPathArrayElement> for TargetPathElement {
 | 
				
			||||||
 | 
					    fn from(value: TargetPathArrayElement) -> Self {
 | 
				
			||||||
 | 
					        Self::ArrayElement(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<TargetPathDynArrayElement> for TargetPathElement {
 | 
				
			||||||
 | 
					    fn from(value: TargetPathDynArrayElement) -> Self {
 | 
				
			||||||
 | 
					        Self::DynArrayElement(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for TargetPathElement {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::BundleField(v) => v.fmt(f),
 | 
				
			||||||
 | 
					            Self::ArrayElement(v) => v.fmt(f),
 | 
				
			||||||
 | 
					            Self::DynArrayElement(v) => v.fmt(f),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl TargetPathElement {
 | 
				
			||||||
 | 
					    pub fn canonical_ty(&self, parent: Interned<Target>) -> CanonicalType {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            &Self::BundleField(TargetPathBundleField { name }) => {
 | 
				
			||||||
 | 
					                let parent_ty = Bundle::from_canonical(parent.canonical_ty());
 | 
				
			||||||
 | 
					                let field = parent_ty
 | 
				
			||||||
 | 
					                    .field_by_name(name)
 | 
				
			||||||
 | 
					                    .expect("field name is known to be a valid field of parent type");
 | 
				
			||||||
 | 
					                field.ty
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            &Self::ArrayElement(TargetPathArrayElement { index }) => {
 | 
				
			||||||
 | 
					                let parent_ty = Array::<CanonicalType>::from_canonical(parent.canonical_ty());
 | 
				
			||||||
 | 
					                assert!(index < parent_ty.len());
 | 
				
			||||||
 | 
					                parent_ty.element()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Self::DynArrayElement(_) => {
 | 
				
			||||||
 | 
					                let parent_ty = Array::<CanonicalType>::from_canonical(parent.canonical_ty());
 | 
				
			||||||
 | 
					                parent_ty.element()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn flow(&self, parent: Interned<Target>) -> Flow {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::BundleField(v) => {
 | 
				
			||||||
 | 
					                let parent_ty = Bundle::from_canonical(parent.canonical_ty());
 | 
				
			||||||
 | 
					                let field = parent_ty
 | 
				
			||||||
 | 
					                    .field_by_name(v.name)
 | 
				
			||||||
 | 
					                    .expect("field name is known to be a valid field of parent type");
 | 
				
			||||||
 | 
					                parent.flow().flip_if(field.flipped)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Self::ArrayElement(_) => parent.flow(),
 | 
				
			||||||
 | 
					            Self::DynArrayElement(_) => parent.flow(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn is_static(&self) -> bool {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::BundleField(_) | Self::ArrayElement(_) => true,
 | 
				
			||||||
 | 
					            Self::DynArrayElement(_) => false,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! impl_target_base {
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					        $(#[$enum_meta:meta])*
 | 
				
			||||||
 | 
					        $enum_vis:vis enum $TargetBase:ident {
 | 
				
			||||||
 | 
					            $(
 | 
				
			||||||
 | 
					                #[is = $is_fn:ident]
 | 
				
			||||||
 | 
					                #[to = $to_fn:ident]
 | 
				
			||||||
 | 
					                $(#[$variant_meta:meta])*
 | 
				
			||||||
 | 
					                $Variant:ident($VariantTy:ty),
 | 
				
			||||||
 | 
					            )*
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ) => {
 | 
				
			||||||
 | 
					        $(#[$enum_meta])*
 | 
				
			||||||
 | 
					        $enum_vis enum $TargetBase {
 | 
				
			||||||
 | 
					            $(
 | 
				
			||||||
 | 
					                $(#[$variant_meta])*
 | 
				
			||||||
 | 
					                $Variant($VariantTy),
 | 
				
			||||||
 | 
					            )*
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl fmt::Debug for $TargetBase {
 | 
				
			||||||
 | 
					            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					                match self {
 | 
				
			||||||
 | 
					                    $(Self::$Variant(v) => v.fmt(f),)*
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $(
 | 
				
			||||||
 | 
					        impl From<$VariantTy> for $TargetBase {
 | 
				
			||||||
 | 
					            fn from(value: $VariantTy) -> Self {
 | 
				
			||||||
 | 
					                Self::$Variant(value)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl From<$VariantTy> for Target {
 | 
				
			||||||
 | 
					            fn from(value: $VariantTy) -> Self {
 | 
				
			||||||
 | 
					                $TargetBase::$Variant(value).into()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        )*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl $TargetBase {
 | 
				
			||||||
 | 
					            $(
 | 
				
			||||||
 | 
					            $enum_vis fn $is_fn(&self) -> bool {
 | 
				
			||||||
 | 
					                self.$to_fn().is_some()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $enum_vis fn $to_fn(&self) -> Option<&$VariantTy> {
 | 
				
			||||||
 | 
					                if let Self::$Variant(retval) = self {
 | 
				
			||||||
 | 
					                    Some(retval)
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            )*
 | 
				
			||||||
 | 
					            $enum_vis fn must_connect_to(&self) -> bool {
 | 
				
			||||||
 | 
					                match self {
 | 
				
			||||||
 | 
					                    $(Self::$Variant(v) => v.must_connect_to(),)*
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $enum_vis fn flow(&self) -> Flow {
 | 
				
			||||||
 | 
					                match self {
 | 
				
			||||||
 | 
					                    $(Self::$Variant(v) => v.flow(),)*
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $enum_vis fn source_location(&self) -> SourceLocation {
 | 
				
			||||||
 | 
					                match self {
 | 
				
			||||||
 | 
					                    $(Self::$Variant(v) => v.source_location(),)*
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl_target_base! {
 | 
				
			||||||
 | 
					    #[derive(Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
 | 
					    pub enum TargetBase {
 | 
				
			||||||
 | 
					        #[is = is_module_io]
 | 
				
			||||||
 | 
					        #[to = module_io]
 | 
				
			||||||
 | 
					        ModuleIO(ModuleIO<CanonicalType>),
 | 
				
			||||||
 | 
					        #[is = is_mem_port]
 | 
				
			||||||
 | 
					        #[to = mem_port]
 | 
				
			||||||
 | 
					        MemPort(MemPort<DynPortType>),
 | 
				
			||||||
 | 
					        #[is = is_reg]
 | 
				
			||||||
 | 
					        #[to = reg]
 | 
				
			||||||
 | 
					        Reg(Reg<CanonicalType>),
 | 
				
			||||||
 | 
					        #[is = is_wire]
 | 
				
			||||||
 | 
					        #[to = wire]
 | 
				
			||||||
 | 
					        Wire(Wire<CanonicalType>),
 | 
				
			||||||
 | 
					        #[is = is_instance]
 | 
				
			||||||
 | 
					        #[to = instance]
 | 
				
			||||||
 | 
					        Instance(Instance<Bundle>),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for TargetBase {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "{:?}", self.target_name())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl TargetBase {
 | 
				
			||||||
 | 
					    pub fn target_name(&self) -> TargetName {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            TargetBase::ModuleIO(v) => TargetName(v.scoped_name(), None),
 | 
				
			||||||
 | 
					            TargetBase::MemPort(v) => TargetName(v.mem_name(), Some(v.port_name())),
 | 
				
			||||||
 | 
					            TargetBase::Reg(v) => TargetName(v.scoped_name(), None),
 | 
				
			||||||
 | 
					            TargetBase::Wire(v) => TargetName(v.scoped_name(), None),
 | 
				
			||||||
 | 
					            TargetBase::Instance(v) => TargetName(v.scoped_name(), None),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn canonical_ty(&self) -> CanonicalType {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            TargetBase::ModuleIO(v) => v.ty(),
 | 
				
			||||||
 | 
					            TargetBase::MemPort(v) => v.ty().canonical(),
 | 
				
			||||||
 | 
					            TargetBase::Reg(v) => v.ty(),
 | 
				
			||||||
 | 
					            TargetBase::Wire(v) => v.ty(),
 | 
				
			||||||
 | 
					            TargetBase::Instance(v) => v.ty().canonical(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
 | 
					pub struct TargetChild {
 | 
				
			||||||
 | 
					    parent: Interned<Target>,
 | 
				
			||||||
 | 
					    path_element: Interned<TargetPathElement>,
 | 
				
			||||||
 | 
					    canonical_ty: CanonicalType,
 | 
				
			||||||
 | 
					    flow: Flow,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Debug for TargetChild {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            parent,
 | 
				
			||||||
 | 
					            path_element,
 | 
				
			||||||
 | 
					            canonical_ty: _,
 | 
				
			||||||
 | 
					            flow: _,
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					        parent.fmt(f)?;
 | 
				
			||||||
 | 
					        fmt::Display::fmt(path_element, f)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for TargetChild {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        let Self {
 | 
				
			||||||
 | 
					            parent,
 | 
				
			||||||
 | 
					            path_element,
 | 
				
			||||||
 | 
					            canonical_ty: _,
 | 
				
			||||||
 | 
					            flow: _,
 | 
				
			||||||
 | 
					        } = self;
 | 
				
			||||||
 | 
					        parent.fmt(f)?;
 | 
				
			||||||
 | 
					        path_element.fmt(f)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl TargetChild {
 | 
				
			||||||
 | 
					    pub fn new(parent: Interned<Target>, path_element: Interned<TargetPathElement>) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            parent,
 | 
				
			||||||
 | 
					            path_element,
 | 
				
			||||||
 | 
					            canonical_ty: path_element.canonical_ty(parent),
 | 
				
			||||||
 | 
					            flow: path_element.flow(parent),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn parent(self) -> Interned<Target> {
 | 
				
			||||||
 | 
					        self.parent
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn path_element(self) -> Interned<TargetPathElement> {
 | 
				
			||||||
 | 
					        self.path_element
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn canonical_ty(self) -> CanonicalType {
 | 
				
			||||||
 | 
					        self.canonical_ty
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn flow(self) -> Flow {
 | 
				
			||||||
 | 
					        self.flow
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn bundle_field(self) -> Option<BundleField> {
 | 
				
			||||||
 | 
					        if let TargetPathElement::BundleField(TargetPathBundleField { name }) = *self.path_element {
 | 
				
			||||||
 | 
					            let parent_ty = Bundle::from_canonical(self.parent.canonical_ty());
 | 
				
			||||||
 | 
					            Some(
 | 
				
			||||||
 | 
					                parent_ty
 | 
				
			||||||
 | 
					                    .field_by_name(name)
 | 
				
			||||||
 | 
					                    .expect("field name known to be a valid field of parent"),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            None
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
 | 
					pub enum Target {
 | 
				
			||||||
 | 
					    Base(Interned<TargetBase>),
 | 
				
			||||||
 | 
					    Child(TargetChild),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<TargetBase> for Target {
 | 
				
			||||||
 | 
					    fn from(value: TargetBase) -> Self {
 | 
				
			||||||
 | 
					        Self::Base(Intern::intern_sized(value))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<TargetChild> for Target {
 | 
				
			||||||
 | 
					    fn from(value: TargetChild) -> Self {
 | 
				
			||||||
 | 
					        Self::Child(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<Interned<TargetBase>> for Target {
 | 
				
			||||||
 | 
					    fn from(value: Interned<TargetBase>) -> Self {
 | 
				
			||||||
 | 
					        Self::Base(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Target {
 | 
				
			||||||
 | 
					    pub fn base(&self) -> Interned<TargetBase> {
 | 
				
			||||||
 | 
					        let mut target = self;
 | 
				
			||||||
 | 
					        loop {
 | 
				
			||||||
 | 
					            match target {
 | 
				
			||||||
 | 
					                Self::Base(v) => break *v,
 | 
				
			||||||
 | 
					                Self::Child(v) => target = &v.parent,
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn child(&self) -> Option<TargetChild> {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Target::Base(_) => None,
 | 
				
			||||||
 | 
					            Target::Child(v) => Some(v),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn is_static(&self) -> bool {
 | 
				
			||||||
 | 
					        let mut target = self;
 | 
				
			||||||
 | 
					        loop {
 | 
				
			||||||
 | 
					            match target {
 | 
				
			||||||
 | 
					                Self::Base(_) => return true,
 | 
				
			||||||
 | 
					                Self::Child(v) if !v.path_element().is_static() => return false,
 | 
				
			||||||
 | 
					                Self::Child(v) => target = &v.parent,
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn join(&self, path_element: Interned<TargetPathElement>) -> Self {
 | 
				
			||||||
 | 
					        TargetChild::new(self.intern(), path_element).into()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn flow(&self) -> Flow {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Base(v) => v.flow(),
 | 
				
			||||||
 | 
					            Self::Child(v) => v.flow(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn canonical_ty(&self) -> CanonicalType {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Target::Base(v) => v.canonical_ty(),
 | 
				
			||||||
 | 
					            Target::Child(v) => v.canonical_ty(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for Target {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Base(v) => v.fmt(f),
 | 
				
			||||||
 | 
					            Self::Child(v) => v.fmt(f),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Debug for Target {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Base(v) => v.fmt(f),
 | 
				
			||||||
 | 
					            Self::Child(v) => v.fmt(f),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait GetTarget {
 | 
				
			||||||
 | 
					    fn target(&self) -> Option<Interned<Target>>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl GetTarget for bool {
 | 
				
			||||||
 | 
					    fn target(&self) -> Option<Interned<Target>> {
 | 
				
			||||||
 | 
					        None
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + GetTarget + Send + Sync + 'static> GetTarget for Interned<T> {
 | 
				
			||||||
 | 
					    fn target(&self) -> Option<Interned<Target>> {
 | 
				
			||||||
 | 
					        T::target(self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + GetTarget> GetTarget for &'_ T {
 | 
				
			||||||
 | 
					    fn target(&self) -> Option<Interned<Target>> {
 | 
				
			||||||
 | 
					        T::target(self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + GetTarget> GetTarget for &'_ mut T {
 | 
				
			||||||
 | 
					    fn target(&self) -> Option<Interned<Target>> {
 | 
				
			||||||
 | 
					        T::target(self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + GetTarget> GetTarget for Box<T> {
 | 
				
			||||||
 | 
					    fn target(&self) -> Option<Interned<Target>> {
 | 
				
			||||||
 | 
					        T::target(self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -22,6 +22,179 @@ use std::{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod type_map;
 | 
					pub mod type_map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait LazyInternedTrait<T: ?Sized + Send + Sync + 'static>: Send + Sync + Any {
 | 
				
			||||||
 | 
					    fn get(&self) -> Interned<T>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Send + Sync + 'static, F: ?Sized + Fn() -> Interned<T> + Send + Sync + Any>
 | 
				
			||||||
 | 
					    LazyInternedTrait<T> for F
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn get(&self) -> Interned<T> {
 | 
				
			||||||
 | 
					        self()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[repr(transparent)]
 | 
				
			||||||
 | 
					pub struct LazyInternedFn<T: ?Sized + Send + Sync + 'static>(pub &'static dyn LazyInternedTrait<T>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Send + Sync + 'static> Copy for LazyInternedFn<T> {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Send + Sync + 'static> Clone for LazyInternedFn<T> {
 | 
				
			||||||
 | 
					    fn clone(&self) -> Self {
 | 
				
			||||||
 | 
					        *self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Send + Sync + 'static> Hash for LazyInternedFn<T> {
 | 
				
			||||||
 | 
					    fn hash<H: Hasher>(&self, state: &mut H) {
 | 
				
			||||||
 | 
					        self.0.get_ptr_eq_with_type_id().hash(state);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Send + Sync + 'static> Eq for LazyInternedFn<T> {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Send + Sync + 'static> PartialEq for LazyInternedFn<T> {
 | 
				
			||||||
 | 
					    fn eq(&self, other: &Self) -> bool {
 | 
				
			||||||
 | 
					        self.0.get_ptr_eq_with_type_id() == other.0.get_ptr_eq_with_type_id()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum LazyInterned<T: ?Sized + Send + Sync + 'static> {
 | 
				
			||||||
 | 
					    Interned(Interned<T>),
 | 
				
			||||||
 | 
					    Lazy(LazyInternedFn<T>),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Send + Sync + 'static> LazyInterned<T> {
 | 
				
			||||||
 | 
					    pub const fn new_lazy(v: &'static dyn LazyInternedTrait<T>) -> Self {
 | 
				
			||||||
 | 
					        Self::Lazy(LazyInternedFn(v))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Sync + Send + 'static> Clone for LazyInterned<T> {
 | 
				
			||||||
 | 
					    fn clone(&self) -> Self {
 | 
				
			||||||
 | 
					        *self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Sync + Send + 'static> Copy for LazyInterned<T> {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Sync + Send + 'static + Intern> Deref for LazyInterned<T> {
 | 
				
			||||||
 | 
					    type Target = T;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn deref(&self) -> &Self::Target {
 | 
				
			||||||
 | 
					        Interned::into_inner(self.interned())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Sync + Send + 'static + Intern> Eq for LazyInterned<T> where Interned<T>: Eq {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Sync + Send + 'static + Intern> PartialEq for LazyInterned<T>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    Interned<T>: PartialEq,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn eq(&self, other: &Self) -> bool {
 | 
				
			||||||
 | 
					        self.interned() == other.interned()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Sync + Send + 'static + Intern> Ord for LazyInterned<T>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    Interned<T>: Ord,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn cmp(&self, other: &Self) -> Ordering {
 | 
				
			||||||
 | 
					        self.interned().cmp(&other.interned())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Sync + Send + 'static + Intern> PartialOrd for LazyInterned<T>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    Interned<T>: PartialOrd,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 | 
				
			||||||
 | 
					        self.interned().partial_cmp(&other.interned())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Sync + Send + 'static + Intern> Hash for LazyInterned<T>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    Interned<T>: Hash,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn hash<H: Hasher>(&self, state: &mut H) {
 | 
				
			||||||
 | 
					        self.interned().hash(state);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: ?Sized + Sync + Send + 'static> LazyInterned<T> {
 | 
				
			||||||
 | 
					    pub fn interned(self) -> Interned<T>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        T: Intern,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        struct MemoizeInterned<T: ?Sized + Intern>(PhantomData<T>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl<T: ?Sized + Intern> Hash for MemoizeInterned<T> {
 | 
				
			||||||
 | 
					            fn hash<H: Hasher>(&self, _state: &mut H) {}
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl<T: ?Sized + Intern> PartialEq for MemoizeInterned<T> {
 | 
				
			||||||
 | 
					            fn eq(&self, _other: &Self) -> bool {
 | 
				
			||||||
 | 
					                true
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl<T: ?Sized + Intern> Eq for MemoizeInterned<T> {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl<T: ?Sized + Intern> Clone for MemoizeInterned<T> {
 | 
				
			||||||
 | 
					            fn clone(&self) -> Self {
 | 
				
			||||||
 | 
					                *self
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl<T: ?Sized + Intern> Copy for MemoizeInterned<T> {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl<T: ?Sized + Intern> MemoizeGeneric for MemoizeInterned<T> {
 | 
				
			||||||
 | 
					            type InputRef<'a> = LazyInternedFn<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            type InputOwned = LazyInternedFn<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            type InputCow<'a> = LazyInternedFn<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            type Output = Interned<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool {
 | 
				
			||||||
 | 
					                a == b
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
 | 
				
			||||||
 | 
					                *input
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned {
 | 
				
			||||||
 | 
					                input
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> {
 | 
				
			||||||
 | 
					                *input
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> {
 | 
				
			||||||
 | 
					                input
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> {
 | 
				
			||||||
 | 
					                input
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fn inner(self, input: Self::InputRef<'_>) -> Self::Output {
 | 
				
			||||||
 | 
					                input.0.get()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Interned(retval) => retval,
 | 
				
			||||||
 | 
					            Self::Lazy(retval) => MemoizeInterned(PhantomData).get(retval),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait InternedCompare {
 | 
					pub trait InternedCompare {
 | 
				
			||||||
    type InternedCompareKey: Ord + Hash;
 | 
					    type InternedCompareKey: Ord + Hash;
 | 
				
			||||||
    fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey;
 | 
					    fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey;
 | 
				
			||||||
| 
						 | 
					@ -471,6 +644,12 @@ pub struct Interned<T: ?Sized + 'static + Send + Sync, C: InternContext = Global
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro_rules! forward_fmt_trait {
 | 
					macro_rules! forward_fmt_trait {
 | 
				
			||||||
    ($Tr:ident) => {
 | 
					    ($Tr:ident) => {
 | 
				
			||||||
 | 
					        impl<T: ?Sized + Intern + fmt::$Tr> fmt::$Tr for LazyInterned<T> {
 | 
				
			||||||
 | 
					            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					                T::fmt(&**self, f)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        impl<T: ?Sized + 'static + Send + Sync + fmt::$Tr, C: InternContext> fmt::$Tr
 | 
					        impl<T: ?Sized + 'static + Send + Sync + fmt::$Tr, C: InternContext> fmt::$Tr
 | 
				
			||||||
            for Interned<T, C>
 | 
					            for Interned<T, C>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,6 @@ extern crate self as fayalite;
 | 
				
			||||||
pub use std as __std;
 | 
					pub use std as __std;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[doc(inline)]
 | 
					#[doc(inline)]
 | 
				
			||||||
#[doc(alias = "hdl")]
 | 
					 | 
				
			||||||
/// The `#[hdl_module]` attribute is applied to a Rust function so that that function creates
 | 
					/// The `#[hdl_module]` attribute is applied to a Rust function so that that function creates
 | 
				
			||||||
/// a [`Module`][`::fayalite::module::Module`] when called.
 | 
					/// a [`Module`][`::fayalite::module::Module`] when called.
 | 
				
			||||||
/// In the function body it will implicitly create a
 | 
					/// In the function body it will implicitly create a
 | 
				
			||||||
| 
						 | 
					@ -21,13 +20,21 @@ pub use std as __std;
 | 
				
			||||||
/// See [Fayalite Modules][crate::_docs::modules]
 | 
					/// See [Fayalite Modules][crate::_docs::modules]
 | 
				
			||||||
pub use fayalite_proc_macros::hdl_module;
 | 
					pub use fayalite_proc_macros::hdl_module;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[doc(inline)]
 | 
				
			||||||
 | 
					pub use fayalite_proc_macros::hdl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// struct used as a placeholder when applying defaults
 | 
				
			||||||
 | 
					#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
 | 
				
			||||||
 | 
					pub struct __;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(feature = "unstable-doc")]
 | 
					#[cfg(feature = "unstable-doc")]
 | 
				
			||||||
pub mod _docs;
 | 
					pub mod _docs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: finish
 | 
				
			||||||
pub mod annotations;
 | 
					pub mod annotations;
 | 
				
			||||||
pub mod array;
 | 
					pub mod array;
 | 
				
			||||||
pub mod bundle;
 | 
					pub mod bundle;
 | 
				
			||||||
pub mod cli;
 | 
					//pub mod cli;
 | 
				
			||||||
pub mod clock;
 | 
					pub mod clock;
 | 
				
			||||||
pub mod enum_;
 | 
					pub mod enum_;
 | 
				
			||||||
pub mod expr;
 | 
					pub mod expr;
 | 
				
			||||||
| 
						 | 
					@ -41,5 +48,5 @@ pub mod reset;
 | 
				
			||||||
pub mod source_location;
 | 
					pub mod source_location;
 | 
				
			||||||
pub mod ty;
 | 
					pub mod ty;
 | 
				
			||||||
pub mod util;
 | 
					pub mod util;
 | 
				
			||||||
pub mod valueless;
 | 
					//pub mod valueless;
 | 
				
			||||||
pub mod wire;
 | 
					pub mod wire;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,15 +4,16 @@
 | 
				
			||||||
#![allow(clippy::multiple_bound_locations)]
 | 
					#![allow(clippy::multiple_bound_locations)]
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    annotations::{Annotation, IntoAnnotations, TargetedAnnotation},
 | 
					    annotations::{Annotation, IntoAnnotations, TargetedAnnotation},
 | 
				
			||||||
    array::{Array, ArrayType, ArrayTypeTrait, ValueArrayOrSlice},
 | 
					    array::{Array, ArrayType},
 | 
				
			||||||
    bundle::{BundleType, BundleValue, DynBundle, DynBundleType},
 | 
					    bundle::{Bundle, BundleType},
 | 
				
			||||||
    clock::{Clock, ClockType},
 | 
					    clock::Clock,
 | 
				
			||||||
    expr::{Expr, ExprEnum, ExprTrait, Flow, ToExpr},
 | 
					    expr::{Expr, Flow, ToExpr, ToLiteralBits},
 | 
				
			||||||
    int::{DynUInt, DynUIntType, UInt, UIntType},
 | 
					    hdl,
 | 
				
			||||||
 | 
					    int::{Bool, DynSize, Size, UInt, UIntType},
 | 
				
			||||||
    intern::{Intern, Interned},
 | 
					    intern::{Intern, Interned},
 | 
				
			||||||
    module::ScopedNameId,
 | 
					    module::ScopedNameId,
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{AsMask, DynCanonicalType, DynCanonicalValue, DynType, Type, Value},
 | 
					    ty::{AsMask, CanonicalType, Type},
 | 
				
			||||||
    util::DebugAsDisplay,
 | 
					    util::DebugAsDisplay,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bitvec::slice::BitSlice;
 | 
					use bitvec::slice::BitSlice;
 | 
				
			||||||
| 
						 | 
					@ -20,37 +21,37 @@ use std::{
 | 
				
			||||||
    cell::RefCell,
 | 
					    cell::RefCell,
 | 
				
			||||||
    fmt,
 | 
					    fmt,
 | 
				
			||||||
    hash::{Hash, Hasher},
 | 
					    hash::{Hash, Hasher},
 | 
				
			||||||
 | 
					    marker::PhantomData,
 | 
				
			||||||
    num::NonZeroU32,
 | 
					    num::NonZeroU32,
 | 
				
			||||||
    rc::Rc,
 | 
					    rc::Rc,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Value, Clone, PartialEq, Eq, Hash, Debug)]
 | 
					#[hdl]
 | 
				
			||||||
pub struct ReadStruct<Element> {
 | 
					pub struct ReadStruct<Element, AddrWidth: Size> {
 | 
				
			||||||
    pub addr: DynUInt,
 | 
					    pub addr: UIntType<AddrWidth>,
 | 
				
			||||||
    pub en: UInt<1>,
 | 
					    pub en: Bool,
 | 
				
			||||||
    pub clk: Clock,
 | 
					    pub clk: Clock,
 | 
				
			||||||
    #[hdl(flip)]
 | 
					    #[hdl(flip)]
 | 
				
			||||||
    pub data: Element,
 | 
					    pub data: Element,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Value, Clone, PartialEq, Eq, Hash, Debug)]
 | 
					#[hdl]
 | 
				
			||||||
pub struct WriteStruct<Element: Value> {
 | 
					pub struct WriteStruct<Element, AddrWidth: Size> {
 | 
				
			||||||
    pub addr: DynUInt,
 | 
					    pub addr: UIntType<AddrWidth>,
 | 
				
			||||||
    pub en: UInt<1>,
 | 
					    pub en: Bool,
 | 
				
			||||||
    pub clk: Clock,
 | 
					    pub clk: Clock,
 | 
				
			||||||
    pub data: Element,
 | 
					    pub data: Element,
 | 
				
			||||||
    pub mask: AsMask<Element>,
 | 
					    pub mask: AsMask<Element>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[allow(clippy::multiple_bound_locations)]
 | 
					#[hdl]
 | 
				
			||||||
#[derive(Value, Clone, PartialEq, Eq, Hash, Debug)]
 | 
					pub struct ReadWriteStruct<Element, AddrWidth: Size> {
 | 
				
			||||||
pub struct ReadWriteStruct<Element: Value> {
 | 
					    pub addr: UIntType<AddrWidth>,
 | 
				
			||||||
    pub addr: DynUInt,
 | 
					    pub en: Bool,
 | 
				
			||||||
    pub en: UInt<1>,
 | 
					 | 
				
			||||||
    pub clk: Clock,
 | 
					    pub clk: Clock,
 | 
				
			||||||
    #[hdl(flip)]
 | 
					    #[hdl(flip)]
 | 
				
			||||||
    pub rdata: Element,
 | 
					    pub rdata: Element,
 | 
				
			||||||
    pub wmode: UInt<1>,
 | 
					    pub wmode: Bool,
 | 
				
			||||||
    pub wdata: Element,
 | 
					    pub wdata: Element,
 | 
				
			||||||
    pub wmask: AsMask<Element>,
 | 
					    pub wmask: AsMask<Element>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -63,11 +64,10 @@ pub trait PortType:
 | 
				
			||||||
    sealed::Sealed + Clone + Eq + Hash + fmt::Debug + Send + Sync + 'static
 | 
					    sealed::Sealed + Clone + Eq + Hash + fmt::Debug + Send + Sync + 'static
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    type PortKindTy: Copy + Eq + Hash + fmt::Debug + Send + Sync + 'static;
 | 
					    type PortKindTy: Copy + Eq + Hash + fmt::Debug + Send + Sync + 'static;
 | 
				
			||||||
    type PortType: BundleType<Value = Self::PortValue>;
 | 
					    type Port: BundleType;
 | 
				
			||||||
    type PortValue: BundleValue<Type = Self::PortType>;
 | 
					 | 
				
			||||||
    fn port_kind(port_kind: Self::PortKindTy) -> PortKind;
 | 
					    fn port_kind(port_kind: Self::PortKindTy) -> PortKind;
 | 
				
			||||||
    fn from_port_kind(port_kind: PortKind) -> Self::PortKindTy;
 | 
					    fn from_port_kind(port_kind: PortKind) -> Self::PortKindTy;
 | 
				
			||||||
    fn port_ty(port: &MemPort<Self>) -> Self::PortType;
 | 
					    fn port_ty(port: &MemPort<Self>) -> Self::Port;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 | 
					#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 | 
				
			||||||
| 
						 | 
					@ -79,8 +79,7 @@ impl sealed::Sealed for DynPortType {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl PortType for DynPortType {
 | 
					impl PortType for DynPortType {
 | 
				
			||||||
    type PortKindTy = PortKind;
 | 
					    type PortKindTy = PortKind;
 | 
				
			||||||
    type PortType = DynBundleType;
 | 
					    type Port = Bundle;
 | 
				
			||||||
    type PortValue = DynBundle;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn port_kind(port_kind: Self::PortKindTy) -> PortKind {
 | 
					    fn port_kind(port_kind: Self::PortKindTy) -> PortKind {
 | 
				
			||||||
        port_kind
 | 
					        port_kind
 | 
				
			||||||
| 
						 | 
					@ -90,41 +89,38 @@ impl PortType for DynPortType {
 | 
				
			||||||
        port_kind
 | 
					        port_kind
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn port_ty(port: &MemPort<Self>) -> Self::PortType {
 | 
					    fn port_ty(port: &MemPort<Self>) -> Self::Port {
 | 
				
			||||||
        match port.port_kind {
 | 
					        Bundle::new(match port.port_kind {
 | 
				
			||||||
            PortKind::ReadOnly => MemPort::<ReadStruct<DynCanonicalValue>>::from_canonical(*port)
 | 
					            PortKind::ReadOnly => {
 | 
				
			||||||
 | 
					                MemPort::<ReadStruct<CanonicalType, DynSize>>::from_canonical(*port)
 | 
				
			||||||
                    .ty()
 | 
					                    .ty()
 | 
				
			||||||
                .canonical(),
 | 
					                    .fields()
 | 
				
			||||||
            PortKind::WriteOnly => MemPort::<WriteStruct<DynCanonicalValue>>::from_canonical(*port)
 | 
					            }
 | 
				
			||||||
 | 
					            PortKind::WriteOnly => {
 | 
				
			||||||
 | 
					                MemPort::<WriteStruct<CanonicalType, DynSize>>::from_canonical(*port)
 | 
				
			||||||
                    .ty()
 | 
					                    .ty()
 | 
				
			||||||
                .canonical(),
 | 
					                    .fields()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            PortKind::ReadWrite => {
 | 
					            PortKind::ReadWrite => {
 | 
				
			||||||
                MemPort::<ReadWriteStruct<DynCanonicalValue>>::from_canonical(*port)
 | 
					                MemPort::<ReadWriteStruct<CanonicalType, DynSize>>::from_canonical(*port)
 | 
				
			||||||
                    .ty()
 | 
					                    .ty()
 | 
				
			||||||
                    .canonical()
 | 
					                    .fields()
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait PortStruct:
 | 
					pub trait PortStruct: BundleType + sealed::Sealed + PortType<PortKindTy = (), Port = Self> {
 | 
				
			||||||
    BundleValue
 | 
					    type Element: Type;
 | 
				
			||||||
    + sealed::Sealed
 | 
					 | 
				
			||||||
    + PortType<PortKindTy = (), PortType = <Self as ToExpr>::Type, PortValue = Self>
 | 
					 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    Self::Type: BundleType<Value = Self>,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    type Element: Value<Type = Self::ElementType>;
 | 
					 | 
				
			||||||
    type ElementType: Type<Value = Self::Element>;
 | 
					 | 
				
			||||||
    const PORT_KIND: PortKind;
 | 
					    const PORT_KIND: PortKind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn addr(this: Expr<Self>) -> Expr<DynUInt>;
 | 
					    fn addr(this: Expr<Self>) -> Expr<UInt>;
 | 
				
			||||||
    fn en(this: Expr<Self>) -> Expr<UInt<1>>;
 | 
					    fn en(this: Expr<Self>) -> Expr<Bool>;
 | 
				
			||||||
    fn clk(this: Expr<Self>) -> Expr<Clock>;
 | 
					    fn clk(this: Expr<Self>) -> Expr<Clock>;
 | 
				
			||||||
    fn rdata(this: Expr<Self>) -> Option<Expr<Self::Element>>;
 | 
					    fn rdata(this: Expr<Self>) -> Option<Expr<Self::Element>>;
 | 
				
			||||||
    fn wdata(this: Expr<Self>) -> Option<Expr<Self::Element>>;
 | 
					    fn wdata(this: Expr<Self>) -> Option<Expr<Self::Element>>;
 | 
				
			||||||
    fn wmask(this: Expr<Self>) -> Option<Expr<AsMask<Self::Element>>>;
 | 
					    fn wmask(this: Expr<Self>) -> Option<Expr<AsMask<Self::Element>>>;
 | 
				
			||||||
    fn wmode(this: Expr<Self>) -> Expr<UInt<1>>;
 | 
					    fn wmode(this: Expr<Self>) -> Expr<Bool>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro_rules! impl_port_struct {
 | 
					macro_rules! impl_port_struct {
 | 
				
			||||||
| 
						 | 
					@ -137,19 +133,11 @@ macro_rules! impl_port_struct {
 | 
				
			||||||
            $($body:tt)*
 | 
					            $($body:tt)*
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    ) => {
 | 
					    ) => {
 | 
				
			||||||
        impl<$Element: Value> sealed::Sealed for $Struct<$Element>
 | 
					        impl<$Element: Type> sealed::Sealed for $Struct<$Element, DynSize> {}
 | 
				
			||||||
        where
 | 
					 | 
				
			||||||
            $Element::Type: Type<Value = $Element>,
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        impl<$Element: Value> PortType for $Struct<$Element>
 | 
					        impl<$Element: Type> PortType for $Struct<$Element, DynSize> {
 | 
				
			||||||
        where
 | 
					 | 
				
			||||||
            $Element::Type: Type<Value = $Element>,
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            type PortKindTy = ();
 | 
					            type PortKindTy = ();
 | 
				
			||||||
            type PortType = <Self as ToExpr>::Type;
 | 
					            type Port = Self;
 | 
				
			||||||
            type PortValue = Self;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            fn port_kind(_port_kind: Self::PortKindTy) -> PortKind {
 | 
					            fn port_kind(_port_kind: Self::PortKindTy) -> PortKind {
 | 
				
			||||||
                Self::PORT_KIND
 | 
					                Self::PORT_KIND
 | 
				
			||||||
| 
						 | 
					@ -164,18 +152,14 @@ macro_rules! impl_port_struct {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        impl<$Element: Value> PortStruct for $Struct<$Element>
 | 
					        impl<$Element: Type> PortStruct for $Struct<$Element, DynSize> {
 | 
				
			||||||
        where
 | 
					 | 
				
			||||||
            $Element::Type: Type<Value = $Element>,
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            type Element = $Element;
 | 
					            type Element = $Element;
 | 
				
			||||||
            type ElementType = $Element::Type;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            fn addr(this: Expr<Self>) -> Expr<DynUInt> {
 | 
					            fn addr(this: Expr<Self>) -> Expr<UInt> {
 | 
				
			||||||
                this.addr
 | 
					                this.addr
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            fn en(this: Expr<Self>) -> Expr<UInt<1>> {
 | 
					            fn en(this: Expr<Self>) -> Expr<Bool> {
 | 
				
			||||||
                this.en
 | 
					                this.en
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -190,14 +174,9 @@ macro_rules! impl_port_struct {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl_port_struct! {
 | 
					impl_port_struct! {
 | 
				
			||||||
    impl<Element> _ for ReadStruct {
 | 
					    impl<Element> _ for ReadStruct {
 | 
				
			||||||
        fn port_ty(port: &MemPort<Self>) -> <MemPort<Self> as ToExpr>::Type {
 | 
					        fn port_ty(port: &MemPort<Self>) -> Self {
 | 
				
			||||||
            type T<V> = <V as ToExpr>::Type;
 | 
					            let element = Element::from_canonical(port.mem_element_type);
 | 
				
			||||||
            T::<Self> {
 | 
					            ReadStruct[element][port.addr_type.width()]
 | 
				
			||||||
                addr: port.addr_type,
 | 
					 | 
				
			||||||
                en: UIntType::new(),
 | 
					 | 
				
			||||||
                clk: ClockType,
 | 
					 | 
				
			||||||
                data: Element::Type::from_dyn_canonical_type(port.mem_element_type),
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const PORT_KIND: PortKind = PortKind::ReadOnly;
 | 
					        const PORT_KIND: PortKind = PortKind::ReadOnly;
 | 
				
			||||||
| 
						 | 
					@ -214,7 +193,7 @@ impl_port_struct! {
 | 
				
			||||||
            None
 | 
					            None
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fn wmode(_this: Expr<Self>) -> Expr<UInt<1>> {
 | 
					        fn wmode(_this: Expr<Self>) -> Expr<Bool> {
 | 
				
			||||||
            false.to_expr()
 | 
					            false.to_expr()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -222,16 +201,9 @@ impl_port_struct! {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl_port_struct! {
 | 
					impl_port_struct! {
 | 
				
			||||||
    impl<Element> _ for WriteStruct {
 | 
					    impl<Element> _ for WriteStruct {
 | 
				
			||||||
        fn port_ty(port: &MemPort<Self>) -> <MemPort<Self> as ToExpr>::Type {
 | 
					        fn port_ty(port: &MemPort<Self>) -> Self {
 | 
				
			||||||
            type T<V> = <V as ToExpr>::Type;
 | 
					            let element = Element::from_canonical(port.mem_element_type);
 | 
				
			||||||
            let element_ty = Element::Type::from_dyn_canonical_type(port.mem_element_type);
 | 
					            WriteStruct[element][port.addr_type.width()]
 | 
				
			||||||
            T::<Self> {
 | 
					 | 
				
			||||||
                addr: port.addr_type,
 | 
					 | 
				
			||||||
                en: UIntType::new(),
 | 
					 | 
				
			||||||
                clk: ClockType,
 | 
					 | 
				
			||||||
                mask: element_ty.mask_type(),
 | 
					 | 
				
			||||||
                data: element_ty,
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const PORT_KIND: PortKind = PortKind::WriteOnly;
 | 
					        const PORT_KIND: PortKind = PortKind::WriteOnly;
 | 
				
			||||||
| 
						 | 
					@ -248,7 +220,7 @@ impl_port_struct! {
 | 
				
			||||||
            Some(this.mask)
 | 
					            Some(this.mask)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fn wmode(_this: Expr<Self>) -> Expr<UInt<1>> {
 | 
					        fn wmode(_this: Expr<Self>) -> Expr<Bool> {
 | 
				
			||||||
            true.to_expr()
 | 
					            true.to_expr()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -256,18 +228,9 @@ impl_port_struct! {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl_port_struct! {
 | 
					impl_port_struct! {
 | 
				
			||||||
    impl<Element> _ for ReadWriteStruct {
 | 
					    impl<Element> _ for ReadWriteStruct {
 | 
				
			||||||
        fn port_ty(port: &MemPort<Self>) -> <MemPort<Self> as ToExpr>::Type {
 | 
					        fn port_ty(port: &MemPort<Self>) -> Self {
 | 
				
			||||||
            type T<V> = <V as ToExpr>::Type;
 | 
					            let element = Element::from_canonical(port.mem_element_type);
 | 
				
			||||||
            let element_ty = Element::Type::from_dyn_canonical_type(port.mem_element_type);
 | 
					            ReadWriteStruct[element][port.addr_type.width()]
 | 
				
			||||||
            T::<Self> {
 | 
					 | 
				
			||||||
                addr: port.addr_type,
 | 
					 | 
				
			||||||
                en: UIntType::new(),
 | 
					 | 
				
			||||||
                clk: ClockType,
 | 
					 | 
				
			||||||
                rdata: element_ty.clone(),
 | 
					 | 
				
			||||||
                wmode: UIntType::new(),
 | 
					 | 
				
			||||||
                wmask: element_ty.mask_type(),
 | 
					 | 
				
			||||||
                wdata: element_ty,
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const PORT_KIND: PortKind = PortKind::ReadWrite;
 | 
					        const PORT_KIND: PortKind = PortKind::ReadWrite;
 | 
				
			||||||
| 
						 | 
					@ -284,7 +247,7 @@ impl_port_struct! {
 | 
				
			||||||
            Some(this.wmask)
 | 
					            Some(this.wmask)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fn wmode(this: Expr<Self>) -> Expr<UInt<1>> {
 | 
					        fn wmode(this: Expr<Self>) -> Expr<Bool> {
 | 
				
			||||||
            this.wmode
 | 
					            this.wmode
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -382,8 +345,8 @@ pub struct MemPort<T: PortType> {
 | 
				
			||||||
    source_location: SourceLocation,
 | 
					    source_location: SourceLocation,
 | 
				
			||||||
    port_kind: T::PortKindTy,
 | 
					    port_kind: T::PortKindTy,
 | 
				
			||||||
    port_index: usize,
 | 
					    port_index: usize,
 | 
				
			||||||
    addr_type: DynUIntType,
 | 
					    addr_type: UInt,
 | 
				
			||||||
    mem_element_type: Interned<dyn DynCanonicalType>,
 | 
					    mem_element_type: CanonicalType,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: PortType> fmt::Debug for MemPort<T> {
 | 
					impl<T: PortType> fmt::Debug for MemPort<T> {
 | 
				
			||||||
| 
						 | 
					@ -405,19 +368,10 @@ impl<T: PortType> fmt::Debug for MemPort<T> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: PortType> ToExpr for MemPort<T> {
 | 
					impl<T: PortType> MemPort<T> {
 | 
				
			||||||
    type Type = T::PortType;
 | 
					    pub fn ty(&self) -> T::Port {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					 | 
				
			||||||
        T::port_ty(self)
 | 
					        T::port_ty(self)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
					 | 
				
			||||||
        Expr::new_unchecked(self.expr_enum())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T: PortType> MemPort<T> {
 | 
					 | 
				
			||||||
    pub fn source_location(&self) -> SourceLocation {
 | 
					    pub fn source_location(&self) -> SourceLocation {
 | 
				
			||||||
        self.source_location
 | 
					        self.source_location
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -436,10 +390,10 @@ impl<T: PortType> MemPort<T> {
 | 
				
			||||||
            index: self.port_index,
 | 
					            index: self.port_index,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn mem_element_type(&self) -> Interned<dyn DynCanonicalType> {
 | 
					    pub fn mem_element_type(&self) -> CanonicalType {
 | 
				
			||||||
        self.mem_element_type
 | 
					        self.mem_element_type
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn addr_type(&self) -> DynUIntType {
 | 
					    pub fn addr_type(&self) -> UInt {
 | 
				
			||||||
        self.addr_type
 | 
					        self.addr_type
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn canonical(&self) -> MemPort<DynPortType> {
 | 
					    pub fn canonical(&self) -> MemPort<DynPortType> {
 | 
				
			||||||
| 
						 | 
					@ -463,7 +417,6 @@ impl<T: PortType> MemPort<T> {
 | 
				
			||||||
    pub fn from_canonical(port: MemPort<DynPortType>) -> Self
 | 
					    pub fn from_canonical(port: MemPort<DynPortType>) -> Self
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        T: PortStruct,
 | 
					        T: PortStruct,
 | 
				
			||||||
        T::Type: BundleType<Value = T>,
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let MemPort {
 | 
					        let MemPort {
 | 
				
			||||||
            mem_name,
 | 
					            mem_name,
 | 
				
			||||||
| 
						 | 
					@ -488,8 +441,8 @@ impl<T: PortType> MemPort<T> {
 | 
				
			||||||
        mem_name: ScopedNameId,
 | 
					        mem_name: ScopedNameId,
 | 
				
			||||||
        source_location: SourceLocation,
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
        port_name: PortName,
 | 
					        port_name: PortName,
 | 
				
			||||||
        addr_type: DynUIntType,
 | 
					        addr_type: UInt,
 | 
				
			||||||
        mem_element_type: Interned<dyn DynCanonicalType>,
 | 
					        mem_element_type: CanonicalType,
 | 
				
			||||||
    ) -> Self {
 | 
					    ) -> Self {
 | 
				
			||||||
        assert!(
 | 
					        assert!(
 | 
				
			||||||
            mem_element_type.is_storable(),
 | 
					            mem_element_type.is_storable(),
 | 
				
			||||||
| 
						 | 
					@ -520,10 +473,10 @@ pub enum ReadUnderWrite {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 | 
					#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
struct MemImpl<T: ArrayTypeTrait, P> {
 | 
					struct MemImpl<Element: Type, Len: Size, P> {
 | 
				
			||||||
    scoped_name: ScopedNameId,
 | 
					    scoped_name: ScopedNameId,
 | 
				
			||||||
    source_location: SourceLocation,
 | 
					    source_location: SourceLocation,
 | 
				
			||||||
    array_type: T,
 | 
					    array_type: ArrayType<Element, Len>,
 | 
				
			||||||
    initial_value: Option<Interned<BitSlice>>,
 | 
					    initial_value: Option<Interned<BitSlice>>,
 | 
				
			||||||
    ports: P,
 | 
					    ports: P,
 | 
				
			||||||
    read_latency: usize,
 | 
					    read_latency: usize,
 | 
				
			||||||
| 
						 | 
					@ -533,11 +486,11 @@ struct MemImpl<T: ArrayTypeTrait, P> {
 | 
				
			||||||
    mem_annotations: Interned<[Annotation]>,
 | 
					    mem_annotations: Interned<[Annotation]>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Mem<VA: ValueArrayOrSlice + ?Sized>(
 | 
					pub struct Mem<Element: Type = CanonicalType, Len: Size = DynSize>(
 | 
				
			||||||
    Interned<MemImpl<ArrayType<VA>, Interned<[Interned<MemPort<DynPortType>>]>>>,
 | 
					    Interned<MemImpl<Element, Len, Interned<[MemPort<DynPortType>]>>>,
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct PortsDebug<'a>(&'a [Interned<MemPort<DynPortType>>]);
 | 
					struct PortsDebug<'a>(&'a [MemPort<DynPortType>]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl fmt::Debug for PortsDebug<'_> {
 | 
					impl fmt::Debug for PortsDebug<'_> {
 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
| 
						 | 
					@ -551,7 +504,7 @@ impl fmt::Debug for PortsDebug<'_> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> fmt::Debug for Mem<VA> {
 | 
					impl<Element: Type, Len: Size> fmt::Debug for Mem<Element, Len> {
 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
        let MemImpl {
 | 
					        let MemImpl {
 | 
				
			||||||
            scoped_name,
 | 
					            scoped_name,
 | 
				
			||||||
| 
						 | 
					@ -579,37 +532,37 @@ impl<VA: ValueArrayOrSlice + ?Sized> fmt::Debug for Mem<VA> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> Hash for Mem<VA> {
 | 
					impl<Element: Type, Len: Size> Hash for Mem<Element, Len> {
 | 
				
			||||||
    fn hash<H: Hasher>(&self, state: &mut H) {
 | 
					    fn hash<H: Hasher>(&self, state: &mut H) {
 | 
				
			||||||
        self.0.hash(state);
 | 
					        self.0.hash(state);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> Eq for Mem<VA> {}
 | 
					impl<Element: Type, Len: Size> Eq for Mem<Element, Len> {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> PartialEq for Mem<VA> {
 | 
					impl<Element: Type, Len: Size> PartialEq for Mem<Element, Len> {
 | 
				
			||||||
    fn eq(&self, other: &Self) -> bool {
 | 
					    fn eq(&self, other: &Self) -> bool {
 | 
				
			||||||
        self.0 == other.0
 | 
					        self.0 == other.0
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> Copy for Mem<VA> {}
 | 
					impl<Element: Type, Len: Size> Copy for Mem<Element, Len> {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> Clone for Mem<VA> {
 | 
					impl<Element: Type, Len: Size> Clone for Mem<Element, Len> {
 | 
				
			||||||
    fn clone(&self) -> Self {
 | 
					    fn clone(&self) -> Self {
 | 
				
			||||||
        *self
 | 
					        *self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> Mem<VA> {
 | 
					impl<Element: Type, Len: Size> Mem<Element, Len> {
 | 
				
			||||||
    #[allow(clippy::too_many_arguments)]
 | 
					    #[allow(clippy::too_many_arguments)]
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn new_unchecked(
 | 
					    pub fn new_unchecked(
 | 
				
			||||||
        scoped_name: ScopedNameId,
 | 
					        scoped_name: ScopedNameId,
 | 
				
			||||||
        source_location: SourceLocation,
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
        array_type: ArrayType<VA>,
 | 
					        array_type: ArrayType<Element, Len>,
 | 
				
			||||||
        initial_value: Option<Interned<BitSlice>>,
 | 
					        initial_value: Option<Interned<BitSlice>>,
 | 
				
			||||||
        ports: Interned<[Interned<MemPort<DynPortType>>]>,
 | 
					        ports: Interned<[MemPort<DynPortType>]>,
 | 
				
			||||||
        read_latency: usize,
 | 
					        read_latency: usize,
 | 
				
			||||||
        write_latency: NonZeroU32,
 | 
					        write_latency: NonZeroU32,
 | 
				
			||||||
        read_under_write: ReadUnderWrite,
 | 
					        read_under_write: ReadUnderWrite,
 | 
				
			||||||
| 
						 | 
					@ -617,14 +570,14 @@ impl<VA: ValueArrayOrSlice + ?Sized> Mem<VA> {
 | 
				
			||||||
        mem_annotations: Interned<[Annotation]>,
 | 
					        mem_annotations: Interned<[Annotation]>,
 | 
				
			||||||
    ) -> Self {
 | 
					    ) -> Self {
 | 
				
			||||||
        if let Some(initial_value) = initial_value {
 | 
					        if let Some(initial_value) = initial_value {
 | 
				
			||||||
            MemBuilder::<VA>::check_initial_value_bit_slice(
 | 
					            MemBuilder::<Element, Len>::check_initial_value_bit_slice(
 | 
				
			||||||
                array_type.element(),
 | 
					                array_type.element(),
 | 
				
			||||||
                Some(array_type.len()),
 | 
					                Some(array_type.len()),
 | 
				
			||||||
                initial_value,
 | 
					                initial_value,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let addr_width = memory_addr_width(array_type.len());
 | 
					        let addr_width = memory_addr_width(array_type.len());
 | 
				
			||||||
        let expected_mem_element_type = array_type.element().canonical_dyn();
 | 
					        let expected_mem_element_type = array_type.element().canonical();
 | 
				
			||||||
        assert!(
 | 
					        assert!(
 | 
				
			||||||
            expected_mem_element_type.is_storable(),
 | 
					            expected_mem_element_type.is_storable(),
 | 
				
			||||||
            "memory element type must be a storable type"
 | 
					            "memory element type must be a storable type"
 | 
				
			||||||
| 
						 | 
					@ -637,7 +590,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> Mem<VA> {
 | 
				
			||||||
                port_index,
 | 
					                port_index,
 | 
				
			||||||
                addr_type,
 | 
					                addr_type,
 | 
				
			||||||
                mem_element_type,
 | 
					                mem_element_type,
 | 
				
			||||||
            } = **port;
 | 
					            } = *port;
 | 
				
			||||||
            assert_eq!(mem_name, scoped_name, "memory name must match with ports");
 | 
					            assert_eq!(mem_name, scoped_name, "memory name must match with ports");
 | 
				
			||||||
            assert_eq!(
 | 
					            assert_eq!(
 | 
				
			||||||
                port_index, index,
 | 
					                port_index, index,
 | 
				
			||||||
| 
						 | 
					@ -659,7 +612,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> Mem<VA> {
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            assert_eq!(
 | 
					            assert_eq!(
 | 
				
			||||||
                Some(port),
 | 
					                Some(port),
 | 
				
			||||||
                ports.get(port.port_index).map(|v| &**v),
 | 
					                ports.get(port.port_index),
 | 
				
			||||||
                "port on memory must match annotation's target base"
 | 
					                "port on memory must match annotation's target base"
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -682,13 +635,13 @@ impl<VA: ValueArrayOrSlice + ?Sized> Mem<VA> {
 | 
				
			||||||
    pub fn source_location(self) -> SourceLocation {
 | 
					    pub fn source_location(self) -> SourceLocation {
 | 
				
			||||||
        self.0.source_location
 | 
					        self.0.source_location
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn array_type(self) -> ArrayType<VA> {
 | 
					    pub fn array_type(self) -> ArrayType<Element, Len> {
 | 
				
			||||||
        self.0.array_type.clone()
 | 
					        self.0.array_type.clone()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn initial_value(self) -> Option<Interned<BitSlice>> {
 | 
					    pub fn initial_value(self) -> Option<Interned<BitSlice>> {
 | 
				
			||||||
        self.0.initial_value
 | 
					        self.0.initial_value
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn ports(self) -> Interned<[Interned<MemPort<DynPortType>>]> {
 | 
					    pub fn ports(self) -> Interned<[MemPort<DynPortType>]> {
 | 
				
			||||||
        self.0.ports
 | 
					        self.0.ports
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn read_latency(self) -> usize {
 | 
					    pub fn read_latency(self) -> usize {
 | 
				
			||||||
| 
						 | 
					@ -706,7 +659,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> Mem<VA> {
 | 
				
			||||||
    pub fn mem_annotations(self) -> Interned<[Annotation]> {
 | 
					    pub fn mem_annotations(self) -> Interned<[Annotation]> {
 | 
				
			||||||
        self.0.mem_annotations
 | 
					        self.0.mem_annotations
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn canonical(self) -> Mem<[DynCanonicalValue]> {
 | 
					    pub fn canonical(self) -> Mem {
 | 
				
			||||||
        let MemImpl {
 | 
					        let MemImpl {
 | 
				
			||||||
            scoped_name,
 | 
					            scoped_name,
 | 
				
			||||||
            source_location,
 | 
					            source_location,
 | 
				
			||||||
| 
						 | 
					@ -719,7 +672,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> Mem<VA> {
 | 
				
			||||||
            port_annotations,
 | 
					            port_annotations,
 | 
				
			||||||
            mem_annotations,
 | 
					            mem_annotations,
 | 
				
			||||||
        } = *self.0;
 | 
					        } = *self.0;
 | 
				
			||||||
        let array_type = array_type.canonical();
 | 
					        let array_type = array_type.as_dyn_array();
 | 
				
			||||||
        Mem(Intern::intern_sized(MemImpl {
 | 
					        Mem(Intern::intern_sized(MemImpl {
 | 
				
			||||||
            scoped_name,
 | 
					            scoped_name,
 | 
				
			||||||
            source_location,
 | 
					            source_location,
 | 
				
			||||||
| 
						 | 
					@ -751,10 +704,10 @@ impl<T: fmt::Debug> fmt::Debug for MaybeSpecified<T> {
 | 
				
			||||||
pub(crate) struct MemBuilderTarget {
 | 
					pub(crate) struct MemBuilderTarget {
 | 
				
			||||||
    pub(crate) scoped_name: ScopedNameId,
 | 
					    pub(crate) scoped_name: ScopedNameId,
 | 
				
			||||||
    pub(crate) source_location: SourceLocation,
 | 
					    pub(crate) source_location: SourceLocation,
 | 
				
			||||||
    pub(crate) mem_element_type: Interned<dyn DynCanonicalType>,
 | 
					    pub(crate) mem_element_type: CanonicalType,
 | 
				
			||||||
    pub(crate) depth: Option<usize>,
 | 
					    pub(crate) depth: Option<usize>,
 | 
				
			||||||
    pub(crate) initial_value: Option<Interned<BitSlice>>,
 | 
					    pub(crate) initial_value: Option<Interned<BitSlice>>,
 | 
				
			||||||
    pub(crate) ports: Vec<Interned<MemPort<DynPortType>>>,
 | 
					    pub(crate) ports: Vec<MemPort<DynPortType>>,
 | 
				
			||||||
    pub(crate) read_latency: usize,
 | 
					    pub(crate) read_latency: usize,
 | 
				
			||||||
    pub(crate) write_latency: NonZeroU32,
 | 
					    pub(crate) write_latency: NonZeroU32,
 | 
				
			||||||
    pub(crate) read_under_write: ReadUnderWrite,
 | 
					    pub(crate) read_under_write: ReadUnderWrite,
 | 
				
			||||||
| 
						 | 
					@ -763,11 +716,11 @@ pub(crate) struct MemBuilderTarget {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl MemBuilderTarget {
 | 
					impl MemBuilderTarget {
 | 
				
			||||||
    pub(crate) fn make_memory(&self) -> Option<Mem<[DynCanonicalValue]>> {
 | 
					    pub(crate) fn make_memory(&self) -> Option<Mem> {
 | 
				
			||||||
        Some(Mem::new_unchecked(
 | 
					        Some(Mem::new_unchecked(
 | 
				
			||||||
            self.scoped_name,
 | 
					            self.scoped_name,
 | 
				
			||||||
            self.source_location,
 | 
					            self.source_location,
 | 
				
			||||||
            ArrayType::new_slice(self.mem_element_type, self.depth?),
 | 
					            ArrayType::new_dyn(self.mem_element_type, self.depth?),
 | 
				
			||||||
            self.initial_value,
 | 
					            self.initial_value,
 | 
				
			||||||
            Intern::intern(&self.ports),
 | 
					            Intern::intern(&self.ports),
 | 
				
			||||||
            self.read_latency,
 | 
					            self.read_latency,
 | 
				
			||||||
| 
						 | 
					@ -817,16 +770,18 @@ impl fmt::Debug for MemBuilderTarget {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct MemBuilder<VA: ValueArrayOrSlice + ?Sized> {
 | 
					pub struct MemBuilder<Element: Type, Len: Size> {
 | 
				
			||||||
    mem_element_type: VA::ElementType,
 | 
					    mem_element_type: Element,
 | 
				
			||||||
    target: Rc<RefCell<MemBuilderTarget>>,
 | 
					    target: Rc<RefCell<MemBuilderTarget>>,
 | 
				
			||||||
 | 
					    _phantom: PhantomData<Len>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> fmt::Debug for MemBuilder<VA> {
 | 
					impl<Element: Type, Len: Size> fmt::Debug for MemBuilder<Element, Len> {
 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
        let Self {
 | 
					        let Self {
 | 
				
			||||||
            mem_element_type,
 | 
					            mem_element_type,
 | 
				
			||||||
            target,
 | 
					            target,
 | 
				
			||||||
 | 
					            _phantom: _,
 | 
				
			||||||
        } = &self;
 | 
					        } = &self;
 | 
				
			||||||
        target.borrow().debug_fmt("MemBuilder", mem_element_type, f)
 | 
					        target.borrow().debug_fmt("MemBuilder", mem_element_type, f)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -838,15 +793,16 @@ pub fn memory_addr_width(depth: usize) -> usize {
 | 
				
			||||||
        .map_or(usize::BITS, usize::ilog2) as usize
 | 
					        .map_or(usize::BITS, usize::ilog2) as usize
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
					impl<Element: Type, Len: Size> MemBuilder<Element, Len> {
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    fn check_initial_value_bit_slice(
 | 
					    fn check_initial_value_bit_slice(
 | 
				
			||||||
        mem_element_type: &VA::ElementType,
 | 
					        mem_element_type: Element,
 | 
				
			||||||
        depth: Option<usize>,
 | 
					        depth: Option<usize>,
 | 
				
			||||||
        initial_value: Interned<BitSlice>,
 | 
					        initial_value: Interned<BitSlice>,
 | 
				
			||||||
    ) -> Interned<BitSlice> {
 | 
					    ) -> Interned<BitSlice> {
 | 
				
			||||||
 | 
					        let element_bit_width = mem_element_type.canonical().bit_width();
 | 
				
			||||||
        if let Some(depth) = depth {
 | 
					        if let Some(depth) = depth {
 | 
				
			||||||
            let expected_len = depth.checked_mul(mem_element_type.bit_width()).expect(
 | 
					            let expected_len = depth.checked_mul(element_bit_width).expect(
 | 
				
			||||||
                "memory must be small enough that its initializer bit length fits in usize",
 | 
					                "memory must be small enough that its initializer bit length fits in usize",
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            assert_eq!(
 | 
					            assert_eq!(
 | 
				
			||||||
| 
						 | 
					@ -858,7 +814,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
				
			||||||
        assert!(
 | 
					        assert!(
 | 
				
			||||||
            initial_value
 | 
					            initial_value
 | 
				
			||||||
                .len()
 | 
					                .len()
 | 
				
			||||||
                .checked_rem(mem_element_type.bit_width())
 | 
					                .checked_rem(element_bit_width)
 | 
				
			||||||
                .unwrap_or(initial_value.len())
 | 
					                .unwrap_or(initial_value.len())
 | 
				
			||||||
                == 0,
 | 
					                == 0,
 | 
				
			||||||
            "Mem's initializer bit length must be a multiple of the element type's bit width",
 | 
					            "Mem's initializer bit length must be a multiple of the element type's bit width",
 | 
				
			||||||
| 
						 | 
					@ -867,14 +823,14 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    fn check_initial_value_expr(
 | 
					    fn check_initial_value_expr(
 | 
				
			||||||
        mem_element_type: &VA::ElementType,
 | 
					        mem_element_type: &Element,
 | 
				
			||||||
        depth: Option<usize>,
 | 
					        depth: Option<usize>,
 | 
				
			||||||
        initial_value: Expr<Array<[DynCanonicalValue]>>,
 | 
					        initial_value: Expr<Array>,
 | 
				
			||||||
    ) -> Interned<BitSlice> {
 | 
					    ) -> Interned<BitSlice> {
 | 
				
			||||||
        let initial_value_ty = initial_value.canonical_type();
 | 
					        let initial_value_ty = Expr::ty(initial_value);
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            *mem_element_type,
 | 
					            *mem_element_type,
 | 
				
			||||||
            <VA::ElementType as DynType>::from_dyn_canonical_type(*initial_value_ty.element()),
 | 
					            Element::from_canonical(initial_value_ty.element()),
 | 
				
			||||||
            "Mem's element type must match initializer's element type",
 | 
					            "Mem's element type must match initializer's element type",
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        if let Some(depth) = depth {
 | 
					        if let Some(depth) = depth {
 | 
				
			||||||
| 
						 | 
					@ -889,7 +845,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        debug_assert_eq!(
 | 
					        debug_assert_eq!(
 | 
				
			||||||
            retval.len(),
 | 
					            retval.len(),
 | 
				
			||||||
            initial_value_ty.bit_width(),
 | 
					            initial_value_ty.type_properties().bit_width,
 | 
				
			||||||
            "initial value produced wrong literal bits length"
 | 
					            "initial value produced wrong literal bits length"
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        retval
 | 
					        retval
 | 
				
			||||||
| 
						 | 
					@ -898,9 +854,9 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
				
			||||||
    pub(crate) fn new(
 | 
					    pub(crate) fn new(
 | 
				
			||||||
        scoped_name: ScopedNameId,
 | 
					        scoped_name: ScopedNameId,
 | 
				
			||||||
        source_location: SourceLocation,
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
        mem_element_type: VA::ElementType,
 | 
					        mem_element_type: Element,
 | 
				
			||||||
    ) -> (Self, Rc<RefCell<MemBuilderTarget>>) {
 | 
					    ) -> (Self, Rc<RefCell<MemBuilderTarget>>) {
 | 
				
			||||||
        let canonical_mem_element_type = mem_element_type.canonical_dyn();
 | 
					        let canonical_mem_element_type = mem_element_type.canonical();
 | 
				
			||||||
        assert!(
 | 
					        assert!(
 | 
				
			||||||
            canonical_mem_element_type.is_storable(),
 | 
					            canonical_mem_element_type.is_storable(),
 | 
				
			||||||
            "memory element type must be a storable type"
 | 
					            "memory element type must be a storable type"
 | 
				
			||||||
| 
						 | 
					@ -909,7 +865,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
				
			||||||
            scoped_name,
 | 
					            scoped_name,
 | 
				
			||||||
            source_location,
 | 
					            source_location,
 | 
				
			||||||
            mem_element_type: canonical_mem_element_type,
 | 
					            mem_element_type: canonical_mem_element_type,
 | 
				
			||||||
            depth: VA::FIXED_LEN_TYPE.map(VA::len_from_len_type),
 | 
					            depth: Len::KNOWN_VALUE,
 | 
				
			||||||
            initial_value: None,
 | 
					            initial_value: None,
 | 
				
			||||||
            ports: vec![],
 | 
					            ports: vec![],
 | 
				
			||||||
            read_latency: 0,
 | 
					            read_latency: 0,
 | 
				
			||||||
| 
						 | 
					@ -922,6 +878,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
				
			||||||
            Self {
 | 
					            Self {
 | 
				
			||||||
                mem_element_type,
 | 
					                mem_element_type,
 | 
				
			||||||
                target: Rc::clone(&target),
 | 
					                target: Rc::clone(&target),
 | 
				
			||||||
 | 
					                _phantom: PhantomData,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            target,
 | 
					            target,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
| 
						 | 
					@ -931,19 +888,19 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        source_location: SourceLocation,
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
        port_kind: PortKind,
 | 
					        port_kind: PortKind,
 | 
				
			||||||
    ) -> Interned<MemPort<DynPortType>> {
 | 
					    ) -> MemPort<DynPortType> {
 | 
				
			||||||
        let mut target = self.target.borrow_mut();
 | 
					        let mut target = self.target.borrow_mut();
 | 
				
			||||||
        let Some(depth) = target.depth else {
 | 
					        let Some(depth) = target.depth else {
 | 
				
			||||||
            panic!("MemBuilder::depth must be called before adding ports");
 | 
					            panic!("MemBuilder::depth must be called before adding ports");
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let port = Intern::intern_sized(MemPort {
 | 
					        let port = MemPort {
 | 
				
			||||||
            mem_name: target.scoped_name,
 | 
					            mem_name: target.scoped_name,
 | 
				
			||||||
            source_location,
 | 
					            source_location,
 | 
				
			||||||
            port_kind,
 | 
					            port_kind,
 | 
				
			||||||
            port_index: target.ports.len(),
 | 
					            port_index: target.ports.len(),
 | 
				
			||||||
            addr_type: DynUIntType::new(memory_addr_width(depth)),
 | 
					            addr_type: UInt::new(memory_addr_width(depth)),
 | 
				
			||||||
            mem_element_type: target.mem_element_type,
 | 
					            mem_element_type: target.mem_element_type,
 | 
				
			||||||
        });
 | 
					        };
 | 
				
			||||||
        target.ports.push(port);
 | 
					        target.ports.push(port);
 | 
				
			||||||
        port
 | 
					        port
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -952,50 +909,53 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        source_location: SourceLocation,
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
        kind: PortKind,
 | 
					        kind: PortKind,
 | 
				
			||||||
    ) -> Expr<DynBundle> {
 | 
					    ) -> Expr<Bundle> {
 | 
				
			||||||
        Expr::new_unchecked(ExprEnum::MemPort(self.new_port_impl(source_location, kind)))
 | 
					        self.new_port_impl(source_location, kind).to_expr()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn new_port(&mut self, kind: PortKind) -> Expr<DynBundle> {
 | 
					    pub fn new_port(&mut self, kind: PortKind) -> Expr<Bundle> {
 | 
				
			||||||
        self.new_port_with_loc(SourceLocation::caller(), kind)
 | 
					        self.new_port_with_loc(SourceLocation::caller(), kind)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn new_read_port_with_loc(
 | 
					    pub fn new_read_port_with_loc(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        source_location: SourceLocation,
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
    ) -> Expr<ReadStruct<VA::Element>> {
 | 
					    ) -> Expr<ReadStruct<Element, DynSize>> {
 | 
				
			||||||
        Expr::new_unchecked(ExprEnum::MemPort(
 | 
					        Expr::from_bundle(
 | 
				
			||||||
            self.new_port_impl(source_location, PortKind::ReadOnly),
 | 
					            self.new_port_impl(source_location, PortKind::ReadOnly)
 | 
				
			||||||
        ))
 | 
					                .to_expr(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn new_read_port(&mut self) -> Expr<ReadStruct<VA::Element>> {
 | 
					    pub fn new_read_port(&mut self) -> Expr<ReadStruct<Element, DynSize>> {
 | 
				
			||||||
        self.new_read_port_with_loc(SourceLocation::caller())
 | 
					        self.new_read_port_with_loc(SourceLocation::caller())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn new_write_port_with_loc(
 | 
					    pub fn new_write_port_with_loc(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        source_location: SourceLocation,
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
    ) -> Expr<WriteStruct<VA::Element>> {
 | 
					    ) -> Expr<WriteStruct<Element, DynSize>> {
 | 
				
			||||||
        Expr::new_unchecked(ExprEnum::MemPort(
 | 
					        Expr::from_bundle(
 | 
				
			||||||
            self.new_port_impl(source_location, PortKind::WriteOnly),
 | 
					            self.new_port_impl(source_location, PortKind::WriteOnly)
 | 
				
			||||||
        ))
 | 
					                .to_expr(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn new_write_port(&mut self) -> Expr<WriteStruct<VA::Element>> {
 | 
					    pub fn new_write_port(&mut self) -> Expr<WriteStruct<Element, DynSize>> {
 | 
				
			||||||
        self.new_write_port_with_loc(SourceLocation::caller())
 | 
					        self.new_write_port_with_loc(SourceLocation::caller())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn new_rw_port_with_loc(
 | 
					    pub fn new_rw_port_with_loc(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        source_location: SourceLocation,
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
    ) -> Expr<ReadWriteStruct<VA::Element>> {
 | 
					    ) -> Expr<ReadWriteStruct<Element, DynSize>> {
 | 
				
			||||||
        Expr::new_unchecked(ExprEnum::MemPort(
 | 
					        Expr::from_bundle(
 | 
				
			||||||
            self.new_port_impl(source_location, PortKind::ReadWrite),
 | 
					            self.new_port_impl(source_location, PortKind::ReadWrite)
 | 
				
			||||||
        ))
 | 
					                .to_expr(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn new_rw_port(&mut self) -> Expr<ReadWriteStruct<VA::Element>> {
 | 
					    pub fn new_rw_port(&mut self) -> Expr<ReadWriteStruct<Element, DynSize>> {
 | 
				
			||||||
        self.new_rw_port_with_loc(SourceLocation::caller())
 | 
					        self.new_rw_port_with_loc(SourceLocation::caller())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn scoped_name(&self) -> ScopedNameId {
 | 
					    pub fn scoped_name(&self) -> ScopedNameId {
 | 
				
			||||||
| 
						 | 
					@ -1004,7 +964,7 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
				
			||||||
    pub fn source_location(&self) -> SourceLocation {
 | 
					    pub fn source_location(&self) -> SourceLocation {
 | 
				
			||||||
        self.target.borrow().source_location
 | 
					        self.target.borrow().source_location
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn get_mem_element_type(&self) -> &VA::ElementType {
 | 
					    pub fn get_mem_element_type(&self) -> &Element {
 | 
				
			||||||
        &self.mem_element_type
 | 
					        &self.mem_element_type
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[allow(clippy::result_unit_err)]
 | 
					    #[allow(clippy::result_unit_err)]
 | 
				
			||||||
| 
						 | 
					@ -1027,28 +987,28 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
				
			||||||
        target.depth = Some(depth);
 | 
					        target.depth = Some(depth);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[allow(clippy::result_unit_err)]
 | 
					    #[allow(clippy::result_unit_err)]
 | 
				
			||||||
    pub fn get_array_type(&self) -> Result<ArrayType<VA>, ()> {
 | 
					    pub fn get_array_type(&self) -> Result<ArrayType<Element, Len>, ()> {
 | 
				
			||||||
        Ok(ArrayType::new_with_len(
 | 
					        Ok(ArrayType::new(
 | 
				
			||||||
            self.mem_element_type.clone(),
 | 
					            self.mem_element_type.clone(),
 | 
				
			||||||
            self.get_depth()?,
 | 
					            Len::from_usize(self.get_depth()?),
 | 
				
			||||||
        ))
 | 
					        ))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn get_initial_value(&self) -> Option<Interned<BitSlice>> {
 | 
					    pub fn get_initial_value(&self) -> Option<Interned<BitSlice>> {
 | 
				
			||||||
        self.target.borrow().initial_value
 | 
					        self.target.borrow().initial_value
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn initial_value(&mut self, initial_value: impl ToExpr<Type = ArrayType<VA>>) {
 | 
					    pub fn initial_value(&mut self, initial_value: impl ToExpr<Type = ArrayType<Element, Len>>) {
 | 
				
			||||||
        let mut target = self.target.borrow_mut();
 | 
					        let mut target = self.target.borrow_mut();
 | 
				
			||||||
        if target.initial_value.is_some() {
 | 
					        if target.initial_value.is_some() {
 | 
				
			||||||
            panic!("can't set Mem's initial value more than once");
 | 
					            panic!("can't set Mem's initial value more than once");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let initial_value = initial_value.to_expr().canonical();
 | 
					        let initial_value = Expr::as_dyn_array(initial_value.to_expr());
 | 
				
			||||||
        target.initial_value = Some(Self::check_initial_value_expr(
 | 
					        target.initial_value = Some(Self::check_initial_value_expr(
 | 
				
			||||||
            &self.mem_element_type,
 | 
					            &self.mem_element_type,
 | 
				
			||||||
            target.depth,
 | 
					            target.depth,
 | 
				
			||||||
            initial_value,
 | 
					            initial_value,
 | 
				
			||||||
        ));
 | 
					        ));
 | 
				
			||||||
        target.depth = Some(initial_value.ty().len());
 | 
					        target.depth = Some(Expr::ty(initial_value).len());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn initial_value_bit_slice(&mut self, initial_value: Interned<BitSlice>) {
 | 
					    pub fn initial_value_bit_slice(&mut self, initial_value: Interned<BitSlice>) {
 | 
				
			||||||
| 
						 | 
					@ -1057,11 +1017,11 @@ impl<VA: ValueArrayOrSlice + ?Sized> MemBuilder<VA> {
 | 
				
			||||||
            panic!("can't set Mem's initial value more than once");
 | 
					            panic!("can't set Mem's initial value more than once");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        target.initial_value = Some(Self::check_initial_value_bit_slice(
 | 
					        target.initial_value = Some(Self::check_initial_value_bit_slice(
 | 
				
			||||||
            &self.mem_element_type,
 | 
					            self.mem_element_type,
 | 
				
			||||||
            target.depth,
 | 
					            target.depth,
 | 
				
			||||||
            initial_value,
 | 
					            initial_value,
 | 
				
			||||||
        ));
 | 
					        ));
 | 
				
			||||||
        let element_bit_width = self.mem_element_type.bit_width();
 | 
					        let element_bit_width = self.mem_element_type.canonical().bit_width();
 | 
				
			||||||
        if element_bit_width != 0 {
 | 
					        if element_bit_width != 0 {
 | 
				
			||||||
            target.depth = Some(initial_value.len() / element_bit_width);
 | 
					            target.depth = Some(initial_value.len() / element_bit_width);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,5 +1,14 @@
 | 
				
			||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
					// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
 | 
					// TODO:
 | 
				
			||||||
pub mod simplify_enums;
 | 
					pub mod simplify_enums;
 | 
				
			||||||
pub mod simplify_memories;
 | 
					//pub mod simplify_memories;
 | 
				
			||||||
pub mod visit;
 | 
					pub mod visit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod simplify_memories {
 | 
				
			||||||
 | 
					    use crate::{bundle::Bundle, intern::Interned, module::Module};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn simplify_memories(_module: Interned<Module<Bundle>>) -> Interned<Module<Bundle>> {
 | 
				
			||||||
 | 
					        todo!()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,14 @@
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    array::{Array, ArrayType},
 | 
					    array::{Array, ArrayType},
 | 
				
			||||||
    bundle::{BundleType, BundleValue, DynBundle, DynBundleType},
 | 
					    bundle::{Bundle, BundleType},
 | 
				
			||||||
    enum_::{DynEnum, DynEnumType, EnumType, EnumValue, VariantType},
 | 
					    enum_::{Enum, EnumType, EnumVariant},
 | 
				
			||||||
    expr::{ops, Expr, ExprEnum, ToExpr},
 | 
					    expr::{
 | 
				
			||||||
    int::{DynUInt, DynUIntType, IntCmp},
 | 
					        ops::{self, EnumLiteral},
 | 
				
			||||||
 | 
					        CastBitsTo, CastToBits, Expr, ExprEnum, ToExpr,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    hdl,
 | 
				
			||||||
 | 
					    int::{DynSize, IntCmp, Size, UInt, UIntType},
 | 
				
			||||||
    intern::{Intern, Interned},
 | 
					    intern::{Intern, Interned},
 | 
				
			||||||
    memory::{DynPortType, Mem, MemPort},
 | 
					    memory::{DynPortType, Mem, MemPort},
 | 
				
			||||||
    module::{
 | 
					    module::{
 | 
				
			||||||
| 
						 | 
					@ -13,7 +17,7 @@ use crate::{
 | 
				
			||||||
        Block, Module, NameIdGen, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
 | 
					        Block, Module, NameIdGen, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{DynCanonicalType, DynCanonicalValue, Type, TypeEnum, Value, ValueEnum},
 | 
					    ty::{CanonicalType, Type},
 | 
				
			||||||
    wire::Wire,
 | 
					    wire::Wire,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use core::fmt;
 | 
					use core::fmt;
 | 
				
			||||||
| 
						 | 
					@ -21,7 +25,7 @@ use hashbrown::HashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub enum SimplifyEnumsError {
 | 
					pub enum SimplifyEnumsError {
 | 
				
			||||||
    EnumIsNotCastableFromBits { enum_type: DynEnumType },
 | 
					    EnumIsNotCastableFromBits { enum_type: Enum },
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl fmt::Display for SimplifyEnumsError {
 | 
					impl fmt::Display for SimplifyEnumsError {
 | 
				
			||||||
| 
						 | 
					@ -37,26 +41,23 @@ impl fmt::Display for SimplifyEnumsError {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl std::error::Error for SimplifyEnumsError {}
 | 
					impl std::error::Error for SimplifyEnumsError {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Value, Clone, Eq, PartialEq, Hash, Debug)]
 | 
					#[hdl]
 | 
				
			||||||
struct TagAndBody<T> {
 | 
					struct TagAndBody<T, BodyWidth: Size> {
 | 
				
			||||||
    tag: T,
 | 
					    tag: T,
 | 
				
			||||||
    body: DynUInt,
 | 
					    body: UIntType<BodyWidth>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type TagAndBodyType<T> = <TagAndBody<T> as ToExpr>::Type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
enum EnumTypeState {
 | 
					enum EnumTypeState {
 | 
				
			||||||
    TagEnumAndBody(TagAndBodyType<DynEnum>),
 | 
					    TagEnumAndBody(TagAndBody<Enum, DynSize>),
 | 
				
			||||||
    TagUIntAndBody(TagAndBodyType<DynUInt>),
 | 
					    TagUIntAndBody(TagAndBody<UInt, DynSize>),
 | 
				
			||||||
    UInt(DynUIntType),
 | 
					    UInt(UInt),
 | 
				
			||||||
    Unchanged,
 | 
					    Unchanged,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct State {
 | 
					struct State {
 | 
				
			||||||
    enum_types: HashMap<DynEnumType, EnumTypeState>,
 | 
					    enum_types: HashMap<Enum, EnumTypeState>,
 | 
				
			||||||
    replacement_mem_ports:
 | 
					    replacement_mem_ports: HashMap<MemPort<DynPortType>, Wire<CanonicalType>>,
 | 
				
			||||||
        HashMap<Interned<MemPort<DynPortType>>, Interned<Wire<Interned<dyn DynCanonicalType>>>>,
 | 
					 | 
				
			||||||
    kind: SimplifyEnumsKind,
 | 
					    kind: SimplifyEnumsKind,
 | 
				
			||||||
    name_id_gen: NameIdGen,
 | 
					    name_id_gen: NameIdGen,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -64,12 +65,12 @@ struct State {
 | 
				
			||||||
impl State {
 | 
					impl State {
 | 
				
			||||||
    fn get_or_make_enum_type_state(
 | 
					    fn get_or_make_enum_type_state(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        enum_type: DynEnumType,
 | 
					        enum_type: Enum,
 | 
				
			||||||
    ) -> Result<EnumTypeState, SimplifyEnumsError> {
 | 
					    ) -> Result<EnumTypeState, SimplifyEnumsError> {
 | 
				
			||||||
        if let Some(retval) = self.enum_types.get(&enum_type) {
 | 
					        if let Some(retval) = self.enum_types.get(&enum_type) {
 | 
				
			||||||
            return Ok(retval.clone());
 | 
					            return Ok(retval.clone());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if !enum_type.is_castable_from_bits() {
 | 
					        if !enum_type.type_properties().is_castable_from_bits {
 | 
				
			||||||
            return Err(SimplifyEnumsError::EnumIsNotCastableFromBits { enum_type });
 | 
					            return Err(SimplifyEnumsError::EnumIsNotCastableFromBits { enum_type });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let has_body = enum_type
 | 
					        let has_body = enum_type
 | 
				
			||||||
| 
						 | 
					@ -78,29 +79,29 @@ impl State {
 | 
				
			||||||
            .any(|variant| variant.ty.is_some());
 | 
					            .any(|variant| variant.ty.is_some());
 | 
				
			||||||
        let retval = match (self.kind, has_body) {
 | 
					        let retval = match (self.kind, has_body) {
 | 
				
			||||||
            (SimplifyEnumsKind::SimplifyToEnumsWithNoBody, true) => {
 | 
					            (SimplifyEnumsKind::SimplifyToEnumsWithNoBody, true) => {
 | 
				
			||||||
                EnumTypeState::TagEnumAndBody(TagAndBodyType::<DynEnum> {
 | 
					                EnumTypeState::TagEnumAndBody(TagAndBody {
 | 
				
			||||||
                    tag: DynEnumType::new(Interned::from_iter(enum_type.variants().iter().map(
 | 
					                    tag: Enum::new(Interned::from_iter(enum_type.variants().iter().map(|v| {
 | 
				
			||||||
                        |v| VariantType {
 | 
					                        EnumVariant {
 | 
				
			||||||
                            name: v.name,
 | 
					                            name: v.name,
 | 
				
			||||||
                            ty: None,
 | 
					                            ty: None,
 | 
				
			||||||
                        },
 | 
					                        }
 | 
				
			||||||
                    ))),
 | 
					                    }))),
 | 
				
			||||||
                    body: DynUIntType::new(
 | 
					                    body: UInt::new_dyn(
 | 
				
			||||||
                        enum_type.bit_width() - enum_type.discriminant_bit_width(),
 | 
					                        enum_type.type_properties().bit_width - enum_type.discriminant_bit_width(),
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            (SimplifyEnumsKind::SimplifyToEnumsWithNoBody, false) => EnumTypeState::Unchanged,
 | 
					            (SimplifyEnumsKind::SimplifyToEnumsWithNoBody, false) => EnumTypeState::Unchanged,
 | 
				
			||||||
            (SimplifyEnumsKind::ReplaceWithBundleOfUInts, _) => {
 | 
					            (SimplifyEnumsKind::ReplaceWithBundleOfUInts, _) => {
 | 
				
			||||||
                EnumTypeState::TagUIntAndBody(TagAndBodyType::<DynUInt> {
 | 
					                EnumTypeState::TagUIntAndBody(TagAndBody {
 | 
				
			||||||
                    tag: DynUIntType::new(enum_type.discriminant_bit_width()),
 | 
					                    tag: UInt::new_dyn(enum_type.discriminant_bit_width()),
 | 
				
			||||||
                    body: DynUIntType::new(
 | 
					                    body: UInt::new_dyn(
 | 
				
			||||||
                        enum_type.bit_width() - enum_type.discriminant_bit_width(),
 | 
					                        enum_type.type_properties().bit_width - enum_type.discriminant_bit_width(),
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            (SimplifyEnumsKind::ReplaceWithUInt, _) => {
 | 
					            (SimplifyEnumsKind::ReplaceWithUInt, _) => {
 | 
				
			||||||
                EnumTypeState::UInt(DynUIntType::new(enum_type.bit_width()))
 | 
					                EnumTypeState::UInt(UInt::new_dyn(enum_type.type_properties().bit_width))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        self.enum_types.insert(enum_type, retval.clone());
 | 
					        self.enum_types.insert(enum_type, retval.clone());
 | 
				
			||||||
| 
						 | 
					@ -108,21 +109,14 @@ impl State {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn value_to_uint<T: Value>(value: Option<&T>, target_ty: DynUIntType) -> DynUInt {
 | 
					 | 
				
			||||||
    let Some(value) = value else {
 | 
					 | 
				
			||||||
        return DynUInt::with_type(target_ty, 0u8);
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    DynUInt::from_bit_slice(&value.to_bits())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn connect_port(
 | 
					fn connect_port(
 | 
				
			||||||
    stmts: &mut Vec<Stmt>,
 | 
					    stmts: &mut Vec<Stmt>,
 | 
				
			||||||
    lhs: Expr<DynCanonicalValue>,
 | 
					    lhs: Expr<CanonicalType>,
 | 
				
			||||||
    rhs: Expr<DynCanonicalValue>,
 | 
					    rhs: Expr<CanonicalType>,
 | 
				
			||||||
    source_location: SourceLocation,
 | 
					    source_location: SourceLocation,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    println!("connect_port: lhs={lhs:?} rhs={rhs:?}");
 | 
					    println!("connect_port: lhs={lhs:?} rhs={rhs:?}");
 | 
				
			||||||
    if lhs.canonical_type() == rhs.canonical_type() {
 | 
					    if Expr::ty(lhs) == Expr::ty(rhs) {
 | 
				
			||||||
        stmts.push(
 | 
					        stmts.push(
 | 
				
			||||||
            dbg!(StmtConnect {
 | 
					            dbg!(StmtConnect {
 | 
				
			||||||
                lhs,
 | 
					                lhs,
 | 
				
			||||||
| 
						 | 
					@ -133,55 +127,53 @@ fn connect_port(
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    match (
 | 
					    match (Expr::ty(lhs), Expr::ty(rhs)) {
 | 
				
			||||||
        lhs.canonical_type().type_enum(),
 | 
					        (CanonicalType::Bundle(lhs_type), CanonicalType::UInt(_)) => {
 | 
				
			||||||
        rhs.canonical_type().type_enum(),
 | 
					            let lhs = Expr::<Bundle>::from_canonical(lhs);
 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        (TypeEnum::BundleType(lhs_type), TypeEnum::UInt(_)) => {
 | 
					 | 
				
			||||||
            let lhs = lhs.with_type::<DynBundle>();
 | 
					 | 
				
			||||||
            for field in lhs_type.fields() {
 | 
					            for field in lhs_type.fields() {
 | 
				
			||||||
                assert!(!field.flipped);
 | 
					                assert!(!field.flipped);
 | 
				
			||||||
                connect_port(stmts, lhs.field(&field.name), rhs, source_location);
 | 
					                connect_port(stmts, Expr::field(lhs, &field.name), rhs, source_location);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        (TypeEnum::UInt(_), TypeEnum::BundleType(rhs_type)) => {
 | 
					        (CanonicalType::UInt(_), CanonicalType::Bundle(rhs_type)) => {
 | 
				
			||||||
            let rhs = rhs.with_type::<DynBundle>();
 | 
					            let rhs = Expr::<Bundle>::from_canonical(rhs);
 | 
				
			||||||
            for field in rhs_type.fields() {
 | 
					            for field in rhs_type.fields() {
 | 
				
			||||||
                assert!(!field.flipped);
 | 
					                assert!(!field.flipped);
 | 
				
			||||||
                connect_port(stmts, lhs, rhs.field(&field.name), source_location);
 | 
					                connect_port(stmts, lhs, Expr::field(rhs, &field.name), source_location);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        (TypeEnum::BundleType(lhs_type), TypeEnum::BundleType(_)) => {
 | 
					        (CanonicalType::Bundle(lhs_type), CanonicalType::Bundle(_)) => {
 | 
				
			||||||
            let lhs = lhs.with_type::<DynBundle>();
 | 
					            let lhs = Expr::<Bundle>::from_canonical(lhs);
 | 
				
			||||||
            let rhs = rhs.with_type::<DynBundle>();
 | 
					            let rhs = Expr::<Bundle>::from_canonical(rhs);
 | 
				
			||||||
            for field in lhs_type.fields() {
 | 
					            for field in lhs_type.fields() {
 | 
				
			||||||
                let (lhs_field, rhs_field) = if field.flipped {
 | 
					                let (lhs_field, rhs_field) = if field.flipped {
 | 
				
			||||||
                    (rhs.field(&field.name), lhs.field(&field.name))
 | 
					                    (Expr::field(rhs, &field.name), Expr::field(lhs, &field.name))
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    (lhs.field(&field.name), rhs.field(&field.name))
 | 
					                    (Expr::field(lhs, &field.name), Expr::field(rhs, &field.name))
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                connect_port(stmts, lhs_field, rhs_field, source_location);
 | 
					                connect_port(stmts, lhs_field, rhs_field, source_location);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        (TypeEnum::ArrayType(lhs_type), TypeEnum::ArrayType(_)) => {
 | 
					        (CanonicalType::Array(lhs_type), CanonicalType::Array(_)) => {
 | 
				
			||||||
            let lhs = lhs.with_type::<Array<[DynCanonicalValue]>>();
 | 
					            let lhs = Expr::<Array>::from_canonical(lhs);
 | 
				
			||||||
            let rhs = rhs.with_type::<Array<[DynCanonicalValue]>>();
 | 
					            let rhs = Expr::<Array>::from_canonical(rhs);
 | 
				
			||||||
            for index in 0..lhs_type.len() {
 | 
					            for index in 0..lhs_type.len() {
 | 
				
			||||||
                connect_port(stmts, lhs[index], rhs[index], source_location);
 | 
					                connect_port(stmts, lhs[index], rhs[index], source_location);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        (TypeEnum::BundleType(_), _)
 | 
					        (CanonicalType::Bundle(_), _)
 | 
				
			||||||
        | (TypeEnum::EnumType(_), _)
 | 
					        | (CanonicalType::Enum(_), _)
 | 
				
			||||||
        | (TypeEnum::ArrayType(_), _)
 | 
					        | (CanonicalType::Array(_), _)
 | 
				
			||||||
        | (TypeEnum::UInt(_), _)
 | 
					        | (CanonicalType::UInt(_), _)
 | 
				
			||||||
        | (TypeEnum::SInt(_), _)
 | 
					        | (CanonicalType::SInt(_), _)
 | 
				
			||||||
        | (TypeEnum::Clock(_), _)
 | 
					        | (CanonicalType::Bool(_), _)
 | 
				
			||||||
        | (TypeEnum::AsyncReset(_), _)
 | 
					        | (CanonicalType::Clock(_), _)
 | 
				
			||||||
        | (TypeEnum::SyncReset(_), _)
 | 
					        | (CanonicalType::AsyncReset(_), _)
 | 
				
			||||||
        | (TypeEnum::Reset(_), _) => unreachable!(
 | 
					        | (CanonicalType::SyncReset(_), _)
 | 
				
			||||||
 | 
					        | (CanonicalType::Reset(_), _) => unreachable!(
 | 
				
			||||||
            "trying to connect memory ports:\n{:?}\n{:?}",
 | 
					            "trying to connect memory ports:\n{:?}\n{:?}",
 | 
				
			||||||
            lhs.canonical_type().type_enum(),
 | 
					            Expr::ty(lhs),
 | 
				
			||||||
            rhs.canonical_type().type_enum(),
 | 
					            Expr::ty(rhs),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -189,18 +181,11 @@ fn connect_port(
 | 
				
			||||||
impl Folder for State {
 | 
					impl Folder for State {
 | 
				
			||||||
    type Error = SimplifyEnumsError;
 | 
					    type Error = SimplifyEnumsError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn fold_dyn_enum(&mut self, _v: DynEnum) -> Result<DynEnum, Self::Error> {
 | 
					    fn fold_enum(&mut self, _v: Enum) -> Result<Enum, Self::Error> {
 | 
				
			||||||
        unreachable!()
 | 
					        unreachable!()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn fold_dyn_enum_type(&mut self, _v: DynEnumType) -> Result<DynEnumType, Self::Error> {
 | 
					    fn fold_module<T: BundleType>(&mut self, v: Module<T>) -> Result<Module<T>, Self::Error> {
 | 
				
			||||||
        unreachable!()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn fold_module<T: BundleValue>(&mut self, v: Module<T>) -> Result<Module<T>, Self::Error>
 | 
					 | 
				
			||||||
    where
 | 
					 | 
				
			||||||
        T::Type: BundleType<Value = T>,
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        let old_name_id_gen =
 | 
					        let old_name_id_gen =
 | 
				
			||||||
            std::mem::replace(&mut self.name_id_gen, NameIdGen::for_module(v.canonical()));
 | 
					            std::mem::replace(&mut self.name_id_gen, NameIdGen::for_module(v.canonical()));
 | 
				
			||||||
        let retval = Fold::default_fold(v, self);
 | 
					        let retval = Fold::default_fold(v, self);
 | 
				
			||||||
| 
						 | 
					@ -211,98 +196,86 @@ impl Folder for State {
 | 
				
			||||||
    fn fold_expr_enum(&mut self, op: ExprEnum) -> Result<ExprEnum, Self::Error> {
 | 
					    fn fold_expr_enum(&mut self, op: ExprEnum) -> Result<ExprEnum, Self::Error> {
 | 
				
			||||||
        match op {
 | 
					        match op {
 | 
				
			||||||
            ExprEnum::EnumLiteral(op) => Ok(match self.get_or_make_enum_type_state(op.ty())? {
 | 
					            ExprEnum::EnumLiteral(op) => Ok(match self.get_or_make_enum_type_state(op.ty())? {
 | 
				
			||||||
                EnumTypeState::TagEnumAndBody(TagAndBodyType::<DynEnum> { tag, body }) => {
 | 
					                EnumTypeState::TagEnumAndBody(TagAndBody { tag, body }) => *Expr::expr_enum(
 | 
				
			||||||
                    TagAndBodyType::<DynEnum>::builder()
 | 
					                    <TagAndBody<Enum, DynSize> as BundleType>::Builder::default()
 | 
				
			||||||
                        .field_tag(DynEnum::new_by_index(tag, op.variant_index(), None))
 | 
					                        .field_tag(EnumLiteral::new_by_index(tag, op.variant_index(), None))
 | 
				
			||||||
                        .field_body(match op.variant_value() {
 | 
					                        .field_body(match op.variant_value() {
 | 
				
			||||||
                            Some(variant_value) => variant_value.fold(self)?.cast_to_bits(),
 | 
					                            Some(variant_value) => variant_value.fold(self)?.cast_to_bits(),
 | 
				
			||||||
                            None => DynUInt::with_type(body, 0u8).to_expr(),
 | 
					                            None => body.zero().to_expr(),
 | 
				
			||||||
                        })
 | 
					                        })
 | 
				
			||||||
                        .build()
 | 
					                        .to_expr(),
 | 
				
			||||||
                        .expr_enum()
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                EnumTypeState::TagUIntAndBody(TagAndBodyType::<DynUInt> { tag, body }) => {
 | 
					 | 
				
			||||||
                    TagAndBodyType::<DynUInt>::builder()
 | 
					 | 
				
			||||||
                        .field_tag(DynUInt::with_type(tag, op.variant_index()))
 | 
					 | 
				
			||||||
                        .field_body(match op.variant_value() {
 | 
					 | 
				
			||||||
                            Some(variant_value) => variant_value.fold(self)?.cast_to_bits(),
 | 
					 | 
				
			||||||
                            None => DynUInt::with_type(body, 0u8).to_expr(),
 | 
					 | 
				
			||||||
                        })
 | 
					 | 
				
			||||||
                        .build()
 | 
					 | 
				
			||||||
                        .expr_enum()
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                EnumTypeState::UInt(_) => TagAndBodyType::<DynUInt>::builder()
 | 
					 | 
				
			||||||
                    .field_tag(DynUInt::with_type(
 | 
					 | 
				
			||||||
                        DynUIntType::new(op.ty().discriminant_bit_width()),
 | 
					 | 
				
			||||||
                        op.variant_index(),
 | 
					 | 
				
			||||||
                    ))
 | 
					 | 
				
			||||||
                    .field_body(match op.variant_value() {
 | 
					 | 
				
			||||||
                        Some(variant_value) => variant_value.fold(self)?.cast_to_bits(),
 | 
					 | 
				
			||||||
                        None => DynUInt::with_type(
 | 
					 | 
				
			||||||
                            DynUIntType::new(
 | 
					 | 
				
			||||||
                                op.ty().bit_width() - op.ty().discriminant_bit_width(),
 | 
					 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                            0u8,
 | 
					                EnumTypeState::TagUIntAndBody(TagAndBody { tag, body }) => *Expr::expr_enum(
 | 
				
			||||||
 | 
					                    <TagAndBody<UInt, DynSize> as BundleType>::Builder::default()
 | 
				
			||||||
 | 
					                        .field_tag(tag.from_int_wrapping(op.variant_index()))
 | 
				
			||||||
 | 
					                        .field_body(match op.variant_value() {
 | 
				
			||||||
 | 
					                            Some(variant_value) => variant_value.fold(self)?.cast_to_bits(),
 | 
				
			||||||
 | 
					                            None => body.zero().to_expr(),
 | 
				
			||||||
 | 
					                        })
 | 
				
			||||||
 | 
					                        .to_expr(),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                EnumTypeState::UInt(_) => *Expr::expr_enum(
 | 
				
			||||||
 | 
					                    <TagAndBody<UInt, DynSize> as BundleType>::Builder::default()
 | 
				
			||||||
 | 
					                        .field_tag(
 | 
				
			||||||
 | 
					                            UIntType::new(op.ty().discriminant_bit_width())
 | 
				
			||||||
 | 
					                                .from_int_wrapping(op.variant_index()),
 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
 | 
					                        .field_body(match op.variant_value() {
 | 
				
			||||||
 | 
					                            Some(variant_value) => variant_value.fold(self)?.cast_to_bits(),
 | 
				
			||||||
 | 
					                            None => UIntType::new(
 | 
				
			||||||
 | 
					                                op.ty().type_properties().bit_width
 | 
				
			||||||
 | 
					                                    - op.ty().discriminant_bit_width(),
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                            .zero()
 | 
				
			||||||
                            .to_expr(),
 | 
					                            .to_expr(),
 | 
				
			||||||
                        })
 | 
					                        })
 | 
				
			||||||
                    .build()
 | 
					                        .cast_to_bits(),
 | 
				
			||||||
                    .cast_to_bits()
 | 
					 | 
				
			||||||
                    .expr_enum(),
 | 
					 | 
				
			||||||
                EnumTypeState::Unchanged => ExprEnum::EnumLiteral(
 | 
					 | 
				
			||||||
                    ops::EnumLiteral::new_unchecked(
 | 
					 | 
				
			||||||
                        op.variant_value().map(|v| v.fold(self)).transpose()?,
 | 
					 | 
				
			||||||
                        op.variant_index(),
 | 
					 | 
				
			||||||
                        op.ty(),
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                    .intern_sized(),
 | 
					 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
 | 
					                EnumTypeState::Unchanged => ExprEnum::EnumLiteral(ops::EnumLiteral::new_by_index(
 | 
				
			||||||
 | 
					                    op.ty(),
 | 
				
			||||||
 | 
					                    op.variant_index(),
 | 
				
			||||||
 | 
					                    op.variant_value().map(|v| v.fold(self)).transpose()?,
 | 
				
			||||||
 | 
					                )),
 | 
				
			||||||
            }),
 | 
					            }),
 | 
				
			||||||
            ExprEnum::VariantAccess(op) => {
 | 
					            ExprEnum::VariantAccess(op) => Ok(
 | 
				
			||||||
                Ok(match self.get_or_make_enum_type_state(op.base().ty())? {
 | 
					                match self.get_or_make_enum_type_state(Expr::ty(op.base()))? {
 | 
				
			||||||
                    EnumTypeState::TagEnumAndBody(_) | EnumTypeState::TagUIntAndBody(_) => {
 | 
					                    EnumTypeState::TagEnumAndBody(_) | EnumTypeState::TagUIntAndBody(_) => {
 | 
				
			||||||
                        match op.variant_type().ty {
 | 
					                        match op.variant_type() {
 | 
				
			||||||
                            Some(_) => op
 | 
					                            Some(variant_type) => *Expr::expr_enum(
 | 
				
			||||||
                                .base()
 | 
					                                Expr::<TagAndBody<CanonicalType, DynSize>>::from_canonical(
 | 
				
			||||||
                                .expr_enum()
 | 
					                                    (*Expr::expr_enum(op.base())).fold(self)?.to_expr(),
 | 
				
			||||||
                                .fold(self)?
 | 
					                                )
 | 
				
			||||||
                                .to_expr()
 | 
					                                .body[..variant_type.bit_width()]
 | 
				
			||||||
                                .with_type::<TagAndBody<DynCanonicalValue>>()
 | 
					                                    .cast_bits_to(variant_type),
 | 
				
			||||||
                                .body[..op.ty().bit_width()]
 | 
					                            ),
 | 
				
			||||||
                                .cast_bits_to::<DynCanonicalValue>(op.ty())
 | 
					                            None => *Expr::expr_enum(().to_expr()),
 | 
				
			||||||
                                .expr_enum(),
 | 
					 | 
				
			||||||
                            None => ().to_expr().expr_enum(),
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    EnumTypeState::UInt(_) => match op.variant_type().ty {
 | 
					                    EnumTypeState::UInt(_) => match op.variant_type() {
 | 
				
			||||||
                        Some(_) => {
 | 
					                        Some(variant_type) => {
 | 
				
			||||||
                            let base_int = op
 | 
					                            let base_int = Expr::<UInt>::from_canonical(
 | 
				
			||||||
                                .base()
 | 
					                                (*Expr::expr_enum(op.base())).fold(self)?.to_expr(),
 | 
				
			||||||
                                .expr_enum()
 | 
					                            );
 | 
				
			||||||
                                .fold(self)?
 | 
					 | 
				
			||||||
                                .to_expr()
 | 
					 | 
				
			||||||
                                .with_type::<DynUInt>();
 | 
					 | 
				
			||||||
                            dbg!(base_int);
 | 
					                            dbg!(base_int);
 | 
				
			||||||
                            let base_ty = op.base().ty();
 | 
					                            let base_ty = Expr::ty(op.base());
 | 
				
			||||||
                            let ty_bit_width = op.ty().bit_width();
 | 
					                            let variant_type_bit_width = variant_type.bit_width();
 | 
				
			||||||
                            base_int[base_ty.discriminant_bit_width()..][..ty_bit_width]
 | 
					                            *Expr::expr_enum(
 | 
				
			||||||
                                .cast_bits_to::<DynCanonicalValue>(op.ty())
 | 
					                                base_int[base_ty.discriminant_bit_width()..]
 | 
				
			||||||
                                .expr_enum()
 | 
					                                    [..variant_type_bit_width]
 | 
				
			||||||
 | 
					                                    .cast_bits_to(variant_type),
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        None => ().to_expr().expr_enum(),
 | 
					                        None => *Expr::expr_enum(().to_expr()),
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    EnumTypeState::Unchanged => match op.variant_type().ty {
 | 
					                    EnumTypeState::Unchanged => match op.variant_type() {
 | 
				
			||||||
                        Some(_) => ExprEnum::VariantAccess(
 | 
					                        Some(_) => ExprEnum::VariantAccess(ops::VariantAccess::new_by_index(
 | 
				
			||||||
                            ops::VariantAccess::new_unchecked(
 | 
					 | 
				
			||||||
                            op.base().fold(self)?,
 | 
					                            op.base().fold(self)?,
 | 
				
			||||||
                            op.variant_index(),
 | 
					                            op.variant_index(),
 | 
				
			||||||
                            )
 | 
					                        )),
 | 
				
			||||||
                            .intern_sized(),
 | 
					                        None => *Expr::expr_enum(().to_expr()),
 | 
				
			||||||
                        ),
 | 
					 | 
				
			||||||
                        None => ().to_expr().expr_enum(),
 | 
					 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                })
 | 
					                },
 | 
				
			||||||
            }
 | 
					            ),
 | 
				
			||||||
            ExprEnum::MemPort(mem_port) => Ok(
 | 
					            ExprEnum::MemPort(mem_port) => Ok(
 | 
				
			||||||
                if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) {
 | 
					                if let Some(&wire) = self.replacement_mem_ports.get(&mem_port) {
 | 
				
			||||||
                    ExprEnum::Wire(wire)
 | 
					                    ExprEnum::Wire(wire)
 | 
				
			||||||
| 
						 | 
					@ -310,24 +283,34 @@ impl Folder for State {
 | 
				
			||||||
                    ExprEnum::MemPort(mem_port.fold(self)?)
 | 
					                    ExprEnum::MemPort(mem_port.fold(self)?)
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            ExprEnum::Literal(_)
 | 
					            ExprEnum::UIntLiteral(_)
 | 
				
			||||||
            | ExprEnum::ArrayLiteral(_)
 | 
					            | ExprEnum::SIntLiteral(_)
 | 
				
			||||||
 | 
					            | ExprEnum::BoolLiteral(_)
 | 
				
			||||||
            | ExprEnum::BundleLiteral(_)
 | 
					            | ExprEnum::BundleLiteral(_)
 | 
				
			||||||
 | 
					            | ExprEnum::ArrayLiteral(_)
 | 
				
			||||||
            | ExprEnum::NotU(_)
 | 
					            | ExprEnum::NotU(_)
 | 
				
			||||||
            | ExprEnum::NotS(_)
 | 
					            | ExprEnum::NotS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::NotB(_)
 | 
				
			||||||
            | ExprEnum::Neg(_)
 | 
					            | ExprEnum::Neg(_)
 | 
				
			||||||
            | ExprEnum::BitAndU(_)
 | 
					            | ExprEnum::BitAndU(_)
 | 
				
			||||||
            | ExprEnum::BitAndS(_)
 | 
					            | ExprEnum::BitAndS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::BitAndB(_)
 | 
				
			||||||
            | ExprEnum::BitOrU(_)
 | 
					            | ExprEnum::BitOrU(_)
 | 
				
			||||||
            | ExprEnum::BitOrS(_)
 | 
					            | ExprEnum::BitOrS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::BitOrB(_)
 | 
				
			||||||
            | ExprEnum::BitXorU(_)
 | 
					            | ExprEnum::BitXorU(_)
 | 
				
			||||||
            | ExprEnum::BitXorS(_)
 | 
					            | ExprEnum::BitXorS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::BitXorB(_)
 | 
				
			||||||
            | ExprEnum::AddU(_)
 | 
					            | ExprEnum::AddU(_)
 | 
				
			||||||
            | ExprEnum::AddS(_)
 | 
					            | ExprEnum::AddS(_)
 | 
				
			||||||
            | ExprEnum::SubU(_)
 | 
					            | ExprEnum::SubU(_)
 | 
				
			||||||
            | ExprEnum::SubS(_)
 | 
					            | ExprEnum::SubS(_)
 | 
				
			||||||
            | ExprEnum::MulU(_)
 | 
					            | ExprEnum::MulU(_)
 | 
				
			||||||
            | ExprEnum::MulS(_)
 | 
					            | ExprEnum::MulS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::DivU(_)
 | 
				
			||||||
 | 
					            | ExprEnum::DivS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::RemU(_)
 | 
				
			||||||
 | 
					            | ExprEnum::RemS(_)
 | 
				
			||||||
            | ExprEnum::DynShlU(_)
 | 
					            | ExprEnum::DynShlU(_)
 | 
				
			||||||
            | ExprEnum::DynShlS(_)
 | 
					            | ExprEnum::DynShlS(_)
 | 
				
			||||||
            | ExprEnum::DynShrU(_)
 | 
					            | ExprEnum::DynShrU(_)
 | 
				
			||||||
| 
						 | 
					@ -336,41 +319,68 @@ impl Folder for State {
 | 
				
			||||||
            | ExprEnum::FixedShlS(_)
 | 
					            | ExprEnum::FixedShlS(_)
 | 
				
			||||||
            | ExprEnum::FixedShrU(_)
 | 
					            | ExprEnum::FixedShrU(_)
 | 
				
			||||||
            | ExprEnum::FixedShrS(_)
 | 
					            | ExprEnum::FixedShrS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CmpLtB(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CmpLeB(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CmpGtB(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CmpGeB(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CmpEqB(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CmpNeB(_)
 | 
				
			||||||
            | ExprEnum::CmpLtU(_)
 | 
					            | ExprEnum::CmpLtU(_)
 | 
				
			||||||
            | ExprEnum::CmpLtS(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CmpLeU(_)
 | 
					            | ExprEnum::CmpLeU(_)
 | 
				
			||||||
            | ExprEnum::CmpLeS(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CmpGtU(_)
 | 
					            | ExprEnum::CmpGtU(_)
 | 
				
			||||||
            | ExprEnum::CmpGtS(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CmpGeU(_)
 | 
					            | ExprEnum::CmpGeU(_)
 | 
				
			||||||
            | ExprEnum::CmpGeS(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CmpEqU(_)
 | 
					            | ExprEnum::CmpEqU(_)
 | 
				
			||||||
            | ExprEnum::CmpEqS(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CmpNeU(_)
 | 
					            | ExprEnum::CmpNeU(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CmpLtS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CmpLeS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CmpGtS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CmpGeS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CmpEqS(_)
 | 
				
			||||||
            | ExprEnum::CmpNeS(_)
 | 
					            | ExprEnum::CmpNeS(_)
 | 
				
			||||||
            | ExprEnum::CastUIntToUInt(_)
 | 
					            | ExprEnum::CastUIntToUInt(_)
 | 
				
			||||||
            | ExprEnum::CastUIntToSInt(_)
 | 
					            | ExprEnum::CastUIntToSInt(_)
 | 
				
			||||||
            | ExprEnum::CastSIntToUInt(_)
 | 
					            | ExprEnum::CastSIntToUInt(_)
 | 
				
			||||||
            | ExprEnum::CastSIntToSInt(_)
 | 
					            | ExprEnum::CastSIntToSInt(_)
 | 
				
			||||||
            | ExprEnum::SliceUInt(_)
 | 
					            | ExprEnum::CastBoolToUInt(_)
 | 
				
			||||||
            | ExprEnum::SliceSInt(_)
 | 
					            | ExprEnum::CastBoolToSInt(_)
 | 
				
			||||||
            | ExprEnum::ReduceBitAnd(_)
 | 
					            | ExprEnum::CastUIntToBool(_)
 | 
				
			||||||
            | ExprEnum::ReduceBitOr(_)
 | 
					            | ExprEnum::CastSIntToBool(_)
 | 
				
			||||||
            | ExprEnum::ReduceBitXor(_)
 | 
					            | ExprEnum::CastBoolToSyncReset(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastUIntToSyncReset(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastSIntToSyncReset(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastBoolToAsyncReset(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastUIntToAsyncReset(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastSIntToAsyncReset(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastSyncResetToBool(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastSyncResetToUInt(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastSyncResetToSInt(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastSyncResetToReset(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastAsyncResetToBool(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastAsyncResetToUInt(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastAsyncResetToSInt(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastAsyncResetToReset(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastResetToBool(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastResetToUInt(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastResetToSInt(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastBoolToClock(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastUIntToClock(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastSIntToClock(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastClockToBool(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastClockToUInt(_)
 | 
				
			||||||
 | 
					            | ExprEnum::CastClockToSInt(_)
 | 
				
			||||||
            | ExprEnum::FieldAccess(_)
 | 
					            | ExprEnum::FieldAccess(_)
 | 
				
			||||||
            | ExprEnum::ArrayIndex(_)
 | 
					            | ExprEnum::ArrayIndex(_)
 | 
				
			||||||
            | ExprEnum::DynArrayIndex(_)
 | 
					            | ExprEnum::DynArrayIndex(_)
 | 
				
			||||||
 | 
					            | ExprEnum::ReduceBitAndU(_)
 | 
				
			||||||
 | 
					            | ExprEnum::ReduceBitAndS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::ReduceBitOrU(_)
 | 
				
			||||||
 | 
					            | ExprEnum::ReduceBitOrS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::ReduceBitXorU(_)
 | 
				
			||||||
 | 
					            | ExprEnum::ReduceBitXorS(_)
 | 
				
			||||||
 | 
					            | ExprEnum::SliceUInt(_)
 | 
				
			||||||
 | 
					            | ExprEnum::SliceSInt(_)
 | 
				
			||||||
            | ExprEnum::CastToBits(_)
 | 
					            | ExprEnum::CastToBits(_)
 | 
				
			||||||
            | ExprEnum::CastBitsTo(_)
 | 
					            | ExprEnum::CastBitsTo(_)
 | 
				
			||||||
            | ExprEnum::CastBitToClock(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CastBitToSyncReset(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CastBitToAsyncReset(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CastSyncResetToReset(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CastAsyncResetToReset(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CastClockToBit(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CastSyncResetToBit(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CastAsyncResetToBit(_)
 | 
					 | 
				
			||||||
            | ExprEnum::CastResetToBit(_)
 | 
					 | 
				
			||||||
            | ExprEnum::ModuleIO(_)
 | 
					            | ExprEnum::ModuleIO(_)
 | 
				
			||||||
            | ExprEnum::Instance(_)
 | 
					            | ExprEnum::Instance(_)
 | 
				
			||||||
            | ExprEnum::Wire(_)
 | 
					            | ExprEnum::Wire(_)
 | 
				
			||||||
| 
						 | 
					@ -382,7 +392,7 @@ impl Folder for State {
 | 
				
			||||||
        let mut memories = vec![];
 | 
					        let mut memories = vec![];
 | 
				
			||||||
        let mut stmts = vec![];
 | 
					        let mut stmts = vec![];
 | 
				
			||||||
        for memory in block.memories {
 | 
					        for memory in block.memories {
 | 
				
			||||||
            let old_element_ty = *memory.array_type().element();
 | 
					            let old_element_ty = memory.array_type().element();
 | 
				
			||||||
            let new_element_ty = memory.array_type().element().fold(self)?;
 | 
					            let new_element_ty = memory.array_type().element().fold(self)?;
 | 
				
			||||||
            if new_element_ty != old_element_ty {
 | 
					            if new_element_ty != old_element_ty {
 | 
				
			||||||
                let mut new_ports = vec![];
 | 
					                let mut new_ports = vec![];
 | 
				
			||||||
| 
						 | 
					@ -394,7 +404,7 @@ impl Folder for State {
 | 
				
			||||||
                        port.addr_type(),
 | 
					                        port.addr_type(),
 | 
				
			||||||
                        new_element_ty,
 | 
					                        new_element_ty,
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    new_ports.push(new_port.intern());
 | 
					                    new_ports.push(new_port);
 | 
				
			||||||
                    let new_port_ty = new_port.ty();
 | 
					                    let new_port_ty = new_port.ty();
 | 
				
			||||||
                    let mut wire_ty_fields = Vec::from_iter(new_port_ty.fields());
 | 
					                    let mut wire_ty_fields = Vec::from_iter(new_port_ty.fields());
 | 
				
			||||||
                    if let Some(wmask_name) = new_port.port_kind().wmask_name() {
 | 
					                    if let Some(wmask_name) = new_port.port_kind().wmask_name() {
 | 
				
			||||||
| 
						 | 
					@ -404,7 +414,7 @@ impl Folder for State {
 | 
				
			||||||
                            .unwrap();
 | 
					                            .unwrap();
 | 
				
			||||||
                        wire_ty_fields[index].ty = port.ty().fields()[index].ty;
 | 
					                        wire_ty_fields[index].ty = port.ty().fields()[index].ty;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    let wire_ty = DynBundleType::new(Intern::intern_owned(wire_ty_fields));
 | 
					                    let wire_ty = Bundle::new(Intern::intern_owned(wire_ty_fields));
 | 
				
			||||||
                    if wire_ty == new_port_ty {
 | 
					                    if wire_ty == new_port_ty {
 | 
				
			||||||
                        continue;
 | 
					                        continue;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
| 
						 | 
					@ -419,23 +429,22 @@ impl Folder for State {
 | 
				
			||||||
                    stmts.push(
 | 
					                    stmts.push(
 | 
				
			||||||
                        StmtWire {
 | 
					                        StmtWire {
 | 
				
			||||||
                            annotations: Default::default(),
 | 
					                            annotations: Default::default(),
 | 
				
			||||||
                            wire: wire.to_dyn_canonical_wire(),
 | 
					                            wire: wire.canonical(),
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        .into(),
 | 
					                        .into(),
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    connect_port(
 | 
					                    connect_port(
 | 
				
			||||||
                        &mut stmts,
 | 
					                        &mut stmts,
 | 
				
			||||||
                        new_port.to_expr().to_canonical_dyn(),
 | 
					                        Expr::canonical(new_port.to_expr()),
 | 
				
			||||||
                        wire.to_expr().to_canonical_dyn(),
 | 
					                        Expr::canonical(wire.to_expr()),
 | 
				
			||||||
                        port.source_location(),
 | 
					                        port.source_location(),
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                    self.replacement_mem_ports
 | 
					                    self.replacement_mem_ports.insert(port, wire.canonical());
 | 
				
			||||||
                        .insert(port, wire.to_dyn_canonical_wire().intern_sized());
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                memories.push(Mem::new_unchecked(
 | 
					                memories.push(Mem::new_unchecked(
 | 
				
			||||||
                    memory.scoped_name(),
 | 
					                    memory.scoped_name(),
 | 
				
			||||||
                    memory.source_location(),
 | 
					                    memory.source_location(),
 | 
				
			||||||
                    ArrayType::new_slice(new_element_ty, memory.array_type().len()),
 | 
					                    ArrayType::new_dyn(new_element_ty, memory.array_type().len()),
 | 
				
			||||||
                    memory.initial_value(),
 | 
					                    memory.initial_value(),
 | 
				
			||||||
                    Intern::intern_owned(new_ports),
 | 
					                    Intern::intern_owned(new_ports),
 | 
				
			||||||
                    memory.read_latency(),
 | 
					                    memory.read_latency(),
 | 
				
			||||||
| 
						 | 
					@ -458,7 +467,7 @@ impl Folder for State {
 | 
				
			||||||
    fn fold_stmt(&mut self, stmt: Stmt) -> Result<Stmt, Self::Error> {
 | 
					    fn fold_stmt(&mut self, stmt: Stmt) -> Result<Stmt, Self::Error> {
 | 
				
			||||||
        fn match_int_tag(
 | 
					        fn match_int_tag(
 | 
				
			||||||
            state: &mut State,
 | 
					            state: &mut State,
 | 
				
			||||||
            int_tag_expr: Expr<DynUInt>,
 | 
					            int_tag_expr: Expr<UInt>,
 | 
				
			||||||
            source_location: SourceLocation,
 | 
					            source_location: SourceLocation,
 | 
				
			||||||
            blocks: Interned<[Block]>,
 | 
					            blocks: Interned<[Block]>,
 | 
				
			||||||
        ) -> Result<StmtIf, SimplifyEnumsError> {
 | 
					        ) -> Result<StmtIf, SimplifyEnumsError> {
 | 
				
			||||||
| 
						 | 
					@ -473,16 +482,15 @@ impl Folder for State {
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            let mut retval = StmtIf {
 | 
					            let mut retval = StmtIf {
 | 
				
			||||||
                cond: int_tag_expr.cmp_eq(DynUInt::with_type(
 | 
					                cond: int_tag_expr
 | 
				
			||||||
                    int_tag_expr.ty(),
 | 
					                    .cmp_eq(Expr::ty(int_tag_expr).from_int_wrapping(next_to_last_variant_index)),
 | 
				
			||||||
                    next_to_last_variant_index,
 | 
					 | 
				
			||||||
                )),
 | 
					 | 
				
			||||||
                source_location,
 | 
					                source_location,
 | 
				
			||||||
                blocks: [next_to_last_block.fold(state)?, last_block.fold(state)?],
 | 
					                blocks: [next_to_last_block.fold(state)?, last_block.fold(state)?],
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            for (variant_index, block) in blocks_iter.rev() {
 | 
					            for (variant_index, block) in blocks_iter.rev() {
 | 
				
			||||||
                retval = StmtIf {
 | 
					                retval = StmtIf {
 | 
				
			||||||
                    cond: int_tag_expr.cmp_eq(DynUInt::with_type(int_tag_expr.ty(), variant_index)),
 | 
					                    cond: int_tag_expr
 | 
				
			||||||
 | 
					                        .cmp_eq(Expr::ty(int_tag_expr).from_int_wrapping(variant_index)),
 | 
				
			||||||
                    source_location,
 | 
					                    source_location,
 | 
				
			||||||
                    blocks: [
 | 
					                    blocks: [
 | 
				
			||||||
                        block.fold(state)?,
 | 
					                        block.fold(state)?,
 | 
				
			||||||
| 
						 | 
					@ -500,33 +508,27 @@ impl Folder for State {
 | 
				
			||||||
                expr,
 | 
					                expr,
 | 
				
			||||||
                source_location,
 | 
					                source_location,
 | 
				
			||||||
                blocks,
 | 
					                blocks,
 | 
				
			||||||
            }) => match self.get_or_make_enum_type_state(expr.ty())? {
 | 
					            }) => match self.get_or_make_enum_type_state(Expr::ty(expr))? {
 | 
				
			||||||
                EnumTypeState::TagEnumAndBody(_) => Ok(StmtMatch {
 | 
					                EnumTypeState::TagEnumAndBody(_) => Ok(StmtMatch {
 | 
				
			||||||
                    expr: expr
 | 
					                    expr: Expr::<TagAndBody<Enum, DynSize>>::from_canonical(
 | 
				
			||||||
                        .expr_enum()
 | 
					                        Expr::canonical(expr).fold(self)?,
 | 
				
			||||||
                        .fold(self)?
 | 
					                    )
 | 
				
			||||||
                        .to_expr()
 | 
					 | 
				
			||||||
                        .with_type::<TagAndBody<DynEnum>>()
 | 
					 | 
				
			||||||
                    .tag,
 | 
					                    .tag,
 | 
				
			||||||
                    source_location,
 | 
					                    source_location,
 | 
				
			||||||
                    blocks: blocks.fold(self)?,
 | 
					                    blocks: blocks.fold(self)?,
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                .into()),
 | 
					                .into()),
 | 
				
			||||||
                EnumTypeState::TagUIntAndBody(_) => {
 | 
					                EnumTypeState::TagUIntAndBody(_) => {
 | 
				
			||||||
                    let int_tag_expr = expr
 | 
					                    let int_tag_expr = Expr::<TagAndBody<UInt, DynSize>>::from_canonical(
 | 
				
			||||||
                        .expr_enum()
 | 
					                        Expr::canonical(expr).fold(self)?,
 | 
				
			||||||
                        .fold(self)?
 | 
					                    )
 | 
				
			||||||
                        .to_expr()
 | 
					 | 
				
			||||||
                        .with_type::<TagAndBody<DynUInt>>()
 | 
					 | 
				
			||||||
                    .tag;
 | 
					                    .tag;
 | 
				
			||||||
                    Ok(match_int_tag(self, int_tag_expr, source_location, blocks)?.into())
 | 
					                    Ok(match_int_tag(self, int_tag_expr, source_location, blocks)?.into())
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                EnumTypeState::UInt(_) => {
 | 
					                EnumTypeState::UInt(_) => {
 | 
				
			||||||
                    let int_tag_expr = expr
 | 
					                    let int_tag_expr =
 | 
				
			||||||
                        .expr_enum()
 | 
					                        Expr::<UInt>::from_canonical(Expr::canonical(expr).fold(self)?)
 | 
				
			||||||
                        .fold(self)?
 | 
					                            [..Expr::ty(expr).discriminant_bit_width()];
 | 
				
			||||||
                        .to_expr()
 | 
					 | 
				
			||||||
                        .with_type::<DynUInt>()[..expr.ty().discriminant_bit_width()];
 | 
					 | 
				
			||||||
                    Ok(match_int_tag(self, int_tag_expr, source_location, blocks)?.into())
 | 
					                    Ok(match_int_tag(self, int_tag_expr, source_location, blocks)?.into())
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                EnumTypeState::Unchanged => Ok(StmtMatch {
 | 
					                EnumTypeState::Unchanged => Ok(StmtMatch {
 | 
				
			||||||
| 
						 | 
					@ -544,92 +546,49 @@ impl Folder for State {
 | 
				
			||||||
        unreachable!()
 | 
					        unreachable!()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn fold_type_enum(&mut self, type_enum: TypeEnum) -> Result<TypeEnum, Self::Error> {
 | 
					    fn fold_canonical_type(
 | 
				
			||||||
        match type_enum {
 | 
					        &mut self,
 | 
				
			||||||
            TypeEnum::EnumType(enum_type) => {
 | 
					        canonical_type: CanonicalType,
 | 
				
			||||||
 | 
					    ) -> Result<CanonicalType, Self::Error> {
 | 
				
			||||||
 | 
					        match canonical_type {
 | 
				
			||||||
 | 
					            CanonicalType::Enum(enum_type) => {
 | 
				
			||||||
                Ok(match self.get_or_make_enum_type_state(enum_type)? {
 | 
					                Ok(match self.get_or_make_enum_type_state(enum_type)? {
 | 
				
			||||||
                    EnumTypeState::TagEnumAndBody(ty) => TypeEnum::BundleType(ty.canonical()),
 | 
					                    EnumTypeState::TagEnumAndBody(ty) => ty.canonical(),
 | 
				
			||||||
                    EnumTypeState::TagUIntAndBody(ty) => TypeEnum::BundleType(ty.canonical()),
 | 
					                    EnumTypeState::TagUIntAndBody(ty) => ty.canonical(),
 | 
				
			||||||
                    EnumTypeState::UInt(ty) => TypeEnum::UInt(ty),
 | 
					                    EnumTypeState::UInt(ty) => ty.canonical(),
 | 
				
			||||||
                    EnumTypeState::Unchanged => TypeEnum::EnumType(enum_type),
 | 
					                    EnumTypeState::Unchanged => enum_type.canonical(),
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            TypeEnum::BundleType(_)
 | 
					            CanonicalType::Bundle(_)
 | 
				
			||||||
            | TypeEnum::ArrayType(_)
 | 
					            | CanonicalType::Array(_)
 | 
				
			||||||
            | TypeEnum::UInt(_)
 | 
					            | CanonicalType::UInt(_)
 | 
				
			||||||
            | TypeEnum::SInt(_)
 | 
					            | CanonicalType::SInt(_)
 | 
				
			||||||
            | TypeEnum::Clock(_)
 | 
					            | CanonicalType::Bool(_)
 | 
				
			||||||
            | TypeEnum::AsyncReset(_)
 | 
					            | CanonicalType::Clock(_)
 | 
				
			||||||
            | TypeEnum::SyncReset(_)
 | 
					            | CanonicalType::AsyncReset(_)
 | 
				
			||||||
            | TypeEnum::Reset(_) => type_enum.default_fold(self),
 | 
					            | CanonicalType::SyncReset(_)
 | 
				
			||||||
 | 
					            | CanonicalType::Reset(_) => canonical_type.default_fold(self),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn fold_value_enum(&mut self, value_enum: ValueEnum) -> Result<ValueEnum, Self::Error> {
 | 
					    fn fold_enum_variant(&mut self, _v: EnumVariant) -> Result<EnumVariant, Self::Error> {
 | 
				
			||||||
        match value_enum {
 | 
					 | 
				
			||||||
            ValueEnum::Enum(enum_value) => {
 | 
					 | 
				
			||||||
                Ok(match self.get_or_make_enum_type_state(enum_value.ty())? {
 | 
					 | 
				
			||||||
                    EnumTypeState::TagEnumAndBody(TagAndBodyType::<DynEnum> {
 | 
					 | 
				
			||||||
                        tag: tag_ty,
 | 
					 | 
				
			||||||
                        body: body_ty,
 | 
					 | 
				
			||||||
                    }) => ValueEnum::Bundle(
 | 
					 | 
				
			||||||
                        TagAndBody {
 | 
					 | 
				
			||||||
                            tag: DynEnum::new_by_index(tag_ty, enum_value.variant_index(), None),
 | 
					 | 
				
			||||||
                            body: value_to_uint(enum_value.variant_value().as_ref(), body_ty),
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        .to_canonical(),
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    EnumTypeState::TagUIntAndBody(TagAndBodyType::<DynUInt> {
 | 
					 | 
				
			||||||
                        tag: tag_ty,
 | 
					 | 
				
			||||||
                        body: body_ty,
 | 
					 | 
				
			||||||
                    }) => ValueEnum::Bundle(
 | 
					 | 
				
			||||||
                        TagAndBody {
 | 
					 | 
				
			||||||
                            tag: DynUInt::with_type(tag_ty, enum_value.variant_index()),
 | 
					 | 
				
			||||||
                            body: value_to_uint(enum_value.variant_value().as_ref(), body_ty),
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        .to_canonical(),
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    EnumTypeState::UInt(target_ty) => {
 | 
					 | 
				
			||||||
                        ValueEnum::UInt(value_to_uint(Some(&enum_value), target_ty))
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    EnumTypeState::Unchanged => ValueEnum::Enum(enum_value),
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            ValueEnum::Bundle(_)
 | 
					 | 
				
			||||||
            | ValueEnum::Array(_)
 | 
					 | 
				
			||||||
            | ValueEnum::UInt(_)
 | 
					 | 
				
			||||||
            | ValueEnum::SInt(_)
 | 
					 | 
				
			||||||
            | ValueEnum::Clock(_)
 | 
					 | 
				
			||||||
            | ValueEnum::AsyncReset(_)
 | 
					 | 
				
			||||||
            | ValueEnum::SyncReset(_)
 | 
					 | 
				
			||||||
            | ValueEnum::Reset(_) => value_enum.default_fold(self),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn fold_variant_type<T>(&mut self, _v: VariantType<T>) -> Result<VariantType<T>, Self::Error> {
 | 
					 | 
				
			||||||
        unreachable!()
 | 
					        unreachable!()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn fold_enum_literal<EnumTy>(
 | 
					    fn fold_enum_literal<T: EnumType>(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        _v: ops::EnumLiteral<EnumTy>,
 | 
					        _v: ops::EnumLiteral<T>,
 | 
				
			||||||
    ) -> Result<ops::EnumLiteral<EnumTy>, Self::Error>
 | 
					    ) -> Result<ops::EnumLiteral<T>, Self::Error>
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        EnumTy: EnumType,
 | 
					        T: Fold<Self>,
 | 
				
			||||||
        EnumTy::Value: EnumValue<Type = EnumTy>,
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unreachable!()
 | 
					        unreachable!()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn fold_variant_access<T, VariantTy>(
 | 
					    fn fold_variant_access<VariantType: Type>(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        _v: ops::VariantAccess<T, VariantTy>,
 | 
					        _v: ops::VariantAccess<VariantType>,
 | 
				
			||||||
    ) -> Result<ops::VariantAccess<T, VariantTy>, Self::Error>
 | 
					    ) -> Result<ops::VariantAccess<VariantType>, Self::Error> {
 | 
				
			||||||
    where
 | 
					 | 
				
			||||||
        T: EnumType,
 | 
					 | 
				
			||||||
        T::Value: EnumValue,
 | 
					 | 
				
			||||||
        VariantTy: Type,
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        unreachable!()
 | 
					        unreachable!()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -642,9 +601,9 @@ pub enum SimplifyEnumsKind {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn simplify_enums(
 | 
					pub fn simplify_enums(
 | 
				
			||||||
    module: Interned<Module<DynBundle>>,
 | 
					    module: Interned<Module<Bundle>>,
 | 
				
			||||||
    kind: SimplifyEnumsKind,
 | 
					    kind: SimplifyEnumsKind,
 | 
				
			||||||
) -> Result<Interned<Module<DynBundle>>, SimplifyEnumsError> {
 | 
					) -> Result<Interned<Module<Bundle>>, SimplifyEnumsError> {
 | 
				
			||||||
    module.fold(&mut State {
 | 
					    module.fold(&mut State {
 | 
				
			||||||
        enum_types: HashMap::new(),
 | 
					        enum_types: HashMap::new(),
 | 
				
			||||||
        replacement_mem_ports: HashMap::new(),
 | 
					        replacement_mem_ports: HashMap::new(),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,18 +3,19 @@
 | 
				
			||||||
#![allow(clippy::multiple_bound_locations)]
 | 
					#![allow(clippy::multiple_bound_locations)]
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    annotations::{Annotation, CustomFirrtlAnnotation, TargetedAnnotation},
 | 
					    annotations::{Annotation, CustomFirrtlAnnotation, TargetedAnnotation},
 | 
				
			||||||
    array::{Array, ArrayType, ArrayTypeTrait, ValueArrayOrSlice},
 | 
					    array::ArrayType,
 | 
				
			||||||
    bundle::{BundleType, BundleValue, DynBundle, DynBundleType, FieldType},
 | 
					    bundle::{Bundle, BundleField, BundleType},
 | 
				
			||||||
    clock::{Clock, ClockType},
 | 
					    clock::Clock,
 | 
				
			||||||
    enum_::{DynEnum, DynEnumType, EnumType, EnumValue, VariantType},
 | 
					    enum_::{Enum, EnumType, EnumVariant},
 | 
				
			||||||
    expr::{
 | 
					    expr::{
 | 
				
			||||||
        ops, Expr, ExprEnum, Literal, Target, TargetBase, TargetChild, TargetPathArrayElement,
 | 
					        ops,
 | 
				
			||||||
        TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, ToExpr,
 | 
					        target::{
 | 
				
			||||||
 | 
					            Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField,
 | 
				
			||||||
 | 
					            TargetPathDynArrayElement, TargetPathElement,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    int::{
 | 
					        Expr, ExprEnum,
 | 
				
			||||||
        DynInt, DynIntType, DynSInt, DynSIntType, DynUInt, DynUIntType, StaticOrDynIntType, IntType,
 | 
					 | 
				
			||||||
        IntTypeTrait,
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    int::{Bool, SIntType, SIntValue, Size, UIntType, UIntValue},
 | 
				
			||||||
    intern::{Intern, Interned},
 | 
					    intern::{Intern, Interned},
 | 
				
			||||||
    memory::{Mem, MemPort, PortKind, PortName, PortType, ReadUnderWrite},
 | 
					    memory::{Mem, MemPort, PortKind, PortName, PortType, ReadUnderWrite},
 | 
				
			||||||
    module::{
 | 
					    module::{
 | 
				
			||||||
| 
						 | 
					@ -24,10 +25,9 @@ use crate::{
 | 
				
			||||||
        StmtMatch, StmtReg, StmtWire,
 | 
					        StmtMatch, StmtReg, StmtWire,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    reg::Reg,
 | 
					    reg::Reg,
 | 
				
			||||||
    reset::{AsyncReset, AsyncResetType, Reset, ResetType, SyncReset, SyncResetType},
 | 
					    reset::{AsyncReset, Reset, SyncReset},
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{DynCanonicalType, DynCanonicalValue, DynType, Type, TypeEnum, Value, ValueEnum},
 | 
					    ty::{CanonicalType, Type},
 | 
				
			||||||
    util::{ConstBool, GenericConstBool},
 | 
					 | 
				
			||||||
    wire::Wire,
 | 
					    wire::Wire,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use num_bigint::{BigInt, BigUint};
 | 
					use num_bigint::{BigInt, BigUint};
 | 
				
			||||||
| 
						 | 
					@ -473,7 +473,4 @@ impl<T: ?Sized + Visit<State>, State: ?Sized + Visitor> Visit<State> for &'_ mut
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type InternedDynType = Interned<dyn DynType>;
 | 
					 | 
				
			||||||
type InternedDynCanonicalType = Interned<dyn DynCanonicalType>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
include!(concat!(env!("OUT_DIR"), "/visit.rs"));
 | 
					include!(concat!(env!("OUT_DIR"), "/visit.rs"));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,21 +2,21 @@
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    clock::ClockDomain,
 | 
					    clock::ClockDomain,
 | 
				
			||||||
    expr::{Expr, ExprTrait, Flow, ToExpr},
 | 
					    expr::{Expr, Flow},
 | 
				
			||||||
    intern::Interned,
 | 
					    intern::Interned,
 | 
				
			||||||
    module::{NameId, ScopedNameId},
 | 
					    module::{NameId, ScopedNameId},
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{DynCanonicalType, DynType, Type},
 | 
					    ty::{CanonicalType, Type},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use std::fmt;
 | 
					use std::fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Eq, PartialEq, Hash)]
 | 
					#[derive(Copy, Clone, Eq, PartialEq, Hash)]
 | 
				
			||||||
pub struct Reg<T: Type> {
 | 
					pub struct Reg<T: Type> {
 | 
				
			||||||
    name: ScopedNameId,
 | 
					    name: ScopedNameId,
 | 
				
			||||||
    source_location: SourceLocation,
 | 
					    source_location: SourceLocation,
 | 
				
			||||||
    ty: T,
 | 
					    ty: T,
 | 
				
			||||||
    clock_domain: Expr<ClockDomain>,
 | 
					    clock_domain: Expr<ClockDomain>,
 | 
				
			||||||
    init: Option<Expr<T::Value>>,
 | 
					    init: Option<Expr<T>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: Type + fmt::Debug> fmt::Debug for Reg<T> {
 | 
					impl<T: Type + fmt::Debug> fmt::Debug for Reg<T> {
 | 
				
			||||||
| 
						 | 
					@ -37,20 +37,8 @@ impl<T: Type + fmt::Debug> fmt::Debug for Reg<T> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: Type> ToExpr for Reg<T> {
 | 
					 | 
				
			||||||
    type Type = T;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					 | 
				
			||||||
        self.ty.clone()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
					 | 
				
			||||||
        Expr::new_unchecked(self.expr_enum())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T: Type> Reg<T> {
 | 
					impl<T: Type> Reg<T> {
 | 
				
			||||||
    pub fn canonical(&self) -> Reg<T::CanonicalType> {
 | 
					    pub fn canonical(&self) -> Reg<CanonicalType> {
 | 
				
			||||||
        let Self {
 | 
					        let Self {
 | 
				
			||||||
            name,
 | 
					            name,
 | 
				
			||||||
            source_location,
 | 
					            source_location,
 | 
				
			||||||
| 
						 | 
					@ -66,49 +54,20 @@ impl<T: Type> Reg<T> {
 | 
				
			||||||
            init: init.map(Expr::canonical),
 | 
					            init: init.map(Expr::canonical),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn to_dyn_reg(&self) -> Reg<Interned<dyn DynType>> {
 | 
					 | 
				
			||||||
        let Self {
 | 
					 | 
				
			||||||
            name,
 | 
					 | 
				
			||||||
            source_location,
 | 
					 | 
				
			||||||
            ref ty,
 | 
					 | 
				
			||||||
            clock_domain,
 | 
					 | 
				
			||||||
            init,
 | 
					 | 
				
			||||||
        } = *self;
 | 
					 | 
				
			||||||
        Reg {
 | 
					 | 
				
			||||||
            name,
 | 
					 | 
				
			||||||
            source_location,
 | 
					 | 
				
			||||||
            ty: ty.to_dyn(),
 | 
					 | 
				
			||||||
            clock_domain,
 | 
					 | 
				
			||||||
            init: init.map(Expr::to_dyn),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn to_dyn_canonical_reg(&self) -> Reg<Interned<dyn DynCanonicalType>> {
 | 
					 | 
				
			||||||
        let Self {
 | 
					 | 
				
			||||||
            name,
 | 
					 | 
				
			||||||
            source_location,
 | 
					 | 
				
			||||||
            ref ty,
 | 
					 | 
				
			||||||
            clock_domain,
 | 
					 | 
				
			||||||
            init,
 | 
					 | 
				
			||||||
        } = *self;
 | 
					 | 
				
			||||||
        Reg {
 | 
					 | 
				
			||||||
            name,
 | 
					 | 
				
			||||||
            source_location,
 | 
					 | 
				
			||||||
            ty: ty.canonical_dyn(),
 | 
					 | 
				
			||||||
            clock_domain,
 | 
					 | 
				
			||||||
            init: init.map(Expr::to_canonical_dyn),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn new_unchecked(
 | 
					    pub fn new_unchecked(
 | 
				
			||||||
        scoped_name: ScopedNameId,
 | 
					        scoped_name: ScopedNameId,
 | 
				
			||||||
        source_location: SourceLocation,
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
        ty: T,
 | 
					        ty: T,
 | 
				
			||||||
        clock_domain: Expr<ClockDomain>,
 | 
					        clock_domain: Expr<ClockDomain>,
 | 
				
			||||||
        init: Option<Expr<T::Value>>,
 | 
					        init: Option<Expr<T>>,
 | 
				
			||||||
    ) -> Self {
 | 
					    ) -> Self {
 | 
				
			||||||
        assert!(ty.is_storable(), "register type must be a storable type");
 | 
					        assert!(
 | 
				
			||||||
 | 
					            ty.canonical().is_storable(),
 | 
				
			||||||
 | 
					            "register type must be a storable type"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        if let Some(init) = init {
 | 
					        if let Some(init) = init {
 | 
				
			||||||
            assert_eq!(ty, init.ty(), "register's type must match init type");
 | 
					            assert_eq!(ty, Expr::ty(init), "register's type must match init type");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            name: scoped_name,
 | 
					            name: scoped_name,
 | 
				
			||||||
| 
						 | 
					@ -118,6 +77,9 @@ impl<T: Type> Reg<T> {
 | 
				
			||||||
            init,
 | 
					            init,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn ty(&self) -> T {
 | 
				
			||||||
 | 
					        self.ty
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    pub fn source_location(&self) -> SourceLocation {
 | 
					    pub fn source_location(&self) -> SourceLocation {
 | 
				
			||||||
        self.source_location
 | 
					        self.source_location
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -139,7 +101,7 @@ impl<T: Type> Reg<T> {
 | 
				
			||||||
    pub fn clock_domain(&self) -> Expr<ClockDomain> {
 | 
					    pub fn clock_domain(&self) -> Expr<ClockDomain> {
 | 
				
			||||||
        self.clock_domain
 | 
					        self.clock_domain
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn init(&self) -> Option<Expr<T::Value>> {
 | 
					    pub fn init(&self) -> Option<Expr<T>> {
 | 
				
			||||||
        self.init
 | 
					        self.init
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn flow(&self) -> Flow {
 | 
					    pub fn flow(&self) -> Flow {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,358 +2,119 @@
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    expr::{Expr, ToExpr},
 | 
					    expr::{Expr, ToExpr},
 | 
				
			||||||
    int::{UInt, UIntType},
 | 
					    int::Bool,
 | 
				
			||||||
    intern::Interned,
 | 
					 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{
 | 
					    ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
 | 
				
			||||||
        impl_match_values_as_self, CanonicalType, CanonicalTypeKind, CanonicalValue, Connect,
 | 
					 | 
				
			||||||
        DynCanonicalType, StaticType, Type, TypeEnum, Value, ValueEnum,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    util::interned_bit,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bitvec::slice::BitSlice;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait ResetTypeTrait: CanonicalType + StaticType<MaskType = UIntType<1>> {}
 | 
					mod sealed {
 | 
				
			||||||
 | 
					    pub trait ResetTypeSealed {}
 | 
				
			||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
 | 
					 | 
				
			||||||
pub struct AsyncResetType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl AsyncResetType {
 | 
					 | 
				
			||||||
    pub const fn new() -> Self {
 | 
					 | 
				
			||||||
        Self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Type for AsyncResetType {
 | 
					pub trait ResetType: StaticType<MaskType = Bool> + sealed::ResetTypeSealed {}
 | 
				
			||||||
    type Value = AsyncReset;
 | 
					 | 
				
			||||||
    type CanonicalType = AsyncResetType;
 | 
					 | 
				
			||||||
    type CanonicalValue = AsyncReset;
 | 
					 | 
				
			||||||
    type MaskType = UIntType<1>;
 | 
					 | 
				
			||||||
    type MaskValue = UInt<1>;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    impl_match_values_as_self!();
 | 
					macro_rules! reset_type {
 | 
				
			||||||
 | 
					    ($name:ident, $Trait:ident::$trait_fn:ident, $is_castable_from_bits:literal) => {
 | 
				
			||||||
 | 
					        #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
 | 
				
			||||||
 | 
					        pub struct $name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl Type for $name {
 | 
				
			||||||
 | 
					            type BaseType = $name;
 | 
				
			||||||
 | 
					            type MaskType = Bool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            impl_match_variant_as_self!();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            fn mask_type(&self) -> Self::MaskType {
 | 
					            fn mask_type(&self) -> Self::MaskType {
 | 
				
			||||||
        UIntType::new()
 | 
					                Bool
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn canonical(&self) -> Self::CanonicalType {
 | 
					            fn canonical(&self) -> CanonicalType {
 | 
				
			||||||
        *self
 | 
					                CanonicalType::$name(*self)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn source_location(&self) -> SourceLocation {
 | 
					            fn source_location() -> SourceLocation {
 | 
				
			||||||
                SourceLocation::builtin()
 | 
					                SourceLocation::builtin()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn type_enum(&self) -> TypeEnum {
 | 
					            fn from_canonical(canonical_type: CanonicalType) -> Self {
 | 
				
			||||||
        TypeEnum::AsyncReset(*self)
 | 
					                let CanonicalType::$name(retval) = canonical_type else {
 | 
				
			||||||
 | 
					                    panic!("expected {}", stringify!($name));
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                retval
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn from_canonical_type(t: Self::CanonicalType) -> Self {
 | 
					        impl $name {
 | 
				
			||||||
        t
 | 
					            pub fn type_properties(self) -> TypeProperties {
 | 
				
			||||||
 | 
					                Self::TYPE_PROPERTIES
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            pub fn can_connect(self, _rhs: Self) -> bool {
 | 
				
			||||||
 | 
					                true
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> {
 | 
					        impl StaticType for $name {
 | 
				
			||||||
        Some(this)
 | 
					            const TYPE: Self = Self;
 | 
				
			||||||
    }
 | 
					            const MASK_TYPE: Self::MaskType = Bool;
 | 
				
			||||||
}
 | 
					            const TYPE_PROPERTIES: TypeProperties = TypeProperties {
 | 
				
			||||||
 | 
					                is_passive: true,
 | 
				
			||||||
impl Connect<Self> for AsyncResetType {}
 | 
					                is_storable: false,
 | 
				
			||||||
 | 
					                is_castable_from_bits: $is_castable_from_bits,
 | 
				
			||||||
impl CanonicalType for AsyncResetType {
 | 
					                bit_width: 1,
 | 
				
			||||||
    const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::AsyncReset;
 | 
					            };
 | 
				
			||||||
}
 | 
					            const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
 | 
				
			||||||
 | 
					 | 
				
			||||||
impl StaticType for AsyncResetType {
 | 
					 | 
				
			||||||
    fn static_type() -> Self {
 | 
					 | 
				
			||||||
        Self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ResetTypeTrait for AsyncResetType {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
 | 
					 | 
				
			||||||
pub struct AsyncReset(pub bool);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ToExpr for AsyncReset {
 | 
					 | 
				
			||||||
    type Type = AsyncResetType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					 | 
				
			||||||
        AsyncResetType
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn to_expr(&self) -> Expr<Self> {
 | 
					        impl sealed::ResetTypeSealed for $name {}
 | 
				
			||||||
        Expr::from_value(self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Value for AsyncReset {
 | 
					        impl ResetType for $name {}
 | 
				
			||||||
    fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
 | 
					 | 
				
			||||||
        *self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        interned_bit(this.0)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl CanonicalValue for AsyncReset {
 | 
					        pub trait $Trait {
 | 
				
			||||||
    fn value_enum_impl(this: &Self) -> ValueEnum {
 | 
					            fn $trait_fn(&self) -> Expr<$name>;
 | 
				
			||||||
        ValueEnum::AsyncReset(*this)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        interned_bit(this.0)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
 | 
					 | 
				
			||||||
pub struct SyncResetType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl SyncResetType {
 | 
					 | 
				
			||||||
    pub const fn new() -> Self {
 | 
					 | 
				
			||||||
        Self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Type for SyncResetType {
 | 
					 | 
				
			||||||
    type CanonicalType = SyncResetType;
 | 
					 | 
				
			||||||
    type Value = SyncReset;
 | 
					 | 
				
			||||||
    type CanonicalValue = SyncReset;
 | 
					 | 
				
			||||||
    type MaskType = UIntType<1>;
 | 
					 | 
				
			||||||
    type MaskValue = UInt<1>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    impl_match_values_as_self!();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn mask_type(&self) -> Self::MaskType {
 | 
					 | 
				
			||||||
        UIntType::new()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn canonical(&self) -> Self::CanonicalType {
 | 
					 | 
				
			||||||
        *self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn source_location(&self) -> SourceLocation {
 | 
					 | 
				
			||||||
        SourceLocation::builtin()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn type_enum(&self) -> TypeEnum {
 | 
					 | 
				
			||||||
        TypeEnum::SyncReset(*self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn from_canonical_type(t: Self::CanonicalType) -> Self {
 | 
					 | 
				
			||||||
        t
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> {
 | 
					 | 
				
			||||||
        Some(this)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Connect<Self> for SyncResetType {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl CanonicalType for SyncResetType {
 | 
					 | 
				
			||||||
    const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::SyncReset;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl StaticType for SyncResetType {
 | 
					 | 
				
			||||||
    fn static_type() -> Self {
 | 
					 | 
				
			||||||
        Self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ResetTypeTrait for SyncResetType {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
 | 
					 | 
				
			||||||
pub struct SyncReset(pub bool);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ToExpr for SyncReset {
 | 
					 | 
				
			||||||
    type Type = SyncResetType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					 | 
				
			||||||
        SyncResetType
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn to_expr(&self) -> Expr<Self> {
 | 
					 | 
				
			||||||
        Expr::from_value(self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Value for SyncReset {
 | 
					 | 
				
			||||||
    fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
 | 
					 | 
				
			||||||
        *self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        interned_bit(this.0)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl CanonicalValue for SyncReset {
 | 
					 | 
				
			||||||
    fn value_enum_impl(this: &Self) -> ValueEnum {
 | 
					 | 
				
			||||||
        ValueEnum::SyncReset(*this)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        interned_bit(this.0)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
 | 
					 | 
				
			||||||
pub struct ResetType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ResetType {
 | 
					 | 
				
			||||||
    pub const fn new() -> Self {
 | 
					 | 
				
			||||||
        Self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Type for ResetType {
 | 
					 | 
				
			||||||
    type Value = Reset;
 | 
					 | 
				
			||||||
    type CanonicalType = ResetType;
 | 
					 | 
				
			||||||
    type CanonicalValue = Reset;
 | 
					 | 
				
			||||||
    type MaskType = UIntType<1>;
 | 
					 | 
				
			||||||
    type MaskValue = UInt<1>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    impl_match_values_as_self!();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn mask_type(&self) -> Self::MaskType {
 | 
					 | 
				
			||||||
        UIntType::new()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn canonical(&self) -> Self::CanonicalType {
 | 
					 | 
				
			||||||
        *self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn source_location(&self) -> SourceLocation {
 | 
					 | 
				
			||||||
        SourceLocation::builtin()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn type_enum(&self) -> TypeEnum {
 | 
					 | 
				
			||||||
        TypeEnum::Reset(*self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn from_canonical_type(t: Self::CanonicalType) -> Self {
 | 
					 | 
				
			||||||
        t
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> {
 | 
					 | 
				
			||||||
        Some(this)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Connect<Self> for ResetType {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl CanonicalType for ResetType {
 | 
					 | 
				
			||||||
    const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::Reset;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl StaticType for ResetType {
 | 
					 | 
				
			||||||
    fn static_type() -> Self {
 | 
					 | 
				
			||||||
        Self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ResetTypeTrait for ResetType {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 | 
					 | 
				
			||||||
pub enum Reset {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ToExpr for Reset {
 | 
					 | 
				
			||||||
    type Type = ResetType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					 | 
				
			||||||
        match *self {}
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn to_expr(&self) -> Expr<Self> {
 | 
					 | 
				
			||||||
        Expr::from_value(self)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Value for Reset {
 | 
					 | 
				
			||||||
    fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
 | 
					 | 
				
			||||||
        *self
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        match *this {}
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl CanonicalValue for Reset {
 | 
					 | 
				
			||||||
    fn value_enum_impl(this: &Self) -> ValueEnum {
 | 
					 | 
				
			||||||
        ValueEnum::Reset(*this)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
					 | 
				
			||||||
        match *this {}
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
macro_rules! make_to_reset {
 | 
					 | 
				
			||||||
    (
 | 
					 | 
				
			||||||
        $(#[from_value($from_value_ty:ty)])*
 | 
					 | 
				
			||||||
        $vis:vis trait $Trait:ident {
 | 
					 | 
				
			||||||
            fn $fn:ident(&self) -> Expr<$T:ty>;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ) => {
 | 
					 | 
				
			||||||
        $vis trait $Trait {
 | 
					 | 
				
			||||||
            fn $fn(&self) -> Expr<$T>;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        impl<T: ?Sized + $Trait> $Trait for &'_ T {
 | 
					        impl<T: ?Sized + $Trait> $Trait for &'_ T {
 | 
				
			||||||
            fn $fn(&self) -> Expr<$T> {
 | 
					            fn $trait_fn(&self) -> Expr<$name> {
 | 
				
			||||||
                (**self).$fn()
 | 
					                (**self).$trait_fn()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        impl<T: ?Sized + $Trait> $Trait for &'_ mut T {
 | 
					        impl<T: ?Sized + $Trait> $Trait for &'_ mut T {
 | 
				
			||||||
            fn $fn(&self) -> Expr<$T> {
 | 
					            fn $trait_fn(&self) -> Expr<$name> {
 | 
				
			||||||
                (**self).$fn()
 | 
					                (**self).$trait_fn()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        impl<T: ?Sized + $Trait> $Trait for Box<T> {
 | 
					        impl<T: ?Sized + $Trait> $Trait for Box<T> {
 | 
				
			||||||
            fn $fn(&self) -> Expr<$T> {
 | 
					            fn $trait_fn(&self) -> Expr<$name> {
 | 
				
			||||||
                (**self).$fn()
 | 
					                (**self).$trait_fn()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        impl $Trait for Expr<$T> {
 | 
					        impl $Trait for Expr<$name> {
 | 
				
			||||||
            fn $fn(&self) -> Expr<$T> {
 | 
					            fn $trait_fn(&self) -> Expr<$name> {
 | 
				
			||||||
                *self
 | 
					                *self
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        impl $Trait for $T {
 | 
					 | 
				
			||||||
            fn $fn(&self) -> Expr<$T> {
 | 
					 | 
				
			||||||
                self.to_expr()
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $(impl $Trait for $from_value_ty {
 | 
					 | 
				
			||||||
            fn $fn(&self) -> Expr<$T> {
 | 
					 | 
				
			||||||
                self.to_expr().$fn()
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        })*
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
make_to_reset! {
 | 
					reset_type!(AsyncReset, ToAsyncReset::to_async_reset, true);
 | 
				
			||||||
    #[from_value(SyncReset)]
 | 
					reset_type!(SyncReset, ToSyncReset::to_sync_reset, true);
 | 
				
			||||||
    #[from_value(AsyncReset)]
 | 
					reset_type!(
 | 
				
			||||||
    pub trait ToReset {
 | 
					    Reset,
 | 
				
			||||||
        fn to_reset(&self) -> Expr<Reset>;
 | 
					    ToReset::to_reset,
 | 
				
			||||||
 | 
					    false // Reset is not castable from bits because we don't know if it's async or sync
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ToSyncReset for bool {
 | 
				
			||||||
 | 
					    fn to_sync_reset(&self) -> Expr<SyncReset> {
 | 
				
			||||||
 | 
					        self.to_expr().to_sync_reset()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
make_to_reset! {
 | 
					impl ToAsyncReset for bool {
 | 
				
			||||||
    #[from_value(bool)]
 | 
					    fn to_async_reset(&self) -> Expr<AsyncReset> {
 | 
				
			||||||
    #[from_value(UInt<1>)]
 | 
					        self.to_expr().to_async_reset()
 | 
				
			||||||
    pub trait ToAsyncReset {
 | 
					 | 
				
			||||||
        fn to_async_reset(&self) -> Expr<AsyncReset>;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
make_to_reset! {
 | 
					 | 
				
			||||||
    #[from_value(bool)]
 | 
					 | 
				
			||||||
    #[from_value(UInt<1>)]
 | 
					 | 
				
			||||||
    pub trait ToSyncReset {
 | 
					 | 
				
			||||||
        fn to_sync_reset(&self) -> Expr<SyncReset>;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -3,10 +3,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod const_bool;
 | 
					mod const_bool;
 | 
				
			||||||
mod const_cmp;
 | 
					mod const_cmp;
 | 
				
			||||||
 | 
					mod const_usize;
 | 
				
			||||||
mod misc;
 | 
					mod misc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[doc(inline)]
 | 
					#[doc(inline)]
 | 
				
			||||||
pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool};
 | 
					pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool};
 | 
				
			||||||
 | 
					#[doc(inline)]
 | 
				
			||||||
 | 
					pub use const_usize::{ConstUsize, GenericConstUsize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[doc(inline)]
 | 
					#[doc(inline)]
 | 
				
			||||||
pub use const_cmp::{
 | 
					pub use const_cmp::{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										29
									
								
								crates/fayalite/src/util/const_usize.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								crates/fayalite/src/util/const_usize.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
				
			||||||
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
 | 
					use std::{fmt::Debug, hash::Hash};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod sealed {
 | 
				
			||||||
 | 
					    pub trait Sealed {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// the only implementation is `ConstUsize<Self::VALUE>`
 | 
				
			||||||
 | 
					pub trait GenericConstUsize:
 | 
				
			||||||
 | 
					    sealed::Sealed + Copy + Ord + Hash + Default + Debug + 'static + Send + Sync
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const VALUE: usize;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
 | 
				
			||||||
 | 
					pub struct ConstUsize<const VALUE: usize>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<const VALUE: usize> Debug for ConstUsize<VALUE> {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        f.debug_tuple("ConstUsize").field(&Self::VALUE).finish()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<const VALUE: usize> sealed::Sealed for ConstUsize<VALUE> {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<const VALUE: usize> GenericConstUsize for ConstUsize<VALUE> {
 | 
				
			||||||
 | 
					    const VALUE: usize = VALUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,15 @@
 | 
				
			||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
					// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    expr::{Expr, ExprTrait, Flow, ToExpr},
 | 
					    expr::Flow,
 | 
				
			||||||
    intern::Interned,
 | 
					    intern::Interned,
 | 
				
			||||||
    module::{NameId, ScopedNameId},
 | 
					    module::{NameId, ScopedNameId},
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{DynCanonicalType, DynType, Type},
 | 
					    ty::{CanonicalType, Type},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use std::fmt;
 | 
					use std::fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Eq, PartialEq, Hash)]
 | 
					#[derive(Copy, Clone, Eq, PartialEq, Hash)]
 | 
				
			||||||
pub struct Wire<T: Type> {
 | 
					pub struct Wire<T: Type> {
 | 
				
			||||||
    name: ScopedNameId,
 | 
					    name: ScopedNameId,
 | 
				
			||||||
    source_location: SourceLocation,
 | 
					    source_location: SourceLocation,
 | 
				
			||||||
| 
						 | 
					@ -25,20 +25,8 @@ impl<T: Type + fmt::Debug> fmt::Debug for Wire<T> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: Type> ToExpr for Wire<T> {
 | 
					 | 
				
			||||||
    type Type = T;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn ty(&self) -> Self::Type {
 | 
					 | 
				
			||||||
        self.ty.clone()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
					 | 
				
			||||||
        Expr::new_unchecked(self.expr_enum())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T: Type> Wire<T> {
 | 
					impl<T: Type> Wire<T> {
 | 
				
			||||||
    pub fn canonical(&self) -> Wire<T::CanonicalType> {
 | 
					    pub fn canonical(&self) -> Wire<CanonicalType> {
 | 
				
			||||||
        let Self {
 | 
					        let Self {
 | 
				
			||||||
            name,
 | 
					            name,
 | 
				
			||||||
            source_location,
 | 
					            source_location,
 | 
				
			||||||
| 
						 | 
					@ -50,29 +38,8 @@ impl<T: Type> Wire<T> {
 | 
				
			||||||
            ty: ty.canonical(),
 | 
					            ty: ty.canonical(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn to_dyn_wire(&self) -> Wire<Interned<dyn DynType>> {
 | 
					    pub fn ty(&self) -> T {
 | 
				
			||||||
        let Self {
 | 
					        self.ty
 | 
				
			||||||
            name,
 | 
					 | 
				
			||||||
            source_location,
 | 
					 | 
				
			||||||
            ref ty,
 | 
					 | 
				
			||||||
        } = *self;
 | 
					 | 
				
			||||||
        Wire {
 | 
					 | 
				
			||||||
            name,
 | 
					 | 
				
			||||||
            source_location,
 | 
					 | 
				
			||||||
            ty: ty.to_dyn(),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn to_dyn_canonical_wire(&self) -> Wire<Interned<dyn DynCanonicalType>> {
 | 
					 | 
				
			||||||
        let Self {
 | 
					 | 
				
			||||||
            name,
 | 
					 | 
				
			||||||
            source_location,
 | 
					 | 
				
			||||||
            ref ty,
 | 
					 | 
				
			||||||
        } = *self;
 | 
					 | 
				
			||||||
        Wire {
 | 
					 | 
				
			||||||
            name,
 | 
					 | 
				
			||||||
            source_location,
 | 
					 | 
				
			||||||
            ty: ty.canonical_dyn(),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn new_unchecked(
 | 
					    pub fn new_unchecked(
 | 
				
			||||||
        scoped_name: ScopedNameId,
 | 
					        scoped_name: ScopedNameId,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,22 +6,22 @@ use fayalite::{
 | 
				
			||||||
    assert_export_firrtl,
 | 
					    assert_export_firrtl,
 | 
				
			||||||
    clock::{Clock, ClockDomain},
 | 
					    clock::{Clock, ClockDomain},
 | 
				
			||||||
    expr::ToExpr,
 | 
					    expr::ToExpr,
 | 
				
			||||||
    hdl_module,
 | 
					    hdl, hdl_module,
 | 
				
			||||||
    int::{DynUInt, DynUIntType, IntCmp, SInt, UInt},
 | 
					    int::{IntCmp, SInt, UInt},
 | 
				
			||||||
    intern::Intern,
 | 
					    intern::Intern,
 | 
				
			||||||
    memory::MemBuilder,
 | 
					    memory::MemBuilder,
 | 
				
			||||||
    module::transform::simplify_enums::{simplify_enums, SimplifyEnumsKind},
 | 
					    module::transform::simplify_enums::{simplify_enums, SimplifyEnumsKind},
 | 
				
			||||||
    reset::{SyncReset, ToReset},
 | 
					    reset::{SyncReset, ToReset},
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{StaticValue, Value},
 | 
					    ty::{StaticType, Type},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use serde_json::json;
 | 
					use serde_json::json;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Value, Hash, Eq, PartialEq, Debug, Clone)]
 | 
					#[hdl(outline_generated)]
 | 
				
			||||||
pub enum TestEnum {
 | 
					pub enum TestEnum {
 | 
				
			||||||
    A,
 | 
					    A,
 | 
				
			||||||
    B(UInt<8>),
 | 
					    B(UInt<8>),
 | 
				
			||||||
    C(Array<[UInt<1>; 3]>),
 | 
					    C(Array<UInt<1>, 3>),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[hdl_module(outline_generated)]
 | 
					#[hdl_module(outline_generated)]
 | 
				
			||||||
| 
						 | 
					@ -376,20 +376,19 @@ circuit check_written_inside_both_if_else:
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Value, Clone, PartialEq, Eq, Hash, Debug)]
 | 
					#[hdl(outline_generated)]
 | 
				
			||||||
#[hdl(static, outline_generated)]
 | 
					 | 
				
			||||||
pub struct TestStruct<T> {
 | 
					pub struct TestStruct<T> {
 | 
				
			||||||
    pub a: T,
 | 
					    pub a: T,
 | 
				
			||||||
    pub b: UInt<8>,
 | 
					    pub b: UInt<8>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Value, Clone, PartialEq, Eq, Hash, Debug)]
 | 
					#[hdl(outline_generated)]
 | 
				
			||||||
#[hdl(static, outline_generated)]
 | 
					pub struct TestStruct2 {
 | 
				
			||||||
pub struct TestStruct2(pub UInt<8>);
 | 
					    pub v: UInt<8>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Value, Clone, PartialEq, Eq, Hash, Debug)]
 | 
					#[hdl(outline_generated)]
 | 
				
			||||||
#[hdl(static, outline_generated)]
 | 
					pub struct TestStruct3 {}
 | 
				
			||||||
pub struct TestStruct3;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[hdl_module(outline_generated)]
 | 
					#[hdl_module(outline_generated)]
 | 
				
			||||||
pub fn check_struct_literals() {
 | 
					pub fn check_struct_literals() {
 | 
				
			||||||
| 
						 | 
					@ -409,7 +408,7 @@ pub fn check_struct_literals() {
 | 
				
			||||||
    m.connect(
 | 
					    m.connect(
 | 
				
			||||||
        o2,
 | 
					        o2,
 | 
				
			||||||
        #[hdl]
 | 
					        #[hdl]
 | 
				
			||||||
        TestStruct2(i),
 | 
					        TestStruct2 { v: i },
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    m.connect(
 | 
					    m.connect(
 | 
				
			||||||
        o3,
 | 
					        o3,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,32 +1,26 @@
 | 
				
			||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
					// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
use fayalite::{
 | 
					use fayalite::{
 | 
				
			||||||
    int::UInt,
 | 
					    array::ArrayType,
 | 
				
			||||||
    ty::{StaticValue, Value},
 | 
					    hdl,
 | 
				
			||||||
 | 
					    int::{IntType, Size, UInt},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Value, Clone, Hash, PartialEq, Eq, Debug)]
 | 
					 | 
				
			||||||
#[hdl(outline_generated)]
 | 
					#[hdl(outline_generated)]
 | 
				
			||||||
pub struct S<T> {
 | 
					pub struct S<T: IntType, Len: Size> {
 | 
				
			||||||
    pub a: T,
 | 
					    pub a: T,
 | 
				
			||||||
    b: UInt<3>,
 | 
					    b: UInt<3>,
 | 
				
			||||||
 | 
					    pub(crate) c: ArrayType<UInt<1>, Len>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Value, Clone, Hash, PartialEq, Eq, Debug)]
 | 
					 | 
				
			||||||
#[hdl(outline_generated)]
 | 
					#[hdl(outline_generated)]
 | 
				
			||||||
pub enum E<T> {
 | 
					pub enum E<T> {
 | 
				
			||||||
    A,
 | 
					    A,
 | 
				
			||||||
    B {},
 | 
					    B(UInt<3>),
 | 
				
			||||||
    C(),
 | 
					    C(T),
 | 
				
			||||||
    D(UInt<3>),
 | 
					 | 
				
			||||||
    E { a: UInt<3> },
 | 
					 | 
				
			||||||
    F(UInt<3>, UInt<3>),
 | 
					 | 
				
			||||||
    G(T),
 | 
					 | 
				
			||||||
    H(T, UInt<1>),
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Value, Clone, Hash, PartialEq, Eq, Debug)]
 | 
					#[hdl(outline_generated)]
 | 
				
			||||||
#[hdl(outline_generated, static, where(T: StaticValue))]
 | 
					pub struct S2<T = ()> {
 | 
				
			||||||
pub struct S2<T> {
 | 
					 | 
				
			||||||
    pub v: E<T>,
 | 
					    pub v: E<T>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue