@@ -5,6 +5,7 @@ package core
55import Contexts ._ , Types ._ , Symbols ._ , Names ._ , Flags ._
66import SymDenotations ._
77import util .Spans ._
8+ import util .Stats
89import util .SourcePosition
910import NameKinds .DepParamName
1011import Decorators ._
@@ -26,11 +27,34 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
2627 /** The type `tp` as seen from prefix `pre` and owner `cls`. See the spec
2728 * for what this means.
2829 */
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+
3051 new AsSeenFromMap (pre, cls).apply(tp)
52+ }
3153
3254 /** The TypeMap handling the asSeenFrom */
3355 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
3458
3559 def apply (tp : Type ): Type = {
3660
@@ -44,7 +68,19 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
4468 case pre : SuperType => toPrefix(pre.thistpe, cls, thiscls)
4569 case _ =>
4670 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+ }
4884 else pre
4985 else if ((pre.termSymbol is Package ) && ! (thiscls is Package ))
5086 toPrefix(pre.select(nme.PACKAGE ), cls, thiscls)
@@ -74,9 +110,14 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
74110 override def reapply (tp : Type ): Type =
75111 // derived infos have already been subjected to asSeenFrom, hence to need to apply the map again.
76112 tp
113+
114+ override protected def expandBounds (tp : TypeBounds ): Type = {
115+ approximated = true
116+ super .expandBounds(tp)
117+ }
77118 }
78119
79- private def isLegalPrefix (pre : Type )(implicit ctx : Context ) =
120+ def isLegalPrefix (pre : Type )(implicit ctx : Context ): Boolean =
80121 pre.isStable || ! ctx.phase.isTyper
81122
82123 /** Implementation of Types#simplified */
0 commit comments