Skip to content

Commit 536c350

Browse files
committed
Match cases in parallel
... as mandated by new spec. This required some changes to Tuple.scala to avoid blow-up of repeated matches. Also, scrutinees of bottom types are now specialized to always yield NoType. This makes sense since corresponding match expressions would not match anything, either. It also prevents deep subtype recursions with Nothing as scrutinee.
1 parent 16d1856 commit 536c350

File tree

3 files changed

+40
-55
lines changed

3 files changed

+40
-55
lines changed

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

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3283,14 +3283,14 @@ object Types {
32833283
case tycon: TypeRef =>
32843284
def tryMatchAlias = tycon.info match {
32853285
case MatchAlias(alias) =>
3286-
trace("normalize $this", show = true) {
3286+
trace("normalize $this", typr, show = true) {
32873287
alias.applyIfParameterized(args).tryNormalize
32883288
}
32893289
case _ =>
32903290
NoType
32913291
}
32923292
if (defn.isTypelevel_S(tycon.symbol) && args.length == 1) {
3293-
trace("normalize S $this", show = true) {
3293+
trace("normalize S $this", typr, show = true) {
32943294
args.head.normalized match {
32953295
case ConstantType(Constant(n: Int)) => ConstantType(Constant(n + 1))
32963296
case none => tryMatchAlias
@@ -3590,25 +3590,6 @@ object Types {
35903590
def alternatives(implicit ctx: Context): List[Type] = cases.map(caseType)
35913591
def underlying(implicit ctx: Context): Type = bound
35923592

3593-
private def wildApproxMap(implicit ctx: Context) = new TypeMap {
3594-
def apply(t: Type) = t match {
3595-
case t: TypeRef =>
3596-
t.info match {
3597-
case TypeBounds(lo, hi) if lo `ne` hi => WildcardType
3598-
case _ => mapOver(t)
3599-
}
3600-
case t: ParamRef => WildcardType
3601-
case _ => mapOver(t)
3602-
}
3603-
}
3604-
3605-
private[this] var myApproxScrut: Type = null
3606-
3607-
def approximatedScrutinee(implicit ctx: Context): Type = {
3608-
if (myApproxScrut == null) myApproxScrut = wildApproxMap.apply(scrutinee)
3609-
myApproxScrut
3610-
}
3611-
36123593
private[this] var myReduced: Type = null
36133594
private[this] var reductionContext: mutable.Map[Type, TypeBounds] = null
36143595

@@ -3618,15 +3599,6 @@ object Types {
36183599
val trackingCtx = ctx.fresh.setTypeComparerFn(new TrackingTypeComparer(_))
36193600
val cmp = trackingCtx.typeComparer.asInstanceOf[TrackingTypeComparer]
36203601

3621-
def recur(cases: List[Type])(implicit ctx: Context): Type = cases match {
3622-
case Nil => NoType
3623-
case cas :: cases1 =>
3624-
val r = cmp.matchCase(scrutinee, cas, instantiate = true)
3625-
if (r.exists) r
3626-
else if (cmp.matchCase(approximatedScrutinee, cas, instantiate = false).exists) NoType
3627-
else recur(cases1)
3628-
}
3629-
36303602
def isRelevant(tp: Type) = tp match {
36313603
case tp: TypeParamRef => ctx.typerState.constraint.entry(tp).exists
36323604
case tp: TypeRef => ctx.gadt.bounds.contains(tp.symbol)
@@ -3658,7 +3630,21 @@ object Types {
36583630
record("MatchType.reduce computed")
36593631
if (myReduced != null) record("MatchType.reduce cache miss")
36603632
myReduced =
3661-
trace(i"reduce match type $this", show = true) { recur(cases)(trackingCtx) }
3633+
trace(i"reduce match type $this", typr, show = true) {
3634+
if (defn.isBottomType(scrutinee)) defn.NothingType
3635+
else {
3636+
val applicableBranches = cases
3637+
.map(cmp.matchCase(scrutinee, _, instantiate = true)(trackingCtx))
3638+
.filter(_.exists)
3639+
applicableBranches match {
3640+
case Nil => NoType
3641+
case applicableBranch :: Nil => applicableBranch
3642+
case _ =>
3643+
record(i"MatchType.multi-branch")
3644+
ctx.typeComparer.glb(applicableBranches)
3645+
}
3646+
}
3647+
}
36623648
updateReductionContext()
36633649
}
36643650
myReduced

library/src-scala3/scala/Tuple.scala

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -119,31 +119,30 @@ object Tuple {
119119
case x1 *: xs1 => x1 *: Concat[xs1, Y]
120120
}
121121

122-
type Elem[+X <: Tuple, +N] = (X, N) match {
123-
case (x *: xs, 0) => x
124-
case (x *: xs, S[n1]) => Elem[xs, n1]
122+
type Elem[+X <: Tuple, +N] = X match {
123+
case x *: xs =>
124+
N match {
125+
case 0 => x
126+
case S[n1] => Elem[xs, n1]
127+
}
125128
}
126129

127130
type Size[+X] <: Int = X match {
128131
case Unit => 0
129132
case x *: xs => S[Size[xs]]
130133
}
131134

132-
private type XXL = S[$MaxSpecialized.type]
133-
134-
private type BoundedS[N <: Int] = N match {
135-
case XXL => XXL
136-
case _ => S[N]
137-
}
138-
139-
private[scala] type BoundedSize[X] <: Int = X match {
135+
private[scala] type BoundedSizeRecur[X, L <: Int] <: Int = X match {
140136
case Unit => 0
141-
case x *: xs => BoundedSize[xs] match {
142-
case XXL => XXL
143-
case _ => S[BoundedSize[xs]]
144-
}
137+
case x *: xs =>
138+
L match {
139+
case 0 => 0
140+
case S[n] => S[BoundedSizeRecur[xs, n]]
141+
}
145142
}
146143

144+
private[scala] type BoundedSize[X] = BoundedSizeRecur[X, 23]
145+
147146
val $emptyArray = Array[Object]()
148147

149148
def $toArray(xs: Tuple, n: Int) = {

tests/pos-deep-subtype/tuples2.scala

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,40 @@
11
object Test extends App {
22
val xs0 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
33
assert(xs0(15) == 16)
4-
// 2.733s
4+
// 2.787s
55

66
val xs1 = xs0 ++ xs0
77
assert(xs1(31) == 16)
8-
// 3.089s
8+
// 3.354s
99

1010
val xs2 = xs1 ++ xs1
1111
assert(xs2(63) == 16)
12-
// 3.329s
12+
// 3.523s
1313

1414
val xs3 = xs2 ++ xs2
1515
assert(xs3(127) == 16)
16-
// 3.416s
16+
// 3.722s
1717

1818
/* The following operations exhaust the standard stack, but succeed with -Xs10m:
1919
2020
val xs4 = xs3 ++ xs3
2121
assert(xs4(255) == 16)
22-
// 3.765s
22+
// 4.023s
2323
2424
val xs5a = xs3 ++ xs4
2525
assert(xs5a(383) == 16)
26-
// 3.804s
26+
// 4.243s
2727
2828
val xs5 = xs4 ++ xs4
2929
assert(xs5(511) == 16)
30-
// 3.866s
30+
// 4.416s
3131
3232
val xs6 = xs5 ++ xs5
3333
assert(xs6(1023) == 16)
34-
// 4.115s
34+
// 4.900s
3535
3636
val xs7 = xs6 ++ xs6
3737
assert(xs7(2047) == 16)
38-
// 4.846s
38+
// 5.538s
3939
*/
4040
}

0 commit comments

Comments
 (0)