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

Revert to the Scala 2 encoding for trait initialization and super calls #8652

Merged
merged 24 commits into from
Jul 22, 2020

Conversation

sjrd
Copy link
Member

@sjrd sjrd commented Apr 2, 2020

Not fit for review yet. This doesn't work. See my line comment below, on which I would like to get some advice.

@sjrd
Copy link
Member Author

sjrd commented Apr 2, 2020

Yes, Scala 2 handles all of that directly in the back-end. Both rewriting calls and generating the static forwarders.

Should we do that in dotty as well (that would mean that the LinkScala2Impls would completely disappear, just like AugmentScala2Traits).

@odersky
Copy link
Contributor

odersky commented Apr 2, 2020

I am not sure. We'd like to avoid pushing too much stuff into the backend, unless it is really JVM specific. On the other hand, if that's what Scala-2 does, it's easiest to duplicate it here.

@sjrd
Copy link
Member Author

sjrd commented Apr 2, 2020

It is actually JVM-specific. Scala.js doesn't do that (in fact the entire phase could be skipped for Scala.js). I'm not sure about Scala Native, but there's no reason that it would do it either.

@odersky
Copy link
Contributor

odersky commented Apr 2, 2020

AFAIK the only way to force an invokeSpecial is with a Super(...) receiver or maybe something else that has a SuperType. But both requires that the underlying value is a This. So I think right now there's no way to tell the backend to do an invokeSpecial on something that is not a this.

@odersky
Copy link
Contributor

odersky commented Apr 3, 2020

Why do we need an invokeSpecial on something that is not the current object?

@sjrd
Copy link
Member Author

sjrd commented Apr 3, 2020

Because the scheme is that, for a concrete def in a trait, we generate both a normal default method with its body, but also a static method that takes an explicit $this, and that forwards to the default method. This static method is called when performing super calls in subclasses (including in mixin forwarders), so it is critical that it be an invokespecial rather than an invokevirtual.

I'll try the solution to move that logic to the back-end like scalac does.

@odersky
Copy link
Contributor

odersky commented Apr 3, 2020

Because the scheme is that, for a concrete def in a trait, we generate both a normal default method with its body, but also a static method that takes an explicit $this, and that forwards to the default method. This static method is called when performing super calls in subclasses (including in mixin forwarders), so it is critical that it be an invokespecial rather than an invokevirtual.

Ah I see. So this is basically a workaround for the problem that you can't call an arbitrary method in some indirect parent with invokeSuper. Because if you could, you would not need the static forwarder method. So yes, this is JVM weirdness, I can't see other platforms having that problem.

@sjrd sjrd force-pushed the trait-init-like-scala-2 branch 2 times, most recently from ae7bc0e to 493cb6e Compare April 6, 2020 16:02
@sjrd sjrd force-pushed the trait-init-like-scala-2 branch from 8fcb94e to 4370981 Compare April 27, 2020 14:45
@sjrd sjrd force-pushed the trait-init-like-scala-2 branch 5 times, most recently from 64b95d2 to 975a4be Compare June 24, 2020 14:21
@sjrd
Copy link
Member Author

sjrd commented Jun 24, 2020

Well, finally all non-bootstrap tests pass.

The tastyBootstrap fails with:

Bad symbolic reference. A signature
refers to Position/T in package xsbti which is not available.
It may be completely missing from the current classpath, or the version on
the classpath might be incompatible with the version used when compiling the signature.
Bad symbolic reference. A signature
refers to Severity/T in package xsbti which is not available.
It may be completely missing from the current classpath, or the version on
the classpath might be incompatible with the version used when compiling the signature.
Compilation failed for: 'dotty1 from tastyBootstrap/dotty1'
[=======================================] completed (1/1, 1 failed, 24s)
[error] Test dotty.tools.dotc.CompilationTests.tastyBootstrap failed: java.lang.AssertionError: Expected no errors when compiling, failed for the following reason(s):
[error]
[error]   - encountered 1 test failures(s), took 43.394 sec
[error]     at dotty.tools.vulpix.ParallelTesting$CompilationTest.checkCompile(ParallelTesting.scala:884)
[error]     at dotty.tools.dotc.CompilationTests.$anonfun$2(CompilationTests.scala:279)
[error]     at scala.collection.immutable.List.map(List.scala:250)
[error]     at dotty.tools.dotc.CompilationTests.tastyBootstrap(CompilationTests.scala:279)
[error]     ...

TBH I have no idea how to start debugging this, so I'll need help here.

In the meantime, I believe this is good enough to be reviewed. Perhaps the reviewer will immediately spot what's wrong with the Bad symbolic reference in tastyBootstrap.

@odersky @smarter Who would like to review this PR?

