Skip to content

Add withErrorMessage and withFailureMessage to Parsers.Parser, #21

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

Closed
wants to merge 1 commit into from

Conversation

dcsobral
Copy link
Contributor

@dcsobral dcsobral commented Dec 2, 2011

which can be used to reliably override the default no success
messages.

which can be used to reliably override the default no success
messages.
@paulp paulp closed this Dec 2, 2011
gkossakowski added a commit to gkossakowski/scala that referenced this pull request Jan 11, 2012
Scala library rewritings tailored to GWT
retronym added a commit to retronym/scala that referenced this pull request Jan 19, 2013
rhs.substituteSymbols(old, new) leaves us with:

    def loop#12225(x#12226: A#15491): scala#21.this.Unit#1615 =
      loop#12225(x#12226)

In which the TermSymbol x#12226 has a stale info, pointing at
the A#7274, the class type parameter, rather than A#15491,
the corresponding type parameter of the synthetic backing
method.

I've improved `TreeSymSubstituter` to substitute not
only `Tree#{tpe, symbol}`, but also `DefTree#sym.info`.

The `pos` test that triggered the new code path are
listed here: https://gist.github.com/4575687
retronym referenced this pull request in retronym/scala Jan 20, 2013
Find trees which have an info referring to an out-of-scope
type parameter, as could happen in cases on SI-6981,
in which tree transplanting did not substitute symbols
in symbol infos.

With the proposed fix for that bug reverted, and this
commit in place, one sees:

    ticket/6891 ~/code/scala2 ./build/quick/bin/scalac -uniqid -Ycheck:extmethods test/files/pos/t6891.scala
    [Now checking: extmethods]
    [check: extmethods] The info of tree @scala#21.annotation#1622.tailrec#2397 def loop#12389(x#12390: A#15658): Unit#1613 = loop#12389(x#12390) refers to a out-of-scope type parameter type A#7437
    [check: extmethods] The info of tree val x#12390: A#7437 = _ refers to a out-of-scope type parameter type A#7437
    [check: extmethods] The info of tree loop#12389(x#12390) refers to a out-of-scope type parameter type A#7437
    [check: extmethods] The info of tree loop#12389 refers to a out-of-scope type parameter type A#7437
    [check: extmethods] The info of tree x#12390 refers to a out-of-scope type parameter type A#7437
    [check: extmethods] The info of tree <synthetic> val x2#15642: O#7027.Foo#7436[A#7437] = (x1#15641.asInstanceOf#4726[O#7027.Foo#7436[A#15676]]: O#7027.Foo#7436[A#15676]) refers to a out-of-scope type parameter type A#7437
    [check: extmethods] The info of tree <synthetic> val Foo$1#12663: O#7027.Foo#7436[A#7437] = x$1#15678.asInstanceOf#4726[O#7027.Foo#7436[A#15676]] refers to a out-of-scope type parameter type A#7437
    [check: extmethods] The info of tree Foo$1#12663 refers to a out-of-scope type parameter type A#7437

TODO
  - extend this to find references to out-of-scope method
    parameters, etc.
  - look for more direct errors in the symbol of a RefTree
retronym added a commit to retronym/scala that referenced this pull request Jan 26, 2013
rhs.substituteSymbols(old, new) leaves us with:

    def loop#12225(x#12226: A#15491): scala#21.this.Unit#1615 =
      loop#12225(x#12226)

In which the TermSymbol x#12226 has a stale info, pointing at
the A#7274, the class type parameter, rather than A#15491,
the corresponding type parameter of the synthetic backing
method.

I've improved `TreeSymSubstituter` to substitute not
only `Tree#{tpe, symbol}`, but also `DefTree#sym.info`.

The `pos` test that triggered the new code path are
listed here: https://gist.github.com/4575687

AFAICS, no special treatment of Function, Return, or Import
is needed in TreeSymSubstutor.
retronym added a commit to retronym/scala that referenced this pull request May 30, 2013
In:

    def foo = { object O { class C }; new O.C }

The inferred return type of can't refer to the local
symbols; they must not leak out of the compilation unit.

