@@ -767,6 +767,67 @@ object TypeOps:
767767 * Otherwise, return NoType.
768768 */
769769 private def instantiateToSubType (tp1 : NamedType , tp2 : Type , mixins : List [Type ])(using Context ): Type = trace(i " instantiateToSubType( $tp1, $tp2, $mixins) " , typr) {
770+ /** Gather GADT symbols and singletons found in `tp2`, ie. the scrutinee. */
771+ object TraverseTp2 extends TypeTraverser :
772+ val singletons = util.HashMap [Symbol , SingletonType ]()
773+ val gadtSyms = new mutable.ListBuffer [Symbol ]
774+
775+ def traverse (tp : Type ) = try
776+ val tpd = tp.dealias
777+ if tpd ne tp then traverse(tpd)
778+ else tp match
779+ case tp : ThisType if ! singletons.contains(tp.tref.symbol) && ! tp.tref.symbol.isStaticOwner =>
780+ singletons(tp.tref.symbol) = tp
781+ traverseChildren(tp.tref)
782+ case tp : TermRef =>
783+ singletons(tp.typeSymbol) = tp
784+ traverseChildren(tp)
785+ case tp : TypeRef if ! gadtSyms.contains(tp.symbol) && tp.symbol.isAbstractOrParamType =>
786+ gadtSyms += tp.symbol
787+ traverseChildren(tp)
788+ // traverse abstract type infos, to add any singletons
789+ // for example, i16451.CanForward.scala, add `Namer.this`, from the info of the type parameter `A1`
790+ // also, i19031.ci-reg2.scala, add `out`, from the info of the type parameter `A1` (from synthetic applyOrElse)
791+ traverseChildren(tp.info)
792+ case _ =>
793+ traverseChildren(tp)
794+ catch case ex : Throwable => handleRecursive(" traverseTp2" , tp.show, ex)
795+ TraverseTp2 .traverse(tp2)
796+ val singletons = TraverseTp2 .singletons
797+ val gadtSyms = TraverseTp2 .gadtSyms.toList
798+
799+ // Prefix inference, given `p.C.this.Child`:
800+ // 1. return it as is, if `C.this` is found in `tp`, i.e. the scrutinee; or
801+ // 2. replace it with `X.Child` where `X <: p.C`, stripping ThisType in `p` recursively.
802+ //
803+ // See tests/patmat/i3938.scala, tests/pos/i15029.more.scala, tests/pos/i16785.scala
804+ class InferPrefixMap extends TypeMap {
805+ var prefixTVar : Type | Null = null
806+ def apply (tp : Type ): Type = tp match {
807+ case tp : TermRef if singletons.contains(tp.symbol) =>
808+ prefixTVar = singletons(tp.symbol) // e.g. tests/pos/i19031.ci-reg2.scala, keep out
809+ prefixTVar.uncheckedNN
810+ case ThisType (tref) if ! tref.symbol.isStaticOwner =>
811+ val symbol = tref.symbol
812+ if singletons.contains(symbol) then
813+ prefixTVar = singletons(symbol) // e.g. tests/pos/i16785.scala, keep Outer.this
814+ prefixTVar.uncheckedNN
815+ else if symbol.is(Module ) then
816+ TermRef (this (tref.prefix), symbol.sourceModule)
817+ else if (prefixTVar != null )
818+ this (tref.applyIfParameterized(tref.typeParams.map(_ => WildcardType )))
819+ else {
820+ prefixTVar = WildcardType // prevent recursive call from assigning it
821+ // e.g. tests/pos/i15029.more.scala, create a TypeVar for `Instances`' B, so we can disregard `Ints`
822+ val tvars = tref.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds, DepParamName .fresh(tparam.paramName)) }
823+ val tref2 = this (tref.applyIfParameterized(tvars))
824+ prefixTVar = newTypeVar(TypeBounds .upper(tref2), DepParamName .fresh(tref.name))
825+ prefixTVar.uncheckedNN
826+ }
827+ case tp => mapOver(tp)
828+ }
829+ }
830+
770831 // In order for a child type S to qualify as a valid subtype of the parent
771832 // T, we need to test whether it is possible S <: T.
772833 //
@@ -788,8 +849,15 @@ object TypeOps:
788849 // then to avoid it failing the <:<
789850 // we'll approximate by widening to its bounds
790851
852+ case tp : TermRef if singletons.contains(tp.symbol) =>
853+ singletons(tp.symbol)
854+
791855 case ThisType (tref : TypeRef ) if ! tref.symbol.isStaticOwner =>
792- tref
856+ val symbol = tref.symbol
857+ if singletons.contains(symbol) then
858+ singletons(symbol)
859+ else
860+ tref
793861
794862 case tp : TypeRef if ! tp.symbol.isClass =>
795863 val lookup = boundTypeParams.lookup(tp)
@@ -840,67 +908,6 @@ object TypeOps:
840908 }
841909 }
842910
843- /** Gather GADT symbols and singletons found in `tp2`, ie. the scrutinee. */
844- object TraverseTp2 extends TypeTraverser :
845- val singletons = util.HashMap [Symbol , SingletonType ]()
846- val gadtSyms = new mutable.ListBuffer [Symbol ]
847-
848- def traverse (tp : Type ) = try
849- val tpd = tp.dealias
850- if tpd ne tp then traverse(tpd)
851- else tp match
852- case tp : ThisType if ! singletons.contains(tp.tref.symbol) && ! tp.tref.symbol.isStaticOwner =>
853- singletons(tp.tref.symbol) = tp
854- traverseChildren(tp.tref)
855- case tp : TermRef if tp.symbol.is(Param ) =>
856- singletons(tp.typeSymbol) = tp
857- traverseChildren(tp)
858- case tp : TypeRef if ! gadtSyms.contains(tp.symbol) && tp.symbol.isAbstractOrParamType =>
859- gadtSyms += tp.symbol
860- traverseChildren(tp)
861- // traverse abstract type infos, to add any singletons
862- // for example, i16451.CanForward.scala, add `Namer.this`, from the info of the type parameter `A1`
863- // also, i19031.ci-reg2.scala, add `out`, from the info of the type parameter `A1` (from synthetic applyOrElse)
864- traverseChildren(tp.info)
865- case _ =>
866- traverseChildren(tp)
867- catch case ex : Throwable => handleRecursive(" traverseTp2" , tp.show, ex)
868- TraverseTp2 .traverse(tp2)
869- val singletons = TraverseTp2 .singletons
870- val gadtSyms = TraverseTp2 .gadtSyms.toList
871-
872- // Prefix inference, given `p.C.this.Child`:
873- // 1. return it as is, if `C.this` is found in `tp`, i.e. the scrutinee; or
874- // 2. replace it with `X.Child` where `X <: p.C`, stripping ThisType in `p` recursively.
875- //
876- // See tests/patmat/i3938.scala, tests/pos/i15029.more.scala, tests/pos/i16785.scala
877- class InferPrefixMap extends TypeMap {
878- var prefixTVar : Type | Null = null
879- def apply (tp : Type ): Type = tp match {
880- case tp : TermRef if singletons.contains(tp.symbol) =>
881- prefixTVar = singletons(tp.symbol) // e.g. tests/pos/i19031.ci-reg2.scala, keep out
882- prefixTVar.uncheckedNN
883- case ThisType (tref) if ! tref.symbol.isStaticOwner =>
884- val symbol = tref.symbol
885- if singletons.contains(symbol) then
886- prefixTVar = singletons(symbol) // e.g. tests/pos/i16785.scala, keep Outer.this
887- prefixTVar.uncheckedNN
888- else if symbol.is(Module ) then
889- TermRef (this (tref.prefix), symbol.sourceModule)
890- else if (prefixTVar != null )
891- this (tref.applyIfParameterized(tref.typeParams.map(_ => WildcardType )))
892- else {
893- prefixTVar = WildcardType // prevent recursive call from assigning it
894- // e.g. tests/pos/i15029.more.scala, create a TypeVar for `Instances`' B, so we can disregard `Ints`
895- val tvars = tref.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds, DepParamName .fresh(tparam.paramName)) }
896- val tref2 = this (tref.applyIfParameterized(tvars))
897- prefixTVar = newTypeVar(TypeBounds .upper(tref2), DepParamName .fresh(tref.name))
898- prefixTVar.uncheckedNN
899- }
900- case tp => mapOver(tp)
901- }
902- }
903-
904911 val inferThisMap = new InferPrefixMap
905912 val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds, DepParamName .fresh(tparam.paramName)) }
906913 val protoTp1 = inferThisMap.apply(tp1).appliedTo(tvars)
0 commit comments