Skip to content

SI-7038 Deskolemize harder #3

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 2 commits into from
Closed

SI-7038 Deskolemize harder #3

wants to merge 2 commits into from

Conversation

retronym
Copy link
Owner

Inferred method return types can contain skolems for
the methods type parameters seen from within the method
body. Namer#typeSig deskolemized these, replacing the
skolems with the type parameter symbols.

This failed to deskolemize the underlying type of a
by a method-local type alias.

This commit changes deskolemizeMap to normalize types
along the way.

preview by @adriaanm, probably can wait for 2.10.2 though

To be remedied in the followup commit.
Inferred method return types can contain skolems for
the methods type parameters seen from within the method
body. `Namer#typeSig` deskolemized these, replacing the
skolems with the type parameter symbols.

This failed to deskolemize the underlying type of a
by a method-local type alias.

This commit changes deskolemizeMap to normalize types
along the way.
@retronym
Copy link
Owner Author

@retronym
Copy link
Owner Author

The test run shows unwanted dealiased types in signatures.

+  def copy[A <: scala.collection.Seq[scala.Int]](i : A, s : java.lang.String) : CaseClass[A] = { /* compiled code */ }
-  def copy[A <: scala.Seq[scala.Int]](i : A, s : scala.Predef.String) : CaseClass[A] = { /* compiled code */ }

@@ -41,6 +41,8 @@ trait ExistentialsAndSkolems {
def apply(tp: Type): Type = tp match {
case TypeRef(pre, sym, args) if sym.isTypeSkolem && (tparams contains sym.deSkolemize) =>
mapOver(typeRef(NoPrefix, sym.deSkolemize, args))
case TypeRef(pre, sym, args) if sym.isAliasType =>
mapOver(tp.normalize)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd dealias instead of normalize (and only if !(tp.dealias =:= tp) -- i.e., when arguments are supplied so that we don't have to eta-expand to a polytype)

otherwise, looks good

EDIT: I think tp.dealias match { ... } should work, no need for the case for alias types

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lukas's latest PR actually removed this custom TypeMap in favour of a straight restpe.substSyms(skolems, tparams). Which got me to thinking about how this version might be expressed in the same way; which other custom type maps could be expressed in the same way, etc.

What I'm thinking of is dealiasLocals(method, restpe).substSyms(skolems, tparams), where dealiasLocals would dealias any types aliases that are local to the method. Does that sound like a reasonable approach? How would I build such a thing?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the problem is sym.deSkolemize doesn't have an inverse, so you can't easily determine the skolems list
for sym in skolems. TR(pre, sym, as) -> TR(NoPrefix, sym.deSkolemize, args)
skolems = {sym | sym.deSkolemize in tparams}

the only way I can see to express this as a substitution is to

  • generalize the from/to arguments of the substitution to a function
  • or get a list of all symbols in the type to transform

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's what @lrytz is up to.

      /* tparams already have symbols (created in enterDefDef/completerOf), namely the skolemized ones (created
       * by the PolyTypeCompleter constructor, and assigned to tparams). reenterTypeParams enters the type skolems
       * into scope and returns the non-skolems.
        */

      val tparamSyms = typer.reenterTypeParams(tparams)
       val tparamSkolems = tparams.map(_.symbol)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that still goes from skolem to non-skolem
i don't know how to go from non-skolem to (original) skolem

@paulp
Copy link

paulp commented Jan 29, 2013

Indeed, please, please we must stop calling normalize without cause. For every new call to normalize, it should be shown why dealiasing does not suffice.

@paulp
Copy link

paulp commented Jan 29, 2013

For more on that point, see scala/scala#2013.

retronym pushed a commit that referenced this pull request Mar 5, 2013
First of all, GIL should only apply to runtime reflection, because noone
is going to run toolboxes in multiple threads: a) that's impossible, b/c
the compiler isn't thread safe, b) ToolBox api prevents that.

Secondly, the only things in symbols which require synchronization are:
1) info/validTo (completers aren't thread-safe),
2) rawInfo and its dependencies (it shares a mutable field with info)
3) non-trivial caches like in typeAsMemberOfLock

If you think about it, other things like sourceModule or associatedFile
don't need synchronization, because they are either set up when a symbol
is created or cloned or when it's completed. The former is obviously safe,
while the latter is safe as well, because before acquiring init-dependent
state of symbols, the compiler calls `initialize`, which is synchronized.

We can say that symbols can be in four possible states: 1) being created,
2) created, but not yet initialized, 3) initializing, 4) initialized.
in runtime reflection can undergo is init. #3 is dangerous and needs protection
retronym added a commit that referenced this pull request Jun 26, 2013
Swathes of important logic are duplicated between `findMember`
and `findMembers` after this run of optimization.

    d905558 Variation #10 to optimze findMember
    fcb0c01 Attempt #9 to opimize findMember.
    71d2ceb Attempt #8 to opimize findMember.
    77e5692 Attempty #7 to optimize findMember
    275115e Fixing problem that caused fingerprints to fail in reflection. Also fixed test case that failed when moving to findMember
    e94252e Attemmpt #6 to optimize findMember
    73e61b8 Attempt #5 to optimize findMember.
    04f0b65 Attempt #4 to optimize findMember
    0e3c70f Attempt #3 to optimize findMember
    41f4497 Attempt #2 to optimize findMember
    1a73aa0 Attempt #1 to optimize findMember

This commit updates `findMembers` with the bug fixes that `findMember`
has received, and adds flashing warning signs for future maintainers.

A followup commit will address the duplication at the root.
retronym pushed a commit that referenced this pull request Aug 6, 2013
First of all, GIL should only apply to runtime reflection, because noone
is going to run toolboxes in multiple threads: a) that's impossible, b/c
the compiler isn't thread safe, b) ToolBox api prevents that.

Secondly, the only things in symbols which require synchronization are:
1) info/validTo (completers aren't thread-safe),
2) rawInfo and its dependencies (it shares a mutable field with info)
3) non-trivial caches like in typeAsMemberOfLock

If you think about it, other things like sourceModule or associatedFile
don't need synchronization, because they are either set up when a symbol
is created or cloned or when it's completed. The former is obviously safe,
while the latter is safe as well, because before acquiring init-dependent
state of symbols, the compiler calls `initialize`, which is synchronized.

We can say that symbols can be in four possible states: 1) being created,
2) created, but not yet initialized, 3) initializing, 4) initialized.
in runtime reflection can undergo is init. #3 is dangerous and needs protection
retronym pushed a commit that referenced this pull request Aug 7, 2013
First of all, GIL should only apply to runtime reflection, because noone
is going to run toolboxes in multiple threads: a) that's impossible, b/c
the compiler isn't thread safe, b) ToolBox api prevents that.

Secondly, the only things in symbols which require synchronization are:
1) info/validTo (completers aren't thread-safe),
2) rawInfo and its dependencies (it shares a mutable field with info)
3) non-trivial caches like in typeAsMemberOfLock

If you think about it, other things like sourceModule or associatedFile
don't need synchronization, because they are either set up when a symbol
is created or cloned or when it's completed. The former is obviously safe,
while the latter is safe as well, because before acquiring init-dependent
state of symbols, the compiler calls `initialize`, which is synchronized.

We can say that symbols can be in four possible states: 1) being created,
2) created, but not yet initialized, 3) initializing, 4) initialized.
in runtime reflection can undergo is init. #3 is dangerous and needs protection
retronym pushed a commit that referenced this pull request Aug 9, 2013
First of all, GIL should only apply to runtime reflection, because noone
is going to run toolboxes in multiple threads: a) that's impossible, b/c
the compiler isn't thread safe, b) ToolBox api prevents that.

Secondly, the only things in symbols which require synchronization are:
1) info/validTo (completers aren't thread-safe),
2) rawInfo and its dependencies (it shares a mutable field with info)
3) non-trivial caches like in typeAsMemberOfLock

If you think about it, other things like sourceModule or associatedFile
don't need synchronization, because they are either set up when a symbol
is created or cloned or when it's completed. The former is obviously safe,
while the latter is safe as well, because before acquiring init-dependent
state of symbols, the compiler calls `initialize`, which is synchronized.

We can say that symbols can be in four possible states: 1) being created,
2) created, but not yet initialized, 3) initializing, 4) initialized.
Of those only #3 is dangerous and needs protection, which is what this
commit does.
retronym pushed a commit that referenced this pull request Oct 20, 2013
First of all, GIL should only apply to runtime reflection, because noone
is going to run toolboxes in multiple threads: a) that's impossible, b/c
the compiler isn't thread safe, b) ToolBox api prevents that.

Secondly, the only things in symbols which require synchronization are:
1) info/validTo (completers aren't thread-safe),
2) rawInfo and its dependencies (it shares a mutable field with info)
3) non-trivial caches like in typeAsMemberOfLock

If you think about it, other things like sourceModule or associatedFile
don't need synchronization, because they are either set up when a symbol
is created or cloned or when it's completed. The former is obviously safe,
while the latter is safe as well, because before acquiring init-dependent
state of symbols, the compiler calls `initialize`, which is synchronized.

We can say that symbols can be in four possible states: 1) being created,
2) created, but not yet initialized, 3) initializing, 4) initialized.
Of those only #3 is dangerous and needs protection, which is what this
commit does.
retronym pushed a commit that referenced this pull request Nov 14, 2013
When an application of a blackbox macro is used as an implicit candidate,
no expansion is performed until the macro is selected as the result of
the implicit search.

