Skip to content

Commit 0416992

Browse files
authored
Patmat: Use less type variables in prefix inference (#16827)
2 parents ce1ca44 + 2d641ec commit 0416992

File tree

3 files changed

+50
-16
lines changed

3 files changed

+50
-16
lines changed

compiler/src/dotty/tools/dotc/core/TypeOps.scala

+38-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package dotty.tools
22
package dotc
33
package core
44

5-
import Contexts._, Types._, Symbols._, Names._, Flags._
5+
import Contexts._, Types._, Symbols._, Names._, NameKinds.*, Flags._
66
import SymDenotations._
77
import util.Spans._
88
import util.Stats
@@ -839,40 +839,63 @@ object TypeOps:
839839
}
840840
}
841841

842-
// Prefix inference, replace `p.C.this.Child` with `X.Child` where `X <: p.C`
843-
// Note: we need to strip ThisType in `p` recursively.
842+
/** Gather GADT symbols and `ThisType`s found in `tp2`, ie. the scrutinee. */
843+
object TraverseTp2 extends TypeTraverser:
844+
val thisTypes = util.HashSet[ThisType]()
845+
val gadtSyms = new mutable.ListBuffer[Symbol]
846+
847+
def traverse(tp: Type) = {
848+
val tpd = tp.dealias
849+
if tpd ne tp then traverse(tpd)
850+
else tp match
851+
case tp: ThisType if !tp.tref.symbol.isStaticOwner && !thisTypes.contains(tp) =>
852+
thisTypes += tp
853+
traverseChildren(tp.tref)
854+
case tp: TypeRef if tp.symbol.isAbstractOrParamType =>
855+
gadtSyms += tp.symbol
856+
traverseChildren(tp)
857+
case _ =>
858+
traverseChildren(tp)
859+
}
860+
TraverseTp2.traverse(tp2)
861+
val thisTypes = TraverseTp2.thisTypes
862+
val gadtSyms = TraverseTp2.gadtSyms.toList
863+
864+
// Prefix inference, given `p.C.this.Child`:
865+
// 1. return it as is, if `C.this` is found in `tp`, i.e. the scrutinee; or
866+
// 2. replace it with `X.Child` where `X <: p.C`, stripping ThisType in `p` recursively.
844867
//
845-
// See tests/patmat/i3938.scala
868+
// See tests/patmat/i3938.scala, tests/pos/i15029.more.scala, tests/pos/i16785.scala
846869
class InferPrefixMap extends TypeMap {
847870
var prefixTVar: Type | Null = null
848871
def apply(tp: Type): Type = tp match {
849-
case ThisType(tref: TypeRef) if !tref.symbol.isStaticOwner =>
872+
case tp @ ThisType(tref) if !tref.symbol.isStaticOwner =>
850873
val symbol = tref.symbol
851-
if (symbol.is(Module))
874+
if thisTypes.contains(tp) then
875+
prefixTVar = tp // e.g. tests/pos/i16785.scala, keep Outer.this
876+
prefixTVar.uncheckedNN
877+
else if symbol.is(Module) then
852878
TermRef(this(tref.prefix), symbol.sourceModule)
853879
else if (prefixTVar != null)
854880
this(tref)
855881
else {
856882
prefixTVar = WildcardType // prevent recursive call from assigning it
857-
val tvars = tref.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) }
883+
// e.g. tests/pos/i15029.more.scala, create a TypeVar for `Instances`' B, so we can disregard `Ints`
884+
val tvars = tref.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds, DepParamName.fresh(tparam.paramName)) }
858885
val tref2 = this(tref.applyIfParameterized(tvars))
859-
prefixTVar = newTypeVar(TypeBounds.upper(tref2))
886+
prefixTVar = newTypeVar(TypeBounds.upper(tref2), DepParamName.fresh(tref.name))
860887
prefixTVar.uncheckedNN
861888
}
862889
case tp => mapOver(tp)
863890
}
864891
}
865892

866893
val inferThisMap = new InferPrefixMap
867-
val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) }
894+
val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds, DepParamName.fresh(tparam.paramName)) }
868895
val protoTp1 = inferThisMap.apply(tp1).appliedTo(tvars)
869896

870-
val getAbstractSymbols = new TypeAccumulator[List[Symbol]]:
871-
def apply(xs: List[Symbol], tp: Type) = tp.dealias match
872-
case tp: TypeRef if tp.symbol.exists && !tp.symbol.isClass => foldOver(tp.symbol :: xs, tp)
873-
case tp => foldOver(xs, tp)
874-
val syms2 = getAbstractSymbols(Nil, tp2).reverse
875-
if syms2.nonEmpty then ctx.gadtState.addToConstraint(syms2)
897+
if gadtSyms.nonEmpty then
898+
ctx.gadtState.addToConstraint(gadtSyms)
876899

877900
// If parent contains a reference to an abstract type, then we should
878901
// refine subtype checking to eliminate abstract types according to

tests/patmat/i12408.check

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
13: Pattern Match Exhaustivity: X[<?>] & (X.this : X[T]).A(_), X[<?>] & (X.this : X[T]).C(_)
1+
13: Pattern Match Exhaustivity: A(_), C(_)
22
21: Pattern Match

tests/pos/i16785.scala

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class VarImpl[Lbl, A]
2+
3+
class Outer[|*|[_, _], Lbl1]:
4+
type Var[A1] = VarImpl[Lbl1, A1]
5+
6+
sealed trait Foo[G]
7+
case class Bar[T, U]()
8+
extends Foo[Var[T] |*| Var[U]]
9+
10+
def go[X](scr: Foo[Var[X]]): Unit = scr match // was: compile hang
11+
case Bar() => ()

0 commit comments

Comments
 (0)