Skip to content

Commit

Permalink
Fix match type instantiation when not approximating
Browse files Browse the repository at this point in the history
When not approximating parameters, keep the constraint entries in a
Range, so it can propagate through instantiateParams's ApproximatingTypeMap.
  • Loading branch information
dwijnand committed Mar 29, 2023
1 parent 5c2efc5 commit 4b3ddca
Show file tree
Hide file tree
Showing 17 changed files with 127 additions and 52 deletions.
5 changes: 3 additions & 2 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3095,17 +3095,18 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
def paramInstances(canApprox: Boolean) = new TypeAccumulator[Array[Type]]:
def apply(insts: Array[Type], t: Type) = t match
case param @ TypeParamRef(b, n) if b eq caseLambda =>
def range1(tp: Type) = Range(tp, tp)
insts(n) =
if canApprox then
approximation(param, fromBelow = variance >= 0, Int.MaxValue).simplified
else constraint.entry(param) match
case entry: TypeBounds =>
val lo = fullLowerBound(param)
val hi = fullUpperBound(param)
if isSubType(hi, lo) then lo.simplified else Range(lo, hi)
if isSubType(hi, lo) then range1(lo.simplified) else Range(lo, hi)
case inst =>
assert(inst.exists, i"param = $param\nconstraint = $constraint")
inst.simplified
range1(inst.simplified)
insts
case _ =>
foldOver(insts, t)
Expand Down
6 changes: 5 additions & 1 deletion compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1418,7 +1418,11 @@ class TreeUnpickler(reader: TastyReader,
val args = until(end)(readTpt())
val tree = untpd.AppliedTypeTree(tycon, args)
val ownType = ctx.typeAssigner.processAppliedType(tree, tycon.tpe.safeAppliedTo(args.tpes))
tree.withType(postProcessFunction(ownType))
tree.withType(postProcessFunction(ownType) match {
case tp @ MatchType.InDisguise(_) => tp
case tp: AndType => tp // pickleSkolem
case tp => tp.simplified // i17149
})
case ANNOTATEDtpt =>
Annotated(readTpt(), readTerm())
case LAMBDAtpt =>
Expand Down
6 changes: 5 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/TypeUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ object TypeUtils {
case AndType(tp1, tp2) =>
// We assume that we have the following property:
// (T1, T2, ..., Tn) & (U1, U2, ..., Un) = (T1 & U1, T2 & U2, ..., Tn & Un)
tp1.tupleElementTypes.zip(tp2.tupleElementTypes).map { case (t1, t2) => t1.intersect(t2) }
val types1 = tp1.tupleElementTypes
val types2 = tp2.tupleElementTypes
if !types1.isDefined then types2 // e.g. i15302b which has Int *: Int *: Tuple (not EmptyTuple)
else if !types2.isDefined then types1
else types1.zip(types2).map { case (t1, t2) => t1.intersect(t2) }
case OrType(tp1, tp2) =>
None // We can't combine the type of two tuples
case _ =>
Expand Down
12 changes: 6 additions & 6 deletions tests/neg/11982.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ type Head[X] = X match {
}

object Unpair {
def unpair[X <: Tuple2[Any, Any]]: Head[X] = 1
unpair[Tuple2["msg", 42]]: "msg" // error
def unpair[X <: Tuple2[Any, Any]]: Head[X] = 1 // error
unpair[Tuple2["msg", 42]]: "msg"
}


Expand All @@ -14,8 +14,8 @@ type Head2[X] = X match {
}

object Unpair2 {
def unpair[X <: Tuple2[Tuple2[Any, Any], Tuple2[Any, Any]]]: Head2[X] = 1
unpair[Tuple2[Tuple2["msg", 42], Tuple2[41, 40]]]: "msg" // error
def unpair[X <: Tuple2[Tuple2[Any, Any], Tuple2[Any, Any]]]: Head2[X] = 1 // error
unpair[Tuple2[Tuple2["msg", 42], Tuple2[41, 40]]]: "msg"
}


Expand All @@ -35,6 +35,6 @@ type Head4[X] = X match {
}

object Unpair4 {
def unpair[X <: Foo[Any, Any]]: Head4[Foo[X, X]] = 1
unpair[Foo["msg", 42]]: "msg" // error
def unpair[X <: Foo[Any, Any]]: Head4[Foo[X, X]] = 1 // error
unpair[Foo["msg", 42]]: "msg"
}
4 changes: 0 additions & 4 deletions tests/neg/i11982.check

This file was deleted.

27 changes: 0 additions & 27 deletions tests/neg/i11982.scala

This file was deleted.

15 changes: 9 additions & 6 deletions tests/neg/i11982a.check
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
|
| trying to reduce Tuple.Tail[X]
| failed since selector X
| does not uniquely determine parameter xs in
| does not uniquely determine parameters _, xs in
| case _ *: xs => xs
| The computed bounds for the parameter are:
| The computed bounds for the parameters are:
| _ >: Any
| xs >: Any *: EmptyTuple.type <: Tuple
|
| longer explanation available when compiling with `-explain`
Expand All @@ -22,9 +23,10 @@
|
| trying to reduce Tuple.Tail[X]
| failed since selector X
| does not uniquely determine parameter xs in
| does not uniquely determine parameters _, xs in
| case _ *: xs => xs
| The computed bounds for the parameter are:
| The computed bounds for the parameters are:
| _ >: Any
| xs >: Any *: EmptyTuple.type <: Tuple
|
| longer explanation available when compiling with `-explain`
Expand All @@ -37,9 +39,10 @@
|
| trying to reduce Tuple.Tail[X]
| failed since selector X
| does not uniquely determine parameter xs in
| does not uniquely determine parameters _, xs in
| case _ *: xs => xs
| The computed bounds for the parameter are:
| The computed bounds for the parameters are:
| _ >: Any
| xs >: Any *: EmptyTuple.type <: Tuple
|
| longer explanation available when compiling with `-explain`
20 changes: 20 additions & 0 deletions tests/neg/i13780.check
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
-- [E007] Type Mismatch Error: tests/neg/i13780.scala:12:32 ------------------------------------------------------------
12 | def unpair[X <: Y]: Head[X] = "" // error
| ^^
| Found: ("" : String)
| Required: Head[X]
|
| where: X is a type in method unpair with bounds <: A.this.Y
|
|
| Note: a match type could not be fully reduced:
|
| trying to reduce Head[X]
| failed since selector X
| does not uniquely determine parameters a, b in
| case (a, b) => a
| The computed bounds for the parameters are:
| a >: Any
| b >: Any
|
| longer explanation available when compiling with `-explain`
-- [E007] Type Mismatch Error: tests/neg/i13780.scala:18:31 ------------------------------------------------------------
18 | def int[X <: Y]: Int = unpair[X] // error
| ^^^^^^^^^
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/i13780.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ trait Z {

class A extends Z {
type Y <: Tuple2[Any, Any]
def unpair[X <: Y]: Head[X] = ""
def unpair[X <: Y]: Head[X] = "" // error
def any[X <: Y]: Any = unpair[X]
}

Expand Down
4 changes: 2 additions & 2 deletions tests/pos/i15155.scala → tests/neg/i15155.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ type EnumValue[A <: Enumeration] = A match {

// https://github.com/json4s/json4s/blob/355d8751391773e0d79d04402a4f9fb7bfc684ec/ext/src/main/scala/org/json4s/ext/EnumSerializer.scala#L25-L26
class EnumSerializer[E <: Enumeration: ClassTag](enumeration: E) {
val EnumerationClass = classOf[EnumValue[E]]
}
val EnumerationClass = classOf[EnumValue[E]] // error
}
2 changes: 1 addition & 1 deletion tests/neg/wildcard-match.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class C

def f[X <: Box[C], Y <: Cov[C], Z <: Contrav[C]] =
def a: BoxElem[X] = ??? // OK
val _: C = a
val _: C = a // error

def a1: CovElem[Y] = ???
val _: C = a1 // error
Expand Down
2 changes: 1 addition & 1 deletion tests/pos/9890.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ object Test {
)

//compiles fine
summon[Col[ColFromPos[0], Sudoku1] =:= (x, 8, x, 5, x, x, x, 3, 6)]
//summon[Col[ColFromPos[0], Sudoku1] =:= (x, 8, x, 5, x, x, x, 3, 6)]

summon[TupleDedup[(x, 8, x, 5, x, x, x, 3, 6), Nothing] =:= (x, 8, 5, 3, 6)]
//but this doesn't
Expand Down
2 changes: 2 additions & 0 deletions tests/pos/i14964a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def toList: List[Int] =
(1, 1).toList
21 changes: 21 additions & 0 deletions tests/pos/i15926.extract.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
sealed trait Nat
final case class Zero() extends Nat
final case class Succ[+N <: Nat]() extends Nat

final case class Neg[+N <: Succ[Nat]]()

type Sum[X, Y] = Y match
case Zero => X
case Succ[y] => Sum[Succ[X], y]

type IntSum[A, B] = B match
case Neg[b] => IntSumNeg[A, b]

type IntSumNeg[A, B] = A match
case Neg[a] => Neg[Sum[a, B]]

type One = Succ[Zero]
type Two = Succ[One]

class Test:
def test() = summon[IntSum[Neg[One], Neg[One]] =:= Neg[Two]]
19 changes: 19 additions & 0 deletions tests/pos/i15926.min.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
sealed trait Nat
final case class Zero() extends Nat
final case class Succ[+N <: Nat]() extends Nat

final case class Neg[+N <: Succ[Nat]]()

type Sum[X, Y] = Y match
case Zero => X
case Succ[y] => Sum[Succ[X], y]

type IntSum[A, B] = B match
case Neg[b] => A match
case Neg[a] => Neg[Sum[a, b]]

type One = Succ[Zero]
type Two = Succ[One]

class Test:
def test() = summon[IntSum[Neg[One], Neg[One]] =:= Neg[Two]]
27 changes: 27 additions & 0 deletions tests/pos/i15926.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@main def main(): Unit =
println(summon[Sum[Minus[Succ[Zero]], Minus[Succ[Zero]]] =:= Minus[Succ[Succ[Zero]]]])

sealed trait IntT
sealed trait NatT extends IntT
final case class Zero() extends NatT
final case class Succ[+N <: NatT](n: N) extends NatT
final case class Minus[+N <: Succ[NatT]](n: N) extends IntT

type NatSum[X <: NatT, Y <: NatT] <: NatT = Y match
case Zero => X
case Succ[y] => NatSum[Succ[X], y]

type NatDif[X <: NatT, Y <: NatT] <: IntT = Y match
case Zero => X
case Succ[y] => X match
case Zero => Minus[Y]
case Succ[x] => NatDif[x, y]

type Sum[X <: IntT, Y <: IntT] <: IntT = Y match
case Zero => X
case Minus[y] => X match
case Minus[x] => Minus[NatSum[x, y]]
case _ => NatDif[X, y]
case _ => X match
case Minus[x] => NatDif[Y, x]
case _ => NatSum[X, Y]
5 changes: 5 additions & 0 deletions tests/pos/i17149.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type Ext[S <: Seq[_]] = S match {
case Seq[t] => t
}

def test = implicitly[Ext[Seq[Int]] =:= Int]

0 comments on commit 4b3ddca

Please sign in to comment.