@@ -19,122 +19,81 @@ import ast.tpd._
1919trait TypeOps { this : Context => // TODO: Make standalone object.
2020
2121 /** 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.
5023 */
5124 final def asSeenFrom (tp : Type , pre : Type , cls : Symbol ): Type =
52- asSeenFrom(tp, pre, cls, null )
25+ new AsSeenFromMap ( pre, cls).apply(tp )
5326
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+ }
8350 }
84- }
8551
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+ }
10067 }
68+ derivedSelect(tp, pre1)
10169 }
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+ }
11881 }
11982 }
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
12087 }
12188
12289 private def isLegalPrefix (pre : Type )(implicit ctx : Context ) =
12390 pre.isStable || ! ctx.phase.isTyper
12491
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-
13392 /** Approximate a type `tp` with a type that does not contain skolem types. */
13493 object deskolemize extends ApproximatingTypeMap {
13594 def apply (tp : Type ) = /* ctx.traceIndented(i"deskolemize($tp) at $variance", show = true)*/ {
13695 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)))
13897 case _ => mapOver(tp)
13998 }
14099 }
0 commit comments