1use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
2use std::borrow::Borrow;
3use std::cell::OnceCell;
4
5use ecow::EcoString;
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct Symbol(EcoString);
16
17impl Symbol {
18 pub fn from_parts(module: &str, local: &str) -> Self {
22 let mut s = String::with_capacity(module.len() + 1 + local.len());
23 s.push_str(module);
24 s.push('.');
25 s.push_str(local);
26 Self(EcoString::from(s))
27 }
28
29 pub fn with_segment(&self, segment: &str) -> Self {
34 let mut s = String::with_capacity(self.0.len() + 1 + segment.len());
35 s.push_str(&self.0);
36 s.push('.');
37 s.push_str(segment);
38 Self(EcoString::from(s))
39 }
40
41 pub fn from_raw(qualified: impl Into<EcoString>) -> Self {
44 Self(qualified.into())
45 }
46
47 pub fn as_str(&self) -> &str {
48 &self.0
49 }
50
51 pub fn as_eco(&self) -> &EcoString {
52 &self.0
53 }
54
55 pub fn last_segment(&self) -> &str {
57 self.0.rsplit('.').next().unwrap_or(&self.0)
58 }
59
60 pub fn without_last_segment(&self) -> Option<&str> {
63 self.0.rsplit_once('.').map(|(rest, _)| rest)
64 }
65
66 pub fn simple_module_part(&self) -> Option<&str> {
70 self.0.split_once('.').map(|(m, _)| m)
71 }
72}
73
74impl Borrow<str> for Symbol {
75 fn borrow(&self) -> &str {
76 &self.0
77 }
78}
79
80impl AsRef<str> for Symbol {
81 fn as_ref(&self) -> &str {
82 &self.0
83 }
84}
85
86impl std::ops::Deref for Symbol {
87 type Target = str;
88
89 fn deref(&self) -> &str {
90 &self.0
91 }
92}
93
94impl From<&Symbol> for EcoString {
95 fn from(s: &Symbol) -> Self {
96 s.0.clone()
97 }
98}
99
100impl std::fmt::Display for Symbol {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 self.0.fmt(f)
103 }
104}
105
106impl From<EcoString> for Symbol {
107 fn from(s: EcoString) -> Self {
108 Self(s)
109 }
110}
111
112impl From<Symbol> for EcoString {
113 fn from(s: Symbol) -> Self {
114 s.0
115 }
116}
117
118impl From<&str> for Symbol {
119 fn from(s: &str) -> Self {
120 Self(EcoString::from(s))
121 }
122}
123
124impl From<String> for Symbol {
125 fn from(s: String) -> Self {
126 Self(EcoString::from(s))
127 }
128}
129
130impl PartialEq<str> for Symbol {
131 fn eq(&self, other: &str) -> bool {
132 self.0.as_str() == other
133 }
134}
135
136impl PartialEq<&str> for Symbol {
137 fn eq(&self, other: &&str) -> bool {
138 self.0.as_str() == *other
139 }
140}
141
142pub fn unqualified_name(id: &str) -> &str {
146 id.rsplit('.').next().unwrap_or(id)
147}
148
149pub type SubstitutionMap = HashMap<EcoString, Type>;
151
152pub fn substitute(ty: &Type, map: &HashMap<EcoString, Type>) -> Type {
153 if map.is_empty() {
154 return ty.clone();
155 }
156 match ty {
157 Type::Parameter(name) => map.get(name).cloned().unwrap_or_else(|| ty.clone()),
158 Type::Nominal {
159 id,
160 params,
161 underlying_ty: underlying,
162 } => Type::Nominal {
163 id: id.clone(),
164 params: params.iter().map(|p| substitute(p, map)).collect(),
165 underlying_ty: underlying.as_ref().map(|u| Box::new(substitute(u, map))),
166 },
167 Type::Function {
168 params,
169 param_mutability,
170 bounds,
171 return_type,
172 } => Type::Function {
173 params: params.iter().map(|p| substitute(p, map)).collect(),
174 param_mutability: param_mutability.clone(),
175 bounds: bounds
176 .iter()
177 .map(|b| Bound {
178 param_name: b.param_name.clone(),
179 generic: substitute(&b.generic, map),
180 ty: substitute(&b.ty, map),
181 })
182 .collect(),
183 return_type: Box::new(substitute(return_type, map)),
184 },
185 Type::Var { .. } | Type::Error => ty.clone(),
186 Type::Forall { vars, body } => {
187 let has_overlap = map.keys().any(|k| vars.contains(k));
188 let substituted_body = if has_overlap {
189 let filtered_map: HashMap<EcoString, Type> = map
190 .iter()
191 .filter(|(k, _)| !vars.contains(*k))
192 .map(|(k, v)| (k.clone(), v.clone()))
193 .collect();
194 substitute(body, &filtered_map)
195 } else {
196 substitute(body, map)
197 };
198 Type::Forall {
199 vars: vars.clone(),
200 body: Box::new(substituted_body),
201 }
202 }
203 Type::Tuple(elements) => Type::Tuple(elements.iter().map(|e| substitute(e, map)).collect()),
204 Type::Compound { kind, args } => Type::Compound {
205 kind: *kind,
206 args: args.iter().map(|a| substitute(a, map)).collect(),
207 },
208 Type::Simple(_) | Type::Never | Type::ImportNamespace(_) | Type::ReceiverPlaceholder => {
209 ty.clone()
210 }
211 }
212}
213
214#[derive(Debug, Clone, PartialEq)]
215#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
216pub struct Bound {
217 pub param_name: EcoString,
218 pub generic: Type,
219 pub ty: Type,
220}
221
222#[derive(Clone, Copy, PartialEq, Eq, Hash)]
226#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
227pub struct TypeVarId(pub u32);
228
229impl TypeVarId {
230 pub const IGNORED: TypeVarId = TypeVarId(u32::MAX);
231 pub const UNINFERRED: TypeVarId = TypeVarId(u32::MAX - 1);
232
233 pub fn is_reserved(self) -> bool {
234 self == Self::IGNORED || self == Self::UNINFERRED
235 }
236
237 pub fn as_u32(self) -> u32 {
238 self.0
239 }
240}
241
242impl std::fmt::Debug for TypeVarId {
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 match *self {
245 Self::IGNORED => write!(f, "ignored"),
246 Self::UNINFERRED => write!(f, "uninferred"),
247 TypeVarId(n) => write!(f, "#{}", n),
248 }
249 }
250}
251
252#[derive(Clone)]
253#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
254pub enum Type {
255 Simple(SimpleKind),
256
257 Compound {
258 kind: CompoundKind,
259 args: Vec<Type>,
260 },
261
262 Nominal {
263 id: Symbol,
264 params: Vec<Type>,
265 underlying_ty: Option<Box<Type>>,
266 },
267
268 ImportNamespace(EcoString),
272
273 Function {
274 params: Vec<Type>,
275 param_mutability: Vec<bool>,
276 bounds: Vec<Bound>,
277 return_type: Box<Type>,
278 },
279
280 Var {
284 id: TypeVarId,
285 hint: Option<EcoString>,
286 },
287
288 Forall {
289 vars: Vec<EcoString>,
290 body: Box<Type>,
291 },
292
293 Parameter(EcoString),
294
295 Never,
296
297 Tuple(Vec<Type>),
298
299 Error,
302
303 ReceiverPlaceholder,
308}
309
310impl std::fmt::Debug for Type {
311 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312 match self {
313 Type::Nominal { id, params, .. } => f
314 .debug_struct("Nominal")
315 .field("id", id)
316 .field("params", params)
317 .finish(),
318 Type::Function {
319 params,
320 param_mutability,
321 bounds,
322 return_type,
323 } => {
324 let mut s = f.debug_struct("Function");
325 s.field("params", params);
326 if param_mutability.iter().any(|m| *m) {
327 s.field("param_mutability", param_mutability);
328 }
329 s.field("bounds", bounds)
330 .field("return_type", return_type)
331 .finish()
332 }
333 Type::Var { id, hint } => {
334 let mut s = f.debug_struct("Var");
335 s.field("id", id);
336 if let Some(h) = hint {
337 s.field("hint", h);
338 }
339 s.finish()
340 }
341 Type::Forall { vars, body } => f
342 .debug_struct("Forall")
343 .field("vars", vars)
344 .field("body", body)
345 .finish(),
346 Type::Parameter(name) => f.debug_tuple("Parameter").field(name).finish(),
347 Type::Never => write!(f, "Never"),
348 Type::Tuple(elements) => f.debug_tuple("Tuple").field(elements).finish(),
349 Type::Error => write!(f, "Error"),
350 Type::ImportNamespace(module_id) => {
351 f.debug_tuple("ImportNamespace").field(module_id).finish()
352 }
353 Type::ReceiverPlaceholder => write!(f, "ReceiverPlaceholder"),
354 Type::Simple(kind) => f.debug_tuple("Simple").field(kind).finish(),
355 Type::Compound { kind, args } => f
356 .debug_struct("Compound")
357 .field("kind", kind)
358 .field("args", args)
359 .finish(),
360 }
361 }
362}
363
364impl PartialEq for Type {
365 fn eq(&self, other: &Self) -> bool {
366 match (self, other) {
367 (
368 Type::Nominal {
369 id: id1,
370 params: params1,
371 ..
372 },
373 Type::Nominal {
374 id: id2,
375 params: params2,
376 ..
377 },
378 ) => id1 == id2 && params1 == params2,
379 (
380 Type::Function {
381 params: p1,
382 param_mutability: m1,
383 bounds: b1,
384 return_type: r1,
385 },
386 Type::Function {
387 params: p2,
388 param_mutability: m2,
389 bounds: b2,
390 return_type: r2,
391 },
392 ) => p1 == p2 && m1 == m2 && b1 == b2 && r1 == r2,
393 (Type::Var { id: id1, .. }, Type::Var { id: id2, .. }) => id1 == id2,
394 (
395 Type::Forall {
396 vars: vars1,
397 body: body1,
398 },
399 Type::Forall {
400 vars: vars2,
401 body: body2,
402 },
403 ) => vars1 == vars2 && body1 == body2,
404 (Type::Parameter(name1), Type::Parameter(name2)) => name1 == name2,
405 (Type::Never, Type::Never) => true,
406 (Type::Tuple(elems1), Type::Tuple(elems2)) => elems1 == elems2,
407 (Type::ImportNamespace(m1), Type::ImportNamespace(m2)) => m1 == m2,
408 (Type::ReceiverPlaceholder, Type::ReceiverPlaceholder) => true,
409 (Type::Simple(k1), Type::Simple(k2)) => k1 == k2,
410 (Type::Compound { kind: k1, args: a1 }, Type::Compound { kind: k2, args: a2 }) => {
411 k1 == k2 && a1 == a2
412 }
413 _ => false,
414 }
415 }
416}
417
418thread_local! {
419 static INTERNED_INT: OnceCell<Type> = const { OnceCell::new() };
420 static INTERNED_STRING: OnceCell<Type> = const { OnceCell::new() };
421 static INTERNED_BOOL: OnceCell<Type> = const { OnceCell::new() };
422 static INTERNED_UNIT: OnceCell<Type> = const { OnceCell::new() };
423 static INTERNED_FLOAT64: OnceCell<Type> = const { OnceCell::new() };
424 static INTERNED_RUNE: OnceCell<Type> = const { OnceCell::new() };
425 static INTERNED_BYTE: OnceCell<Type> = const { OnceCell::new() };
426}
427
428impl Type {
429 pub fn simple(kind: SimpleKind) -> Type {
430 Self::Simple(kind)
431 }
432
433 pub fn compound(kind: CompoundKind, args: Vec<Type>) -> Type {
434 Self::Compound { kind, args }
435 }
436
437 pub fn int() -> Type {
438 INTERNED_INT.with(|cell| cell.get_or_init(|| Self::simple(SimpleKind::Int)).clone())
439 }
440
441 pub fn string() -> Type {
442 INTERNED_STRING.with(|cell| {
443 cell.get_or_init(|| Self::simple(SimpleKind::String))
444 .clone()
445 })
446 }
447
448 pub fn bool() -> Type {
449 INTERNED_BOOL.with(|cell| cell.get_or_init(|| Self::simple(SimpleKind::Bool)).clone())
450 }
451
452 pub fn unit() -> Type {
453 INTERNED_UNIT.with(|cell| cell.get_or_init(|| Self::simple(SimpleKind::Unit)).clone())
454 }
455
456 pub fn float64() -> Type {
457 INTERNED_FLOAT64.with(|cell| {
458 cell.get_or_init(|| Self::simple(SimpleKind::Float64))
459 .clone()
460 })
461 }
462
463 pub fn rune() -> Type {
464 INTERNED_RUNE.with(|cell| cell.get_or_init(|| Self::simple(SimpleKind::Rune)).clone())
465 }
466
467 pub fn byte() -> Type {
468 INTERNED_BYTE.with(|cell| cell.get_or_init(|| Self::simple(SimpleKind::Byte)).clone())
469 }
470}
471
472impl Type {
473 pub fn uninferred() -> Self {
474 Self::Var {
475 id: TypeVarId::UNINFERRED,
476 hint: None,
477 }
478 }
479
480 pub fn ignored() -> Self {
481 Self::Var {
482 id: TypeVarId::IGNORED,
483 hint: None,
484 }
485 }
486
487 pub fn get_type_params(&self) -> Option<&[Type]> {
488 match self {
489 Type::Nominal { params, .. } => Some(params),
490 Type::Compound { args, .. } => Some(args),
491 _ => None,
492 }
493 }
494}
495
496#[derive(Debug, Clone, Copy, PartialEq, Eq)]
497pub enum NumericFamily {
498 SignedInt,
499 UnsignedInt,
500 Float,
501}
502
503#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
504#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
505pub enum CompoundKind {
506 Ref,
507 Slice,
508 EnumeratedSlice,
509 Map,
510 Channel,
511 Sender,
512 Receiver,
513 VarArgs,
514}
515
516impl CompoundKind {
517 pub fn leaf_name(self) -> &'static str {
518 match self {
519 CompoundKind::Ref => "Ref",
520 CompoundKind::Slice => "Slice",
521 CompoundKind::EnumeratedSlice => "EnumeratedSlice",
522 CompoundKind::Map => "Map",
523 CompoundKind::Channel => "Channel",
524 CompoundKind::Sender => "Sender",
525 CompoundKind::Receiver => "Receiver",
526 CompoundKind::VarArgs => "VarArgs",
527 }
528 }
529
530 pub fn from_name(name: &str) -> Option<CompoundKind> {
531 Some(match name {
532 "Ref" => CompoundKind::Ref,
533 "Slice" => CompoundKind::Slice,
534 "EnumeratedSlice" => CompoundKind::EnumeratedSlice,
535 "Map" => CompoundKind::Map,
536 "Channel" => CompoundKind::Channel,
537 "Sender" => CompoundKind::Sender,
538 "Receiver" => CompoundKind::Receiver,
539 "VarArgs" => CompoundKind::VarArgs,
540 _ => return None,
541 })
542 }
543}
544
545#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
546#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
547pub enum SimpleKind {
548 Int,
549 Int8,
550 Int16,
551 Int32,
552 Int64,
553 Uint,
554 Uint8,
555 Uint16,
556 Uint32,
557 Uint64,
558 Uintptr,
559 Byte,
560 Float32,
561 Float64,
562 Complex64,
563 Complex128,
564 Rune,
565 Bool,
566 String,
567 Unit,
568}
569
570impl SimpleKind {
571 pub fn leaf_name(self) -> &'static str {
572 match self {
573 SimpleKind::Int => "int",
574 SimpleKind::Int8 => "int8",
575 SimpleKind::Int16 => "int16",
576 SimpleKind::Int32 => "int32",
577 SimpleKind::Int64 => "int64",
578 SimpleKind::Uint => "uint",
579 SimpleKind::Uint8 => "uint8",
580 SimpleKind::Uint16 => "uint16",
581 SimpleKind::Uint32 => "uint32",
582 SimpleKind::Uint64 => "uint64",
583 SimpleKind::Uintptr => "uintptr",
584 SimpleKind::Byte => "byte",
585 SimpleKind::Float32 => "float32",
586 SimpleKind::Float64 => "float64",
587 SimpleKind::Complex64 => "complex64",
588 SimpleKind::Complex128 => "complex128",
589 SimpleKind::Rune => "rune",
590 SimpleKind::Bool => "bool",
591 SimpleKind::String => "string",
592 SimpleKind::Unit => "Unit",
593 }
594 }
595
596 pub fn from_name(name: &str) -> Option<SimpleKind> {
597 Some(match name {
598 "int" => SimpleKind::Int,
599 "int8" => SimpleKind::Int8,
600 "int16" => SimpleKind::Int16,
601 "int32" => SimpleKind::Int32,
602 "int64" => SimpleKind::Int64,
603 "uint" => SimpleKind::Uint,
604 "uint8" => SimpleKind::Uint8,
605 "uint16" => SimpleKind::Uint16,
606 "uint32" => SimpleKind::Uint32,
607 "uint64" => SimpleKind::Uint64,
608 "uintptr" => SimpleKind::Uintptr,
609 "byte" => SimpleKind::Byte,
610 "float32" => SimpleKind::Float32,
611 "float64" => SimpleKind::Float64,
612 "complex64" => SimpleKind::Complex64,
613 "complex128" => SimpleKind::Complex128,
614 "rune" => SimpleKind::Rune,
615 "bool" => SimpleKind::Bool,
616 "string" => SimpleKind::String,
617 "Unit" => SimpleKind::Unit,
618 _ => return None,
619 })
620 }
621
622 pub fn is_arithmetic(self) -> bool {
623 !matches!(
624 self,
625 SimpleKind::Bool | SimpleKind::String | SimpleKind::Unit | SimpleKind::Uintptr
626 )
627 }
628
629 pub fn is_ordered(self) -> bool {
630 self.is_arithmetic() && !matches!(self, SimpleKind::Complex64 | SimpleKind::Complex128)
631 }
632
633 pub fn is_unsigned_int(self) -> bool {
634 matches!(
635 self,
636 SimpleKind::Byte
637 | SimpleKind::Uint
638 | SimpleKind::Uint8
639 | SimpleKind::Uint16
640 | SimpleKind::Uint32
641 | SimpleKind::Uint64
642 )
643 }
644
645 pub fn is_signed_int(self) -> bool {
646 matches!(
647 self,
648 SimpleKind::Int
649 | SimpleKind::Int8
650 | SimpleKind::Int16
651 | SimpleKind::Int32
652 | SimpleKind::Int64
653 | SimpleKind::Rune
654 )
655 }
656
657 pub fn is_float(self) -> bool {
658 matches!(self, SimpleKind::Float32 | SimpleKind::Float64)
659 }
660
661 pub fn is_complex(self) -> bool {
662 matches!(self, SimpleKind::Complex64 | SimpleKind::Complex128)
663 }
664
665 pub fn numeric_family(self) -> Option<NumericFamily> {
666 if self.is_signed_int() {
667 Some(NumericFamily::SignedInt)
668 } else if self.is_unsigned_int() {
669 Some(NumericFamily::UnsignedInt)
670 } else if self.is_float() {
671 Some(NumericFamily::Float)
672 } else {
673 None
674 }
675 }
676}
677
678impl Type {
679 pub fn get_function_ret(&self) -> Option<&Type> {
680 match self {
681 Type::Function { return_type, .. } => Some(return_type),
682 _ => None,
683 }
684 }
685
686 pub fn has_name(&self, name: &str) -> bool {
687 match self {
688 Type::Nominal { id, .. } => id.last_segment() == name,
689 Type::Simple(kind) => kind.leaf_name() == name,
690 Type::Compound { kind, .. } => kind.leaf_name() == name,
691 _ => false,
692 }
693 }
694
695 pub fn get_qualified_id(&self) -> Option<&str> {
696 match self {
697 Type::Nominal { id, .. } => Some(id.as_str()),
698 _ => None,
699 }
700 }
701
702 pub fn get_underlying(&self) -> Option<&Type> {
703 match self {
704 Type::Nominal {
705 underlying_ty: underlying,
706 ..
707 } => underlying.as_deref(),
708 _ => None,
709 }
710 }
711
712 pub fn is_result(&self) -> bool {
713 self.has_qualified_id("prelude.Result")
714 }
715
716 pub fn is_option(&self) -> bool {
717 self.has_qualified_id("prelude.Option")
718 }
719
720 pub fn is_partial(&self) -> bool {
721 self.has_qualified_id("prelude.Partial")
722 }
723
724 fn has_qualified_id(&self, qualified_id: &str) -> bool {
725 matches!(self, Type::Nominal { id, .. } if id.as_str() == qualified_id)
726 }
727
728 pub fn is_unit(&self) -> bool {
729 self.is_simple(SimpleKind::Unit)
730 }
731
732 pub fn tuple_arity(&self) -> Option<usize> {
733 match self {
734 Type::Tuple(elements) => Some(elements.len()),
735 _ => None,
736 }
737 }
738
739 pub fn is_tuple(&self) -> bool {
740 matches!(self, Type::Tuple(_))
741 }
742
743 pub fn as_import_namespace(&self) -> Option<&str> {
744 match self {
745 Type::ImportNamespace(module_id) => Some(module_id),
746 _ => None,
747 }
748 }
749
750 pub fn as_compound(&self) -> Option<(CompoundKind, &[Type])> {
751 match self {
752 Type::Compound { kind, args } => Some((*kind, args.as_slice())),
753 Type::Nominal { id, params, .. } => {
754 CompoundKind::from_name(id.last_segment()).map(|k| (k, params.as_slice()))
755 }
756 _ => None,
757 }
758 }
759
760 pub fn is_native(&self, kind: CompoundKind) -> bool {
761 self.as_compound().is_some_and(|(k, _)| k == kind)
762 }
763
764 pub fn is_ref(&self) -> bool {
765 self.is_native(CompoundKind::Ref)
766 }
767
768 pub fn is_slice(&self) -> bool {
769 self.is_native(CompoundKind::Slice)
770 }
771
772 pub fn is_map(&self) -> bool {
773 self.is_native(CompoundKind::Map)
774 }
775
776 pub fn is_channel(&self) -> bool {
777 self.is_native(CompoundKind::Channel)
778 }
779
780 pub fn is_receiver_placeholder(&self) -> bool {
781 matches!(self, Type::ReceiverPlaceholder)
782 }
783
784 pub fn is_unknown(&self) -> bool {
785 self.has_name("Unknown")
786 }
787
788 pub fn is_receiver(&self) -> bool {
789 self.is_native(CompoundKind::Receiver)
790 }
791
792 pub fn is_ignored(&self) -> bool {
793 matches!(self, Type::Var { id, .. } if *id == TypeVarId::IGNORED)
794 }
795
796 pub fn is_variadic(&self) -> Option<Type> {
797 let last = self.get_function_params()?.last()?;
798 match last.as_compound()? {
799 (CompoundKind::VarArgs, _) => last.inner(),
800 _ => None,
801 }
802 }
803
804 pub fn is_string(&self) -> bool {
805 self.is_simple(SimpleKind::String)
806 }
807
808 pub fn is_slice_of_simple(&self, element: SimpleKind) -> bool {
809 match self.as_compound() {
810 Some((CompoundKind::Slice, [elem])) => elem.is_simple(element),
811 _ => false,
812 }
813 }
814
815 pub fn is_slice_of(&self, element_name: &str) -> bool {
816 match self.as_compound() {
817 Some((CompoundKind::Slice, [elem])) => elem.has_name(element_name),
818 _ => false,
819 }
820 }
821
822 pub fn is_byte_slice(&self) -> bool {
823 self.is_slice_of_simple(SimpleKind::Byte) || self.is_slice_of_simple(SimpleKind::Uint8)
824 }
825
826 pub fn is_rune_slice(&self) -> bool {
827 self.is_slice_of_simple(SimpleKind::Rune)
828 }
829
830 pub fn is_byte_or_rune_slice(&self) -> bool {
831 self.is_byte_slice() || self.is_rune_slice()
832 }
833
834 pub fn has_byte_or_rune_slice_underlying(&self) -> bool {
835 if self.is_byte_or_rune_slice() {
836 return true;
837 }
838 match self {
839 Type::Nominal { underlying_ty, .. } => underlying_ty
840 .as_deref()
841 .is_some_and(|u| u.has_byte_or_rune_slice_underlying()),
842 _ => false,
843 }
844 }
845
846 pub fn as_simple(&self) -> Option<SimpleKind> {
847 match self {
848 Type::Simple(kind) => Some(*kind),
849 Type::Nominal { id, .. } => SimpleKind::from_name(id.last_segment()),
850 _ => None,
851 }
852 }
853
854 pub fn is_simple(&self, kind: SimpleKind) -> bool {
855 self.as_simple() == Some(kind)
856 }
857
858 pub fn is_boolean(&self) -> bool {
859 self.is_simple(SimpleKind::Bool)
860 }
861
862 pub fn is_rune(&self) -> bool {
863 self.is_simple(SimpleKind::Rune)
864 }
865
866 pub fn is_float64(&self) -> bool {
867 self.is_simple(SimpleKind::Float64)
868 }
869
870 pub fn is_float32(&self) -> bool {
871 self.is_simple(SimpleKind::Float32)
872 }
873
874 pub fn is_float(&self) -> bool {
875 self.as_simple().is_some_and(SimpleKind::is_float)
876 }
877
878 pub fn is_variable(&self) -> bool {
879 matches!(self, Type::Var { .. })
880 }
881
882 pub fn is_type_var(&self) -> bool {
883 matches!(self, Type::Var { .. })
884 }
885
886 pub fn is_numeric(&self) -> bool {
887 self.as_simple().is_some_and(SimpleKind::is_arithmetic)
888 }
889
890 pub fn is_ordered(&self) -> bool {
891 self.as_simple().is_some_and(SimpleKind::is_ordered)
892 }
893
894 pub fn satisfies_ordered_constraint(&self) -> bool {
896 if let Some(kind) = self.as_simple() {
897 return matches!(
898 kind,
899 SimpleKind::Int
900 | SimpleKind::Int8
901 | SimpleKind::Int16
902 | SimpleKind::Int32
903 | SimpleKind::Int64
904 | SimpleKind::Uint
905 | SimpleKind::Uint8
906 | SimpleKind::Uint16
907 | SimpleKind::Uint32
908 | SimpleKind::Uint64
909 | SimpleKind::Uintptr
910 | SimpleKind::Byte
911 | SimpleKind::Rune
912 | SimpleKind::Float32
913 | SimpleKind::Float64
914 | SimpleKind::String
915 );
916 }
917 match self {
918 Type::Nominal { underlying_ty, .. } => underlying_ty
919 .as_deref()
920 .is_some_and(Type::satisfies_ordered_constraint),
921 Type::Parameter(_) => true,
922 _ => false,
923 }
924 }
925
926 pub fn is_complex(&self) -> bool {
927 self.as_simple().is_some_and(SimpleKind::is_complex)
928 }
929
930 pub fn is_unsigned_int(&self) -> bool {
931 self.as_simple().is_some_and(SimpleKind::is_unsigned_int)
932 }
933
934 pub fn is_never(&self) -> bool {
935 matches!(self, Type::Never)
936 }
937
938 pub fn is_error(&self) -> bool {
939 matches!(self, Type::Error)
940 }
941
942 pub fn has_unbound_variables(&self) -> bool {
943 match self {
944 Type::Var { hint, .. } => hint.is_some(),
945 Type::Nominal { params, .. } => params.iter().any(|p| p.has_unbound_variables()),
946 Type::Function {
947 params,
948 return_type,
949 ..
950 } => {
951 params.iter().any(|p| p.has_unbound_variables())
952 || return_type.has_unbound_variables()
953 }
954 Type::Forall { body, .. } => body.has_unbound_variables(),
955 Type::Tuple(elements) => elements.iter().any(|e| e.has_unbound_variables()),
956 Type::Compound { args, .. } => args.iter().any(|a| a.has_unbound_variables()),
957 Type::Simple(_)
958 | Type::Parameter(_)
959 | Type::Never
960 | Type::Error
961 | Type::ImportNamespace(_)
962 | Type::ReceiverPlaceholder => false,
963 }
964 }
965
966 pub fn remove_found_type_names(&self, names: &mut HashSet<EcoString>) {
967 if names.is_empty() {
968 return;
969 }
970
971 match self {
972 Type::Nominal { id, params, .. } => {
973 names.remove(id.last_segment());
974 for param in params {
975 param.remove_found_type_names(names);
976 }
977 }
978 Type::Function {
979 params,
980 return_type,
981 bounds,
982 ..
983 } => {
984 for param in params {
985 param.remove_found_type_names(names);
986 }
987 return_type.remove_found_type_names(names);
988 for bound in bounds {
989 bound.generic.remove_found_type_names(names);
990 bound.ty.remove_found_type_names(names);
991 }
992 }
993 Type::Forall { body, .. } => {
994 body.remove_found_type_names(names);
995 }
996 Type::Var { .. } => {}
997 Type::Parameter(name) => {
998 names.remove(name);
999 }
1000 Type::Tuple(elements) => {
1001 for element in elements {
1002 element.remove_found_type_names(names);
1003 }
1004 }
1005 Type::Compound { kind, args } => {
1006 names.remove(kind.leaf_name());
1007 for arg in args {
1008 arg.remove_found_type_names(names);
1009 }
1010 }
1011 Type::Simple(kind) => {
1012 names.remove(kind.leaf_name());
1013 }
1014 Type::Never | Type::Error | Type::ImportNamespace(_) | Type::ReceiverPlaceholder => {}
1015 }
1016 }
1017}
1018
1019impl Type {
1020 pub fn get_name(&self) -> Option<&str> {
1021 match self {
1022 Type::Simple(kind) => Some(kind.leaf_name()),
1023 Type::Compound { kind, args } => match kind {
1024 CompoundKind::Ref => args.first().and_then(|inner| inner.get_name()),
1025 _ => Some(kind.leaf_name()),
1026 },
1027 Type::Nominal { id, params, .. } => {
1028 let name = id.last_segment();
1029 if CompoundKind::from_name(name) == Some(CompoundKind::Ref) {
1030 return params.first().and_then(|inner| inner.get_name());
1031 }
1032 Some(name)
1033 }
1034 Type::ImportNamespace(module_id) => {
1035 let path = module_id.strip_prefix("go:").unwrap_or(module_id);
1036 path.rsplit('/').next()
1037 }
1038 _ => None,
1039 }
1040 }
1041
1042 pub fn wraps(&self, name: &str, inner: &Type) -> bool {
1043 self.get_name().is_some_and(|n| n == name)
1044 && self
1045 .get_type_params()
1046 .and_then(|p| p.first())
1047 .is_some_and(|first| *first == *inner)
1048 }
1049
1050 pub fn get_function_params(&self) -> Option<&[Type]> {
1051 match self {
1052 Type::Function { params, .. } => Some(params),
1053 Type::Nominal {
1054 underlying_ty: Some(inner),
1055 ..
1056 } => inner.get_function_params(),
1057 _ => None,
1058 }
1059 }
1060
1061 pub fn param_count(&self) -> usize {
1062 match self {
1063 Type::Function { params, .. } => params.len(),
1064 _ => 0,
1065 }
1066 }
1067
1068 pub fn get_param_mutability(&self) -> &[bool] {
1069 match self {
1070 Type::Function {
1071 param_mutability, ..
1072 } => param_mutability,
1073 _ => &[],
1074 }
1075 }
1076
1077 pub fn with_replaced_first_param(&self, new_first: &Type) -> Type {
1078 match self {
1079 Type::Function {
1080 params,
1081 param_mutability,
1082 bounds,
1083 return_type,
1084 } => {
1085 if params.is_empty() {
1086 return self.clone();
1087 }
1088 let mut new_params = params.clone();
1089 new_params[0] = new_first.clone();
1090 Type::Function {
1091 params: new_params,
1092 param_mutability: param_mutability.clone(),
1093 bounds: bounds.clone(),
1094 return_type: return_type.clone(),
1095 }
1096 }
1097 Type::Forall { vars, body } => Type::Forall {
1098 vars: vars.clone(),
1099 body: Box::new(body.with_replaced_first_param(new_first)),
1100 },
1101 _ => self.clone(),
1102 }
1103 }
1104
1105 pub fn get_bounds(&self) -> &[Bound] {
1106 match self {
1107 Type::Function { bounds, .. } => bounds,
1108 Type::Forall { body, .. } => body.get_bounds(),
1109 _ => &[],
1110 }
1111 }
1112
1113 pub fn get_qualified_name(&self) -> Symbol {
1114 match self.strip_refs() {
1115 Type::Nominal { id, .. } => id,
1116 Type::Simple(kind) => Symbol::from_parts("prelude", kind.leaf_name()),
1117 Type::Compound { kind, .. } => Symbol::from_parts("prelude", kind.leaf_name()),
1118 _ => panic!("called get_qualified_name on {:#?}", self),
1119 }
1120 }
1121
1122 pub fn inner(&self) -> Option<Type> {
1123 self.get_type_params()
1124 .and_then(|args| args.first().cloned())
1125 }
1126
1127 pub fn ok_type(&self) -> Type {
1128 debug_assert!(
1129 self.is_result() || self.is_option() || self.is_partial(),
1130 "ok_type called on non-Result/Option/Partial type"
1131 );
1132 self.inner()
1133 .expect("Result/Option/Partial should have inner type")
1134 }
1135
1136 pub fn err_type(&self) -> Type {
1137 debug_assert!(
1138 self.is_result() || self.is_partial(),
1139 "err_type called on non-Result/Partial type"
1140 );
1141 self.get_type_params()
1142 .and_then(|args| args.get(1).cloned())
1143 .expect("Result/Partial should have error type")
1144 }
1145}
1146
1147impl Type {
1148 pub fn unwrap_forall(&self) -> &Type {
1149 match self {
1150 Type::Forall { body, .. } => body.as_ref(),
1151 other => other,
1152 }
1153 }
1154
1155 pub fn strip_refs(&self) -> Type {
1156 if self.is_ref() {
1157 return self.inner().expect("ref type must have inner").strip_refs();
1158 }
1159
1160 self.clone()
1161 }
1162
1163 pub fn with_receiver_placeholder(self) -> Type {
1164 match self {
1165 Type::Function {
1166 params,
1167 param_mutability,
1168 bounds,
1169 return_type,
1170 } => {
1171 let mut new_params = vec![Type::ReceiverPlaceholder];
1172 new_params.extend(params);
1173
1174 let mut new_mutability = vec![false];
1175 new_mutability.extend(param_mutability);
1176
1177 Type::Function {
1178 params: new_params,
1179 param_mutability: new_mutability,
1180 bounds,
1181 return_type,
1182 }
1183 }
1184 _ => unreachable!(
1185 "with_receiver_placeholder called on non-function type: {:?}",
1186 self
1187 ),
1188 }
1189 }
1190
1191 pub fn remove_vars(types: &[&Type]) -> (Vec<Type>, Vec<EcoString>) {
1192 let mut vars = HashMap::default();
1193 let types = types
1194 .iter()
1195 .map(|v| Self::remove_vars_impl(v, &mut vars))
1196 .collect();
1197
1198 (types, vars.into_values().collect())
1199 }
1200
1201 fn remove_vars_impl(ty: &Type, vars: &mut HashMap<u32, EcoString>) -> Type {
1202 match ty {
1203 Type::Nominal {
1204 id: name,
1205 params: args,
1206 underlying_ty: underlying,
1207 } => Type::Nominal {
1208 id: name.clone(),
1209 params: args
1210 .iter()
1211 .map(|a| Self::remove_vars_impl(a, vars))
1212 .collect(),
1213 underlying_ty: underlying
1214 .as_ref()
1215 .map(|u| Box::new(Self::remove_vars_impl(u, vars))),
1216 },
1217
1218 Type::Function {
1219 params: args,
1220 param_mutability,
1221 bounds,
1222 return_type,
1223 } => Type::Function {
1224 params: args
1225 .iter()
1226 .map(|a| Self::remove_vars_impl(a, vars))
1227 .collect(),
1228 param_mutability: param_mutability.clone(),
1229 bounds: bounds
1230 .iter()
1231 .map(|b| Bound {
1232 param_name: b.param_name.clone(),
1233 generic: Self::remove_vars_impl(&b.generic, vars),
1234 ty: Self::remove_vars_impl(&b.ty, vars),
1235 })
1236 .collect(),
1237 return_type: Self::remove_vars_impl(return_type, vars).into(),
1238 },
1239
1240 Type::Var { id, hint } => match vars.get(&id.0) {
1241 Some(g) => Type::Parameter(g.clone()),
1242 None => {
1243 let name: EcoString = hint.clone().unwrap_or_else(|| {
1244 char::from_digit(
1245 (vars.len() + 10)
1246 .try_into()
1247 .expect("type var count fits in u32"),
1248 16,
1249 )
1250 .expect("type var index is valid hex digit")
1251 .to_uppercase()
1252 .to_string()
1253 .into()
1254 });
1255
1256 vars.insert(id.0, name.clone());
1257 Type::Parameter(name)
1258 }
1259 },
1260
1261 Type::Forall { body, .. } => Self::remove_vars_impl(body, vars),
1262 Type::Tuple(elements) => Type::Tuple(
1263 elements
1264 .iter()
1265 .map(|e| Self::remove_vars_impl(e, vars))
1266 .collect(),
1267 ),
1268 Type::Compound { kind, args } => Type::Compound {
1269 kind: *kind,
1270 args: args
1271 .iter()
1272 .map(|a| Self::remove_vars_impl(a, vars))
1273 .collect(),
1274 },
1275 Type::Simple(_) | Type::Parameter(_) => ty.clone(),
1276 Type::Never | Type::Error | Type::ImportNamespace(_) | Type::ReceiverPlaceholder => {
1277 ty.clone()
1278 }
1279 }
1280 }
1281
1282 pub fn contains_type(&self, target: &Type) -> bool {
1283 if *self == *target {
1284 return true;
1285 }
1286 match self {
1287 Type::Nominal { params, .. } => params.iter().any(|p| p.contains_type(target)),
1288 Type::Function {
1289 params,
1290 return_type,
1291 ..
1292 } => {
1293 params.iter().any(|p| p.contains_type(target)) || return_type.contains_type(target)
1294 }
1295 Type::Var { .. } => false,
1296 Type::Forall { body, .. } => body.contains_type(target),
1297 Type::Tuple(elements) => elements.iter().any(|e| e.contains_type(target)),
1298 Type::Compound { args, .. } => args.iter().any(|a| a.contains_type(target)),
1299 Type::Simple(_)
1300 | Type::Parameter(_)
1301 | Type::Never
1302 | Type::Error
1303 | Type::ImportNamespace(_)
1304 | Type::ReceiverPlaceholder => false,
1305 }
1306 }
1307}
1308
1309impl Type {
1310 pub fn underlying_numeric_type(&self) -> Option<Type> {
1311 self.underlying_numeric_type_recursive(&mut HashSet::default())
1312 }
1313
1314 pub fn has_underlying_numeric_type(&self) -> bool {
1315 self.underlying_numeric_type().is_some()
1316 }
1317
1318 fn underlying_numeric_type_recursive(&self, visited: &mut HashSet<Symbol>) -> Option<Type> {
1319 match self {
1320 Type::Simple(_) if self.is_numeric() => Some(self.clone()),
1321 Type::Nominal {
1322 id,
1323 underlying_ty: underlying,
1324 ..
1325 } => {
1326 if self.is_numeric() {
1327 return Some(self.clone());
1328 }
1329
1330 if !visited.insert(id.clone()) {
1331 return None;
1332 }
1333
1334 underlying
1335 .as_ref()?
1336 .underlying_numeric_type_recursive(visited)
1337 }
1338 _ => None,
1339 }
1340 }
1341
1342 pub fn numeric_family(&self) -> Option<NumericFamily> {
1343 self.as_simple()?.numeric_family()
1344 }
1345
1346 pub fn is_numeric_compatible_with(&self, other: &Type) -> bool {
1347 let self_underlying_ty = self.underlying_numeric_type();
1348 let other_underlying_ty = other.underlying_numeric_type();
1349
1350 match (self_underlying_ty, other_underlying_ty) {
1351 (Some(s), Some(o)) => s.numeric_family() == o.numeric_family(),
1352 _ => false,
1353 }
1354 }
1355
1356 pub fn is_aliased_numeric_type(&self) -> bool {
1357 match self {
1358 Type::Nominal { underlying_ty, .. } => {
1359 underlying_ty.is_some() && !self.is_numeric() && self.has_underlying_numeric_type()
1360 }
1361 _ => false,
1362 }
1363 }
1364}