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
1147pub fn peel_alias<F>(ty: &Type, is_alias: F) -> Type
1150where
1151 F: Fn(&str) -> bool,
1152{
1153 let mut current = ty.unwrap_forall().clone();
1154 let mut seen: Vec<String> = Vec::new();
1155 while let Type::Nominal {
1156 id,
1157 underlying_ty: Some(u),
1158 ..
1159 } = ¤t
1160 {
1161 if !is_alias(id.as_str()) {
1162 break;
1163 }
1164 if seen.iter().any(|s| s == id.as_str()) {
1165 break;
1166 }
1167 seen.push(id.to_string());
1168 current = u.unwrap_forall().clone();
1169 }
1170 current
1171}
1172
1173pub fn peel_alias_id<F>(id: &str, next_alias: F) -> String
1176where
1177 F: Fn(&str) -> Option<String>,
1178{
1179 let mut current = id.to_string();
1180 let mut seen: Vec<String> = Vec::new();
1181 loop {
1182 if seen.iter().any(|s| s == ¤t) {
1183 return current;
1184 }
1185 let Some(next) = next_alias(¤t) else {
1186 return current;
1187 };
1188 seen.push(current);
1189 current = next;
1190 }
1191}
1192
1193impl Type {
1194 pub fn unwrap_forall(&self) -> &Type {
1195 match self {
1196 Type::Forall { body, .. } => body.as_ref(),
1197 other => other,
1198 }
1199 }
1200
1201 pub fn strip_refs(&self) -> Type {
1202 if self.is_ref() {
1203 return self.inner().expect("ref type must have inner").strip_refs();
1204 }
1205
1206 self.clone()
1207 }
1208
1209 pub fn with_receiver_placeholder(self) -> Type {
1210 match self {
1211 Type::Function {
1212 params,
1213 param_mutability,
1214 bounds,
1215 return_type,
1216 } => {
1217 let mut new_params = vec![Type::ReceiverPlaceholder];
1218 new_params.extend(params);
1219
1220 let mut new_mutability = vec![false];
1221 new_mutability.extend(param_mutability);
1222
1223 Type::Function {
1224 params: new_params,
1225 param_mutability: new_mutability,
1226 bounds,
1227 return_type,
1228 }
1229 }
1230 _ => unreachable!(
1231 "with_receiver_placeholder called on non-function type: {:?}",
1232 self
1233 ),
1234 }
1235 }
1236
1237 pub fn remove_vars(types: &[&Type]) -> (Vec<Type>, Vec<EcoString>) {
1238 let mut vars = HashMap::default();
1239 let types = types
1240 .iter()
1241 .map(|v| Self::remove_vars_impl(v, &mut vars))
1242 .collect();
1243
1244 (types, vars.into_values().collect())
1245 }
1246
1247 fn remove_vars_impl(ty: &Type, vars: &mut HashMap<u32, EcoString>) -> Type {
1248 match ty {
1249 Type::Nominal {
1250 id: name,
1251 params: args,
1252 underlying_ty: underlying,
1253 } => Type::Nominal {
1254 id: name.clone(),
1255 params: args
1256 .iter()
1257 .map(|a| Self::remove_vars_impl(a, vars))
1258 .collect(),
1259 underlying_ty: underlying
1260 .as_ref()
1261 .map(|u| Box::new(Self::remove_vars_impl(u, vars))),
1262 },
1263
1264 Type::Function {
1265 params: args,
1266 param_mutability,
1267 bounds,
1268 return_type,
1269 } => Type::Function {
1270 params: args
1271 .iter()
1272 .map(|a| Self::remove_vars_impl(a, vars))
1273 .collect(),
1274 param_mutability: param_mutability.clone(),
1275 bounds: bounds
1276 .iter()
1277 .map(|b| Bound {
1278 param_name: b.param_name.clone(),
1279 generic: Self::remove_vars_impl(&b.generic, vars),
1280 ty: Self::remove_vars_impl(&b.ty, vars),
1281 })
1282 .collect(),
1283 return_type: Self::remove_vars_impl(return_type, vars).into(),
1284 },
1285
1286 Type::Var { id, hint } => match vars.get(&id.0) {
1287 Some(g) => Type::Parameter(g.clone()),
1288 None => {
1289 let name: EcoString = hint
1290 .clone()
1291 .unwrap_or_else(|| alpha_index(vars.len()).into());
1292
1293 vars.insert(id.0, name.clone());
1294 Type::Parameter(name)
1295 }
1296 },
1297
1298 Type::Forall { body, .. } => Self::remove_vars_impl(body, vars),
1299 Type::Tuple(elements) => Type::Tuple(
1300 elements
1301 .iter()
1302 .map(|e| Self::remove_vars_impl(e, vars))
1303 .collect(),
1304 ),
1305 Type::Compound { kind, args } => Type::Compound {
1306 kind: *kind,
1307 args: args
1308 .iter()
1309 .map(|a| Self::remove_vars_impl(a, vars))
1310 .collect(),
1311 },
1312 Type::Simple(_) | Type::Parameter(_) => ty.clone(),
1313 Type::Never | Type::Error | Type::ImportNamespace(_) | Type::ReceiverPlaceholder => {
1314 ty.clone()
1315 }
1316 }
1317 }
1318
1319 pub fn contains_type(&self, target: &Type) -> bool {
1320 if *self == *target {
1321 return true;
1322 }
1323 match self {
1324 Type::Nominal { params, .. } => params.iter().any(|p| p.contains_type(target)),
1325 Type::Function {
1326 params,
1327 return_type,
1328 ..
1329 } => {
1330 params.iter().any(|p| p.contains_type(target)) || return_type.contains_type(target)
1331 }
1332 Type::Var { .. } => false,
1333 Type::Forall { body, .. } => body.contains_type(target),
1334 Type::Tuple(elements) => elements.iter().any(|e| e.contains_type(target)),
1335 Type::Compound { args, .. } => args.iter().any(|a| a.contains_type(target)),
1336 Type::Simple(_)
1337 | Type::Parameter(_)
1338 | Type::Never
1339 | Type::Error
1340 | Type::ImportNamespace(_)
1341 | Type::ReceiverPlaceholder => false,
1342 }
1343 }
1344}
1345
1346impl Type {
1347 pub fn underlying_numeric_type(&self) -> Option<Type> {
1348 self.underlying_numeric_type_recursive(&mut HashSet::default())
1349 }
1350
1351 pub fn has_underlying_numeric_type(&self) -> bool {
1352 self.underlying_numeric_type().is_some()
1353 }
1354
1355 fn underlying_numeric_type_recursive(&self, visited: &mut HashSet<Symbol>) -> Option<Type> {
1356 match self {
1357 Type::Simple(_) if self.is_numeric() => Some(self.clone()),
1358 Type::Nominal {
1359 id,
1360 underlying_ty: underlying,
1361 ..
1362 } => {
1363 if self.is_numeric() {
1364 return Some(self.clone());
1365 }
1366
1367 if !visited.insert(id.clone()) {
1368 return None;
1369 }
1370
1371 underlying
1372 .as_ref()?
1373 .underlying_numeric_type_recursive(visited)
1374 }
1375 _ => None,
1376 }
1377 }
1378
1379 pub fn numeric_family(&self) -> Option<NumericFamily> {
1380 self.as_simple()?.numeric_family()
1381 }
1382
1383 pub fn is_numeric_compatible_with(&self, other: &Type) -> bool {
1384 let self_underlying_ty = self.underlying_numeric_type();
1385 let other_underlying_ty = other.underlying_numeric_type();
1386
1387 match (self_underlying_ty, other_underlying_ty) {
1388 (Some(s), Some(o)) => s.numeric_family() == o.numeric_family(),
1389 _ => false,
1390 }
1391 }
1392
1393 pub fn is_aliased_numeric_type(&self) -> bool {
1394 match self {
1395 Type::Nominal { underlying_ty, .. } => {
1396 underlying_ty.is_some() && !self.is_numeric() && self.has_underlying_numeric_type()
1397 }
1398 _ => false,
1399 }
1400 }
1401}
1402
1403fn alpha_index(idx: usize) -> String {
1405 let mut s = String::new();
1406 let mut n = idx + 1;
1407 while n > 0 {
1408 n -= 1;
1409 s.insert(0, (b'A' + (n % 26) as u8) as char);
1410 n /= 26;
1411 }
1412 s
1413}
1414
1415#[cfg(test)]
1416mod tests {
1417 use super::*;
1418
1419 #[test]
1420 fn alpha_index_single() {
1421 assert_eq!(alpha_index(0), "A");
1422 assert_eq!(alpha_index(5), "F");
1423 assert_eq!(alpha_index(25), "Z");
1424 }
1425
1426 #[test]
1427 fn alpha_index_double() {
1428 assert_eq!(alpha_index(26), "AA");
1429 assert_eq!(alpha_index(27), "AB");
1430 assert_eq!(alpha_index(51), "AZ");
1431 assert_eq!(alpha_index(52), "BA");
1432 assert_eq!(alpha_index(701), "ZZ");
1433 }
1434
1435 #[test]
1436 fn alpha_index_triple() {
1437 assert_eq!(alpha_index(702), "AAA");
1438 }
1439
1440 fn unhinted_var(id: u32) -> Type {
1441 Type::Var {
1442 id: TypeVarId(id),
1443 hint: None,
1444 }
1445 }
1446
1447 #[test]
1448 fn remove_vars_handles_more_than_six_unhinted_vars() {
1449 let func = Type::Function {
1450 params: (0..6).map(unhinted_var).collect(),
1451 param_mutability: vec![false; 6],
1452 bounds: vec![],
1453 return_type: Box::new(unhinted_var(6)),
1454 };
1455
1456 let (resolved, generics) = Type::remove_vars(&[&func]);
1457
1458 assert_eq!(generics.len(), 7);
1459 let Type::Function {
1460 params,
1461 return_type,
1462 ..
1463 } = &resolved[0]
1464 else {
1465 panic!("expected function type");
1466 };
1467 let names: Vec<_> = params
1468 .iter()
1469 .chain(std::iter::once(return_type.as_ref()))
1470 .map(|p| match p {
1471 Type::Parameter(name) => name.to_string(),
1472 other => panic!("expected parameter, got {:?}", other),
1473 })
1474 .collect();
1475 assert_eq!(names, vec!["A", "B", "C", "D", "E", "F", "G"]);
1476 }
1477
1478 #[test]
1479 fn remove_vars_handles_dozens_of_unhinted_vars() {
1480 let params: Vec<Type> = (0..30).map(unhinted_var).collect();
1481 let func = Type::Function {
1482 params: params.clone(),
1483 param_mutability: vec![false; params.len()],
1484 bounds: vec![],
1485 return_type: Box::new(Type::Simple(SimpleKind::Unit)),
1486 };
1487 let (_, generics) = Type::remove_vars(&[&func]);
1488 assert_eq!(generics.len(), 30);
1489 }
1490}