lisette_semantics/checker/
type_env.rs1use ecow::EcoString;
16use syntax::types::{Bound, Type, TypeVarId};
17
18#[derive(Debug, Clone)]
19pub enum VarState {
20 Unbound { hint: Option<EcoString> },
21 Bound(Type),
22}
23
24pub struct TypeEnv {
25 entries: Vec<VarState>,
26 undo_log: Option<Vec<(TypeVarId, VarState)>>,
29}
30
31impl Default for TypeEnv {
32 fn default() -> Self {
33 Self::new()
34 }
35}
36
37impl TypeEnv {
38 pub fn new() -> Self {
39 Self {
40 entries: Vec::new(),
41 undo_log: None,
42 }
43 }
44
45 pub fn fresh(&mut self, hint: Option<EcoString>) -> TypeVarId {
47 let id = TypeVarId(self.entries.len() as u32);
48 self.entries.push(VarState::Unbound { hint });
49 id
50 }
51
52 fn slot(id: TypeVarId) -> usize {
53 debug_assert!(
54 !id.is_reserved(),
55 "TypeEnv should not be queried for reserved ids"
56 );
57 id.0 as usize
58 }
59
60 pub fn state(&self, id: TypeVarId) -> &VarState {
61 &self.entries[Self::slot(id)]
62 }
63
64 pub fn is_unbound(&self, id: TypeVarId) -> bool {
65 if id.is_reserved() {
66 return true;
67 }
68 matches!(self.entries[Self::slot(id)], VarState::Unbound { .. })
69 }
70
71 pub fn bind(&mut self, id: TypeVarId, ty: Type) {
74 if id.is_reserved() {
75 return;
76 }
77 let slot = Self::slot(id);
78 let old = std::mem::replace(&mut self.entries[slot], VarState::Bound(ty));
79 if let Some(log) = &mut self.undo_log {
80 log.push((id, old));
81 }
82 }
83
84 pub fn shallow_resolve(&self, ty: &Type) -> Type {
87 let mut current = ty.clone();
88 loop {
89 match ¤t {
90 Type::Var { id, .. } if !id.is_reserved() => match &self.entries[Self::slot(*id)] {
91 VarState::Unbound { .. } => return current,
92 VarState::Bound(bound) => current = bound.clone(),
93 },
94 _ => return current,
95 }
96 }
97 }
98
99 pub fn resolve(&self, ty: &Type) -> Type {
104 match ty {
105 Type::Var { id, .. } if !id.is_reserved() => match &self.entries[Self::slot(*id)] {
106 VarState::Unbound { .. } => ty.clone(),
107 VarState::Bound(bound) => self.resolve(bound),
108 },
109 Type::Nominal {
110 id,
111 params,
112 underlying_ty,
113 } => Type::Nominal {
114 id: id.clone(),
115 params: params.iter().map(|p| self.resolve(p)).collect(),
116 underlying_ty: underlying_ty.as_ref().map(|u| Box::new(self.resolve(u))),
117 },
118 Type::Compound { kind, args } => Type::Compound {
119 kind: *kind,
120 args: args.iter().map(|a| self.resolve(a)).collect(),
121 },
122 Type::Function {
123 params,
124 param_mutability,
125 bounds,
126 return_type,
127 } => Type::Function {
128 params: params.iter().map(|p| self.resolve(p)).collect(),
129 param_mutability: param_mutability.clone(),
130 bounds: bounds
131 .iter()
132 .map(|b| Bound {
133 param_name: b.param_name.clone(),
134 generic: self.resolve(&b.generic),
135 ty: self.resolve(&b.ty),
136 })
137 .collect(),
138 return_type: Box::new(self.resolve(return_type)),
139 },
140 Type::Forall { vars, body } => Type::Forall {
141 vars: vars.clone(),
142 body: Box::new(self.resolve(body)),
143 },
144 Type::Tuple(elements) => {
145 Type::Tuple(elements.iter().map(|e| self.resolve(e)).collect())
146 }
147 _ => ty.clone(),
148 }
149 }
150
151 pub fn occurs(&self, id: TypeVarId, ty: &Type) -> bool {
154 match ty {
155 Type::Var { id: other, .. } => {
156 if *other == id {
157 return true;
158 }
159 if other.is_reserved() {
160 return false;
161 }
162 match &self.entries[Self::slot(*other)] {
163 VarState::Unbound { .. } => false,
164 VarState::Bound(bound) => self.occurs(id, bound),
165 }
166 }
167 Type::Nominal { params, .. } => params.iter().any(|p| self.occurs(id, p)),
168 Type::Compound { args, .. } => args.iter().any(|a| self.occurs(id, a)),
169 Type::Function {
170 params,
171 return_type,
172 ..
173 } => params.iter().any(|p| self.occurs(id, p)) || self.occurs(id, return_type),
174 Type::Forall { body, .. } => self.occurs(id, body),
175 Type::Tuple(elements) => elements.iter().any(|e| self.occurs(id, e)),
176 _ => false,
177 }
178 }
179
180 pub fn begin_speculation(&mut self) -> Speculation {
183 let prev = self.undo_log.take();
184 self.undo_log = Some(Vec::new());
185 Speculation { prev }
186 }
187
188 pub fn end_speculation(&mut self, spec: Speculation, is_err: bool) {
193 let log = self.undo_log.take().expect("speculation log must exist");
194 self.undo_log = spec.prev;
195 if is_err {
196 for (id, original) in log.into_iter().rev() {
197 self.entries[Self::slot(id)] = original;
198 }
199 } else if let Some(parent_log) = &mut self.undo_log {
200 parent_log.extend(log);
201 }
202 }
203}
204
205#[must_use]
208pub struct Speculation {
209 prev: Option<Vec<(TypeVarId, VarState)>>,
210}
211
212pub trait EnvResolve {
215 fn resolve_in(&self, env: &TypeEnv) -> Type;
216 fn shallow_resolve_in(&self, env: &TypeEnv) -> Type;
217}
218
219impl EnvResolve for Type {
220 fn resolve_in(&self, env: &TypeEnv) -> Type {
221 env.resolve(self)
222 }
223 fn shallow_resolve_in(&self, env: &TypeEnv) -> Type {
224 env.shallow_resolve(self)
225 }
226}