This makes it impossible to dynamically calculate availability of
implicit macros.
retronym added a commit that referenced this pull request Dec 12, 2013
Introduce Unliftable for Quasiquotes (take #3)
retronym added a commit that referenced this pull request Jan 29, 2014
Exclude them from superclasses in `findMember` and in
`OverridingPairs`.

The odd logic in `findMember` that considered whether the
selector class was owned by the owner of the candidate private
symbol dates back to 2007 (bff4268), but does not appear to
have any relationship to the spec.

Refinement types are still able to inherit private members from
all direct parents, as was needed in pos/t2399.scala. More tests
are included for this scenario.

In short, the logic now:

 - includes direct parents of refinements,
 - otherwise, excludes privates after the first class in the
   base class sequence

TODO: Swathes of important logic are duplicated between `findMember`
and `findMembers` after this run of optimization.

    d905558 Variation #10 to optimze findMember
    fcb0c01 Attempt #9 to opimize findMember.
    71d2ceb Attempt #8 to opimize findMember.
    77e5692 Attempty #7 to optimize findMember
    275115e Fixing problem that caused fingerprints to fail in reflection. Als
    e94252e Attemmpt #6 to optimize findMember
    73e61b8 Attempt #5 to optimize findMember.
    04f0b65 Attempt #4 to optimize findMember
    0e3c70f Attempt #3 to optimize findMember
    41f4497 Attempt #2 to optimize findMember
    1a73aa0 Attempt #1 to optimize findMember
retronym added a commit that referenced this pull request Jan 31, 2014
Swathes of important logic are duplicated between `findMember`
and `findMembers` after they separated on grounds of irreconcilable
differences about how fast they should run:

    d905558 Variation #10 to optimze findMember
    fcb0c01 Attempt #9 to opimize findMember.
    71d2ceb Attempt #8 to opimize findMember.
    77e5692 Attempty #7 to optimize findMember
    275115e Fixing problem that caused fingerprints to fail in
    e94252e Attemmpt #6 to optimize findMember
    73e61b8 Attempt #5 to optimize findMember.
    04f0b65 Attempt #4 to optimize findMember
    0e3c70f Attempt #3 to optimize findMember
    41f4497 Attempt #2 to optimize findMember
    1a73aa0 Attempt #1 to optimize findMember

This didn't actually bear fruit, and the intervening years have
seen the implementations drift.

Now is the time to reunite them under the banner of `FindMemberBase`.

Each has a separate subclass to customise the behaviour. This is
primarily used by `findMember` to cache member types and to assemble
the resulting list of symbols in an low-allocation manner.

While there I have introduced some polymorphic calls, the call sites
are only bi-morphic, and our typical pattern of compilation involves
far more `findMember` calls, so I expect that JIT will keep the
virtual call cost to an absolute minimum.

Test results have been updated now that `findMembers` correctly
excludes constructors and doesn't inherit privates.

Coming up next: we can actually fix SI-7475!
retronym added a commit that referenced this pull request Jan 31, 2014
Swathes of important logic are duplicated between `findMember`
and `findMembers` after they separated on grounds of irreconcilable
differences about how fast they should run:

    d905558 Variation #10 to optimze findMember
    fcb0c01 Attempt #9 to opimize findMember.
    71d2ceb Attempt #8 to opimize findMember.
    77e5692 Attempty #7 to optimize findMember
    275115e Fixing problem that caused fingerprints to fail in
    e94252e Attemmpt #6 to optimize findMember
    73e61b8 Attempt #5 to optimize findMember.
    04f0b65 Attempt #4 to optimize findMember
    0e3c70f Attempt #3 to optimize findMember
    41f4497 Attempt #2 to optimize findMember
    1a73aa0 Attempt #1 to optimize findMember

This didn't actually bear fruit, and the intervening years have
seen the implementations drift.

Now is the time to reunite them under the banner of `FindMemberBase`.

Each has a separate subclass to customise the behaviour. This is
primarily used by `findMember` to cache member types and to assemble
the resulting list of symbols in an low-allocation manner.

While there I have introduced some polymorphic calls, the call sites
are only bi-morphic, and our typical pattern of compilation involves
far more `findMember` calls, so I expect that JIT will keep the
virtual call cost to an absolute minimum.

Test results have been updated now that `findMembers` correctly
excludes constructors and doesn't inherit privates.

Coming up next: we can actually fix SI-7475!
retronym added a commit that referenced this pull request Jan 31, 2014
Swathes of important logic are duplicated between `findMember`
and `findMembers` after they separated on grounds of irreconcilable
differences about how fast they should run:

    d905558 Variation #10 to optimze findMember
    fcb0c01 Attempt #9 to opimize findMember.
    71d2ceb Attempt #8 to opimize findMember.
    77e5692 Attempty #7 to optimize findMember
    275115e Fixing problem that caused fingerprints to fail in
    e94252e Attemmpt #6 to optimize findMember
    73e61b8 Attempt #5 to optimize findMember.
    04f0b65 Attempt #4 to optimize findMember
    0e3c70f Attempt #3 to optimize findMember
    41f4497 Attempt #2 to optimize findMember
    1a73aa0 Attempt #1 to optimize findMember

This didn't actually bear fruit, and the intervening years have
seen the implementations drift.

Now is the time to reunite them under the banner of `FindMemberBase`.

Each has a separate subclass to customise the behaviour. This is
primarily used by `findMember` to cache member types and to assemble
the resulting list of symbols in an low-allocation manner.

While there I have introduced some polymorphic calls, the call sites
are only bi-morphic, and our typical pattern of compilation involves
far more `findMember` calls, so I expect that JIT will keep the
virtual call cost to an absolute minimum.

Test results have been updated now that `findMembers` correctly
excludes constructors and doesn't inherit privates.

Coming up next: we can actually fix SI-7475!
retronym added a commit that referenced this pull request Feb 6, 2014
Swathes of important logic are duplicated between `findMember`
and `findMembers` after they separated on grounds of irreconcilable
differences about how fast they should run:

    d905558 Variation #10 to optimze findMember
    fcb0c01 Attempt #9 to opimize findMember.
    71d2ceb Attempt #8 to opimize findMember.
    77e5692 Attempty #7 to optimize findMember
    275115e Fixing problem that caused fingerprints to fail in
    e94252e Attemmpt #6 to optimize findMember
    73e61b8 Attempt #5 to optimize findMember.
    04f0b65 Attempt #4 to optimize findMember
    0e3c70f Attempt #3 to optimize findMember
    41f4497 Attempt #2 to optimize findMember
    1a73aa0 Attempt #1 to optimize findMember

This didn't actually bear fruit, and the intervening years have
seen the implementations drift.

Now is the time to reunite them under the banner of `FindMemberBase`.

Each has a separate subclass to customise the behaviour. This is
primarily used by `findMember` to cache member types and to assemble
the resulting list of symbols in an low-allocation manner.

While there I have introduced some polymorphic calls, the call sites
are only bi-morphic, and our typical pattern of compilation involves
far more `findMember` calls, so I expect that JIT will keep the
virtual call cost to an absolute minimum.

Test results have been updated now that `findMembers` correctly
excludes constructors and doesn't inherit privates.

Coming up next: we can actually fix SI-7475!
retronym added a commit that referenced this pull request Feb 12, 2014
Swathes of important logic are duplicated between `findMember`
and `findMembers` after they separated on grounds of irreconcilable
differences about how fast they should run:

    d905558 Variation #10 to optimze findMember
    fcb0c01 Attempt #9 to opimize findMember.
    71d2ceb Attempt #8 to opimize findMember.
    77e5692 Attempty #7 to optimize findMember
    275115e Fixing problem that caused fingerprints to fail in
    e94252e Attemmpt #6 to optimize findMember
    73e61b8 Attempt #5 to optimize findMember.
    04f0b65 Attempt #4 to optimize findMember
    0e3c70f Attempt #3 to optimize findMember
    41f4497 Attempt #2 to optimize findMember
    1a73aa0 Attempt #1 to optimize findMember

This didn't actually bear fruit, and the intervening years have
seen the implementations drift.

Now is the time to reunite them under the banner of `FindMemberBase`.

Each has a separate subclass to customise the behaviour. This is
primarily used by `findMember` to cache member types and to assemble
the resulting list of symbols in an low-allocation manner.

While there I have introduced some polymorphic calls, the call sites
are only bi-morphic, and our typical pattern of compilation involves
far more `findMember` calls, so I expect that JIT will keep the
virtual call cost to an absolute minimum.

Test results have been updated now that `findMembers` correctly
excludes constructors and doesn't inherit privates.

Coming up next: we can actually fix SI-7475!
retronym pushed a commit that referenced this pull request May 7, 2014
retronym added a commit that referenced this pull request Mar 1, 2015
Under `-Ydelambdafy:method`, a public, static accessor method is
created to expose the private method containing the body of the
lambda.

Currently this accessor method has its parameters in the same order
structure as those of the lambda body method.

What is this order? There are three categories of parameters:

  1. lambda parameters
  2. captured parameters (added by lambdalift)
  3. self parameters (added to lambda bodies that end up in trait
     impl classes by mixin, and added unconditionally to the static
     accessor method.)

These are currently emitted in order #3, #1, #2.

Here are examples of the current behaviour:

BEFORE (trait):

```
% cat sandbox/test.scala
trait Test {
  def member: A
  def foo {
    val local = new B
    (arg: C) => "" + arg + member + local
  }
}

% qscalac -Ydelambdafy:method sandbox/test.scala && echo ':javap -private Test$class' | qscala

scala> :javap -private Test$class
Compiled from "test.scala"
public abstract class Test$class {
  public static void foo(Test);
  private static final java.lang.String $anonfun$1(Test, C, B);
  public static void $init$(Test);
  public static final java.lang.String accessor$1(Test, C, B);
}
```

BEFORE (class):

```
% cat sandbox/test.scala
abstract class Test {
  def member: A
  def foo {
    val local = new B
    (arg: C) => "" + arg + member + local
  }
}
% qscalac -Ydelambdafy:method sandbox/test.scala && echo ':javap -private Test' | qscala

scala> :javap -private Test
Compiled from "test.scala"
public abstract class Test {
  public abstract A member();
  public void foo();
  private final java.lang.String $anonfun$1(C, B);
  public Test();
  public static final java.lang.String accessor$1(Test, C, B);
}
```

Contrasting the class case with Java:

```
% cat sandbox/Test.java
public abstract class Test {
  public static class A {};
  public static class B {};
  public static class C {};
  public static interface I {
    public abstract Object c(C arg);
  }
  public abstract A member();
  public void test() {
    B local = new B();
    I i1 = (C arg) -> "" + member() + local;
  }
}

% javac -d . sandbox/Test.java && javap -private Test
Compiled from "Test.java"
public abstract class Test {
  public Test();
  public abstract Test$A member();
  public void test();
  private java.lang.Object lambda$test$0(Test$B, Test$C);
}
```

We can see that in Java 8 lambda parameters come first. If we
want to use Java's LambdaMetafactory to spin up our anoymous FunctionN
subclasses on the fly, a signature must change.

I can see three options for change:

  1. Adjust `Mixin` to always append the `$this` parameter, rather
     than prepending it.
  2. More conservatively, do this just for lambda bodies
  3. Adjust the parameters of the accessor method only. The body
     of this method can permute params before calling the lambda
     body method.

This commit implements option #3. This is the lowest risk / impact
to pave the way for experimentation with indy lambdas. But it isn't
ideal as a long term solution, as indy lambdas actually don't need
the accessor method at all, private methods can be used directly
by LambdaMetaFactory, saving a little indirection.

Option #1 might be worth a shot on the 2.12.x branch. Option #2 might
even be feasible on 2.11.x.

I've included a test that shows this in all in action. However, that
is currently disabled, as we don't have a partest category for tests
that require Java 8.
retronym added a commit that referenced this pull request Mar 1, 2015
Under `-Ydelambdafy:method`, a public, static accessor method is
created to expose the private method containing the body of the
lambda.

Currently this accessor method has its parameters in the same order
structure as those of the lambda body method.

What is this order? There are three categories of parameters:

  1. lambda parameters
  2. captured parameters (added by lambdalift)
  3. self parameters (added to lambda bodies that end up in trait
     impl classes by mixin, and added unconditionally to the static
     accessor method.)

These are currently emitted in order #3, #1, #2.

Here are examples of the current behaviour:

BEFORE (trait):

```
% cat sandbox/test.scala
trait Test {
  def member: A
  def foo {
    val local = new B
    (arg: C) => "" + arg + member + local
  }
}

% qscalac -Ydelambdafy:method sandbox/test.scala && echo ':javap -private Test$class' | qscala

scala> :javap -private Test$class
Compiled from "test.scala"
public abstract class Test$class {
  public static void foo(Test);
  private static final java.lang.String $anonfun$1(Test, C, B);
  public static void $init$(Test);
  public static final java.lang.String accessor$1(Test, C, B);
}
```

BEFORE (class):

```
% cat sandbox/test.scala
abstract class Test {
  def member: A
  def foo {
    val local = new B
    (arg: C) => "" + arg + member + local
  }
}
% qscalac -Ydelambdafy:method sandbox/test.scala && echo ':javap -private Test' | qscala

scala> :javap -private Test
Compiled from "test.scala"
public abstract class Test {
  public abstract A member();
  public void foo();
  private final java.lang.String $anonfun$1(C, B);
  public Test();
  public static final java.lang.String accessor$1(Test, C, B);
}
```

Contrasting the class case with Java:

```
% cat sandbox/Test.java
public abstract class Test {
  public static class A {};
  public static class B {};
  public static class C {};
  public static interface I {
    public abstract Object c(C arg);
  }
  public abstract A member();
  public void test() {
    B local = new B();
    I i1 = (C arg) -> "" + member() + local;
  }
}

% javac -d . sandbox/Test.java && javap -private Test
Compiled from "Test.java"
public abstract class Test {
  public Test();
  public abstract Test$A member();
  public void test();
  private java.lang.Object lambda$test$0(Test$B, Test$C);
}
```

We can see that in Java 8 lambda parameters come first. If we
want to use Java's LambdaMetafactory to spin up our anoymous FunctionN
subclasses on the fly, a signature must change.

I can see three options for change:

  1. Adjust `Mixin` to always append the `$this` parameter, rather
     than prepending it.
  2. More conservatively, do this just for lambda bodies
  3. Adjust the parameters of the accessor method only. The body
     of this method can permute params before calling the lambda
     body method.

This commit implements option #3. This is the lowest risk / impact
to pave the way for experimentation with indy lambdas. But it isn't
ideal as a long term solution, as indy lambdas actually don't need
the accessor method at all, private methods can be used directly
by LambdaMetaFactory, saving a little indirection.

Option #1 might be worth a shot on the 2.12.x branch. Option #2 might
even be feasible on 2.11.x.

I've included a test that shows this in all in action. However, that
is currently disabled, as we don't have a partest category for tests
that require Java 8.
retronym added a commit that referenced this pull request Mar 4, 2015
Under `-Ydelambdafy:method`, a public, static accessor method is
created to expose the private method containing the body of the
lambda.

Currently this accessor method has its parameters in the same order
structure as those of the lambda body method.

What is this order? There are three categories of parameters:

  1. lambda parameters
  2. captured parameters (added by lambdalift)
  3. self parameters (added to lambda bodies that end up in trait
     impl classes by mixin, and added unconditionally to the static
     accessor method.)

These are currently emitted in order #3, #1, #2.

Here are examples of the current behaviour:

BEFORE (trait):

```
% cat sandbox/test.scala && scalac-hash v2.11.5 -Ydelambdafy:method sandbox/test.scala && javap -private -classpath . 'Test$class'
trait Member; class Capture; trait LambdaParam
trait Test {
  def member: Member
  def foo {
    val local = new Capture
    (arg: LambdaParam) => "" + arg + member + local
  }
}
Compiled from "test.scala"
public abstract class Test$class {
  public static void foo(Test);
  private static final java.lang.String $anonfun$1(Test, LambdaParam, Capture);
  public static void $init$(Test);
  public static final java.lang.String accessor$1(Test, LambdaParam, Capture);
}
```

BEFORE (class):

```
% cat sandbox/test.scala && scalac-hash v2.11.5 -Ydelambdafy:method sandbox/test.scala && javap -private -classpath . Test
trait Member; class Capture; trait LambdaParam
abstract class Test {
  def member: Member
  def foo {
    val local = new Capture
    (arg: LambdaParam) => "" + arg + member + local
  }
}
Compiled from "test.scala"
public abstract class Test {
  public abstract Member member();
  public void foo();
  private final java.lang.String $anonfun$1(LambdaParam, Capture);
  public Test();
  public static final java.lang.String accessor$1(Test, LambdaParam, Capture);
}
```

Contrasting the class case with Java:

```
% cat sandbox/Test.java && javac -d . sandbox/Test.java && javap -private -classpath . Test
public abstract class Test {
  public static class Member {};
  public static class Capture {};
  public static class LambaParam {};
  public static interface I {
    public abstract Object c(LambaParam arg);
  }
  public abstract Member member();
  public void test() {
    Capture local = new Capture();
    I i1 = (LambaParam arg) -> "" + member() + local;
  }
}

Compiled from "Test.java"
public abstract class Test {
  public Test();
  public abstract Test$Member member();
  public void test();
  private java.lang.Object lambda$test$0(Test$Capture, Test$LambaParam);
}
```

We can see that in Java 8 lambda parameters come after captures. If we
want to use Java's LambdaMetafactory to spin up our anoymous FunctionN
subclasses on the fly, our ordering must change.

I can see three options for change:

  1. Adjust `Mixin` to always append the `$this` parameter, rather
     than prepending it.
  2. More conservatively, do this just for lambda bodies
  3. Adjust the parameters of the accessor method only. The body
     of this method can permute params before calling the lambda
     body method.

This commit implements option #3. This is the lowest risk / impact
to pave the way for experimentation with indy lambdas. But it isn't
ideal as a long term solution, as indy lambdas actually don't need
the accessor method at all, private methods can be used directly
by LambdaMetaFactory, saving a little indirection.

Option #1 might be worth a shot on the 2.12.x branch. Option #2 might
even be feasible on 2.11.x.

I've included a test that shows this in all in action. However, that
is currently disabled, as we don't have a partest category for tests
that require Java 8.
retronym added a commit that referenced this pull request Mar 4, 2015
Under `-Ydelambdafy:method`, a public, static accessor method is
created to expose the private method containing the body of the
lambda.

Currently this accessor method has its parameters in the same order
structure as those of the lambda body method.

What is this order? There are three categories of parameters:

  1. lambda parameters
  2. captured parameters (added by lambdalift)
  3. self parameters (added to lambda bodies that end up in trait
     impl classes by mixin, and added unconditionally to the static
     accessor method.)

These are currently emitted in order #3, #1, #2.

Here are examples of the current behaviour:

BEFORE (trait):

```
% cat sandbox/test.scala && scalac-hash v2.11.5 -Ydelambdafy:method sandbox/test.scala && javap -private -classpath . 'Test$class'
trait Member; class Capture; trait LambdaParam
trait Test {
  def member: Member
  def foo {
    val local = new Capture
    (arg: LambdaParam) => "" + arg + member + local
  }
}
Compiled from "test.scala"
public abstract class Test$class {
  public static void foo(Test);
  private static final java.lang.String $anonfun$1(Test, LambdaParam, Capture);
  public static void $init$(Test);
  public static final java.lang.String accessor$1(Test, LambdaParam, Capture);
}
```

BEFORE (class):

```
% cat sandbox/test.scala && scalac-hash v2.11.5 -Ydelambdafy:method sandbox/test.scala && javap -private -classpath . Test
trait Member; class Capture; trait LambdaParam
abstract class Test {
  def member: Member
  def foo {
    val local = new Capture
    (arg: LambdaParam) => "" + arg + member + local
  }
}
Compiled from "test.scala"
public abstract class Test {
  public abstract Member member();
  public void foo();
  private final java.lang.String $anonfun$1(LambdaParam, Capture);
  public Test();
  public static final java.lang.String accessor$1(Test, LambdaParam, Capture);
}
```

Contrasting the class case with Java:

```
% cat sandbox/Test.java && javac -d . sandbox/Test.java && javap -private -classpath . Test
public abstract class Test {
  public static class Member {};
  public static class Capture {};
  public static class LambaParam {};
  public static interface I {
    public abstract Object c(LambaParam arg);
  }
  public abstract Member member();
  public void test() {
    Capture local = new Capture();
    I i1 = (LambaParam arg) -> "" + member() + local;
  }
}

Compiled from "Test.java"
public abstract class Test {
  public Test();
  public abstract Test$Member member();
  public void test();
  private java.lang.Object lambda$test$0(Test$Capture, Test$LambaParam);
}
```

We can see that in Java 8 lambda parameters come after captures. If we
want to use Java's LambdaMetafactory to spin up our anoymous FunctionN
subclasses on the fly, our ordering must change.

I can see three options for change:

  1. Adjust `LambdaLift` to always prepend captured parameters,
     rather than appending them. I think we could leave `Mixin` as
     it is, it already prepends the self parameter. This would result
     a parameter ordering, in terms of the list above: #3, #2, #1.
  2. More conservatively, do this just for methods known to hold
     lambda bodies. This might avoid needlessly breaking code that
     has come to depend on our binary encoding.
  3. Adjust the parameters of the accessor method only. The body
     of this method can permute params before calling the lambda
     body method.

This commit implements option #3. This is the lowest risk / impact
to pave the way for experimentation with indy lambdas. But it isn't
ideal as a long term solution, as indy lambdas actually don't need
the accessor method at all, private methods can be used directly
by LambdaMetaFactory, saving a little indirection.

Option #1 might be worth a shot on the 2.12.x branch. Option #2 might
even be feasible on 2.11.x.

I've included a test that shows this in all in action. However, that
is currently disabled, as we don't have a partest category for tests
that require Java 8.
retronym added a commit that referenced this pull request Mar 4, 2015
Under `-Ydelambdafy:method`, a public, static accessor method is
created to expose the private method containing the body of the
lambda.

Currently this accessor method has its parameters in the same order
structure as those of the lambda body method.

What is this order? There are three categories of parameters:

  1. lambda parameters
  2. captured parameters (added by lambdalift)
  3. self parameters (added to lambda bodies that end up in trait
     impl classes by mixin, and added unconditionally to the static
     accessor method.)

These are currently emitted in order #3, #1, #2.

Here are examples of the current behaviour:

BEFORE (trait):

```
% cat sandbox/test.scala && scalac-hash v2.11.5 -Ydelambdafy:method sandbox/test.scala && javap -private -classpath . 'Test$class'
trait Member; class Capture; trait LambdaParam
trait Test {
  def member: Member
  def foo {
    val local = new Capture
    (arg: LambdaParam) => "" + arg + member + local
  }
}
Compiled from "test.scala"
public abstract class Test$class {
  public static void foo(Test);
  private static final java.lang.String $anonfun$1(Test, LambdaParam, Capture);
  public static void $init$(Test);
  public static final java.lang.String accessor$1(Test, LambdaParam, Capture);
}
```

BEFORE (class):

```
% cat sandbox/test.scala && scalac-hash v2.11.5 -Ydelambdafy:method sandbox/test.scala && javap -private -classpath . Test
trait Member; class Capture; trait LambdaParam
abstract class Test {
  def member: Member
  def foo {
    val local = new Capture
    (arg: LambdaParam) => "" + arg + member + local
  }
}
Compiled from "test.scala"
public abstract class Test {
  public abstract Member member();
  public void foo();
  private final java.lang.String $anonfun$1(LambdaParam, Capture);
  public Test();
  public static final java.lang.String accessor$1(Test, LambdaParam, Capture);
}
```

Contrasting the class case with Java:

```
% cat sandbox/Test.java && javac -d . sandbox/Test.java && javap -private -classpath . Test
public abstract class Test {
  public static class Member {};
  public static class Capture {};
  public static class LambaParam {};
  public static interface I {
    public abstract Object c(LambaParam arg);
  }
  public abstract Member member();
  public void test() {
    Capture local = new Capture();
    I i1 = (LambaParam arg) -> "" + member() + local;
  }
}

Compiled from "Test.java"
public abstract class Test {
  public Test();
  public abstract Test$Member member();
  public void test();
  private java.lang.Object lambda$test$0(Test$Capture, Test$LambaParam);
}
```

We can see that in Java 8 lambda parameters come after captures. If we
want to use Java's LambdaMetafactory to spin up our anoymous FunctionN
subclasses on the fly, our ordering must change.

I can see three options for change:

  1. Adjust `LambdaLift` to always prepend captured parameters,
     rather than appending them. I think we could leave `Mixin` as
     it is, it already prepends the self parameter. This would result
     a parameter ordering, in terms of the list above: #3, #2, #1.
  2. More conservatively, do this just for methods known to hold
     lambda bodies. This might avoid needlessly breaking code that
     has come to depend on our binary encoding.
  3. Adjust the parameters of the accessor method only. The body
     of this method can permute params before calling the lambda
     body method.

This commit implements option #1.

I've included a test that shows this in all in action. However, that
is currently disabled, as we don't have a partest category for tests
that require Java 8.
retronym added a commit that referenced this pull request Mar 6, 2015
Under `-Ydelambdafy:method`, a public, static accessor method is
created to expose the private method containing the body of the
lambda.

Currently this accessor method has its parameters in the same order
structure as those of the lambda body method.

What is this order? There are three categories of parameters:

  1. lambda parameters
  2. captured parameters (added by lambdalift)
  3. self parameters (added to lambda bodies that end up in trait
     impl classes by mixin, and added unconditionally to the static
     accessor method.)

These are currently emitted in order #3, #1, #2.

Here are examples of the current behaviour:

BEFORE (trait):

```
% cat sandbox/test.scala && scalac-hash v2.11.5 -Ydelambdafy:method sandbox/test.scala && javap -private -classpath . 'Test$class'
trait Member; class Capture; trait LambdaParam
trait Test {
  def member: Member
  def foo {
    val local = new Capture
    (arg: LambdaParam) => "" + arg + member + local
  }
}
Compiled from "test.scala"
public abstract class Test$class {
  public static void foo(Test);
  private static final java.lang.String $anonfun$1(Test, LambdaParam, Capture);
  public static void $init$(Test);
  public static final java.lang.String accessor$1(Test, LambdaParam, Capture);
}
```

BEFORE (class):

```
% cat sandbox/test.scala && scalac-hash v2.11.5 -Ydelambdafy:method sandbox/test.scala && javap -private -classpath . Test
trait Member; class Capture; trait LambdaParam
abstract class Test {
  def member: Member
  def foo {
    val local = new Capture
    (arg: LambdaParam) => "" + arg + member + local
  }
}
Compiled from "test.scala"
public abstract class Test {
  public abstract Member member();
  public void foo();
  private final java.lang.String $anonfun$1(LambdaParam, Capture);
  public Test();
  public static final java.lang.String accessor$1(Test, LambdaParam, Capture);
}
```

Contrasting the class case with Java:

```
% cat sandbox/Test.java && javac -d . sandbox/Test.java && javap -private -classpath . Test
public abstract class Test {
  public static class Member {};
  public static class Capture {};
  public static class LambaParam {};
  public static interface I {
    public abstract Object c(LambaParam arg);
  }
  public abstract Member member();
  public void test() {
    Capture local = new Capture();
    I i1 = (LambaParam arg) -> "" + member() + local;
  }
}

Compiled from "Test.java"
public abstract class Test {
  public Test();
  public abstract Test$Member member();
  public void test();
  private java.lang.Object lambda$test$0(Test$Capture, Test$LambaParam);
}
```

We can see that in Java 8 lambda parameters come after captures. If we
want to use Java's LambdaMetafactory to spin up our anoymous FunctionN
subclasses on the fly, our ordering must change.

I can see three options for change:

  1. Adjust `LambdaLift` to always prepend captured parameters,
     rather than appending them. I think we could leave `Mixin` as
     it is, it already prepends the self parameter. This would result
     a parameter ordering, in terms of the list above: #3, #2, #1.
  2. More conservatively, do this just for methods known to hold
     lambda bodies. This might avoid needlessly breaking code that
     has come to depend on our binary encoding.
  3. Adjust the parameters of the accessor method only. The body
     of this method can permute params before calling the lambda
     body method.

This commit implements option #1. We limit this change to
non-constructors, to sidestep the need to make corresponding
changes elsewhere in the compiler to avoid the crasher shown
in the enclosed test case, which was minimized from a bootstrap
failure from an earlier a version of this patch.

I've included a test that shows this in all in action. However, that
is currently disabled, as we don't have a partest category for tests
that require Java 8.
retronym added a commit that referenced this pull request Mar 24, 2015
Under `-Ydelambdafy:method`, a public, static accessor method is
created to expose the private method containing the body of the
lambda.

Currently this accessor method has its parameters in the same order
structure as those of the lambda body method.

What is this order? There are three categories of parameters:

  1. lambda parameters
  2. captured parameters (added by lambdalift)
  3. self parameters (added to lambda bodies that end up in trait
     impl classes by mixin, and added unconditionally to the static
     accessor method.)

These are currently emitted in order #3, #1, #2.

Here are examples of the current behaviour:

BEFORE (trait):

```
% cat sandbox/test.scala && scalac-hash v2.11.5 -Ydelambdafy:method sandbox/test.scala && javap -private -classpath . 'Test$class'
trait Member; class Capture; trait LambdaParam
trait Test {
  def member: Member
  def foo {
    val local = new Capture
    (arg: LambdaParam) => "" + arg + member + local
  }
}
Compiled from "test.scala"
public abstract class Test$class {
  public static void foo(Test);
  private static final java.lang.String $anonfun$1(Test, LambdaParam, Capture);
  public static void $init$(Test);
  public static final java.lang.String accessor$1(Test, LambdaParam, Capture);
}
```

BEFORE (class):

```
% cat sandbox/test.scala && scalac-hash v2.11.5 -Ydelambdafy:method sandbox/test.scala && javap -private -classpath . Test
trait Member; class Capture; trait LambdaParam
abstract class Test {
  def member: Member
  def foo {
    val local = new Capture
    (arg: LambdaParam) => "" + arg + member + local
  }
}
Compiled from "test.scala"
public abstract class Test {
  public abstract Member member();
  public void foo();
  private final java.lang.String $anonfun$1(LambdaParam, Capture);
  public Test();
  public static final java.lang.String accessor$1(Test, LambdaParam, Capture);
}
```

Contrasting the class case with Java:

```
% cat sandbox/Test.java && javac -d . sandbox/Test.java && javap -private -classpath . Test
public abstract class Test {
  public static class Member {};
  public static class Capture {};
  public static class LambaParam {};
  public static interface I {
    public abstract Object c(LambaParam arg);
  }
  public abstract Member member();
  public void test() {
    Capture local = new Capture();
    I i1 = (LambaParam arg) -> "" + member() + local;
  }
}

Compiled from "Test.java"
public abstract class Test {
  public Test();
  public abstract Test$Member member();
  public void test();
  private java.lang.Object lambda$test$0(Test$Capture, Test$LambaParam);
}
```

We can see that in Java 8 lambda parameters come after captures. If we
want to use Java's LambdaMetafactory to spin up our anoymous FunctionN
subclasses on the fly, our ordering must change.

I can see three options for change:

  1. Adjust `LambdaLift` to always prepend captured parameters,
     rather than appending them. I think we could leave `Mixin` as
     it is, it already prepends the self parameter. This would result
     a parameter ordering, in terms of the list above: #3, #2, #1.
  2. More conservatively, do this just for methods known to hold
     lambda bodies. This might avoid needlessly breaking code that
     has come to depend on our binary encoding.
  3. Adjust the parameters of the accessor method only. The body
     of this method can permute params before calling the lambda
     body method.

This commit implements option #2.

In also prototyped #1, and found it worked so long as I limited it to
non-constructors, to sidestep the need to make corresponding
changes elsewhere in the compiler to avoid the crasher shown
in the enclosed test case, which was minimized from a bootstrap
failure from an earlier a version of this patch.

We would need to defer option #1 to 2.12 in any case, as some of
these lifted methods are publicied by the optimizer, and we must
leave the signatures alone to comply with MiMa.

I've included a test that shows this in all in action. However, that
is currently disabled, as we don't have a partest category for tests
that require Java 8.
retronym added a commit that referenced this pull request Aug 6, 2015
The log messages intented to chronicle implicit search were
always being filtered out by virtue of the fact that the the tree
passed to `printTyping` was already typed, (e.g. with an implicit
MethodType.)

This commit enabled printing in this case, although it still
filters out trees that are deemed unfit for typer tracing,
such as `()`. In the context of implicit search, this happens
to filter out the noise of:

```
|    |    |    [search #2] start `()`, searching for adaptation to pt=Unit => Foo[Int,Int] (silent: value <local Test> in Test) implicits disabled
|    |    |    [search #3] start `()`, searching for adaptation to pt=(=> Unit) => Foo[Int,Int] (silent: value <local Test> in Test) implicits disabled
|    |    |    \-> <error>
```

... which I think is desirable.

The motivation for this fix was to better display the interaction
between implicit search and type inference. For instance:

```
class Foo[A, B]
class Test {
  implicit val f: Foo[Int, String] = ???
  def t[A, B](a: A)(implicit f: Foo[A, B]) = ???
  t(1)
}
```

````
% scalac -Ytyper-debug sandbox/instantiate.scala
...
|    |-- t(1) BYVALmode-EXPRmode (site: value <local Test> in Test)
|    |    |-- t BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value <local Test> in Test)
|    |    |    [adapt] [A, B](a: A)(implicit f: Foo[A,B])Nothing adapted to [A, B](a: A)(implicit f: Foo[A,B])Nothing
|    |    |    \-> (a: A)(implicit f: Foo[A,B])Nothing
|    |    |-- 1 BYVALmode-EXPRmode-POLYmode (site: value <local Test> in Test)
|    |    |    \-> Int(1)
|    |    solving for (A: ?A, B: ?B)
|    |    solving for (B: ?B)
|    |    [search #1] start `[A, B](a: A)(implicit f: Foo[A,B])Nothing` inferring type B, searching for adaptation to pt=Foo[Int,B] (silent: value <local Test> in Test) implicits disabled
|    |    [search #1] considering f
|    |    [adapt] f adapted to => Foo[Int,String] based on pt Foo[Int,B]
|    |    [search #1] solve tvars=?B, tvars.constr= >: String <: String
|    |    solving for (B: ?B)
|    |    [search #1] success inferred value of type Foo[Int,=?String] is SearchResult(Test.this.f, TreeTypeSubstituter(List(type B),List(String)))
|    |    |-- [A, B](a: A)(implicit f: Foo[A,B])Nothing BYVALmode-EXPRmode (site: value <local Test> in Test)
|    |    |    \-> Nothing
|    |    [adapt] [A, B](a: A)(implicit f: Foo[A,B])Nothing adapted to [A, B](a: A)(implicit f: Foo[A,B])Nothing
|    |    \-> Nothing
```
retronym pushed a commit that referenced this pull request Oct 14, 2015
must replace old trait accessor symbols by mixed in symbols
in the infos of the mixed in symbols

```
trait T { val a: String ; val b: a.type }
class C extends T {
  // a, b synthesized, but the a in b's type, a.type, refers to the original symbol, not the clone in C
}
```

symbols occurring in types of synthesized members
do not get rebound to other synthesized symbols

package <empty>#4 {
  abstract <defaultparam/trait> trait N#7352 extends scala#22.AnyRef#2378 {
    <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$self_$eq#15011(x$1#15012: <empty>#3.this.N#7352): scala#23.this.Unit#2340;
    <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$n_$eq#15013(x$1#15014: N#7352.this.self#7442.type): scala#23.this.Unit#2340;
    <method> def /*N*/$init$scala#7441(): scala#23.this.Unit#2340 = {
      ()
    };
    <method> <deferred> <stable> <accessor> <triedcooking> <sub_synth> def self#7442: <empty>#3.this.N#7352;
    N#7352.this.N$_setter_$self_$eq#15011(scala#22.Predef#1729.$qmark$qmark$qmark#6917);
    <method> <deferred> <stable> <accessor> <sub_synth> def n#7443: N#7352.this.self#7442.type;
    N#7352.this.N$_setter_$n_$eq#15013(N#7352.this.self#7442)
  };
  abstract class M#7353 extends scala#22.AnyRef#2378 {
    <method> <triedcooking> def <init>#13465(): <empty>#3.this.M#7353 = {
      M#7353.super.<init>scala#2719();
      ()
    };
    <method> <deferred> <stable> <accessor> <triedcooking> def self#13466: <empty>#3.this.N#7352;
    <method> <deferred> <stable> <accessor> def n#13467: M#7353.this.self#13466.type
  };
  class C#7354 extends M#7353 with <empty>#3.this.N#7352 {
    <method> <stable> <accessor> <triedcooking> def self#15016: <empty>#3.this.N#7352 = C#7354.this.self #15015;
    <triedcooking> private[this] val self #15015: <empty>#3.this.N#7352 = _;
    <method> <stable> <accessor> def n#15018: C#7354.this.self#7442.type = C#7354.this.n #15017;
    <triedcooking> private[this] val n #15017: C#7354.this.self#7442.type = _;
    <method> <mutable> <accessor> <triedcooking> def N$_setter_$self_$eq#15019(x$1#15021: <empty>#3.this.N#7352): scala#23.this.Unit#2340 = C#7354.this.self #15015 = x$1#15021;
    <method> <mutable> <accessor> <triedcooking> def N$_setter_$n_$eq#15022(x$1#15025: C#7354.this.self#7442.type): scala#23.this.Unit#2340 = C#7354.this.n #15017 = x$1#15025;
    <method> def <init>#14997(): <empty>#3.this.C#7354 = {
      C#7354.super.<init>#13465();
      ()
    }
  }
}

[running phase pickler on dependent_rebind.scala]
[running phase refchecks on dependent_rebind.scala]
test/files/trait-defaults/dependent_rebind.scala:16: error: overriding field n#15049 in trait N#7352 of type C#7354.this.self#15016.type;
 value n #15017 has incompatible type;
 found   : => C#7354.this.self#7442.type (with underlying type => C#7354.this.self#7442.type)
 required: => N#7352.this.self#7442.type
class C extends M with N
      ^
retronym pushed a commit that referenced this pull request Dec 2, 2015
the info-transformed of constructors:
  - traits receive trait-setters for vals
  - classes receive fields & accessors for mixed in traits

Constructors tree transformer
  - makes trees for decls added during above info transform
  - adds mixin super calls to the primary constructor

```
trait OneConcreteVal[T] {
var x = 1 // : T = ???
def foo = x
}

trait OneOtherConcreteVal[T] {
var y: T = ???
}

class C extends OneConcreteVal[Int] with OneOtherConcreteVal[String]
```

we don't have a field -- only a getter -- so,
where will we keep non-getter but-field annotations?

mixin only deals with lazy accessors/vals

do not used referenced to correlate getter/setter
it messes with paramaccessor's usage, and we don't really need it

make sure to clone info's, so we don't share symbols for method args
this manifests itself as an exception in lambdalift, finding proxies

Use NEEDS_TREES for all comms between InfoTransform and tree transform

yep, need SYNTHESIZE_IMPL_IN_SUBCLASS

distinguish accessors that should be mixed into subclass,
and those that simply need to be implemented in tree transform,
after info transform added the decl

commit 4b4932e
Author: Adriaan Moors <[email protected]>
Date:   6 days ago

    do assignment to trait fields in AddInterfaces

    regular class vals get assignments during constructors, as before

impl classes get accessors + assignments through trait setters in addinterfaces
so that constructors acts on them there,
and produced the init method in the required spot (the impl class)

bootstrapped compiler needs new partest

commit baf568d
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    produce identical bytecode for constant trait val getters

    I couldn't bring myself to emit the unused fields that we
    used to emit for constant vals, even though the getters
    immediately return the constant, and thus the field goes unused.

    In the next version, there's no need to synthesize impls
    for these in subclasses -- the getter can be implemented
    in the interface.

commit b9052da
Author: Lukas Rytz <[email protected]>
Date:   3 weeks ago

    Fix enclosing method attribute for classes nested in trait fields

    Trait fields are now created as MethodSymbol (no longer TermSymbol).
    This symbol shows up in the `originalOwner` chain of a class declared
    within the field initializer. This promoted the field getter to
    being the enclosing method of the nested class, which it is not
    (the EnclosingMethod attribute is a source-level property).

commit cf845ab
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    don't suppress field for unit-typed vals

    it affects the memory model -- even a write of unit to a field is relevant...

commit 337a9dd
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    unit-typed lazy vals should never receive a field

    this need was unmasked by test/files/run/t7843-jsr223-service.scala,
    which no longer printed the output expected from the `0 to 10 foreach`

    Currently failing tests:

     - test/files/pos/t6780.scala
     - test/files/neg/anytrait.scala
     - test/files/neg/delayed-init-ref.scala
     - test/files/neg/t562.scala
     - test/files/neg/t6276.scala
     - test/files/run/delambdafy_uncurry_byname_inline.scala
     - test/files/run/delambdafy_uncurry_byname_method.scala
     - test/files/run/delambdafy_uncurry_inline.scala
     - test/files/run/delambdafy_uncurry_method.scala
     - test/files/run/inner-obj-auto.scala
     - test/files/run/lazy-traits.scala
     - test/files/run/reify_lazyunit.scala
     - test/files/run/showraw_mods.scala
     - test/files/run/t3670.scala
     - test/files/run/t3980.scala
     - test/files/run/t4047.scala
     - test/files/run/t6622.scala
     - test/files/run/t7406.scala
     - test/files/run/t7843-jsr223-service.scala
     - test/files/jvm/innerClassAttribute
     - test/files/specialized/SI-7343.scala
     - test/files/specialized/constant_lambda.scala
     - test/files/specialized/spec-early.scala
     - test/files/specialized/spec-init.scala
     - test/files/specialized/spec-matrix-new.scala
     - test/files/specialized/spec-matrix-old.scala
     - test/files/presentation/scope-completion-3

commit b1b4e5c
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    wip: lambdalift fix

    test/files/trait-defaults/lambdalift.scala works,
    but still some related tests failing

    (note that we can't use a bootstrapped compiler yet
    due to binary incompatibility in partest)

commit eae7dac
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    update check now that trait vals can be concrete, use names not letters

    note the progression in a concrete trait val now being recognized as such
    ```
    -trait T => true
    -method $init$ => false
    -value z1 => true
    -value z2 => true // z2 is actually concrete!
    ```

commit 6555c74
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    bootstraps again by running info transform once per class...

    not sure how this ever worked, as separate compilation would transform a trait's info
    multiple times, resulting in double defs...

commit 273cb20
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    skip presuper vals in new encoding

commit 728e71e
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    incoherent cyclic references between synthesized members

    must replace old trait accessor symbols by mixed in symbols
    in the infos of the mixed in symbols

    ```
    trait T { val a: String ; val b: a.type }
    class C extends T {
      // a, b synthesized, but the a in b's type, a.type, refers to the original symbol, not the clone in C
    }
    ```

    symbols occurring in types of synthesized members
    do not get rebound to other synthesized symbols

    package <empty>#4 {
      abstract <defaultparam/trait> trait N#7352 extends scala#22.AnyRef#2378 {
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$self_$eq#15011(x$1#15012: <empty>#3.this.N#7352): scala#23.this.Unit#2340;
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$n_$eq#15013(x$1#15014: N#7352.this.self#7442.type): scala#23.this.Unit#2340;
        <method> def /*N*/$init$scala#7441(): scala#23.this.Unit#2340 = {
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> <sub_synth> def self#7442: <empty>#3.this.N#7352;
        N#7352.this.N$_setter_$self_$eq#15011(scala#22.Predef#1729.$qmark$qmark$qmark#6917);
        <method> <deferred> <stable> <accessor> <sub_synth> def n#7443: N#7352.this.self#7442.type;
        N#7352.this.N$_setter_$n_$eq#15013(N#7352.this.self#7442)
      };
      abstract class M#7353 extends scala#22.AnyRef#2378 {
        <method> <triedcooking> def <init>#13465(): <empty>#3.this.M#7353 = {
          M#7353.super.<init>scala#2719();
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> def self#13466: <empty>#3.this.N#7352;
        <method> <deferred> <stable> <accessor> def n#13467: M#7353.this.self#13466.type
      };
      class C#7354 extends M#7353 with <empty>#3.this.N#7352 {
        <method> <stable> <accessor> <triedcooking> def self#15016: <empty>#3.this.N#7352 = C#7354.this.self #15015;
        <triedcooking> private[this] val self #15015: <empty>#3.this.N#7352 = _;
        <method> <stable> <accessor> def n#15018: C#7354.this.self#7442.type = C#7354.this.n #15017;
        <triedcooking> private[this] val n #15017: C#7354.this.self#7442.type = _;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$self_$eq#15019(x$1#15021: <empty>#3.this.N#7352): scala#23.this.Unit#2340 = C#7354.this.self #15015 = x$1#15021;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$n_$eq#15022(x$1#15025: C#7354.this.self#7442.type): scala#23.this.Unit#2340 = C#7354.this.n #15017 = x$1#15025;
        <method> def <init>#14997(): <empty>#3.this.C#7354 = {
          C#7354.super.<init>#13465();
          ()
        }
      }
    }

    [running phase pickler on dependent_rebind.scala]
    [running phase refchecks on dependent_rebind.scala]
    test/files/trait-defaults/dependent_rebind.scala:16: error: overriding field n#15049 in trait N#7352 of type C#7354.this.self#15016.type;
     value n #15017 has incompatible type;
     found   : => C#7354.this.self#7442.type (with underlying type => C#7354.this.self#7442.type)
     required: => N#7352.this.self#7442.type
    class C extends M with N
          ^

    pos/t9111-inliner-workaround revealed need for:
-  override def transformInfo(sym: Symbol, tp: Type): Type = synthFieldsAndAccessors(tp)
+  override def transformInfo(sym: Symbol, tp: Type): Type = if (!sym.isJavaDefined) synthFieldsAndAccessors(tp) else tp

commit b56ca2f
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    static forwarders & private[this] val in trait

    object Properties extends PropertiesTrait

    trait PropertiesTrait {
      // the protected member is not emitted as a static member of  -- it works when dropping the access modifier
      // somehow, the module class member is considered deferred in BForwardersGen
      protected val propFilename: String = /
    }

    // [log jvm] No forwarder for 'getter propFilename' from Properties to 'module class Properties': false || m.isDeferred == true || false || false

    // the following method is missing compared to scalac
    // public final class Properties {
    //     public static String propFilename() {
    //         return Properties$.MODULE$.propFilename();
    //     }

    trait Chars {
      private[this] val char2uescapeArray = Array[Char]('\', 'u', 0, 0, 0, 0)
    }

    object Chars extends Chars

    // +++ w/reflect/scala/reflect/internal/Chars$.class
    // -  private final [C scala83014char2uescapeArray

    constant fold in forwarder for backwards compat
    constant-typed final val in trait should yield impl method

    bean{setter,getter} delegates to setter/getter (commit 1655d1b)
retronym pushed a commit that referenced this pull request Jan 19, 2016
the info-transformed of constructors:
  - traits receive trait-setters for vals
  - classes receive fields & accessors for mixed in traits

Constructors tree transformer
  - makes trees for decls added during above info transform
  - adds mixin super calls to the primary constructor

```
trait OneConcreteVal[T] {
var x = 1 // : T = ???
def foo = x
}

trait OneOtherConcreteVal[T] {
var y: T = ???
}

class C extends OneConcreteVal[Int] with OneOtherConcreteVal[String]
```

we don't have a field -- only a getter -- so,
where will we keep non-getter but-field annotations?

mixin only deals with lazy accessors/vals

do not used referenced to correlate getter/setter
it messes with paramaccessor's usage, and we don't really need it

make sure to clone info's, so we don't share symbols for method args
this manifests itself as an exception in lambdalift, finding proxies

Use NEEDS_TREES for all comms between InfoTransform and tree transform

yep, need SYNTHESIZE_IMPL_IN_SUBCLASS

distinguish accessors that should be mixed into subclass,
and those that simply need to be implemented in tree transform,
after info transform added the decl

commit 4b4932e
Author: Adriaan Moors <[email protected]>
Date:   6 days ago

    do assignment to trait fields in AddInterfaces

    regular class vals get assignments during constructors, as before

impl classes get accessors + assignments through trait setters in addinterfaces
so that constructors acts on them there,
and produced the init method in the required spot (the impl class)

bootstrapped compiler needs new partest

commit baf568d
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    produce identical bytecode for constant trait val getters

    I couldn't bring myself to emit the unused fields that we
    used to emit for constant vals, even though the getters
    immediately return the constant, and thus the field goes unused.

    In the next version, there's no need to synthesize impls
    for these in subclasses -- the getter can be implemented
    in the interface.

commit b9052da
Author: Lukas Rytz <[email protected]>
Date:   3 weeks ago

    Fix enclosing method attribute for classes nested in trait fields

    Trait fields are now created as MethodSymbol (no longer TermSymbol).
    This symbol shows up in the `originalOwner` chain of a class declared
    within the field initializer. This promoted the field getter to
    being the enclosing method of the nested class, which it is not
    (the EnclosingMethod attribute is a source-level property).

commit cf845ab
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    don't suppress field for unit-typed vals

    it affects the memory model -- even a write of unit to a field is relevant...

commit 337a9dd
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    unit-typed lazy vals should never receive a field

    this need was unmasked by test/files/run/t7843-jsr223-service.scala,
    which no longer printed the output expected from the `0 to 10 foreach`

    Currently failing tests:

     - test/files/pos/t6780.scala
     - test/files/neg/anytrait.scala
     - test/files/neg/delayed-init-ref.scala
     - test/files/neg/t562.scala
     - test/files/neg/t6276.scala
     - test/files/run/delambdafy_uncurry_byname_inline.scala
     - test/files/run/delambdafy_uncurry_byname_method.scala
     - test/files/run/delambdafy_uncurry_inline.scala
     - test/files/run/delambdafy_uncurry_method.scala
     - test/files/run/inner-obj-auto.scala
     - test/files/run/lazy-traits.scala
     - test/files/run/reify_lazyunit.scala
     - test/files/run/showraw_mods.scala
     - test/files/run/t3670.scala
     - test/files/run/t3980.scala
     - test/files/run/t4047.scala
     - test/files/run/t6622.scala
     - test/files/run/t7406.scala
     - test/files/run/t7843-jsr223-service.scala
     - test/files/jvm/innerClassAttribute
     - test/files/specialized/SI-7343.scala
     - test/files/specialized/constant_lambda.scala
     - test/files/specialized/spec-early.scala
     - test/files/specialized/spec-init.scala
     - test/files/specialized/spec-matrix-new.scala
     - test/files/specialized/spec-matrix-old.scala
     - test/files/presentation/scope-completion-3

commit b1b4e5c
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    wip: lambdalift fix

    test/files/trait-defaults/lambdalift.scala works,
    but still some related tests failing

    (note that we can't use a bootstrapped compiler yet
    due to binary incompatibility in partest)

commit eae7dac
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    update check now that trait vals can be concrete, use names not letters

    note the progression in a concrete trait val now being recognized as such
    ```
    -trait T => true
    -method $init$ => false
    -value z1 => true
    -value z2 => true // z2 is actually concrete!
    ```

commit 6555c74
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    bootstraps again by running info transform once per class...

    not sure how this ever worked, as separate compilation would transform a trait's info
    multiple times, resulting in double defs...

commit 273cb20
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    skip presuper vals in new encoding

commit 728e71e
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    incoherent cyclic references between synthesized members

    must replace old trait accessor symbols by mixed in symbols
    in the infos of the mixed in symbols

    ```
    trait T { val a: String ; val b: a.type }
    class C extends T {
      // a, b synthesized, but the a in b's type, a.type, refers to the original symbol, not the clone in C
    }
    ```

    symbols occurring in types of synthesized members
    do not get rebound to other synthesized symbols

    package <empty>#4 {
      abstract <defaultparam/trait> trait N#7352 extends scala#22.AnyRef#2378 {
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$self_$eq#15011(x$1#15012: <empty>#3.this.N#7352): scala#23.this.Unit#2340;
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$n_$eq#15013(x$1#15014: N#7352.this.self#7442.type): scala#23.this.Unit#2340;
        <method> def /*N*/$init$scala#7441(): scala#23.this.Unit#2340 = {
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> <sub_synth> def self#7442: <empty>#3.this.N#7352;
        N#7352.this.N$_setter_$self_$eq#15011(scala#22.Predef#1729.$qmark$qmark$qmark#6917);
        <method> <deferred> <stable> <accessor> <sub_synth> def n#7443: N#7352.this.self#7442.type;
        N#7352.this.N$_setter_$n_$eq#15013(N#7352.this.self#7442)
      };
      abstract class M#7353 extends scala#22.AnyRef#2378 {
        <method> <triedcooking> def <init>#13465(): <empty>#3.this.M#7353 = {
          M#7353.super.<init>scala#2719();
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> def self#13466: <empty>#3.this.N#7352;
        <method> <deferred> <stable> <accessor> def n#13467: M#7353.this.self#13466.type
      };
      class C#7354 extends M#7353 with <empty>#3.this.N#7352 {
        <method> <stable> <accessor> <triedcooking> def self#15016: <empty>#3.this.N#7352 = C#7354.this.self #15015;
        <triedcooking> private[this] val self #15015: <empty>#3.this.N#7352 = _;
        <method> <stable> <accessor> def n#15018: C#7354.this.self#7442.type = C#7354.this.n #15017;
        <triedcooking> private[this] val n #15017: C#7354.this.self#7442.type = _;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$self_$eq#15019(x$1#15021: <empty>#3.this.N#7352): scala#23.this.Unit#2340 = C#7354.this.self #15015 = x$1#15021;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$n_$eq#15022(x$1#15025: C#7354.this.self#7442.type): scala#23.this.Unit#2340 = C#7354.this.n #15017 = x$1#15025;
        <method> def <init>#14997(): <empty>#3.this.C#7354 = {
          C#7354.super.<init>#13465();
          ()
        }
      }
    }

    [running phase pickler on dependent_rebind.scala]
    [running phase refchecks on dependent_rebind.scala]
    test/files/trait-defaults/dependent_rebind.scala:16: error: overriding field n#15049 in trait N#7352 of type C#7354.this.self#15016.type;
     value n #15017 has incompatible type;
     found   : => C#7354.this.self#7442.type (with underlying type => C#7354.this.self#7442.type)
     required: => N#7352.this.self#7442.type
    class C extends M with N
          ^

    pos/t9111-inliner-workaround revealed need for:
-  override def transformInfo(sym: Symbol, tp: Type): Type = synthFieldsAndAccessors(tp)
+  override def transformInfo(sym: Symbol, tp: Type): Type = if (!sym.isJavaDefined) synthFieldsAndAccessors(tp) else tp

commit b56ca2f
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    static forwarders & private[this] val in trait

    object Properties extends PropertiesTrait

    trait PropertiesTrait {
      // the protected member is not emitted as a static member of  -- it works when dropping the access modifier
      // somehow, the module class member is considered deferred in BForwardersGen
      protected val propFilename: String = /
    }

    // [log jvm] No forwarder for 'getter propFilename' from Properties to 'module class Properties': false || m.isDeferred == true || false || false

    // the following method is missing compared to scalac
    // public final class Properties {
    //     public static String propFilename() {
    //         return Properties$.MODULE$.propFilename();
    //     }

    trait Chars {
      private[this] val char2uescapeArray = Array[Char]('\', 'u', 0, 0, 0, 0)
    }

    object Chars extends Chars

    // +++ w/reflect/scala/reflect/internal/Chars$.class
    // -  private final [C scala83014char2uescapeArray

    constant fold in forwarder for backwards compat
    constant-typed final val in trait should yield impl method

    bean{setter,getter} delegates to setter/getter (commit 1655d1b)
retronym pushed a commit that referenced this pull request Feb 11, 2016
the info-transformed of constructors:
  - traits receive trait-setters for vals
  - classes receive fields & accessors for mixed in traits

Constructors tree transformer
  - makes trees for decls added during above info transform
  - adds mixin super calls to the primary constructor

```
trait OneConcreteVal[T] {
var x = 1 // : T = ???
def foo = x
}

trait OneOtherConcreteVal[T] {
var y: T = ???
}

class C extends OneConcreteVal[Int] with OneOtherConcreteVal[String]
```

we don't have a field -- only a getter -- so,
where will we keep non-getter but-field annotations?

mixin only deals with lazy accessors/vals

do not used referenced to correlate getter/setter
it messes with paramaccessor's usage, and we don't really need it

make sure to clone info's, so we don't share symbols for method args
this manifests itself as an exception in lambdalift, finding proxies

Use NEEDS_TREES for all comms between InfoTransform and tree transform

yep, need SYNTHESIZE_IMPL_IN_SUBCLASS

distinguish accessors that should be mixed into subclass,
and those that simply need to be implemented in tree transform,
after info transform added the decl

commit 4b4932e
Author: Adriaan Moors <[email protected]>
Date:   6 days ago

    do assignment to trait fields in AddInterfaces

    regular class vals get assignments during constructors, as before

impl classes get accessors + assignments through trait setters in addinterfaces
so that constructors acts on them there,
and produced the init method in the required spot (the impl class)

bootstrapped compiler needs new partest

commit baf568d
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    produce identical bytecode for constant trait val getters

    I couldn't bring myself to emit the unused fields that we
    used to emit for constant vals, even though the getters
    immediately return the constant, and thus the field goes unused.

    In the next version, there's no need to synthesize impls
    for these in subclasses -- the getter can be implemented
    in the interface.

commit b9052da
Author: Lukas Rytz <[email protected]>
Date:   3 weeks ago

    Fix enclosing method attribute for classes nested in trait fields

    Trait fields are now created as MethodSymbol (no longer TermSymbol).
    This symbol shows up in the `originalOwner` chain of a class declared
    within the field initializer. This promoted the field getter to
    being the enclosing method of the nested class, which it is not
    (the EnclosingMethod attribute is a source-level property).

commit cf845ab
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    don't suppress field for unit-typed vals

    it affects the memory model -- even a write of unit to a field is relevant...

commit 337a9dd
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    unit-typed lazy vals should never receive a field

    this need was unmasked by test/files/run/t7843-jsr223-service.scala,
    which no longer printed the output expected from the `0 to 10 foreach`

    Currently failing tests:

     - test/files/pos/t6780.scala
     - test/files/neg/anytrait.scala
     - test/files/neg/delayed-init-ref.scala
     - test/files/neg/t562.scala
     - test/files/neg/t6276.scala
     - test/files/run/delambdafy_uncurry_byname_inline.scala
     - test/files/run/delambdafy_uncurry_byname_method.scala
     - test/files/run/delambdafy_uncurry_inline.scala
     - test/files/run/delambdafy_uncurry_method.scala
     - test/files/run/inner-obj-auto.scala
     - test/files/run/lazy-traits.scala
     - test/files/run/reify_lazyunit.scala
     - test/files/run/showraw_mods.scala
     - test/files/run/t3670.scala
     - test/files/run/t3980.scala
     - test/files/run/t4047.scala
     - test/files/run/t6622.scala
     - test/files/run/t7406.scala
     - test/files/run/t7843-jsr223-service.scala
     - test/files/jvm/innerClassAttribute
     - test/files/specialized/SI-7343.scala
     - test/files/specialized/constant_lambda.scala
     - test/files/specialized/spec-early.scala
     - test/files/specialized/spec-init.scala
     - test/files/specialized/spec-matrix-new.scala
     - test/files/specialized/spec-matrix-old.scala
     - test/files/presentation/scope-completion-3

commit b1b4e5c
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    wip: lambdalift fix

    test/files/trait-defaults/lambdalift.scala works,
    but still some related tests failing

    (note that we can't use a bootstrapped compiler yet
    due to binary incompatibility in partest)

commit eae7dac
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    update check now that trait vals can be concrete, use names not letters

    note the progression in a concrete trait val now being recognized as such
    ```
    -trait T => true
    -method $init$ => false
    -value z1 => true
    -value z2 => true // z2 is actually concrete!
    ```

commit 6555c74
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    bootstraps again by running info transform once per class...

    not sure how this ever worked, as separate compilation would transform a trait's info
    multiple times, resulting in double defs...

commit 273cb20
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    skip presuper vals in new encoding

commit 728e71e
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    incoherent cyclic references between synthesized members

    must replace old trait accessor symbols by mixed in symbols
    in the infos of the mixed in symbols

    ```
    trait T { val a: String ; val b: a.type }
    class C extends T {
      // a, b synthesized, but the a in b's type, a.type, refers to the original symbol, not the clone in C
    }
    ```

    symbols occurring in types of synthesized members
    do not get rebound to other synthesized symbols

    package <empty>#4 {
      abstract <defaultparam/trait> trait N#7352 extends scala#22.AnyRef#2378 {
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$self_$eq#15011(x$1#15012: <empty>#3.this.N#7352): scala#23.this.Unit#2340;
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$n_$eq#15013(x$1#15014: N#7352.this.self#7442.type): scala#23.this.Unit#2340;
        <method> def /*N*/$init$scala#7441(): scala#23.this.Unit#2340 = {
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> <sub_synth> def self#7442: <empty>#3.this.N#7352;
        N#7352.this.N$_setter_$self_$eq#15011(scala#22.Predef#1729.$qmark$qmark$qmark#6917);
        <method> <deferred> <stable> <accessor> <sub_synth> def n#7443: N#7352.this.self#7442.type;
        N#7352.this.N$_setter_$n_$eq#15013(N#7352.this.self#7442)
      };
      abstract class M#7353 extends scala#22.AnyRef#2378 {
        <method> <triedcooking> def <init>#13465(): <empty>#3.this.M#7353 = {
          M#7353.super.<init>scala#2719();
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> def self#13466: <empty>#3.this.N#7352;
        <method> <deferred> <stable> <accessor> def n#13467: M#7353.this.self#13466.type
      };
      class C#7354 extends M#7353 with <empty>#3.this.N#7352 {
        <method> <stable> <accessor> <triedcooking> def self#15016: <empty>#3.this.N#7352 = C#7354.this.self #15015;
        <triedcooking> private[this] val self #15015: <empty>#3.this.N#7352 = _;
        <method> <stable> <accessor> def n#15018: C#7354.this.self#7442.type = C#7354.this.n #15017;
        <triedcooking> private[this] val n #15017: C#7354.this.self#7442.type = _;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$self_$eq#15019(x$1#15021: <empty>#3.this.N#7352): scala#23.this.Unit#2340 = C#7354.this.self #15015 = x$1#15021;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$n_$eq#15022(x$1#15025: C#7354.this.self#7442.type): scala#23.this.Unit#2340 = C#7354.this.n #15017 = x$1#15025;
        <method> def <init>#14997(): <empty>#3.this.C#7354 = {
          C#7354.super.<init>#13465();
          ()
        }
      }
    }

    [running phase pickler on dependent_rebind.scala]
    [running phase refchecks on dependent_rebind.scala]
    test/files/trait-defaults/dependent_rebind.scala:16: error: overriding field n#15049 in trait N#7352 of type C#7354.this.self#15016.type;
     value n #15017 has incompatible type;
     found   : => C#7354.this.self#7442.type (with underlying type => C#7354.this.self#7442.type)
     required: => N#7352.this.self#7442.type
    class C extends M with N
          ^

    pos/t9111-inliner-workaround revealed need for:
-  override def transformInfo(sym: Symbol, tp: Type): Type = synthFieldsAndAccessors(tp)
+  override def transformInfo(sym: Symbol, tp: Type): Type = if (!sym.isJavaDefined) synthFieldsAndAccessors(tp) else tp

commit b56ca2f
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    static forwarders & private[this] val in trait

    object Properties extends PropertiesTrait

    trait PropertiesTrait {
      // the protected member is not emitted as a static member of  -- it works when dropping the access modifier
      // somehow, the module class member is considered deferred in BForwardersGen
      protected val propFilename: String = /
    }

    // [log jvm] No forwarder for 'getter propFilename' from Properties to 'module class Properties': false || m.isDeferred == true || false || false

    // the following method is missing compared to scalac
    // public final class Properties {
    //     public static String propFilename() {
    //         return Properties$.MODULE$.propFilename();
    //     }

    trait Chars {
      private[this] val char2uescapeArray = Array[Char]('\', 'u', 0, 0, 0, 0)
    }

    object Chars extends Chars

    // +++ w/reflect/scala/reflect/internal/Chars$.class
    // -  private final [C scala83014char2uescapeArray

    constant fold in forwarder for backwards compat
    constant-typed final val in trait should yield impl method

    bean{setter,getter} delegates to setter/getter (commit 1655d1b)
retronym pushed a commit that referenced this pull request Feb 12, 2016
the info-transformed of constructors:
  - traits receive trait-setters for vals
  - classes receive fields & accessors for mixed in traits

Constructors tree transformer
  - makes trees for decls added during above info transform
  - adds mixin super calls to the primary constructor

```
trait OneConcreteVal[T] {
var x = 1 // : T = ???
def foo = x
}

trait OneOtherConcreteVal[T] {
var y: T = ???
}

class C extends OneConcreteVal[Int] with OneOtherConcreteVal[String]
```

we don't have a field -- only a getter -- so,
where will we keep non-getter but-field annotations?

mixin only deals with lazy accessors/vals

do not used referenced to correlate getter/setter
it messes with paramaccessor's usage, and we don't really need it

make sure to clone info's, so we don't share symbols for method args
this manifests itself as an exception in lambdalift, finding proxies

Use NEEDS_TREES for all comms between InfoTransform and tree transform

yep, need SYNTHESIZE_IMPL_IN_SUBCLASS

distinguish accessors that should be mixed into subclass,
and those that simply need to be implemented in tree transform,
after info transform added the decl

commit 4b4932e
Author: Adriaan Moors <[email protected]>
Date:   6 days ago

    do assignment to trait fields in AddInterfaces

    regular class vals get assignments during constructors, as before

impl classes get accessors + assignments through trait setters in addinterfaces
so that constructors acts on them there,
and produced the init method in the required spot (the impl class)

bootstrapped compiler needs new partest

commit baf568d
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    produce identical bytecode for constant trait val getters

    I couldn't bring myself to emit the unused fields that we
    used to emit for constant vals, even though the getters
    immediately return the constant, and thus the field goes unused.

    In the next version, there's no need to synthesize impls
    for these in subclasses -- the getter can be implemented
    in the interface.

commit b9052da
Author: Lukas Rytz <[email protected]>
Date:   3 weeks ago

    Fix enclosing method attribute for classes nested in trait fields

    Trait fields are now created as MethodSymbol (no longer TermSymbol).
    This symbol shows up in the `originalOwner` chain of a class declared
    within the field initializer. This promoted the field getter to
    being the enclosing method of the nested class, which it is not
    (the EnclosingMethod attribute is a source-level property).

commit cf845ab
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    don't suppress field for unit-typed vals

    it affects the memory model -- even a write of unit to a field is relevant...

commit 337a9dd
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    unit-typed lazy vals should never receive a field

    this need was unmasked by test/files/run/t7843-jsr223-service.scala,
    which no longer printed the output expected from the `0 to 10 foreach`

    Currently failing tests:

     - test/files/pos/t6780.scala
     - test/files/neg/anytrait.scala
     - test/files/neg/delayed-init-ref.scala
     - test/files/neg/t562.scala
     - test/files/neg/t6276.scala
     - test/files/run/delambdafy_uncurry_byname_inline.scala
     - test/files/run/delambdafy_uncurry_byname_method.scala
     - test/files/run/delambdafy_uncurry_inline.scala
     - test/files/run/delambdafy_uncurry_method.scala
     - test/files/run/inner-obj-auto.scala
     - test/files/run/lazy-traits.scala
     - test/files/run/reify_lazyunit.scala
     - test/files/run/showraw_mods.scala
     - test/files/run/t3670.scala
     - test/files/run/t3980.scala
     - test/files/run/t4047.scala
     - test/files/run/t6622.scala
     - test/files/run/t7406.scala
     - test/files/run/t7843-jsr223-service.scala
     - test/files/jvm/innerClassAttribute
     - test/files/specialized/SI-7343.scala
     - test/files/specialized/constant_lambda.scala
     - test/files/specialized/spec-early.scala
     - test/files/specialized/spec-init.scala
     - test/files/specialized/spec-matrix-new.scala
     - test/files/specialized/spec-matrix-old.scala
     - test/files/presentation/scope-completion-3

commit b1b4e5c
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    wip: lambdalift fix

    test/files/trait-defaults/lambdalift.scala works,
    but still some related tests failing

    (note that we can't use a bootstrapped compiler yet
    due to binary incompatibility in partest)

commit eae7dac
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    update check now that trait vals can be concrete, use names not letters

    note the progression in a concrete trait val now being recognized as such
    ```
    -trait T => true
    -method $init$ => false
    -value z1 => true
    -value z2 => true // z2 is actually concrete!
    ```

commit 6555c74
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    bootstraps again by running info transform once per class...

    not sure how this ever worked, as separate compilation would transform a trait's info
    multiple times, resulting in double defs...

commit 273cb20
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    skip presuper vals in new encoding

commit 728e71e
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    incoherent cyclic references between synthesized members

    must replace old trait accessor symbols by mixed in symbols
    in the infos of the mixed in symbols

    ```
    trait T { val a: String ; val b: a.type }
    class C extends T {
      // a, b synthesized, but the a in b's type, a.type, refers to the original symbol, not the clone in C
    }
    ```

    symbols occurring in types of synthesized members
    do not get rebound to other synthesized symbols

    package <empty>#4 {
      abstract <defaultparam/trait> trait N#7352 extends scala#22.AnyRef#2378 {
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$self_$eq#15011(x$1#15012: <empty>#3.this.N#7352): scala#23.this.Unit#2340;
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$n_$eq#15013(x$1#15014: N#7352.this.self#7442.type): scala#23.this.Unit#2340;
        <method> def /*N*/$init$scala#7441(): scala#23.this.Unit#2340 = {
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> <sub_synth> def self#7442: <empty>#3.this.N#7352;
        N#7352.this.N$_setter_$self_$eq#15011(scala#22.Predef#1729.$qmark$qmark$qmark#6917);
        <method> <deferred> <stable> <accessor> <sub_synth> def n#7443: N#7352.this.self#7442.type;
        N#7352.this.N$_setter_$n_$eq#15013(N#7352.this.self#7442)
      };
      abstract class M#7353 extends scala#22.AnyRef#2378 {
        <method> <triedcooking> def <init>#13465(): <empty>#3.this.M#7353 = {
          M#7353.super.<init>scala#2719();
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> def self#13466: <empty>#3.this.N#7352;
        <method> <deferred> <stable> <accessor> def n#13467: M#7353.this.self#13466.type
      };
      class C#7354 extends M#7353 with <empty>#3.this.N#7352 {
        <method> <stable> <accessor> <triedcooking> def self#15016: <empty>#3.this.N#7352 = C#7354.this.self #15015;
        <triedcooking> private[this] val self #15015: <empty>#3.this.N#7352 = _;
        <method> <stable> <accessor> def n#15018: C#7354.this.self#7442.type = C#7354.this.n #15017;
        <triedcooking> private[this] val n #15017: C#7354.this.self#7442.type = _;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$self_$eq#15019(x$1#15021: <empty>#3.this.N#7352): scala#23.this.Unit#2340 = C#7354.this.self #15015 = x$1#15021;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$n_$eq#15022(x$1#15025: C#7354.this.self#7442.type): scala#23.this.Unit#2340 = C#7354.this.n #15017 = x$1#15025;
        <method> def <init>#14997(): <empty>#3.this.C#7354 = {
          C#7354.super.<init>#13465();
          ()
        }
      }
    }

    [running phase pickler on dependent_rebind.scala]
    [running phase refchecks on dependent_rebind.scala]
    test/files/trait-defaults/dependent_rebind.scala:16: error: overriding field n#15049 in trait N#7352 of type C#7354.this.self#15016.type;
     value n #15017 has incompatible type;
     found   : => C#7354.this.self#7442.type (with underlying type => C#7354.this.self#7442.type)
     required: => N#7352.this.self#7442.type
    class C extends M with N
          ^

    pos/t9111-inliner-workaround revealed need for:
-  override def transformInfo(sym: Symbol, tp: Type): Type = synthFieldsAndAccessors(tp)
+  override def transformInfo(sym: Symbol, tp: Type): Type = if (!sym.isJavaDefined) synthFieldsAndAccessors(tp) else tp

commit b56ca2f
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    static forwarders & private[this] val in trait

    object Properties extends PropertiesTrait

    trait PropertiesTrait {
      // the protected member is not emitted as a static member of  -- it works when dropping the access modifier
      // somehow, the module class member is considered deferred in BForwardersGen
      protected val propFilename: String = /
    }

    // [log jvm] No forwarder for 'getter propFilename' from Properties to 'module class Properties': false || m.isDeferred == true || false || false

    // the following method is missing compared to scalac
    // public final class Properties {
    //     public static String propFilename() {
    //         return Properties$.MODULE$.propFilename();
    //     }

    trait Chars {
      private[this] val char2uescapeArray = Array[Char]('\', 'u', 0, 0, 0, 0)
    }

    object Chars extends Chars

    // +++ w/reflect/scala/reflect/internal/Chars$.class
    // -  private final [C scala83014char2uescapeArray

    constant fold in forwarder for backwards compat
    constant-typed final val in trait should yield impl method

    bean{setter,getter} delegates to setter/getter (commit 1655d1b)
retronym pushed a commit that referenced this pull request Feb 17, 2016
the info-transformed of constructors:
  - traits receive trait-setters for vals
  - classes receive fields & accessors for mixed in traits

Constructors tree transformer
  - makes trees for decls added during above info transform
  - adds mixin super calls to the primary constructor

```
trait OneConcreteVal[T] {
var x = 1 // : T = ???
def foo = x
}

trait OneOtherConcreteVal[T] {
var y: T = ???
}

class C extends OneConcreteVal[Int] with OneOtherConcreteVal[String]
```

we don't have a field -- only a getter -- so,
where will we keep non-getter but-field annotations?

mixin only deals with lazy accessors/vals

do not used referenced to correlate getter/setter
it messes with paramaccessor's usage, and we don't really need it

make sure to clone info's, so we don't share symbols for method args
this manifests itself as an exception in lambdalift, finding proxies

Use NEEDS_TREES for all comms between InfoTransform and tree transform

yep, need SYNTHESIZE_IMPL_IN_SUBCLASS

distinguish accessors that should be mixed into subclass,
and those that simply need to be implemented in tree transform,
after info transform added the decl

commit 4b4932e
Author: Adriaan Moors <[email protected]>
Date:   6 days ago

    do assignment to trait fields in AddInterfaces

    regular class vals get assignments during constructors, as before

impl classes get accessors + assignments through trait setters in addinterfaces
so that constructors acts on them there,
and produced the init method in the required spot (the impl class)

bootstrapped compiler needs new partest

commit baf568d
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    produce identical bytecode for constant trait val getters

    I couldn't bring myself to emit the unused fields that we
    used to emit for constant vals, even though the getters
    immediately return the constant, and thus the field goes unused.

    In the next version, there's no need to synthesize impls
    for these in subclasses -- the getter can be implemented
    in the interface.

commit b9052da
Author: Lukas Rytz <[email protected]>
Date:   3 weeks ago

    Fix enclosing method attribute for classes nested in trait fields

    Trait fields are now created as MethodSymbol (no longer TermSymbol).
    This symbol shows up in the `originalOwner` chain of a class declared
    within the field initializer. This promoted the field getter to
    being the enclosing method of the nested class, which it is not
    (the EnclosingMethod attribute is a source-level property).

commit cf845ab
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    don't suppress field for unit-typed vals

    it affects the memory model -- even a write of unit to a field is relevant...

commit 337a9dd
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    unit-typed lazy vals should never receive a field

    this need was unmasked by test/files/run/t7843-jsr223-service.scala,
    which no longer printed the output expected from the `0 to 10 foreach`

    Currently failing tests:

     - test/files/pos/t6780.scala
     - test/files/neg/anytrait.scala
     - test/files/neg/delayed-init-ref.scala
     - test/files/neg/t562.scala
     - test/files/neg/t6276.scala
     - test/files/run/delambdafy_uncurry_byname_inline.scala
     - test/files/run/delambdafy_uncurry_byname_method.scala
     - test/files/run/delambdafy_uncurry_inline.scala
     - test/files/run/delambdafy_uncurry_method.scala
     - test/files/run/inner-obj-auto.scala
     - test/files/run/lazy-traits.scala
     - test/files/run/reify_lazyunit.scala
     - test/files/run/showraw_mods.scala
     - test/files/run/t3670.scala
     - test/files/run/t3980.scala
     - test/files/run/t4047.scala
     - test/files/run/t6622.scala
     - test/files/run/t7406.scala
     - test/files/run/t7843-jsr223-service.scala
     - test/files/jvm/innerClassAttribute
     - test/files/specialized/SI-7343.scala
     - test/files/specialized/constant_lambda.scala
     - test/files/specialized/spec-early.scala
     - test/files/specialized/spec-init.scala
     - test/files/specialized/spec-matrix-new.scala
     - test/files/specialized/spec-matrix-old.scala
     - test/files/presentation/scope-completion-3

commit b1b4e5c
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    wip: lambdalift fix

    test/files/trait-defaults/lambdalift.scala works,
    but still some related tests failing

    (note that we can't use a bootstrapped compiler yet
    due to binary incompatibility in partest)

commit eae7dac
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    update check now that trait vals can be concrete, use names not letters

    note the progression in a concrete trait val now being recognized as such
    ```
    -trait T => true
    -method $init$ => false
    -value z1 => true
    -value z2 => true // z2 is actually concrete!
    ```

commit 6555c74
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    bootstraps again by running info transform once per class...

    not sure how this ever worked, as separate compilation would transform a trait's info
    multiple times, resulting in double defs...

commit 273cb20
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    skip presuper vals in new encoding

commit 728e71e
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    incoherent cyclic references between synthesized members

    must replace old trait accessor symbols by mixed in symbols
    in the infos of the mixed in symbols

    ```
    trait T { val a: String ; val b: a.type }
    class C extends T {
      // a, b synthesized, but the a in b's type, a.type, refers to the original symbol, not the clone in C
    }
    ```

    symbols occurring in types of synthesized members
    do not get rebound to other synthesized symbols

    package <empty>#4 {
      abstract <defaultparam/trait> trait N#7352 extends scala#22.AnyRef#2378 {
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$self_$eq#15011(x$1#15012: <empty>#3.this.N#7352): scala#23.this.Unit#2340;
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$n_$eq#15013(x$1#15014: N#7352.this.self#7442.type): scala#23.this.Unit#2340;
        <method> def /*N*/$init$scala#7441(): scala#23.this.Unit#2340 = {
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> <sub_synth> def self#7442: <empty>#3.this.N#7352;
        N#7352.this.N$_setter_$self_$eq#15011(scala#22.Predef#1729.$qmark$qmark$qmark#6917);
        <method> <deferred> <stable> <accessor> <sub_synth> def n#7443: N#7352.this.self#7442.type;
        N#7352.this.N$_setter_$n_$eq#15013(N#7352.this.self#7442)
      };
      abstract class M#7353 extends scala#22.AnyRef#2378 {
        <method> <triedcooking> def <init>#13465(): <empty>#3.this.M#7353 = {
          M#7353.super.<init>scala#2719();
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> def self#13466: <empty>#3.this.N#7352;
        <method> <deferred> <stable> <accessor> def n#13467: M#7353.this.self#13466.type
      };
      class C#7354 extends M#7353 with <empty>#3.this.N#7352 {
        <method> <stable> <accessor> <triedcooking> def self#15016: <empty>#3.this.N#7352 = C#7354.this.self #15015;
        <triedcooking> private[this] val self #15015: <empty>#3.this.N#7352 = _;
        <method> <stable> <accessor> def n#15018: C#7354.this.self#7442.type = C#7354.this.n #15017;
        <triedcooking> private[this] val n #15017: C#7354.this.self#7442.type = _;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$self_$eq#15019(x$1#15021: <empty>#3.this.N#7352): scala#23.this.Unit#2340 = C#7354.this.self #15015 = x$1#15021;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$n_$eq#15022(x$1#15025: C#7354.this.self#7442.type): scala#23.this.Unit#2340 = C#7354.this.n #15017 = x$1#15025;
        <method> def <init>#14997(): <empty>#3.this.C#7354 = {
          C#7354.super.<init>#13465();
          ()
        }
      }
    }

    [running phase pickler on dependent_rebind.scala]
    [running phase refchecks on dependent_rebind.scala]
    test/files/trait-defaults/dependent_rebind.scala:16: error: overriding field n#15049 in trait N#7352 of type C#7354.this.self#15016.type;
     value n #15017 has incompatible type;
     found   : => C#7354.this.self#7442.type (with underlying type => C#7354.this.self#7442.type)
     required: => N#7352.this.self#7442.type
    class C extends M with N
          ^

    pos/t9111-inliner-workaround revealed need for:
-  override def transformInfo(sym: Symbol, tp: Type): Type = synthFieldsAndAccessors(tp)
+  override def transformInfo(sym: Symbol, tp: Type): Type = if (!sym.isJavaDefined) synthFieldsAndAccessors(tp) else tp

commit b56ca2f
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    static forwarders & private[this] val in trait

    object Properties extends PropertiesTrait

    trait PropertiesTrait {
      // the protected member is not emitted as a static member of  -- it works when dropping the access modifier
      // somehow, the module class member is considered deferred in BForwardersGen
      protected val propFilename: String = /
    }

    // [log jvm] No forwarder for 'getter propFilename' from Properties to 'module class Properties': false || m.isDeferred == true || false || false

    // the following method is missing compared to scalac
    // public final class Properties {
    //     public static String propFilename() {
    //         return Properties$.MODULE$.propFilename();
    //     }

    trait Chars {
      private[this] val char2uescapeArray = Array[Char]('\', 'u', 0, 0, 0, 0)
    }

    object Chars extends Chars

    // +++ w/reflect/scala/reflect/internal/Chars$.class
    // -  private final [C scala83014char2uescapeArray

    constant fold in forwarder for backwards compat
    constant-typed final val in trait should yield impl method

    bean{setter,getter} delegates to setter/getter (commit 1655d1b)
retronym pushed a commit that referenced this pull request Feb 18, 2016
the info-transformed of constructors:
  - traits receive trait-setters for vals
  - classes receive fields & accessors for mixed in traits

Constructors tree transformer
  - makes trees for decls added during above info transform
  - adds mixin super calls to the primary constructor

```
trait OneConcreteVal[T] {
var x = 1 // : T = ???
def foo = x
}

trait OneOtherConcreteVal[T] {
var y: T = ???
}

class C extends OneConcreteVal[Int] with OneOtherConcreteVal[String]
```

we don't have a field -- only a getter -- so,
where will we keep non-getter but-field annotations?

mixin only deals with lazy accessors/vals

do not used referenced to correlate getter/setter
it messes with paramaccessor's usage, and we don't really need it

make sure to clone info's, so we don't share symbols for method args
this manifests itself as an exception in lambdalift, finding proxies

Use NEEDS_TREES for all comms between InfoTransform and tree transform

yep, need SYNTHESIZE_IMPL_IN_SUBCLASS

distinguish accessors that should be mixed into subclass,
and those that simply need to be implemented in tree transform,
after info transform added the decl

commit 4b4932e
Author: Adriaan Moors <[email protected]>
Date:   6 days ago

    do assignment to trait fields in AddInterfaces

    regular class vals get assignments during constructors, as before

impl classes get accessors + assignments through trait setters in addinterfaces
so that constructors acts on them there,
and produced the init method in the required spot (the impl class)

bootstrapped compiler needs new partest

commit baf568d
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    produce identical bytecode for constant trait val getters

    I couldn't bring myself to emit the unused fields that we
    used to emit for constant vals, even though the getters
    immediately return the constant, and thus the field goes unused.

    In the next version, there's no need to synthesize impls
    for these in subclasses -- the getter can be implemented
    in the interface.

commit b9052da
Author: Lukas Rytz <[email protected]>
Date:   3 weeks ago

    Fix enclosing method attribute for classes nested in trait fields

    Trait fields are now created as MethodSymbol (no longer TermSymbol).
    This symbol shows up in the `originalOwner` chain of a class declared
    within the field initializer. This promoted the field getter to
    being the enclosing method of the nested class, which it is not
    (the EnclosingMethod attribute is a source-level property).

commit cf845ab
Author: Adriaan Moors <[email protected]>
Date:   3 weeks ago

    don't suppress field for unit-typed vals

    it affects the memory model -- even a write of unit to a field is relevant...

commit 337a9dd
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    unit-typed lazy vals should never receive a field

    this need was unmasked by test/files/run/t7843-jsr223-service.scala,
    which no longer printed the output expected from the `0 to 10 foreach`

    Currently failing tests:

     - test/files/pos/t6780.scala
     - test/files/neg/anytrait.scala
     - test/files/neg/delayed-init-ref.scala
     - test/files/neg/t562.scala
     - test/files/neg/t6276.scala
     - test/files/run/delambdafy_uncurry_byname_inline.scala
     - test/files/run/delambdafy_uncurry_byname_method.scala
     - test/files/run/delambdafy_uncurry_inline.scala
     - test/files/run/delambdafy_uncurry_method.scala
     - test/files/run/inner-obj-auto.scala
     - test/files/run/lazy-traits.scala
     - test/files/run/reify_lazyunit.scala
     - test/files/run/showraw_mods.scala
     - test/files/run/t3670.scala
     - test/files/run/t3980.scala
     - test/files/run/t4047.scala
     - test/files/run/t6622.scala
     - test/files/run/t7406.scala
     - test/files/run/t7843-jsr223-service.scala
     - test/files/jvm/innerClassAttribute
     - test/files/specialized/SI-7343.scala
     - test/files/specialized/constant_lambda.scala
     - test/files/specialized/spec-early.scala
     - test/files/specialized/spec-init.scala
     - test/files/specialized/spec-matrix-new.scala
     - test/files/specialized/spec-matrix-old.scala
     - test/files/presentation/scope-completion-3

commit b1b4e5c
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    wip: lambdalift fix

    test/files/trait-defaults/lambdalift.scala works,
    but still some related tests failing

    (note that we can't use a bootstrapped compiler yet
    due to binary incompatibility in partest)

commit eae7dac
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    update check now that trait vals can be concrete, use names not letters

    note the progression in a concrete trait val now being recognized as such
    ```
    -trait T => true
    -method $init$ => false
    -value z1 => true
    -value z2 => true // z2 is actually concrete!
    ```

commit 6555c74
Author: Adriaan Moors <[email protected]>
Date:   4 weeks ago

    bootstraps again by running info transform once per class...

    not sure how this ever worked, as separate compilation would transform a trait's info
    multiple times, resulting in double defs...

commit 273cb20
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    skip presuper vals in new encoding

commit 728e71e
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    incoherent cyclic references between synthesized members

    must replace old trait accessor symbols by mixed in symbols
    in the infos of the mixed in symbols

    ```
    trait T { val a: String ; val b: a.type }
    class C extends T {
      // a, b synthesized, but the a in b's type, a.type, refers to the original symbol, not the clone in C
    }
    ```

    symbols occurring in types of synthesized members
    do not get rebound to other synthesized symbols

    package <empty>#4 {
      abstract <defaultparam/trait> trait N#7352 extends scala#22.AnyRef#2378 {
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$self_$eq#15011(x$1#15012: <empty>#3.this.N#7352): scala#23.this.Unit#2340;
        <method> <deferred> <mutable> <accessor> <triedcooking> <sub_synth> def N$_setter_$n_$eq#15013(x$1#15014: N#7352.this.self#7442.type): scala#23.this.Unit#2340;
        <method> def /*N*/$init$scala#7441(): scala#23.this.Unit#2340 = {
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> <sub_synth> def self#7442: <empty>#3.this.N#7352;
        N#7352.this.N$_setter_$self_$eq#15011(scala#22.Predef#1729.$qmark$qmark$qmark#6917);
        <method> <deferred> <stable> <accessor> <sub_synth> def n#7443: N#7352.this.self#7442.type;
        N#7352.this.N$_setter_$n_$eq#15013(N#7352.this.self#7442)
      };
      abstract class M#7353 extends scala#22.AnyRef#2378 {
        <method> <triedcooking> def <init>#13465(): <empty>#3.this.M#7353 = {
          M#7353.super.<init>scala#2719();
          ()
        };
        <method> <deferred> <stable> <accessor> <triedcooking> def self#13466: <empty>#3.this.N#7352;
        <method> <deferred> <stable> <accessor> def n#13467: M#7353.this.self#13466.type
      };
      class C#7354 extends M#7353 with <empty>#3.this.N#7352 {
        <method> <stable> <accessor> <triedcooking> def self#15016: <empty>#3.this.N#7352 = C#7354.this.self #15015;
        <triedcooking> private[this] val self #15015: <empty>#3.this.N#7352 = _;
        <method> <stable> <accessor> def n#15018: C#7354.this.self#7442.type = C#7354.this.n #15017;
        <triedcooking> private[this] val n #15017: C#7354.this.self#7442.type = _;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$self_$eq#15019(x$1#15021: <empty>#3.this.N#7352): scala#23.this.Unit#2340 = C#7354.this.self #15015 = x$1#15021;
        <method> <mutable> <accessor> <triedcooking> def N$_setter_$n_$eq#15022(x$1#15025: C#7354.this.self#7442.type): scala#23.this.Unit#2340 = C#7354.this.n #15017 = x$1#15025;
        <method> def <init>#14997(): <empty>#3.this.C#7354 = {
          C#7354.super.<init>#13465();
          ()
        }
      }
    }

    [running phase pickler on dependent_rebind.scala]
    [running phase refchecks on dependent_rebind.scala]
    test/files/trait-defaults/dependent_rebind.scala:16: error: overriding field n#15049 in trait N#7352 of type C#7354.this.self#15016.type;
     value n #15017 has incompatible type;
     found   : => C#7354.this.self#7442.type (with underlying type => C#7354.this.self#7442.type)
     required: => N#7352.this.self#7442.type
    class C extends M with N
          ^

    pos/t9111-inliner-workaround revealed need for:
-  override def transformInfo(sym: Symbol, tp: Type): Type = synthFieldsAndAccessors(tp)
+  override def transformInfo(sym: Symbol, tp: Type): Type = if (!sym.isJavaDefined) synthFieldsAndAccessors(tp) else tp

commit b56ca2f
Author: Adriaan Moors <[email protected]>
Date:   6 weeks ago

    static forwarders & private[this] val in trait

    object Properties extends PropertiesTrait

    trait PropertiesTrait {
      // the protected member is not emitted as a static member of  -- it works when dropping the access modifier
      // somehow, the module class member is considered deferred in BForwardersGen
      protected val propFilename: String = /
    }

    // [log jvm] No forwarder for 'getter propFilename' from Properties to 'module class Properties': false || m.isDeferred == true || false || false

    // the following method is missing compared to scalac
    // public final class Properties {
    //     public static String propFilename() {
    //         return Properties$.MODULE$.propFilename();
    //     }

    trait Chars {
      private[this] val char2uescapeArray = Array[Char]('\', 'u', 0, 0, 0, 0)
    }

    object Chars extends Chars

    // +++ w/reflect/scala/reflect/internal/Chars$.class
    // -  private final [C scala83014char2uescapeArray

    constant fold in forwarder for backwards compat
    constant-typed final val in trait should yield impl method

    bean{setter,getter} delegates to setter/getter (commit 1655d1b)
retronym added a commit that referenced this pull request May 4, 2016
Motivation:

  - Avoid introducing public virtual methods. (javac uses private methods,
    but we prefer to make the public to support important AOT inlining
    use cases)
     - No more need for unsightly expanded names in lambda stack traces!
     - CHA in on HotSpot is great at devirtualizing, but that doesn't mean
       we *should* emit non-virtual methods as virtual so pervasively.

```
// Entering paste mode (ctrl-D to finish)

package com.acme.wizzle.wozzle; class C { def foo = () => ??? }

// Exiting paste mode, now interpreting.

scala> new com.acme.wizzle.wozzle.C().foo
res0: () => Nothing = com.acme.wizzle.wozzle.C$$Lambda$1986/43856716@100f9bbe

scala> new com.acme.wizzle.wozzle.C().foo.apply()
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:284)
  at com.acme.wizzle.wozzle.C.$anonfun$1(<pastie>:1)
  ... 30 elided

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

package p1; class StaticAllTheThings { def foo = () => ""; def bar = () => foo; def baz = () => this }

// Exiting paste mode, now interpreting.

scala> :javap -private -c p1.StaticAllTheThings
Compiled from "<pastie>"
public class p1.StaticAllTheThings {
  public scala.Function0<java.lang.String> foo();
    Code:
       0: invokedynamic #38,  0             // InvokeDynamic #0:apply:()Lscala/Function0;
       5: areturn

  public scala.Function0<scala.Function0<java.lang.String>> bar();
    Code:
       0: aload_0
       1: invokedynamic #49,  0             // InvokeDynamic #1:apply:(Lp1/StaticAllTheThings;)Lscala/Function0;
       6: areturn

  public scala.Function0<p1.StaticAllTheThings> baz();
    Code:
       0: aload_0
       1: invokedynamic #58,  0             // InvokeDynamic #2:apply:(Lp1/StaticAllTheThings;)Lscala/Function0;
       6: areturn

  public static final java.lang.String $anonfun$1();
    Code:
       0: ldc           #60                 // String
       2: areturn

  public static final scala.Function0 $anonfun$2(p1.StaticAllTheThings);
    Code:
       0: aload_0
       1: invokevirtual #63                 // Method foo:()Lscala/Function0;
       4: areturn

  public static final p1.StaticAllTheThings $anonfun$3(p1.StaticAllTheThings);
    Code:
       0: aload_0
       1: areturn

  public p1.StaticAllTheThings();
    Code:
       0: aload_0
       1: invokespecial #67                 // Method java/lang/Object."<init>":()V
       4: return

  private static java.lang.Object $deserializeLambda$(java.lang.invoke.SerializedLambda);
    Code:
       0: aload_0
       1: invokedynamic #79,  0             // InvokeDynamic #3:lambdaDeserialize:(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;
       6: areturn
}
```
retronym added a commit that referenced this pull request May 5, 2016
Motivation:

  - Avoid introducing public virtual methods. (javac uses private methods,
    but we prefer to make the public to support important AOT inlining
    use cases)
     - No more need for unsightly expanded names in lambda stack traces!
     - CHA in on HotSpot is great at devirtualizing, but that doesn't mean
       we *should* emit non-virtual methods as virtual so pervasively.

```
// Entering paste mode (ctrl-D to finish)

package com.acme.wizzle.wozzle; class C { def foo = () => ??? }

// Exiting paste mode, now interpreting.

scala> new com.acme.wizzle.wozzle.C().foo
res0: () => Nothing = com.acme.wizzle.wozzle.C$$Lambda$1986/43856716@100f9bbe

scala> new com.acme.wizzle.wozzle.C().foo.apply()
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:284)
  at com.acme.wizzle.wozzle.C.$anonfun$1(<pastie>:1)
  ... 30 elided

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

package p1; class StaticAllTheThings { def foo = () => ""; def bar = () => foo; def baz = () => this }

// Exiting paste mode, now interpreting.

scala> :javap -private -c p1.StaticAllTheThings
Compiled from "<pastie>"
public class p1.StaticAllTheThings {
  public scala.Function0<java.lang.String> foo();
    Code:
       0: invokedynamic #38,  0             // InvokeDynamic #0:apply:()Lscala/Function0;
       5: areturn

  public scala.Function0<scala.Function0<java.lang.String>> bar();
    Code:
       0: aload_0
       1: invokedynamic #49,  0             // InvokeDynamic #1:apply:(Lp1/StaticAllTheThings;)Lscala/Function0;
       6: areturn

  public scala.Function0<p1.StaticAllTheThings> baz();
    Code:
       0: aload_0
       1: invokedynamic #58,  0             // InvokeDynamic #2:apply:(Lp1/StaticAllTheThings;)Lscala/Function0;
       6: areturn

  public static final java.lang.String $anonfun$1();
    Code:
       0: ldc           #60                 // String
       2: areturn

  public static final scala.Function0 $anonfun$2(p1.StaticAllTheThings);
    Code:
       0: aload_0
       1: invokevirtual #63                 // Method foo:()Lscala/Function0;
       4: areturn

  public static final p1.StaticAllTheThings $anonfun$3(p1.StaticAllTheThings);
    Code:
       0: aload_0
       1: areturn

  public p1.StaticAllTheThings();
    Code:
       0: aload_0
       1: invokespecial #67                 // Method java/lang/Object."<init>":()V
       4: return

  private static java.lang.Object $deserializeLambda$(java.lang.invoke.SerializedLambda);
    Code:
       0: aload_0
       1: invokedynamic #79,  0             // InvokeDynamic #3:lambdaDeserialize:(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;
       6: areturn
}
```
@retronym retronym closed this Jun 2, 2016
retronym added a commit that referenced this pull request Oct 6, 2016
Manually tested with:

```
% cat sandbox/test.scala
package p {
  object X { def f(i: Int) = ??? ; def f(s: String) = ??? }
  object Main {
    val res = X.f(3.14)
  }
}

% qscalac  -Ytyper-debug sandbox/test.scala
|-- p EXPRmode-POLYmode-QUALmode (site: package <root>)
|    \-> p.type
|-- object X BYVALmode-EXPRmode (site: package p)
|    |-- super EXPRmode-POLYmode-QUALmode (silent: <init> in X)
|    |    |-- this EXPRmode (silent: <init> in X)
|    |    |    \-> p.X.type
|    |    \-> p.X.type
|    |-- def f BYVALmode-EXPRmode (site: object X)
|    |    |-- $qmark$qmark$qmark EXPRmode (site: method f in X)
|    |    |    \-> Nothing
|    |    |-- Int TYPEmode (site: value i in X)
|    |    |    \-> Int
|    |    |-- Int TYPEmode (site: value i in X)
|    |    |    \-> Int
|    |    \-> [def f] (i: Int)Nothing
|    |-- def f BYVALmode-EXPRmode (site: object X)
|    |    |-- $qmark$qmark$qmark EXPRmode (site: method f in X)
|    |    |    \-> Nothing
|    |    |-- String TYPEmode (site: value s in X)
|    |    |    [adapt] String is now a TypeTree(String)
|    |    |    \-> String
|    |    |-- String TYPEmode (site: value s in X)
|    |    |    [adapt] String is now a TypeTree(String)
|    |    |    \-> String
|    |    \-> [def f] (s: String)Nothing
|    \-> [object X] p.X.type
|-- object Main BYVALmode-EXPRmode (site: package p)
|    |-- X.f(3.14) EXPRmode (site: value res  in Main)
|    |    |-- X.f BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value res  in Main)
|    |    |    |-- X EXPRmode-POLYmode-QUALmode (silent: value res  in Main)
|    |    |    |    \-> p.X.type
|    |    |    \-> (s: String)Nothing <and> (i: Int)Nothing
|    |    |-- 3.14 BYVALmode-EXPRmode (silent: value res  in Main)
|    |    |    \-> Double(3.14)
|    |    [search #1] start `<?>`, searching for adaptation to pt=Double => String (silent: value res  in Main) implicits disabled
|    |    [search #2] start `<?>`, searching for adaptation to pt=(=> Double) => String (silent: value res  in Main) implicits disabled
|    |    [search #3] start `<?>`, searching for adaptation to pt=Double => Int (silent: value res  in Main) implicits disabled
|    |    1 implicits in companion scope
|    |    [search #4] start `<?>`, searching for adaptation to pt=(=> Double) => Int (silent: value res  in Main) implicits disabled
|    |    1 implicits in companion scope
|    |    second try: <error> and 3.14
|    |    [search #5] start `p.X.type`, searching for adaptation to pt=p.X.type => ?{def f(x$1: ? >: Double(3.14)): ?} (silent: value res  in Main) implicits disabled
|    |    [search #6] start `p.X.type`, searching for adaptation to pt=(=> p.X.type) => ?{def f(x$1: ? >: Double(3.14)): ?} (silent: value res  in Main) implicits disabled
sandbox/test.scala:4: error: overloaded method value f with alternatives:
  (s: String)Nothing <and>
  (i: Int)Nothing
 cannot be applied to (Double)
    val res = X.f(3.14)
                ^
```
retronym pushed a commit that referenced this pull request Mar 29, 2017
The following commit message is a squash of several commit messages.

- This is the 1st commit message:

Add position to stub error messages

Stub errors happen when we've started the initialization of a symbol but
key information of this symbol is missing (the information cannot be
found in any entry of the classpath not sources).

When this error happens, we better have a good error message with a
position to the place where the stub error came from. This commit goes
into this direction by adding a `pos` value to `StubSymbol` and filling
it in in all the use sites (especifically `UnPickler`).

This commit also changes some tests that test stub errors-related
issues. Concretely, `t6440` is using special Partest infrastructure and
doens't pretty print the position, while `t5148` which uses the
conventional infrastructure does. Hence the difference in the changes
for both tests.

- This is the commit message #2:

Add partest infrastructure to test stub errors

`StubErrorMessageTest` is the friend I introduce in this commit to help
state stub errors. The strategy to test them is easy and builds upon
previous concepts: we reuse `StoreReporterDirectTest` and add some
methods that will compile the code and simulate a missing classpath
entry by removing the class files from the class directory (the folder
where Scalac compiles to).

This first iteration allow us to programmatically check that stub errors
are emitted under certain conditions.

- This is the commit message #3:

Improve contents of stub error message

This commit does three things:

* Keep track of completing symbol while unpickling

  First, it removes the previous `symbolOnCompletion` definition to be
  more restrictive/clear and use only positions, since only positions are
  used to report the error (the rest of the information comes from the
  context of the `UnPickler`).

  Second, it adds a new variable called `lazyCompletingSymbol` that is
  responsible for keeping a reference to the symbol that produces the stub
  error. This symbol will usually (always?) come from the classpath
  entries and therefore we don't have its position (that's why we keep
  track of `symbolOnCompletion` as well). This is the one that we have to
  explicitly use in the stub error message, the culprit so to speak.

  Aside from these two changes, this commit modifies the existing tests
  that are affected by the change in the error message, which is more
  precise now, and adds new tests for stub errors that happen in complex
  inner cases and in return type of `MethodType`.

* Check that order of initialization is correct

  With the changes introduced previously to keep track of position of
  symbols coming from source files, we may ask ourselves: is this going to
  work always? What happens if two symbols the initialization of two
  symbols is intermingled and the stub error message gets the wrong
  position?

  This commit adds a test case and modifications to the test
  infrastructure to double check empirically that this does not happen.
  Usually, this interaction in symbol initialization won't happen because
  the `UnPickler` will lazily load all the buckets necessary for a symbol
  to be truly initialized, with the pertinent addresses from which this
  information has to be deserialized. This ensures that this operation is
  atomic and no other symbol initialization can happen in the meantime.

  Even though the previous paragraph is the feeling I got from reading the
  sources, this commit creates a test to double-check it. My attempt to be
  better safe than sorry.

* Improve contents of the stub error message

  This commit modifies the format of the previous stub error message by
  being more precise in its formulation. It follows the structured format:

  ```
  s"""|Symbol '${name.nameKind} ${owner.fullName}.$name' is missing from the classpath.
      |This symbol is required by '${lazyCompletingSymbol.kindString} ${lazyCompletingSymbol.fullName}'.
  ```

  This format has the advantage that is more readable and explicit on
  what's happening. First, we report what is missing. Then, why it was
  required. Hopefully, people working on direct dependencies will find the
  new message friendlier.

Having a good test suite to check the previously added code is
important. This commit checks that stub errors happen in presence of
well-known and widely used Scala features. These include:

* Higher kinded types.
* Type definitions.
* Inheritance and subclasses.
* Typeclasses and implicits.

- This is the commit message #4:

Use `lastTreeToTyper` to get better positions

The previous strategy to get the last user-defined position for knowing
what was the root cause (the trigger) of stub errors relied on
instrumenting `def info`.

This instrumentation, while easy to implement, is inefficient since we
register the positions for symbols that are already completed.

However, we cannot do it only for uncompleted symbols (!hasCompleteInfo)
because the positions won't be correct anymore -- definitions using stub
symbols (val b = new B) are for the compiler completed, but their use
throws stub errors. This means that if we initialize symbols between a
definition and its use, we'll use their positions instead of the
position of `b`.

To work around this we use `lastTreeToTyper`. We assume that stub errors
will be thrown by Typer at soonest.

The benefit of this approach is better error messages. The positions
used in them are now as concrete as possible since they point to the
exact tree that **uses** a symbol, instead of the one that **defines**
it. Have a look at `StubErrorComplexInnerClass` for an example.

This commit removes the previous infrastructure and replaces it by the
new one. It also removes the fields positions from the subclasses of
`StubSymbol`s.

- This is the commit message #5:

Keep track of completing symbols

Make sure that cycles don't happen by keeping track of all the
symbols that are being completed by `completeInternal`. Stub errors only
need the last completing symbols, but the whole stack of symbols may
be useful to reporting other error like cyclic initialization issues.

I've added this per Jason's suggestion. I've implemented with a list
because `remove` in an array buffer is linear. Array was not an option
because I would need to resize it myself. I think that even though list
is not as efficient memory-wise, it probably doesn't matter since the
stack will usually be small.

- This is the commit message #6:

Remove `isPackage` from `newStubSymbol`

Remove `isPackage` since in 2.12.x its value is not used.
retronym pushed a commit that referenced this pull request Apr 18, 2017
The following commit message is a squash of several commit messages.

- This is the 1st commit message:

Add position to stub error messages

Stub errors happen when we've started the initialization of a symbol but
key information of this symbol is missing (the information cannot be
found in any entry of the classpath not sources).

When this error happens, we better have a good error message with a
position to the place where the stub error came from. This commit goes
into this direction by adding a `pos` value to `StubSymbol` and filling
it in in all the use sites (especifically `UnPickler`).

This commit also changes some tests that test stub errors-related
issues. Concretely, `t6440` is using special Partest infrastructure and
doens't pretty print the position, while `t5148` which uses the
conventional infrastructure does. Hence the difference in the changes
for both tests.

- This is the commit message #2:

Add partest infrastructure to test stub errors

`StubErrorMessageTest` is the friend I introduce in this commit to help
state stub errors. The strategy to test them is easy and builds upon
previous concepts: we reuse `StoreReporterDirectTest` and add some
methods that will compile the code and simulate a missing classpath
entry by removing the class files from the class directory (the folder
where Scalac compiles to).

This first iteration allow us to programmatically check that stub errors
are emitted under certain conditions.

- This is the commit message #3:

Improve contents of stub error message

This commit does three things:

* Keep track of completing symbol while unpickling

  First, it removes the previous `symbolOnCompletion` definition to be
  more restrictive/clear and use only positions, since only positions are
  used to report the error (the rest of the information comes from the
  context of the `UnPickler`).

  Second, it adds a new variable called `lazyCompletingSymbol` that is
  responsible for keeping a reference to the symbol that produces the stub
  error. This symbol will usually (always?) come from the classpath
  entries and therefore we don't have its position (that's why we keep
  track of `symbolOnCompletion` as well). This is the one that we have to
  explicitly use in the stub error message, the culprit so to speak.

  Aside from these two changes, this commit modifies the existing tests
  that are affected by the change in the error message, which is more
  precise now, and adds new tests for stub errors that happen in complex
  inner cases and in return type of `MethodType`.

* Check that order of initialization is correct

  With the changes introduced previously to keep track of position of
  symbols coming from source files, we may ask ourselves: is this going to
  work always? What happens if two symbols the initialization of two
  symbols is intermingled and the stub error message gets the wrong
  position?

  This commit adds a test case and modifications to the test
  infrastructure to double check empirically that this does not happen.
  Usually, this interaction in symbol initialization won't happen because
  the `UnPickler` will lazily load all the buckets necessary for a symbol
  to be truly initialized, with the pertinent addresses from which this
  information has to be deserialized. This ensures that this operation is
  atomic and no other symbol initialization can happen in the meantime.

  Even though the previous paragraph is the feeling I got from reading the
  sources, this commit creates a test to double-check it. My attempt to be
  better safe than sorry.

* Improve contents of the stub error message

  This commit modifies the format of the previous stub error message by
  being more precise in its formulation. It follows the structured format:

  ```
  s"""|Symbol '${name.nameKind} ${owner.fullName}.$name' is missing from the classpath.
      |This symbol is required by '${lazyCompletingSymbol.kindString} ${lazyCompletingSymbol.fullName}'.
  ```

  This format has the advantage that is more readable and explicit on
  what's happening. First, we report what is missing. Then, why it was
  required. Hopefully, people working on direct dependencies will find the
  new message friendlier.

Having a good test suite to check the previously added code is
important. This commit checks that stub errors happen in presence of
well-known and widely used Scala features. These include:

* Higher kinded types.
* Type definitions.
* Inheritance and subclasses.
* Typeclasses and implicits.

- This is the commit message #4:

Use `lastTreeToTyper` to get better positions

The previous strategy to get the last user-defined position for knowing
what was the root cause (the trigger) of stub errors relied on
instrumenting `def info`.

This instrumentation, while easy to implement, is inefficient since we
register the positions for symbols that are already completed.

However, we cannot do it only for uncompleted symbols (!hasCompleteInfo)
because the positions won't be correct anymore -- definitions using stub
symbols (val b = new B) are for the compiler completed, but their use
throws stub errors. This means that if we initialize symbols between a
definition and its use, we'll use their positions instead of the
position of `b`.

To work around this we use `lastTreeToTyper`. We assume that stub errors
will be thrown by Typer at soonest.

The benefit of this approach is better error messages. The positions
used in them are now as concrete as possible since they point to the
exact tree that **uses** a symbol, instead of the one that **defines**
it. Have a look at `StubErrorComplexInnerClass` for an example.

This commit removes the previous infrastructure and replaces it by the
new one. It also removes the fields positions from the subclasses of
`StubSymbol`s.

- This is the commit message #5:

Keep track of completing symbols

Make sure that cycles don't happen by keeping track of all the
symbols that are being completed by `completeInternal`. Stub errors only
need the last completing symbols, but the whole stack of symbols may
be useful to reporting other error like cyclic initialization issues.

I've added this per Jason's suggestion. I've implemented with a list
because `remove` in an array buffer is linear. Array was not an option
because I would need to resize it myself. I think that even though list
is not as efficient memory-wise, it probably doesn't matter since the
stack will usually be small.

- This is the commit message #6:

Remove `isPackage` from `newStubSymbol`

Remove `isPackage` since in 2.12.x its value is not used.
retronym pushed a commit that referenced this pull request Mar 27, 2018
retronym added a commit that referenced this pull request Sep 21, 2018
```
/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/bin/java -Xmx1G -Xss1M "-javaagent:/Users/jz/Library/Application Support/JetBrains/Toolbox/apps/IDEA-U/ch-0/183.2407.10/IntelliJ IDEA 2018.3 EAP.app/Contents/lib/idea_rt.jar=60195:/Users/jz/Library/Application Support/JetBrains/Toolbox/apps/IDEA-U/ch-0/183.2407.10/IntelliJ IDEA 2018.3 EAP.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/tools.jar:/Users/jz/code/scala/build/quick/classes/compiler:/Users/jz/code/scala/build/quick/classes/library:/Users/jz/code/scala/build/quick/classes/reflect:/Users/jz/.ivy2/cache/org.apache.ant/ant/jars/ant-1.9.4.jar:/Users/jz/.ivy2/cache/org.apache.ant/ant-launcher/jars/ant-launcher-1.9.4.jar:/Users/jz/.ivy2/cache/org.scala-lang.modules/scala-asm/bundles/scala-asm-6.2.0-scala-2.jar:/Users/jz/.ivy2/cache/org.scala-lang.modules/scala-xml_2.12/bundles/scala-xml_2.12-1.0.6.jar:/Users/jz/.ivy2/cache/jline/jline/jars/jline-2.14.6.jar scala.tools.nsc.PipelineMain /code/scala-2.12.x/target/compiler/compile.args /code/scala-2.12.x/target/interactive/compile.args /code/scala-2.12.x/target/library/compile.args /code/scala-2.12.x/target/partest-extras/compile.args /code/scala-2.12.x/target/reflect/compile.args /code/scala-2.12.x/target/repl-jline/compile.args /code/scala-2.12.x/target/repl/compile.args /code/scala-2.12.x/target/scaladoc/compile.args /code/scala-2.12.x/target/scalap/compile.args
Round #1: /code/scala-2.12.x/target/library/compile.args
warning: there were 37 deprecation warnings (since 2.10.0)
warning: there were 24 deprecation warnings (since 2.11.0)
warning: there were 46 deprecation warnings (since 2.12.0)
warning: there were 107 deprecation warnings in total; re-run with -deprecation for details
four warnings found
Round #2: /code/scala-2.12.x/target/reflect/compile.args
warning: there was one deprecation warning
warning: there were three deprecation warnings (since 2.10.0)
warning: there were four deprecation warnings (since 2.10.1)
warning: there were 17 deprecation warnings (since 2.11.0)
warning: there were 15 deprecation warnings (since 2.12.0)
warning: there were 40 deprecation warnings in total; re-run with -deprecation for details
warning: there were four unchecked warnings; re-run with -unchecked for details
7 warnings found
Round #3: /code/scala-2.12.x/target/compiler/compile.args
warning: there were two deprecation warnings
warning: there were 12 deprecation warnings (since 2.10.0)
warning: there were 55 deprecation warnings (since 2.11.0)
warning: there were three deprecation warnings (since 2.11.2)
warning: there were 26 deprecation warnings (since 2.12.0)
warning: there was one deprecation warning (since 2.12.4)
warning: there was one deprecation warning (since 2.12.5)
warning: there were three deprecation warnings (since 2.12.7)
warning: there were 103 deprecation warnings in total; re-run with -deprecation for details
warning: there were 31 unchecked warnings; re-run with -unchecked for details
warning: there were 6 feature warnings; re-run with -feature for details
Round #4: /code/scala-2.12.x/target/interactive/compile.args
11 warnings found
warning: there were four deprecation warnings (since 2.11.0)
Round #4: /code/scala-2.12.x/target/scaladoc/compile.args
warning: there was one deprecation warning (since 2.12.0)
warning: there were 5 deprecation warnings in total; re-run with -deprecation for details
warning: there were two unchecked warnings; re-run with -unchecked for details
four warnings found
Round #4: /code/scala-2.12.x/target/scalap/compile.args
warning: there were two deprecation warnings (since 2.12.0); re-run with -deprecation for details
warning: there were two unchecked warnings; re-run with -unchecked for details
two warnings found
warning: there was one deprecation warning (since 2.12.0); re-run with -deprecation for details
Round #5: /code/scala-2.12.x/target/repl/compile.args
one warning found
warning: there were 10 deprecation warnings (since 2.11.0)
Round #6: /code/scala-2.12.x/target/repl-jline/compile.args
warning: there were three deprecation warnings (since 2.12.0)
warning: there was one deprecation warning (since 2.9.0)
warning: there were 14 deprecation warnings in total; re-run with -deprecation for details
four warnings found
Round #7: /code/scala-2.12.x/target/partest-extras/compile.args

```
retronym added a commit that referenced this pull request Sep 21, 2018
```
/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/bin/java -Xmx1G -Xss1M "-javaagent:/Users/jz/Library/Application Support/JetBrains/Toolbox/apps/IDEA-U/ch-0/183.2407.10/IntelliJ IDEA 2018.3 EAP.app/Contents/lib/idea_rt.jar=60195:/Users/jz/Library/Application Support/JetBrains/Toolbox/apps/IDEA-U/ch-0/183.2407.10/IntelliJ IDEA 2018.3 EAP.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/tools.jar:/Users/jz/code/scala/build/quick/classes/compiler:/Users/jz/code/scala/build/quick/classes/library:/Users/jz/code/scala/build/quick/classes/reflect:/Users/jz/.ivy2/cache/org.apache.ant/ant/jars/ant-1.9.4.jar:/Users/jz/.ivy2/cache/org.apache.ant/ant-launcher/jars/ant-launcher-1.9.4.jar:/Users/jz/.ivy2/cache/org.scala-lang.modules/scala-asm/bundles/scala-asm-6.2.0-scala-2.jar:/Users/jz/.ivy2/cache/org.scala-lang.modules/scala-xml_2.12/bundles/scala-xml_2.12-1.0.6.jar:/Users/jz/.ivy2/cache/jline/jline/jars/jline-2.14.6.jar scala.tools.nsc.PipelineMain /code/scala-2.12.x/target/compiler/compile.args /code/scala-2.12.x/target/interactive/compile.args /code/scala-2.12.x/target/library/compile.args /code/scala-2.12.x/target/partest-extras/compile.args /code/scala-2.12.x/target/reflect/compile.args /code/scala-2.12.x/target/repl-jline/compile.args /code/scala-2.12.x/target/repl/compile.args /code/scala-2.12.x/target/scaladoc/compile.args /code/scala-2.12.x/target/scalap/compile.args
Round #1: /code/scala-2.12.x/target/library/compile.args
warning: there were 37 deprecation warnings (since 2.10.0)
warning: there were 24 deprecation warnings (since 2.11.0)
warning: there were 46 deprecation warnings (since 2.12.0)
warning: there were 107 deprecation warnings in total; re-run with -deprecation for details
four warnings found
Round #2: /code/scala-2.12.x/target/reflect/compile.args
warning: there was one deprecation warning
warning: there were three deprecation warnings (since 2.10.0)
warning: there were four deprecation warnings (since 2.10.1)
warning: there were 17 deprecation warnings (since 2.11.0)
warning: there were 15 deprecation warnings (since 2.12.0)
warning: there were 40 deprecation warnings in total; re-run with -deprecation for details
warning: there were four unchecked warnings; re-run with -unchecked for details
7 warnings found
Round #3: /code/scala-2.12.x/target/compiler/compile.args
warning: there were two deprecation warnings
warning: there were 12 deprecation warnings (since 2.10.0)
warning: there were 55 deprecation warnings (since 2.11.0)
warning: there were three deprecation warnings (since 2.11.2)
warning: there were 26 deprecation warnings (since 2.12.0)
warning: there was one deprecation warning (since 2.12.4)
warning: there was one deprecation warning (since 2.12.5)
warning: there were three deprecation warnings (since 2.12.7)
warning: there were 103 deprecation warnings in total; re-run with -deprecation for details
warning: there were 31 unchecked warnings; re-run with -unchecked for details
warning: there were 6 feature warnings; re-run with -feature for details
Round #4: /code/scala-2.12.x/target/interactive/compile.args
11 warnings found
warning: there were four deprecation warnings (since 2.11.0)
Round #4: /code/scala-2.12.x/target/scaladoc/compile.args
warning: there was one deprecation warning (since 2.12.0)
warning: there were 5 deprecation warnings in total; re-run with -deprecation for details
warning: there were two unchecked warnings; re-run with -unchecked for details
four warnings found
Round #4: /code/scala-2.12.x/target/scalap/compile.args
warning: there were two deprecation warnings (since 2.12.0); re-run with -deprecation for details
warning: there were two unchecked warnings; re-run with -unchecked for details
two warnings found
warning: there was one deprecation warning (since 2.12.0); re-run with -deprecation for details
Round #5: /code/scala-2.12.x/target/repl/compile.args
one warning found
warning: there were 10 deprecation warnings (since 2.11.0)
Round #6: /code/scala-2.12.x/target/repl-jline/compile.args
warning: there were three deprecation warnings (since 2.12.0)
warning: there was one deprecation warning (since 2.9.0)
warning: there were 14 deprecation warnings in total; re-run with -deprecation for details
four warnings found
Round #7: /code/scala-2.12.x/target/partest-extras/compile.args
```
retronym pushed a commit that referenced this pull request Jun 24, 2019
* origin/2.10.x:
  SI-6089 pt2: _ is tailpos in `_ || _` and `_ && _`
  Linked the PR policy in the README file.
  Scaladoc: Removing forgotten debugging info
  address "this would catch all throwables" warnings
  SI-1832 consistent symbols in casedef's pattern&body
  SIP-14 - Fix critical Java compatibility issue in scala.concurrent.Await
  Removes redundant outers
  Use `findMember` to lookup the static field in the host class.
  update docs for (partial) fun synth in uncurry
  SI-5999 a real fix to the packageless problem
  evicts calls to reify from our codebase
  an improvement based on Adriaan's comment
  SI-6031 customizable budget for patmat analyses
  SI-5739 address @retronym's feedback, more docs
  SI-5999 staticXXX is now friendly to packageless
  SI-5949 updates documentation of staticClass
  SI-5999 removes the macro context mirror
  more meaningful name for a missing hook method
  SI-5999 deploys a new starr
  SI-5999 removes Context.reify
  improves docs of scala.reflect.api.Mirrors
  SI-5984 improves error reporting in JavaMirrors
  SI-4897 derive expected value from single type
  Switch to 1.6 target for all javac invocations.
  Clean ups in impl.Future
  Critical bugfixes/leak fixes/API corrections + ScalaDoc for SIP-14
  Print the stack trace.
  Deprecate all JVM 1.5 targets and make 1.6 default.
  Shield from InterruptedException in partest.
  Scaladoc: Adressed @hubertp's comment on scala#925
  SI-5784 Scaladoc: Type templates
  Scaladoc: Groups
  Better debugging output in GenASM.
  Updated list of targets allowed in Ant's scalac.
  WIP add private/lazy checks and a few tests.
  Removes Float.Epsilon and Double.Epsilon
  SI-5939 resident compilation of sources in empty package
  Scaladoc: Typers change
  SI-6104 support This pattern
  Make  field strict and private.
  Implement @static annotation on singleton object fields.
  Fixed SI-6092. Fixed leaky annotations, and relaxed the conditions under which a try-catch is lifted out to an inner method.
  Fix SI-5937.
  SI-6089 better tail position analysis for matches
  SI-5695 removes Context.enclosingApplication
  SI-5892 allow implicit views in annotation args
  SI-5739 store sub-patterns in local vals
  changes error message generated by compiler
  SI-5856 enables use of $this in string interpolation
  SI-5895 fixes FieldMirrors
  SI-5784 Scaladoc: {Abstract,Alias} type templates
  test case closes SI-6047
  Fix for SI-5385.
  SI-6086 magic symbols strike back
  Scaladoc: Refactoring the entities
  SI-5533 Skip scaladoc packages from documentation
  Scaladoc: updated type class descriptions
  Scaladoc: Reducing the memory footprint 2
  Scaladoc: Reducing the memory footprint
  SI-3695 SI-4224 SI-4497 SI-5079 scaladoc links
  SI-4887 Link existentials in scaladoc
  Scaladoc minor fix: Typos in diagrams
  SI-4360 Adds prefixes to scaladoc
  Scaladoc: workaround for untypical Map usecases
  SI-4324 Scaladoc case class argument currying
  SI-5558 Package object members indexing
  SI-5965 Scaladoc crash
  Scaladoc: Inherited templates in diagrams
  SI-3314 SI-4888 Scaladoc: Relative type prefixes
  SI-5235 Correct usecase variable expansion
  Variation #10 to optimze findMember
  Attempt #9 to opimize findMember.
  Attempt #8 to opimize findMember.
  Attempty #7 to optimize findMember
  Fixing problem that caused fingerprints to fail in reflection. Also fixed test case that failed when moving to findMembers. Avoids similar problems in the future by renaming nme.ANYNAME
  Attemmpt #6 to optimize findMember
  Attempt #5 to optimize findMember.
  Attempt #4 to optimize findMember
  Attempt #3 to optimize findMember
  Attempt #2 to optimize findMember
  Attempt #1 to optimize findMember

Conflicts:
	test/files/run/existentials-in-compiler.scala
retronym pushed a commit that referenced this pull request Jun 24, 2019
First of all, GIL should only apply to runtime reflection, because noone
is going to run toolboxes in multiple threads: a) that's impossible, b/c
the compiler isn't thread safe, b) ToolBox api prevents that.

Secondly, the only things in symbols which require synchronization are:
1) info/validTo (completers aren't thread-safe),
2) rawInfo and its dependencies (it shares a mutable field with info)
3) non-trivial caches like in typeAsMemberOfLock

If you think about it, other things like sourceModule or associatedFile
don't need synchronization, because they are either set up when a symbol
is created or cloned or when it's completed. The former is obviously safe,
while the latter is safe as well, because before acquiring init-dependent
state of symbols, the compiler calls `initialize`, which is synchronized.

We can say that symbols can be in four possible states: 1) being created,
2) created, but not yet initialized, 3) initializing, 4) initialized.
in runtime reflection can undergo is init. #3 is dangerous and needs protection
retronym pushed a commit that referenced this pull request Jun 24, 2019
First of all, GIL should only apply to runtime reflection, because noone
is going to run toolboxes in multiple threads: a) that's impossible, b/c
the compiler isn't thread safe, b) ToolBox api prevents that.

Secondly, the only things in symbols which require synchronization are:
1) info/validTo (completers aren't thread-safe),
2) rawInfo and its dependencies (it shares a mutable field with info)
3) non-trivial caches like in typeAsMemberOfLock

If you think about it, other things like sourceModule or associatedFile
don't need synchronization, because they are either set up when a symbol
is created or cloned or when it's completed.

We can say that symbols can be in four possible states: 1) being created,
2) created, but not yet initialized, 3) initializing, 4) initialized.
single thread. #2 and #4 don't need synchronization either, because the
only mutation symbols in runtime reflection can undergo is init. #3 is
dangerous and needs protection.
retronym pushed a commit that referenced this pull request Jun 24, 2019
First of all, GIL should only apply to runtime reflection, because noone
is going to run toolboxes in multiple threads: a) that's impossible, b/c
the compiler isn't thread safe, b) ToolBox api prevents that.

Secondly, the only things in symbols which require synchronization are:
1) info/validTo (completers aren't thread-safe),
2) rawInfo and its dependencies (it shares a mutable field with info)
3) non-trivial caches like in typeAsMemberOfLock

If you think about it, other things like sourceModule or associatedFile
don't need synchronization, because they are either set up when a symbol
is created or cloned or when it's completed.

We can say that symbols can be in four possible states: 1) being created,
2) created, but not yet initialized, 3) initializing, 4) initialized.
single thread. #2 and #4 don't need synchronization either, because the
only mutation symbols in runtime reflection can undergo is init. #3 is
dangerous and needs protection.
retronym pushed a commit that referenced this pull request Jun 24, 2019
Fixed fingerPrinting scheme to work with rehashes, also added finger prints to typedIdent searches.
retronym pushed a commit that referenced this pull request Jun 24, 2019
SubScript Actors basic implementation
retronym pushed a commit that referenced this pull request Jun 24, 2019
retronym pushed a commit that referenced this pull request Jun 24, 2019
As discussed a couple weeks ago, submitting this to formalize the hacks
that I used in macro paradise for 2.10, so that it continues working
after possible refactorings in 2.11.

One of the strategies to implement this would be to make a list of
functions overridden by the plugin and then to reuse the analyzer
plugins architecture to introduce them as hooks. However:
1) The list is quite big and disparate (Namers.enterSym,
Namers.ensureCompanionObject, Typers.reallyExists, Typers.typed1,
Typers.typedTemplate, Typers.typedBlock, Typers.typedClassDef).
2) The list doesn't correspond to the spirit of analyzer plugins that
modify return types of namer/typer functions rather than override them.
3) There's no guarantee that later on paradise won't need to override
additional functionality of namer/typer, requiring new hacks.

Another strategy lets plugins suggest their own analyzers to the compiler.
It enables augmenting namer/typer with arbitrary functionality, providing
ultimate flexibility. Shortcomings:
1) If multiple plugins want to install their own analyzers, it won't work
(but such situations can be detected and meaningful errors can be reported).
One can argue though, that even if we provided finer-grained API for
such plugins, it wouldn't work anyway, because e.g. it's hard to imagine
several plugins robustly applying their modifications to Namers.enterSym.

None of the outlined two strategies is ideal, however, the second one
makes more sense to me, because shortcoming #3 of the first one seems to
defeat the idea of introducing the hooks into the compiler in the first place.
Therefore this patch implements the second strategy.
retronym pushed a commit that referenced this pull request Jun 24, 2019
When an application of a blackbox macro is used as an implicit candidate,
no expansion is performed until the macro is selected as the result of
the implicit search.

This makes it impossible to dynamically calculate availability of
implicit macros.
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.

3 participants