From 8f2b6cf0dc2d681be6c585572e7cf0680e627d2e Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 22 Feb 2024 13:59:04 +0000 Subject: [PATCH] Approximate MatchTypes with lub of case bodies, if non-recursive --- .../src/dotty/tools/dotc/core/TypeComparer.scala | 13 ++++++++++++- tests/pos/i19710.scala | 11 +++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i19710.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index b23bfe9fe14b..9373889b37d6 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1030,6 +1030,17 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling if tp1 ne tp1norm then recur(tp1norm, tp2) else either(recur(tp11, tp2), recur(tp12, tp2)) case tp1: MatchType => + def compareUpper = + val lub1 = tp1.cases.foldLeft(defn.NothingType: Type): (acc, case1) => + if acc.exists then + val rhs = case1.resultType match { case defn.MatchCase(_, body) => body } + val isRecursive = rhs.existsPart(_.isInstanceOf[LazyRef]) + if isRecursive then NoType else lub(acc, rhs) + else acc + if lub1.exists then + recur(lub1, tp2) + else + recur(tp1.underlying, tp2) def compareMatch = tp2 match { case tp2: MatchType => // we allow a small number of scrutinee types to be widened: @@ -1047,7 +1058,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling tp1.cases.corresponds(tp2.cases)(isSubType) case _ => false } - (!caseLambda.exists || canWidenAbstract) && recur(tp1.underlying, tp2) || compareMatch + (!caseLambda.exists || canWidenAbstract) && compareUpper || compareMatch case tp1: AnnotatedType if tp1.isRefining => isNewSubType(tp1.parent) case JavaArrayType(elem1) => diff --git a/tests/pos/i19710.scala b/tests/pos/i19710.scala new file mode 100644 index 000000000000..03fd1e2d80b3 --- /dev/null +++ b/tests/pos/i19710.scala @@ -0,0 +1,11 @@ +import scala.util.NotGiven + +type HasName1 = [n] =>> [x] =>> x match { + case n => true + case _ => false + } +@main def Test = { + summon[HasName1["foo"]["foo"] =:= true] + summon[NotGiven[HasName1["foo"]["bar"] =:= true]] + summon[Tuple.Filter[(1, "foo", 2, "bar"), HasName1["foo"]] =:= Tuple1["foo"]] // error +}