Skip to content

Commit 6764ad7

Browse files
Backport "Remove unnecessary and recursive Space decomposition" to LTS (#20804)
Backports #19216 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents 912aa20 + 8c29c1f commit 6764ad7

File tree

8 files changed

+80
-34
lines changed

8 files changed

+80
-34
lines changed

Diff for: compiler/src/dotty/tools/dotc/core/TypeComparer.scala

+5-3
Original file line numberDiff line numberDiff line change
@@ -2758,10 +2758,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
27582758
case (tp1: TypeRef, tp2: TypeRef) if tp1.symbol.isClass && tp2.symbol.isClass =>
27592759
val cls1 = tp1.classSymbol
27602760
val cls2 = tp2.classSymbol
2761-
def isDecomposable(tp: Symbol): Boolean =
2762-
tp.is(Sealed) && !tp.hasAnonymousChild
2761+
val sameKind = tp1.hasSameKindAs(tp2)
2762+
def isDecomposable(sym: Symbol): Boolean =
2763+
sameKind && sym.is(Sealed) && !sym.hasAnonymousChild
27632764
def decompose(sym: Symbol, tp: Type): List[Type] =
2764-
sym.children.map(x => refineUsingParent(tp, x)).filter(_.exists)
2765+
val tpSimple = tp.applyIfParameterized(tp.typeParams.map(_ => WildcardType))
2766+
sym.children.map(x => refineUsingParent(tpSimple, x)).filter(_.exists)
27652767
if (cls1.derivesFrom(cls2) || cls2.derivesFrom(cls1))
27662768
false
27672769
else

Diff for: compiler/src/dotty/tools/dotc/core/TypeOps.scala

+25-20
Original file line numberDiff line numberDiff line change
@@ -838,33 +838,34 @@ object TypeOps:
838838
}
839839
}
840840

841-
/** Gather GADT symbols and `ThisType`s found in `tp2`, ie. the scrutinee. */
841+
/** Gather GADT symbols and singletons found in `tp2`, ie. the scrutinee. */
842842
object TraverseTp2 extends TypeTraverser:
843-
val thisTypes = util.HashSet[ThisType]()
844-
val gadtSyms = new mutable.ListBuffer[Symbol]
843+
val singletons = util.HashMap[Symbol, SingletonType]()
844+
val gadtSyms = new mutable.ListBuffer[Symbol]
845845

846-
def traverse(tp: Type) = {
846+
def traverse(tp: Type) = try
847847
val tpd = tp.dealias
848848
if tpd ne tp then traverse(tpd)
849849
else tp match
850-
case tp: ThisType if !tp.tref.symbol.isStaticOwner && !thisTypes.contains(tp) =>
851-
thisTypes += tp
850+
case tp: ThisType if !singletons.contains(tp.tref.symbol) && !tp.tref.symbol.isStaticOwner =>
851+
singletons(tp.tref.symbol) = tp
852852
traverseChildren(tp.tref)
853-
case tp: TypeRef if tp.symbol.isAbstractOrParamType =>
853+
case tp: TermRef if tp.symbol.is(Param) =>
854+
singletons(tp.typeSymbol) = tp
855+
traverseChildren(tp)
856+
case tp: TypeRef if !gadtSyms.contains(tp.symbol) && tp.symbol.isAbstractOrParamType =>
854857
gadtSyms += tp.symbol
855858
traverseChildren(tp)
856-
val owners = Iterator.iterate(tp.symbol)(_.maybeOwner).takeWhile(_.exists)
857-
for sym <- owners do
858-
// add ThisType's for the classes symbols in the ownership of `tp`
859-
// for example, i16451.CanForward.scala, add `Namer.this`, as one of the owners of the type parameter `A1`
860-
if sym.isClass && !sym.isAnonymousClass && !sym.isStaticOwner then
861-
traverse(sym.thisType)
859+
// traverse abstract type infos, to add any singletons
860+
// for example, i16451.CanForward.scala, add `Namer.this`, from the info of the type parameter `A1`
861+
// also, i19031.ci-reg2.scala, add `out`, from the info of the type parameter `A1` (from synthetic applyOrElse)
862+
traverseChildren(tp.info)
862863
case _ =>
863864
traverseChildren(tp)
864-
}
865+
catch case ex: Throwable => handleRecursive("traverseTp2", tp.show, ex)
865866
TraverseTp2.traverse(tp2)
866-
val thisTypes = TraverseTp2.thisTypes
867-
val gadtSyms = TraverseTp2.gadtSyms.toList
867+
val singletons = TraverseTp2.singletons
868+
val gadtSyms = TraverseTp2.gadtSyms.toList
868869

