1use crate::{Generics, RefID, TypesBuf};
2use itertools::Itertools;
3use std::fmt;
4use std::hash::Hash;
5
6pub trait TypeData: Sized + fmt::Debug + Clone + PartialEq {
7 type Concrete: Key;
8 type Generic: Key;
9 type Trait: Key;
10 type Association: Key;
11
12 type Meta: Clone + fmt::Debug + Default;
13
14 fn fmt_specific(
16 constr: &Self::Concrete,
17 t: &Type<Self>,
18 f: &mut fmt::Formatter,
19 ) -> fmt::Result {
20 t.fmt_with_params(constr, f)
21 }
22
23 fn first_available(forall: &Generics<Self>) -> Self::Generic;
25}
26
27pub trait Key: PartialEq + Eq + fmt::Debug + Clone + Hash + fmt::Display {}
28
29impl<'a> Key for &'a str {}
30impl Key for usize {}
31impl Key for u32 {}
32impl Key for u16 {}
33impl Key for u8 {}
34impl Key for char {}
35impl Key for String {}
36
37#[derive(Debug, Clone)]
38pub struct Type<D: TypeData> {
39 pub constr: TypeKind<D>,
40 pub meta: D::Meta,
41 pub params: Vec<Self>,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub enum TypeKind<D: TypeData> {
46 Generic(D::Generic),
47 Concrete(D::Concrete),
48 Ref(RefID),
49 Self_,
50 Object(D::Trait),
57}
58
59impl<D: TypeData> Type<D> {
60 #[must_use]
61 pub fn with_params(mut self, params: TypesBuf<D>) -> Self {
62 assert!(
63 std::mem::replace(&mut self.params, params).is_empty(),
64 "`with_params` called onto type already containing parameters"
65 );
66 self
67 }
68 pub fn concrete(meta: D::Meta, constr: D::Concrete, params: TypesBuf<D>) -> Self {
69 Self {
70 params,
71 meta,
72 constr: TypeKind::Concrete(constr),
73 }
74 }
75
76 pub fn generic(meta: D::Meta, constr: D::Generic, params: TypesBuf<D>) -> Self {
77 Self {
78 params,
79 meta,
80 constr: TypeKind::Generic(constr),
81 }
82 }
83
84 pub fn object(meta: D::Meta, trait_: D::Trait, params: TypesBuf<D>) -> Self {
85 Self {
86 constr: TypeKind::Object(trait_),
87 meta,
88 params,
89 }
90 }
91
92 pub fn self_(meta: D::Meta, params: TypesBuf<D>) -> Self {
93 Self {
94 constr: TypeKind::Self_,
95 meta,
96 params,
97 }
98 }
99
100 pub fn reference(meta: D::Meta, rid: RefID, hkt: TypesBuf<D>) -> Self {
101 Self {
102 params: hkt,
103 meta,
104 constr: TypeKind::Ref(rid),
105 }
106 }
107
108 pub fn direct_eq(&self, other: &Self) -> bool {
109 self.constr == other.constr
110 && self
111 .params
112 .iter()
113 .zip(&other.params)
114 .all(|(s, o)| s.direct_eq(o))
115 }
116}
117
118impl<D: TypeData> TypeKind<D> {
119 pub fn describe(&self) -> &'static str {
120 match self {
121 TypeKind::Concrete(_) => "concrete",
122 TypeKind::Ref(_) => "inference",
123 TypeKind::Object(_) => "trait object",
124 TypeKind::Generic(_) => "generic",
125 TypeKind::Self_ => "self",
126 }
127 }
128}
129
130impl<D: TypeData> fmt::Display for Type<D> {
131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 match &self.constr {
133 TypeKind::Concrete(c) => D::fmt_specific(c, self, f),
134 TypeKind::Generic(g) => self.fmt_with_params(g, f),
135 TypeKind::Object(trid) => self.fmt_with_params(format!("dyn {}", trid), f),
136 TypeKind::Ref(rid) if *rid > 25 => self.fmt_with_params(format!("'{}", rid), f),
137 TypeKind::Ref(rid) => {
138 self.fmt_with_params(format!("'{}", (*rid as u8 + b'a') as char), f)
139 }
140 TypeKind::Self_ => self.fmt_with_params("self", f),
141 }
142 }
143}
144
145impl<D: TypeData> fmt::Display for TypeKind<D> {
146 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147 match &self {
148 TypeKind::Concrete(c) => c.fmt(f),
149 TypeKind::Generic(g) => g.fmt(f),
150 TypeKind::Object(trid) => trid.fmt(f),
151 TypeKind::Ref(rid) if *rid > 25 => write!(f, "'{}", rid),
152 TypeKind::Ref(rid) => {
153 write!(f, "'{}", (*rid as u8 + b'a') as char)
154 }
155 TypeKind::Self_ => "self".fmt(f),
156 }
157 }
158}
159
160impl<D: TypeData> Type<D> {
161 pub fn fmt_with_params(&self, v: impl fmt::Display, f: &mut fmt::Formatter) -> fmt::Result {
165 if self.params.is_empty() {
166 v.fmt(f)
167 } else {
168 write!(f, "({} {})", v, self.params.iter().format(" "))
169 }
170 }
171}