Skip to content

Commit 0022dcc

Browse files
committed
[backport] SI-7756 Uncripple refchecks in case bodies
In 65340ed, parts of RefChecks were disabled when we traversed into the results of the new pattern matcher. Similar logic existed for the old pattern matcher, but in that case the Match / CaseDef nodes still existed in the tree. The new approach was too broad: important checks no longer scrutinized the body of cases. This commit turns the checks back on when it finds the remnants of a case body, which appears as an application to a label def. Conflicts: src/compiler/scala/tools/nsc/typechecker/RefChecks.scala Cherry pick of 3df1d77
1 parent 5720e97 commit 0022dcc

File tree

8 files changed

+69
-8
lines changed

8 files changed

+69
-8
lines changed

src/compiler/scala/tools/nsc/typechecker/RefChecks.scala

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
9898
var localTyper: analyzer.Typer = typer;
9999
var currentApplication: Tree = EmptyTree
100100
var inPattern: Boolean = false
101+
@inline final def savingInPattern[A](body: => A): A = {
102+
val saved = inPattern
103+
try body finally inPattern = saved
104+
}
105+
101106
var checkedCombinations = Set[List[Type]]()
102107

103108
// only one overloaded alternative is allowed to define default arguments
@@ -1822,19 +1827,33 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
18221827

18231828
case _ => tree
18241829
}
1830+
18251831
// skip refchecks in patterns....
18261832
result = result match {
18271833
case CaseDef(pat, guard, body) =>
1828-
inPattern = true
1829-
val pat1 = transform(pat)
1830-
inPattern = false
1834+
val pat1 = savingInPattern {
1835+
inPattern = true
1836+
transform(pat)
1837+
}
18311838
treeCopy.CaseDef(tree, pat1, transform(guard), transform(body))
18321839
case LabelDef(_, _, _) if treeInfo.hasSynthCaseSymbol(result) =>
1833-
val old = inPattern
1834-
inPattern = true
1835-
val res = deriveLabelDef(result)(transform) // TODO SI-7756 Too broad! The code from the original case body should be fully refchecked!
1836-
inPattern = old
1837-
res
1840+
savingInPattern {
1841+
inPattern = true
1842+
deriveLabelDef(result)(transform)
1843+
}
1844+
case Apply(fun, args) if fun.symbol.isLabel && treeInfo.isSynthCaseSymbol(fun.symbol) =>
1845+
savingInPattern {
1846+
// SI-7756 If we were in a translated pattern, we can now switch out of pattern mode, as the label apply signals
1847+
// that we are in the user-supplied code in the case body.
1848+
//
1849+
// Relies on the translation of:
1850+
// (null: Any) match { case x: List[_] => x; x.reverse; case _ => }'
1851+
// to:
1852+
// <synthetic> val x2: List[_] = (x1.asInstanceOf[List[_]]: List[_]);
1853+
// matchEnd4({ x2; x2.reverse}) // case body is an argument to a label apply.
1854+
if (settings.future.value) inPattern = false // By default, bug compatibility with 2.10.[0-4]
1855+
super.transform(result)
1856+
}
18381857
case ValDef(_, _, _, _) if treeInfo.hasSynthCaseSymbol(result) =>
18391858
deriveValDef(result)(transform) // SI-7716 Don't refcheck the tpt of the synthetic val that holds the selector.
18401859
case _ =>

test/files/neg/t7756a.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
t7756a.scala:7: error: type arguments [Object] do not conform to trait TA's type parameter bounds [X <: CharSequence]
2+
locally(null: TA[Object])
3+
^
4+
t7756a.scala:7: error: type arguments [Object] do not conform to trait TA's type parameter bounds [X <: CharSequence]
5+
locally(null: TA[Object])
6+
^
7+
two errors found

test/files/neg/t7756a.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Xfuture

test/files/neg/t7756a.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
object Test {
2+
def test: Unit = {
3+
trait TA[X <: CharSequence]
4+
0 match {
5+
case _ =>
6+
// the bounds violation isn't reported. RefChecks seems to be too broadly disabled under virtpatmat: see 65340ed4ad2e
7+
locally(null: TA[Object])
8+
()
9+
}
10+
}
11+
}

test/files/neg/t7756b.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
t7756b.scala:3: error: comparing values of types Int and String using `==' will always yield false
2+
case _ => 0 == ""
3+
^
4+
one error found

test/files/neg/t7756b.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Xfuture -Xfatal-warnings

test/files/neg/t7756b.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object Test {
2+
0 match {
3+
case _ => 0 == ""
4+
}
5+
}

test/files/pos/t7756b.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// This is a pos test to show that the backported bug fix for SI-7756 is
2+
// only enabled under -Xfuture.
3+
object Test {
4+
def test: Unit = {
5+
trait TA[X <: CharSequence]
6+
0 match {
7+
case _ =>
8+
// the bounds violation isn't reported. RefChecks seems to be too broadly disabled under virtpatmat: see 65340ed4ad2e
9+
locally(null: TA[Object])
10+
()
11+
}
12+
}
13+
}

0 commit comments

Comments
 (0)