@sjrd sjrd changed the title WiP Revert to the Scala 2 for trait initialization and super calls Revert to the Scala 2 for trait initialization and super calls Jun 24, 2020
@sjrd sjrd marked this pull request as ready for review June 24, 2020 15:13
@smarter
Copy link
Member

smarter commented Jun 24, 2020

TBH I have no idea how to start debugging this, so I'll need help here.

I would start by checking what classpath is being passed to the compiler in this test, it looks like the compiler-interface jar from sbt is missing somehow, which is weird. Are you seeing this locally or on the CI?

@sjrd
Copy link
Member Author

sjrd commented Jun 24, 2020

Both locally and on the CI.

@smarter
Copy link
Member

smarter commented Jun 24, 2020

ah, looking at the CI log, I think the stub symbol for xsbti.Position is not the root issue but a follow-on error after:

2020-06-24T16:10:32.7076646Z error while transforming method problem
2020-06-24T16:10:32.7077152Z error while transforming trait AnalysisCallback
2020-06-24T16:10:32.7081971Z exception while typing ... (caught cyclic reference) ... of class class dotty.tools.dotc.ast.Trees$DefDef # 399145855
2020-06-24T16:10:32.8077990Z exception while typing abstract class Context(base: dotty.tools.dotc.core.Contexts.ContextBase) extends dotty.tools.dotc.core.Periods, 
[...]
2020-06-24T16:10:33.2807471Z *** error while checking compiler/src/dotty/tools/dotc/core/Contexts.scala after phase capturedVars ***

I can't be sure what's going on without digging further (which I don't have the time to do right now), but my guess is that there's a mini-phase in the same group as CapturedVars whose denotation transformer can now force other denotations in a way that can lead to a cycle, which means Mixin#transformSym is likely to be the culprit, especially since it seems to be doing some phase-travelling.

@smarter
Copy link
Member

smarter commented Jun 24, 2020

error while transforming trait AnalysisCallback

AnalysisCallback is Java-defined, but we do set the Trait flag on Java interfaces, and Mixin#transformSym does:

 else if sym.is(Trait) then

so maybe you just need to do sym.is(Trait, butNot = JavaDefined) ?

@smarter
Copy link
Member

smarter commented Jun 24, 2020

(this is a bit misleading, maybe the flag should be called TraitOrInterface and we should have an isScalaTrait method)

@sjrd
Copy link
Member Author

sjrd commented Jun 25, 2020

Yes! Thanks a lot @smarter! That was exactly the lead I needed. There were actually two issues: a) the Java-defined interfaces and b) some cycles. I broke the cycles with some more phase traveling.

Now test and test_bootstrapped are green 🎉 Still waiting on the other CI jobs, but I hope it's going to be fine :)

@sjrd
Copy link
Member Author

sjrd commented Jun 29, 2020

Minimization of the NPE in scalaz:

class Foo

trait GenericTrait[A] {
  def bar: A
}

trait ConcreteTrait extends GenericTrait[Foo] {
  val bar: Foo = new Foo
}

class ConcreteClass extends ConcreteTrait

object Test {
  def main(args: Array[String]): Unit = {
    val obj = new ConcreteClass
    println(obj)
    println(obj.bar)
    assert(obj.bar != null) // AssertionError
  }
}

I expect ScalaTest is the same issue.

I'll work on fixing those next.


For fastparse, there is an error in the Scala2Unpickler. I'm pretty sure this is a bug that already existed before my PR, but that was not exposed.

dotty.tools.dotc.core.unpickleScala2.Scala2Unpickler$BadSignature: error reading Scala signature of trait Trees from /root/.cache/coursier/v1/https/scala-webapps.epfl.ch/artifactory/central/org/scala-lang/scala-reflect/2.13.0/scala-reflect-2.13.0.jar(scala/reflect/internal/Trees.class):
error occurred at position 50546: a runtime exception occurred: scala.MatchError: NoType (of class dotty.tools.dotc.core.Types$NoType$)
	at dotty.tools.dotc.core.unpickleScala2.Scala2Unpickler.errorBadSignature(Scala2Unpickler.scala:172)
	at dotty.tools.dotc.core.unpickleScala2.Scala2Unpickler.handleRuntimeException(Scala2Unpickler.scala:179)
	at dotty.tools.dotc.core.unpickleScala2.Scala2Unpickler$LocalUnpickler.complete(Scala2Unpickler.scala:614)
	at dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:259)
	at dotty.tools.dotc.core.Denotations$Denotation.completeInfo$1(Denotations.scala:188)
	at dotty.tools.dotc.core.Denotations$Denotation.info(Denotations.scala:190)
...

Who is responsible for Scala2Unpicker? Any idea what might be going on there, off the top of your head, before I dive in there?

@sjrd
Copy link
Member Author

sjrd commented Jun 29, 2020

-Ydebug-missing-refs gives me this more precise stack trace for the Scala2Unpickler issue:

scala.MatchError: NoType (of class dotty.tools.dotc.core.Types$NoType$)
        at dotty.tools.dotc.core.SymDenotations$SymDenotation.sourceOfSelf$1(SymDenotations.scala:1079)
        at dotty.tools.dotc.core.SymDenotations$SymDenotation.sourceModule(SymDenotations.scala:1081)
        at dotty.tools.dotc.core.SymDenotations$SymDenotation.scalacLinkedClass(SymDenotations.scala:1242)
        at dotty.tools.dotc.core.unpickleScala2.Scala2Unpickler$.setClassInfo(Scala2Unpickler.scala:113)
        at dotty.tools.dotc.core.unpickleScala2.Scala2Unpickler$LocalUnpickler.parseToCompletion$1(Scala2Unpickler.scala:581)
        at dotty.tools.dotc.core.unpickleScala2.Scala2Unpickler$LocalUnpickler.complete$$anonfun$1(Scala2Unpickler.scala:607)
        at dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
        at dotty.tools.dotc.core.unpickleScala2.Scala2Unpickler.atReadPos(Scala2Unpickler.scala:316)
        at dotty.tools.dotc.core.unpickleScala2.Scala2Unpickler$LocalUnpickler.complete(Scala2Unpickler.scala:607)
...

Note in particular setClassInfo at line 113:
https://github.com/lampepfl/dotty/blob/4d512f0301241de31481cc0f2e821958940930d3/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala#L113
as well as
https://github.com/lampepfl/dotty/blob/4d512f0301241de31481cc0f2e821958940930d3/compiler/src/dotty/tools/dotc/core/SymDenotations.scala#L1074-L1080

Apparently the scalacLinkedClass ends up with a ModuleClass whose info is NoType, causing the MatchError in sourceOfSelf inside sourceModule.

A few lines above in setClassInfo, there is this comment:
https://github.com/lampepfl/dotty/blob/4d512f0301241de31481cc0f2e821958940930d3/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala#L92-L98
I wonder if something similar happens here, and if we should add a similar provision?

That said I have no idea what's going on in this code, so I'm bit lost.

sjrd added 12 commits July 22, 2020 10:23
This might not be the best way to fix t4753.scala, but this is the
last run test and I'll take anything that makes the tests pass at
this point.
The round-trip is useless, and causes issues with some
Scala2-emitted modules that do not have module classes (seems to be
related to modules inside traits).
* Avoid transforming members of Java interfaces.
* Avoid cloning a scope if we do not need it.
This allows to entirely get rid of the phase as well as the
`Scala2xAugmented` flag.
@sjrd sjrd force-pushed the trait-init-like-scala-2 branch from 7276641 to 77e2925 Compare July 22, 2020 08:29
@sjrd
Copy link
Member Author

sjrd commented Jul 22, 2020

Rebased after #9343. If there's no objection by the time the CI's green, I'll merge this.

@sjrd sjrd merged commit d6d374a into scala:master Jul 22, 2020
@sjrd sjrd deleted the trait-init-like-scala-2 branch July 22, 2020 09:35
liufengyun added a commit to dotty-staging/dotty that referenced this pull request Jul 26, 2020
This reverts a change in scala#8652, which breaks the benchmarking of stdlib:

```
Exception in thread "main" java.lang.AssertionError: assertion failed: moduleRoot = val <none>, moduleClassRoot = module class volatile$, classRoot = class volatile
	at dotty.DottyPredef$.assertFail(DottyPredef.scala:17)
	at dotty.tools.dotc.core.unpickleScala2.Scala2Unpickler.<init>(Scala2Unpickler.scala:150)
	at dotty.tools.dotc.core.classfile.ClassfileParser.unpickleScala$1(ClassfileParser.scala:754)
	at dotty.tools.dotc.core.classfile.ClassfileParser.unpickleOrParseInnerClasses(ClassfileParser.scala:861)
	at dotty.tools.dotc.core.classfile.ClassfileParser.parseClass(ClassfileParser.scala:165)
	at dotty.tools.dotc.core.classfile.ClassfileParser.run(ClassfileParser.scala:90)
	at dotty.tools.dotc.core.ClassfileLoader.load(SymbolLoaders.scala:402)
	at dotty.tools.dotc.core.ClassfileLoader.doComplete(SymbolLoaders.scala:397)
	at dotty.tools.dotc.core.SymbolLoader.complete(SymbolLoaders.scala:342)y.scala, community-build/community-projects/std
```
@liufengyun liufengyun mentioned this pull request Aug 14, 2020
7 tasks
griggt added a commit to griggt/dotty that referenced this pull request Oct 21, 2020
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