Skip to content

Commit 2b156c6

Browse files
committed
Fix #9740: harden type checking for pattern match on objects
We enforce that when pattern match on an object, the object should be a subtype of the scrutinee type. Reasons for doing so: - such code patterns usually implies hidden errors in the code - it's always safe/sound to reject the code We could check whether `equals` is overridden in the object, but - it complicates the protocol - overriding `equals` of object is also a bad practice - there is no sign that the slightly improved completeness is useful
1 parent 8b1188b commit 2b156c6

File tree

2 files changed

+32
-7
lines changed

2 files changed

+32
-7
lines changed

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

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -865,9 +865,9 @@ class Typer extends Namer
865865
*/
866866
val arg1 = pt match {
867867
case AppliedType(a, typ :: Nil) if ctx.isJava && a.isRef(defn.ArrayClass) =>
868-
tryAlternatively { typed(tree.arg, pt) } {
868+
tryAlternatively { typed(tree.arg, pt) } {
869869
val elemTp = untpd.TypedSplice(TypeTree(typ))
870-
typed(untpd.JavaSeqLiteral(tree.arg :: Nil, elemTp), pt)
870+
typed(untpd.JavaSeqLiteral(tree.arg :: Nil, elemTp), pt)
871871
}
872872
case _ => typed(tree.arg, pt)
873873
}
@@ -3761,11 +3761,20 @@ class Typer extends Namer
37613761
withMode(Mode.GadtConstraintInference) {
37623762
TypeComparer.constrainPatternType(tree.tpe, pt)
37633763
}
3764-
val cmp =
3765-
untpd.Apply(
3766-
untpd.Select(untpd.TypedSplice(tree), nme.EQ),
3767-
untpd.TypedSplice(dummyTreeOfType(pt)))
3768-
typedExpr(cmp, defn.BooleanType)
3764+
3765+
if tree.symbol.is(Module) && !(tree.tpe <:< pt) then
3766+
// We could check whether `equals` is overriden.
3767+
// Reasons for not doing so:
3768+
// - it complicates the protocol
3769+
// - such code patterns usually implies hidden errors in the code
3770+
// - it's safe/sound to reject the code
3771+
report.error(TypeMismatch(tree.tpe, pt, "\npattern type is incompatible with expected type"), tree.srcPos)
3772+
else
3773+
val cmp =
3774+
untpd.Apply(
3775+
untpd.Select(untpd.TypedSplice(tree), nme.EQ),
3776+
untpd.TypedSplice(dummyTreeOfType(pt)))
3777+
typedExpr(cmp, defn.BooleanType)
37693778
case _ =>
37703779

37713780
private def checkStatementPurity(tree: tpd.Tree)(original: untpd.Tree, exprOwner: Symbol)(using Context): Unit =

tests/neg/i9740.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
abstract class RecoveryCompleted
2+
object RecoveryCompleted extends RecoveryCompleted
3+
4+
abstract class TypedRecoveryCompleted
5+
object TypedRecoveryCompleted extends TypedRecoveryCompleted
6+
7+
class Test {
8+
TypedRecoveryCompleted match {
9+
case RecoveryCompleted => println("Recovery completed") // error
10+
case TypedRecoveryCompleted => println("Typed recovery completed")
11+
}
12+
13+
def foo(x: TypedRecoveryCompleted) = x match
14+
case RecoveryCompleted => // error
15+
case TypedRecoveryCompleted =>
16+
}

0 commit comments

Comments
 (0)