@@ -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