summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-10-14 17:34:54 +0000
committerPaul Phillips <paulp@improving.org>2010-10-14 17:34:54 +0000
commit185700607dc2fd12cf47a61f583bdbafd726558b (patch)
treede5ce98a84176042276101368c07cd828625b334 /src
parent920449d6eeb0267f96b115a47866ccd53a5a3c55 (diff)
downloadscala-185700607dc2fd12cf47a61f583bdbafd726558b.tar.gz
scala-185700607dc2fd12cf47a61f583bdbafd726558b.tar.bz2
scala-185700607dc2fd12cf47a61f583bdbafd726558b.zip
Modification to the widening logic to treat loc...
Modification to the widening logic to treat locally defined symbols like final members thus allowing more constants to be inlined. Concretely, that means that in code like this: def f: Unit = { val b = false ; if (b) println("ok") } The call to println is no longer generated at all, and in this code: def f(x: Int) = { val X = 1 ; val Y = 2; x match { case X => 1 ; case Y => 2 } } A tableswitch is generated instead of the present if/then/else. I also added a big comment to the former widenIfNotFinal (now widenIfNecessary for obvious reasons.) Review by rytz.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala30
1 files changed, 24 insertions, 6 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)