869870
// Prefix inference, given `p.C.this.Child`:
870871
// 1. return it as is, if `C.this` is found in `tp`, i.e. the scrutinee; or
@@ -874,10 +875,13 @@ object TypeOps:
874875
class InferPrefixMap extends TypeMap {
875876
var prefixTVar: Type | Null = null
876877
def apply(tp: Type): Type = tp match {
877-
case tp @ ThisType(tref) if !tref.symbol.isStaticOwner =>
878+
case tp: TermRef if singletons.contains(tp.symbol) =>
879+
prefixTVar = singletons(tp.symbol) // e.g. tests/pos/i19031.ci-reg2.scala, keep out
880+
prefixTVar.uncheckedNN
881+
case ThisType(tref) if !tref.symbol.isStaticOwner =>
878882
val symbol = tref.symbol
879-
if thisTypes.contains(tp) then
880-
prefixTVar = tp // e.g. tests/pos/i16785.scala, keep Outer.this
883+
if singletons.contains(symbol) then
884+
prefixTVar = singletons(symbol) // e.g. tests/pos/i16785.scala, keep Outer.this
881885
prefixTVar.uncheckedNN
882886
else if symbol.is(Module) then
883887
TermRef(this(tref.prefix), symbol.sourceModule)
@@ -912,7 +916,8 @@ object TypeOps:
912916
}
913917

914918
def instantiate(): Type = {
915-
for tp <- mixins.reverseIterator do protoTp1 <:< tp
919+
for tp <- mixins.reverseIterator do
920+
protoTp1 <:< tp
916921
maximizeType(protoTp1, NoSpan)
917922
wildApprox(protoTp1)
918923
}

Diff for: compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ class PatternMatcher extends MiniPhase {
5555

5656
if !inInlinedCode then
5757
// check exhaustivity and unreachability
58-
SpaceEngine.checkExhaustivity(tree)
59-
SpaceEngine.checkRedundancy(tree)
58+
SpaceEngine.checkMatch(tree)
6059

6160
translated.ensureConforms(matchType)
6261
}

Diff for: compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

+7-7
Original file line numberDiff line numberDiff line change
@@ -209,17 +209,13 @@ object SpaceEngine {
209209
case (a @ Typ(tp1, _), b @ Typ(tp2, _)) =>
210210
if isSubType(tp1, tp2) then a
211211
else if isSubType(tp2, tp1) then b
212-
else if canDecompose(a) then intersect(Or(decompose(a)), b)
213-
else if canDecompose(b) then intersect(a, Or(decompose(b)))
214212
else intersectUnrelatedAtomicTypes(tp1, tp2)(a)
215213
case (a @ Typ(tp1, _), Prod(tp2, fun, ss)) =>
216214
if isSubType(tp2, tp1) then b
217-
else if canDecompose(a) then intersect(Or(decompose(a)), b)
218215
else if isSubType(tp1, tp2) then a // problematic corner case: inheriting a case class
219216
else intersectUnrelatedAtomicTypes(tp1, tp2)(b)
220217
case (Prod(tp1, fun, ss), b @ Typ(tp2, _)) =>
221218
if isSubType(tp1, tp2) then a
222-
else if canDecompose(b) then intersect(a, Or(decompose(b)))
223219
else if isSubType(tp2, tp1) then a // problematic corner case: inheriting a case class
224220
else intersectUnrelatedAtomicTypes(tp1, tp2)(a)
225221
case (a @ Prod(tp1, fun1, ss1), Prod(tp2, fun2, ss2)) =>
@@ -882,7 +878,7 @@ object SpaceEngine {
882878
case _ => tp
883879
})
884880

885-
def checkExhaustivity(m: Match)(using Context): Unit = if exhaustivityCheckable(m.selector) then trace(i"checkExhaustivity($m)", debug) {
881+
def checkExhaustivity(m: Match)(using Context): Unit = trace(i"checkExhaustivity($m)", debug) {
886882
val selTyp = toUnderlying(m.selector.tpe).dealias
887883
debug.println(i"selTyp = $selTyp")
888884

@@ -905,7 +901,7 @@ object SpaceEngine {
905901
report.warning(PatternMatchExhaustivity(showSpaces(deduped), m), m.selector)
906902
}
907903

908-
private def redundancyCheckable(sel: Tree)(using Context): Boolean =
904+
private def reachabilityCheckable(sel: Tree)(using Context): Boolean =
909905
// Ignore Expr[T] and Type[T] for unreachability as a special case.
910906
// Quote patterns produce repeated calls to the same unapply method, but with different implicit parameters.
911907
// Since we assume that repeated calls to the same unapply method overlap
@@ -915,7 +911,7 @@ object SpaceEngine {
915911
&& !sel.tpe.widen.isRef(defn.QuotedExprClass)
916912
&& !sel.tpe.widen.isRef(defn.QuotedTypeClass)
917913

918-
def checkRedundancy(m: Match)(using Context): Unit = if redundancyCheckable(m.selector) then trace(i"checkRedundancy($m)", debug) {
914+
def checkReachability(m: Match)(using Context): Unit = trace(i"checkReachability($m)", debug) {
919915
val cases = m.cases.toIndexedSeq
920916

921917
val selTyp = toUnderlying(m.selector.tpe).dealias
@@ -967,4 +963,8 @@ object SpaceEngine {
967963
i += 1
968964
}
969965
}
966+
967+
def checkMatch(m: Match)(using Context): Unit =
968+
if exhaustivityCheckable(m.selector) then checkExhaustivity(m)
969+
if reachabilityCheckable(m.selector) then checkReachability(m)
970970
}

Diff for: scaladoc-js/common/src/utils/html.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ object HTML {
2626
case ("id", id) => elem.id = id
2727
case ("class", value) => value.split("\\s+").foreach(cls => elem.classList.add(cls))
2828
case (attr, value) => elem.setAttribute(attr, value)
29-
case s: Seq[AppliedAttr] => unpackAttributes(s*)
29+
case s: Seq[AppliedAttr @unchecked] => unpackAttributes(s*)
3030
}
3131

3232
unpackTags(tags:_*)
@@ -118,4 +118,4 @@ object HTML {
118118
val titleAttr =Attr("title")
119119
val onkeyup = Attr("onkeyup")
120120

121-
}
121+
}

Diff for: tests/pos/i19031.ci-reg1.scala

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//> using options -Werror
2+
3+
sealed trait Mark[T]
4+
5+
trait Foo[T]
6+
class Bar1[T] extends Foo[T]
7+
class Bar2[T] extends Foo[T] with Mark[T]
8+
9+
class Test:
10+
def t1(foo: Foo[Int]): Unit = foo match
11+
case _: Mark[t] =>
12+
case _ =>
13+
14+
def t2[F <: Foo[Int]](foo: F): Unit = foo match
15+
case _: Mark[t] =>
16+
case _ =>

Diff for: tests/pos/i19031.ci-reg2.scala

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//> using options -Werror
2+
3+
trait Outer:
4+
sealed trait Foo
5+
case class Bar1() extends Foo
6+
case class Bar2() extends Foo
7+
case object Bar3 extends Foo
8+
9+
def foos: List[Foo]
10+
11+
class Test:
12+
def t1(out: Outer) = out.foos.collect:
13+
case out.Bar1() => 1
14+
case out.Bar2() => 2
15+
case out.Bar3 => 3

Diff for: tests/pos/i19031.scala

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//> using options -Werror
2+
3+
sealed trait A:
4+
class B extends A
5+
6+
class Test:
7+
def t1(a: A): Boolean =
8+
a match
9+
case b: A#B => true

0 commit comments

Comments
 (0)