1use 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 Anonymous,
97 Definition(&'a NameID),
100 ImplBlock {
101 target: &'a ImplTarget,
102 id: ImplID,
103 },
104 Expression(Loc<ExprID>),
106}
107
108#[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#[derive(Clone, Serialize, Deserialize)]
133pub struct OwnedTypeState {
134 key: u64,
139 keys: BTreeSet<u64>,
141
142 equations: TypeEquations,
143
144 constraints: TypeConstraints,
146
147 generic_lists: GenericLists,
150
151 #[serde(skip)]
155 requirements: Vec<Requirement>,
156
157 replacements: ReplacementStack,
158 #[serde(skip)]
161 checkpoints: Vec<(Vec<Requirement>, TypeConstraints)>,
162
163 pipeline_state: Option<PipelineState>,
165
166 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 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 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 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 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 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 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 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 &entity.head.where_clauses,
552 )?;
553
554 pp(self, entity, &generic_list, ctx)?;
555
556 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 self.check_requirements(false, ctx)?;
602 }
603
604 self.visit_expression(&entity.body, ctx, &generic_list);
605
606 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 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 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, ¤t_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 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 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 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 #[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 visit_args: bool,
1017 is_method: bool,
1020 turbofish: Option<TurbofishCtx>,
1021 generic_list: &GenericListToken,
1022 ) -> Result<()> {
1023 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 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 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 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 ["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 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 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 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 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 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 matched_params
1360 .iter()
1361 .map(|matched_param| {
1362 let i = type_params
1363 .iter()
1364 .enumerate()
1365 .find_map(|(i, param)| match ¶m.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 } = ¶m.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 } = ¶m.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 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 ¶m.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 ¶m.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 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(®.pattern, ctx, generic_list)?;
2076
2077 let type_spec_type = match ®.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 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(®.clock, ctx, generic_list);
2094 self.visit_expression(®.value, ctx, generic_list);
2095
2096 if let Some(tvar) = &type_spec_type {
2097 self.unify(®.value, tvar, ctx)
2098 .into_default_diagnostic(reg.value.loc(), self)?;
2099 }
2100
2101 if let Some((rst_cond, rst_value)) = ®.reset {
2102 self.visit_expression(rst_cond, ctx, generic_list);
2103 self.visit_expression(rst_value, ctx, generic_list);
2104 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 self.unify(&rst_value.inner, ®.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(®.pattern, format!("because this has type {expected}"))
2135 },
2136 self,
2137 )?;
2138 }
2139
2140 if let Some(initial) = ®.initial {
2141 self.visit_expression(initial, ctx, generic_list);
2142
2143 self.unify(&initial.inner, ®.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(®.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), ®.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 }
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
2424impl 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 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 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 unify_if!(val1 == val2, v1, vec![])
2571 }
2572 (KnownType::String(val1), KnownType::String(val2)) => {
2573 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 unify_params(self, &p1, &p2)?;
2637 Ok((v1, vec![]))
2638 }
2639 (_, _) => Err(err_producer!()),
2640 }
2641 }
2642 (
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, ©, 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(©, &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 (_, MetaType::Any)
2758 | (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 | (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 (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 (KnownType::Integer(_), MetaType::Type) => Err(meta_err_producer!()),
2788
2789 (_, MetaType::Bool) => Err(meta_err_producer!()),
2791 (KnownType::Bool(_), _) => Err(meta_err_producer!()),
2792
2793 (_, MetaType::Str) => Err(meta_err_producer!()),
2795 (KnownType::String(_), _) => Err(meta_err_producer!()),
2796
2797 (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 loop {
2858 trace!("Updating constraints");
2859 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 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 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 loop {
3140 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 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 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 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}