scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

separate accessibility and lifting #7085

Open scabug opened 11 years ago

scabug commented 11 years ago

when java needs to give access to an inaccessible method, it doesn't change the method itself, but generates a synthetic static accessor that takes the same arguments, plus the this pointer for that method

this scheme makes it easier to stay binary compatible in the presence of changing access patterns, because it doesn't involve making private, non-synthetic, methods public when the need arises for them to be accessible from somewhere

as the static accessor is synthetic, it doesn't affect binary compatibility

This might give us a chance at fixing:

trait A {
  def foo: Long
}

object Main {
  def a(): A = new A {
    var foo: Long = 1000L

    val test = () => {
      foo = 28
    }
  }
  def main(args: Array[String]) {
    println(a().foo)
  }
}

which, as reported in #6387 (now marked as a duplicate), gives an AbstractMethodError

scabug commented 11 years ago

Imported From: https://issues.scala-lang.org/browse/SI-7085?orig=1 Reporter: @gkossakowski

scabug commented 11 years ago

@retronym said:

as the static accessor is synthetic, it doesn't affect binary compatibility

Could you elaborate on that point?

I thought that any method can be called from a different compilation unit affect BC. So the specific case of private (visible to the companion class) would be okay, as would private[enclObject], but private[enclPackage] or protected[anything] would not.

scabug commented 11 years ago

@adriaanm said: my understanding was that introducing new methods is fine as long as we don't let anyone call them, which would be the case since they're synthetic -- calls to them are only emitted by the compiler, and in this case I was thinking (but didn't specify, sorry) of lambdalifted methods that become visible when they start to be used from an under-privileged scope

scabug commented 11 years ago

@retronym said: One difference between Java and Scala that we have to consider is that we allow private access outside of the current compilation unit. So we have a few different scenarios wrt separate compilation. e.g. changing a member from public to private[pack] is currently binary compatible for call sites in that pack. (Admittedly, it is also BC for call sites outside of the package, so we have no runtime enforcement of access.)

% qbin/scalac sandbox/{A,B}.scala
% qbin/scalac sandbox/A-pack-private.scala
% qbin/scala p.Test
% qbin/scala

scala> :javap -public p.C
Compiled from "A-pack-private.scala"
public class p.C extends java.lang.Object{
    public int foo();
    public p.C();
}

If we compiled foo as private and provided an accessor, this would no longer be the case.

In addition, we would need to generate stable names for the accessors (rather than java's acesssNNN). But this could be done easily enough in the same manner as the current mangling.

So perhaps we need to consider the scheme used for package-qualified access separately from other cases.

Another tricky aspect of Java's approach to access is constructors. It creates 'access constructors' with an extra dummy parameter. The type of the parameter was used to uniquely distinguish the constructors, and was chosen to be the type of the inner class that needed to access the constructor.

scabug commented 10 years ago

@adriaanm said: see also #6387

scabug commented 9 years ago

Guillaume Martres (Smarter) said: Was this closed intentionally?

scabug commented 9 years ago

@retronym said: Nope, I think I mentioned it in a commit comment and JIRA thought I fixed it.