summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-02-22 10:44:48 +0100
committerJason Zaugg <jzaugg@gmail.com>2014-02-22 11:13:50 +0100
commit5dfcf5eb6a2fea69327420a3ebc4792f9365bf5a (patch)
tree4579d84e6063552cea02f4f7a09b02d74ceaef92
parent00624a39ed84c3fd245dd9df7454d4cec4399e13 (diff)
downloadscala-5dfcf5eb6a2fea69327420a3ebc4792f9365bf5a.tar.gz
scala-5dfcf5eb6a2fea69327420a3ebc4792f9365bf5a.tar.bz2
scala-5dfcf5eb6a2fea69327420a3ebc4792f9365bf5a.zip
SI-8324 Fix regression in override checks for sealed classes
adeffda25 changed `Symbol#isEffectivelyFinal` to help the optimizer by inferring finality within sealed class hierarchies. However, this change wasn't neccesarily welcome for other clients of that method. In the enclosed test case, we see that overriding checks in `RefChecks` regressed. This commit moves the enhanced version into a new method and selectively uses it in the optimizer (and the tail call optimizer).
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala14
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Checkable.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala3
-rw-r--r--test/files/pos/t8234.scala16
7 files changed, 30 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
index 2e44c405cf..676ee12683 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala
@@ -415,7 +415,7 @@ abstract class TypeFlowAnalysis {
}
val concreteMethod = inliner.lookupImplFor(msym, receiver)
val isCandidate = {
- ( inliner.isClosureClass(receiver) || concreteMethod.isEffectivelyFinal || receiver.isEffectivelyFinal ) &&
+ ( inliner.isClosureClass(receiver) || concreteMethod.isEffectivelyFinalOrNotOverridden || receiver.isEffectivelyFinalOrNotOverridden ) &&
!blackballed(concreteMethod)
}
if(isCandidate) {
@@ -501,7 +501,7 @@ abstract class TypeFlowAnalysis {
}
private def isReceiverKnown(cm: opcodes.CALL_METHOD): Boolean = {
- cm.method.isEffectivelyFinal && cm.method.owner.isEffectivelyFinal
+ cm.method.isEffectivelyFinalOrNotOverridden && cm.method.owner.isEffectivelyFinalOrNotOverridden
}
private def putOnRadar(blocks: Traversable[BasicBlock]) {
diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
index 0f317422ac..e70c558db0 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
@@ -431,7 +431,7 @@ abstract class DeadCodeElimination extends SubComponent {
}
private def isPure(sym: Symbol) = (
- (sym.isGetter && sym.isEffectivelyFinal && !sym.isLazy)
+ (sym.isGetter && sym.isEffectivelyFinalOrNotOverridden && !sym.isLazy)
|| (sym.isPrimaryConstructor && (sym.enclosingPackage == RuntimePackage || inliner.isClosureClass(sym.owner)))
)
/** Is 'sym' a side-effecting method? TODO: proper analysis. */
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index fa424584b2..f6de522d09 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -72,8 +72,8 @@ abstract class Inliners extends SubComponent {
def needsLookup = (
(clazz != NoSymbol)
&& (clazz != sym.owner)
- && !sym.isEffectivelyFinal
- && clazz.isEffectivelyFinal
+ && !sym.isEffectivelyFinalOrNotOverridden
+ && clazz.isEffectivelyFinalOrNotOverridden
)
def lookup(clazz: Symbol): Symbol = {
// println("\t\tlooking up " + meth + " in " + clazz.fullName + " meth.owner = " + meth.owner)
@@ -362,7 +362,7 @@ abstract class Inliners extends SubComponent {
for(x <- inputBlocks; easyCake = callsites(x); if easyCake.nonEmpty) {
breakable {
for(ocm <- easyCake) {
- assert(ocm.method.isEffectivelyFinal && ocm.method.owner.isEffectivelyFinal)
+ assert(ocm.method.isEffectivelyFinalOrNotOverridden && ocm.method.owner.isEffectivelyFinalOrNotOverridden)
if(analyzeInc(ocm, x, ocm.method.owner, -1, ocm.method)) {
inlineCount += 1
break()
@@ -409,8 +409,8 @@ abstract class Inliners extends SubComponent {
def isCandidate = (
isClosureClass(receiver)
- || concreteMethod.isEffectivelyFinal
- || receiver.isEffectivelyFinal
+ || concreteMethod.isEffectivelyFinalOrNotOverridden
+ || receiver.isEffectivelyFinalOrNotOverridden
)
def isApply = concreteMethod.name == nme.apply
@@ -425,7 +425,7 @@ abstract class Inliners extends SubComponent {
debuglog("Treating " + i
+ "\n\treceiver: " + receiver
+ "\n\ticodes.available: " + isAvailable
- + "\n\tconcreteMethod.isEffectivelyFinal: " + concreteMethod.isEffectivelyFinal)
+ + "\n\tconcreteMethod.isEffectivelyFinalOrNotOverridden: " + concreteMethod.isEffectivelyFinalOrNotOverridden)
if (!isCandidate) warnNoInline("it can be overridden")
else if (!isAvailable) warnNoInline("bytecode unavailable")
@@ -592,7 +592,7 @@ abstract class Inliners extends SubComponent {
/** Should method 'sym' being called in 'receiver' be loaded from disk? */
def shouldLoadImplFor(sym: Symbol, receiver: Symbol): Boolean = {
def alwaysLoad = (receiver.enclosingPackage == RuntimePackage) || (receiver == PredefModule.moduleClass)
- def loadCondition = sym.isEffectivelyFinal && isMonadicMethod(sym) && isHigherOrderMethod(sym)
+ def loadCondition = sym.isEffectivelyFinalOrNotOverridden && isMonadicMethod(sym) && isHigherOrderMethod(sym)
val res = hasInline(sym) || alwaysLoad || loadCondition
debuglog("shouldLoadImplFor: " + receiver + "." + sym + ": " + res)
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index 5973c70583..714f189ead 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -116,7 +116,7 @@ abstract class TailCalls extends Transform {
def tailLabels: Set[Symbol]
def enclosingType = method.enclClass.typeOfThis
- def isEligible = method.isEffectivelyFinal
+ def isEligible = method.isEffectivelyFinalOrNotOverridden
def isMandatory = method.hasAnnotation(TailrecClass)
def isTransformed = isEligible && accessed(label)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala
index b899cd8994..13884404b3 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala
@@ -203,7 +203,7 @@ trait Checkable {
private def isSealedOrFinal(sym: Symbol) = sym.isSealed || sym.isFinal
private def isEffectivelyFinal(sym: Symbol): Boolean = (
// initialization important
- sym.initialize.isEffectivelyFinal || (
+ sym.initialize.isEffectivelyFinalOrNotOverridden || (
settings.future && isTupleSymbol(sym) // SI-7294 step into the future and treat TupleN as final.
)
)
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 83c2e2acdb..03d8f97831 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -943,9 +943,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
|| isTerm && (
isPrivate
|| isLocalToBlock
- || isNotOverridden
)
)
+ /** Is this symbol effectively final or a concrete term member of sealed class whose childred do not override it */
+ final def isEffectivelyFinalOrNotOverridden: Boolean = isEffectivelyFinal || (isTerm && !isDeferred && isNotOverridden)
/** Is this symbol owned by a package? */
final def isTopLevel = owner.isPackageClass
diff --git a/test/files/pos/t8234.scala b/test/files/pos/t8234.scala
new file mode 100644
index 0000000000..2cb1562326
--- /dev/null
+++ b/test/files/pos/t8234.scala
@@ -0,0 +1,16 @@
+package p1
+
+private abstract class ProjectDef(val autoPlugins: Any) extends ProjectDefinition
+sealed trait ResolvedProject extends ProjectDefinition {
+ def autoPlugins: Any
+}
+
+sealed trait ProjectDefinition {
+ private[p1] def autoPlugins: Any
+}
+
+
+object Test {
+ // was "error: value autoPlugins in class ProjectDef of type Any cannot override final member"
+ new ProjectDef(null) with ResolvedProject
+}