@@ -19,122 +19,81 @@ import ast.tpd._
19
19
trait TypeOps { this : Context => // TODO: Make standalone object.
20
20
21
21
/** The type `tp` as seen from prefix `pre` and owner `cls`. See the spec
22
- * for what this means. Called very often, so the code is optimized heavily.
23
- *
24
- * A tricky aspect is what to do with unstable prefixes. E.g. say we have a class
25
- *
26
- * class C { type T; def f(x: T): T }
27
- *
28
- * and an expression `e` of type `C`. Then computing the type of `e.f` leads
29
- * to the query asSeenFrom(`C`, `(x: T)T`). What should its result be? The
30
- * naive answer `(x: C#T)C#T` is incorrect given that we treat `C#T` as the existential
31
- * `exists(c: C)c.T`. What we need to do instead is to skolemize the existential. So
32
- * the answer would be `(x: c.T)c.T` for some (unknown) value `c` of type `C`.
33
- * `c.T` is expressed in the compiler as a skolem type `Skolem(C)`.
34
- *
35
- * Now, skolemization is messy and expensive, so we want to do it only if we absolutely
36
- * must. Also, skolemizing immediately would mean that asSeenFrom was no longer
37
- * idempotent - each call would return a type with a different skolem.
38
- * Instead we produce an annotated type that marks the prefix as unsafe:
39
- *
40
- * (x: (C @ UnsafeNonvariant)#T)C#T
41
- *
42
- * We also set a global state flag `unsafeNonvariant` to the current run.
43
- * When typing a Select node, typer will check that flag, and if it
44
- * points to the current run will scan the result type of the select for
45
- * @UnsafeNonvariant annotations. If it finds any, it will introduce a skolem
46
- * constant for the prefix and try again.
47
- *
48
- * The scheme is efficient in particular because we expect that unsafe situations are rare;
49
- * most compiles would contain none, so no scanning would be necessary.
22
+ * for what this means.
50
23
*/
51
24
final def asSeenFrom (tp : Type , pre : Type , cls : Symbol ): Type =
52
- asSeenFrom(tp, pre, cls, null )
25
+ new AsSeenFromMap ( pre, cls).apply(tp )
53
26
54
- /** Helper method, taking a map argument which is instantiated only for more
55
- * complicated cases of asSeenFrom.
56
- */
57
- private def asSeenFrom (tp : Type , pre : Type , cls : Symbol , theMap : AsSeenFromMap ): Type = {
58
-
59
- /** Map a `C.this` type to the right prefix. If the prefix is unstable and
60
- * the `C.this` occurs in nonvariant or contravariant position, mark the map
61
- * to be unstable.
62
- */
63
- def toPrefix (pre : Type , cls : Symbol , thiscls : ClassSymbol ): Type = /* >|>*/ ctx.conditionalTraceIndented(TypeOps .track, s " toPrefix( $pre, $cls, $thiscls) " ) /* <|<*/ {
64
- if ((pre eq NoType ) || (pre eq NoPrefix ) || (cls is PackageClass ))
65
- tp
66
- else pre match {
67
- case pre : SuperType => toPrefix(pre.thistpe, cls, thiscls)
68
- case _ =>
69
- if (thiscls.derivesFrom(cls) && pre.baseTypeRef(thiscls).exists) {
70
- if (theMap != null && theMap.currentVariance <= 0 && ! isLegalPrefix(pre)) {
71
- ctx.base.unsafeNonvariant = ctx.runId
72
- pre match {
73
- case AnnotatedType (_, ann) if ann.symbol == defn.UnsafeNonvariantAnnot => pre
74
- case _ => AnnotatedType (pre, Annotation (defn.UnsafeNonvariantAnnot , Nil ))
75
- }
76
- }
77
- else pre
78
- }
79
- else if ((pre.termSymbol is Package ) && ! (thiscls is Package ))
80
- toPrefix(pre.select(nme.PACKAGE ), cls, thiscls)
81
- else
82
- toPrefix(pre.baseTypeRef(cls).normalizedPrefix, cls.owner, thiscls)
27
+ /** The TypeMap handling the asSeenFrom */
28
+ class AsSeenFromMap (pre : Type , cls : Symbol ) extends ApproximatingTypeMap {
29
+
30
+ def apply (tp : Type ): Type = {
31
+
32
+ /** Map a `C.this` type to the right prefix. If the prefix is unstable and
33
+ * the `C.this` occurs in nonvariant or contravariant position, mark the map
34
+ * to be unstable.
35
+ */
36
+ def toPrefix (pre : Type , cls : Symbol , thiscls : ClassSymbol ): Type = /* >|>*/ ctx.conditionalTraceIndented(TypeOps .track, s " toPrefix( $pre, $cls, $thiscls) " ) /* <|<*/ {
37
+ if ((pre eq NoType ) || (pre eq NoPrefix ) || (cls is PackageClass ))
38
+ tp
39
+ else pre match {
40
+ case pre : SuperType => toPrefix(pre.thistpe, cls, thiscls)
41
+ case _ =>
42
+ if (thiscls.derivesFrom(cls) && pre.baseTypeRef(thiscls).exists)
43
+ if (variance <= 0 && ! isLegalPrefix(pre)) Range (pre.bottomType, pre)
44
+ else pre
45
+ else if ((pre.termSymbol is Package ) && ! (thiscls is Package ))
46
+ toPrefix(pre.select(nme.PACKAGE ), cls, thiscls)
47
+ else
48
+ toPrefix(pre.baseTypeRef(cls).normalizedPrefix, cls.owner, thiscls)
49
+ }
83
50
}
84
- }
85
51
86
- /* >|>*/ ctx.conditionalTraceIndented(TypeOps .track, s " asSeen ${tp.show} from ( ${pre.show}, ${cls.show}) " , show = true ) /* <|<*/ { // !!! DEBUG
87
- tp match {
88
- case tp : NamedType =>
89
- val sym = tp.symbol
90
- if (sym.isStatic) tp
91
- else {
92
- val pre1 = asSeenFrom(tp.prefix, pre, cls, theMap)
93
- if (pre1.isUnsafeNonvariant) {
94
- val safeCtx = ctx.withProperty(TypeOps .findMemberLimit, Some (()))
95
- pre1.member(tp.name)(safeCtx).info match {
96
- case TypeAlias (alias) =>
97
- // try to follow aliases of this will avoid skolemization.
98
- return alias
99
- case _ =>
52
+ /* >|>*/ ctx.conditionalTraceIndented(TypeOps .track, s " asSeen ${tp.show} from ( ${pre.show}, ${cls.show}) " , show = true ) /* <|<*/ { // !!! DEBUG
53
+ tp match {
54
+ case tp : NamedType =>
55
+ val sym = tp.symbol
56
+ if (sym.isStatic) tp
57
+ else {
58
+ val pre1 = apply(tp.prefix)
59
+ if (pre1.isUnsafeNonvariant) {
60
+ val safeCtx = ctx.withProperty(TypeOps .findMemberLimit, Some (()))
61
+ pre1.member(tp.name)(safeCtx).info match {
62
+ case TypeAlias (alias) =>
63
+ // try to follow aliases of this will avoid skolemization.
64
+ return alias
65
+ case _ =>
66
+ }
100
67
}
68
+ derivedSelect(tp, pre1)
101
69
}
102
- tp.derivedSelect(pre1)
103
- }
104
- case tp : ThisType =>
105
- toPrefix(pre, cls, tp.cls)
106
- case _ : BoundType | NoPrefix =>
107
- tp
108
- case tp : RefinedType =>
109
- tp.derivedRefinedType(
110
- asSeenFrom(tp.parent, pre, cls, theMap),
111
- tp.refinedName,
112
- asSeenFrom(tp.refinedInfo, pre, cls, theMap))
113
- case tp : TypeAlias if tp.variance == 1 => // if variance != 1, need to do the variance calculation
114
- tp.derivedTypeAlias(asSeenFrom(tp.alias, pre, cls, theMap))
115
- case _ =>
116
- (if (theMap != null ) theMap else new AsSeenFromMap (pre, cls))
117
- .mapOver(tp)
70
+ case tp : ThisType =>
71
+ toPrefix(pre, cls, tp.cls)
72
+ case _ : BoundType | NoPrefix =>
73
+ tp
74
+ case tp : RefinedType =>
75
+ derivedRefinedType(tp, apply(tp.parent), apply(tp.refinedInfo))
76
+ case tp : TypeAlias if tp.variance == 1 => // if variance != 1, need to do the variance calculation
77
+ derivedTypeAlias(tp, apply(tp.alias))
78
+ case _ =>
79
+ mapOver(tp)
80
+ }
118
81
}
119
82
}
83
+
84
+ override def reapply (tp : Type ) =
85
+ // derives infos have already been subjected to asSeenFrom, hence to need to apply the map again.
86
+ tp
120
87
}
121
88
122
89
private def isLegalPrefix (pre : Type )(implicit ctx : Context ) =
123
90
pre.isStable || ! ctx.phase.isTyper
124
91
125
- /** The TypeMap handling the asSeenFrom in more complicated cases */
126
- class AsSeenFromMap (pre : Type , cls : Symbol ) extends TypeMap {
127
- def apply (tp : Type ) = asSeenFrom(tp, pre, cls, this )
128
-
129
- /** A method to export the current variance of the map */
130
- def currentVariance = variance
131
- }
132
-
133
92
/** Approximate a type `tp` with a type that does not contain skolem types. */
134
93
object deskolemize extends ApproximatingTypeMap {
135
94
def apply (tp : Type ) = /* ctx.traceIndented(i"deskolemize($tp) at $variance", show = true)*/ {
136
95
tp match {
137
- case tp : SkolemType => range(hi = atVariance(1 )(apply(tp.info)))
96
+ case tp : SkolemType => range(tp.bottomType, atVariance(1 )(apply(tp.info)))
138
97
case _ => mapOver(tp)
139
98
}
140
99
}
0 commit comments