Skip to content

Fix #4404: In LambdaLift, modify flags properly #4804

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

Merged
merged 1 commit into from
Jul 20, 2018
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/LambdaLift.scala
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,23 @@ object LambdaLift {
else (topClass, JavaStatic)
}
else (lOwner, EmptyFlags)
// Drop Module because class is no longer a singleton in the lifted context.
var initFlags = local.flags &~ Module | Private | Lifted | maybeStatic
if (local is Method) {
if (newOwner is Trait)
// Drop Final when a method is lifted into a trait.
// According to the JVM specification, a method declared inside interface cannot have the final flag.
// "Methods of interfaces may have any of the flags in Table 4.6-A set except ACC_PROTECTED, ACC_FINAL, ..."
// (https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6)
initFlags = initFlags &~ Final
else
// Add Final when a method is lifted into a class.
initFlags = initFlags | Final
}
local.copySymDenotation(
owner = newOwner,
name = newName(local),
initFlags = local.flags &~ Module &~ Final | Private | Lifted | maybeStatic,
// drop Module because class is no longer a singleton in the lifted context.
initFlags = initFlags,
info = liftedInfo(local)).installAfter(thisPhase)
}
for (local <- free.keys)
Expand Down
8 changes: 8 additions & 0 deletions tests/run/i4404a.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
false
false
false
true
false
true
true
true
19 changes: 19 additions & 0 deletions tests/run/i4404a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import java.lang.reflect.Modifier

class Car
final class Volvo extends Car

object Car {
val car = new Car {}
}

object Test {
def main(args: Array[String]) = {
List(new Car, new Volvo, Car, Car.car)
.map(_.getClass.getModifiers)
.foreach { m =>
println(Modifier.isPrivate(m))
println(Modifier.isFinal(m))
}
}
}
2 changes: 2 additions & 0 deletions tests/run/i4404b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
true
true
14 changes: 14 additions & 0 deletions tests/run/i4404b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import java.lang.reflect.Modifier

object Test {
val x = {
final class Foo
new Foo
}

def main(args: Array[String]) = {
val m = x.getClass.getModifiers
println(Modifier.isPrivate(m))
println(Modifier.isFinal(m))
}
}
2 changes: 2 additions & 0 deletions tests/run/i4404c.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
false
true
23 changes: 23 additions & 0 deletions tests/run/i4404c.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import java.lang.reflect.Modifier

trait T {
def f = {
def f0 = ()
}
}

class C {
def g = {
def g0 = ()
}
}

object Test {
def main(args: Array[String]) = {
List((new T {}).getClass.getInterfaces.head, (new C).getClass)
.map(_.getDeclaredMethods)
.foreach { ms =>
println(ms.exists(m => Modifier.isFinal(m.getModifiers)))
}
}
}