Skip to content

Commit e9f980e

Browse files
committed
Stop using scala.runtime.function.JFunction*mc*
Instead, use the equivalent classes in the Scala 2 standard library in scala.runtime.java8. The only difference is that these classes are written in Scala instead of Java, which exposed a bug in the Scala2Unpickler: we were calling `atPhaseNoLater(picklerPhase)`, but this doesn't actually do anything in situation where the Pickler phase is not used (for example, when using the `QuoteCompiler`), this is fixed by introducing a new `atPhaseBeforeTransforms` which does the right thing. Because the `FirstTransform` phase itself might not be present, this also required fixing `Phase#next` and `Phase#prev` to work on `NoPhase`: the issue was that `myBase.NoPhase` failed with an NPE which we fix by making `NoPhase` a static object instead of a member of `PhasesBase`. Since an instace of `Phase` contains mutable state this requires making it `@sharable` to pass our tests, this is safe since we never mutate anything in `NoPhase` (this also matches what we do for `NoSymbol` and `NoDenotation`).
1 parent d5721f4 commit e9f980e

File tree

94 files changed

+33
-18
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+33
-18
lines changed

compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4135,7 +4135,7 @@ class JSCodeGen()(using genCtx: Context) {
41354135
}
41364136

41374137
private def computeJSNativeLoadSpecOfValDef(sym: Symbol): js.JSNativeLoadSpec = {
4138-
atPhase(picklerPhase.next) {
4138+
atPhaseBeforeTransforms {
41394139
computeJSNativeLoadSpecOfInPhase(sym)
41404140
}
41414141
}
@@ -4144,7 +4144,7 @@ class JSCodeGen()(using genCtx: Context) {
41444144
if (sym.is(Trait) || sym.hasAnnotation(jsdefn.JSGlobalScopeAnnot)) {
41454145
None
41464146
} else {
4147-
atPhase(picklerPhase.next) {
4147+
atPhaseBeforeTransforms {
41484148
if (sym.owner.isStaticOwner)
41494149
Some(computeJSNativeLoadSpecOfInPhase(sym))
41504150
else

compiler/src/dotty/tools/dotc/core/Annotations.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ object Annotations {
6161
mySym match {
6262
case symFn: (Context ?=> Symbol) @unchecked =>
6363
mySym = null
64-
mySym = atPhaseNoLater(picklerPhase)(symFn)
64+
mySym = atPhaseBeforeTransforms(symFn)
6565
// We should always produce the same annotation tree, no matter when the
6666
// annotation is evaluated. Setting the phase to a pre-transformation phase
6767
// seems to be enough to ensure this (note that after erasure, `ctx.typer`
@@ -79,7 +79,7 @@ object Annotations {
7979
myTree match {
8080
case treeFn: (Context ?=> Tree) @unchecked =>
8181
myTree = null
82-
myTree = atPhaseNoLater(picklerPhase)(treeFn)
82+
myTree = atPhaseBeforeTransforms(treeFn)
8383
case _ =>
8484
}
8585
myTree.asInstanceOf[Tree]
@@ -112,7 +112,7 @@ object Annotations {
112112
myTree match {
113113
case treeFn: (Context ?=> Tree) @unchecked =>
114114
myTree = null
115-
myTree = atPhaseNoLater(picklerPhase)(treeFn)
115+
myTree = atPhaseBeforeTransforms(treeFn)
116116
case _ =>
117117
}
118118
myTree.asInstanceOf[Tree]

compiler/src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ object Contexts {
7676
inline def atNextPhase[T](inline op: Context ?=> T)(using Context): T =
7777
atPhase(ctx.phase.next)(op)
7878

79+
/** Execute `op` at the current phase if it's before the first transform phase,
80+
* otherwise at the last phase before the first transform phase.
81+
*
82+
* Note: this should be used instead of `atPhaseNoLater(ctx.picklerPhase)`
83+
* because the later won't work if the `Pickler` phase is not present (for example,
84+
* when using `QuoteCompiler`).
85+
*/
86+
inline def atPhaseBeforeTransforms[T](inline op: Context ?=> T)(using Context): T =
87+
atPhaseNoLater(firstTransformPhase.prev)(op)
88+
7989
inline def atPhaseNoLater[T](limit: Phase)(inline op: Context ?=> T)(using Context): T =
8090
op(using if !limit.exists || ctx.phase <= limit then ctx else ctx.withPhase(limit))
8191

compiler/src/dotty/tools/dotc/core/Phases.scala

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,26 @@ import Periods._
1616
import typer.{FrontEnd, RefChecks}
1717
import typer.ImportInfo.withRootImports
1818
import ast.tpd
19+
import scala.annotation.internal.sharable
1920

2021
object Phases {
2122

2223
inline def phaseOf(id: PhaseId)(using Context): Phase =
2324
ctx.base.phases(id)
2425

26+
@sharable object NoPhase extends Phase {
27+
override def exists: Boolean = false
28+
def phaseName: String = "<no phase>"
29+
def run(using Context): Unit = unsupported("run")
30+
def transform(ref: SingleDenotation)(using Context): SingleDenotation = unsupported("transform")
31+
}
32+
2533
trait PhasesBase {
2634
this: ContextBase =>
2735

2836
// drop NoPhase at beginning
2937
def allPhases: Array[Phase] = (if (fusedPhases.nonEmpty) fusedPhases else phases).tail
3038

31-
object NoPhase extends Phase {
32-
override def exists: Boolean = false
33-
def phaseName: String = "<no phase>"
34-
def run(using Context): Unit = unsupported("run")
35-
def transform(ref: SingleDenotation)(using Context): SingleDenotation = unsupported("transform")
36-
}
37-
3839
object SomePhase extends Phase {
3940
def phaseName: String = "<some phase>"
4041
def run(using Context): Unit = unsupported("run")
@@ -198,6 +199,7 @@ object Phases {
198199
private var mySbtExtractDependenciesPhase: Phase = _
199200
private var myPicklerPhase: Phase = _
200201
private var myPickleQuotesPhase: Phase = _
202+
private var myFirstTransformPhase: Phase = _
201203
private var myCollectNullableFieldsPhase: Phase = _
202204
private var myRefChecksPhase: Phase = _
203205
private var myPatmatPhase: Phase = _
@@ -217,6 +219,7 @@ object Phases {
217219
final def sbtExtractDependenciesPhase: Phase = mySbtExtractDependenciesPhase
218220
final def picklerPhase: Phase = myPicklerPhase
219221
final def pickleQuotesPhase: Phase = myPickleQuotesPhase
222+
final def firstTransformPhase: Phase = myFirstTransformPhase
220223
final def collectNullableFieldsPhase: Phase = myCollectNullableFieldsPhase
221224
final def refchecksPhase: Phase = myRefChecksPhase
222225
final def patmatPhase: Phase = myPatmatPhase
@@ -239,6 +242,7 @@ object Phases {
239242
mySbtExtractDependenciesPhase = phaseOfClass(classOf[sbt.ExtractDependencies])
240243
myPicklerPhase = phaseOfClass(classOf[Pickler])
241244
myPickleQuotesPhase = phaseOfClass(classOf[PickleQuotes])
245+
myFirstTransformPhase = phaseOfClass(classOf[FirstTransform])
242246
myCollectNullableFieldsPhase = phaseOfClass(classOf[CollectNullableFields])
243247
myRefChecksPhase = phaseOfClass(classOf[RefChecks])
244248
myElimRepeatedPhase = phaseOfClass(classOf[ElimRepeated])
@@ -385,10 +389,10 @@ object Phases {
385389
exists && id <= that.id
386390

387391
final def prev: Phase =
388-
if (id > FirstPhaseId) myBase.phases(start - 1) else myBase.NoPhase
392+
if (id > FirstPhaseId) myBase.phases(start - 1) else NoPhase
389393

390394
final def next: Phase =
391-
if (hasNext) myBase.phases(end + 1) else myBase.NoPhase
395+
if (hasNext) myBase.phases(end + 1) else NoPhase
392396

393397
final def hasNext: Boolean = start >= FirstPhaseId && end + 1 < myBase.phases.length
394398

@@ -403,6 +407,7 @@ object Phases {
403407
def sbtExtractDependenciesPhase(using Context): Phase = ctx.base.sbtExtractDependenciesPhase
404408
def picklerPhase(using Context): Phase = ctx.base.picklerPhase
405409
def pickleQuotesPhase(using Context): Phase = ctx.base.pickleQuotesPhase
410+
def firstTransformPhase(using Context): Phase = ctx.base.firstTransformPhase
406411
def refchecksPhase(using Context): Phase = ctx.base.refchecksPhase
407412
def elimRepeatedPhase(using Context): Phase = ctx.base.elimRepeatedPhase
408413
def extensionMethodsPhase(using Context): Phase = ctx.base.extensionMethodsPhase

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ class TreeUnpickler(reader: TastyReader,
116116
val owner = ctx.owner
117117
val source = ctx.source
118118
def complete(denot: SymDenotation)(using Context): Unit =
119-
treeAtAddr(currentAddr) = atPhaseNoLater(picklerPhase) {
119+
treeAtAddr(currentAddr) = atPhaseBeforeTransforms {
120120
new TreeReader(reader).readIndexedDef()(
121121
using ctx.withOwner(owner).withSource(source))
122122
}
@@ -1392,7 +1392,7 @@ class TreeUnpickler(reader: TastyReader,
13921392
op: TreeReader => Context ?=> T) extends Trees.Lazy[T] {
13931393
def complete(using Context): T = {
13941394
pickling.println(i"starting to read at ${reader.reader.currentAddr} with owner $owner")
1395-
atPhaseNoLater(picklerPhase) {
1395+
atPhaseBeforeTransforms {
13961396
op(reader)(using ctx
13971397
.withOwner(owner)
13981398
.withModeBits(mode)

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
608608
}
609609
atReadPos(startCoord(denot).toIndex,
610610
() => withMode(Mode.Scala2Unpickling) {
611-
atPhaseNoLater(picklerPhase) {
611+
atPhaseBeforeTransforms {
612612
parseToCompletion(denot)
613613
}
614614
})

compiler/src/dotty/tools/dotc/transform/FunctionalInterfaces.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class FunctionalInterfaces extends MiniPhase {
2525
def phaseName: String = FunctionalInterfaces.name
2626

2727
private val functionName = "JFunction".toTermName
28-
private val functionPackage = "scala.runtime.function.".toTermName
28+
private val functionPackage = "scala.runtime.java8.".toTermName
2929

3030
override def transformClosure(tree: Closure)(using Context): Tree = {
3131
val cls = tree.tpe.classSymbol.asClass

0 commit comments

Comments
 (0)