-
Notifications
You must be signed in to change notification settings - Fork 11
/
TypeRefConverter.scala
116 lines (106 loc) · 3.32 KB
/
TypeRefConverter.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package org.bykn.bosatsu
import cats.Applicative
import cats.data.NonEmptyList
import org.bykn.bosatsu.rankn.Type
import org.bykn.bosatsu.Identifier.Constructor
import cats.implicits._
object TypeRefConverter {
/** given the ability to convert a name to a fully resolved type constant,
* convert TypeRef to Type
*/
def apply[F[_]: Applicative](
t: TypeRef
)(nameToType: Constructor => F[Type.Const]): F[Type] = {
def toType(t: TypeRef): F[Type] = apply(t)(nameToType)
import Type._
import TypeRef._
t match {
case tv @ TypeVar(_) => Applicative[F].pure(TyVar(tv.toBoundVar))
case TypeName(n) => nameToType(n.ident).map(TyConst(_))
case TypeArrow(as, b) =>
(as.traverse(toType(_)), toType(b)).mapN(Fun(_, _))
case TypeApply(a, bs) =>
(toType(a), bs.toList.traverse(toType)).mapN(Type.applyAll(_, _))
case TypeForAll(pars, e) =>
toType(e).map { te =>
Type.forAll(
pars.map { case (TypeVar(v), optK) =>
val k = optK match {
case None => Kind.Type
case Some(k) => k
}
(Type.Var.Bound(v), k)
},
te
)
}
case TypeExists(pars, e) =>
toType(e).map { te =>
Type.exists(
pars.map { case (TypeVar(v), optK) =>
val k = optK match {
case None => Kind.Type
case Some(k) => k
}
(Type.Var.Bound(v), k)
},
te
)
}
case TypeTuple(ts) =>
ts.traverse(toType).map(Type.Tuple(_))
}
}
def fromTypeA[F[_]: Applicative](
tpe: Type,
onSkolem: Type.Var.Skolem => F[TypeRef],
onMeta: Long => F[TypeRef],
onConst: Type.Const.Defined => F[TypeRef]
): F[TypeRef] = {
import Type._
import TypeRef._
def loop(tpe: Type) = fromTypeA(tpe, onSkolem, onMeta, onConst)
tpe match {
case ForAll(vs, in) =>
val args = vs.map { case (Type.Var.Bound(b), k) =>
val k1 = if (k.isType) None else Some(k)
(TypeVar(b), k1)
}
loop(in).map(TypeForAll(args, _))
case Exists(vs, in) =>
val args = vs.map { case (Type.Var.Bound(b), k) =>
val k1 = if (k.isType) None else Some(k)
(TypeVar(b), k1)
}
loop(in).map(TypeExists(args, _))
case Type.Tuple(ts) =>
// this needs to be above TyConst
ts.traverse(loop(_)).map(TypeTuple(_))
case TyConst(defined @ Type.Const.Defined(_, _)) =>
onConst(defined)
case Type.Fun(args, to) =>
(args.traverse(loop), loop(to)).mapN { (ftr, ttr) =>
TypeArrow(ftr, ttr)
}
case ta @ TyApply(_, _) =>
val (on, args) = unapplyAll(ta)
(loop(on), args.traverse(loop)).mapN { (of, arg1) =>
TypeApply(of, NonEmptyList.fromListUnsafe(arg1))
}
case TyVar(tv) =>
tv match {
case Type.Var.Bound(v) =>
Applicative[F].pure(TypeVar(v))
case sk: Type.Var.Skolem =>
onSkolem(sk)
}
case TyMeta(Type.Meta(_, id, _, _)) =>
onMeta(id)
// $COVERAGE-OFF$
case other =>
// the extractors mess this up
sys.error(s"unreachable: $other")
// $COVERAGE-ON$
}
}
}