Instead, `packSymbols` is used to choose a less precise
existential type, `(AnyRef { type C <: AnyRef })#C)`.

This is implemented as a `TypeMap`, which is supposed to
takes care of rebinding `C` to something valid in the new
prefix (`(AnyRef { type C <: AnyRef })`).

If `C` was orginally a type alias, and the original
prefix was a refinement type, this was handled in
`AliasTypeRef#coevolveSym`, which looks for a type
in the new prefix with the name `C`. But for other
type refs (e.g. a class type ref, as in this case),
a no-op `coevolveSym` was used, deferring the rebinding
of abstract classes until `typeRef`.

But our case falls between the cracks, and we end up
propagating a type ref in which the prefix does not
contain the member.

With the help of `-uniqid`, this is clear:

    <method> def foo#7445(): scala#21.this.AnyRef#2222{type Bar#12153 <: scala#21.this.AnyRef#2222}#Bar#12125

Notice the reference to symbol `#12125`, rather than `#12153`.

This commit moves the `coevolveSym` logic up to `TypeRef`,
generalizing it to work for any `pre1`. This example answered
the question in that code:

> // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre?
retronym added a commit to retronym/scala that referenced this pull request May 31, 2013
In:

    def foo = { object O { class C }; new O.C }

The inferred return type of can't refer to the local
symbols; they must not leak out of the compilation unit.

Instead, `packSymbols` is used to choose a less precise
existential type, `(AnyRef { type C <: AnyRef })#C)`.

This is implemented as a `TypeMap`, which is supposed to
takes care of rebinding `C` to something valid in the new
prefix (`(AnyRef { type C <: AnyRef })`).

If `C` was orginally a type alias, and the original
prefix was a refinement type, this was handled in
`AliasTypeRef#coevolveSym`, which looks for a type
in the new prefix with the name `C`. But for other
type refs (e.g. a class type ref, as in this case),
a no-op `coevolveSym` was used, deferring the rebinding
of abstract classes until `typeRef`.

But our case falls between the cracks, and we end up
propagating a type ref in which the prefix does not
contain the member.

With the help of `-uniqid`, this is clear:

    <method> def foo#7445(): scala#21.this.AnyRef#2222{type Bar#12153 <: scala#21.this.AnyRef#2222}#Bar#12125

Notice the reference to symbol `#12125`, rather than `#12153`.

This commit moves the `coevolveSym` logic up to `TypeRef`,
generalizing it to work for any `pre1`. This example answered
the question in that code:

> // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre?
retronym added a commit to retronym/scala that referenced this pull request Sep 25, 2013
In:

    def foo = { object O { class C }; new O.C }

The inferred return type of can't refer to the local
symbols; they must not leak out of the compilation unit.

Instead, `packSymbols` is used to choose a less precise
existential type, `(AnyRef { type C <: AnyRef })#C)`.

This is implemented as a `TypeMap`, which is supposed to
takes care of rebinding `C` to something valid in the new
prefix (`(AnyRef { type C <: AnyRef })`).

If `C` was orginally a type alias, and the original
prefix was a refinement type, this was handled in
`AliasTypeRef#coevolveSym`, which looks for a type
in the new prefix with the name `C`. But for other
type refs (e.g. a class type ref, as in this case),
a no-op `coevolveSym` was used, deferring the rebinding
of abstract classes until `typeRef`.

But our case falls between the cracks, and we end up
propagating a type ref in which the prefix does not
contain the member.

With the help of `-uniqid`, this is clear:

    <method> def foo#7445(): scala#21.this.AnyRef#2222{type Bar#12153 <: scala#21.this.AnyRef#2222}#Bar#12125

Notice the reference to symbol `#12125`, rather than `#12153`.

This commit moves the `coevolveSym` logic up to `TypeRef`,
generalizing it to work for any `pre1`. This example answered
the question in that code:

> // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre?

Note: The first attempt at the commit failed to bootstrap GenSeqLike,
for reasons mimimized in pos/t6493b.scala. In AliasTypeRef it was
sufficient to look at `decls` to find the corresponding member, but
in other cases we need to do a member lookup.
retronym referenced this pull request in retronym/scala May 19, 2015
See also: https://github.com/retronym/indy-structural

