@@ -782,6 +782,67 @@ object TypeOps:
782782 * Otherwise, return NoType.
783783 */
784784 private def instantiateToSubType (tp1 : NamedType , tp2 : Type , mixins : List [Type ])(using Context ): Type = trace(i " instantiateToSubType( $tp1, $tp2, $mixins) " , typr) {
785+ /** Gather GADT symbols and singletons found in `tp2`, ie. the scrutinee. */
786+ object TraverseTp2 extends TypeTraverser :
787+ val singletons = util.HashMap [Symbol , SingletonType ]()
788+ val gadtSyms = new mutable.ListBuffer [Symbol ]
789+
790+ def traverse (tp : Type ) = try
791+ val tpd = tp.dealias
792+ if tpd ne tp then traverse(tpd)
793+ else tp match
794+ case tp : ThisType if ! singletons.contains(tp.tref.symbol) && ! tp.tref.symbol.isStaticOwner =>
795+ singletons(tp.tref.symbol) = tp
796+ traverseChildren(tp.tref)
797+ case tp : TermRef =>
798+ singletons(tp.typeSymbol) = tp
799+ traverseChildren(tp)
800+ case tp : TypeRef if ! gadtSyms.contains(tp.symbol) && tp.symbol.isAbstractOrParamType =>
801+ gadtSyms += tp.symbol
802+ traverseChildren(tp)
803+ // traverse abstract type infos, to add any singletons
804+ // for example, i16451.CanForward.scala, add `Namer.this`, from the info of the type parameter `A1`
805+ // also, i19031.ci-reg2.scala, add `out`, from the info of the type parameter `A1` (from synthetic applyOrElse)
806+ traverseChildren(tp.info)
807+ case _ =>
808+ traverseChildren(tp)
809+ catch case ex : Throwable => handleRecursive(" traverseTp2" , tp.show, ex)
810+ TraverseTp2 .traverse(tp2)
811+ val singletons = TraverseTp2 .singletons
812+ val gadtSyms = TraverseTp2 .gadtSyms.toList
813+
814+ // Prefix inference, given `p.C.this.Child`:
815+ // 1. return it as is, if `C.this` is found in `tp`, i.e. the scrutinee; or
816+ // 2. replace it with `X.Child` where `X <: p.C`, stripping ThisType in `p` recursively.
817+ //
818+ // See tests/patmat/i3938.scala, tests/pos/i15029.more.scala, tests/pos/i16785.scala
819+ class InferPrefixMap extends TypeMap {
820+ var prefixTVar : Type | Null = null
821+ def apply (tp : Type ): Type = tp match {
822+ case tp : TermRef if singletons.contains(tp.symbol) =>
823+ prefixTVar = singletons(tp.symbol) // e.g. tests/pos/i19031.ci-reg2.scala, keep out
824+ prefixTVar.uncheckedNN
825+ case ThisType (tref) if ! tref.symbol.isStaticOwner =>
826+ val symbol = tref.symbol
827+ if singletons.contains(symbol) then
828+ prefixTVar = singletons(symbol) // e.g. tests/pos/i16785.scala, keep Outer.this
829+ prefixTVar.uncheckedNN
830+ else if symbol.is(Module ) then
831+ TermRef (this (tref.prefix), symbol.sourceModule)
832+ else if (prefixTVar != null )
833+ this (tref.applyIfParameterized(tref.typeParams.map(_ => WildcardType )))
834+ else {
835+ prefixTVar = WildcardType // prevent recursive call from assigning it
836+ // e.g. tests/pos/i15029.more.scala, create a TypeVar for `Instances`' B, so we can disregard `Ints`
837+ val tvars = tref.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds, DepParamName .fresh(tparam.paramName)) }
838+ val tref2 = this (tref.applyIfParameterized(tvars))
839+ prefixTVar = newTypeVar(TypeBounds .upper(tref2), DepParamName .fresh(tref.name))
840+ prefixTVar.uncheckedNN
841+ }
842+ case tp => mapOver(tp)
843+ }
844+ }
845+
785846 // In order for a child type S to qualify as a valid subtype of the parent
786847 // T, we need to test whether it is possible S <: T.
787848 //
@@ -803,8 +864,15 @@ object TypeOps:
803864 // then to avoid it failing the <:<
804865 // we'll approximate by widening to its bounds
805866
867+ case tp : TermRef if singletons.contains(tp.symbol) =>
868+ singletons(tp.symbol)
869+
806870 case ThisType (tref : TypeRef ) if ! tref.symbol.isStaticOwner =>
807- tref
871+ val symbol = tref.symbol
872+ if singletons.contains(symbol) then
873+ singletons(symbol)
874+ else
875+ tref
808876
809877 case tp : TypeRef if ! tp.symbol.isClass =>
810878 val lookup = boundTypeParams.lookup(tp)
@@ -855,67 +923,6 @@ object TypeOps:
855923 }
856924 }
857925
858- /** Gather GADT symbols and singletons found in `tp2`, ie. the scrutinee. */
859- object TraverseTp2 extends TypeTraverser :
860- val singletons = util.HashMap [Symbol , SingletonType ]()
861- val gadtSyms = new mutable.ListBuffer [Symbol ]
862-
863- def traverse (tp : Type ) = try
864- val tpd = tp.dealias
865- if tpd ne tp then traverse(tpd)
866- else tp match
867- case tp : ThisType if ! singletons.contains(tp.tref.symbol) && ! tp.tref.symbol.isStaticOwner =>
868- singletons(tp.tref.symbol) = tp
869- traverseChildren(tp.tref)
870- case tp : TermRef if tp.symbol.is(Param ) =>
871- singletons(tp.typeSymbol) = tp
872- traverseChildren(tp)
873- case tp : TypeRef if ! gadtSyms.contains(tp.symbol) && tp.symbol.isAbstractOrParamType =>
874- gadtSyms += tp.symbol
875- traverseChildren(tp)
876- // traverse abstract type infos, to add any singletons
877- // for example, i16451.CanForward.scala, add `Namer.this`, from the info of the type parameter `A1`
878- // also, i19031.ci-reg2.scala, add `out`, from the info of the type parameter `A1` (from synthetic applyOrElse)
879- traverseChildren(tp.info)
880- case _ =>
881- traverseChildren(tp)
882- catch case ex : Throwable => handleRecursive(" traverseTp2" , tp.show, ex)
883- TraverseTp2 .traverse(tp2)
884- val singletons = TraverseTp2 .singletons
885- val gadtSyms = TraverseTp2 .gadtSyms.toList
886-
887- // Prefix inference, given `p.C.this.Child`:
888- // 1. return it as is, if `C.this` is found in `tp`, i.e. the scrutinee; or
889- // 2. replace it with `X.Child` where `X <: p.C`, stripping ThisType in `p` recursively.
890- //
891- // See tests/patmat/i3938.scala, tests/pos/i15029.more.scala, tests/pos/i16785.scala
892- class InferPrefixMap extends TypeMap {
893- var prefixTVar : Type | Null = null
894- def apply (tp : Type ): Type = tp match {
895- case tp : TermRef if singletons.contains(tp.symbol) =>
896- prefixTVar = singletons(tp.symbol) // e.g. tests/pos/i19031.ci-reg2.scala, keep out
897- prefixTVar.uncheckedNN
898- case ThisType (tref) if ! tref.symbol.isStaticOwner =>
899- val symbol = tref.symbol
900- if singletons.contains(symbol) then
901- prefixTVar = singletons(symbol) // e.g. tests/pos/i16785.scala, keep Outer.this
902- prefixTVar.uncheckedNN
903- else if symbol.is(Module ) then
904- TermRef (this (tref.prefix), symbol.sourceModule)
905- else if (prefixTVar != null )
906- this (tref.applyIfParameterized(tref.typeParams.map(_ => WildcardType )))
907- else {
908- prefixTVar = WildcardType // prevent recursive call from assigning it
909- // e.g. tests/pos/i15029.more.scala, create a TypeVar for `Instances`' B, so we can disregard `Ints`
910- val tvars = tref.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds, DepParamName .fresh(tparam.paramName)) }
911- val tref2 = this (tref.applyIfParameterized(tvars))
912- prefixTVar = newTypeVar(TypeBounds .upper(tref2), DepParamName .fresh(tref.name))
913- prefixTVar.uncheckedNN
914- }
915- case tp => mapOver(tp)
916- }
917- }
918-
919926 val inferThisMap = new InferPrefixMap
920927 val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds, DepParamName .fresh(tparam.paramName)) }
921928 val protoTp1 = inferThisMap.apply(tp1).appliedTo(tvars)
0 commit comments