@@ -12,14 +12,50 @@ import ast.tpd._
12
12
13
13
trait TypeOps { this : Context => // TODO: Make standalone object.
14
14
15
+ /** The type `tp` as seen from prefix `pre` and owner `cls`. See the spec
16
+ * for what this means. Called very often, so the code is optimized heavily.
17
+ *
18
+ * A tricky aspect is what to do with unstable prefixes. E.g. say we have a class
19
+ *
20
+ * class C { type T; def f(x: T): T }
21
+ *
22
+ * and an expression `e` of type `C`. Then computing the type of `e.f` leads
23
+ * to the query asSeenFrom(`C`, `(x: T)T`). What should it's result be? The
24
+ * naive answer `(x: C.T)C.T` is incorrect given that we treat `C.T` as the existential
25
+ * `exists(c: C)c.T`. What we need to do instead is to skolemize the existential. So
26
+ * the answer would be `(x: c.T)c.T` for some (unknown) value `c` of type `C`.
27
+ * `c.T` is expressed in the compiler as a skolem type `Skolem(C)`.
28
+ *
29
+ * Now, skolemization is messy and expensive, so we want to do it only if we absolutely
30
+ * must. We must skolemize if an unstable prefix is used in nonvariant or
31
+ * contravariant position of the return type of asSeenFrom.
32
+ *
33
+ * In the implementation of asSeenFrom, we first try to run asSeenFrom without
34
+ * skolemizing. If that would be incorrect we will be told by the fact that
35
+ * `unstable` is set in the passed AsSeenFromMap. In that case we run asSeenFrom
36
+ * again with a skolemized prefix.
37
+ *
38
+ * In the interest of speed we want to avoid creating an AsSeenFromMap every time
39
+ * asSeenFrom is called. So we do this here only if the prefix is unstable
40
+ * (because then we need the map as a container for the unstable field). For
41
+ * stable prefixes the map is `null`; it might however be instantiated later
42
+ * for more complicated types.
43
+ */
15
44
final def asSeenFrom (tp : Type , pre : Type , cls : Symbol ): Type = {
16
45
val m = if (pre.isStable || ! ctx.phase.isTyper) null else new AsSeenFromMap (pre, cls)
17
46
var res = asSeenFrom(tp, pre, cls, m)
18
47
if (m != null && m.unstable) asSeenFrom(tp, SkolemType (pre), cls) else res
19
48
}
20
49
21
- final def asSeenFrom (tp : Type , pre : Type , cls : Symbol , theMap : AsSeenFromMap ): Type = {
50
+ /** Helper method, taking a map argument which is instantiated only for more
51
+ * complicated cases of asSeenFrom.
52
+ */
53
+ private def asSeenFrom (tp : Type , pre : Type , cls : Symbol , theMap : AsSeenFromMap ): Type = {
22
54
55
+ /** Map a `C.this` type to the right prefix. If the prefix is unstable and
56
+ * the `C.this` occurs in nonvariant or contravariant position, mark the map
57
+ * to be unstable.
58
+ */
23
59
def toPrefix (pre : Type , cls : Symbol , thiscls : ClassSymbol ): Type = /* >|>*/ ctx.conditionalTraceIndented(TypeOps .track, s " toPrefix( $pre, $cls, $thiscls) " ) /* <|<*/ {
24
60
if ((pre eq NoType ) || (pre eq NoPrefix ) || (cls is PackageClass ))
25
61
tp
@@ -48,6 +84,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
48
84
if (theMap != null && theMap.unstable && prevStable) {
49
85
pre1.member(tp.name).info match {
50
86
case TypeAlias (alias) =>
87
+ // try to follow aliases of this will avoid skolemization.
51
88
theMap.unstable = false
52
89
return alias
53
90
case _ =>
@@ -73,13 +110,20 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
73
110
}
74
111
}
75
112
113
+ /** The TypeMap handling the asSeenFrom in more complicated cases */
76
114
class AsSeenFromMap (pre : Type , cls : Symbol ) extends TypeMap {
77
115
def apply (tp : Type ) = asSeenFrom(tp, pre, cls, this )
116
+
117
+ /** A method to export the current variance of the map */
78
118
def currentVariance = variance
119
+
120
+ /** A field which indicates whether an unstable argument in nonvariant
121
+ * or contravariant position was encountered.
122
+ */
79
123
var unstable = false
80
124
}
81
125
82
- /** Approximate a type `tp` with a type that does not contain skolem types.
126
+ /** Approximate a type `tp` with a type that does not contain skolem types.
83
127
*/
84
128
final def deskolemize (tp : Type ): Type = deskolemize(tp, 1 , Set ())
85
129
0 commit comments