```
qscalac -target:jvm-1.8 -Ybackend:GenBCode sandbox/structural.scala && qscala Test && javap -v 'Test$' | cat -v
warning: there was one feature warning; re-run with -feature for details
one warning found

QUACK! A
QUICK! A

Classfile /Users/jason/code/scala2/Test$.class
{
  public static final Test$ MODULE$;
    descriptor: LTest$;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL

  public void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=2, args_size=2
         0: getstatic     #19                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
         3: aload_0
         4: new           #21                 // class C
         7: dup
         8: invokespecial #22                 // Method C."<init>":()V
        11: invokevirtual #26                 // Method duckduck:(Ljava/lang/Object;)Ljava/lang/String;
        14: invokevirtual #30                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
        17: getstatic     #19                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
        20: aload_0
        21: new           #32                 // class D
        24: dup
        25: invokespecial #33                 // Method D."<init>":()V
        28: invokevirtual #26                 // Method duckduck:(Ljava/lang/Object;)Ljava/lang/String;
        31: invokevirtual #30                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
        34: return

  public java.lang.String duckduck(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_1
         1: ldc           #38                 // String A
         3: invokedynamic #49,  0             // InvokeDynamic #0:"dyn:callMethod:quack":(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;
         8: checkcast     #51                 // class java/lang/String
        11: areturn

}
BootstrapMethods:
  0: #45 invokestatic jdk/internal/dynalink/DefaultBootstrapper.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:

```
retronym referenced this pull request in retronym/scala May 19, 2015
See also: https://github.com/retronym/indy-structural

```
// sandbox/structural.scala
object Test {
  def main(args: Array[String]): Unit = {
    println(duckduck(new C))
    println(duckduck(new D))
  }

  def duckduck(a: { def quack(a: String): String }): String = {
    a.quack("A")
  }

}

class C {
  def quack(a: String) = "QUACK! " + a
}

class D {
  def quack(a: String) = "QUICK! " + a
}
```

```
qscalac -target:jvm-1.8 -Ybackend:GenBCode sandbox/structural.scala && qscala Test && javap -v 'Test$' | cat -v
warning: there was one feature warning; re-run with -feature for details
one warning found

QUACK! A
QUICK! A

Classfile /Users/jason/code/scala2/Test$.class
{
  public static final Test$ MODULE$;
    descriptor: LTest$;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL

  public void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=2, args_size=2
         0: getstatic     #19                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
         3: aload_0
         4: new           #21                 // class C
         7: dup
         8: invokespecial #22                 // Method C."<init>":()V
        11: invokevirtual #26                 // Method duckduck:(Ljava/lang/Object;)Ljava/lang/String;
        14: invokevirtual #30                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
        17: getstatic     #19                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
        20: aload_0
        21: new           #32                 // class D
        24: dup
        25: invokespecial #33                 // Method D."<init>":()V
        28: invokevirtual #26                 // Method duckduck:(Ljava/lang/Object;)Ljava/lang/String;
        31: invokevirtual #30                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
        34: return

  public java.lang.String duckduck(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_1
         1: ldc           #38                 // String A
         3: invokedynamic #49,  0             // InvokeDynamic #0:"dyn:callMethod:quack":(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;
         8: checkcast     #51                 // class java/lang/String
        11: areturn

}
BootstrapMethods:
  0: #45 invokestatic jdk/internal/dynalink/DefaultBootstrapper.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:

```
retronym referenced this pull request in retronym/scala May 19, 2015
See also: https://github.com/retronym/indy-structural

```
// sandbox/structural.scala
object Test {
  def main(args: Array[String]): Unit = {
    println(duckduck(new C))
    println(duckduck(new D))
  }

  def duckduck(a: { def quack(a: String): String }): String = {
    a.quack("A")
  }

}

class C {
  def quack(a: String) = "QUACK! " + a
}

class D {
  def quack(a: String) = "QUICK! " + a
}
```

