@@ -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 &&
@@ -2070,17 +2074,36 @@ object Types {
20702074 else this
20712075
20722076 /** 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.
20752094 */
20762095 final def withDenot (denot : Denotation )(implicit ctx : Context ): ThisType =
20772096 if (denot.exists) {
20782097 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 ]
20842107 }
20852108 else // don't assign NoDenotation, we might need to recover later. Test case is pos/avoid.scala.
20862109 this
@@ -2181,6 +2204,11 @@ object Types {
21812204 override protected def designator_= (d : Designator ): Unit = myDesignator = d
21822205
21832206 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+ }
21842212 }
21852213
21862214 final class CachedTermRef (prefix : Type , designator : Designator , hc : Int ) extends TermRef (prefix, designator) {
@@ -2197,6 +2225,23 @@ object Types {
21972225 private def assertUnerased ()(implicit ctx : Context ) =
21982226 if (Config .checkUnerased) assert(! ctx.phase.erasedTypes)
21992227
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+
22002245 object NamedType {
22012246 def isType (desig : Designator )(implicit ctx : Context ): Boolean = desig match {
22022247 case sym : Symbol => sym.isType
@@ -2220,7 +2265,7 @@ object Types {
22202265 * from the denotation's symbol if the latter exists, or else it is the given name.
22212266 */
22222267 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)
22242269 }
22252270
22262271 object TypeRef {
@@ -2233,7 +2278,7 @@ object Types {
22332278 * from the denotation's symbol if the latter exists, or else it is the given name.
22342279 */
22352280 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)
22372282 }
22382283
22392284 // --- Other SingletonTypes: ThisType/SuperType/ConstantType ---------------------------
0 commit comments