@@ -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 &&
@@ -2070,17 +2074,36 @@ object Types {
2070
2074
else this
2071
2075
2072
2076
/** A reference like this one, but with the given denotation, if it exists.
2073
- * If the symbol of `denot` is the same as the current symbol, the denotation
2074
- * is re-used, otherwise a new one is created.
2077
+ * Returns a new named type with the denotation's symbol if that symbol exists, and
2078
+ * one of the following alternatives applies:
2079
+ * 1. The current designator is a symbol and the symbols differ, or
2080
+ * 2. The current designator is a name and the new symbolic named type
2081
+ * does not have a currently known denotation.
2082
+ * 3. The current designator is a name and the new symbolic named type
2083
+ * has the same info as the current info
2084
+ * Otherwise the current denotation is overwritten with the given one.
2085
+ *
2086
+ * Note: (2) and (3) are a "lock in mechanism" where a reference with a name as
2087
+ * designator can turn into a symbolic reference.
2088
+ *
2089
+ * Note: This is a subtle dance to keep the balance between going to symbolic
2090
+ * references as much as we can (since otherwise we'd risk getting cycles)
2091
+ * and to still not lose any type info in the denotation (since symbolic
2092
+ * references often recompute their info directly from the symbol's info).
2093
+ * A test case is neg/opaque-self-encoding.scala.
2075
2094
*/
2076
2095
final def withDenot (denot : Denotation )(implicit ctx : Context ): ThisType =
2077
2096
if (denot.exists) {
2078
2097
val adapted = withSym(denot.symbol)
2079
- if (adapted ne this ) adapted.withDenot(denot).asInstanceOf [ThisType ]
2080
- else {
2081
- setDenot(denot)
2082
- this
2083
- }
2098
+ val result =
2099
+ if (adapted.eq(this )
2100
+ || designator.isInstanceOf [Symbol ]
2101
+ || ! adapted.denotationIsCurrent
2102
+ || adapted.info.eq(denot.info))
2103
+ adapted
2104
+ else this
2105
+ result.setDenot(denot)
2106
+ result.asInstanceOf [ThisType ]
2084
2107
}
2085
2108
else // don't assign NoDenotation, we might need to recover later. Test case is pos/avoid.scala.
2086
2109
this
@@ -2181,6 +2204,11 @@ object Types {
2181
2204
override protected def designator_= (d : Designator ): Unit = myDesignator = d
2182
2205
2183
2206
override def underlying (implicit ctx : Context ): Type = info
2207
+
2208
+ /** Hook that can be called from creation methods in TermRef and TypeRef */
2209
+ def validated (implicit ctx : Context ): this .type = {
2210
+ this
2211
+ }
2184
2212
}
2185
2213
2186
2214
final class CachedTermRef (prefix : Type , designator : Designator , hc : Int ) extends TermRef (prefix, designator) {
@@ -2197,6 +2225,23 @@ object Types {
2197
2225
private def assertUnerased ()(implicit ctx : Context ) =
2198
2226
if (Config .checkUnerased) assert(! ctx.phase.erasedTypes)
2199
2227
2228
+ /** The designator to be used for a named type creation with given prefix, name, and denotation.
2229
+ * This is the denotation's symbol, if it exists and the prefix is not the this type
2230
+ * of the class owning the symbol. The reason for the latter qualification is that
2231
+ * when re-computing the denotation of a `this.<symbol>` reference we read the
2232
+ * type directly off the symbol. But the given denotation might contain a more precise
2233
+ * type than what can be computed from the symbol's info. We have to create in this case
2234
+ * a reference with a name as designator so that the denotation will be correctly updated in
2235
+ * the future. See also NamedType#withDenot. Test case is neg/opaque-self-encoding.scala.
2236
+ */
2237
+ private def designatorFor (prefix : Type , name : Name , denot : Denotation )(implicit ctx : Context ): Designator = {
2238
+ val sym = denot.symbol
2239
+ if (sym.exists && (prefix.eq(NoPrefix ) || prefix.ne(sym.owner.thisType)))
2240
+ sym
2241
+ else
2242
+ name
2243
+ }
2244
+
2200
2245
object NamedType {
2201
2246
def isType (desig : Designator )(implicit ctx : Context ): Boolean = desig match {
2202
2247
case sym : Symbol => sym.isType
@@ -2220,7 +2265,7 @@ object Types {
2220
2265
* from the denotation's symbol if the latter exists, or else it is the given name.
2221
2266
*/
2222
2267
def apply (prefix : Type , name : TermName , denot : Denotation )(implicit ctx : Context ): TermRef =
2223
- apply(prefix, if (denot.symbol.exists) denot.symbol.asTerm else name).withDenot(denot)
2268
+ apply(prefix, designatorFor(prefix, name, denot) ).withDenot(denot)
2224
2269
}
2225
2270
2226
2271
object TypeRef {
@@ -2233,7 +2278,7 @@ object Types {
2233
2278
* from the denotation's symbol if the latter exists, or else it is the given name.
2234
2279
*/
2235
2280
def apply (prefix : Type , name : TypeName , denot : Denotation )(implicit ctx : Context ): TypeRef =
2236
- apply(prefix, if (denot.symbol.exists) denot.symbol.asType else name).withDenot(denot)
2281
+ apply(prefix, designatorFor(prefix, name, denot) ).withDenot(denot)
2237
2282
}
2238
2283
2239
2284
// --- Other SingletonTypes: ThisType/SuperType/ConstantType ---------------------------
0 commit comments