```
qscalac -target:jvm-1.8 -Ybackend:GenBCode sandbox/structural.scala && qscala Test && javap -v 'Test$' | cat -v
warning: there was one feature warning; re-run with -feature for details
one warning found

QUACK! A
QUICK! A

Classfile /Users/jason/code/scala2/Test$.class
{
  public static final Test$ MODULE$;
    descriptor: LTest$;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL

  public void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=2, args_size=2
         0: getstatic     #19                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
         3: aload_0
         4: new           #21                 // class C
         7: dup
         8: invokespecial #22                 // Method C."<init>":()V
        11: invokevirtual #26                 // Method duckduck:(Ljava/lang/Object;)Ljava/lang/String;
        14: invokevirtual #30                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
        17: getstatic     #19                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
        20: aload_0
        21: new           #32                 // class D
        24: dup
        25: invokespecial #33                 // Method D."<init>":()V
        28: invokevirtual #26                 // Method duckduck:(Ljava/lang/Object;)Ljava/lang/String;
        31: invokevirtual #30                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
        34: return

  public java.lang.String duckduck(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_1
         1: ldc           #38                 // String A
         3: invokedynamic #49,  0             // InvokeDynamic #0:"dyn:callMethod:quack":(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;
         8: checkcast     #51                 // class java/lang/String
        11: areturn

}
BootstrapMethods:
  0: #45 invokestatic jdk/internal/dynalink/DefaultBootstrapper.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:

```
retronym referenced this pull request in retronym/scala Dec 2, 2015
```
⚡ cat sandbox/test.scala
trait T {
  def m = v
  val v = 42
}

class C extends T

object Test {
  def main(args: Array[String]): Unit = {
    assert(new C().m == 42)
  }
}
/code/scala on topic/nuke-impl-classes*
⚡ qscalac -Xprint:fields,constructors,erasure,mixin sandbox/test.scala  && qscala Test
[[syntax trees at end of                    fields]] // test.scala
package <empty> {
  abstract <sub_synth> trait T extends scala.AnyRef {
    <accessor> <sub_synth> def T$_setter_$v_=(x$1: Int): Unit;
    def /*T*/$init$(): Unit = {
      ()
    };
    def m: Int = T.this.v;
    <stable> <accessor> <sub_synth> def v: Int = 42
  };
  <sub_synth> class C extends AnyRef with T {
    override <stable> <accessor> def v: Int = C.this.v;
    private[this] val v: Int = _;
    override <accessor> def T$_setter_$v_=(x$1: Int): Unit = C.this.v = x$1;
    def <init>(): C = {
      C.super.<init>();
      ()
    }
  };
  object Test extends scala.AnyRef {
    def <init>(): Test.type = {
      Test.super.<init>();
      ()
    };
    def main(args: Array[String]): Unit = scala.Predef.assert(new C().m.==(42))
  }
}

[[syntax trees at end of                   erasure]] // test.scala
package <empty> {
  abstract <sub_synth> trait T extends Object {
    <accessor> <defaultmethod> <sub_synth> def T$_setter_$v_=(x$1: Int): Unit;
    def /*T*/$init$(): Unit = {
      ()
    };
    <defaultmethod> def m(): Int = T.this.v();
    <stable> <accessor> <defaultmethod> <sub_synth> def v(): Int = 42
  };
  <sub_synth> class C extends Object with T {
    override <stable> <accessor> def v(): Int = C.this.v;
    private[this] val v: Int = _;
    override <accessor> def T$_setter_$v_=(x$1: Int): Unit = C.this.v = x$1;
    def <init>(): C = {
      C.super.<init>();
      C.super./*T*/$init$();
      ()
    }
  };
  <sub_synth> object Test extends Object {
    def <init>(): Test.type = {
      Test.super.<init>();
      ()
    };
    def main(args: Array[String]): Unit = scala.Predef.assert(new C().m().==(42))
  }
}

[[syntax trees at end of              constructors]] // test.scala
package <empty> {
  abstract <sub_synth> trait T extends Object {
    <accessor> <defaultmethod> <sub_synth> def T$_setter_$v_=(x$1: Int): Unit;
    <defaultmethod> def m(): Int = T.this.v();
    <stable> <accessor> <defaultmethod> <sub_synth> def v(): Int;
    def /*T*/$init$(): Unit = {
      T.this.T$_setter_$v_=(42);
      ()
    }
  };
  <sub_synth> class C extends Object with T {
    override <stable> <accessor> def v(): Int = C.this.v;
    private[this] val v: Int = _;
    override <accessor> def T$_setter_$v_=(x$1: Int): Unit = C.this.v = x$1;
    def <init>(): C = {
      C.super.<init>();
      C.super./*T*/$init$();
      ()
    }
  };
  <sub_synth> object Test extends Object {
    def main(args: Array[String]): Unit = scala.Predef.assert(new C().m().==(42));
    def <init>(): Test.type = {
      Test.super.<init>();
      ()
    }
  }
}

[[syntax trees at end of                     mixin]] // test.scala: tree is unchanged since constructors
/code/scala on topic/nuke-impl-classes*
⚡ javap -c -classpath . T C
Compiled from "test.scala"
public interface T {
  public abstract void T$_setter_$v_$eq(int);

  public int m();
    Code:
       0: aload_0
       1: invokeinterface #15,  1           // InterfaceMethod v:()I
       6: ireturn

  public abstract int v();

  public void $init$();
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface #21,  2           // InterfaceMethod T$_setter_$v_$eq:(I)V
       8: return
}
Compiled from "test.scala"
public class C implements T {
  public int v();
    Code:
       0: aload_0
       1: getfield      #15                 // Field v:I
       4: ireturn

  public void T$_setter_$v_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #15                 // Field v:I
       5: return

  public C();
    Code:
       0: aload_0
       1: invokespecial #24                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: invokespecial #27                 // Method T.$init$:()V
       8: return
}
```
lrytz pushed a commit to lrytz/scala that referenced this pull request May 20, 2016
This corrects an error in the change to the trait encoding
in scala#5003: getters in traits should have empty bodies and
be emitted as abstract.

