Skip to content

Fix #9171: Eliminate difference _ and Any in MT #9172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why simplified here?

Copy link
Contributor Author

@OlivierBlanvillain OlivierBlanvillain Jun 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The added test case (with case Int => instead of case _ =>) fails to compile on master with the following:

11 |  val fib2: Fib[2] = 1
   |                     ^
   |                  Found:    (1 : Int)
   |                  Required: LazyRef(Test2.Fib[(2 : Int) - (1 : Int)]) + 
   |                    LazyRef(Test2.Fib[(2 : Int) - (2 : Int)])

That's because when match type reduction simply reduces to body without going through instantiateParams reduction would stop without trying to further simplify the body in question.

}
}
else if (provablyDisjoint(scrut, pat))
Expand Down
21 changes: 13 additions & 8 deletions compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 6 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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)))
Expand Down
4 changes: 2 additions & 2 deletions tests/neg-custom-args/matchtype-loop.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do these time out now? Isn't that a problem?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do these time out now?

Because instead of stoping after one step of reduction we now try to keep reducing the match type body after the first step, which causes in infinite loop.

All the infinite loops that we encountered in match type reduction would eventually run out of stack, but this nicely trampolines and ultimately fails with an out of memory error.

This is indeed a problem, but the only solution I see would be to add some sort of reduction counter to match type reduction similar to -Xmax-inlines.

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 ...
Expand Down
8 changes: 4 additions & 4 deletions tests/neg/matchtype-seq.check
Original file line number Diff line number Diff line change
Expand Up @@ -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 -----------------------------------------------------
Expand All @@ -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 -----------------------------------------------------
Expand Down Expand Up @@ -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 ----------------------------------------------------
Expand All @@ -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`
16 changes: 15 additions & 1 deletion tests/pos/i8449.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import scala.compiletime.ops.int.*

object Test {
Expand All @@ -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
}
23 changes: 23 additions & 0 deletions tests/pos/unify-wildcard-patterns.scala
Original file line number Diff line number Diff line change
@@ -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" }
}