@@ -5,6 +5,7 @@ package core
5
5
import Contexts ._ , Types ._ , Symbols ._ , Names ._ , Flags ._
6
6
import SymDenotations ._
7
7
import util .Spans ._
8
+ import util .Stats
8
9
import util .SourcePosition
9
10
import NameKinds .DepParamName
10
11
import Decorators ._
@@ -26,11 +27,34 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
26
27
/** The type `tp` as seen from prefix `pre` and owner `cls`. See the spec
27
28
* for what this means.
28
29
*/
29
- final def asSeenFrom (tp : Type , pre : Type , cls : Symbol ): Type =
30
+ final def asSeenFrom (tp : Type , pre : Type , cls : Symbol ): Type = {
31
+ pre match {
32
+ case pre : QualSkolemType =>
33
+ // When a selection has an unstable qualifier, the qualifier type gets
34
+ // wrapped in a `QualSkolemType` so that it may appear soundly as the
35
+ // prefix of a path in the selection type.
36
+ // However, we'd like to avoid referring to skolems when possible since
37
+ // they're an extra level of indirection we usually don't need, so we
38
+ // compute the type as seen from the widened prefix, and in the rare
39
+ // cases where this leads to an approximated type we recompute it with
40
+ // the skolemized prefix. See the i6199* tests for usecases.
41
+ val widenedAsf = new AsSeenFromMap (pre.info, cls)
42
+ val ret = widenedAsf.apply(tp)
43
+
44
+ if (! widenedAsf.approximated)
45
+ return ret
46
+
47
+ Stats .record(" asSeenFrom skolem prefix required" )
48
+ case _ =>
49
+ }
50
+
30
51
new AsSeenFromMap (pre, cls).apply(tp)
52
+ }
31
53
32
54
/** The TypeMap handling the asSeenFrom */
33
55
class AsSeenFromMap (pre : Type , cls : Symbol ) extends ApproximatingTypeMap {
56
+ /** Set to true when the result of `apply` was approximated to avoid an unstable prefix. */
57
+ var approximated : Boolean = false
34
58
35
59
def apply (tp : Type ): Type = {
36
60
@@ -44,7 +68,19 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
44
68
case pre : SuperType => toPrefix(pre.thistpe, cls, thiscls)
45
69
case _ =>
46
70
if (thiscls.derivesFrom(cls) && pre.baseType(thiscls).exists)
47
- if (variance <= 0 && ! isLegalPrefix(pre)) range(defn.NothingType , pre)
71
+ if (variance <= 0 && ! isLegalPrefix(pre)) {
72
+ if (variance < 0 ) {
73
+ approximated = true
74
+ defn.NothingType
75
+ }
76
+ else
77
+ // Don't set the `approximated` flag yet: if this is a prefix
78
+ // of a path, we might be able to dealias the path instead
79
+ // (this is handled in `ApproximatingTypeMap`). If dealiasing
80
+ // is not possible, then `expandBounds` will end up being
81
+ // called which we override to set the `approximated` flag.
82
+ range(defn.NothingType , pre)
83
+ }
48
84
else pre
49
85
else if ((pre.termSymbol is Package ) && ! (thiscls is Package ))
50
86
toPrefix(pre.select(nme.PACKAGE ), cls, thiscls)
@@ -74,9 +110,14 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
74
110
override def reapply (tp : Type ): Type =
75
111
// derived infos have already been subjected to asSeenFrom, hence to need to apply the map again.
76
112
tp
113
+
114
+ override protected def expandBounds (tp : TypeBounds ): Type = {
115
+ approximated = true
116
+ super .expandBounds(tp)
117
+ }
77
118
}
78
119
79
- private def isLegalPrefix (pre : Type )(implicit ctx : Context ) =
120
+ def isLegalPrefix (pre : Type )(implicit ctx : Context ): Boolean =
80
121
pre.isStable || ! ctx.phase.isTyper
81
122
82
123
/** Implementation of Types#simplified */
0 commit comments