```
% ~/scala/2.12.0-M4/bin/scalac sandbox/test.scala && javap -c T
Compiled from "test.scala"
public interface T {
  public abstract void T$_setter_$x_$eq(int);

  public int x();
    Code:
       0: aload_0
       1: invokeinterface scala#15,  1           // InterfaceMethod x:()I
       6: ireturn

  public int y();
    Code:
       0: aload_0
       1: invokeinterface scala#20,  1           // InterfaceMethod y:()I
       6: ireturn

  public void y_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokeinterface scala#24,  2           // InterfaceMethod y_$eq:(I)V
       7: return

  public void $init$();
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface scala#29,  2           // InterfaceMethod T$_setter_$x_$eq:(I)V
       8: aload_0
       9: bipush        24
      11: invokeinterface scala#24,  2           // InterfaceMethod y_$eq:(I)V
      16: return
}

% qscalac sandbox/test.scala && javap -c T
Compiled from "test.scala"
public interface T {
  public abstract void T$_setter_$x_$eq(int);

  public abstract int x();

  public abstract int y();

  public abstract void y_$eq(int);

  public static void $init$(T);
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface scala#21,  2           // InterfaceMethod T$_setter_$x_$eq:(I)V
       8: aload_0
       9: bipush        24
      11: invokeinterface scala#23,  2           // InterfaceMethod y_$eq:(I)V
      16: return

  public void $init$();
    Code:
       0: aload_0
       1: invokestatic  scala#27                 // Method $init$:(LT;)V
       4: return
}
```
lrytz pushed a commit to lrytz/scala that referenced this pull request May 25, 2016
This corrects an error in the change to the trait encoding
in scala#5003: getters in traits should have empty bodies and
be emitted as abstract.

