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 is_complex(&self) -> bool {
895 self.as_simple().is_some_and(SimpleKind::is_complex)
896 }
897
898 pub fn is_unsigned_int(&self) -> bool {
899 self.as_simple().is_some_and(SimpleKind::is_unsigned_int)
900 }
901
902 pub fn is_never(&self) -> bool {
903 matches!(self, Type::Never)
904 }
905
906 pub fn is_error(&self) -> bool {
907 matches!(self, Type::Error)
908 }
909
910 pub fn has_unbound_variables(&self) -> bool {
911 match self {
912 Type::Var { hint, .. } => hint.is_some(),
913 Type::Nominal { params, .. } => params.iter().any(|p| p.has_unbound_variables()),
914 Type::Function {
915 params,
916 return_type,
917 ..
918 } => {
919 params.iter().any(|p| p.has_unbound_variables())
920 || return_type.has_unbound_variables()
921 }
922 Type::Forall { body, .. } => body.has_unbound_variables(),
923 Type::Tuple(elements) => elements.iter().any(|e| e.has_unbound_variables()),
924 Type::Compound { args, .. } => args.iter().any(|a| a.has_unbound_variables()),
925 Type::Simple(_)
926 | Type::Parameter(_)
927 | Type::Never
928 | Type::Error
929 | Type::ImportNamespace(_)
930 | Type::ReceiverPlaceholder => false,
931 }
932 }
933
934 pub fn remove_found_type_names(&self, names: &mut HashSet<EcoString>) {
935 if names.is_empty() {
936 return;
937 }
938
939 match self {
940 Type::Nominal { id, params, .. } => {
941 names.remove(id.last_segment());
942 for param in params {
943 param.remove_found_type_names(names);
944 }
945 }
946 Type::Function {
947 params,
948 return_type,
949 bounds,
950 ..
951 } => {
952 for param in params {
953 param.remove_found_type_names(names);
954 }
955 return_type.remove_found_type_names(names);
956 for bound in bounds {
957 bound.generic.remove_found_type_names(names);
958 bound.ty.remove_found_type_names(names);
959 }
960 }
961 Type::Forall { body, .. } => {
962 body.remove_found_type_names(names);
963 }
964 Type::Var { .. } => {}
965 Type::Parameter(name) => {
966 names.remove(name);
967 }
968 Type::Tuple(elements) => {
969 for element in elements {
970 element.remove_found_type_names(names);
971 }
972 }
973 Type::Compound { kind, args } => {
974 names.remove(kind.leaf_name());
975 for arg in args {
976 arg.remove_found_type_names(names);
977 }
978 }
979 Type::Simple(kind) => {
980 names.remove(kind.leaf_name());
981 }
982 Type::Never | Type::Error | Type::ImportNamespace(_) | Type::ReceiverPlaceholder => {}
983 }
984 }
985}
986
987impl Type {
988 pub fn get_name(&self) -> Option<&str> {
989 match self {
990 Type::Simple(kind) => Some(kind.leaf_name()),
991 Type::Compound { kind, args } => match kind {
992 CompoundKind::Ref => args.first().and_then(|inner| inner.get_name()),
993 _ => Some(kind.leaf_name()),
994 },
995 Type::Nominal { id, params, .. } => {
996 let name = id.last_segment();
997 if CompoundKind::from_name(name) == Some(CompoundKind::Ref) {
998 return params.first().and_then(|inner| inner.get_name());
999 }
1000 Some(name)
1001 }
1002 Type::ImportNamespace(module_id) => {
1003 let path = module_id.strip_prefix("go:").unwrap_or(module_id);
1004 path.rsplit('/').next()
1005 }
1006 _ => None,
1007 }
1008 }
1009
1010 pub fn wraps(&self, name: &str, inner: &Type) -> bool {
1011 self.get_name().is_some_and(|n| n == name)
1012 && self
1013 .get_type_params()
1014 .and_then(|p| p.first())
1015 .is_some_and(|first| *first == *inner)
1016 }
1017
1018 pub fn get_function_params(&self) -> Option<&[Type]> {
1019 match self {
1020 Type::Function { params, .. } => Some(params),
1021 Type::Nominal {
1022 underlying_ty: Some(inner),
1023 ..
1024 } => inner.get_function_params(),
1025 _ => None,
1026 }
1027 }
1028
1029 pub fn param_count(&self) -> usize {
1030 match self {
1031 Type::Function { params, .. } => params.len(),
1032 _ => 0,
1033 }
1034 }
1035
1036 pub fn get_param_mutability(&self) -> &[bool] {
1037 match self {
1038 Type::Function {
1039 param_mutability, ..
1040 } => param_mutability,
1041 _ => &[],
1042 }
1043 }
1044
1045 pub fn with_replaced_first_param(&self, new_first: &Type) -> Type {
1046 match self {
1047 Type::Function {
1048 params,
1049 param_mutability,
1050 bounds,
1051 return_type,
1052 } => {
1053 if params.is_empty() {
1054 return self.clone();
1055 }
1056 let mut new_params = params.clone();
1057 new_params[0] = new_first.clone();
1058 Type::Function {
1059 params: new_params,
1060 param_mutability: param_mutability.clone(),
1061 bounds: bounds.clone(),
1062 return_type: return_type.clone(),
1063 }
1064 }
1065 Type::Forall { vars, body } => Type::Forall {
1066 vars: vars.clone(),
1067 body: Box::new(body.with_replaced_first_param(new_first)),
1068 },
1069 _ => self.clone(),
1070 }
1071 }
1072
1073 pub fn get_bounds(&self) -> &[Bound] {
1074 match self {
1075 Type::Function { bounds, .. } => bounds,
1076 Type::Forall { body, .. } => body.get_bounds(),
1077 _ => &[],
1078 }
1079 }
1080
1081 pub fn get_qualified_name(&self) -> Symbol {
1082 match self.strip_refs() {
1083 Type::Nominal { id, .. } => id,
1084 Type::Simple(kind) => Symbol::from_parts("prelude", kind.leaf_name()),
1085 Type::Compound { kind, .. } => Symbol::from_parts("prelude", kind.leaf_name()),
1086 _ => panic!("called get_qualified_name on {:#?}", self),
1087 }
1088 }
1089
1090 pub fn inner(&self) -> Option<Type> {
1091 self.get_type_params()
1092 .and_then(|args| args.first().cloned())
1093 }
1094
1095 pub fn ok_type(&self) -> Type {
1096 debug_assert!(
1097 self.is_result() || self.is_option() || self.is_partial(),
1098 "ok_type called on non-Result/Option/Partial type"
1099 );
1100 self.inner()
1101 .expect("Result/Option/Partial should have inner type")
1102 }
1103
1104 pub fn err_type(&self) -> Type {
1105 debug_assert!(
1106 self.is_result() || self.is_partial(),
1107 "err_type called on non-Result/Partial type"
1108 );
1109 self.get_type_params()
1110 .and_then(|args| args.get(1).cloned())
1111 .expect("Result/Partial should have error type")
1112 }
1113}
1114
1115impl Type {
1116 pub fn unwrap_forall(&self) -> &Type {
1117 match self {
1118 Type::Forall { body, .. } => body.as_ref(),
1119 other => other,
1120 }
1121 }
1122
1123 pub fn strip_refs(&self) -> Type {
1124 if self.is_ref() {
1125 return self.inner().expect("ref type must have inner").strip_refs();
1126 }
1127
1128 self.clone()
1129 }
1130
1131 pub fn with_receiver_placeholder(self) -> Type {
1132 match self {
1133 Type::Function {
1134 params,
1135 param_mutability,
1136 bounds,
1137 return_type,
1138 } => {
1139 let mut new_params = vec![Type::ReceiverPlaceholder];
1140 new_params.extend(params);
1141
1142 let mut new_mutability = vec![false];
1143 new_mutability.extend(param_mutability);
1144
1145 Type::Function {
1146 params: new_params,
1147 param_mutability: new_mutability,
1148 bounds,
1149 return_type,
1150 }
1151 }
1152 _ => unreachable!(
1153 "with_receiver_placeholder called on non-function type: {:?}",
1154 self
1155 ),
1156 }
1157 }
1158
1159 pub fn remove_vars(types: &[&Type]) -> (Vec<Type>, Vec<EcoString>) {
1160 let mut vars = HashMap::default();
1161 let types = types
1162 .iter()
1163 .map(|v| Self::remove_vars_impl(v, &mut vars))
1164 .collect();
1165
1166 (types, vars.into_values().collect())
1167 }
1168
1169 fn remove_vars_impl(ty: &Type, vars: &mut HashMap<u32, EcoString>) -> Type {
1170 match ty {
1171 Type::Nominal {
1172 id: name,
1173 params: args,
1174 underlying_ty: underlying,
1175 } => Type::Nominal {
1176 id: name.clone(),
1177 params: args
1178 .iter()
1179 .map(|a| Self::remove_vars_impl(a, vars))
1180 .collect(),
1181 underlying_ty: underlying
1182 .as_ref()
1183 .map(|u| Box::new(Self::remove_vars_impl(u, vars))),
1184 },
1185
1186 Type::Function {
1187 params: args,
1188 param_mutability,
1189 bounds,
1190 return_type,
1191 } => Type::Function {
1192 params: args
1193 .iter()
1194 .map(|a| Self::remove_vars_impl(a, vars))
1195 .collect(),
1196 param_mutability: param_mutability.clone(),
1197 bounds: bounds
1198 .iter()
1199 .map(|b| Bound {
1200 param_name: b.param_name.clone(),
1201 generic: Self::remove_vars_impl(&b.generic, vars),
1202 ty: Self::remove_vars_impl(&b.ty, vars),
1203 })
1204 .collect(),
1205 return_type: Self::remove_vars_impl(return_type, vars).into(),
1206 },
1207
1208 Type::Var { id, hint } => match vars.get(&id.0) {
1209 Some(g) => Type::Parameter(g.clone()),
1210 None => {
1211 let name: EcoString = hint.clone().unwrap_or_else(|| {
1212 char::from_digit(
1213 (vars.len() + 10)
1214 .try_into()
1215 .expect("type var count fits in u32"),
1216 16,
1217 )
1218 .expect("type var index is valid hex digit")
1219 .to_uppercase()
1220 .to_string()
1221 .into()
1222 });
1223
1224 vars.insert(id.0, name.clone());
1225 Type::Parameter(name)
1226 }
1227 },
1228
1229 Type::Forall { body, .. } => Self::remove_vars_impl(body, vars),
1230 Type::Tuple(elements) => Type::Tuple(
1231 elements
1232 .iter()
1233 .map(|e| Self::remove_vars_impl(e, vars))
1234 .collect(),
1235 ),
1236 Type::Compound { kind, args } => Type::Compound {
1237 kind: *kind,
1238 args: args
1239 .iter()
1240 .map(|a| Self::remove_vars_impl(a, vars))
1241 .collect(),
1242 },
1243 Type::Simple(_) | Type::Parameter(_) => ty.clone(),
1244 Type::Never | Type::Error | Type::ImportNamespace(_) | Type::ReceiverPlaceholder => {
1245 ty.clone()
1246 }
1247 }
1248 }
1249
1250 pub fn contains_type(&self, target: &Type) -> bool {
1251 if *self == *target {
1252 return true;
1253 }
1254 match self {
1255 Type::Nominal { params, .. } => params.iter().any(|p| p.contains_type(target)),
1256 Type::Function {
1257 params,
1258 return_type,
1259 ..
1260 } => {
1261 params.iter().any(|p| p.contains_type(target)) || return_type.contains_type(target)
1262 }
1263 Type::Var { .. } => false,
1264 Type::Forall { body, .. } => body.contains_type(target),
1265 Type::Tuple(elements) => elements.iter().any(|e| e.contains_type(target)),
1266 Type::Compound { args, .. } => args.iter().any(|a| a.contains_type(target)),
1267 Type::Simple(_)
1268 | Type::Parameter(_)
1269 | Type::Never
1270 | Type::Error
1271 | Type::ImportNamespace(_)
1272 | Type::ReceiverPlaceholder => false,
1273 }
1274 }
1275}
1276
1277impl Type {
1278 pub fn underlying_numeric_type(&self) -> Option<Type> {
1279 self.underlying_numeric_type_recursive(&mut HashSet::default())
1280 }
1281
1282 pub fn has_underlying_numeric_type(&self) -> bool {
1283 self.underlying_numeric_type().is_some()
1284 }
1285
1286 fn underlying_numeric_type_recursive(&self, visited: &mut HashSet<Symbol>) -> Option<Type> {
1287 match self {
1288 Type::Simple(_) if self.is_numeric() => Some(self.clone()),
1289 Type::Nominal {
1290 id,
1291 underlying_ty: underlying,
1292 ..
1293 } => {
1294 if self.is_numeric() {
1295 return Some(self.clone());
1296 }
1297
1298 if !visited.insert(id.clone()) {
1299 return None;
1300 }
1301
1302 underlying
1303 .as_ref()?
1304 .underlying_numeric_type_recursive(visited)
1305 }
1306 _ => None,
1307 }
1308 }
1309
1310 pub fn numeric_family(&self) -> Option<NumericFamily> {
1311 self.as_simple()?.numeric_family()
1312 }
1313
1314 pub fn is_numeric_compatible_with(&self, other: &Type) -> bool {
1315 let self_underlying_ty = self.underlying_numeric_type();
1316 let other_underlying_ty = other.underlying_numeric_type();
1317
1318 match (self_underlying_ty, other_underlying_ty) {
1319 (Some(s), Some(o)) => s.numeric_family() == o.numeric_family(),
1320 _ => false,
1321 }
1322 }
1323
1324 pub fn is_aliased_numeric_type(&self) -> bool {
1325 match self {
1326 Type::Nominal { underlying_ty, .. } => {
1327 underlying_ty.is_some() && !self.is_numeric() && self.has_underlying_numeric_type()
1328 }
1329 _ => false,
1330 }
1331 }
1332}