Skip to content

Commit

Permalink
Merge pull request #10629 from som-snytt/issue/9414-known-subclasses
Browse files Browse the repository at this point in the history
Infer more final to permit tailrec
  • Loading branch information
lrytz committed Dec 14, 2023
2 parents ed8005f + 8df9830 commit 61d31ab
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 6 deletions.
13 changes: 7 additions & 6 deletions src/reflect/scala/reflect/internal/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1025,12 +1025,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
)
/** Is this symbol effectively final or a concrete term member of sealed class whose children do not override it */
final def isEffectivelyFinalOrNotOverridden: Boolean = {
def isNotOverridden =
owner.isClass && (
owner.isEffectivelyFinal
|| owner.isSealed && owner.sealedChildren.forall(c => c.isEffectivelyFinal && overridingSymbol(c) == NoSymbol)
)
isEffectivelyFinal || isTerm && !isDeferred && isNotOverridden
def isNotOverriddenAt(c: Symbol, hasLocalOwner: Boolean): Boolean = {
def checkOverrideIn(sc: Symbol) = overridingSymbol(sc) == NoSymbol && isNotOverriddenAt(sc, hasLocalOwner || sc.originalOwner.isTerm)
c.isClass && (c.isEffectivelyFinal || {
(c.isSealed || hasLocalOwner) && c.children.forall(checkOverrideIn)
})
}
isEffectivelyFinal || isTerm && !isDeferred && isNotOverriddenAt(owner, owner.originalOwner.isTerm)
}

/** Is this symbol owned by a package? */
Expand Down
10 changes: 10 additions & 0 deletions test/files/neg/t9414.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
t9414.scala:6: error: could not optimize @tailrec annotated method bar: it is neither private nor final so can be overridden
@tailrec def bar: Int = {
^
t9414.scala:20: error: could not optimize @tailrec annotated method bar: it is neither private nor final so can be overridden
@tailrec def bar: Int = {
^
t9414.scala:34: error: could not optimize @tailrec annotated method bar: it is neither private nor final so can be overridden
@tailrec def bar: Int = {
^
3 errors
42 changes: 42 additions & 0 deletions test/files/neg/t9414.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import annotation._

class C {
def foo = {
class Parent {
@tailrec def bar: Int = {
println("here we go again")
bar
}
}
class Child extends Parent {
override def bar = 42
}
}
}

class D {
def foo = {
class Parent {
@tailrec def bar: Int = {
println("here we go again")
bar
}
}
class Child extends Parent
class GrandChild extends Child {
override def bar = 42
}
}
}

object E {
sealed class Parent {
@tailrec def bar: Int = {
println("here we go again")
bar
}
}
final class Child extends Parent {
override def bar = 42
}
}
78 changes: 78 additions & 0 deletions test/files/pos/t9414.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import annotation._

class C {
def foo = {
class Parent {
@tailrec def bar: Int = {
println("here we go again")
bar
}
}
class Child extends Parent {
def notBar = 42
}
}
}

class D {
def foo = {
class Parent {
@tailrec def bar: Int = {
println("here we go again")
bar
}
}
class Child extends Parent
class GrandChild extends Child {
def notBar = 42
}
}
}

object E {
sealed class Parent {
@tailrec def bar: Int = {
println("here we go again")
bar
}
}
final class Child extends Parent {
def notBar = 42
}
}

class F {
def foo = {
class Parent {
@tailrec def bar: Int = {
println("here we go again")
bar
}
}
class K {
class Child extends Parent {
def notBar = 42
}
class GrandChild extends Child {
def neitherBar = 42
}
}
}
}

class G {
sealed class Parent {
@tailrec def bar: Int = {
println("here we go again")
bar
}
}
def foo = {
class Child extends Parent {
def notBar = 42
}
class GrandChild extends Child {
def neitherBar = 42
}
}
}

0 comments on commit 61d31ab

Please sign in to comment.