spade_typeinference/
lib.rs

1// This algorithm is based off the excellent lecture here
2// https://www.youtube.com/watch?v=xJXcZp2vgLs
3//
4// The basic idea is to go through every node in the HIR tree, for every typed thing,
5// add an equation indicating a constraint on that thing. This can onlytydone once
6// and should be done by the visitor for that node. The visitor should then unify
7// types according to the rules of the node.
8
9use std::cmp::PartialEq;
10use std::collections::{BTreeMap, BTreeSet};
11use std::sync::Arc;
12
13use colored::Colorize;
14use fixed_types::{t_int, t_uint};
15use hir::expression::CallKind;
16use hir::{
17    param_util, Binding, ConstGeneric, Parameter, PipelineRegMarkerExtra, TypeExpression, TypeSpec,
18    UnitHead, UnitKind, WalTrace, WhereClause,
19};
20type HashMap<K, V> = imbl::GenericHashMap<K, V, rustc_hash::FxBuildHasher, DefaultSharedPtr>;
21use imbl::shared_ptr::DefaultSharedPtr;
22use itertools::{Either, Itertools};
23use method_resolution::{FunctionLikeName, IntoImplTarget};
24use num::{BigInt, BigUint, Zero};
25use replacement::ReplacementStack;
26use rustc_hash::FxHashMap;
27use serde::{Deserialize, Serialize};
28use spade_common::id_tracker::{ExprID, ImplID};
29use spade_common::num_ext::InfallibleToBigInt;
30use spade_diagnostics::diag_list::{DiagList, ResultExt};
31use spade_diagnostics::{diag_anyhow, diag_bail, Diagnostic};
32use spade_macros::trace_typechecker;
33use spade_types::meta_types::{unify_meta, MetaType};
34use trace_stack::TraceStack;
35use tracing::{info, trace};
36
37use spade_common::location_info::{Loc, WithLocation};
38use spade_common::name::{Identifier, NameID, Path, PathSegment};
39use spade_hir::param_util::{match_args_with_params, Argument};
40use spade_hir::symbol_table::{Patternable, PatternableKind, SymbolTable, TypeSymbol};
41use spade_hir::{self as hir, ConstGenericWithId, ImplTarget};
42use spade_hir::{
43    ArgumentList, Block, ExprKind, Expression, ItemList, Pattern, PatternArgument, Register,
44    Statement, TraitName, TraitSpec, TypeParam, Unit,
45};
46use spade_types::KnownType;
47
48use constraints::{
49    bits_to_store, ce_int, ce_var, ConstraintExpr, ConstraintSource, TypeConstraints,
50};
51use equation::{TemplateTypeVarID, TypeEquations, TypeVar, TypeVarID, TypedExpression};
52use error::{
53    error_pattern_type_mismatch, Result, UnificationError, UnificationErrorExt, UnificationTrace,
54};
55use requirements::{Replacement, Requirement};
56use trace_stack::{format_trace_stack, TraceStackEntry};
57use traits::{TraitList, TraitReq};
58
59use crate::error::TypeMismatch as Tm;
60use crate::requirements::ConstantInt;
61pub use crate::shared::SharedTypeState;
62use crate::traits::{TraitImpl, TraitImplList};
63
64mod constraints;
65pub mod dump;
66pub mod equation;
67pub mod error;
68pub mod expression;
69pub mod fixed_types;
70pub mod method_resolution;
71pub mod mir_type_lowering;
72mod replacement;
73mod requirements;
74mod shared;
75pub mod testutil;
76pub mod trace_stack;
77pub mod traits;
78
79type GenericList = HashMap<NameID, TypeVarID>;
80type GenericLists = HashMap<GenericListToken, GenericList>;
81
82pub struct Context<'a> {
83    pub symtab: &'a SymbolTable,
84    pub items: &'a ItemList,
85    pub trait_impls: &'a TraitImplList,
86}
87impl<'a> std::fmt::Debug for Context<'a> {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        write!(f, "{{context omitted}}")
90    }
91}
92#[derive(Debug, Clone)]
93pub enum GenericListSource<'a> {
94    /// For when you just need a new generic list but have no need to refer back
95    /// to it in the future
96    Anonymous,
97    /// For managing the generics of callable with the specified name when type checking
98    /// their body
99    Definition(&'a NameID),
100    ImplBlock {
101        target: &'a ImplTarget,
102        id: ImplID,
103    },
104    /// For expressions which instantiate generic items
105    Expression(Loc<ExprID>),
106}
107
108/// Stored version of GenericListSource
109#[derive(Clone, Hash, Eq, PartialEq, Debug, Serialize, Deserialize)]
110pub enum GenericListToken {
111    Anonymous(u64),
112    Definition(NameID),
113    ImplBlock(ImplTarget, ImplID),
114    Expression(ExprID),
115}
116
117#[derive(Debug)]
118pub struct TurbofishCtx<'a> {
119    turbofish: &'a Loc<ArgumentList<TypeExpression>>,
120    prev_generic_list: &'a GenericListToken,
121    type_ctx: &'a Context<'a>,
122}
123
124#[derive(Clone, Serialize, Deserialize)]
125pub struct PipelineState {
126    current_stage_depth: TypeVarID,
127    total_depth: Loc<TypeVarID>,
128    pipeline_loc: Loc<()>,
129}
130
131/// State of the type inference algorithm
132#[derive(Clone, Serialize, Deserialize)]
133pub struct OwnedTypeState {
134    /// This key is used to prevent bugs when multiple type states are mixed. Each TypeVarID
135    /// holds the value of the key of the type state which created it, and this is checked
136    /// to ensure that type vars are not mixed. The key is initialized randomly on type
137    /// state creation
138    key: u64,
139    /// A type state can also support keys from other sources, this is tracked here
140    keys: BTreeSet<u64>,
141
142    equations: TypeEquations,
143
144    // `#[serde(skip)] is set internally
145    constraints: TypeConstraints,
146
147    /// Contains generic lists containing Expression and Definition lists. Impl and anonymous lists
148    /// are stored in the shared state
149    generic_lists: GenericLists,
150
151    /// Requirements which must be fulfilled but which do not guide further type inference.
152    /// For example, if seeing `let y = x.a` before knowing the type of `x`, a requirement is
153    /// added to say "x has field a, and y should be the type of that field"
154    #[serde(skip)]
155    requirements: Vec<Requirement>,
156
157    replacements: ReplacementStack,
158    // Skipping serialization of these is fine as we only push checkpoints during
159    // trait resolution
160    #[serde(skip)]
161    checkpoints: Vec<(Vec<Requirement>, TypeConstraints)>,
162
163    /// The type var containing the depth of the pipeline stage we are currently in
164    pipeline_state: Option<PipelineState>,
165
166    /// An error type that can be accessed anywhere without mut access. This is an option
167    /// to facilitate safe initialization, in practice it can never be None
168    error_type: Option<TypeVarID>,
169
170    #[serde(skip)]
171    pub trace_stack: TraceStack,
172
173    #[serde(skip)]
174    pub diags: DiagList,
175}
176
177impl OwnedTypeState {
178    /// Create a fresh type state, in most cases, this should be .create_child of an
179    /// existing type state
180    pub fn fresh() -> Self {
181        let key = fastrand::u64(..);
182        let result = Self {
183            key,
184            keys: [key].into_iter().collect(),
185            equations: HashMap::default(),
186            generic_lists: Default::default(),
187            trace_stack: TraceStack::new(),
188            constraints: TypeConstraints::new(),
189            requirements: vec![],
190            replacements: ReplacementStack::new(),
191            checkpoints: vec![],
192            error_type: None,
193            pipeline_state: None,
194            diags: DiagList::new(),
195        };
196        result
197    }
198
199    pub fn create_child(&self) -> Self {
200        let mut result = self.clone();
201        result.key = fastrand::u64(..);
202        result.keys.insert(result.key);
203        result
204    }
205}
206
207#[derive(Clone)]
208pub struct TypeState {
209    pub owned: OwnedTypeState,
210    pub shared: Arc<SharedTypeState>,
211}
212
213impl TypeState {
214    pub fn fresh(shared: Arc<SharedTypeState>) -> Self {
215        let owned = OwnedTypeState::fresh();
216        let mut result = Self { shared, owned };
217        result.owned.error_type =
218            Some(result.add_type_var(TypeVar::Known(().nowhere(), KnownType::Error, vec![])));
219        result
220    }
221
222    pub fn create_child(&self) -> Self {
223        Self {
224            shared: Arc::clone(&self.shared),
225            owned: self.owned.create_child(),
226        }
227    }
228
229    pub fn add_type_var(&mut self, var: TypeVar) -> TypeVarID {
230        self.shared.modify_type_vars(|type_vars| {
231            let idx = type_vars.len();
232            type_vars.push(var);
233            TypeVarID {
234                inner: idx,
235                type_state_key: self.owned.key,
236            }
237        })
238    }
239
240    pub fn get_equations(&self) -> &TypeEquations {
241        &self.owned.equations
242    }
243
244    pub fn get_constraints(&self) -> &TypeConstraints {
245        &self.owned.constraints
246    }
247
248    // Get a generic list with a safe unwrap since a token is acquired
249    pub fn get_generic_list(
250        &self,
251        generic_list_token: &GenericListToken,
252    ) -> Option<HashMap<NameID, TypeVarID>> {
253        match generic_list_token {
254            GenericListToken::Anonymous(_) | GenericListToken::ImplBlock(_, _) => self
255                .shared
256                .read_generic_lists(|lists| lists.get(generic_list_token).cloned()),
257
258            GenericListToken::Definition(_) | GenericListToken::Expression(_) => {
259                self.owned.generic_lists.get(generic_list_token).cloned()
260            }
261        }
262    }
263
264    fn modify_generic_list<T>(
265        &mut self,
266        token: &GenericListToken,
267        f: impl FnOnce(&mut GenericList) -> T,
268    ) -> T {
269        match token {
270            GenericListToken::Anonymous(_) | GenericListToken::ImplBlock(_, _) => {
271                self.shared.modify_generic_lists(|gl| {
272                    (f)(gl
273                        .get_mut(token)
274                        .expect(&format!("Did not find a generic list for {token:?}")))
275                })
276            }
277            GenericListToken::Definition(_) | GenericListToken::Expression(_) => (f)(self
278                .owned
279                .generic_lists
280                .get_mut(token)
281                .expect(&format!("Did not find a generic list for {token:?}"))),
282        }
283    }
284
285    #[tracing::instrument(level = "trace", skip_all)]
286    fn hir_type_expr_to_var<'a>(
287        &'a mut self,
288        e: &Loc<hir::TypeExpression>,
289        generic_list_token: &GenericListToken,
290    ) -> Result<TypeVarID> {
291        let id = match &e.inner {
292            hir::TypeExpression::Integer(i) => self.add_type_var(TypeVar::Known(
293                e.loc(),
294                KnownType::Integer(i.clone()),
295                vec![],
296            )),
297            hir::TypeExpression::String(s) => self.add_type_var(TypeVar::Known(
298                e.loc(),
299                KnownType::String(s.clone()),
300                vec![],
301            )),
302            hir::TypeExpression::TypeSpec(spec) => {
303                self.type_var_from_hir(e.loc(), &spec.clone(), generic_list_token)?
304            }
305            hir::TypeExpression::ConstGeneric(g) => {
306                let constraint = self.visit_const_generic(g, generic_list_token)?;
307
308                let tvar = self.new_generic_tlnumber(e.loc());
309                self.add_constraint(
310                    tvar.clone(),
311                    constraint,
312                    g.loc(),
313                    &tvar,
314                    ConstraintSource::Where,
315                );
316
317                tvar
318            }
319        };
320        Ok(id)
321    }
322
323    #[tracing::instrument(level = "trace", skip_all, fields(%hir_type))]
324    pub fn type_var_from_hir<'a>(
325        &'a mut self,
326        loc: Loc<()>,
327        hir_type: &crate::hir::TypeSpec,
328        generic_list_token: &GenericListToken,
329    ) -> Result<TypeVarID> {
330        let generic_list = self.get_generic_list(generic_list_token);
331        let var = match &hir_type {
332            hir::TypeSpec::Declared(base, params) => {
333                let params = params
334                    .iter()
335                    .map(|e| self.hir_type_expr_to_var(e, generic_list_token))
336                    .collect::<Result<Vec<_>>>()?;
337
338                self.add_type_var(TypeVar::Known(
339                    loc,
340                    KnownType::Named(base.inner.clone()),
341                    params,
342                ))
343            }
344            hir::TypeSpec::Generic(name) => match generic_list
345                .ok_or_else(|| diag_anyhow!(loc, "Found no generic list for {name}"))?
346                .get(&name.inner)
347            {
348                Some(t) => t.clone(),
349                None => {
350                    info!("Current source is {generic_list_token:?}");
351                    panic!("No entry in generic list for {name:?}");
352                }
353            },
354            hir::TypeSpec::Tuple(inner) => {
355                let inner = inner
356                    .iter()
357                    .map(|t| self.type_var_from_hir(loc, t, generic_list_token))
358                    .collect::<Result<_>>()?;
359                self.add_type_var(TypeVar::tuple(loc, inner))
360            }
361            hir::TypeSpec::Array { inner, size } => {
362                let inner = self.type_var_from_hir(loc, inner, generic_list_token)?;
363                let size = self.hir_type_expr_to_var(size, generic_list_token)?;
364
365                self.add_type_var(TypeVar::array(loc, inner, size))
366            }
367            hir::TypeSpec::Wire(inner) => {
368                let inner = self.type_var_from_hir(loc, inner, generic_list_token)?;
369                self.add_type_var(TypeVar::wire(loc, inner))
370            }
371            hir::TypeSpec::Inverted(inner) => {
372                let inner = self.type_var_from_hir(loc, inner, generic_list_token)?;
373                self.add_type_var(TypeVar::inverted(loc, inner))
374            }
375            hir::TypeSpec::Wildcard(_) => self.new_generic_any(),
376            hir::TypeSpec::TraitSelf(_) => {
377                diag_bail!(
378                    loc,
379                    "Trying to convert TraitSelf to type inference type var"
380                )
381            }
382        };
383
384        Ok(var)
385    }
386
387    /// Returns the type of the expression with the specified id. Error if no equation
388    /// for the specified expression exists
389    pub fn type_of(&self, expr: &TypedExpression) -> TypeVarID {
390        if let Some(t) = self.owned.equations.get(expr) {
391            *t
392        } else {
393            panic!("Tried looking up the type of {expr:?} but it was not found")
394        }
395    }
396
397    pub fn maybe_type_of(&self, expr: &TypedExpression) -> Option<&TypeVarID> {
398        self.owned.equations.get(expr)
399    }
400
401    pub fn new_generic_int(&mut self, loc: Loc<()>, symtab: &SymbolTable) -> TypeVar {
402        TypeVar::Known(loc, t_int(symtab), vec![self.new_generic_tluint(loc)])
403    }
404
405    pub fn new_concrete_int(&mut self, size: BigUint, loc: Loc<()>) -> TypeVarID {
406        TypeVar::Known(loc, KnownType::Integer(size.to_bigint()), vec![]).insert(self)
407    }
408
409    /// Return a new generic int. The first returned value is int<N>, and the second
410    /// value is N
411    pub fn new_split_generic_int(
412        &mut self,
413        loc: Loc<()>,
414        symtab: &SymbolTable,
415    ) -> (TypeVarID, TypeVarID) {
416        let size = self.new_generic_tlint(loc);
417        let full = self.add_type_var(TypeVar::Known(loc, t_int(symtab), vec![size.clone()]));
418        (full, size)
419    }
420
421    pub fn new_split_generic_uint(
422        &mut self,
423        loc: Loc<()>,
424        symtab: &SymbolTable,
425    ) -> (TypeVarID, TypeVarID) {
426        let size = self.new_generic_tluint(loc);
427        let full = self.add_type_var(TypeVar::Known(loc, t_uint(symtab), vec![size.clone()]));
428        (full, size)
429    }
430
431    pub fn new_generic_with_meta(&mut self, loc: Loc<()>, meta: MetaType) -> TypeVarID {
432        let id = self.new_typeid();
433        self.add_type_var(TypeVar::Unknown(loc, id, TraitList::empty(), meta))
434    }
435
436    pub fn new_generic_type(&mut self, loc: Loc<()>) -> TypeVarID {
437        let id = self.new_typeid();
438        self.add_type_var(TypeVar::Unknown(
439            loc,
440            id,
441            TraitList::empty(),
442            MetaType::Type,
443        ))
444    }
445
446    pub fn new_generic_any(&mut self) -> TypeVarID {
447        let id = self.new_typeid();
448        // NOTE: ().nowhere() is fine here, we can never fail to unify with MetaType::Any so
449        // this loc will never be displayed
450        self.add_type_var(TypeVar::Unknown(
451            ().nowhere(),
452            id,
453            TraitList::empty(),
454            MetaType::Any,
455        ))
456    }
457
458    pub fn new_generic_tlbool(&mut self, loc: Loc<()>) -> TypeVarID {
459        let id = self.new_typeid();
460        self.add_type_var(TypeVar::Unknown(
461            loc,
462            id,
463            TraitList::empty(),
464            MetaType::Bool,
465        ))
466    }
467
468    pub fn new_generic_tlstr(&mut self, loc: Loc<()>) -> TypeVarID {
469        let id = self.new_typeid();
470        self.add_type_var(TypeVar::Unknown(loc, id, TraitList::empty(), MetaType::Str))
471    }
472
473    pub fn new_generic_tluint(&mut self, loc: Loc<()>) -> TypeVarID {
474        let id = self.new_typeid();
475        self.add_type_var(TypeVar::Unknown(
476            loc,
477            id,
478            TraitList::empty(),
479            MetaType::Uint,
480        ))
481    }
482
483    pub fn new_generic_tlint(&mut self, loc: Loc<()>) -> TypeVarID {
484        let id = self.new_typeid();
485        self.add_type_var(TypeVar::Unknown(loc, id, TraitList::empty(), MetaType::Int))
486    }
487
488    pub fn new_generic_tlnumber(&mut self, loc: Loc<()>) -> TypeVarID {
489        let id = self.new_typeid();
490        self.add_type_var(TypeVar::Unknown(
491            loc,
492            id,
493            TraitList::empty(),
494            MetaType::Number,
495        ))
496    }
497
498    pub fn new_generic_number(&mut self, loc: Loc<()>, ctx: &Context) -> (TypeVarID, TypeVarID) {
499        let number = ctx
500            .symtab
501            .lookup_trait(&Path::from_strs(&["Number"]).nowhere())
502            .expect("Did not find number in symtab")
503            .0;
504        let id = self.new_typeid();
505        let size = self.new_generic_tluint(loc);
506        let t = TraitReq {
507            name: TraitName::Named(number.nowhere()),
508            type_params: vec![size.clone()],
509        }
510        .nowhere();
511        (
512            self.add_type_var(TypeVar::Unknown(
513                loc,
514                id,
515                TraitList::from_vec(vec![t]),
516                MetaType::Type,
517            )),
518            size,
519        )
520    }
521
522    pub fn new_generic_with_traits(&mut self, loc: Loc<()>, traits: TraitList) -> TypeVarID {
523        let id = self.new_typeid();
524        self.add_type_var(TypeVar::Unknown(loc, id, traits, MetaType::Type))
525    }
526
527    /// Returns the current pipeline state. `access_loc` is *not* used to specify where to get the
528    /// state from, it is only used for the Diagnostic::bug that gets emitted if there is no
529    /// pipeline state
530    pub fn get_pipeline_state<T>(&self, access_loc: &Loc<T>) -> Result<&PipelineState> {
531        self.owned
532            .pipeline_state
533            .as_ref()
534            .ok_or_else(|| diag_anyhow!(access_loc, "Expected to have a pipeline state"))
535    }
536
537    /// Visit a unit but before doing any preprocessing run the `pp` function.
538    pub fn visit_unit_with_preprocessing(
539        &mut self,
540        entity: &Loc<Unit>,
541        pp: impl FnOnce(&mut TypeState, &Loc<Unit>, &GenericListToken, &Context) -> Result<()>,
542        ctx: &Context,
543    ) -> Result<()> {
544        let generic_list = self.create_generic_list(
545            GenericListSource::Definition(&entity.name.name_id().inner),
546            &entity.head.unit_type_params,
547            &entity.head.scope_type_params,
548            None,
549            // NOTE: I'm not 100% sure we need to pass these here, the information
550            // is probably redundant
551            &entity.head.where_clauses,
552        )?;
553
554        pp(self, entity, &generic_list, ctx)?;
555
556        // Add equations for the inputs
557        for (name, t) in &entity.inputs {
558            let tvar = self.type_var_from_hir(t.loc(), t, &generic_list)?;
559            self.add_equation(TypedExpression::Name(name.inner.clone()), tvar)
560        }
561
562        if let UnitKind::Pipeline {
563            depth,
564            depth_typeexpr_id,
565        } = &entity.head.unit_kind.inner
566        {
567            self.setup_pipeline_state(
568                &entity.head.unit_kind,
569                &entity.body,
570                &generic_list,
571                depth,
572                depth_typeexpr_id,
573            )?;
574
575            let clock_index = if entity.head.is_nonstatic_method {
576                1
577            } else {
578                0
579            };
580
581            TypedExpression::Name(entity.inputs[clock_index].0.clone().inner)
582                .unify_with(&self.t_clock(entity.head.unit_kind.loc(), ctx.symtab), self)
583                .commit(self, ctx)
584                .into_diagnostic(
585                    entity.inputs[0].1.loc(),
586                    |diag,
587                     Tm {
588                         g: got,
589                         e: _expected,
590                     }| {
591                        diag.message(format!(
592                            "First pipeline argument must be a clock. Got {}",
593                            got.display(self)
594                        ))
595                        .primary_label("expected clock")
596                    },
597                    self,
598                )?;
599            // In order to catch negative depth early when they are specified as literals,
600            // we'll instantly check requirements here
601            self.check_requirements(false, ctx)?;
602        }
603
604        self.visit_expression(&entity.body, ctx, &generic_list);
605
606        // Ensure that the output type matches what the user specified, and unit otherwise
607        if let Some(output_type) = &entity.head.output_type {
608            let tvar = self.type_var_from_hir(output_type.loc(), output_type, &generic_list)?;
609
610            self.owned.trace_stack.push(|| {
611                TraceStackEntry::Message(format!(
612                    "Unifying with output type {}",
613                    tvar.debug_resolve(self)
614                ))
615            });
616            self.unify(&TypedExpression::Id(entity.body.inner.id), &tvar, ctx)
617                .into_diagnostic_no_expected_source(
618                    &entity.body,
619                    |diag,
620                     Tm {
621                         g: got,
622                         e: expected,
623                     }| {
624                        let expected = expected.display(self);
625                        let got = got.display(self);
626                        // FIXME: Might want to check if there is no return value in the block
627                        // and in that case suggest adding it.
628                        diag.message(format!(
629                            "Output type mismatch. Expected {expected}, got {got}"
630                        ))
631                        .primary_label(format!("Found type {got}"))
632                        .secondary_label(output_type, format!("{expected} type specified here"))
633                    },
634                    self,
635                )?;
636        } else {
637            // No output type, so unify with the unit type.
638            TypedExpression::Id(entity.body.inner.id)
639                .unify_with(&self.add_type_var(TypeVar::unit(entity.head.name.loc())), self)
640                .commit(self, ctx)
641                .into_diagnostic_no_expected_source(entity.body.loc(), |diag, Tm{g: got, e: _expected}| {
642                    diag.message("Output type mismatch")
643                        .primary_label(format!("Found type {got}", got = got.display(self)))
644                        .note(format!(
645                            "The {} does not specify a return type.\nAdd a return type, or remove the return value.",
646                            entity.head.unit_kind.name()
647                        ))
648                }, self)?;
649        }
650
651        if let Some(PipelineState {
652            current_stage_depth,
653            pipeline_loc,
654            total_depth,
655        }) = self.owned.pipeline_state.clone()
656        {
657            self.unify(&total_depth.inner, &current_stage_depth, ctx)
658                .into_diagnostic_no_expected_source(
659                    pipeline_loc,
660                    |diag, tm| {
661                        let (e, g) = tm.display_e_g(self);
662                        diag.message(format!("Pipeline depth mismatch. Expected {g} got {e}"))
663                            .primary_label(format!("Found {e} stages in this pipeline"))
664                    },
665                    self,
666                )?;
667        }
668
669        self.check_requirements(true, ctx)?;
670
671        // NOTE: We may accidentally leak a stage depth if this function returns early. However,
672        // since we only use stage depths in pipelines where we re-set it when we enter,
673        // accidentally leaving a depth in place should not trigger any *new* compiler bugs, but
674        // may help track something down
675        self.owned.pipeline_state = None;
676
677        Ok(())
678    }
679
680    fn setup_pipeline_state(
681        &mut self,
682        unit_kind: &Loc<UnitKind>,
683        body_loc: &Loc<Expression>,
684        generic_list: &GenericListToken,
685        depth: &Loc<TypeExpression>,
686        depth_typeexpr_id: &ExprID,
687    ) -> Result<()> {
688        let depth_var = self.hir_type_expr_to_var(depth, generic_list)?;
689        self.add_equation(TypedExpression::Id(*depth_typeexpr_id), depth_var.clone());
690        self.owned.pipeline_state = Some(PipelineState {
691            current_stage_depth: self.add_type_var(TypeVar::Known(
692                unit_kind.loc(),
693                KnownType::Integer(BigInt::zero()),
694                vec![],
695            )),
696            pipeline_loc: body_loc.loc(),
697            total_depth: depth_var.clone().at_loc(depth),
698        });
699        self.add_requirement(Requirement::PositivePipelineDepth {
700            depth: depth_var.at_loc(depth),
701        });
702        Ok(())
703    }
704
705    #[trace_typechecker]
706    #[tracing::instrument(level = "trace", skip_all, fields(%entity.name))]
707    pub fn visit_unit(&mut self, entity: &Loc<Unit>, ctx: &Context) -> Result<()> {
708        self.visit_unit_with_preprocessing(entity, |_, _, _, _| Ok(()), ctx)
709    }
710
711    #[trace_typechecker]
712    #[tracing::instrument(level = "trace", skip_all)]
713    fn visit_argument_list(
714        &mut self,
715        args: &Loc<ArgumentList<Expression>>,
716        ctx: &Context,
717        generic_list: &GenericListToken,
718    ) -> Result<()> {
719        for expr in args.expressions() {
720            self.visit_expression(expr, ctx, generic_list);
721        }
722        Ok(())
723    }
724
725    #[trace_typechecker]
726    fn type_check_argument_list(
727        &mut self,
728        args: &[Argument<Expression, TypeSpec>],
729        ctx: &Context,
730        generic_list: &GenericListToken,
731    ) -> Result<()> {
732        for Argument {
733            target,
734            target_type,
735            value,
736            kind,
737        } in args.iter()
738        {
739            let target_type = self.type_var_from_hir(value.loc(), target_type, generic_list)?;
740
741            let loc = match kind {
742                hir::param_util::ArgumentKind::Positional => value.loc(),
743                hir::param_util::ArgumentKind::Named => value.loc(),
744                hir::param_util::ArgumentKind::ShortNamed => target.loc(),
745            };
746
747            self.unify(&value.inner, &target_type, ctx)
748                .into_diagnostic(
749                    loc,
750                    |d, tm| {
751                        let (expected, got) = tm.display_e_g(self);
752                        d.message(format!(
753                            "Argument type mismatch. Expected {expected} got {got}"
754                        ))
755                        .primary_label(format!("expected {expected}"))
756                    },
757                    self,
758                )?;
759        }
760
761        Ok(())
762    }
763
764    #[trace_typechecker]
765    pub fn visit_expression_result(
766        &mut self,
767        expression: &Loc<Expression>,
768        ctx: &Context,
769        generic_list: &GenericListToken,
770        new_type: TypeVarID,
771    ) -> Result<()> {
772        // Recurse down the expression
773        match &expression.inner.kind {
774            ExprKind::Error => {
775                new_type
776                    .unify_with(&self.t_err(expression.loc()), self)
777                    .commit(self, ctx)
778                    .unwrap();
779            }
780            ExprKind::Identifier(_) => self.visit_identifier(expression, ctx)?,
781            ExprKind::TypeLevelInteger(_) => {
782                self.visit_type_level_integer(expression, generic_list, ctx)?
783            }
784            ExprKind::IntLiteral(_, _) => self.visit_int_literal(expression, ctx)?,
785            ExprKind::BoolLiteral(_) => self.visit_bool_literal(expression, ctx)?,
786            ExprKind::TriLiteral(_) => self.visit_tri_literal(expression, ctx)?,
787            ExprKind::TupleLiteral(_) => self.visit_tuple_literal(expression, ctx, generic_list)?,
788            ExprKind::TupleIndex(_, _) => self.visit_tuple_index(expression, ctx, generic_list)?,
789            ExprKind::ArrayLiteral(_) => self.visit_array_literal(expression, ctx, generic_list)?,
790            ExprKind::ArrayShorthandLiteral(_, _) => {
791                self.visit_array_shorthand_literal(expression, ctx, generic_list)?
792            }
793            ExprKind::CreatePorts => self.visit_create_ports(expression, ctx, generic_list)?,
794            ExprKind::FieldAccess(_, _) => {
795                self.visit_field_access(expression, ctx, generic_list)?
796            }
797            ExprKind::MethodCall { .. } => self.visit_method_call(expression, ctx, generic_list)?,
798            ExprKind::RangeIndex { .. } => self.visit_range_index(expression, ctx, generic_list)?,
799            ExprKind::Index(_, _) => self.visit_index(expression, ctx, generic_list)?,
800            ExprKind::Block(_) => self.visit_block_expr(expression, ctx, generic_list)?,
801            ExprKind::If(_, _, _) => self.visit_if(expression, ctx, generic_list)?,
802            ExprKind::Match(_, _) => self.visit_match(expression, ctx, generic_list)?,
803            ExprKind::BinaryOperator(_, _, _) => {
804                self.visit_binary_operator(expression, ctx, generic_list)?
805            }
806            ExprKind::UnaryOperator(_, _) => {
807                self.visit_unary_operator(expression, ctx, generic_list)?
808            }
809            ExprKind::Call {
810                kind,
811                callee,
812                args,
813                turbofish,
814                safety: _,
815            } => {
816                let head = ctx.symtab.unit_by_id(&callee.inner);
817
818                self.handle_function_like(
819                    expression.map_ref(|e| e.id),
820                    &expression.get_type(self),
821                    &FunctionLikeName::Free(callee.inner.clone()),
822                    &head,
823                    kind,
824                    args,
825                    ctx,
826                    true,
827                    false,
828                    turbofish.as_ref().map(|turbofish| TurbofishCtx {
829                        turbofish,
830                        prev_generic_list: generic_list,
831                        type_ctx: ctx,
832                    }),
833                    generic_list,
834                )?;
835            }
836            ExprKind::PipelineRef { .. } => {
837                self.visit_pipeline_ref(expression, generic_list, ctx)?;
838            }
839            ExprKind::StageReady | ExprKind::StageValid => {
840                expression
841                    .unify_with(&self.t_bool(expression.loc(), ctx.symtab), self)
842                    .commit(self, ctx)
843                    .into_default_diagnostic(expression, self)?;
844            }
845
846            ExprKind::TypeLevelIf(cond, on_true, on_false) => {
847                let cond_var = self.visit_const_generic_with_id(
848                    cond,
849                    generic_list,
850                    ConstraintSource::TypeLevelIf,
851                    ctx,
852                )?;
853                let t_bool = self.new_generic_tlbool(cond.loc());
854                self.unify(&cond_var, &t_bool, ctx).into_diagnostic(
855                    cond,
856                    |diag, tm| {
857                        let (_e, g) = tm.display_e_g(self);
858                        diag.message(format!("gen if conditions must be #bool, got {g}"))
859                    },
860                    self,
861                )?;
862
863                self.visit_expression(on_true, ctx, generic_list);
864                self.visit_expression(on_false, ctx, generic_list);
865
866                self.unify_expression_generic_error(expression, on_true.as_ref(), ctx)?;
867                self.unify_expression_generic_error(expression, on_false.as_ref(), ctx)?;
868            }
869            ExprKind::LambdaDef {
870                unit_kind,
871                arguments,
872                body,
873                lambda_type,
874                type_params,
875                outer_generic_params,
876                lambda_unit: _,
877                clock,
878                captures,
879            } => {
880                for arg in arguments {
881                    self.visit_pattern(arg, ctx, generic_list)?;
882                }
883
884                if let Some(clock) = clock {
885                    clock
886                        .unify_with(&self.t_clock(clock.loc(), ctx.symtab), self)
887                        .commit(self, ctx)
888                        .into_default_diagnostic(clock, self)?;
889                }
890
891                let outer_pipeline_state = self.owned.pipeline_state.take();
892                if let UnitKind::Pipeline {
893                    depth,
894                    depth_typeexpr_id,
895                } = &unit_kind.inner
896                {
897                    self.setup_pipeline_state(
898                        unit_kind,
899                        body,
900                        &generic_list,
901                        depth,
902                        depth_typeexpr_id,
903                    )?;
904                }
905                self.visit_expression(body, ctx, generic_list);
906                self.owned.pipeline_state = outer_pipeline_state;
907
908                let lambda_params = arguments
909                    .iter()
910                    .map(|arg| arg.get_type(self))
911                    .chain(vec![body.get_type(self)])
912                    .chain(captures.iter().map(|(_, cap_name)| cap_name.get_type(self)))
913                    .chain(
914                        outer_generic_params
915                            .iter()
916                            .map(|cap| {
917                                let gl = self.get_generic_list(generic_list).ok_or_else(|| {
918                                    diag_anyhow!(
919                                        expression,
920                                        "Found a captured generic but no generic list"
921                                    )
922                                })?;
923                                let t = gl.get(&cap.name_in_body).ok_or_else(|| {
924                                    diag_anyhow!(
925                                        &cap.name_in_body,
926                                        "Did not find an entry for {} in lambda generic list",
927                                        cap.name_in_body
928                                    )
929                                });
930                                Ok(t?.clone())
931                            })
932                            .collect::<Result<Vec<_>>>()?
933                            .into_iter(),
934                    )
935                    .collect::<Vec<_>>();
936
937                let self_type = TypeVar::Known(
938                    expression.loc(),
939                    KnownType::Named(lambda_type.clone()),
940                    lambda_params.clone(),
941                );
942
943                let unit_generic_list = self.create_generic_list(
944                    GenericListSource::Expression(expression.id.at_loc(expression)),
945                    &type_params.all().cloned().collect::<Vec<_>>(),
946                    &[],
947                    None,
948                    &[],
949                )?;
950
951                for (p, tp) in lambda_params.iter().zip(type_params.all()) {
952                    let gl = self.get_generic_list(&unit_generic_list).unwrap();
953                    // Safe unwrap, we're just unifying unknowns with unknowns
954                    p.unify_with(
955                        gl.get(&tp.name_id).ok_or_else(|| {
956                            diag_anyhow!(
957                                expression,
958                                "Lambda unit list did not contain {}",
959                                tp.name_id
960                            )
961                        })?,
962                        self,
963                    )
964                    .commit(self, ctx)
965                    .into_default_diagnostic(expression, self)?;
966                }
967                expression
968                    .unify_with(&self.add_type_var(self_type), self)
969                    .commit(self, ctx)
970                    .into_default_diagnostic(expression, self)?;
971            }
972            ExprKind::StaticUnreachable(_) => {}
973            ExprKind::Null => {}
974        }
975        Ok(())
976    }
977
978    #[tracing::instrument(level = "trace", skip_all)]
979    pub fn visit_expression(
980        &mut self,
981        expression: &Loc<Expression>,
982        ctx: &Context,
983        generic_list: &GenericListToken,
984    ) {
985        let new_type = self.new_generic_type(expression.loc());
986        self.add_equation(TypedExpression::Id(expression.inner.id), new_type);
987
988        match self.visit_expression_result(expression, ctx, generic_list, new_type) {
989            Ok(_) => {}
990            Err(e) => {
991                new_type
992                    .unify_with(&self.t_err(expression.loc()), self)
993                    .commit(self, ctx)
994                    .unwrap();
995
996                self.owned.diags.errors.push(e);
997            }
998        }
999    }
1000
1001    // Common handler for entities, functions and pipelines
1002    #[tracing::instrument(level = "trace", skip_all, fields(%name))]
1003    #[trace_typechecker]
1004    fn handle_function_like(
1005        &mut self,
1006        expression_id: Loc<ExprID>,
1007        expression_type: &TypeVarID,
1008        name: &FunctionLikeName,
1009        head: &Loc<UnitHead>,
1010        call_kind: &CallKind,
1011        args: &Loc<ArgumentList<Expression>>,
1012        ctx: &Context,
1013        // Whether or not to visit the argument expressions passed to the function here. This
1014        // should not be done if the expressoins have been visited before, for example, when
1015        // handling methods
1016        visit_args: bool,
1017        // If we are calling a method, we have an implicit self argument which means
1018        // that any error reporting number of arguments should be reduced by one
1019        is_method: bool,
1020        turbofish: Option<TurbofishCtx>,
1021        generic_list: &GenericListToken,
1022    ) -> Result<()> {
1023        // Add new symbols for all the type parameters
1024        let unit_generic_list = self.create_generic_list(
1025            GenericListSource::Expression(expression_id),
1026            &head.unit_type_params,
1027            &head.scope_type_params,
1028            turbofish,
1029            &head.where_clauses,
1030        )?;
1031
1032        match (&head.unit_kind.inner, call_kind) {
1033            (
1034                UnitKind::Pipeline {
1035                    depth: udepth,
1036                    depth_typeexpr_id: _,
1037                },
1038                CallKind::Pipeline {
1039                    inst_loc: _,
1040                    depth: cdepth,
1041                    depth_typeexpr_id: cdepth_typeexpr_id,
1042                },
1043            ) => {
1044                let definition_depth = self.hir_type_expr_to_var(udepth, &unit_generic_list)?;
1045                let call_depth = self.hir_type_expr_to_var(cdepth, generic_list)?;
1046
1047                // NOTE: We're not adding udepth_typeexpr_id here as that would break
1048                // in the future if we try to do recursion. We will also never need to look
1049                // up the depth in the definition
1050                self.add_equation(TypedExpression::Id(*cdepth_typeexpr_id), call_depth.clone());
1051
1052                self.unify(&call_depth, &definition_depth, ctx)
1053                    .into_diagnostic_no_expected_source(
1054                        cdepth,
1055                        |diag, tm| {
1056                            let (e, g) = tm.display_e_g(self);
1057                            diag.message("Pipeline depth mismatch")
1058                                .primary_label(format!("Expected depth {e}, got {g}"))
1059                                .secondary_label(udepth, format!("{name} has depth {e}"))
1060                        },
1061                        self,
1062                    )?;
1063            }
1064            _ => {}
1065        }
1066
1067        if visit_args {
1068            self.visit_argument_list(args, ctx, &generic_list)?;
1069        }
1070
1071        let type_params = &head.get_type_params();
1072
1073        // Special handling of built in functions
1074        macro_rules! handle_special_functions {
1075            ($([$($path:expr),*] => $handler:expr),*) => {
1076                $(
1077                    let path = Path(vec![$(PathSegment::Named(Identifier::intern($path).nowhere())),*]).nowhere();
1078                    if ctx.symtab
1079                        .try_lookup_id(&path)
1080                        .map(|n| &FunctionLikeName::Free(n) == name)
1081                        .unwrap_or(false)
1082                    {
1083                        $handler
1084                    };
1085                )*
1086            }
1087        }
1088
1089        // NOTE: These would be better as a closure, but unfortunately that does not satisfy
1090        // the borrow checker
1091        macro_rules! generic_arg {
1092            ($idx:expr) => {
1093                self.get_generic_list(&unit_generic_list)
1094                    .ok_or_else(|| diag_anyhow!(expression_id, "Found no generic list for call"))?
1095                    [&type_params[$idx].name_id()]
1096                    .clone()
1097            };
1098        }
1099
1100        let matched_args =
1101            match_args_with_params(args, &head.inputs.inner, is_method).map_err(|e| {
1102                let diag: Diagnostic = e.into();
1103                diag.secondary_label(
1104                    head,
1105                    format!("{kind} defined here", kind = head.unit_kind.name()),
1106                )
1107            })?;
1108
1109        handle_special_functions! {
1110            ["std", "conv", "concat"] => {
1111                self.handle_concat(
1112                    expression_id,
1113                    generic_arg!(0),
1114                    generic_arg!(1),
1115                    generic_arg!(2),
1116                    &matched_args,
1117                    ctx
1118                )?
1119            },
1120            ["std", "conv", "trunc"] => {
1121                self.handle_trunc(
1122                    expression_id,
1123                    generic_arg!(0),
1124                    generic_arg!(1),
1125                    &matched_args,
1126                    ctx
1127                )?
1128            },
1129            ["std", "ops", "comb_div"] => {
1130                self.handle_comb_mod_or_div(
1131                    generic_arg!(0),
1132                    &matched_args,
1133                    ctx
1134                )?
1135            },
1136            ["std", "ops", "comb_mod"] => {
1137                self.handle_comb_mod_or_div(
1138                    generic_arg!(0),
1139                    &matched_args,
1140                    ctx
1141                )?
1142            },
1143            ["std", "mem", "clocked_memory"]  => {
1144                let num_elements = generic_arg!(0);
1145                let addr_size = generic_arg!(2);
1146
1147                self.handle_clocked_memory(num_elements, addr_size, &matched_args, ctx)?
1148            },
1149            // NOTE: the last argument of _init does not need special treatment, so
1150            // we can use the same code path for both for now
1151            ["std", "mem", "clocked_memory_init"]  => {
1152                let num_elements = generic_arg!(0);
1153                let addr_size = generic_arg!(2);
1154
1155                self.handle_clocked_memory(num_elements, addr_size, &matched_args, ctx)?
1156            },
1157            ["std", "mem", "read_memory"]  => {
1158                let addr_size = generic_arg!(0);
1159                let num_elements = generic_arg!(2);
1160
1161                self.handle_read_memory(num_elements, addr_size, &matched_args, ctx)?
1162            }
1163        };
1164
1165        // Unify the types of the arguments
1166        self.type_check_argument_list(&matched_args, ctx, &unit_generic_list)?;
1167
1168        let return_type = head
1169            .output_type
1170            .as_ref()
1171            .map(|o| self.type_var_from_hir(expression_id.loc(), o, &unit_generic_list))
1172            .transpose()?
1173            .unwrap_or_else(|| {
1174                self.add_type_var(TypeVar::Known(
1175                    expression_id.loc(),
1176                    KnownType::Tuple,
1177                    vec![],
1178                ))
1179            });
1180
1181        self.unify(expression_type, &return_type, ctx)
1182            .into_default_diagnostic(expression_id.loc(), self)?;
1183
1184        Ok(())
1185    }
1186
1187    pub fn handle_concat(
1188        &mut self,
1189        expression_id: Loc<ExprID>,
1190        source_lhs_ty: TypeVarID,
1191        source_rhs_ty: TypeVarID,
1192        source_result_ty: TypeVarID,
1193        args: &[Argument<Expression, TypeSpec>],
1194        ctx: &Context,
1195    ) -> Result<()> {
1196        let (lhs_type, lhs_size) = self.new_generic_number(expression_id.loc(), ctx);
1197        let (rhs_type, rhs_size) = self.new_generic_number(expression_id.loc(), ctx);
1198        let (result_type, result_size) = self.new_generic_number(expression_id.loc(), ctx);
1199        self.unify(&source_lhs_ty, &lhs_type, ctx)
1200            .into_default_diagnostic(args[0].value.loc(), self)?;
1201        self.unify(&source_rhs_ty, &rhs_type, ctx)
1202            .into_default_diagnostic(args[1].value.loc(), self)?;
1203        self.unify(&source_result_ty, &result_type, ctx)
1204            .into_default_diagnostic(expression_id.loc(), self)?;
1205
1206        // Result size is sum of input sizes
1207        self.add_constraint(
1208            result_size.clone(),
1209            ce_var(&lhs_size) + ce_var(&rhs_size),
1210            expression_id.loc(),
1211            &result_size,
1212            ConstraintSource::Concatenation,
1213        );
1214        self.add_constraint(
1215            lhs_size.clone(),
1216            ce_var(&result_size) + -ce_var(&rhs_size),
1217            args[0].value.loc(),
1218            &lhs_size,
1219            ConstraintSource::Concatenation,
1220        );
1221        self.add_constraint(
1222            rhs_size.clone(),
1223            ce_var(&result_size) + -ce_var(&lhs_size),
1224            args[1].value.loc(),
1225            &rhs_size,
1226            ConstraintSource::Concatenation,
1227        );
1228
1229        self.add_requirement(Requirement::SharedBase(vec![
1230            lhs_type.at_loc(args[0].value),
1231            rhs_type.at_loc(args[1].value),
1232            result_type.at_loc(&expression_id.loc()),
1233        ]));
1234        Ok(())
1235    }
1236
1237    pub fn handle_trunc(
1238        &mut self,
1239        expression_id: Loc<ExprID>,
1240        source_in_ty: TypeVarID,
1241        source_result_ty: TypeVarID,
1242        args: &[Argument<Expression, TypeSpec>],
1243        ctx: &Context,
1244    ) -> Result<()> {
1245        let (in_ty, _) = self.new_generic_number(expression_id.loc(), ctx);
1246        let (result_type, _) = self.new_generic_number(expression_id.loc(), ctx);
1247        self.unify(&source_in_ty, &in_ty, ctx)
1248            .into_default_diagnostic(args[0].value.loc(), self)?;
1249        self.unify(&source_result_ty, &result_type, ctx)
1250            .into_default_diagnostic(expression_id.loc(), self)?;
1251
1252        self.add_requirement(Requirement::SharedBase(vec![
1253            in_ty.at_loc(args[0].value),
1254            result_type.at_loc(&expression_id.loc()),
1255        ]));
1256        Ok(())
1257    }
1258
1259    pub fn handle_comb_mod_or_div(
1260        &mut self,
1261        n_ty: TypeVarID,
1262        args: &[Argument<Expression, TypeSpec>],
1263        ctx: &Context,
1264    ) -> Result<()> {
1265        let (num, _) = self.new_generic_number(args[0].value.loc(), ctx);
1266        self.unify(&n_ty, &num, ctx)
1267            .into_default_diagnostic(args[0].value.loc(), self)?;
1268        Ok(())
1269    }
1270
1271    pub fn handle_clocked_memory(
1272        &mut self,
1273        num_elements: TypeVarID,
1274        addr_size_arg: TypeVarID,
1275        args: &[Argument<Expression, TypeSpec>],
1276        ctx: &Context,
1277    ) -> Result<()> {
1278        // FIXME: When we support where clauses, we should move this
1279        // definition into the definition of clocked_memory
1280        let (addr_type, addr_size) = self.new_split_generic_uint(args[1].value.loc(), ctx.symtab);
1281        let arg1_loc = args[1].value.loc();
1282        let tup = TypeVar::tuple(
1283            args[1].value.loc(),
1284            vec![
1285                self.new_generic_type(arg1_loc),
1286                addr_type,
1287                self.new_generic_type(arg1_loc),
1288            ],
1289        );
1290        let port_type = TypeVar::array(
1291            arg1_loc,
1292            self.add_type_var(tup),
1293            self.new_generic_tluint(arg1_loc),
1294        )
1295        .insert(self);
1296
1297        self.add_constraint(
1298            addr_size.clone(),
1299            bits_to_store(ce_var(&num_elements) - ce_int(1.to_bigint())),
1300            args[1].value.loc(),
1301            &port_type,
1302            ConstraintSource::MemoryIndexing,
1303        );
1304
1305        // NOTE: Unwrap is safe, size is still generic at this point
1306        self.unify(&addr_size, &addr_size_arg, ctx).unwrap();
1307        self.unify_expression_generic_error(args[1].value, &port_type, ctx)?;
1308
1309        Ok(())
1310    }
1311
1312    pub fn handle_read_memory(
1313        &mut self,
1314        num_elements: TypeVarID,
1315        addr_size_arg: TypeVarID,
1316        args: &[Argument<Expression, TypeSpec>],
1317        ctx: &Context,
1318    ) -> Result<()> {
1319        let (addr_type, addr_size) = self.new_split_generic_uint(args[1].value.loc(), ctx.symtab);
1320
1321        self.add_constraint(
1322            addr_size.clone(),
1323            bits_to_store(ce_var(&num_elements) - ce_int(1.to_bigint())),
1324            args[1].value.loc(),
1325            &addr_type,
1326            ConstraintSource::MemoryIndexing,
1327        );
1328
1329        // NOTE: Unwrap is safe, size is still generic at this point
1330        self.unify(&addr_size, &addr_size_arg, ctx).unwrap();
1331
1332        Ok(())
1333    }
1334
1335    #[tracing::instrument(level = "trace", skip(self, turbofish, where_clauses))]
1336    pub fn create_generic_list(
1337        &mut self,
1338        source: GenericListSource,
1339        type_params: &[Loc<TypeParam>],
1340        scope_type_params: &[Loc<TypeParam>],
1341        turbofish: Option<TurbofishCtx>,
1342        where_clauses: &[Loc<WhereClause>],
1343    ) -> Result<GenericListToken> {
1344        let turbofish_params = if let Some(turbofish) = turbofish.as_ref() {
1345            if type_params.is_empty() {
1346                return Err(Diagnostic::error(
1347                    turbofish.turbofish,
1348                    "Turbofish on non-generic function",
1349                )
1350                .primary_label("Turbofish on non-generic function"));
1351            }
1352
1353            let matched_params =
1354                param_util::match_args_with_params(turbofish.turbofish, &type_params, false)?;
1355
1356            // We want this to be positional, but the params we get from matching are
1357            // named, transform it. We'll do some unwrapping here, but it is safe
1358            // because we know all params are present
1359            matched_params
1360                .iter()
1361                .map(|matched_param| {
1362                    let i = type_params
1363                        .iter()
1364                        .enumerate()
1365                        .find_map(|(i, param)| match &param.inner {
1366                            TypeParam {
1367                                ident,
1368                                name_id: _,
1369                                trait_bounds: _,
1370                                meta: _,
1371                            } => {
1372                                if ident == matched_param.target {
1373                                    Some(i)
1374                                } else {
1375                                    None
1376                                }
1377                            }
1378                        })
1379                        .unwrap();
1380                    (i, matched_param)
1381                })
1382                .sorted_by_key(|(i, _)| *i)
1383                .map(|(_, mp)| Some(mp.value))
1384                .collect::<Vec<_>>()
1385        } else {
1386            type_params.iter().map(|_| None).collect::<Vec<_>>()
1387        };
1388
1389        let mut inline_trait_bounds: Vec<Loc<WhereClause>> = vec![];
1390
1391        let scope_type_params = scope_type_params
1392            .iter()
1393            .map(|param| {
1394                let hir::TypeParam {
1395                    ident,
1396                    name_id,
1397                    trait_bounds,
1398                    meta,
1399                } = &param.inner;
1400                if !trait_bounds.is_empty() {
1401                    if let MetaType::Type = meta {
1402                        inline_trait_bounds.push(
1403                            WhereClause::Type {
1404                                target: name_id.clone().at_loc(ident),
1405                                traits: trait_bounds.clone(),
1406                            }
1407                            .at_loc(param),
1408                        );
1409                    } else {
1410                        return Err(Diagnostic::bug(param, "Trait bounds on generic int")
1411                            .primary_label("Trait bounds are only allowed on type parameters"));
1412                    }
1413                }
1414                Ok((
1415                    name_id.clone(),
1416                    self.new_generic_with_meta(param.loc(), meta.clone()),
1417                ))
1418            })
1419            .collect::<Result<Vec<_>>>()?;
1420
1421        let new_list = type_params
1422            .iter()
1423            .enumerate()
1424            .map(|(i, param)| {
1425                let hir::TypeParam {
1426                    ident,
1427                    name_id,
1428                    trait_bounds,
1429                    meta,
1430                } = &param.inner;
1431
1432                let t = self.new_generic_with_meta(param.loc(), meta.clone());
1433
1434                if let Some(tf) = &turbofish_params[i] {
1435                    let tf_ctx = turbofish.as_ref().unwrap();
1436                    let ty = self.hir_type_expr_to_var(tf, tf_ctx.prev_generic_list)?;
1437                    self.unify(&ty, &t, tf_ctx.type_ctx)
1438                        .into_default_diagnostic(param, self)?;
1439                }
1440
1441                if !trait_bounds.is_empty() {
1442                    if let MetaType::Type = meta {
1443                        inline_trait_bounds.push(
1444                            WhereClause::Type {
1445                                target: name_id.clone().at_loc(ident),
1446                                traits: trait_bounds.clone(),
1447                            }
1448                            .at_loc(param),
1449                        );
1450                    }
1451                    Ok((name_id.clone(), t))
1452                } else {
1453                    Ok((name_id.clone(), t))
1454                }
1455            })
1456            .collect::<Result<Vec<_>>>()?
1457            .into_iter()
1458            .chain(scope_type_params.into_iter())
1459            .map(|(name, t)| (name, t.clone()))
1460            .collect::<HashMap<_, _>>();
1461
1462        self.owned.trace_stack.push(|| {
1463            TraceStackEntry::NewGenericList(
1464                new_list
1465                    .iter()
1466                    .map(|(name, var)| (name.clone(), var.debug_resolve(self)))
1467                    .collect(),
1468            )
1469        });
1470
1471        let token = self.add_mapped_generic_list(source.clone(), new_list.clone());
1472
1473        for constraint in where_clauses.iter().chain(inline_trait_bounds.iter()) {
1474            match &constraint.inner {
1475                WhereClause::Type { target, traits } => {
1476                    self.visit_trait_bounds(target, traits.as_slice(), &token)?;
1477                }
1478                WhereClause::Int {
1479                    target,
1480                    kind,
1481                    constraint,
1482                    if_unsatisfied,
1483                } => {
1484                    let tvar = new_list.get(target).ok_or_else(|| {
1485                        Diagnostic::error(
1486                            target,
1487                            format!("{target} is not a generic parameter on this unit"),
1488                        )
1489                        .primary_label("Not a generic parameter")
1490                    })?;
1491                    let int_constraint = self.visit_const_generic(constraint, &token)?;
1492                    match kind {
1493                        spade_hir::WhereClauseKind::Eq => {
1494                            self.add_constraint(
1495                                tvar.clone(),
1496                                int_constraint,
1497                                constraint.loc(),
1498                                &tvar,
1499                                ConstraintSource::Where,
1500                            );
1501                        }
1502                        _ => {
1503                            let rhsvar = self.new_generic_tlint(constraint.loc());
1504                            self.add_constraint(
1505                                rhsvar.clone(),
1506                                int_constraint,
1507                                constraint.loc(),
1508                                &tvar,
1509                                ConstraintSource::Where,
1510                            );
1511
1512                            self.add_requirement(Requirement::WhereInequality {
1513                                var: target.inner.clone(),
1514                                lhs: tvar.clone().at_loc(target),
1515                                rhs: rhsvar.at_loc(&constraint.loc()),
1516                                inequality: *kind,
1517                                message: if_unsatisfied.clone(),
1518                                callsite: match source {
1519                                    GenericListSource::Anonymous => None,
1520                                    GenericListSource::Definition(_) => None,
1521                                    GenericListSource::ImplBlock { .. } => None,
1522                                    GenericListSource::Expression(loc) => Some(loc.loc()),
1523                                },
1524                            });
1525                        }
1526                    }
1527                }
1528            }
1529        }
1530
1531        Ok(token)
1532    }
1533
1534    /// Adds a generic list with parameters already mapped to types
1535    pub fn add_mapped_generic_list(
1536        &mut self,
1537        source: GenericListSource,
1538        mapping: HashMap<NameID, TypeVarID>,
1539    ) -> GenericListToken {
1540        let token = match source {
1541            GenericListSource::Anonymous => GenericListToken::Anonymous(
1542                self.shared
1543                    .next_annon_generic_list
1544                    .fetch_add(1, std::sync::atomic::Ordering::SeqCst),
1545            ),
1546            GenericListSource::Definition(name) => GenericListToken::Definition(name.clone()),
1547            GenericListSource::ImplBlock { target, id } => {
1548                GenericListToken::ImplBlock(target.clone(), id)
1549            }
1550            GenericListSource::Expression(id) => GenericListToken::Expression(id.inner),
1551        };
1552
1553        let prev = match source {
1554            GenericListSource::Anonymous | GenericListSource::ImplBlock { .. } => self
1555                .shared
1556                .modify_generic_lists(|lists| lists.insert(token.clone(), mapping)),
1557            GenericListSource::Definition(_) | GenericListSource::Expression(_) => {
1558                self.owned.generic_lists.insert(token.clone(), mapping)
1559            }
1560        };
1561
1562        if prev.is_some() {
1563            panic!("A generic list already existed for {token:?}");
1564        }
1565
1566        token
1567    }
1568
1569    #[tracing::instrument(level = "trace", skip_all)]
1570    #[trace_typechecker]
1571    pub fn visit_block(
1572        &mut self,
1573        block: &Block,
1574        ctx: &Context,
1575        generic_list: &GenericListToken,
1576    ) -> Result<()> {
1577        for statement in &block.statements {
1578            self.visit_statement(statement, ctx, generic_list);
1579        }
1580        if let Some(result) = &block.result {
1581            self.visit_expression(result, ctx, generic_list);
1582        }
1583        Ok(())
1584    }
1585
1586    #[tracing::instrument(level = "trace", skip_all)]
1587    pub fn visit_impl_blocks(&mut self, item_list: &ItemList) -> TraitImplList {
1588        let mut trait_impls = TraitImplList::new();
1589        for (target, impls) in &item_list.impls.inner {
1590            for (trait_name, impls) in impls {
1591                for (target_args, impls) in impls {
1592                    for (trait_args, impl_block) in impls {
1593                        let result =
1594                            (|| {
1595                                let generic_list = self.create_generic_list(
1596                                    GenericListSource::ImplBlock {
1597                                        target,
1598                                        id: impl_block.id,
1599                                    },
1600                                    &[],
1601                                    impl_block.type_params.as_slice(),
1602                                    None,
1603                                    &[],
1604                                )?;
1605
1606                                let loc = trait_name
1607                                    .name_loc()
1608                                    .map(|n| ().at_loc(&n))
1609                                    .unwrap_or(().at_loc(&impl_block));
1610
1611                                let trait_type_params = trait_args
1612                                    .iter()
1613                                    .map(|param| {
1614                                        Ok(TemplateTypeVarID::new(self.hir_type_expr_to_var(
1615                                            &param.clone().at_loc(&loc),
1616                                            &generic_list,
1617                                        )?))
1618                                    })
1619                                    .collect::<Result<_>>()?;
1620
1621                                let target_type_params = target_args
1622                                    .iter()
1623                                    .map(|param| {
1624                                        Ok(TemplateTypeVarID::new(self.hir_type_expr_to_var(
1625                                            &param.clone().at_loc(&loc),
1626                                            &generic_list,
1627                                        )?))
1628                                    })
1629                                    .collect::<Result<_>>()?;
1630
1631                                trait_impls.inner.entry(target.clone()).or_default().push(
1632                                    TraitImpl {
1633                                        name: trait_name.clone(),
1634                                        target_type_params,
1635                                        trait_type_params,
1636
1637                                        impl_block: impl_block.inner.clone(),
1638                                    },
1639                                );
1640
1641                                Ok(())
1642                            })();
1643
1644                        match result {
1645                            Ok(()) => {}
1646                            Err(e) => self.owned.diags.errors.push(e),
1647                        }
1648                    }
1649                }
1650            }
1651        }
1652
1653        trait_impls
1654    }
1655
1656    #[trace_typechecker]
1657    pub fn visit_pattern(
1658        &mut self,
1659        pattern: &Loc<Pattern>,
1660        ctx: &Context,
1661        generic_list: &GenericListToken,
1662    ) -> Result<()> {
1663        let new_type = self.new_generic_type(pattern.loc());
1664        self.add_equation(TypedExpression::Id(pattern.inner.id), new_type);
1665        match &pattern.inner.kind {
1666            hir::PatternKind::Integer(val) => {
1667                let (num_t, _) = &self.new_generic_number(pattern.loc(), ctx);
1668                self.add_requirement(Requirement::FitsIntLiteral {
1669                    value: ConstantInt::Literal(val.clone()),
1670                    target_type: num_t.clone().at_loc(pattern),
1671                });
1672                self.unify(pattern, num_t, ctx)
1673                    .expect("Failed to unify new_generic with int");
1674            }
1675            hir::PatternKind::Bool(_) => {
1676                pattern
1677                    .unify_with(&self.t_bool(pattern.loc(), ctx.symtab), self)
1678                    .commit(self, ctx)
1679                    .expect("Expected new_generic with boolean");
1680            }
1681            hir::PatternKind::Name { name, pre_declared } => {
1682                if !pre_declared {
1683                    self.add_equation(
1684                        TypedExpression::Name(name.clone().inner),
1685                        pattern.get_type(self),
1686                    );
1687                }
1688                self.unify(
1689                    &TypedExpression::Id(pattern.id),
1690                    &TypedExpression::Name(name.clone().inner),
1691                    ctx,
1692                )
1693                .into_default_diagnostic(name.loc(), self)?;
1694            }
1695            hir::PatternKind::Tuple(subpatterns) => {
1696                for pattern in subpatterns {
1697                    self.visit_pattern(pattern, ctx, generic_list)?;
1698                }
1699                let tuple_type = self.add_type_var(TypeVar::tuple(
1700                    pattern.loc(),
1701                    subpatterns
1702                        .iter()
1703                        .map(|pattern| {
1704                            let p_type = pattern.get_type(self);
1705                            Ok(p_type)
1706                        })
1707                        .collect::<Result<_>>()?,
1708                ));
1709
1710                self.unify(pattern, &tuple_type, ctx)
1711                    .expect("Unification of new_generic with tuple type cannot fail");
1712            }
1713            hir::PatternKind::Array(inner) => {
1714                for pattern in inner {
1715                    self.visit_pattern(pattern, ctx, generic_list)?;
1716                }
1717                if inner.len() == 0 {
1718                    return Err(
1719                        Diagnostic::error(pattern, "Empty array patterns are unsupported")
1720                            .primary_label("Empty array pattern"),
1721                    );
1722                } else {
1723                    let inner_t = inner[0].get_type(self);
1724
1725                    for pattern in inner.iter().skip(1) {
1726                        self.unify(pattern, &inner_t, ctx)
1727                            .into_default_diagnostic(pattern, self)?;
1728                    }
1729
1730                    pattern
1731                        .unify_with(
1732                            &TypeVar::Known(
1733                                pattern.loc(),
1734                                KnownType::Array,
1735                                vec![
1736                                    inner_t,
1737                                    self.add_type_var(TypeVar::Known(
1738                                        pattern.loc(),
1739                                        KnownType::Integer(inner.len().to_bigint()),
1740                                        vec![],
1741                                    )),
1742                                ],
1743                            )
1744                            .insert(self),
1745                            self,
1746                        )
1747                        .commit(self, ctx)
1748                        .into_default_diagnostic(pattern, self)?;
1749                }
1750            }
1751            hir::PatternKind::Type(name, args) => {
1752                let (condition_type, params, generic_list) =
1753                    match ctx.symtab.patternable_type_by_id(name).inner {
1754                        Patternable {
1755                            kind: PatternableKind::Enum,
1756                            params: _,
1757                        } => {
1758                            let enum_variant = ctx.symtab.enum_variant_by_id(name).inner;
1759                            let generic_list = self.create_generic_list(
1760                                GenericListSource::Anonymous,
1761                                &enum_variant.type_params,
1762                                &[],
1763                                None,
1764                                &[],
1765                            )?;
1766
1767                            let condition_type = self.type_var_from_hir(
1768                                pattern.loc(),
1769                                &enum_variant.output_type,
1770                                &generic_list,
1771                            )?;
1772
1773                            (condition_type, enum_variant.params, generic_list)
1774                        }
1775                        Patternable {
1776                            kind: PatternableKind::Struct,
1777                            params: _,
1778                        } => {
1779                            let s = ctx.symtab.struct_by_id(name).inner;
1780                            let generic_list = self.create_generic_list(
1781                                GenericListSource::Anonymous,
1782                                &s.type_params,
1783                                &[],
1784                                None,
1785                                &[],
1786                            )?;
1787
1788                            let condition_type =
1789                                self.type_var_from_hir(pattern.loc(), &s.self_type, &generic_list)?;
1790
1791                            (condition_type, s.params, generic_list)
1792                        }
1793                    };
1794
1795                self.unify(pattern, &condition_type, ctx)
1796                    .expect("Unification of new_generic with enum cannot fail");
1797
1798                for (
1799                    PatternArgument {
1800                        target,
1801                        value: pattern,
1802                        kind,
1803                    },
1804                    Parameter {
1805                        name: _,
1806                        ty: target_type,
1807                        no_mangle: _,
1808                        field_translator: _,
1809                    },
1810                ) in args.iter().zip(params.0.iter())
1811                {
1812                    self.visit_pattern(pattern, ctx, &generic_list)?;
1813                    let target_type =
1814                        self.type_var_from_hir(target_type.loc(), target_type, &generic_list)?;
1815
1816                    let loc = match kind {
1817                        hir::ArgumentKind::Positional => pattern.loc(),
1818                        hir::ArgumentKind::Named => pattern.loc(),
1819                        hir::ArgumentKind::ShortNamed => target.loc(),
1820                    };
1821
1822                    self.unify(pattern, &target_type, ctx).into_diagnostic(
1823                        loc,
1824                        |d, tm| {
1825                            let (expected, got) = tm.display_e_g(self);
1826                            d.message(format!(
1827                                "Argument type mismatch. Expected {expected} got {got}"
1828                            ))
1829                            .primary_label(format!("expected {expected}"))
1830                        },
1831                        self,
1832                    )?;
1833                }
1834            }
1835        }
1836        Ok(())
1837    }
1838
1839    #[trace_typechecker]
1840    pub fn visit_wal_trace(
1841        &mut self,
1842        trace: &Loc<WalTrace>,
1843        ctx: &Context,
1844        generic_list: &GenericListToken,
1845    ) -> Result<()> {
1846        let WalTrace { clk, rst } = &trace.inner;
1847        clk.as_ref()
1848            .map(|x| {
1849                self.visit_expression(x, ctx, generic_list);
1850                x.unify_with(&self.t_clock(trace.loc(), ctx.symtab), self)
1851                    .commit(self, ctx)
1852                    .into_default_diagnostic(x, self)
1853            })
1854            .transpose()?;
1855        rst.as_ref()
1856            .map(|x| {
1857                self.visit_expression(x, ctx, generic_list);
1858                x.unify_with(&self.t_bool(trace.loc(), ctx.symtab), self)
1859                    .commit(self, ctx)
1860                    .into_default_diagnostic(x, self)
1861            })
1862            .transpose()?;
1863        Ok(())
1864    }
1865
1866    #[trace_typechecker]
1867    pub fn visit_statement_error(
1868        &mut self,
1869        stmt: &Loc<Statement>,
1870        ctx: &Context,
1871        generic_list: &GenericListToken,
1872    ) -> Result<()> {
1873        match &stmt.inner {
1874            Statement::Error => {
1875                if let Some(current_stage_depth) = self
1876                    .owned
1877                    .pipeline_state
1878                    .as_ref()
1879                    .map(|s| s.current_stage_depth)
1880                {
1881                    current_stage_depth
1882                        .unify_with(&self.t_err(stmt.loc()), self)
1883                        .commit(self, ctx)
1884                        .unwrap();
1885                }
1886                Ok(())
1887            }
1888            Statement::Binding(Binding {
1889                pattern,
1890                ty,
1891                value,
1892                wal_trace,
1893            }) => {
1894                trace!("Visiting `let {} = ..`", pattern.kind);
1895                self.visit_expression(value, ctx, generic_list);
1896
1897                self.visit_pattern(pattern, ctx, generic_list)
1898                    .handle_in(&mut self.owned.diags);
1899
1900                self.unify(&TypedExpression::Id(pattern.id), value, ctx)
1901                    .into_diagnostic(
1902                        pattern.loc(),
1903                        error_pattern_type_mismatch(
1904                            ty.as_ref().map(|t| t.loc()).unwrap_or_else(|| value.loc()),
1905                            self,
1906                        ),
1907                        self,
1908                    )
1909                    .handle_in(&mut self.owned.diags);
1910
1911                if let Some(t) = ty {
1912                    let tvar = self.type_var_from_hir(t.loc(), t, generic_list)?;
1913                    self.unify(&TypedExpression::Id(pattern.id), &tvar, ctx)
1914                        .into_default_diagnostic(value.loc(), self)
1915                        .handle_in(&mut self.owned.diags);
1916                }
1917
1918                wal_trace
1919                    .as_ref()
1920                    .map(|wt| self.visit_wal_trace(wt, ctx, generic_list))
1921                    .transpose()
1922                    .handle_in(&mut self.owned.diags);
1923
1924                Ok(())
1925            }
1926            Statement::Expression(expr) => {
1927                self.visit_expression(expr, ctx, generic_list);
1928                Ok(())
1929            }
1930            Statement::Register(reg) => self.visit_register(reg, ctx, generic_list),
1931            Statement::Declaration(names) => {
1932                for name in names {
1933                    let new_type = self.new_generic_type(name.loc());
1934                    self.add_equation(TypedExpression::Name(name.clone().inner), new_type);
1935                }
1936                Ok(())
1937            }
1938            Statement::PipelineRegMarker(extra) => {
1939                match extra {
1940                    Some(PipelineRegMarkerExtra::Condition(cond)) => {
1941                        self.visit_expression(cond, ctx, generic_list);
1942                        cond.unify_with(&self.t_bool(cond.loc(), ctx.symtab), self)
1943                            .commit(self, ctx)
1944                            .into_default_diagnostic(cond, self)?;
1945                    }
1946                    Some(PipelineRegMarkerExtra::Count {
1947                        count: _,
1948                        count_typeexpr_id: _,
1949                    }) => {}
1950                    None => {}
1951                }
1952
1953                let current_stage_depth = self
1954                    .owned
1955                    .pipeline_state
1956                    .clone()
1957                    .ok_or_else(|| {
1958                        diag_anyhow!(stmt, "Found a pipeline reg marker in a non-pipeline")
1959                    })?
1960                    .current_stage_depth;
1961
1962                let new_depth = self.new_generic_tlint(stmt.loc());
1963                let offset = match extra {
1964                    Some(PipelineRegMarkerExtra::Count {
1965                        count,
1966                        count_typeexpr_id,
1967                    }) => {
1968                        let var = self.hir_type_expr_to_var(count, generic_list)?;
1969                        self.add_equation(TypedExpression::Id(*count_typeexpr_id), var.clone());
1970                        var
1971                    }
1972                    Some(PipelineRegMarkerExtra::Condition(_)) | None => self.add_type_var(
1973                        TypeVar::Known(stmt.loc(), KnownType::Integer(1.to_bigint()), vec![]),
1974                    ),
1975                };
1976
1977                let total_depth = ConstraintExpr::Sum(
1978                    Box::new(ConstraintExpr::Var(offset)),
1979                    Box::new(ConstraintExpr::Var(current_stage_depth)),
1980                );
1981                self.owned
1982                    .pipeline_state
1983                    .as_mut()
1984                    .expect("Expected to have a pipeline state")
1985                    .current_stage_depth = new_depth.clone();
1986
1987                self.add_constraint(
1988                    new_depth.clone(),
1989                    total_depth,
1990                    stmt.loc(),
1991                    &new_depth,
1992                    ConstraintSource::PipelineRegCount {
1993                        reg: stmt.loc(),
1994                        total: self.get_pipeline_state(stmt)?.total_depth.loc(),
1995                    },
1996                );
1997
1998                Ok(())
1999            }
2000            Statement::Label(name) => {
2001                let key = TypedExpression::Name(name.inner.clone());
2002                let var = if !self.owned.equations.contains_key(&key) {
2003                    let var = self.new_generic_tlint(name.loc());
2004                    self.owned.trace_stack.push(|| {
2005                        TraceStackEntry::AddingPipelineLabel(
2006                            name.inner.clone(),
2007                            var.debug_resolve(self),
2008                        )
2009                    });
2010                    self.add_equation(key.clone(), var.clone());
2011                    var
2012                } else {
2013                    let var = self.owned.equations.get(&key).unwrap().clone();
2014                    self.owned.trace_stack.push(|| {
2015                        TraceStackEntry::RecoveringPipelineLabel(
2016                            name.inner.clone(),
2017                            var.debug_resolve(self),
2018                        )
2019                    });
2020                    var
2021                };
2022                // Safe unwrap, unifying with a fresh var
2023                self.unify(
2024                    &var,
2025                    &self.get_pipeline_state(name)?.current_stage_depth.clone(),
2026                    ctx,
2027                )
2028                .unwrap();
2029                Ok(())
2030            }
2031            Statement::WalSuffixed { .. } => Ok(()),
2032            Statement::Assert(expr) => {
2033                self.visit_expression(expr, ctx, generic_list);
2034
2035                expr.unify_with(&self.t_bool(stmt.loc(), ctx.symtab), self)
2036                    .commit(self, ctx)
2037                    .into_default_diagnostic(expr, self)
2038                    .handle_in(&mut self.owned.diags);
2039                Ok(())
2040            }
2041            Statement::Set { target, value } => {
2042                self.visit_expression(target, ctx, generic_list);
2043                self.visit_expression(value, ctx, generic_list);
2044
2045                let inner_type = self.new_generic_type(value.loc());
2046                let outer_type = TypeVar::inverted(stmt.loc(), inner_type.clone()).insert(self);
2047                self.unify_expression_generic_error(target, &outer_type, ctx)
2048                    .handle_in(&mut self.owned.diags);
2049                self.unify_expression_generic_error(value, &inner_type, ctx)
2050                    .handle_in(&mut self.owned.diags);
2051
2052                Ok(())
2053            }
2054        }
2055    }
2056
2057    pub fn visit_statement(
2058        &mut self,
2059        stmt: &Loc<Statement>,
2060        ctx: &Context,
2061        generic_list: &GenericListToken,
2062    ) {
2063        if let Err(e) = self.visit_statement_error(stmt, ctx, generic_list) {
2064            self.owned.diags.errors.push(e);
2065        }
2066    }
2067
2068    #[trace_typechecker]
2069    pub fn visit_register(
2070        &mut self,
2071        reg: &Register,
2072        ctx: &Context,
2073        generic_list: &GenericListToken,
2074    ) -> Result<()> {
2075        self.visit_pattern(&reg.pattern, ctx, generic_list)?;
2076
2077        let type_spec_type = match &reg.value_type {
2078            Some(t) => Some(self.type_var_from_hir(t.loc(), t, generic_list)?.at_loc(t)),
2079            None => None,
2080        };
2081
2082        // We need to do this before visiting value, in case it constrains the
2083        // type of the identifiers in the pattern
2084        if let Some(tvar) = &type_spec_type {
2085            self.unify(&TypedExpression::Id(reg.pattern.id), tvar, ctx)
2086                .into_diagnostic_no_expected_source(
2087                    reg.pattern.loc(),
2088                    error_pattern_type_mismatch(tvar.loc(), self),
2089                    self,
2090                )?;
2091        }
2092
2093        self.visit_expression(&reg.clock, ctx, generic_list);
2094        self.visit_expression(&reg.value, ctx, generic_list);
2095
2096        if let Some(tvar) = &type_spec_type {
2097            self.unify(&reg.value, tvar, ctx)
2098                .into_default_diagnostic(reg.value.loc(), self)?;
2099        }
2100
2101        if let Some((rst_cond, rst_value)) = &reg.reset {
2102            self.visit_expression(rst_cond, ctx, generic_list);
2103            self.visit_expression(rst_value, ctx, generic_list);
2104            // Ensure cond is a boolean
2105            rst_cond
2106                .unify_with(&self.t_bool(rst_cond.loc(), ctx.symtab), self)
2107                .commit(self, ctx)
2108                .into_diagnostic(
2109                    rst_cond.loc(),
2110                    |diag,
2111                     Tm {
2112                         g: got,
2113                         e: _expected,
2114                     }| {
2115                        diag.message(format!(
2116                            "Register reset condition must be a bool, got {got}",
2117                            got = got.display(self)
2118                        ))
2119                        .primary_label("expected bool")
2120                    },
2121                    self,
2122                )?;
2123
2124            // Ensure the reset value has the same type as the register itself
2125            self.unify(&rst_value.inner, &reg.value.inner, ctx)
2126                .into_diagnostic(
2127                    rst_value.loc(),
2128                    |diag, tm| {
2129                        let (expected, got) = tm.display_e_g(self);
2130                        diag.message(format!(
2131                            "Register reset value mismatch. Expected {expected} got {got}"
2132                        ))
2133                        .primary_label(format!("expected {expected}"))
2134                        .secondary_label(&reg.pattern, format!("because this has type {expected}"))
2135                    },
2136                    self,
2137                )?;
2138        }
2139
2140        if let Some(initial) = &reg.initial {
2141            self.visit_expression(initial, ctx, generic_list);
2142
2143            self.unify(&initial.inner, &reg.value.inner, ctx)
2144                .into_diagnostic(
2145                    initial.loc(),
2146                    |diag, tm| {
2147                        let (expected, got) = tm.display_e_g(self);
2148                        diag.message(format!(
2149                            "Register initial value mismatch. Expected {expected} got {got}"
2150                        ))
2151                        .primary_label(format!("expected {expected}, got {got}"))
2152                        .secondary_label(&reg.pattern, format!("because this has type {got}"))
2153                    },
2154                    self,
2155                )?;
2156        }
2157
2158        reg.clock
2159            .unify_with(&self.t_clock(reg.clock.loc(), ctx.symtab), self)
2160            .commit(self, ctx)
2161            .into_diagnostic(
2162                reg.clock.loc(),
2163                |diag,
2164                 Tm {
2165                     g: got,
2166                     e: _expected,
2167                 }| {
2168                    diag.message(format!(
2169                        "Expected clock, got {got}",
2170                        got = got.display(self)
2171                    ))
2172                    .primary_label("expected clock")
2173                },
2174                self,
2175            )?;
2176
2177        self.unify(&TypedExpression::Id(reg.pattern.id), &reg.value, ctx)
2178            .into_diagnostic(
2179                reg.pattern.loc(),
2180                error_pattern_type_mismatch(reg.value.loc(), self),
2181                self,
2182            )?;
2183
2184        Ok(())
2185    }
2186
2187    #[trace_typechecker]
2188    pub fn visit_trait_spec(
2189        &mut self,
2190        trait_spec: &Loc<TraitSpec>,
2191        generic_list: &GenericListToken,
2192    ) -> Result<Loc<TraitReq>> {
2193        let type_params = if let Some(type_params) = &trait_spec.inner.type_params {
2194            type_params
2195                .inner
2196                .iter()
2197                .map(|te| self.hir_type_expr_to_var(te, generic_list))
2198                .collect::<Result<_>>()?
2199        } else {
2200            vec![]
2201        };
2202
2203        Ok(TraitReq {
2204            name: trait_spec.name.clone(),
2205            type_params,
2206        }
2207        .at_loc(trait_spec))
2208    }
2209
2210    #[trace_typechecker]
2211    pub fn visit_trait_bounds(
2212        &mut self,
2213        target: &Loc<NameID>,
2214        traits: &[Loc<TraitSpec>],
2215        generic_list_tok: &GenericListToken,
2216    ) -> Result<()> {
2217        let trait_reqs = traits
2218            .iter()
2219            .map(|spec| self.visit_trait_spec(spec, generic_list_tok))
2220            .collect::<Result<BTreeSet<_>>>()?
2221            .into_iter()
2222            .collect_vec();
2223
2224        if !trait_reqs.is_empty() {
2225            let trait_list = TraitList::from_vec(trait_reqs);
2226
2227            let generic_list = self.get_generic_list(generic_list_tok).ok_or_else(|| {
2228                diag_anyhow!(
2229                    target,
2230                    "Did not have a generic list when visiting trait bounds"
2231                )
2232            })?;
2233
2234            let Some(tvar) = generic_list.get(&target.inner) else {
2235                return Err(Diagnostic::bug(
2236                    target,
2237                    "Couldn't find generic from where clause in generic list",
2238                )
2239                .primary_label(format!(
2240                    "Generic type {} not found in generic list",
2241                    target.inner
2242                )));
2243            };
2244
2245            self.owned.trace_stack.push(|| {
2246                TraceStackEntry::AddingTraitBounds(tvar.debug_resolve(self), trait_list.clone())
2247            });
2248
2249            match tvar.resolve(self) {
2250                TypeVar::Known(_, _, _) => {
2251                    // NOTE: This branch is a no-op as it is only triggered when re-visiting
2252                    // units for typeinference during monomorpization, a process which replaces
2253                    // some unknown types with known counterparts.
2254                    // Ideally, we'd re-run ensure_impls here but that requires a context which
2255                    // isn't necessarily available here, so #yolo
2256                }
2257                TypeVar::Unknown(loc, id, old_trait_list, _meta_type) => {
2258                    let new_tvar = self.add_type_var(TypeVar::Unknown(
2259                        loc,
2260                        id,
2261                        old_trait_list.clone().extend(trait_list),
2262                        MetaType::Type,
2263                    ));
2264
2265                    trace!(
2266                        "Adding trait bound {} on type {}",
2267                        new_tvar.display_with_meta(true, self),
2268                        target.inner
2269                    );
2270
2271                    self.modify_generic_list(generic_list_tok, |generic_list| {
2272                        generic_list.insert(target.inner.clone(), new_tvar);
2273                    });
2274                }
2275            }
2276        }
2277
2278        Ok(())
2279    }
2280
2281    pub fn visit_const_generic_with_id(
2282        &mut self,
2283        gen: &Loc<ConstGenericWithId>,
2284        generic_list_token: &GenericListToken,
2285        constraint_source: ConstraintSource,
2286        ctx: &Context,
2287    ) -> Result<TypeVarID> {
2288        let var = match &gen.inner.inner {
2289            ConstGeneric::Name(name) => {
2290                let ty = &ctx.symtab.type_symbol_by_id(&name);
2291                match &ty.inner {
2292                    TypeSymbol::Declared(_, _) => {
2293                        return Err(Diagnostic::error(
2294                            name,
2295                            "{type_decl_kind} cannot be used in a const generic expression",
2296                        )
2297                        .primary_label("Type in  const generic")
2298                        .secondary_label(ty, "{name} is declared here"))
2299                    }
2300                    TypeSymbol::GenericArg { .. } | TypeSymbol::GenericMeta(MetaType::Type) => {
2301                        return Err(Diagnostic::error(
2302                            name,
2303                            "Generic types cannot be used in const generic expressions",
2304                        )
2305                        .primary_label("Type in  const generic")
2306                        .secondary_label(ty, "{name} is declared here")
2307                        .span_suggest_insert_before(
2308                            "Consider making this a value",
2309                            ty.loc(),
2310                            "#uint ",
2311                        ))
2312                    }
2313                    TypeSymbol::GenericMeta(MetaType::Number) => {
2314                        self.new_generic_tlnumber(gen.loc())
2315                    }
2316                    TypeSymbol::GenericMeta(MetaType::Int) => self.new_generic_tlint(gen.loc()),
2317                    TypeSymbol::GenericMeta(MetaType::Uint) => self.new_generic_tluint(gen.loc()),
2318                    TypeSymbol::GenericMeta(MetaType::Bool) => self.new_generic_tlbool(gen.loc()),
2319                    TypeSymbol::GenericMeta(MetaType::Str) => self.new_generic_tlstr(gen.loc()),
2320                    TypeSymbol::GenericMeta(MetaType::Any) => {
2321                        diag_bail!(gen, "Found any meta type")
2322                    }
2323                    TypeSymbol::Alias(_) => {
2324                        return Err(Diagnostic::error(
2325                            gen,
2326                            "Aliases are not currently supported in const generics",
2327                        )
2328                        .secondary_label(ty, "Alias defined here"))
2329                    }
2330                }
2331            }
2332            ConstGeneric::Int(_)
2333            | ConstGeneric::Add(_, _)
2334            | ConstGeneric::Sub(_, _)
2335            | ConstGeneric::Mul(_, _)
2336            | ConstGeneric::Div(_, _)
2337            | ConstGeneric::Mod(_, _)
2338            | ConstGeneric::UintBitsToFit(_) => self.new_generic_tlnumber(gen.loc()),
2339            ConstGeneric::Str(_) => self.new_generic_tlstr(gen.loc()),
2340            ConstGeneric::Eq(_, _) | ConstGeneric::NotEq(_, _) => {
2341                self.new_generic_tlbool(gen.loc())
2342            }
2343        };
2344        let constraint = self.visit_const_generic(&gen.inner.inner, generic_list_token)?;
2345        self.add_equation(TypedExpression::Id(gen.id), var.clone());
2346        self.add_constraint(var.clone(), constraint, gen.loc(), &var, constraint_source);
2347        Ok(var)
2348    }
2349
2350    #[trace_typechecker]
2351    pub fn visit_const_generic(
2352        &self,
2353        constraint: &ConstGeneric,
2354        generic_list: &GenericListToken,
2355    ) -> Result<ConstraintExpr> {
2356        let wrap = |lhs,
2357                    rhs,
2358                    wrapper: fn(Box<ConstraintExpr>, Box<ConstraintExpr>) -> ConstraintExpr|
2359         -> Result<_> {
2360            Ok(wrapper(
2361                Box::new(self.visit_const_generic(lhs, generic_list)?),
2362                Box::new(self.visit_const_generic(rhs, generic_list)?),
2363            ))
2364        };
2365        let constraint = match constraint {
2366            ConstGeneric::Name(n) => {
2367                let gl = self
2368                    .get_generic_list(generic_list)
2369                    .ok_or_else(|| diag_anyhow!(n, "Found no generic list"))?;
2370                let var = gl.get(n).ok_or_else(|| {
2371                    Diagnostic::bug(n, "Found non-generic argument in where clause")
2372                })?;
2373                ConstraintExpr::Var(*var)
2374            }
2375            ConstGeneric::Int(val) => ConstraintExpr::Integer(val.clone()),
2376            ConstGeneric::Str(val) => ConstraintExpr::String(val.clone()),
2377            ConstGeneric::Add(lhs, rhs) => wrap(lhs, rhs, ConstraintExpr::Sum)?,
2378            ConstGeneric::Sub(lhs, rhs) => wrap(lhs, rhs, ConstraintExpr::Difference)?,
2379            ConstGeneric::Mul(lhs, rhs) => wrap(lhs, rhs, ConstraintExpr::Product)?,
2380            ConstGeneric::Div(lhs, rhs) => wrap(lhs, rhs, ConstraintExpr::Div)?,
2381            ConstGeneric::Mod(lhs, rhs) => wrap(lhs, rhs, ConstraintExpr::Mod)?,
2382            ConstGeneric::Eq(lhs, rhs) => wrap(lhs, rhs, ConstraintExpr::Eq)?,
2383            ConstGeneric::NotEq(lhs, rhs) => wrap(lhs, rhs, ConstraintExpr::NotEq)?,
2384            ConstGeneric::UintBitsToFit(a) => ConstraintExpr::UintBitsToRepresent(Box::new(
2385                self.visit_const_generic(a, generic_list)?,
2386            )),
2387        };
2388        Ok(constraint)
2389    }
2390}
2391
2392impl spade_common::sizes::SerializedSize for OwnedTypeState {
2393    fn accumulate_size(
2394        &self,
2395        field: &[&'static str],
2396        into: &mut FxHashMap<Vec<&'static str>, usize>,
2397    ) {
2398        let Self {
2399            key,
2400            keys,
2401            equations,
2402            constraints,
2403            requirements: _,
2404            replacements,
2405            checkpoints: _,
2406            pipeline_state,
2407            error_type,
2408            trace_stack: _,
2409            diags: _,
2410            generic_lists,
2411        } = self;
2412
2413        spade_common::sizes::add_field(field, "key", key, into);
2414        spade_common::sizes::add_field(field, "keys", keys, into);
2415        spade_common::sizes::add_field(field, "equations", equations, into);
2416        spade_common::sizes::add_field(field, "constraints", constraints, into);
2417        spade_common::sizes::add_field(field, "replacements", replacements, into);
2418        spade_common::sizes::add_field(field, "pipeline_state", pipeline_state, into);
2419        spade_common::sizes::add_field(field, "error_type", error_type, into);
2420        spade_common::sizes::add_field(field, "generic_lists", generic_lists, into);
2421    }
2422}
2423
2424// Private helper functions
2425impl TypeState {
2426    fn new_typeid(&self) -> u64 {
2427        self.shared
2428            .next_typeid
2429            .fetch_add(1, std::sync::atomic::Ordering::Relaxed)
2430    }
2431
2432    pub fn add_equation(&mut self, expression: TypedExpression, var: TypeVarID) {
2433        self.owned
2434            .trace_stack
2435            .push(|| TraceStackEntry::AddingEquation(expression.clone(), var.debug_resolve(self)));
2436        if let Some(prev) = self.owned.equations.insert(expression.clone(), var.clone()) {
2437            let var = var.clone();
2438            let expr = expression.clone();
2439            println!("{}", format_trace_stack(self));
2440            panic!("Adding equation for {} == {} but a previous eq exists.\n\tIt was previously bound to {}", expr, var.debug_resolve(self), prev.debug_resolve(self))
2441        }
2442    }
2443
2444    fn add_constraint(
2445        &mut self,
2446        lhs: TypeVarID,
2447        rhs: ConstraintExpr,
2448        loc: Loc<()>,
2449        inside: &TypeVarID,
2450        source: ConstraintSource,
2451    ) {
2452        let replaces = lhs.clone();
2453        let rhs = rhs.with_context(&replaces, &inside, source).at_loc(&loc);
2454
2455        self.owned
2456            .trace_stack
2457            .push(|| TraceStackEntry::AddingConstraint(lhs.debug_resolve(self), rhs.inner.clone()));
2458
2459        self.owned.constraints.add_int_constraint(lhs, rhs);
2460    }
2461
2462    fn add_requirement(&mut self, requirement: Requirement) {
2463        self.owned
2464            .trace_stack
2465            .push(|| TraceStackEntry::AddRequirement(requirement.clone()));
2466        self.owned.requirements.push(requirement)
2467    }
2468
2469    /// Performs unification but does not update constraints. This is done to avoid
2470    /// updating constraints more often than necessary. Technically, constraints can
2471    /// be updated even less often, but `unify` is a pretty natural point to do so.
2472
2473    fn unify_inner(
2474        &mut self,
2475        e1: &impl HasType,
2476        e2: &impl HasType,
2477        ctx: &Context,
2478    ) -> std::result::Result<TypeVarID, UnificationError> {
2479        let v1 = e1.get_type(self);
2480        let v2 = e2.get_type(self);
2481
2482        trace!(
2483            "Unifying {} with {}",
2484            v1.debug_resolve(self),
2485            v2.debug_resolve(self)
2486        );
2487
2488        self.owned
2489            .trace_stack
2490            .push(|| TraceStackEntry::TryingUnify(v1.debug_resolve(self), v2.debug_resolve(self)));
2491
2492        macro_rules! err_producer {
2493            () => {{
2494                self.owned
2495                    .trace_stack
2496                    .push(|| TraceStackEntry::Message("Produced error".to_string()));
2497                UnificationError::Normal(Tm {
2498                    g: UnificationTrace::new(v1),
2499                    e: UnificationTrace::new(v2),
2500                })
2501            }};
2502        }
2503        macro_rules! meta_err_producer {
2504            () => {{
2505                self.owned
2506                    .trace_stack
2507                    .push(|| TraceStackEntry::Message("Produced error".to_string()));
2508                UnificationError::MetaMismatch(Tm {
2509                    g: UnificationTrace::new(v1),
2510                    e: UnificationTrace::new(v2),
2511                })
2512            }};
2513        }
2514
2515        macro_rules! unify_if {
2516            ($condition:expr, $new_type:expr, $replaced_type:expr) => {
2517                if $condition {
2518                    Ok(($new_type, $replaced_type))
2519                } else {
2520                    Err(err_producer!())
2521                }
2522            };
2523        }
2524
2525        let unify_params = |s: &mut Self,
2526                            p1: &[TypeVarID],
2527                            p2: &[TypeVarID]|
2528         -> std::result::Result<(), UnificationError> {
2529            if p1.len() != p2.len() {
2530                return Err({
2531                    s.owned
2532                        .trace_stack
2533                        .push(|| TraceStackEntry::Message("Produced error".to_string()));
2534                    UnificationError::Normal(Tm {
2535                        g: UnificationTrace::new(v1),
2536                        e: UnificationTrace::new(v2),
2537                    })
2538                });
2539            }
2540
2541            for (t1, t2) in p1.iter().zip(p2.iter()) {
2542                match s.unify_inner(t1, t2, ctx) {
2543                    Ok(result) => result,
2544                    Err(e) => {
2545                        s.owned
2546                            .trace_stack
2547                            .push(|| TraceStackEntry::Message("Adding context".to_string()));
2548                        return Err(e).add_context(v1.clone(), v2.clone());
2549                    }
2550                };
2551            }
2552            Ok(())
2553        };
2554
2555        // Figure out the most general type, and take note if we need to
2556        // do any replacement of the types in the rest of the state
2557        let result = match (
2558            &(v1, v1.resolve(self).clone()),
2559            &(v2, v2.resolve(self).clone()),
2560        ) {
2561            ((_, TypeVar::Known(_, KnownType::Error, _)), _) => Ok((v1, vec![v2])),
2562            (_, (_, TypeVar::Known(_, KnownType::Error, _))) => Ok((v2, vec![v1])),
2563            ((_, TypeVar::Known(_, t1, p1)), (_, TypeVar::Known(_, t2, p2))) => {
2564                match (t1, t2) {
2565                    (KnownType::Integer(val1), KnownType::Integer(val2)) => {
2566                        // NOTE: We get better error messages if we don't actually
2567                        // replace v1 with v2. Not entirely sure why, but since they already
2568                        // have the same known type, we're fine. The same applies
2569                        // to all known types
2570                        unify_if!(val1 == val2, v1, vec![])
2571                    }
2572                    (KnownType::String(val1), KnownType::String(val2)) => {
2573                        // Copied from the (Integer, Integer) case, its remark may also apply
2574                        unify_if!(val1 == val2, v1, vec![])
2575                    }
2576                    (KnownType::Named(n1), KnownType::Named(n2)) => {
2577                        match (
2578                            &ctx.symtab.type_symbol_by_id(n1).inner,
2579                            &ctx.symtab.type_symbol_by_id(n2).inner,
2580                        ) {
2581                            (TypeSymbol::Declared(_, _), TypeSymbol::Declared(_, _)) => {
2582                                if n1 != n2 {
2583                                    return Err(err_producer!());
2584                                }
2585
2586                                let new_ts1 = ctx.symtab.type_symbol_by_id(n1).inner;
2587                                let new_ts2 = ctx.symtab.type_symbol_by_id(n2).inner;
2588                                unify_params(self, &p1, &p2)?;
2589                                unify_if!(new_ts1 == new_ts2, v1, vec![])
2590                            }
2591                            (TypeSymbol::Declared(_, _), TypeSymbol::GenericArg { traits }) => {
2592                                if !traits.is_empty() {
2593                                    todo!("Implement trait unifictaion");
2594                                }
2595                                Ok((v1, vec![]))
2596                            }
2597                            (TypeSymbol::GenericArg { traits }, TypeSymbol::Declared(_, _)) => {
2598                                if !traits.is_empty() {
2599                                    todo!("Implement trait unifictaion");
2600                                }
2601                                Ok((v2, vec![]))
2602                            }
2603                            (
2604                                TypeSymbol::GenericArg { traits: ltraits },
2605                                TypeSymbol::GenericArg { traits: rtraits },
2606                            ) => {
2607                                if !ltraits.is_empty() || !rtraits.is_empty() {
2608                                    todo!("Implement trait unifictaion");
2609                                }
2610                                Ok((v1, vec![]))
2611                            }
2612                            (TypeSymbol::Declared(_, _), TypeSymbol::GenericMeta(_)) => todo!(),
2613                            (TypeSymbol::GenericArg { traits: _ }, TypeSymbol::GenericMeta(_)) => {
2614                                todo!()
2615                            }
2616                            (TypeSymbol::GenericMeta(_), TypeSymbol::Declared(_, _)) => todo!(),
2617                            (TypeSymbol::GenericMeta(_), TypeSymbol::GenericArg { traits: _ }) => {
2618                                todo!()
2619                            }
2620                            (TypeSymbol::Alias(_), _) | (_, TypeSymbol::Alias(_)) => {
2621                                return Err(UnificationError::Specific(Diagnostic::bug(
2622                                    ().nowhere(),
2623                                    "Encountered a raw type alias during unification",
2624                                )))
2625                            }
2626                            (TypeSymbol::GenericMeta(_), TypeSymbol::GenericMeta(_)) => todo!(),
2627                        }
2628                    }
2629                    (KnownType::Array, KnownType::Array)
2630                    | (KnownType::Tuple, KnownType::Tuple)
2631                    | (KnownType::Wire, KnownType::Wire)
2632                    | (KnownType::Inverted, KnownType::Inverted) => {
2633                        // Note, replacements should only occur when a variable goes from Unknown
2634                        // to Known, not when the base is the same. Replacements take care
2635                        // of parameters. Therefore, None is returned here
2636                        unify_params(self, &p1, &p2)?;
2637                        Ok((v1, vec![]))
2638                    }
2639                    (_, _) => Err(err_producer!()),
2640                }
2641            }
2642            // Unknown with unknown requires merging traits
2643            (
2644                (_, TypeVar::Unknown(loc1, _, traits1, meta1)),
2645                (_, TypeVar::Unknown(loc2, _, traits2, meta2)),
2646            ) => {
2647                let new_loc = if meta1.is_more_concrete_than(meta2) {
2648                    loc1
2649                } else {
2650                    loc2
2651                };
2652                let new_t = match unify_meta(meta1, meta2) {
2653                    Some(meta @ MetaType::Any) => {
2654                        if traits1.inner.is_empty() || traits2.inner.is_empty() {
2655                            return Err(UnificationError::Specific(diag_anyhow!(
2656                                new_loc,
2657                                "Inferred an any meta-type with traits"
2658                            )));
2659                        }
2660                        self.new_generic_with_meta(*loc1, meta)
2661                    }
2662                    Some(MetaType::Type) => {
2663                        let new_trait_names = traits1
2664                            .inner
2665                            .iter()
2666                            .chain(traits2.inner.iter())
2667                            .map(|t| t.name.clone())
2668                            .collect::<BTreeSet<_>>()
2669                            .into_iter()
2670                            .collect::<Vec<_>>();
2671
2672                        let new_traits = new_trait_names
2673                            .iter()
2674                            .map(
2675                                |name| match (traits1.get_trait(name), traits2.get_trait(name)) {
2676                                    (Some(req1), Some(req2)) => {
2677                                        let new_params = req1
2678                                            .inner
2679                                            .type_params
2680                                            .iter()
2681                                            .zip(req2.inner.type_params.iter())
2682                                            .map(|(p1, p2)| self.unify(p1, p2, ctx))
2683                                            .collect::<std::result::Result<_, UnificationError>>(
2684                                            )?;
2685
2686                                        Ok(TraitReq {
2687                                            name: name.clone(),
2688                                            type_params: new_params,
2689                                        }
2690                                        .at_loc(req1))
2691                                    }
2692                                    (Some(t), None) => Ok(t.clone()),
2693                                    (None, Some(t)) => Ok(t.clone()),
2694                                    (None, None) => panic!("Found a trait but neither side has it"),
2695                                },
2696                            )
2697                            .collect::<std::result::Result<Vec<_>, UnificationError>>()?;
2698
2699                        self.new_generic_with_traits(*new_loc, TraitList::from_vec(new_traits))
2700                    }
2701                    Some(MetaType::Number) => self.new_generic_tlnumber(*new_loc),
2702                    Some(MetaType::Int) => self.new_generic_tlint(*new_loc),
2703                    Some(MetaType::Uint) => self.new_generic_tluint(*new_loc),
2704                    Some(MetaType::Bool) => self.new_generic_tlbool(*new_loc),
2705                    Some(MetaType::Str) => self.new_generic_tlstr(*new_loc),
2706                    None => return Err(meta_err_producer!()),
2707                };
2708                Ok((new_t, vec![v1, v2]))
2709            }
2710            (
2711                (otherid, TypeVar::Known(loc, base, params)),
2712                (ukid, TypeVar::Unknown(ukloc, _, traits, meta)),
2713            )
2714            | (
2715                (ukid, TypeVar::Unknown(ukloc, _, traits, meta)),
2716                (otherid, TypeVar::Known(loc, base, params)),
2717            ) => {
2718                let trait_is_expected = match (&v1.resolve(self), &v2.resolve(self)) {
2719                    (TypeVar::Known(_, _, _), _) => true,
2720                    _ => false,
2721                };
2722
2723                let impls = self.ensure_impls(otherid, traits, trait_is_expected, ukloc, ctx)?;
2724
2725                self.owned
2726                    .trace_stack
2727                    .push(|| TraceStackEntry::Message("Unifying trait_parameters".to_string()));
2728                let mut new_params = params.clone();
2729                for (trait_impl, trait_req) in impls {
2730                    let mut param_map = BTreeMap::new();
2731
2732                    for (l, r) in trait_req
2733                        .type_params
2734                        .iter()
2735                        .zip(trait_impl.trait_type_params)
2736                    {
2737                        let copy = r.make_copy_with_mapping(self, &mut param_map);
2738                        self.unify(l, &copy, ctx)?;
2739                    }
2740
2741                    new_params = trait_impl
2742                        .target_type_params
2743                        .iter()
2744                        .zip(new_params)
2745                        .map(|(l, r)| {
2746                            let copy = l.make_copy_with_mapping(self, &mut param_map);
2747                            self.unify(&copy, &r, ctx).add_context(*ukid, *otherid)
2748                        })
2749                        .collect::<std::result::Result<_, _>>()?
2750                }
2751
2752                match (base, meta) {
2753                    (KnownType::Error, _) => {
2754                        unreachable!()
2755                    }
2756                    // Any matches all types
2757                    (_, MetaType::Any)
2758                    // All types are types
2759                    | (KnownType::Named(_), MetaType::Type)
2760                    | (KnownType::Tuple, MetaType::Type)
2761                    | (KnownType::Array, MetaType::Type)
2762                    | (KnownType::Wire, MetaType::Type)
2763                    | (KnownType::Bool(_), MetaType::Bool)
2764                    | (KnownType::String(_), MetaType::Str)
2765                    | (KnownType::Inverted, MetaType::Type)
2766                    // Integers match ints and numbers
2767                    | (KnownType::Integer(_), MetaType::Int)
2768                    | (KnownType::Integer(_), MetaType::Number)
2769                    => {
2770                        let new = self.add_type_var(TypeVar::Known(*loc, base.clone(), new_params));
2771
2772                        Ok((new, vec![otherid.clone(), ukid.clone()]))
2773                    },
2774                    // Integers match uints but only if the concrete integer is >= 0
2775                    (KnownType::Integer(val), MetaType::Uint)
2776                    => {
2777                        if val < &0.to_bigint() {
2778                            Err(meta_err_producer!())
2779                        } else {
2780                            let new = self.add_type_var(TypeVar::Known(*loc, base.clone(), new_params));
2781
2782                            Ok((new, vec![otherid.clone(), ukid.clone()]))
2783                        }
2784                    },
2785
2786                    // Integer with type
2787                    (KnownType::Integer(_), MetaType::Type) => Err(meta_err_producer!()),
2788
2789                    // Bools only unify with any or bool
2790                    (_, MetaType::Bool) => Err(meta_err_producer!()),
2791                    (KnownType::Bool(_), _) => Err(meta_err_producer!()),
2792
2793                    // Strings only unify with any or str
2794                    (_, MetaType::Str) => Err(meta_err_producer!()),
2795                    (KnownType::String(_), _) => Err(meta_err_producer!()),
2796
2797                    // Type with integer
2798                    (KnownType::Named(_), MetaType::Int | MetaType::Number | MetaType::Uint)
2799                    | (KnownType::Tuple, MetaType::Int | MetaType::Uint | MetaType::Number)
2800                    | (KnownType::Array, MetaType::Int | MetaType::Uint | MetaType::Number)
2801                    | (KnownType::Wire, MetaType::Int | MetaType::Uint | MetaType::Number)
2802                    | (KnownType::Inverted, MetaType::Int | MetaType::Uint | MetaType::Number)
2803                    => Err(meta_err_producer!())
2804                }
2805            }
2806        };
2807
2808        let (new_type, replaced_types) = result?;
2809
2810        self.owned.trace_stack.push(|| {
2811            TraceStackEntry::Unified(
2812                v1.debug_resolve(self),
2813                v2.debug_resolve(self),
2814                new_type.debug_resolve(self),
2815                replaced_types
2816                    .iter()
2817                    .map(|v| v.debug_resolve(self))
2818                    .collect(),
2819            )
2820        });
2821
2822        for replaced_type in &replaced_types {
2823            if v1.inner != v2.inner {
2824                let (from, to) = (replaced_type.get_type(self), new_type.get_type(self));
2825                self.owned.replacements.insert(from, to);
2826                if let Err(rec) = self.check_type_for_recursion(to, &mut vec![]) {
2827                    let err_t = self.t_err(().nowhere());
2828                    self.owned.replacements.insert(to, err_t);
2829                    return Err(UnificationError::RecursiveType(rec));
2830                }
2831            }
2832        }
2833
2834        Ok(new_type)
2835    }
2836
2837    pub fn can_unify(&mut self, e1: &impl HasType, e2: &impl HasType, ctx: &Context) -> bool {
2838        self.owned
2839            .trace_stack
2840            .push(|| TraceStackEntry::Enter("Running can_unify".to_string()));
2841        let result = self.do_and_restore(|s| s.unify(e1, e2, ctx)).is_ok();
2842        self.owned.trace_stack.push(|| TraceStackEntry::Exit);
2843        result
2844    }
2845
2846    #[tracing::instrument(level = "trace", skip_all)]
2847    pub fn unify(
2848        &mut self,
2849        e1: &impl HasType,
2850        e2: &impl HasType,
2851        ctx: &Context,
2852    ) -> std::result::Result<TypeVarID, UnificationError> {
2853        let new_type = self.unify_inner(e1, e2, ctx)?;
2854
2855        // With replacement done, some of our constraints may have been updated to provide
2856        // more type inference information. Try to do unification of those new constraints too
2857        loop {
2858            trace!("Updating constraints");
2859            // NOTE: Cloning here is kind of ugly
2860            let new_info;
2861            (self.owned.constraints, new_info) = self
2862                .owned
2863                .constraints
2864                .clone()
2865                .update_type_level_value_constraints(self);
2866
2867            if new_info.is_empty() {
2868                break;
2869            }
2870
2871            for constraint in new_info {
2872                trace!(
2873                    "Constraint replaces {} with {:?}",
2874                    constraint.inner.0.display(self),
2875                    constraint.inner.1
2876                );
2877
2878                let ((var, replacement), loc) = constraint.split_loc();
2879
2880                self.owned.trace_stack.push(|| {
2881                    TraceStackEntry::InferringFromConstraints(
2882                        var.debug_resolve(self),
2883                        replacement.val.clone(),
2884                    )
2885                });
2886
2887                // NOTE: safe unwrap. We already checked the constraint above
2888                let expected_type = self.add_type_var(TypeVar::Known(loc, replacement.val, vec![]));
2889                let result = self.unify_inner(&expected_type.clone().at_loc(&loc), &var, ctx);
2890                let is_meta_error = matches!(result, Err(UnificationError::MetaMismatch { .. }));
2891                match result {
2892                    Ok(_) => {}
2893                    Err(UnificationError::Normal(Tm { mut e, mut g }))
2894                    | Err(UnificationError::MetaMismatch(Tm { mut e, mut g })) => {
2895                        e.inside.replace(
2896                            replacement
2897                                .context
2898                                .inside
2899                                .replace_inside(var, e.failing, self),
2900                        );
2901                        g.inside.replace(
2902                            replacement
2903                                .context
2904                                .inside
2905                                .replace_inside(var, g.failing, self),
2906                        );
2907                        return Err(UnificationError::FromConstraints {
2908                            got: g,
2909                            expected: e,
2910                            source: replacement.context.source,
2911                            loc,
2912                            is_meta_error,
2913                        });
2914                    }
2915                    Err(
2916                        e @ UnificationError::FromConstraints { .. }
2917                        | e @ UnificationError::Specific { .. }
2918                        | e @ UnificationError::RecursiveType(_)
2919                        | e @ UnificationError::UnsatisfiedTraits { .. },
2920                    ) => return Err(e),
2921                };
2922            }
2923        }
2924
2925        Ok(new_type)
2926    }
2927
2928    fn check_type_for_recursion(
2929        &self,
2930        ty: TypeVarID,
2931        seen: &mut Vec<TypeVarID>,
2932    ) -> std::result::Result<(), String> {
2933        seen.push(ty);
2934        match ty.resolve(self) {
2935            TypeVar::Known(_, base, params) => {
2936                for (i, param) in params.iter().enumerate() {
2937                    if seen.contains(param) {
2938                        return Err("*".to_string());
2939                    }
2940
2941                    if let Err(rest) = self.check_type_for_recursion(*param, seen) {
2942                        let list = params
2943                            .iter()
2944                            .enumerate()
2945                            .map(|(j, _)| {
2946                                if j == i {
2947                                    rest.clone()
2948                                } else {
2949                                    "_".to_string()
2950                                }
2951                            })
2952                            .join(", ");
2953
2954                        match base {
2955                            KnownType::Error => {}
2956                            KnownType::Named(name_id) => {
2957                                return Err(format!("{name_id}<{}>", list));
2958                            }
2959                            KnownType::Bool(_) | KnownType::Integer(_) | KnownType::String(_) => {
2960                                unreachable!("Encountered recursive type level bool, int or str")
2961                            }
2962                            KnownType::Tuple => return Err(format!("({})", list)),
2963                            KnownType::Array => return Err(format!("[{}]", list)),
2964                            KnownType::Wire => return Err(format!("&{}", list)),
2965                            KnownType::Inverted => return Err(format!("inv {}", list)),
2966                        }
2967                    }
2968                }
2969            }
2970            TypeVar::Unknown(_, _, traits, _) => {
2971                for t in &traits.inner {
2972                    for param in &t.type_params {
2973                        if seen.contains(param) {
2974                            return Err("...".to_string());
2975                        }
2976
2977                        self.check_type_for_recursion(*param, seen)?;
2978                    }
2979                }
2980            }
2981        }
2982        seen.pop();
2983        Ok(())
2984    }
2985
2986    fn ensure_impls(
2987        &mut self,
2988        var: &TypeVarID,
2989        traits: &TraitList,
2990        trait_is_expected: bool,
2991        trait_list_loc: &Loc<()>,
2992        ctx: &Context,
2993    ) -> std::result::Result<Vec<(TraitImpl, TraitReq)>, UnificationError> {
2994        self.owned.trace_stack.push(|| {
2995            TraceStackEntry::EnsuringImpls(
2996                var.debug_resolve(self),
2997                traits.clone(),
2998                trait_is_expected,
2999            )
3000        });
3001
3002        let number = ctx
3003            .symtab
3004            .lookup_trait(&Path::from_strs(&["Number"]).nowhere())
3005            .expect("Did not find number in symtab")
3006            .0;
3007
3008        macro_rules! error_producer {
3009            ($required_traits:expr) => {
3010                if trait_is_expected {
3011                    if $required_traits.inner.len() == 1
3012                        && $required_traits
3013                            .get_trait(&TraitName::Named(number.clone().nowhere()))
3014                            .is_some()
3015                    {
3016                        Err(UnificationError::Normal(Tm {
3017                            e: UnificationTrace::new(
3018                                self.new_generic_with_traits(*trait_list_loc, $required_traits),
3019                            ),
3020                            g: UnificationTrace::new(var.clone()),
3021                        }))
3022                    } else {
3023                        Err(UnificationError::UnsatisfiedTraits {
3024                            var: *var,
3025                            traits: $required_traits.inner,
3026                            target_loc: trait_list_loc.clone(),
3027                        })
3028                    }
3029                } else {
3030                    Err(UnificationError::Normal(Tm {
3031                        e: UnificationTrace::new(var.clone()),
3032                        g: UnificationTrace::new(
3033                            self.new_generic_with_traits(*trait_list_loc, $required_traits),
3034                        ),
3035                    }))
3036                }
3037            };
3038        }
3039
3040        match &var.resolve(self).clone() {
3041            TypeVar::Known(_, known, params) if known.into_impl_target().is_some() => {
3042                let Some(target) = known.into_impl_target() else {
3043                    unreachable!()
3044                };
3045
3046                let (impls, unsatisfied): (Vec<_>, Vec<_>) = traits
3047                    .inner
3048                    .iter()
3049                    .map(|trait_req| {
3050                        if let Some(impld) = ctx.trait_impls.inner.get(&target).cloned() {
3051                            // Get a list of implementations of this trait where the type
3052                            // parameters can match
3053                            let target_impls = impld
3054                                .iter()
3055                                .filter_map(|trait_impl| {
3056                                    self.checkpoint();
3057                                    let trait_params_match = trait_impl
3058                                        .trait_type_params
3059                                        .iter()
3060                                        .zip(trait_req.type_params.iter())
3061                                        .all(|(l, r)| {
3062                                            let l = l.make_copy(self);
3063                                            self.unify(&l, r, ctx).is_ok()
3064                                        });
3065
3066                                    let impl_params_match =
3067                                        trait_impl.target_type_params.iter().zip(params).all(
3068                                            |(l, r)| {
3069                                                let l = l.make_copy(self);
3070                                                self.unify(&l, r, ctx).is_ok()
3071                                            },
3072                                        );
3073                                    self.restore();
3074
3075                                    if trait_impl.name == trait_req.name
3076                                        && trait_params_match
3077                                        && impl_params_match
3078                                    {
3079                                        Some(trait_impl)
3080                                    } else {
3081                                        None
3082                                    }
3083                                })
3084                                .collect::<Vec<_>>();
3085
3086                            if target_impls.len() == 0 {
3087                                Ok(Either::Right(trait_req.clone()))
3088                            } else if target_impls.len() == 1 {
3089                                let target_impl = *target_impls.last().unwrap();
3090                                Ok(Either::Left((target_impl.clone(), trait_req.inner.clone())))
3091                            } else {
3092                                Err(UnificationError::Specific(diag_anyhow!(
3093                                    trait_req,
3094                                    "Found more than one impl of {} for {}",
3095                                    trait_req.display(self),
3096                                    var.display(self)
3097                                )))
3098                            }
3099                        } else {
3100                            Ok(Either::Right(trait_req.clone()))
3101                        }
3102                    })
3103                    .process_results(|it| it.partition_map(|x| x))?;
3104
3105                if unsatisfied.is_empty() {
3106                    self.owned
3107                        .trace_stack
3108                        .push(|| TraceStackEntry::Message("Ensuring impl successful".to_string()));
3109                    Ok(impls)
3110                } else {
3111                    error_producer!(TraitList::from_vec(unsatisfied.clone()))
3112                }
3113            }
3114            TypeVar::Unknown(_, _, _, _) => {
3115                panic!("running ensure_impls on an unknown type")
3116            }
3117            _ => {
3118                if traits.inner.is_empty() {
3119                    Ok(vec![])
3120                } else {
3121                    error_producer!(traits.clone())
3122                }
3123            }
3124        }
3125    }
3126
3127    pub fn unify_expression_generic_error(
3128        &mut self,
3129        expr: &Loc<Expression>,
3130        other: &impl HasType,
3131        ctx: &Context,
3132    ) -> Result<TypeVarID> {
3133        self.unify(&expr.inner, other, ctx)
3134            .into_default_diagnostic(expr.loc(), self)
3135    }
3136
3137    pub fn check_requirements(&mut self, is_final_check: bool, ctx: &Context) -> Result<()> {
3138        // Once we are done type checking the rest of the entity, check all requirements
3139        loop {
3140            // Walk through all the requirements, checking each one. If the requirement
3141            // is still undetermined, take note to retain that id, otherwise store the
3142            // replacement to be performed
3143            let (retain, replacements_option): (Vec<_>, Vec<_>) = self
3144                .owned
3145                .requirements
3146                .clone()
3147                .iter()
3148                .map(|req| match req.check(self, ctx)? {
3149                    requirements::RequirementResult::NoChange => Ok((true, None)),
3150                    requirements::RequirementResult::UnsatisfiedNow(diag) => {
3151                        if is_final_check {
3152                            Err(diag)
3153                        } else {
3154                            Ok((true, None))
3155                        }
3156                    }
3157                    requirements::RequirementResult::Satisfied(replacement) => {
3158                        self.owned
3159                            .trace_stack
3160                            .push(|| TraceStackEntry::ResolvedRequirement(req.clone()));
3161                        Ok((false, Some(replacement)))
3162                    }
3163                })
3164                .collect::<Result<Vec<_>>>()?
3165                .into_iter()
3166                .unzip();
3167
3168            let replacements = replacements_option
3169                .into_iter()
3170                .flatten()
3171                .flatten()
3172                .collect::<Vec<_>>();
3173
3174            // Drop all replacements that have now been applied
3175            self.owned.requirements = self
3176                .owned
3177                .requirements
3178                .drain(0..)
3179                .zip(retain)
3180                .filter_map(|(req, keep)| if keep { Some(req) } else { None })
3181                .collect();
3182
3183            if replacements.is_empty() {
3184                break;
3185            }
3186
3187            for Replacement { from, to, context } in replacements {
3188                self.unify(&to, &from, ctx).into_diagnostic_or_default(
3189                    from.loc(),
3190                    context,
3191                    self,
3192                )?;
3193            }
3194        }
3195
3196        Ok(())
3197    }
3198
3199    pub fn get_replacement(&self, var: &TypeVarID) -> TypeVarID {
3200        self.owned.replacements.get(*var)
3201    }
3202
3203    pub fn do_and_restore<T, E>(
3204        &mut self,
3205        inner: impl Fn(&mut Self) -> std::result::Result<T, E>,
3206    ) -> std::result::Result<T, E> {
3207        self.checkpoint();
3208        let result = inner(self);
3209        self.restore();
3210        result
3211    }
3212
3213    /// Create a "checkpoint" to which we can restore later using `restore`. This acts
3214    /// like a stack, nested checkpoints are possible
3215    fn checkpoint(&mut self) {
3216        self.owned
3217            .trace_stack
3218            .push(|| TraceStackEntry::Enter("Creating checkpoint".to_string()));
3219        self.owned.replacements.push();
3220
3221        // This is relatively expensive if these lists are large, however, for now
3222        // this is a much simpler solution than attempting to roll-back replaced requirements
3223        // later
3224        self.owned.checkpoints.push((
3225            self.owned.requirements.clone(),
3226            self.owned.constraints.clone(),
3227        ));
3228    }
3229
3230    fn restore(&mut self) {
3231        self.owned.replacements.discard_top();
3232        self.owned.trace_stack.push(|| TraceStackEntry::Exit);
3233
3234        let (requirements, constraints) = self
3235            .owned
3236            .checkpoints
3237            .pop()
3238            .expect("Popped a checkpoint without any existing checkpoints.");
3239
3240        self.owned.requirements = requirements;
3241        self.owned.constraints = constraints;
3242    }
3243}
3244
3245impl TypeState {
3246    pub fn print_equations(&self) {
3247        for (lhs, rhs) in &self.owned.equations {
3248            println!(
3249                "{} -> {}",
3250                format!("{lhs}").blue(),
3251                format!("{}", rhs.debug_resolve(self)).green()
3252            )
3253        }
3254
3255        println!("\nReplacments:");
3256
3257        for repl_stack in &self.owned.replacements.all() {
3258            let replacements = { repl_stack.read().unwrap().clone() };
3259            for (lhs, rhs) in replacements.iter().sorted() {
3260                println!(
3261                    "{} -> {} ({} -> {})",
3262                    format!("{}", lhs.inner).blue(),
3263                    format!("{}", rhs.inner).green(),
3264                    format!("{}", lhs.debug_resolve(self)).blue(),
3265                    format!("{}", rhs.debug_resolve(self)).green(),
3266                )
3267            }
3268            println!("---")
3269        }
3270
3271        println!("\n Requirements:");
3272
3273        for requirement in &self.owned.requirements {
3274            println!("{:?}", requirement)
3275        }
3276
3277        println!()
3278    }
3279}
3280
3281#[must_use]
3282pub struct UnificationBuilder {
3283    lhs: TypeVarID,
3284    rhs: TypeVarID,
3285}
3286impl UnificationBuilder {
3287    pub fn commit(
3288        self,
3289        state: &mut TypeState,
3290        ctx: &Context,
3291    ) -> std::result::Result<TypeVarID, UnificationError> {
3292        state.unify(&self.lhs, &self.rhs, ctx)
3293    }
3294}
3295
3296pub trait HasType: std::fmt::Debug {
3297    fn get_type(&self, state: &TypeState) -> TypeVarID {
3298        self.try_get_type(state)
3299            .unwrap_or(state.owned.error_type.unwrap())
3300    }
3301
3302    fn try_get_type(&self, state: &TypeState) -> Option<TypeVarID> {
3303        let id = self.get_type_impl(state);
3304        id.map(|id| state.get_replacement(&id))
3305    }
3306
3307    fn get_type_impl(&self, state: &TypeState) -> Option<TypeVarID>;
3308
3309    fn unify_with(&self, rhs: &dyn HasType, state: &TypeState) -> UnificationBuilder {
3310        UnificationBuilder {
3311            lhs: self.get_type(state),
3312            rhs: rhs.get_type(state),
3313        }
3314    }
3315}
3316
3317impl HasType for TypeVarID {
3318    fn get_type_impl(&self, _state: &TypeState) -> Option<TypeVarID> {
3319        Some(*self)
3320    }
3321}
3322impl HasType for Loc<TypeVarID> {
3323    fn get_type_impl(&self, state: &TypeState) -> Option<TypeVarID> {
3324        self.inner.try_get_type(state)
3325    }
3326}
3327impl HasType for TypedExpression {
3328    fn get_type_impl(&self, state: &TypeState) -> Option<TypeVarID> {
3329        state.maybe_type_of(self).cloned()
3330    }
3331}
3332impl HasType for Expression {
3333    fn get_type_impl(&self, state: &TypeState) -> Option<TypeVarID> {
3334        state.maybe_type_of(&TypedExpression::Id(self.id)).cloned()
3335    }
3336}
3337impl HasType for Loc<Expression> {
3338    fn get_type_impl(&self, state: &TypeState) -> Option<TypeVarID> {
3339        state
3340            .maybe_type_of(&TypedExpression::Id(self.inner.id))
3341            .cloned()
3342    }
3343}
3344impl HasType for Pattern {
3345    fn get_type_impl(&self, state: &TypeState) -> Option<TypeVarID> {
3346        state.maybe_type_of(&TypedExpression::Id(self.id)).cloned()
3347    }
3348}
3349impl HasType for Loc<Pattern> {
3350    fn get_type_impl(&self, state: &TypeState) -> Option<TypeVarID> {
3351        state
3352            .maybe_type_of(&TypedExpression::Id(self.inner.id))
3353            .cloned()
3354    }
3355}
3356impl HasType for NameID {
3357    fn get_type_impl(&self, state: &TypeState) -> Option<TypeVarID> {
3358        state
3359            .maybe_type_of(&TypedExpression::Name(self.clone()))
3360            .cloned()
3361    }
3362}