-
Notifications
You must be signed in to change notification settings - Fork 3
/
Untyper.scala
121 lines (107 loc) · 4.93 KB
/
Untyper.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
117
118
119
120
121
package com.thoughtworks.feature
import scala.reflect.api.Universe
import com.thoughtworks.Extractor._
/** A utility to convert [[scala.reflect.api.Universe.Type Type]] to [[scala.reflect.api.Universe.Tree Tree]].
*
* @note The primary intent of '''Untyper''' class is for some macro libraries in this [[https://github.com/ThoughtWorksInc/feature.scala feature.scala]] project,
* although it may also useful for other projects.
*
* @author 杨博 (Yang Bo) <pop.atry@gmail.com>
*/
class Untyper[Universe <: Singleton with scala.reflect.api.Universe](val universe: Universe) {
import universe._
/** Returns the instance tree for given singleton type */
def singletonValue: PartialFunction[Type, Tree] = {
case ThisType(symbol) =>
q"$symbol.this"
case SingleType(NoPrefix, sym) =>
q"${sym.name.toTermName}"
case SingleType(pre, sym) if pre.typeSymbol.isPackage =>
q"$sym"
case SingleType(singletonValue.extract(pre), sym) =>
q"$pre.$sym"
case SuperType(singletonValue.extract(thisValue), ThisType(superSymbol)) =>
Super(thisValue, superSymbol.name.toTypeName)
case SingleType(untype.extract(pre), sym) =>
SelectFromTypeTree(pre, sym.name.toTypeName)
}
def termSymbol: PartialFunction[Symbol, TermSymbol] = {
case symbol if symbol.isTerm => symbol.asTerm
}
def typeSymbol: PartialFunction[Symbol, TypeSymbol] = {
case symbol if symbol.isType => symbol.asType
}
def typeDefinitionSymbol: PartialFunction[TypeSymbol, (TypeName, Seq[Symbol], Type)] = {
case symbol if !symbol.isClass =>
val info = symbol.info
(symbol.name.toTypeName, info.typeParams, info.resultType)
}
def varDefinitionSymbol: PartialFunction[TermSymbol, (TermName, Type)] = {
case symbol if symbol.isVar =>
(symbol.name.toTermName, symbol.info.resultType)
}
def valDefinitionSymbol: PartialFunction[TermSymbol, (TermName, Type)] = {
case symbol if symbol.isVal || symbol.isStable =>
(symbol.name.toTermName, symbol.info.resultType)
}
def defDefinitionSymbol: PartialFunction[TermSymbol, (TermName, Seq[Symbol], Seq[Seq[Symbol]], Type)] = {
case symbol if symbol.isMethod =>
val info = symbol.info
(symbol.name.toTermName, info.typeParams, info.paramLists, info.finalResultType)
}
def typeDefinition: PartialFunction[TypeSymbol, TypeDef] = {
case typeSymbol.extract(
typeDefinitionSymbol.extract(name,
typeDefinition.extract.forall(params),
TypeBounds(untype.extract(upper), untype.extract(lower)))) =>
q"type $name[..$params] >: $upper <: $lower"
case typeSymbol.extract(
typeDefinitionSymbol
.extract(name, typeDefinition.extract.forall(params: Seq[TypeDef]), untype.extract(concreteType))) =>
q"type $name[..$params] = $concreteType"
}
def definition: PartialFunction[Symbol, Tree] = {
case typeDefinition.extract(typeDef) => typeDef
case termDefinition.extract(termDef) => termDef
}
def termDefinition: PartialFunction[Symbol, Tree] = {
case termSymbol.extract(varDefinitionSymbol.extract(name, untype.extract(result))) =>
q"var $name: $result"
case termSymbol.extract(symbol @ valDefinitionSymbol.extract(name, untype.extract(result))) =>
if (symbol.isImplicit) {
q"implicit val $name: $result"
} else {
q"val $name: $result"
}
case termSymbol.extract(
defDefinitionSymbol.extract(name,
typeDefinition.extract.forall(typeParams),
termDefinition.extract.forall.forall(params),
untype.extract(result))) =>
q"def $name[..$typeParams](...$params): $result"
}
def untype: PartialFunction[Type, Tree] = {
case ConstantType(value) =>
Literal(value)
case singletonValue.extract(value) =>
tq"$value.type"
case TypeRef(NoPrefix, sym, args) =>
tq"${sym.name.toTypeName}[..${args.map(untype)}]"
case TypeRef(pre, sym, args) if pre.typeSymbol.isPackage =>
tq"$sym[..${args.map(untype)}]"
case TypeRef(singletonValue.extract(pre), sym, args) =>
tq"$pre.$sym[..${args.map(untype)}]"
case TypeRef(untype.extract(pre), sym, args) =>
tq"$pre#$sym[..${args.map(untype)}]"
case RefinedType(untype.extract.forall(parents), decls) =>
CompoundTypeTree(Template(parents.toList, noSelfType, decls.view.map(definition).toList))
case PolyType(typeSymbol.extract.forall(typeDefinition.extract.forall(typeParams)), untype.extract(resultType)) =>
tq"({type Λ$$[..$typeParams] = $resultType})#Λ$$"
case ExistentialType(definition.extract.forall(quantified), untype.extract(underlying)) =>
tq"$underlying forSome { ..$quantified }"
case AnnotatedType(annotations, untype.extract(underlying)) =>
annotations.foldLeft(underlying) { (tree, annotation) =>
Annotated(annotation.tree, tree)
}
}
}