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 resolves_to_unknown(&self) -> bool {
789 peel_alias(self, |_| true).is_unknown()
790 }
791
792 pub fn contains_unknown(&self) -> bool {
793 let peeled = peel_alias(self, |_| true);
794 if peeled.is_unknown() {
795 return true;
796 }
797 match &peeled {
798 Type::Compound { args, .. } => args.iter().any(|a| a.contains_unknown()),
799 Type::Function {
800 params,
801 return_type,
802 ..
803 } => params.iter().any(|p| p.contains_unknown()) || return_type.contains_unknown(),
804 Type::Tuple(elements) => elements.iter().any(|e| e.contains_unknown()),
805 Type::Nominal { params, .. } => params.iter().any(|p| p.contains_unknown()),
806 Type::Forall { body, .. } => body.contains_unknown(),
807 _ => false,
808 }
809 }
810
811 pub fn is_receiver(&self) -> bool {
812 self.is_native(CompoundKind::Receiver)
813 }
814
815 pub fn is_ignored(&self) -> bool {
816 matches!(self, Type::Var { id, .. } if *id == TypeVarId::IGNORED)
817 }
818
819 pub fn is_variadic(&self) -> Option<Type> {
820 let last = self.get_function_params()?.last()?;
821 match last.as_compound()? {
822 (CompoundKind::VarArgs, _) => last.inner(),
823 _ => None,
824 }
825 }
826
827 pub fn is_string(&self) -> bool {
828 self.is_simple(SimpleKind::String)
829 }
830
831 pub fn is_slice_of_simple(&self, element: SimpleKind) -> bool {
832 match self.as_compound() {
833 Some((CompoundKind::Slice, [elem])) => elem.is_simple(element),
834 _ => false,
835 }
836 }
837
838 pub fn is_slice_of(&self, element_name: &str) -> bool {
839 match self.as_compound() {
840 Some((CompoundKind::Slice, [elem])) => elem.has_name(element_name),
841 _ => false,
842 }
843 }
844
845 pub fn is_byte_slice(&self) -> bool {
846 self.is_slice_of_simple(SimpleKind::Byte) || self.is_slice_of_simple(SimpleKind::Uint8)
847 }
848
849 pub fn is_rune_slice(&self) -> bool {
850 self.is_slice_of_simple(SimpleKind::Rune)
851 }
852
853 pub fn is_byte_or_rune_slice(&self) -> bool {
854 self.is_byte_slice() || self.is_rune_slice()
855 }
856
857 pub fn has_byte_or_rune_slice_underlying(&self) -> bool {
858 if self.is_byte_or_rune_slice() {
859 return true;
860 }
861 match self {
862 Type::Nominal { underlying_ty, .. } => underlying_ty
863 .as_deref()
864 .is_some_and(|u| u.has_byte_or_rune_slice_underlying()),
865 _ => false,
866 }
867 }
868
869 pub fn as_simple(&self) -> Option<SimpleKind> {
870 match self {
871 Type::Simple(kind) => Some(*kind),
872 Type::Nominal { id, .. } => SimpleKind::from_name(id.last_segment()),
873 _ => None,
874 }
875 }
876
877 pub fn is_simple(&self, kind: SimpleKind) -> bool {
878 self.as_simple() == Some(kind)
879 }
880
881 pub fn is_boolean(&self) -> bool {
882 self.is_simple(SimpleKind::Bool)
883 }
884
885 pub fn is_rune(&self) -> bool {
886 self.is_simple(SimpleKind::Rune)
887 }
888
889 pub fn is_float64(&self) -> bool {
890 self.is_simple(SimpleKind::Float64)
891 }
892
893 pub fn is_float32(&self) -> bool {
894 self.is_simple(SimpleKind::Float32)
895 }
896
897 pub fn is_float(&self) -> bool {
898 self.as_simple().is_some_and(SimpleKind::is_float)
899 }
900
901 pub fn is_variable(&self) -> bool {
902 matches!(self, Type::Var { .. })
903 }
904
905 pub fn is_type_var(&self) -> bool {
906 matches!(self, Type::Var { .. })
907 }
908
909 pub fn is_numeric(&self) -> bool {
910 self.as_simple().is_some_and(SimpleKind::is_arithmetic)
911 }
912
913 pub fn is_ordered(&self) -> bool {
914 self.as_simple().is_some_and(SimpleKind::is_ordered)
915 }
916
917 pub fn satisfies_ordered_constraint(&self) -> bool {
919 if let Some(kind) = self.as_simple() {
920 return matches!(
921 kind,
922 SimpleKind::Int
923 | SimpleKind::Int8
924 | SimpleKind::Int16
925 | SimpleKind::Int32
926 | SimpleKind::Int64
927 | SimpleKind::Uint
928 | SimpleKind::Uint8
929 | SimpleKind::Uint16
930 | SimpleKind::Uint32
931 | SimpleKind::Uint64
932 | SimpleKind::Uintptr
933 | SimpleKind::Byte
934 | SimpleKind::Rune
935 | SimpleKind::Float32
936 | SimpleKind::Float64
937 | SimpleKind::String
938 );
939 }
940 match self {
941 Type::Nominal { underlying_ty, .. } => underlying_ty
942 .as_deref()
943 .is_some_and(Type::satisfies_ordered_constraint),
944 Type::Parameter(_) => true,
945 _ => false,
946 }
947 }
948
949 pub fn is_complex(&self) -> bool {
950 self.as_simple().is_some_and(SimpleKind::is_complex)
951 }
952
953 pub fn is_unsigned_int(&self) -> bool {
954 self.as_simple().is_some_and(SimpleKind::is_unsigned_int)
955 }
956
957 pub fn is_never(&self) -> bool {
958 matches!(self, Type::Never)
959 }
960
961 pub fn is_error(&self) -> bool {
962 matches!(self, Type::Error)
963 }
964
965 pub fn contains_error(&self) -> bool {
966 match self {
967 Type::Error => true,
968 Type::Nominal {
969 params,
970 underlying_ty,
971 ..
972 } => {
973 params.iter().any(Type::contains_error)
974 || underlying_ty.as_deref().is_some_and(Type::contains_error)
975 }
976 Type::Compound { args, .. } => args.iter().any(Type::contains_error),
977 Type::Function {
978 params,
979 return_type,
980 ..
981 } => params.iter().any(Type::contains_error) || return_type.contains_error(),
982 Type::Tuple(elements) => elements.iter().any(Type::contains_error),
983 Type::Forall { body, .. } => body.contains_error(),
984 _ => false,
985 }
986 }
987
988 pub fn has_unbound_variables(&self) -> bool {
989 match self {
990 Type::Var { hint, .. } => hint.is_some(),
991 Type::Nominal { params, .. } => params.iter().any(|p| p.has_unbound_variables()),
992 Type::Function {
993 params,
994 return_type,
995 ..
996 } => {
997 params.iter().any(|p| p.has_unbound_variables())
998 || return_type.has_unbound_variables()
999 }
1000 Type::Forall { body, .. } => body.has_unbound_variables(),
1001 Type::Tuple(elements) => elements.iter().any(|e| e.has_unbound_variables()),
1002 Type::Compound { args, .. } => args.iter().any(|a| a.has_unbound_variables()),
1003 Type::Simple(_)
1004 | Type::Parameter(_)
1005 | Type::Never
1006 | Type::Error
1007 | Type::ImportNamespace(_)
1008 | Type::ReceiverPlaceholder => false,
1009 }
1010 }
1011
1012 pub fn remove_found_type_names(&self, names: &mut HashSet<EcoString>) {
1013 if names.is_empty() {
1014 return;
1015 }
1016
1017 match self {
1018 Type::Nominal { id, params, .. } => {
1019 names.remove(id.last_segment());
1020 for param in params {
1021 param.remove_found_type_names(names);
1022 }
1023 }
1024 Type::Function {
1025 params,
1026 return_type,
1027 bounds,
1028 ..
1029 } => {
1030 for param in params {
1031 param.remove_found_type_names(names);
1032 }
1033 return_type.remove_found_type_names(names);
1034 for bound in bounds {
1035 bound.generic.remove_found_type_names(names);
1036 bound.ty.remove_found_type_names(names);
1037 }
1038 }
1039 Type::Forall { body, .. } => {
1040 body.remove_found_type_names(names);
1041 }
1042 Type::Var { .. } => {}
1043 Type::Parameter(name) => {
1044 names.remove(name);
1045 }
1046 Type::Tuple(elements) => {
1047 for element in elements {
1048 element.remove_found_type_names(names);
1049 }
1050 }
1051 Type::Compound { kind, args } => {
1052 names.remove(kind.leaf_name());
1053 for arg in args {
1054 arg.remove_found_type_names(names);
1055 }
1056 }
1057 Type::Simple(kind) => {
1058 names.remove(kind.leaf_name());
1059 }
1060 Type::Never | Type::Error | Type::ImportNamespace(_) | Type::ReceiverPlaceholder => {}
1061 }
1062 }
1063}
1064
1065impl Type {
1066 pub fn get_name(&self) -> Option<&str> {
1067 match self {
1068 Type::Simple(kind) => Some(kind.leaf_name()),
1069 Type::Compound { kind, args } => match kind {
1070 CompoundKind::Ref => args.first().and_then(|inner| inner.get_name()),
1071 _ => Some(kind.leaf_name()),
1072 },
1073 Type::Nominal { id, params, .. } => {
1074 let name = id.last_segment();
1075 if CompoundKind::from_name(name) == Some(CompoundKind::Ref) {
1076 return params.first().and_then(|inner| inner.get_name());
1077 }
1078 Some(name)
1079 }
1080 Type::ImportNamespace(module_id) => {
1081 let path = module_id.strip_prefix("go:").unwrap_or(module_id);
1082 path.rsplit('/').next()
1083 }
1084 _ => None,
1085 }
1086 }
1087
1088 pub fn wraps(&self, name: &str, inner: &Type) -> bool {
1089 self.get_name().is_some_and(|n| n == name)
1090 && self
1091 .get_type_params()
1092 .and_then(|p| p.first())
1093 .is_some_and(|first| *first == *inner)
1094 }
1095
1096 pub fn get_function_params(&self) -> Option<&[Type]> {
1097 match self {
1098 Type::Function { params, .. } => Some(params),
1099 Type::Nominal {
1100 underlying_ty: Some(inner),
1101 ..
1102 } => inner.get_function_params(),
1103 _ => None,
1104 }
1105 }
1106
1107 pub fn param_count(&self) -> usize {
1108 match self {
1109 Type::Function { params, .. } => params.len(),
1110 _ => 0,
1111 }
1112 }
1113
1114 pub fn get_param_mutability(&self) -> &[bool] {
1115 match self {
1116 Type::Function {
1117 param_mutability, ..
1118 } => param_mutability,
1119 _ => &[],
1120 }
1121 }
1122
1123 pub fn with_replaced_first_param(&self, new_first: &Type) -> Type {
1124 match self {
1125 Type::Function {
1126 params,
1127 param_mutability,
1128 bounds,
1129 return_type,
1130 } => {
1131 if params.is_empty() {
1132 return self.clone();
1133 }
1134 let mut new_params = params.clone();
1135 new_params[0] = new_first.clone();
1136 Type::Function {
1137 params: new_params,
1138 param_mutability: param_mutability.clone(),
1139 bounds: bounds.clone(),
1140 return_type: return_type.clone(),
1141 }
1142 }
1143 Type::Forall { vars, body } => Type::Forall {
1144 vars: vars.clone(),
1145 body: Box::new(body.with_replaced_first_param(new_first)),
1146 },
1147 _ => self.clone(),
1148 }
1149 }
1150
1151 pub fn get_bounds(&self) -> &[Bound] {
1152 match self {
1153 Type::Function { bounds, .. } => bounds,
1154 Type::Forall { body, .. } => body.get_bounds(),
1155 _ => &[],
1156 }
1157 }
1158
1159 pub fn get_qualified_name(&self) -> Symbol {
1160 match self.strip_refs() {
1161 Type::Nominal { id, .. } => id,
1162 Type::Simple(kind) => Symbol::from_parts("prelude", kind.leaf_name()),
1163 Type::Compound { kind, .. } => Symbol::from_parts("prelude", kind.leaf_name()),
1164 _ => panic!("called get_qualified_name on {:#?}", self),
1165 }
1166 }
1167
1168 pub fn inner(&self) -> Option<Type> {
1169 self.get_type_params()
1170 .and_then(|args| args.first().cloned())
1171 }
1172
1173 pub fn ok_type(&self) -> Type {
1174 debug_assert!(
1175 self.is_result() || self.is_option() || self.is_partial(),
1176 "ok_type called on non-Result/Option/Partial type"
1177 );
1178 self.inner()
1179 .expect("Result/Option/Partial should have inner type")
1180 }
1181
1182 pub fn err_type(&self) -> Type {
1183 debug_assert!(
1184 self.is_result() || self.is_partial(),
1185 "err_type called on non-Result/Partial type"
1186 );
1187 self.get_type_params()
1188 .and_then(|args| args.get(1).cloned())
1189 .expect("Result/Partial should have error type")
1190 }
1191}
1192
1193pub fn peel_alias<F>(ty: &Type, is_alias: F) -> Type
1196where
1197 F: Fn(&str) -> bool,
1198{
1199 let mut current = ty.unwrap_forall().clone();
1200 let mut seen: Vec<String> = Vec::new();
1201 while let Type::Nominal {
1202 id,
1203 underlying_ty: Some(u),
1204 ..
1205 } = ¤t
1206 {
1207 if !is_alias(id.as_str()) {
1208 break;
1209 }
1210 if seen.iter().any(|s| s == id.as_str()) {
1211 break;
1212 }
1213 seen.push(id.to_string());
1214 current = u.unwrap_forall().clone();
1215 }
1216 current
1217}
1218
1219pub fn peel_alias_id<F>(id: &str, next_alias: F) -> String
1222where
1223 F: Fn(&str) -> Option<String>,
1224{
1225 let mut current = id.to_string();
1226 let mut seen: Vec<String> = Vec::new();
1227 loop {
1228 if seen.iter().any(|s| s == ¤t) {
1229 return current;
1230 }
1231 let Some(next) = next_alias(¤t) else {
1232 return current;
1233 };
1234 seen.push(current);
1235 current = next;
1236 }
1237}
1238
1239impl Type {
1240 pub fn unwrap_forall(&self) -> &Type {
1241 match self {
1242 Type::Forall { body, .. } => body.as_ref(),
1243 other => other,
1244 }
1245 }
1246
1247 pub fn strip_refs(&self) -> Type {
1248 if self.is_ref() {
1249 return self.inner().expect("ref type must have inner").strip_refs();
1250 }
1251
1252 self.clone()
1253 }
1254
1255 pub fn with_receiver_placeholder(self) -> Type {
1256 match self {
1257 Type::Function {
1258 params,
1259 param_mutability,
1260 bounds,
1261 return_type,
1262 } => {
1263 let mut new_params = vec![Type::ReceiverPlaceholder];
1264 new_params.extend(params);
1265
1266 let mut new_mutability = vec![false];
1267 new_mutability.extend(param_mutability);
1268
1269 Type::Function {
1270 params: new_params,
1271 param_mutability: new_mutability,
1272 bounds,
1273 return_type,
1274 }
1275 }
1276 _ => unreachable!(
1277 "with_receiver_placeholder called on non-function type: {:?}",
1278 self
1279 ),
1280 }
1281 }
1282
1283 pub fn remove_vars(types: &[&Type]) -> (Vec<Type>, Vec<EcoString>) {
1284 let mut vars = HashMap::default();
1285 let types = types
1286 .iter()
1287 .map(|v| Self::remove_vars_impl(v, &mut vars))
1288 .collect();
1289
1290 (types, vars.into_values().collect())
1291 }
1292
1293 fn remove_vars_impl(ty: &Type, vars: &mut HashMap<u32, EcoString>) -> Type {
1294 match ty {
1295 Type::Nominal {
1296 id: name,
1297 params: args,
1298 underlying_ty: underlying,
1299 } => Type::Nominal {
1300 id: name.clone(),
1301 params: args
1302 .iter()
1303 .map(|a| Self::remove_vars_impl(a, vars))
1304 .collect(),
1305 underlying_ty: underlying
1306 .as_ref()
1307 .map(|u| Box::new(Self::remove_vars_impl(u, vars))),
1308 },
1309
1310 Type::Function {
1311 params: args,
1312 param_mutability,
1313 bounds,
1314 return_type,
1315 } => Type::Function {
1316 params: args
1317 .iter()
1318 .map(|a| Self::remove_vars_impl(a, vars))
1319 .collect(),
1320 param_mutability: param_mutability.clone(),
1321 bounds: bounds
1322 .iter()
1323 .map(|b| Bound {
1324 param_name: b.param_name.clone(),
1325 generic: Self::remove_vars_impl(&b.generic, vars),
1326 ty: Self::remove_vars_impl(&b.ty, vars),
1327 })
1328 .collect(),
1329 return_type: Self::remove_vars_impl(return_type, vars).into(),
1330 },
1331
1332 Type::Var { id, hint } => match vars.get(&id.0) {
1333 Some(g) => Type::Parameter(g.clone()),
1334 None => {
1335 let name: EcoString = hint
1336 .clone()
1337 .unwrap_or_else(|| alpha_index(vars.len()).into());
1338
1339 vars.insert(id.0, name.clone());
1340 Type::Parameter(name)
1341 }
1342 },
1343
1344 Type::Forall { body, .. } => Self::remove_vars_impl(body, vars),
1345 Type::Tuple(elements) => Type::Tuple(
1346 elements
1347 .iter()
1348 .map(|e| Self::remove_vars_impl(e, vars))
1349 .collect(),
1350 ),
1351 Type::Compound { kind, args } => Type::Compound {
1352 kind: *kind,
1353 args: args
1354 .iter()
1355 .map(|a| Self::remove_vars_impl(a, vars))
1356 .collect(),
1357 },
1358 Type::Simple(_) | Type::Parameter(_) => ty.clone(),
1359 Type::Never | Type::Error | Type::ImportNamespace(_) | Type::ReceiverPlaceholder => {
1360 ty.clone()
1361 }
1362 }
1363 }
1364
1365 pub fn contains_type(&self, target: &Type) -> bool {
1366 if *self == *target {
1367 return true;
1368 }
1369 match self {
1370 Type::Nominal { params, .. } => params.iter().any(|p| p.contains_type(target)),
1371 Type::Function {
1372 params,
1373 return_type,
1374 ..
1375 } => {
1376 params.iter().any(|p| p.contains_type(target)) || return_type.contains_type(target)
1377 }
1378 Type::Var { .. } => false,
1379 Type::Forall { body, .. } => body.contains_type(target),
1380 Type::Tuple(elements) => elements.iter().any(|e| e.contains_type(target)),
1381 Type::Compound { args, .. } => args.iter().any(|a| a.contains_type(target)),
1382 Type::Simple(_)
1383 | Type::Parameter(_)
1384 | Type::Never
1385 | Type::Error
1386 | Type::ImportNamespace(_)
1387 | Type::ReceiverPlaceholder => false,
1388 }
1389 }
1390}
1391
1392impl Type {
1393 pub fn underlying_numeric_type(&self) -> Option<Type> {
1394 self.underlying_numeric_type_recursive(&mut HashSet::default())
1395 }
1396
1397 pub fn has_underlying_numeric_type(&self) -> bool {
1398 self.underlying_numeric_type().is_some()
1399 }
1400
1401 fn underlying_numeric_type_recursive(&self, visited: &mut HashSet<Symbol>) -> Option<Type> {
1402 match self {
1403 Type::Simple(_) if self.is_numeric() => Some(self.clone()),
1404 Type::Nominal {
1405 id,
1406 underlying_ty: underlying,
1407 ..
1408 } => {
1409 if self.is_numeric() {
1410 return Some(self.clone());
1411 }
1412
1413 if !visited.insert(id.clone()) {
1414 return None;
1415 }
1416
1417 underlying
1418 .as_ref()?
1419 .underlying_numeric_type_recursive(visited)
1420 }
1421 _ => None,
1422 }
1423 }
1424
1425 pub fn numeric_family(&self) -> Option<NumericFamily> {
1426 self.as_simple()?.numeric_family()
1427 }
1428
1429 pub fn is_numeric_compatible_with(&self, other: &Type) -> bool {
1430 let self_underlying_ty = self.underlying_numeric_type();
1431 let other_underlying_ty = other.underlying_numeric_type();
1432
1433 match (self_underlying_ty, other_underlying_ty) {
1434 (Some(s), Some(o)) => s.numeric_family() == o.numeric_family(),
1435 _ => false,
1436 }
1437 }
1438
1439 pub fn is_aliased_numeric_type(&self) -> bool {
1440 match self {
1441 Type::Nominal { underlying_ty, .. } => {
1442 underlying_ty.is_some() && !self.is_numeric() && self.has_underlying_numeric_type()
1443 }
1444 _ => false,
1445 }
1446 }
1447}
1448
1449fn alpha_index(idx: usize) -> String {
1451 let mut s = String::new();
1452 let mut n = idx + 1;
1453 while n > 0 {
1454 n -= 1;
1455 s.insert(0, (b'A' + (n % 26) as u8) as char);
1456 n /= 26;
1457 }
1458 s
1459}
1460
1461#[cfg(test)]
1462mod tests {
1463 use super::*;
1464
1465 #[test]
1466 fn alpha_index_single() {
1467 assert_eq!(alpha_index(0), "A");
1468 assert_eq!(alpha_index(5), "F");
1469 assert_eq!(alpha_index(25), "Z");
1470 }
1471
1472 #[test]
1473 fn alpha_index_double() {
1474 assert_eq!(alpha_index(26), "AA");
1475 assert_eq!(alpha_index(27), "AB");
1476 assert_eq!(alpha_index(51), "AZ");
1477 assert_eq!(alpha_index(52), "BA");
1478 assert_eq!(alpha_index(701), "ZZ");
1479 }
1480
1481 #[test]
1482 fn alpha_index_triple() {
1483 assert_eq!(alpha_index(702), "AAA");
1484 }
1485
1486 fn unhinted_var(id: u32) -> Type {
1487 Type::Var {
1488 id: TypeVarId(id),
1489 hint: None,
1490 }
1491 }
1492
1493 #[test]
1494 fn remove_vars_handles_more_than_six_unhinted_vars() {
1495 let func = Type::Function {
1496 params: (0..6).map(unhinted_var).collect(),
1497 param_mutability: vec![false; 6],
1498 bounds: vec![],
1499 return_type: Box::new(unhinted_var(6)),
1500 };
1501
1502 let (resolved, generics) = Type::remove_vars(&[&func]);
1503
1504 assert_eq!(generics.len(), 7);
1505 let Type::Function {
1506 params,
1507 return_type,
1508 ..
1509 } = &resolved[0]
1510 else {
1511 panic!("expected function type");
1512 };
1513 let names: Vec<_> = params
1514 .iter()
1515 .chain(std::iter::once(return_type.as_ref()))
1516 .map(|p| match p {
1517 Type::Parameter(name) => name.to_string(),
1518 other => panic!("expected parameter, got {:?}", other),
1519 })
1520 .collect();
1521 assert_eq!(names, vec!["A", "B", "C", "D", "E", "F", "G"]);
1522 }
1523
1524 #[test]
1525 fn remove_vars_handles_dozens_of_unhinted_vars() {
1526 let params: Vec<Type> = (0..30).map(unhinted_var).collect();
1527 let func = Type::Function {
1528 params: params.clone(),
1529 param_mutability: vec![false; params.len()],
1530 bounds: vec![],
1531 return_type: Box::new(Type::Simple(SimpleKind::Unit)),
1532 };
1533 let (_, generics) = Type::remove_vars(&[&func]);
1534 assert_eq!(generics.len(), 30);
1535 }
1536}