@@ -76,6 +76,103 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
76
76
var unstable = false
77
77
}
78
78
79
+ /** Approximate a type `tp` with a type that does not contain skolem types.
80
+ */
81
+ final def deskolemize (tp : Type ): Type = deskolemize(tp, 1 , Set ())
82
+
83
+ private def deskolemize (tp : Type , variance : Int , seen : Set [SkolemType ]): Type = {
84
+ def approx (lo : Type = defn.NothingType , hi : Type = defn.AnyType , newSeen : Set [SkolemType ] = seen) =
85
+ if (variance == 0 ) NoType
86
+ else deskolemize(if (variance < 0 ) lo else hi, variance, newSeen)
87
+ tp match {
88
+ case tp : SkolemType =>
89
+ if (seen contains tp) NoType
90
+ else approx(hi = tp.info, newSeen = seen + tp)
91
+ case tp : NamedType =>
92
+ val sym = tp.symbol
93
+ if (sym.isStatic) tp
94
+ else {
95
+ val pre1 = deskolemize(tp.prefix, variance, seen)
96
+ if (pre1 eq tp.prefix) tp
97
+ else {
98
+ val d = tp.prefix.member(tp.name)
99
+ d.info match {
100
+ case TypeAlias (alias) => deskolemize(alias, variance, seen)
101
+ case _ =>
102
+ if (pre1.exists && ! pre1.isRef(defn.NothingClass )) tp.derivedSelect(pre1)
103
+ else {
104
+ ctx.log(s " deskolem: $tp: ${tp.info}" )
105
+ tp.info match {
106
+ case TypeBounds (lo, hi) => approx(lo, hi)
107
+ case info => approx(defn.NothingType , info)
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ case _ : ThisType | _ : BoundType | _ : SuperType | NoType | NoPrefix =>
114
+ tp
115
+ case tp : RefinedType =>
116
+ val parent1 = deskolemize(tp.parent, variance, seen)
117
+ if (parent1.exists) {
118
+ val refinedInfo1 = deskolemize(tp.refinedInfo, variance, seen)
119
+ if (refinedInfo1.exists)
120
+ tp.derivedRefinedType(parent1, tp.refinedName, refinedInfo1)
121
+ else
122
+ approx(hi = parent1)
123
+ }
124
+ else approx()
125
+ case tp : TypeAlias =>
126
+ val alias1 = deskolemize(tp.alias, variance * tp.variance, seen)
127
+ if (alias1.exists) tp.derivedTypeAlias(alias1)
128
+ else approx(hi = TypeBounds .empty)
129
+ case tp : TypeBounds =>
130
+ val lo1 = deskolemize(tp.lo, - variance, seen)
131
+ val hi1 = deskolemize(tp.hi, variance, seen)
132
+ if (lo1.exists && hi1.exists) tp.derivedTypeBounds(lo1, hi1)
133
+ else approx(hi =
134
+ if (lo1.exists) TypeBounds .lower(lo1)
135
+ else if (hi1.exists) TypeBounds .upper(hi1)
136
+ else TypeBounds .empty)
137
+ case tp : ClassInfo =>
138
+ val pre1 = deskolemize(tp.prefix, variance, seen)
139
+ if (pre1.exists) tp.derivedClassInfo(pre1)
140
+ else NoType
141
+ case tp : AndOrType =>
142
+ val tp1d = deskolemize(tp.tp1, variance, seen)
143
+ val tp2d = deskolemize(tp.tp2, variance, seen)
144
+ if (tp1d.exists && tp2d.exists)
145
+ tp.derivedAndOrType(tp1d, tp2d)
146
+ else if (tp.isAnd)
147
+ approx(hi = tp1d & tp2d) // if one of tp1d, tp2d exists, it is the result of tp1d & tp2d
148
+ else
149
+ approx(lo = tp1d & tp2d)
150
+ case tp : WildcardType =>
151
+ val bounds1 = deskolemize(tp.optBounds, variance, seen)
152
+ if (bounds1.exists) tp.derivedWildcardType(bounds1)
153
+ else WildcardType
154
+ case _ =>
155
+ if (tp.isInstanceOf [MethodicType ]) assert(variance != 0 , tp)
156
+ deskolemizeMap.mapOver(tp, variance, seen)
157
+ }
158
+ }
159
+
160
+ object deskolemizeMap extends TypeMap {
161
+ private var seen : Set [SkolemType ] = _
162
+ def apply (tp : Type ) = deskolemize(tp, variance, seen)
163
+ def mapOver (tp : Type , variance : Int , seen : Set [SkolemType ]) = {
164
+ val savedVariance = this .variance
165
+ val savedSeen = this .seen
166
+ this .variance = variance
167
+ this .seen = seen
168
+ try super .mapOver(tp)
169
+ finally {
170
+ this .variance = savedVariance
171
+ this .seen = savedSeen
172
+ }
173
+ }
174
+ }
175
+
79
176
/** Implementation of Types#simplified */
80
177
final def simplify (tp : Type , theMap : SimplifyMap ): Type = tp match {
81
178
case tp : NamedType =>
0 commit comments