1use std::{borrow::Cow, iter::FromIterator};
2
3use crate::{
4 fnv::FnvMap,
5 symbol::Symbol,
6 types::{AliasData, AliasRef, Generic, Type, TypeContext, TypeEnv, TypeExt},
7};
8
9quick_error! {
10 #[derive(Debug, PartialEq)]
11 pub enum Error {
12 UndefinedType(id: Symbol) {
13 display("Type `{}` does not exist.", id)
14 }
15 SelfRecursiveAlias(id: Symbol) {
16 display("Tried to remove self recursive alias `{}`.", id)
17 }
18 }
19}
20
21#[derive(Debug)]
22pub struct AliasRemover<T> {
23 reduced_aliases: Vec<Symbol>,
24 pub named_variables: FnvMap<Symbol, T>,
25}
26
27impl<T> Default for AliasRemover<T> {
28 fn default() -> Self {
29 AliasRemover {
30 reduced_aliases: Default::default(),
31 named_variables: Default::default(),
32 }
33 }
34}
35
36impl<T> AliasRemover<T> {
37 pub fn new() -> Self {
38 Self::default()
39 }
40
41 pub fn len(&self) -> usize {
42 self.reduced_aliases.len()
43 }
44
45 pub fn is_empty(&self) -> bool {
46 self.reduced_aliases.is_empty()
47 }
48
49 pub fn reset(&mut self, to: usize) {
50 self.reduced_aliases.truncate(to)
51 }
52
53 pub fn clear(&mut self) {
54 self.reduced_aliases.clear();
55 self.named_variables.clear();
56 }
57}
58
59impl<T> AliasRemover<T>
60where
61 T: TypeExt<Id = Symbol, SpannedId = Symbol> + Clone + ::std::fmt::Display,
62 T::Types: Clone + Default + Extend<T> + FromIterator<T>,
63 T::Generics: Clone + FromIterator<Generic<Symbol>>,
64 T::Fields: Clone,
65{
66 pub fn canonical_alias<'t, F>(
67 &mut self,
68 env: &(dyn TypeEnv<Type = T> + '_),
69 interner: &mut impl TypeContext<Symbol, T>,
70 typ: &'t T,
71 mut canonical: F,
72 ) -> Result<Cow<'t, T>, Error>
73 where
74 F: FnMut(&AliasRef<Symbol, T>) -> bool,
75 {
76 Ok(match peek_alias(env, typ) {
77 Ok(Some(alias)) => {
78 if self.reduced_aliases.contains(&alias.name) {
79 return Err(Error::SelfRecursiveAlias(alias.name.clone()));
80 }
81 self.reduced_aliases.push(alias.name.clone());
82
83 if canonical(&alias) {
84 Cow::Borrowed(typ)
85 } else {
86 match alias.typ(interner).apply_args(
87 alias.params(),
88 &typ.unapplied_args(),
89 interner,
90 &mut self.named_variables,
91 ) {
92 Some(typ) => Cow::Owned(
93 self.canonical_alias(env, interner, &typ, canonical)?
94 .into_owned(),
95 ),
96 None => Cow::Borrowed(typ),
97 }
98 }
99 }
100 _ => Cow::Borrowed(typ),
101 })
102 }
103
104 pub fn remove_aliases_to_concrete<'a>(
105 &mut self,
106 env: &(dyn TypeEnv<Type = T> + '_),
107 interner: &mut impl TypeContext<Symbol, T>,
108 mut typ: T,
109 ) -> Result<T, Error> {
110 loop {
111 typ = match self.remove_alias_to_concrete(env, interner, &typ, |_| true)? {
112 Some((typ, args)) => match *typ {
113 Type::Builtin(..)
114 | Type::Function(..)
115 | Type::Record(..)
116 | Type::Variant(..)
117 | Type::Effect(..)
118 | Type::EmptyRow
119 | Type::ExtendRow { .. }
120 | Type::ExtendTypeRow { .. }
121 if args.is_empty() =>
122 {
123 return Ok(typ)
124 }
125 _ => {
126 let typ = typ
127 .replace_generics(interner, &mut self.named_variables)
128 .unwrap_or_else(|| typ);
129
130 interner.app(typ, args.iter().cloned().collect())
131 }
132 },
133 None => return Ok(typ),
134 };
135 }
136 }
137
138 pub fn remove_aliases(
139 &mut self,
140 env: &(dyn TypeEnv<Type = T> + '_),
141 interner: &mut impl TypeContext<Symbol, T>,
142 typ: T,
143 ) -> Result<T, Error> {
144 self.remove_aliases_predicate(env, interner, typ, |_| true)
145 }
146
147 pub fn remove_aliases_predicate(
148 &mut self,
149 env: &(dyn TypeEnv<Type = T> + '_),
150 interner: &mut impl TypeContext<Symbol, T>,
151 mut typ: T,
152 mut predicate: impl FnMut(&AliasData<Symbol, T>) -> bool,
153 ) -> Result<T, Error> {
154 loop {
155 typ = match self.remove_alias(env, interner, &typ, &mut predicate)? {
156 Some(typ) => typ,
157 None => return Ok(typ),
158 };
159 }
160 }
161
162 pub fn remove_alias(
163 &mut self,
164 env: &(dyn TypeEnv<Type = T> + '_),
165 interner: &mut impl TypeContext<Symbol, T>,
166 typ: &T,
167 predicate: impl FnOnce(&AliasData<Symbol, T>) -> bool,
168 ) -> Result<Option<T>, Error> {
169 Ok(self
170 .remove_alias_to_concrete(env, interner, typ, predicate)?
171 .map(|(non_replaced_type, unapplied_args)| {
172 let non_replaced_type = non_replaced_type
173 .replace_generics(interner, &mut self.named_variables)
174 .unwrap_or_else(|| non_replaced_type.clone());
175
176 interner.app(non_replaced_type, unapplied_args.iter().cloned().collect())
177 }))
178 }
179
180 pub fn remove_alias_to_concrete<'a>(
181 &mut self,
182 env: &'a (dyn TypeEnv<Type = T> + '_),
183 interner: &mut impl TypeContext<Symbol, T>,
184 typ: &'a T,
185 predicate: impl FnOnce(&AliasData<Symbol, T>) -> bool,
186 ) -> Result<Option<(T, Cow<'a, [T]>)>, Error> {
187 match peek_alias(env, &typ)? {
188 Some(ref alias) if predicate(alias) => {
189 self.remove_alias_to_concrete_inner(interner, typ, alias)
190 }
191 _ => Ok(None),
192 }
193 }
194
195 fn remove_alias_to_concrete_inner<'a>(
196 &mut self,
197 interner: &mut impl TypeContext<Symbol, T>,
198 typ: &'a T,
199 alias: &AliasRef<Symbol, T>,
200 ) -> Result<Option<(T, Cow<'a, [T]>)>, Error> {
201 if self.reduced_aliases.iter().any(|name| *name == alias.name) {
202 return Err(Error::SelfRecursiveAlias(alias.name.clone()));
203 }
204 self.reduced_aliases.push(alias.name.clone());
205 if let Type::Opaque = **alias.unresolved_type() {
207 return Ok(None);
208 }
209
210 let unapplied_args = typ.unapplied_args();
211
212 let opt = alias.typ(interner).arg_application(
213 alias.params(),
214 &unapplied_args,
215 interner,
216 &mut self.named_variables,
217 );
218 match opt {
219 Some((t, a)) => {
220 let l = unapplied_args.len() - a.len();
221 Ok(Some((
222 t,
223 match unapplied_args {
224 Cow::Borrowed(slice) => Cow::Borrowed(&slice[l..]),
225 Cow::Owned(mut vec) => {
226 vec.drain(l..);
227 Cow::Owned(vec)
228 }
229 },
230 )))
231 }
232 None => Ok(None),
233 }
234 }
235}
236
237pub fn remove_aliases<T>(
239 env: &(dyn TypeEnv<Type = T> + '_),
240 interner: &mut impl TypeContext<Symbol, T>,
241 mut typ: T,
242) -> T
243where
244 T: TypeExt<Id = Symbol, SpannedId = Symbol> + Clone + ::std::fmt::Display,
245 T::Types: Clone + Default + Extend<T> + FromIterator<T>,
246 T::Generics: Clone + FromIterator<Generic<Symbol>>,
247 T::Fields: Clone,
248{
249 while let Ok(Some(new)) = remove_alias(env, interner, &typ) {
250 typ = new;
251 }
252 typ
253}
254
255pub fn remove_aliases_cow<'t, T>(
256 env: &(dyn TypeEnv<Type = T> + '_),
257 interner: &mut impl TypeContext<Symbol, T>,
258 typ: &'t T,
259) -> Cow<'t, T>
260where
261 T: TypeExt<Id = Symbol, SpannedId = Symbol> + Clone + ::std::fmt::Display,
262 T::Types: Clone + Default + Extend<T> + FromIterator<T>,
263 T::Generics: Clone + FromIterator<Generic<Symbol>>,
264 T::Fields: Clone,
265{
266 match remove_alias(env, interner, typ) {
267 Ok(Some(typ)) => Cow::Owned(remove_aliases(env, interner, typ)),
268 _ => Cow::Borrowed(typ),
269 }
270}
271
272pub fn canonical_alias<'t, F, T>(
275 env: &(dyn TypeEnv<Type = T> + '_),
276 interner: &mut impl TypeContext<Symbol, T>,
277 typ: &'t T,
278 mut canonical: F,
279) -> Cow<'t, T>
280where
281 F: FnMut(&AliasRef<Symbol, T>) -> bool,
282 T: TypeExt<Id = Symbol, SpannedId = Symbol> + Clone + ::std::fmt::Display,
283 T::Types: Clone + Default + Extend<T> + FromIterator<T>,
284 T::Generics: Clone + FromIterator<Generic<Symbol>>,
285 T::Fields: Clone,
286{
287 match peek_alias(env, typ) {
288 Ok(Some(alias)) => {
289 if canonical(&alias) {
290 Cow::Borrowed(typ)
291 } else {
292 alias
293 .typ(interner)
294 .apply_args(
295 alias.params(),
296 &typ.unapplied_args(),
297 interner,
298 &mut Default::default(),
299 )
300 .map(|typ| {
301 Cow::Owned(canonical_alias(env, interner, &typ, canonical).into_owned())
302 })
303 .unwrap_or_else(|| Cow::Borrowed(typ))
304 }
305 }
306 _ => Cow::Borrowed(typ),
307 }
308}
309
310pub fn remove_alias<T>(
313 env: &(dyn TypeEnv<Type = T> + '_),
314 interner: &mut impl TypeContext<Symbol, T>,
315 typ: &T,
316) -> Result<Option<T>, Error>
317where
318 T: TypeExt<Id = Symbol, SpannedId = Symbol> + Clone + ::std::fmt::Display,
319 T::Types: Clone + Default + Extend<T> + FromIterator<T>,
320 T::Generics: Clone + FromIterator<Generic<Symbol>>,
321 T::Fields: Clone,
322{
323 Ok(peek_alias(env, &typ)?.and_then(|alias| {
324 if let Type::Opaque = **alias.unresolved_type() {
326 return None;
327 }
328 alias.typ(interner).apply_args(
329 alias.params(),
330 &typ.unapplied_args(),
331 interner,
332 &mut Default::default(),
333 )
334 }))
335}
336
337pub fn peek_alias<'t, T>(
338 env: &(dyn TypeEnv<Type = T> + '_),
339 typ: &'t T,
340) -> Result<Option<AliasRef<Symbol, T>>, Error>
341where
342 T: TypeExt<Id = Symbol, SpannedId = Symbol> + Clone + ::std::fmt::Display,
343 T::Types: Clone + Default + Extend<T>,
344 T::Generics: Clone + FromIterator<Generic<Symbol>>,
345 T::Fields: Clone,
346{
347 let maybe_alias = typ.applied_alias();
348
349 match typ.alias_ident() {
350 Some(id) => {
351 let alias = match maybe_alias {
352 Some(alias) => Some(alias.clone()),
353 None => env.find_type_info(id).map(|a| (*a).clone()),
354 };
355 Ok(alias)
356 }
357 None => Ok(None),
358 }
359}