Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize tail recursion on effectively final methods even when final keyword is absent #10629

Merged
merged 1 commit into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)
lrytz marked this conversation as resolved.
Show resolved Hide resolved
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
}
}
}