From 97d92ada5b7814637664df3f0876dffdc1271519 Mon Sep 17 00:00:00 2001 From: Olivier Blanvillain Date: Fri, 12 Jun 2020 12:58:03 +0200 Subject: [PATCH 1/2] Fix #9171: Eliminate difference _ and Any in MT `case _ =>` use to be typed as a `HKTypeLambda`, despite not binding anything. As a result, result of match type reduction going through `case _` would get further reduce that their `case Any` counterpart. This commit eliminates this distinction with the following changes: - Eliminate this distinction in typing (type `case _ =>` *as* `case Any =>`) - Simplify the body of match types in non-binding cases - Change the match type/expression unification to treat the `case _ =>` in a pattern like `case _: Any =>` Unfortunately this change introduces a regression in `matchtype-loop.scala` where the loop suddenly turns into an infinite loop that doesn't stack overflow. I don't see any other way to nicely fail than to introduce a new fuel-like counter to keep track of match type reductions. --- .../dotty/tools/dotc/core/TypeComparer.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 21 ++++++++++------- .../src/dotty/tools/dotc/typer/Typer.scala | 7 +++++- tests/neg-custom-args/matchtype-loop.scala | 4 ++-- tests/pos/i8449.scala | 16 ++++++++++++- tests/pos/unify-wildcard-patterns.scala | 23 +++++++++++++++++++ 6 files changed, 60 insertions(+), 13 deletions(-) create mode 100644 tests/pos/unify-wildcard-patterns.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 801ba332c596..11f20505fb17 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2788,7 +2788,7 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) { val instances = paramInstances(new Array(caseLambda.paramNames.length), pat) instantiateParams(instances)(body) case _ => - body + body.simplified } } else if (provablyDisjoint(scrut, pat)) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 8ce74a6061cc..24b64c4f521f 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -387,15 +387,20 @@ trait TypeAssigner { def assignType(tree: untpd.CaseDef, pat: Tree, body: Tree)(using Context): CaseDef = { val ownType = if (body.isType) { - val params = new TreeAccumulator[mutable.ListBuffer[TypeSymbol]] { - def apply(ps: mutable.ListBuffer[TypeSymbol], t: Tree)(using Context) = t match { - case t: Bind if t.symbol.isType => foldOver(ps += t.symbol.asType, t) - case _ => foldOver(ps, t) - } + pat match { + case Bind(name, _) if name == nme.WILDCARD.toTypeName => + defn.MatchCase(defn.AnyType, body.tpe) + case pat => + val params = new TreeAccumulator[mutable.ListBuffer[TypeSymbol]] { + def apply(ps: mutable.ListBuffer[TypeSymbol], t: Tree)(using Context) = t match { + case t: Bind if t.symbol.isType => foldOver(ps += t.symbol.asType, t) + case _ => foldOver(ps, t) + } + } + HKTypeLambda.fromParams( + params(new mutable.ListBuffer[TypeSymbol](), pat).toList, + defn.MatchCase(pat.tpe, body.tpe)) } - HKTypeLambda.fromParams( - params(new mutable.ListBuffer[TypeSymbol](), pat).toList, - defn.MatchCase(pat.tpe, body.tpe)) } else body.tpe tree.withType(ownType) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index e91269bf0965..85ffae7a0611 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1484,6 +1484,11 @@ class Typer extends Namer case defn.MatchCase(patternTp, _) => tpt.tpe frozen_=:= patternTp case _ => false } + case (id @ Ident(nme.WILDCARD), pt) => + pt match { + case defn.MatchCase(patternTp, _) => defn.AnyType frozen_=:= patternTp + case _ => false + } case _ => false } @@ -1615,7 +1620,7 @@ class Typer extends Namer assignType(cpy.Labeled(tree)(bind1, expr1)) } - /** Type a case of a type match */ + /** Type a case of a match type */ def typedTypeCase(cdef: untpd.CaseDef, selType: Type, pt: Type)(using Context): CaseDef = { def caseRest(using Context) = { val pat1 = withMode(Mode.Pattern)(checkSimpleKinded(typedType(cdef.pat))) diff --git a/tests/neg-custom-args/matchtype-loop.scala b/tests/neg-custom-args/matchtype-loop.scala index 316897b808a5..f0a2801a9e43 100644 --- a/tests/neg-custom-args/matchtype-loop.scala +++ b/tests/neg-custom-args/matchtype-loop.scala @@ -6,9 +6,9 @@ object Test { case Int => LL[LL[X]] } def a: L[Boolean] = ??? - def b: L[Int] = ??? + // def b: L[Int] = ??? // times out def g[X]: L[X] = ??? - val x: Int = g[Int] // error: found: L[Int], required: Int + // val x: Int = g[Int] // times out def aa: LL[Boolean] = ??? def bb: LL[Int] = ??? // error: recursion limit exceeded with reduce type LazyRef(Test.LL[Int]) match ... diff --git a/tests/pos/i8449.scala b/tests/pos/i8449.scala index e96801554e5c..08dd6757c7f7 100644 --- a/tests/pos/i8449.scala +++ b/tests/pos/i8449.scala @@ -1,4 +1,3 @@ - import scala.compiletime.ops.int.* object Test { @@ -15,3 +14,18 @@ object Test { val fib5: Fib[5] = 5 val fib6: Fib[6] = 8 } + +object Test2 { + type Fib[N <: Int] <: Int = N match { + case 0 => 0 + case 1 => 1 + case Int => Fib[N - 1] + Fib[N - 2] + } + val fib0: Fib[0] = 0 + val fib1: Fib[1] = 1 + val fib2: Fib[2] = 1 + val fib3: Fib[3] = 2 + val fib4: Fib[4] = 3 + val fib5: Fib[5] = 5 + val fib6: Fib[6] = 8 +} diff --git a/tests/pos/unify-wildcard-patterns.scala b/tests/pos/unify-wildcard-patterns.scala new file mode 100644 index 000000000000..9f18cebae1f5 --- /dev/null +++ b/tests/pos/unify-wildcard-patterns.scala @@ -0,0 +1,23 @@ +// `case _ => expr` in a match expression should be equivalant to +// `case _: Any => expr`. Likewise, in a match type, `case _ => T` +// should be equivalant to `case Any => T`. + +object Test0 { + type M[X] = X match { case String => Int case Any => String } + def m[X](x: X): M[X] = x match { case _: String => 1 case _: Any => "s" } +} + +object Test1 { + type M[X] = X match { case String => Int case Any => String } + def m[X](x: X): M[X] = x match { case _: String => 1 case _ => "s" } +} + +object Test2 { + type M[X] = X match { case String => Int case _ => String } + def m[X](x: X): M[X] = x match { case _: String => 1 case _: Any => "s" } +} + +object Test3 { + type M[X] = X match { case String => Int case _ => String } + def m[X](x: X): M[X] = x match { case _: String => 1 case _ => "s" } +} From 29337824eb6223db5be43c71272677129ddb6a3d Mon Sep 17 00:00:00 2001 From: Olivier Blanvillain Date: Mon, 26 Apr 2021 15:28:28 +0200 Subject: [PATCH 2/2] Update matchtype-seq.check --- tests/neg/matchtype-seq.check | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/neg/matchtype-seq.check b/tests/neg/matchtype-seq.check index b5dc6923d374..8933f333b97d 100644 --- a/tests/neg/matchtype-seq.check +++ b/tests/neg/matchtype-seq.check @@ -78,7 +78,7 @@ longer explanation available when compiling with `-explain` | and cannot be shown to be disjoint from it either. | Therefore, reduction cannot advance to the remaining case | - | case _ => String + | case Any => String longer explanation available when compiling with `-explain` -- [E007] Type Mismatch Error: tests/neg/matchtype-seq.scala:22:18 ----------------------------------------------------- @@ -102,7 +102,7 @@ longer explanation available when compiling with `-explain` | and cannot be shown to be disjoint from it either. | Therefore, reduction cannot advance to the remaining case | - | case _ => String + | case Any => String longer explanation available when compiling with `-explain` -- [E007] Type Mismatch Error: tests/neg/matchtype-seq.scala:36:18 ----------------------------------------------------- @@ -459,7 +459,7 @@ longer explanation available when compiling with `-explain` | and cannot be shown to be disjoint from it either. | Therefore, reduction cannot advance to the remaining case | - | case _ => Int + | case Any => Int longer explanation available when compiling with `-explain` -- [E007] Type Mismatch Error: tests/neg/matchtype-seq.scala:187:25 ---------------------------------------------------- @@ -476,6 +476,6 @@ longer explanation available when compiling with `-explain` | and cannot be shown to be disjoint from it either. | Therefore, reduction cannot advance to the remaining case | - | case _ => Int + | case Any => Int longer explanation available when compiling with `-explain`