```
% ~/scala/2.12.0-M4/bin/scalac sandbox/test.scala && javap -c T
Compiled from "test.scala"
public interface T {
  public abstract void T$_setter_$x_$eq(int);

  public int x();
    Code:
       0: aload_0
       1: invokeinterface scala#15,  1           // InterfaceMethod x:()I
       6: ireturn

  public int y();
    Code:
       0: aload_0
       1: invokeinterface scala#20,  1           // InterfaceMethod y:()I
       6: ireturn

  public void y_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokeinterface scala#24,  2           // InterfaceMethod y_$eq:(I)V
       7: return

  public void $init$();
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface scala#29,  2           // InterfaceMethod T$_setter_$x_$eq:(I)V
       8: aload_0
       9: bipush        24
      11: invokeinterface scala#24,  2           // InterfaceMethod y_$eq:(I)V
      16: return
}

% qscalac sandbox/test.scala && javap -c T
Compiled from "test.scala"
public interface T {
  public abstract void T$_setter_$x_$eq(int);

  public abstract int x();

  public abstract int y();

  public abstract void y_$eq(int);

  public static void $init$(T);
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface scala#21,  2           // InterfaceMethod T$_setter_$x_$eq:(I)V
       8: aload_0
       9: bipush        24
      11: invokeinterface scala#23,  2           // InterfaceMethod y_$eq:(I)V
      16: return

  public void $init$();
    Code:
       0: aload_0
       1: invokestatic  scala#27                 // Method $init$:(LT;)V
       4: return
}
```
lrytz pushed a commit to lrytz/scala that referenced this pull request Jun 6, 2016
This corrects an error in the change to the trait encoding
in scala#5003: getters in traits should have empty bodies and
be emitted as abstract.

```
% ~/scala/2.12.0-M4/bin/scalac sandbox/test.scala && javap -c T
Compiled from "test.scala"
public interface T {
  public abstract void T$_setter_$x_$eq(int);

  public int x();
    Code:
       0: aload_0
       1: invokeinterface scala#15,  1           // InterfaceMethod x:()I
       6: ireturn

  public int y();
    Code:
       0: aload_0
       1: invokeinterface scala#20,  1           // InterfaceMethod y:()I
       6: ireturn

  public void y_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokeinterface scala#24,  2           // InterfaceMethod y_$eq:(I)V
       7: return

  public void $init$();
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface scala#29,  2           // InterfaceMethod T$_setter_$x_$eq:(I)V
       8: aload_0
       9: bipush        24
      11: invokeinterface scala#24,  2           // InterfaceMethod y_$eq:(I)V
      16: return
}

% qscalac sandbox/test.scala && javap -c T
Compiled from "test.scala"
public interface T {
  public abstract void T$_setter_$x_$eq(int);

  public abstract int x();

  public abstract int y();

  public abstract void y_$eq(int);

  public static void $init$(T);
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface scala#21,  2           // InterfaceMethod T$_setter_$x_$eq:(I)V
       8: aload_0
       9: bipush        24
      11: invokeinterface scala#23,  2           // InterfaceMethod y_$eq:(I)V
      16: return

  public void $init$();
    Code:
       0: aload_0
       1: invokestatic  scala#27                 // Method $init$:(LT;)V
       4: return
}
```
lrytz pushed a commit that referenced this pull request Jun 29, 2016
This corrects an error in the change to the trait encoding
in #5003: getters in traits should have empty bodies and
be emitted as abstract.

```
% ~/scala/2.12.0-M4/bin/scalac sandbox/test.scala && javap -c T
Compiled from "test.scala"
public interface T {
  public abstract void T$_setter_$x_$eq(int);

  public int x();
    Code:
       0: aload_0
       1: invokeinterface #15,  1           // InterfaceMethod x:()I
       6: ireturn

  public int y();
    Code:
       0: aload_0
       1: invokeinterface #20,  1           // InterfaceMethod y:()I
       6: ireturn

  public void y_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokeinterface #24,  2           // InterfaceMethod y_$eq:(I)V
       7: return

  public void $init$();
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface #29,  2           // InterfaceMethod T$_setter_$x_$eq:(I)V
       8: aload_0
       9: bipush        24
      11: invokeinterface #24,  2           // InterfaceMethod y_$eq:(I)V
      16: return
}

% qscalac sandbox/test.scala && javap -c T
Compiled from "test.scala"
public interface T {
  public abstract void T$_setter_$x_$eq(int);

  public abstract int x();

  public abstract int y();

  public abstract void y_$eq(int);

  public static void $init$(T);
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface #21,  2           // InterfaceMethod T$_setter_$x_$eq:(I)V
       8: aload_0
       9: bipush        24
      11: invokeinterface #23,  2           // InterfaceMethod y_$eq:(I)V
      16: return

  public void $init$();
    Code:
       0: aload_0
       1: invokestatic  #27                 // Method $init$:(LT;)V
       4: return
}
```
adriaanm pushed a commit that referenced this pull request Aug 22, 2016
Top level modules in Scala currently desugar as:

