@@ -1917,6 +1917,10 @@ object Types {
19171917 ||
19181918 lastSymbol.infoOrCompleter.isInstanceOf [ErrorType ]
19191919 ||
1920+ ! sym.exists
1921+ ||
1922+ ! lastSymbol.exists
1923+ ||
19201924 sym.isPackageObject // package objects can be visited before we get around to index them
19211925 ||
19221926 sym.owner != lastSymbol.owner &&
@@ -2079,17 +2083,36 @@ object Types {
20792083 else this
20802084
20812085 /** 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.
20842103 */
20852104 final def withDenot (denot : Denotation )(implicit ctx : Context ): ThisType =
20862105 if (denot.exists) {
20872106 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 ]
20932116 }
20942117 else // don't assign NoDenotation, we might need to recover later. Test case is pos/avoid.scala.
20952118 this
@@ -2190,6 +2213,11 @@ object Types {
21902213 override protected def designator_= (d : Designator ): Unit = myDesignator = d
21912214
21922215 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+ }
21932221 }
21942222
21952223 final class CachedTermRef (prefix : Type , designator : Designator , hc : Int ) extends TermRef (prefix, designator) {
@@ -2206,6 +2234,23 @@ object Types {
22062234 private def assertUnerased ()(implicit ctx : Context ) =
22072235 if (Config .checkUnerased) assert(! ctx.phase.erasedTypes)
22082236
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+
22092254 object NamedType {
22102255 def isType (desig : Designator )(implicit ctx : Context ): Boolean = desig match {
22112256 case sym : Symbol => sym.isType
@@ -2229,7 +2274,7 @@ object Types {
22292274 * from the denotation's symbol if the latter exists, or else it is the given name.
22302275 */
22312276 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)
22332278 }
22342279
22352280 object TypeRef {
@@ -2242,7 +2287,7 @@ object Types {
22422287 * from the denotation's symbol if the latter exists, or else it is the given name.
22432288 */
22442289 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)
22462291 }
22472292
22482293 // --- Other SingletonTypes: ThisType/SuperType/ConstantType ---------------------------
0 commit comments