Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

trait lazy val with path-dependent type should not crash during fields #219

Closed
adriaanm opened this issue Sep 8, 2016 · 2 comments
Closed
Milestone

Comments

@adriaanm
Copy link
Contributor

adriaanm commented Sep 8, 2016

class Global { class Name }

trait CommonPrintUtils {
  val global: Global 
  import global._

  lazy val precedence: Name => Int = ???
}

trait CompilerProvider {
  val global: Global = ???
}

class AbstractPrinter extends CommonPrintUtils with CompilerProvider 

Crashes with (under -uniqid -Ydebug ):

error: scala.reflect.internal.Types$TypeError: type mismatch;
 found   : scala#25.this.Function1#1283[AbstractPrinter#6560.this.global#14333.Name#6687,scala#25.this.Int#929]
 required: scala#25.this.Function1#1283[AbstractPrinter#6560.this.global#14238.Name#6687,scala#25.this.Int#929]

[...]
    at scala.tools.nsc.transform.Fields$FieldsTransformer.typedPos(Fields.scala:511)
    at scala.tools.nsc.transform.AccessorSynthesis$CheckedAccessorTreeSynthesis$SynthLazyAccessorsIn.$anonfun$expandLazyClassMember$5(AccessorSynthesis.scala:356)
    at scala.tools.nsc.transform.AccessorSynthesis$CheckedAccessorTreeSynthesis$SynthLazyAccessorsIn.$anonfun$expandLazyClassMember$4(AccessorSynthesis.scala:356)
    at scala.tools.nsc.transform.AccessorSynthesis$CheckedAccessorTreeSynthesis$SynthLazyAccessorsIn.expandLazyClassMember(AccessorSynthesis.scala:356)
    at scala.tools.nsc.transform.Fields$FieldsTransformer.superLazy$1(Fields.scala:636)
    at scala.tools.nsc.transform.Fields$FieldsTransformer.$anonfun$fieldsAndAccessors$3(Fields.scala:641)
    at scala.tools.nsc.transform.Fields$FieldsTransformer.fieldsAndAccessors(Fields.scala:639)
@adriaanm adriaanm added this to the 2.12.0-RC2 milestone Sep 8, 2016
@adriaanm
Copy link
Contributor Author

adriaanm commented Sep 8, 2016

Somehow the global in CommonPrintUtils and CompilerProvider give rise to different singleton types when type checking AbstractPrinter.this.precedence = AbstractPrinter.super.precedence(); in AbstractPrinter

The expected tree at fields would look something like:

  trait CommonPrintUtils extends Object {
    <stable> <accessor> def global(): Global;
    <stable> <accessor> lazy <sub_synth> def precedence(): global.Name => Int = scala.Predef.???()
  }

  abstract trait CompilerProvider extends Object with CommonPrintUtils {
    <accessor> <sub_synth> protected[this] def CompilerProvider$_setter_$global_=(x$1: Global): Unit;
    <stable> <accessor> <sub_synth> def global(): Global = scala.Predef.???()
  }

  class AbstractPrinter extends Object with CompilerProvider {
    override <stable> <accessor> def global(): Global = AbstractPrinter.this.global;
    private[this] val global: Global = _;
    override <accessor> protected[this] def CompilerProvider$_setter_$global_=(x$1: Global): Unit = AbstractPrinter.this.global = x$1;
    final <synthetic> lazy private[this] var precedence: global.Name => Int = _;
    private def precedence$lzycompute(): global.Name => Int = {
      AbstractPrinter.this.synchronized[Unit](if (AbstractPrinter.this.bitmap$0.unary_!())
        {
          AbstractPrinter.this.precedence = AbstractPrinter.super.precedence();
          AbstractPrinter.this.bitmap$0 = true
        });
      AbstractPrinter.this.precedence
    };

    override <stable> <accessor> lazy def precedence(): global.Name => Int = 
      if (AbstractPrinter.this.bitmap$0.unary_!())  AbstractPrinter.this.precedence$lzycompute()
      else AbstractPrinter.this.precedence;

    @volatile private[this] var bitmap$0: Boolean = _;
  }

@adriaanm
Copy link
Contributor Author

adriaanm commented Sep 8, 2016

Current hypo: the type of the lazy var is determined when the global accessor has not yet been created in AbstractPrinter, and thus the CompilerProvider's accessor is used. When we're mixing in the impl of precedence$lzycompute in AbstractPrinter, the RHS of the assignment will type check to a type that does see the overridden accessor for global in AbstractPrinter

adriaanm added a commit to adriaanm/scala that referenced this issue Sep 8, 2016
The info of the var that stores a trait's lazy val's computed value
is expressed in terms of symbols that exist before the fields phase.
When we're implementing the lazy val in a subclass of that trait,
we now see symbols created by the fields phase, which results
in mismatches between the types of the lhs and rhs in the assignment
of `lazyVar = super.lazyImpl`.

So, type check the super-call to the trait's lazy accessor before our
own phase. If the lazy var's info depends on a val that is now
implemented by an accessor synthesize by our info transformer,
we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`,
unless we also run before our own phase (like when we were
creating the info for the lazy var).

This was revealed by Hanns Holger Rutz's efforts in compiling
scala-refactoring's test suite (reported on scala-internals).

Fixes scala/scala-dev#219
adriaanm added a commit to adriaanm/scala that referenced this issue Sep 26, 2016
The info of the var that stores a trait's lazy val's computed value
is expressed in terms of symbols that exist before the fields phase.
When we're implementing the lazy val in a subclass of that trait,
we now see symbols created by the fields phase, which results
in mismatches between the types of the lhs and rhs in the assignment
of `lazyVar = super.lazyImpl`.

So, type check the super-call to the trait's lazy accessor before our
own phase. If the lazy var's info depends on a val that is now
implemented by an accessor synthesize by our info transformer,
we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`,
unless we also run before our own phase (like when we were
creating the info for the lazy var).

This was revealed by Hanns Holger Rutz's efforts in compiling
scala-refactoring's test suite (reported on scala-internals).

Fixes scala/scala-dev#219
retronym pushed a commit to retronym/scala that referenced this issue Sep 28, 2016
The info of the var that stores a trait's lazy val's computed value
is expressed in terms of symbols that exist before the fields phase.
When we're implementing the lazy val in a subclass of that trait,
we now see symbols created by the fields phase, which results
in mismatches between the types of the lhs and rhs in the assignment
of `lazyVar = super.lazyImpl`.

So, type check the super-call to the trait's lazy accessor before our
own phase. If the lazy var's info depends on a val that is now
implemented by an accessor synthesize by our info transformer,
we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`,
unless we also run before our own phase (like when we were
creating the info for the lazy var).

This was revealed by Hanns Holger Rutz's efforts in compiling
scala-refactoring's test suite (reported on scala-internals).

Fixes scala/scala-dev#219
retronym added a commit to retronym/scala that referenced this issue Nov 17, 2016
In the same manner as scala/scala-dev#219, the placement of the fields
phase after uncurry is presenting some challenges in keeping our trees
type correct.

This commit whacks a few more moles by adding a casts in the body of
synthetic methods.
retronym added a commit to retronym/scala that referenced this issue Nov 17, 2016
In the same manner as scala/scala-dev#219, the placement of the fields
phase after uncurry is presenting some challenges in keeping our trees
type correct.

This commit whacks a few more moles by adding a casts in the body of
synthetic methods.
retronym added a commit to retronym/scala that referenced this issue Nov 17, 2016
In the same manner as scala/scala-dev#219, the placement of the fields
phase after uncurry is presenting some challenges in keeping our trees
type correct.

This commit whacks a few more moles by adding a casts in the body of
synthetic methods.

Fixes scala/scala-dev#268
retronym added a commit to retronym/scala that referenced this issue Nov 21, 2016
In the same manner as scala/scala-dev#219, the placement of the fields
phase after uncurry is presenting some challenges in keeping our trees
type correct.

This commit whacks a few more moles by adding a casts in the body of
synthetic methods.

Fixes scala/scala-dev#268
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

No branches or pull requests

1 participant