```
class C; object O extends C { toString }
```

```
public final class O$ extends C {
  public static final O$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class O$
       3: invokespecial #12                 // Method "<init>":()V
       6: return

  private O$();
    Code:
       0: aload_0
       1: invokespecial #13                 // Method C."<init>":()V
       4: aload_0
       5: putstatic     #15                 // Field MODULE$:LO$;
       8: aload_0
       9: invokevirtual #21                 // Method java/lang/Object.toString:()Ljava/lang/String;
      12: pop
      13: return
}
```

The static initalizer `<clinit>` calls the constructor `<init>`, which
invokes superclass constructor, assigns `MODULE$= this`, and then runs
the remainder of the object's constructor (`toString` in the example
above.)

It turns out that this relies on a bug in the JVM's verifier: assignment to a
static final must occur lexically within the <clinit>, not from within `<init>`
(even if the latter is happens to be called by the former).

I'd like to move the assignment to <clinit> but that would
change behaviour of "benign" cyclic references between modules.

Example:

```
package p1; class CC { def foo = O.bar}; object O {new CC().foo; def bar = println(1)};

// Exiting paste mode, now interpreting.

scala> p1.O
1
```

This relies on the way that we assign MODULE$ field after the super class constructors
are finished, but before the rest of the module constructor is called.

Instead, this commit removes the ACC_FINAL bit from the field. It actually wasn't
behaving as final at all, precisely the issue that the stricter verifier
now alerts us to.

```
scala> :paste -raw
// Entering paste mode (ctrl-D to finish)

package p1; object O

// Exiting paste mode, now interpreting.

scala> val O1 = p1.O
O1: p1.O.type = p1.O$@ee7d9f1

scala> scala.reflect.ensureAccessible(p1.O.getClass.getDeclaredConstructor()).newInstance()
res0: p1.O.type = p1.O$@64cee07

scala> O1 eq p1.O
res1: Boolean = false
```

We will still achieve safe publication of the assignment to other threads
by virtue of the fact that `<clinit>` is executed within the scope of
an initlization lock, as specified by:

  https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.5

Fixes scala/scala-dev#SD-194
adriaanm pushed a commit that referenced this pull request May 25, 2017
Non local returns aren't eliminated after inlined in 2.11 or 2.12

```
⚡ scala
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_112).
Type in expressions for evaluation. Or try :help.

scala> @inlune def foo(a: => Any) = if ("".isEmpty) a else ""
<console>:11: error: not found: type inlune
       @inlune def foo(a: => Any) = if ("".isEmpty) a else ""
        ^

scala> @inline def foo(a: => Any) = if ("".isEmpty) a else ""
foo: (a: => Any)Any

scala> class InlineReturn { def test: Any = foo(return "") }
defined class InlineReturn

scala> :javap -c InlineReturn#test
  public java.lang.Object test();
    Code:
       0: new           #4                  // class java/lang/Object
       3: dup
       4: invokespecial #32                 // Method java/lang/Object."<init>":()V
       7: astore_1
       8: getstatic     #36                 // Field $line4/$read$$iw$$iw$.MODULE$:L$line4/$read$$iw$$iw$;
      11: aload_1
      12: invokedynamic #59,  0             // InvokeDynamic #0:apply:(Ljava/lang/Object;)Lscala/Function0;
      17: invokevirtual #63                 // Method $line4/$read$$iw$$iw$.foo:(Lscala/Function0;)Ljava/lang/Object;
      20: goto          44
      23: astore_2
      24: aload_2
      25: invokevirtual #66                 // Method scala/runtime/NonLocalReturnControl.key:()Ljava/lang/Object;
      28: aload_1
      29: if_acmpne     39
      32: aload_2
      33: invokevirtual #69                 // Method scala/runtime/NonLocalReturnControl.value:()Ljava/lang/Object;
      36: goto          41
      39: aload_2
      40: athrow
      41: goto          44
      44: areturn
    Exception table:
       from    to  target type
           8    20    23   Class scala/runtime/NonLocalReturnControl
```

