summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala30
-rw-r--r--test/files/pos/no-widen-locals.scala17
-rw-r--r--test/files/run/constrained-types.check4
-rw-r--r--test/files/run/constrained-types.scala2
4 files changed, 44 insertions, 9 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 7b2b737fb5..70d326ceb7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -577,9 +577,27 @@ trait Namers { self: Analyzer =>
sym.setInfo(selftpe)
}
- private def widenIfNotFinal(sym: Symbol, tpe: Type, pt: Type): Type = {
+ /** This method has a big impact on the eventual compiled code.
+ * At this point many values have the most specific possible
+ * type (e.g. in val x = 42, x's type is Int(42), not Int) but
+ * most need to be widened to avoid undesirable propagation of
+ * those singleton types.
+ *
+ * However, the compilation of pattern matches into switch
+ * statements depends on constant folding, which will only take
+ * place for those values which aren't widened. The "final"
+ * modifier is the present means of signaling that a constant
+ * value should not be widened, so it has a use even in situations
+ * whether it is otherwise redundant (such as in a singleton.)
+ * Locally defined symbols are also excluded from widening.
+ *
+ * PP:is there a useful difference in practice between widen
+ * and deconst which wouldn't be achieved by simply calling widen
+ * in both situations? If so, could an example of this be added?
+ */
+ private def widenIfNecessary(sym: Symbol, tpe: Type, pt: Type): Type = {
val getter =
- if (sym.isValue && sym.owner.isClass && (sym hasFlag PRIVATE))
+ if (sym.isValue && sym.owner.isClass && sym.isPrivate)
sym.getter(sym.owner)
else sym
def isHidden(tp: Type): Boolean = tp match {
@@ -597,8 +615,8 @@ trait Namers { self: Analyzer =>
if ((sym.isVariable || sym.isMethod && !(sym hasFlag ACCESSOR)))
if (tpe2 <:< pt) tpe2 else tpe1
else if (isHidden(tpe)) tpe2
- else if (!(sym hasFlag FINAL)) tpe1
- else tpe
+ else if (sym.isFinal || sym.isLocal) tpe
+ else tpe1
}
// sets each ValDef's symbol
@@ -895,7 +913,7 @@ trait Namers { self: Analyzer =>
// replace deSkolemized symbols with skolemized ones (for resultPt computed by looking at overridden symbol, right?)
val pt = resultPt.substSym(tparamSyms, tparams map (_.symbol))
// compute result type from rhs
- tpt defineType widenIfNotFinal(meth, typer.computeType(rhs, pt), pt)
+ tpt defineType widenIfNecessary(meth, typer.computeType(rhs, pt), pt)
tpt setPos meth.pos.focus
tpt.tpe
} else typer.typedType(tpt).tpe
@@ -1138,7 +1156,7 @@ trait Namers { self: Analyzer =>
context.error(tpt.pos, "missing parameter type");
ErrorType
} else {
- tpt defineType widenIfNotFinal(
+ tpt defineType widenIfNecessary(
sym,
newTyper(typer1.context.make(vdef, sym)).computeType(rhs, WildcardType),
WildcardType)
diff --git a/test/files/pos/no-widen-locals.scala b/test/files/pos/no-widen-locals.scala
new file mode 100644
index 0000000000..32579404b2
--- /dev/null
+++ b/test/files/pos/no-widen-locals.scala
@@ -0,0 +1,17 @@
+import annotation.switch
+
+object Test {
+ def f(x: Int) = {
+ val X1 = 5
+ val X2 = 10
+ val X3 = 15
+ val X4 = 20
+
+ (x: @switch) match {
+ case X1 => 1
+ case X2 => 2
+ case X3 => 3
+ case X4 => 4
+ }
+ }
+}
diff --git a/test/files/run/constrained-types.check b/test/files/run/constrained-types.check
index 8050017659..dbad841d99 100644
--- a/test/files/run/constrained-types.check
+++ b/test/files/run/constrained-types.check
@@ -92,8 +92,8 @@ def m = {
val x = "three"
val y : String @Annot(x) = x
y
-} // x should be existentially bound
-m: java.lang.String @Annot(x) forSome { val x: java.lang.String }
+} // x should not escape the local scope with a narrow type
+m: String @Annot("three")
-----
def n(y: String) = {
diff --git a/test/files/run/constrained-types.scala b/test/files/run/constrained-types.scala
index c03c144ad1..62abfe9e31 100644
--- a/test/files/run/constrained-types.scala
+++ b/test/files/run/constrained-types.scala
@@ -61,7 +61,7 @@ object Test {
| val x = "three"
| val y : String @Annot(x) = x
| y
- |} // x should be existentially bound""",
+ |} // x should not escape the local scope with a narrow type""",
"""def n(y: String) = {
| def m(x: String) : String @Annot(x) = {