summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Modes.scala14
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala13
-rw-r--r--test/files/neg/checksensible.check4
-rw-r--r--test/files/neg/checksensible.scala2
4 files changed, 24 insertions, 9 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Modes.scala b/src/compiler/scala/tools/nsc/typechecker/Modes.scala
index 3eff5ef024..5d827e0de2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Modes.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Modes.scala
@@ -86,6 +86,17 @@ trait Modes {
*/
final val TYPEPATmode = 0x10000
+ /** STATmode is set when typing statements inside a block.
+ *
+ * This is useful only for skipping lub computations in
+ * such positions, when the expected type is known to be Unit. This
+ * saves time in pathological cases where lubs can take many seconds
+ * but in the end is discarded.
+ *
+ * TODO: Remove when lubs become types in their own right.
+ */
+ final val STATmode = 0x20000
+
final private val StickyModes = EXPRmode | PATTERNmode | TYPEmode | ALTmode
final def onlyStickyModes(mode: Int) =
@@ -128,7 +139,8 @@ trait Modes {
(1 << 13) -> "ALTmode",
(1 << 14) -> "HKmode",
(1 << 15) -> "BYVALmode",
- (1 << 16) -> "TYPEPATmode"
+ (1 << 16) -> "TYPEPATmode",
+ (1 << 17) -> "STATmode"
)
def modeString(mode: Int): String =
if (mode == 0) "NOmode"
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index b0f6e44e88..f6d5f84107 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1127,9 +1127,11 @@ trait Typers extends Modes with Adaptations with Taggings {
if (inExprModeButNot(mode, FUNmode)) {
pt.normalize match {
case TypeRef(_, sym, _) =>
- // note: was if (pt.typeSymbol == UnitClass) but this leads to a potentially
- // infinite expansion if pt is constant type ()
- if (sym == UnitClass && tree.tpe <:< AnyClass.tpe) { // (12)
+ // note: there was an additional '&& tree.tpe <:< AnyClass.tpe', claiming that
+ // it would save us from a potentially infinite expansion if pt is constant type ()
+ // didn't seem to do any good, and the test would miss the fact that Object.tpe <:< AnyClass.tpe
+ // after erasure (triggered by try-catches added by cleanup for structural types)
+ if (sym == UnitClass) { // (12)
if (settings.warnValueDiscard.value)
context.unit.warning(tree.pos, "discarded non-Unit value")
return typed(atPos(tree.pos)(Block(List(tree), Literal(Constant()))), mode, pt)
@@ -2566,7 +2568,7 @@ trait Typers extends Modes with Adaptations with Taggings {
} else newTyper(context.make(stat, exprOwner))
// XXX this creates a spurious dead code warning if an exception is thrown
// in a constructor, even if it is the only thing in the constructor.
- val result = checkDead(localTyper.typed(stat, EXPRmode | BYVALmode, WildcardType))
+ val result = checkDead(localTyper.typed(stat, EXPRmode | BYVALmode | STATmode, WildcardType))
if (treeInfo.isSelfOrSuperConstrCall(result)) {
context.inConstructorSuffix = true
@@ -3861,6 +3863,7 @@ trait Typers extends Modes with Adaptations with Taggings {
&& thenTp =:= elseTp
) (thenp1.tpe, false) // use unpacked type
// TODO: skolemize (lub of packed types) when that no longer crashes on files/pos/t4070b.scala
+ else if ((mode & STATmode) != 0) (definitions.UnitClass.tpe, true)
else ptOrLub(List(thenp1.tpe, elsep1.tpe), pt)
if (needAdapt) { //isNumericValueType(owntype)) {
@@ -4744,7 +4747,7 @@ trait Typers extends Modes with Adaptations with Taggings {
var catches1 = typedCases(catches, ThrowableClass.tpe, pt)
val finalizer1 = if (finalizer.isEmpty) finalizer
else typed(finalizer, UnitClass.tpe)
- val (owntype, needAdapt) = ptOrLub(block1.tpe :: (catches1 map (_.tpe)), pt)
+ val (owntype, needAdapt) = if ((mode & STATmode) != 0) (definitions.UnitClass.tpe, true) else ptOrLub(block1.tpe :: (catches1 map (_.tpe)), pt)
if (needAdapt) {
block1 = adapt(block1, mode, owntype)
catches1 = catches1 map (adaptCase(_, mode, owntype))
diff --git a/test/files/neg/checksensible.check b/test/files/neg/checksensible.check
index 23af94180a..772d58322d 100644
--- a/test/files/neg/checksensible.check
+++ b/test/files/neg/checksensible.check
@@ -77,8 +77,8 @@ checksensible.scala:63: error: comparing a fresh object using `!=' will always y
new Exception() != new Exception()
^
checksensible.scala:66: error: comparing values of types Int and Null using `==' will always yield false
- if (foo.length == null) "plante" else "plante pas"
- ^
+ val dummy = if (foo.length == null) "plante" else "plante pas"
+ ^
checksensible.scala:71: error: comparing values of types Bip and Bop using `==' will always yield false
(x1 == x2)
^
diff --git a/test/files/neg/checksensible.scala b/test/files/neg/checksensible.scala
index 27ee908153..15a9b6d9b6 100644
--- a/test/files/neg/checksensible.scala
+++ b/test/files/neg/checksensible.scala
@@ -63,7 +63,7 @@ class EqEqRefTest {
new Exception() != new Exception()
val foo: Array[String] = Array("1","2","3")
- if (foo.length == null) "plante" else "plante pas"
+ val dummy = if (foo.length == null) "plante" else "plante pas"
// final classes with default equals
val x1 = new Bip