```
⚡ ~/scala/2.11.8/bin/scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_112).
Type in expressions for evaluation. Or try :help.

scala> @inline def foo(a: => Any) = if ("".isEmpty) a else ""
foo: (a: => Any)Any

scala> class InlineReturn { def test: Any = foo(return "") }
defined class InlineReturn

scala> :javap -c InlineReturn#test
  public java.lang.Object test();
    Code:
       0: new           #4                  // class java/lang/Object
       3: dup
       4: invokespecial #13                 // Method java/lang/Object."<init>":()V
       7: astore_1
       8: getstatic     #19                 // Field .MODULE$:L;
      11: new           #21                 // class InlineReturn$$anonfun$test$1
      14: dup
      15: aload_0
      16: aload_1
      17: invokespecial #24                 // Method InlineReturn$$anonfun$test$1."<init>":(LInlineReturn;Ljava/lang/Object;)V
      20: invokevirtual #28                 // Method .foo:(Lscala/Function0;)Ljava/lang/Object;
      23: goto          39
      26: astore_2
      27: aload_2
      28: invokevirtual #31                 // Method scala/runtime/NonLocalReturnControl.key:()Ljava/lang/Object;
      31: aload_1
      32: if_acmpne     40
      35: aload_2
      36: invokevirtual #34                 // Method scala/runtime/NonLocalReturnControl.value:()Ljava/lang/Object;
      39: areturn
      40: aload_2
      41: athrow
    Exception table:
       from    to  target type
           8    26    26   Class scala/runtime/NonLocalReturnControl

scala> :quit
```
OlivierBlanvillain pushed a commit to OlivierBlanvillain/scala that referenced this pull request Jun 27, 2017
SethTisue pushed a commit that referenced this pull request Aug 16, 2018
Before:

```
scala> trait T { val foo = 24 }; class C extends T
defined trait T
defined class C

scala> :javap -private -c C
Compiled from "<console>"
public class $line3.$read$$iw$$iw$C implements $line3.$read$$iw$$iw$T {
  private final int foo;

  public int foo();
    Code:
       0: aload_0
       1: getfield      #21                 // Field foo:I
       4: ireturn

  public void $line3$$read$$iw$$iw$T$_setter_$foo_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #21                 // Field foo:I
       5: return

  public $line3.$read$$iw$$iw$C();
    Code:
       0: aload_0
       1: invokespecial #30                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: invokestatic  #34                 // InterfaceMethod $line3/$read$$iw$$iw$T.$init$:(L$line3/$read$$iw$$iw$T;)V
       8: return
}
```

The assignment to the final field `foo` has always contravened the JVM spec,
and this rule is enforced for any classfiles of format 53 and higher.

After this patch:

```
scala> trait T { val foo = 24 }; class C extends T
defined trait T
defined class C

scala> :javap -private -c C
Compiled from "<console>"
public class $line3.$read$$iw$$iw$C implements $line3.$read$$iw$$iw$T {
  private int foo;

  public int foo();
    Code:
       0: aload_0
       1: getfield      #21                 // Field foo:I
       4: ireturn

  public void $line3$$read$$iw$$iw$T$_setter_$foo_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #21                 // Field foo:I
       5: return

  public $line3.$read$$iw$$iw$C();
    Code:
       0: aload_0
       1: invokespecial #30                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: invokestatic  #34                 // InterfaceMethod $line3/$read$$iw$$iw$T.$init$:(L$line3/$read$$iw$$iw$T;)V
       8: getstatic     #40                 // Field scala/runtime/ScalaRunTime$.MODULE$:Lscala/runtime/ScalaRunTime$;
      11: invokevirtual #43                 // Method scala/runtime/ScalaRunTime$.releaseFence:()V
      14: return
}
```
da-liii pushed a commit to da-liii/scala that referenced this pull request Nov 11, 2018
Update Kate from 14.11.97 (unstable) to 14.12.2 (stable)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants