@@ -1917,6 +1917,10 @@ object Types {
1917
1917
||
1918
1918
lastSymbol.infoOrCompleter.isInstanceOf [ErrorType ]
1919
1919
||
1920
+ ! sym.exists
1921
+ ||
1922
+ ! lastSymbol.exists
1923
+ ||
1920
1924
sym.isPackageObject // package objects can be visited before we get around to index them
1921
1925
||
1922
1926
sym.owner != lastSymbol.owner &&
@@ -2079,17 +2083,36 @@ object Types {
2079
2083
else this
2080
2084
2081
2085
/** A reference like this one, but with the given denotation, if it exists.
2082
- * If the symbol of `denot` is the same as the current symbol, the denotation
2083
- * is re-used, otherwise a new one is created.
2086
+ * Returns a new named type with the denotation's symbol if that symbol exists, and
2087
+ * one of the following alternatives applies:
2088
+ * 1. The current designator is a symbol and the symbols differ, or
2089
+ * 2. The current designator is a name and the new symbolic named type
2090
+ * does not have a currently known denotation.
2091
+ * 3. The current designator is a name and the new symbolic named type
2092
+ * has the same info as the current info
2093
+ * Otherwise the current denotation is overwritten with the given one.
2094
+ *
2095
+ * Note: (2) and (3) are a "lock in mechanism" where a reference with a name as
2096
+ * designator can turn into a symbolic reference.
2097
+ *
2098
+ * Note: This is a subtle dance to keep the balance between going to symbolic
2099
+ * references as much as we can (since otherwise we'd risk getting cycles)
2100
+ * and to still not lose any type info in the denotation (since symbolic
2101
+ * references often recompute their info directly from the symbol's info).
2102
+ * A test case is neg/opaque-self-encoding.scala.
2084
2103
*/
2085
2104
final def withDenot (denot : Denotation )(implicit ctx : Context ): ThisType =
2086
2105
if (denot.exists) {
2087
2106
val adapted = withSym(denot.symbol)
2088
- if (adapted ne this ) adapted.withDenot(denot).asInstanceOf [ThisType ]
2089
- else {
2090
- setDenot(denot)
2091
- this
2092
- }
2107
+ val result =
2108
+ if (adapted.eq(this )
2109
+ || designator.isInstanceOf [Symbol ]
2110
+ || ! adapted.denotationIsCurrent
2111
+ || adapted.info.eq(denot.info))
2112
+ adapted
2113
+ else this
2114
+ result.setDenot(denot)
2115
+ result.asInstanceOf [ThisType ]
2093
2116
}
2094
2117
else // don't assign NoDenotation, we might need to recover later. Test case is pos/avoid.scala.
2095
2118
this
@@ -2190,6 +2213,11 @@ object Types {
2190
2213
override protected def designator_= (d : Designator ): Unit = myDesignator = d
2191
2214
2192
2215
override def underlying (implicit ctx : Context ): Type = info
2216
+
2217
+ /** Hook that can be called from creation methods in TermRef and TypeRef */
2218
+ def validated (implicit ctx : Context ): this .type = {
2219
+ this
2220
+ }
2193
2221
}
2194
2222
2195
2223
final class CachedTermRef (prefix : Type , designator : Designator , hc : Int ) extends TermRef (prefix, designator) {
@@ -2206,6 +2234,23 @@ object Types {
2206
2234
private def assertUnerased ()(implicit ctx : Context ) =
2207
2235
if (Config .checkUnerased) assert(! ctx.phase.erasedTypes)
2208
2236
2237
+ /** The designator to be used for a named type creation with given prefix, name, and denotation.
2238
+ * This is the denotation's symbol, if it exists and the prefix is not the this type
2239
+ * of the class owning the symbol. The reason for the latter qualification is that
2240
+ * when re-computing the denotation of a `this.<symbol>` reference we read the
2241
+ * type directly off the symbol. But the given denotation might contain a more precise
2242
+ * type than what can be computed from the symbol's info. We have to create in this case
2243
+ * a reference with a name as designator so that the denotation will be correctly updated in
2244
+ * the future. See also NamedType#withDenot. Test case is neg/opaque-self-encoding.scala.
2245
+ */
2246
+ private def designatorFor (prefix : Type , name : Name , denot : Denotation )(implicit ctx : Context ): Designator = {
2247
+ val sym = denot.symbol
2248
+ if (sym.exists && (prefix.eq(NoPrefix ) || prefix.ne(sym.owner.thisType)))
2249
+ sym
2250
+ else
2251
+ name
2252
+ }
2253
+
2209
2254
object NamedType {
2210
2255
def isType (desig : Designator )(implicit ctx : Context ): Boolean = desig match {
2211
2256
case sym : Symbol => sym.isType
@@ -2229,7 +2274,7 @@ object Types {
2229
2274
* from the denotation's symbol if the latter exists, or else it is the given name.
2230
2275
*/
2231
2276
def apply (prefix : Type , name : TermName , denot : Denotation )(implicit ctx : Context ): TermRef =
2232
- apply(prefix, if (denot.symbol.exists) denot.symbol.asTerm else name).withDenot(denot)
2277
+ apply(prefix, designatorFor(prefix, name, denot) ).withDenot(denot)
2233
2278
}
2234
2279
2235
2280
object TypeRef {
@@ -2242,7 +2287,7 @@ object Types {
2242
2287
* from the denotation's symbol if the latter exists, or else it is the given name.
2243
2288
*/
2244
2289
def apply (prefix : Type , name : TypeName , denot : Denotation )(implicit ctx : Context ): TypeRef =
2245
- apply(prefix, if (denot.symbol.exists) denot.symbol.asType else name).withDenot(denot)
2290
+ apply(prefix, designatorFor(prefix, name, denot) ).withDenot(denot)
2246
2291
}
2247
2292
2248
2293
// --- Other SingletonTypes: ThisType/SuperType/ConstantType ---------------------------
0 commit comments