Skip to content

Commit e0d2567

Browse files
committed
Document asSeenFrom
1 parent 8232261 commit e0d2567

File tree

1 file changed

+46
-2
lines changed

1 file changed

+46
-2
lines changed

src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,50 @@ import ast.tpd._
1212

1313
trait TypeOps { this: Context => // TODO: Make standalone object.
1414

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+
*/
1544
final def asSeenFrom(tp: Type, pre: Type, cls: Symbol): Type = {
1645
val m = if (pre.isStable || !ctx.phase.isTyper) null else new AsSeenFromMap(pre, cls)
1746
var res = asSeenFrom(tp, pre, cls, m)
1847
if (m != null && m.unstable) asSeenFrom(tp, SkolemType(pre), cls) else res
1948
}
2049

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 = {
2254

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+
*/
2359
def toPrefix(pre: Type, cls: Symbol, thiscls: ClassSymbol): Type = /*>|>*/ ctx.conditionalTraceIndented(TypeOps.track, s"toPrefix($pre, $cls, $thiscls)") /*<|<*/ {
2460
if ((pre eq NoType) || (pre eq NoPrefix) || (cls is PackageClass))
2561
tp
@@ -48,6 +84,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
4884
if (theMap != null && theMap.unstable && prevStable) {
4985
pre1.member(tp.name).info match {
5086
case TypeAlias(alias) =>
87+
// try to follow aliases of this will avoid skolemization.
5188
theMap.unstable = false
5289
return alias
5390
case _ =>
@@ -73,13 +110,20 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
73110
}
74111
}
75112

113+
/** The TypeMap handling the asSeenFrom in more complicated cases */
76114
class AsSeenFromMap(pre: Type, cls: Symbol) extends TypeMap {
77115
def apply(tp: Type) = asSeenFrom(tp, pre, cls, this)
116+
117+
/** A method to export the current variance of the map */
78118
def currentVariance = variance
119+
120+
/** A field which indicates whether an unstable argument in nonvariant
121+
* or contravariant position was encountered.
122+
*/
79123
var unstable = false
80124
}
81125

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.
83127
*/
84128
final def deskolemize(tp: Type): Type = deskolemize(tp, 1, Set())
85129

0 commit comments

Comments
 (0)