1use core::panic;
2use std::{collections::VecDeque};
3use crate::parse_type;
4use crate::expr::{Expr,Lambda};
5use crate::dsl::Domain;
6use egg::{Symbol,Id};
7
8
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum UnifyErr {
12 Occurs,
13 ConcreteSubtree,
14 Production
15}
16pub type UnifyResult = Result<(), UnifyErr>;
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub enum Type {
20 Var(usize), Term(Symbol, Vec<Type>), }
24
25
26#[derive(Debug, Clone, PartialEq, Eq, Hash)]
37pub enum TNode {
38 Var(usize), Term(Symbol, Option<RawTypeRef>), ArgCons(RawTypeRef,Option<RawTypeRef>),
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub struct TypeRef {
45 pub raw: RawTypeRef,
46 pub shift: usize,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
50pub struct RawTypeRef(usize);
51
52
53impl RawTypeRef {
54 pub fn shift(&self, shift: usize) -> TypeRef {
55 TypeRef::new(*self,shift)
56 }
57
58 pub fn resolve<'a>(&self, typeset: &'a TypeSet) -> &'a TNode {
59 &typeset.nodes[self.0]
60 }
61
62 #[inline(never)]
64 pub fn tp(&self, typeset: &TypeSet) -> Type {
65 match self.resolve(typeset) {
66 TNode::Var(i) => Type::Var(*i),
67 TNode::Term(p, _) => {
68 Type::Term(*p, self.iter_term_args(typeset).map(|arg| arg.tp(typeset)).collect())
69 },
70 TNode::ArgCons(_, _) => unreachable!()
71 }
72 }
73
74 pub fn show(&self, typeset: &TypeSet) -> String {
75 self.tp(typeset).to_string()
76 }
77
78 pub fn iter_term_args<'a>(&self, typeset: &'a TypeSet) -> TermArgIter<'a> {
79 if let TNode::Term(_,args) = self.resolve(typeset) {
80 TermArgIter { typeset, curr_idx: args}
81 } else {
82 panic!("cant iterate, not a term")
83 }
84 }
85
86 pub fn as_arrow(&self, typeset: &TypeSet) -> Option<(RawTypeRef, RawTypeRef)> {
87 if let TNode::Term(name,_) = self.resolve(typeset) {
88 if *name != *ARROW_SYM {
89 return None
90 }
91 let mut it = self.iter_term_args(typeset);
92 let left = it.next().unwrap();
93 let right = it.next().unwrap();
94 assert!(it.next().is_none(), "malformed arrow");
95 Some((left,right))
96 } else {
97 None
98 }
99 }
100
101 pub fn is_arrow(&self, typeset: &TypeSet) -> bool {
102 if let TNode::Term(name,_) = self.resolve(typeset) {
103 return *name == *ARROW_SYM
104 }
105 false
106 }
107
108 pub fn iter_arrows<'a>(&self, typeset: &'a TypeSet) -> ArrowIterTypeRef<'a> {
110 ArrowIterTypeRef { curr: *self, typeset }
111 }
112
113 pub fn iter_args<'a>(&self, typeset: &'a TypeSet) -> impl Iterator<Item=RawTypeRef> + 'a {
115 self.iter_arrows(typeset).map(|(left,_right)| left)
116 }
117
118 pub fn arity(&self, typeset: &TypeSet) -> usize {
120 self.iter_args(typeset).count()
121 }
122
123 pub fn return_type(&self, typeset: &TypeSet) -> RawTypeRef {
126 self.iter_arrows(typeset).last().map(|(_left,right)| right).unwrap_or(*self)
127 }
128
129 pub fn is_concrete(&self, typeset: &TypeSet) -> bool {
131 match self.resolve(typeset) {
132 TNode::Var(_) => false,
133 TNode::Term(_, _) => self.iter_term_args(typeset).all(|ty| ty.is_concrete(typeset)),
134 TNode::ArgCons(_,_) => panic!("is_concrete on an ArgCons")
135 }
136 }
137
138 pub fn max_var(&self, typeset: &TypeSet) -> Option<usize> {
139 match self.resolve(typeset) {
140 TNode::Var(i) => Some(*i),
141 TNode::Term(_, _) => self.iter_term_args(typeset).filter_map(|ty| ty.max_var(typeset)).max(),
142 TNode::ArgCons(_,_) => panic!("is_concrete on an ArgCons")
143 }
144 }
145
146 pub fn instantiate(&self, typeset: &mut TypeSet) -> TypeRef {
147 let shift_by = typeset.next_var;
148 if let Some(max_var) = self.max_var(typeset) {
149 for _ in 0..=max_var {
151 typeset.fresh_type_var();
152 }
153 }
154 TypeRef::new(*self, shift_by)
155 }
156
157}
158
159
160impl TypeRef {
161 fn new(raw: RawTypeRef, shift: usize) -> TypeRef {
162 TypeRef {raw, shift}
163 }
164
165 pub fn canonicalize(&self, typeset: &TypeSet) -> TypeRef {
167 if let TNode::Var(i) = self.raw.resolve(typeset) {
168 if let Some(tp_ref) = typeset.get_var(*i + self.shift) {
169 return tp_ref.canonicalize(typeset) }
172 }
173 *self
174 }
175
176 pub fn resolve(&self, typeset: &TypeSet) -> TNode {
179 let canonical = self.canonicalize(typeset);
180 let resolved = canonical.raw.resolve(typeset);
181 match resolved {
182 TNode::Var(i) => TNode::Var(i + canonical.shift), _ => resolved.clone()
184 }
185 }
186
187 pub fn tp(&self, typeset: &TypeSet) -> Type {
188 self.raw.tp(typeset)
189 }
190
191 pub fn show(&self, typeset: &TypeSet) -> String {
192 format!("[shift {}] {}", self.shift, self.raw.tp(typeset))
193 }
194
195 pub fn iter_term_args<'a>(&'a self, typeset: &'a TypeSet) -> impl Iterator<Item=TypeRef> + 'a {
196 let canonical = self.canonicalize(typeset);
197 canonical.raw.iter_term_args(typeset).map(move |raw| raw.shift(canonical.shift))
198 }
199
200 pub fn as_arrow(&self, typeset: &TypeSet) -> Option<(TypeRef, TypeRef)> {
201 let canonical = self.canonicalize(typeset);
202 canonical.raw.as_arrow(typeset).map(|(r1,r2)| (r1.shift(canonical.shift),r2.shift(canonical.shift)))
203 }
204
205 pub fn is_arrow(&self, typeset: &TypeSet) -> bool {
206 if let TNode::Term(name,_) = self.resolve(typeset) {
207 return name == *ARROW_SYM
208 }
209 false
210 }
211
212 pub fn iter_arrows<'a>(&'a self, typeset: &'a TypeSet) -> impl Iterator<Item=(TypeRef,TypeRef)> + 'a {
214 let canonical = self.canonicalize(typeset);
215 canonical.raw.iter_arrows(typeset).map(move |(r1,r2)| (r1.shift(canonical.shift),r2.shift(canonical.shift)))
216 }
217
218 pub fn iter_args<'a>(&'a self, typeset: &'a TypeSet) -> impl Iterator<Item=TypeRef> + 'a {
220 self.iter_arrows(typeset).map(|(left,_right)| left)
221 }
222
223 pub fn arity(&self, typeset: &TypeSet) -> usize {
225 self.iter_args(typeset).count()
226 }
227
228 pub fn return_type(&self, typeset: &TypeSet) -> TypeRef {
231 self.iter_arrows(typeset).last().map(|(_left,right)| right).unwrap_or(*self)
232 }
233
234 pub fn is_concrete(&self, typeset: &TypeSet) -> bool {
236 match self.resolve(typeset) {
237 TNode::Var(_) => false,
238 TNode::Term(_, _) => self.iter_term_args(typeset).all(|ty| ty.is_concrete(typeset)),
239 TNode::ArgCons(_,_) => panic!("is_concrete on an ArgCons")
240 }
241 }
242
243 pub fn occurs(&self, i: usize, typeset: &TypeSet) -> bool {
245 let resolved = self.resolve(typeset);
253
254 match resolved {
257 TNode::Var(j) => i == j,
258 TNode::Term(_, _) => {
259 self.iter_term_args(typeset).any(|ty| ty.occurs(i, typeset))
261 },
262 TNode::ArgCons(_, _) => panic!("occurs() on ArgCons")
263 }
264 }
265
266}
267
268#[derive(Debug, Clone, PartialEq, Eq)]
269pub struct TypeSet {
270 pub nodes: Vec<TNode>,
271 pub subst: Vec<(usize,TypeRef)>,
272 pub next_var: usize,
273}
274
275impl TypeSet {
276 pub fn add_tp(&mut self, tp: &Type) -> RawTypeRef {
277 match tp {
278 Type::Var(i) => {
279 self.nodes.push(TNode::Var(*i));
280 RawTypeRef(self.nodes.len() - 1)
281 }
282 Type::Term(p, args) => {
283 let mut arg_cons = None;
284 for arg in args.iter().rev() {
285 let arg_hd = self.add_tp(arg);
286 self.nodes.push(TNode::ArgCons(arg_hd, arg_cons));
287 arg_cons = Some(RawTypeRef(self.nodes.len() - 1));
288 }
289 self.nodes.push(TNode::Term(*p, arg_cons));
290 RawTypeRef(self.nodes.len() - 1)
291 },
292 }
293 }
294 pub fn empty() -> TypeSet {
297 TypeSet {
298 nodes: Default::default(),
299 subst: Default::default(),
300 next_var: 0,
301 }
302 }
303
304 pub fn save_state(&self) -> (usize,usize) {
305 (self.subst.len(), self.next_var)
306 }
307
308 pub fn load_state(&mut self, state: (usize,usize)) {
309 self.subst.truncate(state.0);
310 self.next_var = state.1;
311 }
312
313 fn fresh_type_var(&mut self) -> Type {
314 self.next_var += 1;
315 Type::Var(self.next_var-1)
316 }
317
318 pub fn might_unify(&self, t1: &RawTypeRef, t2: &TypeRef) -> bool {
335 let node1 = t1.resolve(self);
336 let node2 = t2.resolve(self);
337 match (node1,node2) {
338 (TNode::Var(_), TNode::Var(_)) => true,
339 (TNode::Var(_), TNode::Term(_, _)) => true,
340 (TNode::Term(_, _), TNode::Var(_)) => true,
341 (TNode::Term(x, _), TNode::Term(y, _)) => {
342 *x == y && t1.arity(self) == t2.arity(self) && t1.iter_term_args(self).zip(t2.iter_term_args(self)).all(|(x,y)| self.might_unify(&x,&y))
343 },
344 _ => panic!("attempting to unify ArgCons or some other invalid constructor"),
345 }
346 }
347
348 pub fn unify(&mut self, t1: &TypeRef, t2: &TypeRef) -> UnifyResult {
352 match ((t1.resolve(self),t1.canonicalize(self)), (t2.resolve(self),t2.canonicalize(self))) {
360 ((TNode::Var(i), _), (other, tref_other))
361 | ((other, tref_other), (TNode::Var(i),_)) =>
362 {
363 if other == TNode::Var(i) { return Ok(()) } if tref_other.occurs(i, self) { return Err(UnifyErr::Occurs) } assert!(self.get_var(i).is_none());
373 self.set_var(i, tref_other);
374 Ok(())
375 },
376 ((TNode::Term(x, _),tref_x), (TNode::Term(y, _),tref_y)) =>
377 {
378 if x != y || tref_x.arity(self) != tref_y.arity(self) {
381 return Err(UnifyErr::Production)
382 }
383 tref_x.iter_term_args(self).zip(tref_y.iter_term_args(self)).collect::<Vec<_>>().into_iter().try_for_each(|(x,y)| self.unify(&x,&y))
385 }
386 _ => unreachable!()
387 }
388 }
389
390 #[inline(always)]
392 fn get_var(&self, var: usize) -> Option<&TypeRef> { self.subst.iter().rfind(|(i,_)| *i == var).map(|(_,tp)| tp)
394 }
395 #[inline(always)]
397 fn set_var(&mut self, var: usize, ty: TypeRef) {
398 self.subst.push((var,ty));
399 }
400}
401
402
403
404
405lazy_static::lazy_static! {
406 static ref ARROW_SYM: egg::Symbol = Symbol::from(Type::ARROW);
407}
408
409impl Type {
410 pub const ARROW: &'static str = "->";
411
412 pub fn base(name: Symbol) -> Type {
413 Type::Term(name, vec![])
414 }
415
416 pub fn arrow(left: Type, right: Type) -> Type {
417 Type::Term(*ARROW_SYM, vec![left, right])
418 }
419
420 pub fn is_arrow(&self) -> bool {
421 match self {
422 Type::Var(_) => false,
423 Type::Term(name, _) => *name == *ARROW_SYM,
424 }
425 }
426
427 pub fn as_arrow(&self) -> Option<(&Type, &Type)> {
428 match self {
429 Type::Term(name,args) => {
430 if *name != *ARROW_SYM {
431 return None
432 }
433 assert_eq!(args.len(),2);
434 Some((&args[0], &args[1]))
435 },
436 _ => None
437 }
438 }
439
440 pub fn iter_arrows(&self) -> ArrowIter {
448 ArrowIter { curr: self }
449 }
450
451 pub fn iter_args(&self) -> impl Iterator<Item=&Type> {
453 self.iter_arrows().map(|(left,_right)| left)
454 }
455
456 pub fn arity(&self) -> usize {
458 self.iter_args().count()
459 }
460
461 pub fn return_type(&self) -> &Type {
464 self.iter_arrows().last().map(|(_left,right)| right).unwrap_or(self)
465 }
466
467 pub fn is_concrete(&self) -> bool {
469 match self {
470 Type::Var(_) => false,
471 Type::Term(_, args) => args.iter().all(|ty| ty.is_concrete())
472 }
473 }
474
475 pub fn occurs(&self, i: usize) -> bool {
477 match self {
478 Type::Var(j) => i == *j,
479 Type::Term(_, args) => args.iter().any(|ty| ty.occurs(i))
480 }
481 }
482
483 pub fn apply_cached(&self, ctx: &mut Context) -> Type {
484 if self.is_concrete() {
485 return self.clone();
486 }
487 match self {
488 Type::Var(i) => {
489 if let Some(tp) = ctx.get(*i).cloned() {
491 let tp_applied = tp.apply(ctx);
493 if tp != tp_applied {
494 ctx.set(*i, tp_applied.clone())
497 }
498 tp_applied
499 } else {
500 self.clone() }
502 },
503 Type::Term(name, args) => Type::Term(*name, args.iter().map(|ty| ty.apply_cached(ctx)).collect())
504 }
505 }
506
507 pub fn apply(&self, ctx: &Context) -> Type {
509 if self.is_concrete() {
510 return self.clone();
511 }
512 match self {
513 Type::Var(i) => {
514 if let Some(tp) = ctx.get(*i).cloned() {
516 tp.apply(ctx)
518 } else {
519 self.clone() }
521 },
522 Type::Term(name, args) => Type::Term(*name, args.iter().map(|ty| ty.apply(ctx)).collect())
523 }
524 }
525
526
527 pub fn instantiate(&self, ctx: &mut Context) -> Type {
529 if self.is_concrete() {
530 return self.clone()
531 }
532 fn instantiate_aux(ty: &Type, ctx: &mut Context, shift_by: usize) -> Type {
533 match ty {
534 Type::Var(i) => {
535 let new = i + shift_by;
536 ctx.fresh_type_vars(new);
537 assert!(ctx.get(new).is_none());
538 Type::Var(new)
539 },
540 Type::Term(name, args) => Type::Term(*name, args.iter().map(|t| instantiate_aux(t, ctx, shift_by)).collect()),
541 }
542 }
543 instantiate_aux(self, ctx, ctx.next_var)
545 }
546}
547
548pub struct ArrowIter<'a> {
549 curr: &'a Type
550}
551
552impl<'a> Iterator for ArrowIter<'a> {
553 type Item = (&'a Type, &'a Type);
554
555 fn next(&mut self) -> Option<Self::Item> {
556 if let Some((left,right)) = self.curr.as_arrow() {
557 self.curr = right;
558 Some((left,right))
559 } else {
560 None
561 }
562 }
563}
564
565pub struct ArrowIterTypeRef<'a> {
566 typeset: &'a TypeSet,
567 curr: RawTypeRef,
568}
569
570impl<'a> Iterator for ArrowIterTypeRef<'a> {
571 type Item = (RawTypeRef,RawTypeRef);
572
573 fn next(&mut self) -> Option<Self::Item> {
574 if let Some((left,right)) = self.curr.as_arrow(self.typeset) {
575 self.curr = right;
576 Some((left,right))
577 } else {
578 None
579 }
580 }
581}
582
583pub struct TermArgIter<'a> {
584 typeset: &'a TypeSet,
585 curr_idx: &'a Option<RawTypeRef>,
586}
587
588impl<'a> Iterator for TermArgIter<'a> {
589 type Item = RawTypeRef;
590
591 fn next(&mut self) -> Option<Self::Item> {
592 if let Some(curr_idx) = self.curr_idx {
593 if let TNode::ArgCons(arg,tl) = curr_idx.resolve(self.typeset) {
594 self.curr_idx = tl;
595 Some(*arg)
596 } else {
597 panic!("Cant iterate over something that's not a term")
598 }
599 } else {
600 None
601 }
602 }
603}
604
605
606
607impl std::str::FromStr for Type {
608 type Err = String;
609 fn from_str(s: &str) -> Result<Self, Self::Err> {
610 parse_type::parse(s)
611 }
612}
613
614impl std::fmt::Display for Type {
615 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
616 fn helper(ty: &Type, f: &mut std::fmt::Formatter<'_>, arrow_parens: bool) -> std::fmt::Result {
617 match ty {
618 Type::Var(i) => write!(f,"t{}", i),
619 Type::Term(name, args) => {
620 if args.is_empty() {
621 write!(f, "{}", name)
622 } else if *name == *ARROW_SYM {
623 assert_eq!(args.len(), 2);
624 if arrow_parens {
626 write!(f, "(")?;
627 }
628 helper(&args[0], f, true)?;
629 write!(f, " {} ", Type::ARROW)?;
630 helper(&args[1], f, false)?;
631 if arrow_parens {
632 write!(f, ")")?;
633 }
634 Ok(())
635 } else {
636 write!(f, "({}", name)?;
637 for arg in args.iter() {
638 write!(f, " ")?;
639 helper(arg, f, true)?;
640 }
641 write!(f, ")")
642 }
643 },
644 }
645 }
646 helper(self, f, true)
647 }
648}
649
650
651#[derive(Debug, Clone, PartialEq, Eq)]
652pub struct Context {
653 subst_unionfind: Vec<Option<Type>>, subst_append_only: Vec<(usize,Type)>,
655 next_var: usize,
656 append_only: bool,
657}
658
659impl Context {
660
661 pub fn empty() -> Context {
664 Context {
665 subst_unionfind: Default::default(),
666 subst_append_only: Default::default(),
667 next_var: 0,
668 append_only: true,
669 }
670 }
671
672 pub fn empty_unionfind() -> Context {
675 Context {
676 subst_unionfind: Default::default(),
677 subst_append_only: Default::default(),
678 next_var: 0,
679 append_only: false,
680 }
681 }
682
683 pub fn save_state(&self) -> (usize,usize) {
684 assert!(self.append_only);
685 (self.subst_append_only.len(), self.next_var)
686 }
687
688 pub fn load_state(&mut self, state: (usize,usize)) {
689 assert!(self.append_only);
690 self.subst_append_only.truncate(state.0);
691 self.next_var = state.1;
692 }
693
694 fn fresh_type_var(&mut self) -> Type {
695 if !self.append_only {
696 self.subst_unionfind.push(None);
697 }
698 self.next_var += 1;
699 Type::Var(self.next_var-1)
700 }
701
702 #[inline(always)]
704 fn fresh_type_vars(&mut self, var: usize) {
705 while var >= self.next_var {
706 self.fresh_type_var();
707 }
708 }
709
710 pub fn might_unify(&self, t1: &Type, t2: &Type) -> bool {
719 match (t1,t2) {
720 (Type::Var(_), Type::Var(_)) => true,
721 (Type::Var(_), Type::Term(_, _)) => true,
722 (Type::Term(_, _), Type::Var(_)) => true,
723 (Type::Term(x, xs), Type::Term(y, ys)) => {
724 x == y && xs.len() == ys.len() && xs.iter().zip(ys.iter()).all(|(x,y)| self.might_unify(x,y))
725 },
726 }
727 }
728
729 pub fn unify(&mut self, t1: &Type, t2: &Type) -> UnifyResult {
733 let t1: Type = t1.apply(self);
735 let t2: Type = t2.apply(self);
736 if t1.is_concrete() && t2.is_concrete() {
738 if t1 == t2 {
740 return Ok(())
741 } else {
742 return Err(UnifyErr::ConcreteSubtree)
743 }
744 }
745 match (t1, t2) {
746 (Type::Var(i), ty) | (ty, Type::Var(i)) => {
747 if ty == Type::Var(i) { return Ok(()) } if ty.occurs(i) { return Err(UnifyErr::Occurs) } assert!(self.get(i).is_none());
752 self.set(i, ty);
753 Ok(())
754 },
755 (Type::Term(x, xs), Type::Term(y, ys)) => {
756 if x != y || xs.len() != ys.len() {
758 return Err(UnifyErr::Production)
759 }
760 xs.iter().zip(ys.iter()).try_for_each(|(x,y)| self.unify(x,y))
761 }
762 }
763 }
764
765 pub fn unify_cached(&mut self, t1: &Type, t2: &Type) -> UnifyResult {
768 let t1: Type = t1.apply_cached(self);
770 let t2: Type = t2.apply_cached(self);
771 if t1.is_concrete() && t2.is_concrete() {
773 if t1 == t2 {
775 return Ok(())
776 } else {
777 return Err(UnifyErr::ConcreteSubtree)
778 }
779 }
780 match (t1, t2) {
781 (Type::Var(i), ty) | (ty, Type::Var(i)) => {
782 if ty == Type::Var(i) { return Ok(()) } if ty.occurs(i) { return Err(UnifyErr::Occurs) } assert!(self.subst_unionfind.get(i).is_none());
787 self.set(i, ty);
788 Ok(())
789 },
790 (Type::Term(x, xs), Type::Term(y, ys)) => {
791 if x != y || xs.len() != ys.len() {
793 return Err(UnifyErr::Production)
794 }
795 xs.iter().zip(ys.iter()).try_for_each(|(x,y)| self.unify(x,y))
796 }
797 }
798 }
799
800 #[inline(always)]
802 fn get(&self, var: usize) -> Option<&Type> { if self.append_only {
804 self.subst_append_only.iter().rfind(|(i,_)| *i == var).map(|(_,tp)| tp)
805 } else {
806 self.subst_unionfind[var].as_ref()
807 }
808 }
809 #[inline(always)]
811 fn set(&mut self, var: usize, ty: Type) {
812 if self.append_only {
813 self.subst_append_only.push((var,ty));
814 } else {
815 self.subst_unionfind[var] = Some(ty);
816 }
817 }
818
819}
820
821impl std::fmt::Display for Context {
822 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
823 write!(f,"{{")?;
824 let mut first: bool = true;
825 for (i, item) in self.subst_unionfind.iter().enumerate() {
826 if let Some(ty) = item {
827 if !first { write!(f, ", ")? } else { first = false }
828 write!(f, "{}:{}", i, ty)?
829 }
830 }
831 write!(f,"}}")
832 }
833}
834
835
836impl Expr {
837 pub fn infer<D: Domain>(&self, child: Option<Id>, ctx: &mut Context, env: &mut VecDeque<Type>) -> Result<Type,UnifyErr> {
838 let child = child.unwrap_or_else(||self.root());
840 match &self.nodes[usize::from(child)] {
841 Lambda::App([f,x]) => {
842 let return_tp = ctx.fresh_type_var();
843 let x_tp = self.infer::<D>(Some(*x), ctx, env)?;
844 let f_tp = self.infer::<D>(Some(*f), ctx, env)?;
845 ctx.unify(&f_tp, &Type::arrow(x_tp, return_tp.clone()))?;
846 Ok(return_tp.apply(ctx))
847 },
848 Lambda::Lam([b]) => {
849 let var_tp = ctx.fresh_type_var();
850 env.push_front(var_tp.clone());
852 let body_tp = self.infer::<D>(Some(*b), ctx, env)?;
853 env.pop_front();
854 Ok(Type::arrow(var_tp, body_tp).apply(ctx))
855 },
856 Lambda::Var(i) => {
857 if (*i as usize) >= env.len() {
858 panic!("unbound variable encountered during infer(): ${}", i)
859 }
860 Ok(env[*i as usize].apply(ctx))
861 },
862 Lambda::IVar(_i) => {
863 unimplemented!();
865 }
866 Lambda::Prim(p) => {
867 Ok(D::type_of_prim(*p).instantiate(ctx))
868 },
869 Lambda::Programs(_) => panic!("trying to infer() type of Programs() node"),
870 }
871 }
872}
873
874