1 use crate::cdsl::ast::{Def, DefIndex, DefPool, Var, VarIndex, VarPool};
2 use crate::cdsl::typevar::{DerivedFunc, TypeSet, TypeVar};
3
4 use std::collections::{HashMap, HashSet};
5 use std::iter::FromIterator;
6
7 #[derive(Debug, Hash, PartialEq, Eq)]
8 pub(crate) enum Constraint {
9 /// Constraint specifying that a type var tv1 must be wider than or equal to type var tv2 at
10 /// runtime. This requires that:
11 /// 1) They have the same number of lanes
12 /// 2) In a lane tv1 has at least as many bits as tv2.
13 WiderOrEq(TypeVar, TypeVar),
14
15 /// Constraint specifying that two derived type vars must have the same runtime type.
16 Eq(TypeVar, TypeVar),
17
18 /// Constraint specifying that a type var must belong to some typeset.
19 InTypeset(TypeVar, TypeSet),
20 }
21
22 impl Constraint {
translate_with<F: Fn(&TypeVar) -> TypeVar>(&self, func: F) -> Constraint23 fn translate_with<F: Fn(&TypeVar) -> TypeVar>(&self, func: F) -> Constraint {
24 match self {
25 Constraint::WiderOrEq(lhs, rhs) => {
26 let lhs = func(&lhs);
27 let rhs = func(&rhs);
28 Constraint::WiderOrEq(lhs, rhs)
29 }
30 Constraint::Eq(lhs, rhs) => {
31 let lhs = func(&lhs);
32 let rhs = func(&rhs);
33 Constraint::Eq(lhs, rhs)
34 }
35 Constraint::InTypeset(tv, ts) => {
36 let tv = func(&tv);
37 Constraint::InTypeset(tv, ts.clone())
38 }
39 }
40 }
41
42 /// Creates a new constraint by replacing type vars by their hashmap equivalent.
translate_with_map( &self, original_to_own_typevar: &HashMap<&TypeVar, TypeVar>, ) -> Constraint43 fn translate_with_map(
44 &self,
45 original_to_own_typevar: &HashMap<&TypeVar, TypeVar>,
46 ) -> Constraint {
47 self.translate_with(|tv| substitute(original_to_own_typevar, tv))
48 }
49
50 /// Creates a new constraint by replacing type vars by their canonical equivalent.
translate_with_env(&self, type_env: &TypeEnvironment) -> Constraint51 fn translate_with_env(&self, type_env: &TypeEnvironment) -> Constraint {
52 self.translate_with(|tv| type_env.get_equivalent(tv))
53 }
54
is_trivial(&self) -> bool55 fn is_trivial(&self) -> bool {
56 match self {
57 Constraint::WiderOrEq(lhs, rhs) => {
58 // Trivially true.
59 if lhs == rhs {
60 return true;
61 }
62
63 let ts1 = lhs.get_typeset();
64 let ts2 = rhs.get_typeset();
65
66 // Trivially true.
67 if ts1.is_wider_or_equal(&ts2) {
68 return true;
69 }
70
71 // Trivially false.
72 if ts1.is_narrower(&ts2) {
73 return true;
74 }
75
76 // Trivially false.
77 if (&ts1.lanes & &ts2.lanes).is_empty() {
78 return true;
79 }
80
81 self.is_concrete()
82 }
83 Constraint::Eq(lhs, rhs) => lhs == rhs || self.is_concrete(),
84 Constraint::InTypeset(_, _) => {
85 // The way InTypeset are made, they would always be trivial if we were applying the
86 // same logic as the Python code did, so ignore this.
87 self.is_concrete()
88 }
89 }
90 }
91
92 /// Returns true iff all the referenced type vars are singletons.
is_concrete(&self) -> bool93 fn is_concrete(&self) -> bool {
94 match self {
95 Constraint::WiderOrEq(lhs, rhs) => {
96 lhs.singleton_type().is_some() && rhs.singleton_type().is_some()
97 }
98 Constraint::Eq(lhs, rhs) => {
99 lhs.singleton_type().is_some() && rhs.singleton_type().is_some()
100 }
101 Constraint::InTypeset(tv, _) => tv.singleton_type().is_some(),
102 }
103 }
104
typevar_args(&self) -> Vec<&TypeVar>105 fn typevar_args(&self) -> Vec<&TypeVar> {
106 match self {
107 Constraint::WiderOrEq(lhs, rhs) => vec![lhs, rhs],
108 Constraint::Eq(lhs, rhs) => vec![lhs, rhs],
109 Constraint::InTypeset(tv, _) => vec![tv],
110 }
111 }
112 }
113
114 #[derive(Clone, Copy)]
115 enum TypeEnvRank {
116 Singleton = 5,
117 Input = 4,
118 Intermediate = 3,
119 Output = 2,
120 Temp = 1,
121 Internal = 0,
122 }
123
124 /// Class encapsulating the necessary bookkeeping for type inference.
125 pub(crate) struct TypeEnvironment {
126 vars: HashSet<VarIndex>,
127 ranks: HashMap<TypeVar, TypeEnvRank>,
128 equivalency_map: HashMap<TypeVar, TypeVar>,
129 pub constraints: Vec<Constraint>,
130 }
131
132 impl TypeEnvironment {
new() -> Self133 fn new() -> Self {
134 TypeEnvironment {
135 vars: HashSet::new(),
136 ranks: HashMap::new(),
137 equivalency_map: HashMap::new(),
138 constraints: Vec::new(),
139 }
140 }
141
register(&mut self, var_index: VarIndex, var: &mut Var)142 fn register(&mut self, var_index: VarIndex, var: &mut Var) {
143 self.vars.insert(var_index);
144 let rank = if var.is_input() {
145 TypeEnvRank::Input
146 } else if var.is_intermediate() {
147 TypeEnvRank::Intermediate
148 } else if var.is_output() {
149 TypeEnvRank::Output
150 } else {
151 assert!(var.is_temp());
152 TypeEnvRank::Temp
153 };
154 self.ranks.insert(var.get_or_create_typevar(), rank);
155 }
156
add_constraint(&mut self, constraint: Constraint)157 fn add_constraint(&mut self, constraint: Constraint) {
158 if self.constraints.iter().any(|item| *item == constraint) {
159 return;
160 }
161
162 // Check extra conditions for InTypeset constraints.
163 if let Constraint::InTypeset(tv, _) = &constraint {
164 assert!(
165 tv.base.is_none(),
166 "type variable is {:?}, while expecting none",
167 tv
168 );
169 assert!(
170 tv.name.starts_with("typeof_"),
171 "Name \"{}\" should start with \"typeof_\"",
172 tv.name
173 );
174 }
175
176 self.constraints.push(constraint);
177 }
178
179 /// Returns the canonical representative of the equivalency class of the given argument, or
180 /// duplicates it if it's not there yet.
get_equivalent(&self, tv: &TypeVar) -> TypeVar181 pub fn get_equivalent(&self, tv: &TypeVar) -> TypeVar {
182 let mut tv = tv;
183 while let Some(found) = self.equivalency_map.get(tv) {
184 tv = found;
185 }
186 match &tv.base {
187 Some(parent) => self
188 .get_equivalent(&parent.type_var)
189 .derived(parent.derived_func),
190 None => tv.clone(),
191 }
192 }
193
194 /// Get the rank of tv in the partial order:
195 /// - TVs directly associated with a Var get their rank from the Var (see register()).
196 /// - Internally generated non-derived TVs implicitly get the lowest rank (0).
197 /// - Derived variables get their rank from their free typevar.
198 /// - Singletons have the highest rank.
199 /// - TVs associated with vars in a source pattern have a higher rank than TVs associated with
200 /// temporary vars.
rank(&self, tv: &TypeVar) -> u8201 fn rank(&self, tv: &TypeVar) -> u8 {
202 let actual_tv = match tv.base {
203 Some(_) => tv.free_typevar(),
204 None => Some(tv.clone()),
205 };
206
207 let rank = match actual_tv {
208 Some(actual_tv) => match self.ranks.get(&actual_tv) {
209 Some(rank) => Some(*rank),
210 None => {
211 assert!(
212 !actual_tv.name.starts_with("typeof_"),
213 "variable {} should be explicitly ranked",
214 actual_tv.name
215 );
216 None
217 }
218 },
219 None => None,
220 };
221
222 let rank = match rank {
223 Some(rank) => rank,
224 None => {
225 if tv.singleton_type().is_some() {
226 TypeEnvRank::Singleton
227 } else {
228 TypeEnvRank::Internal
229 }
230 }
231 };
232
233 rank as u8
234 }
235
236 /// Record the fact that the free tv1 is part of the same equivalence class as tv2. The
237 /// canonical representative of the merged class is tv2's canonical representative.
record_equivalent(&mut self, tv1: TypeVar, tv2: TypeVar)238 fn record_equivalent(&mut self, tv1: TypeVar, tv2: TypeVar) {
239 assert!(tv1.base.is_none());
240 assert!(self.get_equivalent(&tv1) == tv1);
241 if let Some(tv2_base) = &tv2.base {
242 // Ensure there are no cycles.
243 assert!(self.get_equivalent(&tv2_base.type_var) != tv1);
244 }
245 self.equivalency_map.insert(tv1, tv2);
246 }
247
248 /// Get the free typevars in the current type environment.
free_typevars(&self, var_pool: &mut VarPool) -> Vec<TypeVar>249 pub fn free_typevars(&self, var_pool: &mut VarPool) -> Vec<TypeVar> {
250 let mut typevars = Vec::new();
251 typevars.extend(self.equivalency_map.keys().cloned());
252 typevars.extend(
253 self.vars
254 .iter()
255 .map(|&var_index| var_pool.get_mut(var_index).get_or_create_typevar()),
256 );
257
258 let set: HashSet<TypeVar> = HashSet::from_iter(
259 typevars
260 .iter()
261 .map(|tv| self.get_equivalent(tv).free_typevar())
262 .filter(|opt_tv| {
263 // Filter out singleton types.
264 opt_tv.is_some()
265 })
266 .map(|tv| tv.unwrap()),
267 );
268 Vec::from_iter(set)
269 }
270
271 /// Normalize by collapsing any roots that don't correspond to a concrete type var AND have a
272 /// single type var derived from them or equivalent to them.
273 ///
274 /// e.g. if we have a root of the tree that looks like:
275 ///
276 /// typeof_a typeof_b
277 /// \\ /
278 /// typeof_x
279 /// |
280 /// half_width(1)
281 /// |
282 /// 1
283 ///
284 /// we want to collapse the linear path between 1 and typeof_x. The resulting graph is:
285 ///
286 /// typeof_a typeof_b
287 /// \\ /
288 /// typeof_x
normalize(&mut self, var_pool: &mut VarPool)289 fn normalize(&mut self, var_pool: &mut VarPool) {
290 let source_tvs: HashSet<TypeVar> = HashSet::from_iter(
291 self.vars
292 .iter()
293 .map(|&var_index| var_pool.get_mut(var_index).get_or_create_typevar()),
294 );
295
296 let mut children: HashMap<TypeVar, HashSet<TypeVar>> = HashMap::new();
297
298 // Insert all the parents found by the derivation relationship.
299 for type_var in self.equivalency_map.values() {
300 if type_var.base.is_none() {
301 continue;
302 }
303
304 let parent_tv = type_var.free_typevar();
305 if parent_tv.is_none() {
306 // Ignore this type variable, it's a singleton.
307 continue;
308 }
309 let parent_tv = parent_tv.unwrap();
310
311 children
312 .entry(parent_tv)
313 .or_insert_with(HashSet::new)
314 .insert(type_var.clone());
315 }
316
317 // Insert all the explicit equivalency links.
318 for (equivalent_tv, canon_tv) in self.equivalency_map.iter() {
319 children
320 .entry(canon_tv.clone())
321 .or_insert_with(HashSet::new)
322 .insert(equivalent_tv.clone());
323 }
324
325 // Remove links that are straight paths up to typevar of variables.
326 for free_root in self.free_typevars(var_pool) {
327 let mut root = &free_root;
328 while !source_tvs.contains(&root)
329 && children.contains_key(&root)
330 && children.get(&root).unwrap().len() == 1
331 {
332 let child = children.get(&root).unwrap().iter().next().unwrap();
333 assert_eq!(self.equivalency_map[child], root.clone());
334 self.equivalency_map.remove(child);
335 root = child;
336 }
337 }
338 }
339
340 /// Extract a clean type environment from self, that only mentions type vars associated with
341 /// real variables.
extract(self, var_pool: &mut VarPool) -> TypeEnvironment342 fn extract(self, var_pool: &mut VarPool) -> TypeEnvironment {
343 let vars_tv: HashSet<TypeVar> = HashSet::from_iter(
344 self.vars
345 .iter()
346 .map(|&var_index| var_pool.get_mut(var_index).get_or_create_typevar()),
347 );
348
349 let mut new_equivalency_map: HashMap<TypeVar, TypeVar> = HashMap::new();
350 for tv in &vars_tv {
351 let canon_tv = self.get_equivalent(tv);
352 if *tv != canon_tv {
353 new_equivalency_map.insert(tv.clone(), canon_tv.clone());
354 }
355
356 // Sanity check: the translated type map should only refer to real variables.
357 assert!(vars_tv.contains(tv));
358 let canon_free_tv = canon_tv.free_typevar();
359 assert!(canon_free_tv.is_none() || vars_tv.contains(&canon_free_tv.unwrap()));
360 }
361
362 let mut new_constraints: HashSet<Constraint> = HashSet::new();
363 for constraint in &self.constraints {
364 let constraint = constraint.translate_with_env(&self);
365 if constraint.is_trivial() || new_constraints.contains(&constraint) {
366 continue;
367 }
368
369 // Sanity check: translated constraints should refer only to real variables.
370 for arg in constraint.typevar_args() {
371 let arg_free_tv = arg.free_typevar();
372 assert!(arg_free_tv.is_none() || vars_tv.contains(&arg_free_tv.unwrap()));
373 }
374
375 new_constraints.insert(constraint);
376 }
377
378 TypeEnvironment {
379 vars: self.vars,
380 ranks: self.ranks,
381 equivalency_map: new_equivalency_map,
382 constraints: Vec::from_iter(new_constraints),
383 }
384 }
385 }
386
387 /// Replaces an external type variable according to the following rules:
388 /// - if a local copy is present in the map, return it.
389 /// - or if it's derived, create a local derived one that recursively substitutes the parent.
390 /// - or return itself.
substitute(map: &HashMap<&TypeVar, TypeVar>, external_type_var: &TypeVar) -> TypeVar391 fn substitute(map: &HashMap<&TypeVar, TypeVar>, external_type_var: &TypeVar) -> TypeVar {
392 match map.get(&external_type_var) {
393 Some(own_type_var) => own_type_var.clone(),
394 None => match &external_type_var.base {
395 Some(parent) => {
396 let parent_substitute = substitute(map, &parent.type_var);
397 TypeVar::derived(&parent_substitute, parent.derived_func)
398 }
399 None => external_type_var.clone(),
400 },
401 }
402 }
403
404 /// Normalize a (potentially derived) typevar using the following rules:
405 ///
406 /// - vector and width derived functions commute
407 /// {HALF,DOUBLE}VECTOR({HALF,DOUBLE}WIDTH(base)) ->
408 /// {HALF,DOUBLE}WIDTH({HALF,DOUBLE}VECTOR(base))
409 ///
410 /// - half/double pairs collapse
411 /// {HALF,DOUBLE}WIDTH({DOUBLE,HALF}WIDTH(base)) -> base
412 /// {HALF,DOUBLE}VECTOR({DOUBLE,HALF}VECTOR(base)) -> base
canonicalize_derivations(tv: TypeVar) -> TypeVar413 fn canonicalize_derivations(tv: TypeVar) -> TypeVar {
414 let base = match &tv.base {
415 Some(base) => base,
416 None => return tv,
417 };
418
419 let derived_func = base.derived_func;
420
421 if let Some(base_base) = &base.type_var.base {
422 let base_base_tv = &base_base.type_var;
423 match (derived_func, base_base.derived_func) {
424 (DerivedFunc::HalfWidth, DerivedFunc::DoubleWidth)
425 | (DerivedFunc::DoubleWidth, DerivedFunc::HalfWidth)
426 | (DerivedFunc::HalfVector, DerivedFunc::DoubleVector)
427 | (DerivedFunc::DoubleVector, DerivedFunc::HalfVector) => {
428 // Cancelling bijective transformations. This doesn't hide any overflow issues
429 // since derived type sets are checked upon derivaion, and base typesets are only
430 // allowed to shrink.
431 return canonicalize_derivations(base_base_tv.clone());
432 }
433 (DerivedFunc::HalfWidth, DerivedFunc::HalfVector)
434 | (DerivedFunc::HalfWidth, DerivedFunc::DoubleVector)
435 | (DerivedFunc::DoubleWidth, DerivedFunc::DoubleVector)
436 | (DerivedFunc::DoubleWidth, DerivedFunc::HalfVector) => {
437 // Arbitrarily put WIDTH derivations before VECTOR derivations, since they commute.
438 return canonicalize_derivations(
439 base_base_tv
440 .derived(derived_func)
441 .derived(base_base.derived_func),
442 );
443 }
444 _ => {}
445 };
446 }
447
448 canonicalize_derivations(base.type_var.clone()).derived(derived_func)
449 }
450
451 /// Given typevars tv1 and tv2 (which could be derived from one another), constrain their typesets
452 /// to be the same. When one is derived from the other, repeat the constrain process until
453 /// a fixed point is reached.
constrain_fixpoint(tv1: &TypeVar, tv2: &TypeVar)454 fn constrain_fixpoint(tv1: &TypeVar, tv2: &TypeVar) {
455 loop {
456 let old_tv1_ts = tv1.get_typeset().clone();
457 tv2.constrain_types(tv1.clone());
458 if tv1.get_typeset() == old_tv1_ts {
459 break;
460 }
461 }
462
463 let old_tv2_ts = tv2.get_typeset();
464 tv1.constrain_types(tv2.clone());
465 // The above loop should ensure that all reference cycles have been handled.
466 assert!(old_tv2_ts == tv2.get_typeset());
467 }
468
469 /// Unify tv1 and tv2 in the given type environment. tv1 must have a rank greater or equal to tv2's
470 /// one, modulo commutations.
unify(tv1: &TypeVar, tv2: &TypeVar, type_env: &mut TypeEnvironment) -> Result<(), String>471 fn unify(tv1: &TypeVar, tv2: &TypeVar, type_env: &mut TypeEnvironment) -> Result<(), String> {
472 let tv1 = canonicalize_derivations(type_env.get_equivalent(tv1));
473 let tv2 = canonicalize_derivations(type_env.get_equivalent(tv2));
474
475 if tv1 == tv2 {
476 // Already unified.
477 return Ok(());
478 }
479
480 if type_env.rank(&tv2) < type_env.rank(&tv1) {
481 // Make sure tv1 always has the smallest rank, since real variables have the higher rank
482 // and we want them to be the canonical representatives of their equivalency classes.
483 return unify(&tv2, &tv1, type_env);
484 }
485
486 constrain_fixpoint(&tv1, &tv2);
487
488 if tv1.get_typeset().size() == 0 || tv2.get_typeset().size() == 0 {
489 return Err(format!(
490 "Error: empty type created when unifying {} and {}",
491 tv1.name, tv2.name
492 ));
493 }
494
495 let base = match &tv1.base {
496 Some(base) => base,
497 None => {
498 type_env.record_equivalent(tv1, tv2);
499 return Ok(());
500 }
501 };
502
503 if let Some(inverse) = base.derived_func.inverse() {
504 return unify(&base.type_var, &tv2.derived(inverse), type_env);
505 }
506
507 type_env.add_constraint(Constraint::Eq(tv1, tv2));
508 Ok(())
509 }
510
511 /// Perform type inference on one Def in the current type environment and return an updated type
512 /// environment or error.
513 ///
514 /// At a high level this works by creating fresh copies of each formal type var in the Def's
515 /// instruction's signature, and unifying the formal typevar with the corresponding actual typevar.
infer_definition( def: &Def, var_pool: &mut VarPool, type_env: TypeEnvironment, last_type_index: &mut usize, ) -> Result<TypeEnvironment, String>516 fn infer_definition(
517 def: &Def,
518 var_pool: &mut VarPool,
519 type_env: TypeEnvironment,
520 last_type_index: &mut usize,
521 ) -> Result<TypeEnvironment, String> {
522 let apply = &def.apply;
523 let inst = &apply.inst;
524
525 let mut type_env = type_env;
526 let free_formal_tvs = inst.all_typevars();
527
528 let mut original_to_own_typevar: HashMap<&TypeVar, TypeVar> = HashMap::new();
529 for &tv in &free_formal_tvs {
530 assert!(original_to_own_typevar
531 .insert(
532 tv,
533 TypeVar::copy_from(tv, format!("own_{}", last_type_index))
534 )
535 .is_none());
536 *last_type_index += 1;
537 }
538
539 // Update the mapping with any explicity bound type vars:
540 for (i, value_type) in apply.value_types.iter().enumerate() {
541 let singleton = TypeVar::new_singleton(value_type.clone());
542 assert!(original_to_own_typevar
543 .insert(free_formal_tvs[i], singleton)
544 .is_some());
545 }
546
547 // Get fresh copies for each typevar in the signature (both free and derived).
548 let mut formal_tvs = Vec::new();
549 formal_tvs.extend(inst.value_results.iter().map(|&i| {
550 substitute(
551 &original_to_own_typevar,
552 inst.operands_out[i].type_var().unwrap(),
553 )
554 }));
555 formal_tvs.extend(inst.value_opnums.iter().map(|&i| {
556 substitute(
557 &original_to_own_typevar,
558 inst.operands_in[i].type_var().unwrap(),
559 )
560 }));
561
562 // Get the list of actual vars.
563 let mut actual_vars = Vec::new();
564 actual_vars.extend(inst.value_results.iter().map(|&i| def.defined_vars[i]));
565 actual_vars.extend(
566 inst.value_opnums
567 .iter()
568 .map(|&i| apply.args[i].unwrap_var()),
569 );
570
571 // Get the list of the actual TypeVars.
572 let mut actual_tvs = Vec::new();
573 for var_index in actual_vars {
574 let var = var_pool.get_mut(var_index);
575 type_env.register(var_index, var);
576 actual_tvs.push(var.get_or_create_typevar());
577 }
578
579 // Make sure we start unifying with the control type variable first, by putting it at the
580 // front of both vectors.
581 if let Some(poly) = &inst.polymorphic_info {
582 let own_ctrl_tv = &original_to_own_typevar[&poly.ctrl_typevar];
583 let ctrl_index = formal_tvs.iter().position(|tv| tv == own_ctrl_tv).unwrap();
584 if ctrl_index != 0 {
585 formal_tvs.swap(0, ctrl_index);
586 actual_tvs.swap(0, ctrl_index);
587 }
588 }
589
590 // Unify each actual type variable with the corresponding formal type variable.
591 for (actual_tv, formal_tv) in actual_tvs.iter().zip(&formal_tvs) {
592 if let Err(msg) = unify(actual_tv, formal_tv, &mut type_env) {
593 return Err(format!(
594 "fail ti on {} <: {}: {}",
595 actual_tv.name, formal_tv.name, msg
596 ));
597 }
598 }
599
600 // Add any instruction specific constraints.
601 for constraint in &inst.constraints {
602 type_env.add_constraint(constraint.translate_with_map(&original_to_own_typevar));
603 }
604
605 Ok(type_env)
606 }
607
608 /// Perform type inference on an transformation. Return an updated type environment or error.
infer_transform( src: DefIndex, dst: &[DefIndex], def_pool: &DefPool, var_pool: &mut VarPool, ) -> Result<TypeEnvironment, String>609 pub(crate) fn infer_transform(
610 src: DefIndex,
611 dst: &[DefIndex],
612 def_pool: &DefPool,
613 var_pool: &mut VarPool,
614 ) -> Result<TypeEnvironment, String> {
615 let mut type_env = TypeEnvironment::new();
616 let mut last_type_index = 0;
617
618 // Execute type inference on the source pattern.
619 type_env = infer_definition(def_pool.get(src), var_pool, type_env, &mut last_type_index)
620 .map_err(|err| format!("In src pattern: {}", err))?;
621
622 // Collect the type sets once after applying the source patterm; we'll compare the typesets
623 // after we've also considered the destination pattern, and will emit supplementary InTypeset
624 // checks if they don't match.
625 let src_typesets = type_env
626 .vars
627 .iter()
628 .map(|&var_index| {
629 let var = var_pool.get_mut(var_index);
630 let tv = type_env.get_equivalent(&var.get_or_create_typevar());
631 (var_index, tv.get_typeset())
632 })
633 .collect::<Vec<_>>();
634
635 // Execute type inference on the destination pattern.
636 for (i, &def_index) in dst.iter().enumerate() {
637 let def = def_pool.get(def_index);
638 type_env = infer_definition(def, var_pool, type_env, &mut last_type_index)
639 .map_err(|err| format!("line {}: {}", i, err))?;
640 }
641
642 for (var_index, src_typeset) in src_typesets {
643 let var = var_pool.get(var_index);
644 if !var.has_free_typevar() {
645 continue;
646 }
647 let tv = type_env.get_equivalent(&var.get_typevar().unwrap());
648 let new_typeset = tv.get_typeset();
649 assert!(
650 new_typeset.is_subset(&src_typeset),
651 "type sets can only get narrower"
652 );
653 if new_typeset != src_typeset {
654 type_env.add_constraint(Constraint::InTypeset(tv.clone(), new_typeset.clone()));
655 }
656 }
657
658 type_env.normalize(var_pool);
659
660 Ok(type_env.extract(var_pool))
661 }
662