Skip to content

Commit ea11087

Browse files
committed
Widen type params in checking whether an object is matchable
1 parent 2b156c6 commit ea11087

File tree

7 files changed

+64
-11
lines changed

7 files changed

+64
-11
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3762,7 +3762,19 @@ class Typer extends Namer
37623762
TypeComparer.constrainPatternType(tree.tpe, pt)
37633763
}
37643764

3765-
if tree.symbol.is(Module) && !(tree.tpe <:< pt) then
3765+
// approximate type params with bounds
3766+
def approx = new ApproximatingTypeMap {
3767+
def apply(tp: Type) = tp.dealias match
3768+
case tp: TypeRef if !tp.symbol.isClass =>
3769+
expandBounds(tp.info.bounds)
3770+
case _ =>
3771+
mapOver(tp)
3772+
}
3773+
3774+
if tree.symbol.is(Module)
3775+
&& !(tree.tpe frozen_<:< pt) // fast track
3776+
&& !(tree.tpe frozen_<:< approx(pt))
3777+
then
37663778
// We could check whether `equals` is overriden.
37673779
// Reasons for not doing so:
37683780
// - it complicates the protocol

tests/neg/i5077.scala

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
trait Is[A]
2+
case object IsInt extends Is[Int]
3+
case object IsString extends Is[String]
4+
case class C[A](is: Is[A], value: A)
5+
6+
@main
7+
def Test = {
8+
val c_string: C[String] = C(IsString, "name")
9+
val c_any: C[_] = c_string
10+
val any: Any = c_string
11+
12+
// Case 1: error
13+
c_string match {
14+
case C(IsInt, _) => println(s"An Int") // error
15+
case C(IsString, s) => println(s"A String with length ${s.length}")
16+
case _ => println("No match")
17+
}
18+
19+
// Case 2: Should match the second case and print the length of the string
20+
c_any match {
21+
case C(IsInt, i) if i < 10 => println(s"An Int less than 10")
22+
case C(IsString, s) => println(s"A String with length ${s.length}")
23+
case _ => println("No match")
24+
}
25+
26+
// Case 3: Same as above; should match the second case and print the length of the string
27+
any match {
28+
case C(IsInt, i) if i < 10 => println(s"An Int less than 10")
29+
case C(IsString, s) => println(s"A String with length ${s.length}")
30+
case _ => println("No match")
31+
}
32+
}

tests/pos/autoTuplingTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
object autoTupling {
22

3-
val x = Some(1, 2)
3+
val x: Option[(Int, Int)] = Some(1, 2)
44

55
x match {
66
case Some(a, b) => a + b

tests/pos/i7516.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
val foo: Int => Int = Some(7) match
1+
val foo: Int => Int = Option(7) match
22
case Some(y) => x => y
33
case None => identity[Int]

tests/pos/i9740b.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
sealed trait Exp[T]
2+
case class IntExp(x: Int) extends Exp[Int]
3+
case class StrExp(x: String) extends Exp[String]
4+
object UnitExp extends Exp[Unit]
5+
6+
class Foo[U <: Int, T <: U] {
7+
def bar[A <: T](x: Exp[A]): Unit = x match
8+
case IntExp(x) =>
9+
case StrExp(x) =>
10+
case UnitExp =>
11+
}

tests/run/i5077.check

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
A String with length 4
22
A String with length 4
3-
A String with length 4

tests/run/i5077.scala

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ def Test = {
99
val c_any: C[_] = c_string
1010
val any: Any = c_string
1111

12-
// Case 1: no error
13-
// `IsInt.equals` might be overridden to match a value of `C[String]`
14-
c_string match {
15-
case C(IsInt, _) => println(s"An Int") // Can't possibly happen!
16-
case C(IsString, s) => println(s"A String with length ${s.length}")
17-
case _ => println("No match")
18-
}
12+
// Case 1: error, tested in tests/neg/i5077.scala
13+
// c_string match {
14+
// case C(IsInt, _) => println(s"An Int") // Can't possibly happen!
15+
// case C(IsString, s) => println(s"A String with length ${s.length}")
16+
// case _ => println("No match")
17+
// }
1918

2019
// Case 2: Should match the second case and print the length of the string
2120
c_any match {

0 commit comments

Comments
 (0)