Skip to content

Commit 25f8558

Browse files
committed
Check for FromJavaObject in -Ytest-pickler
1 parent 60dfd96 commit 25f8558

File tree

6 files changed

+83
-5
lines changed

6 files changed

+83
-5
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package dotty.tools
2+
package dotc
3+
package printing
4+
5+
import core.*
6+
import Texts.*
7+
import Flags.*
8+
import NameOps.*
9+
import StdNames.*
10+
import Contexts.*
11+
import Symbols.*
12+
import ast.{Trees, untpd}
13+
import Trees.*
14+
15+
object OutlinePrinter:
16+
def apply(_ctx: Context): Printer = new OutlinePrinter(_ctx)
17+
18+
/** A printer that elides known standard tree forms from the rhs of def and val.
19+
* Typically used for printing Java trees which elide the rhs.
20+
*/
21+
class OutlinePrinter private (_ctx: Context) extends RefinedPrinter(_ctx) {
22+
23+
/* Typical patterns seen in output of typer for Java code, plus the output of unpickling an ELIDED tree */
24+
def isElidableExpr[T <: Untyped](tree: Tree[T]): Boolean = tree match {
25+
case tree: Ident[T] if tree.name == nme.WILDCARD => true
26+
case tree: Select[T] if tree.symbol == defn.Predef_undefined => true
27+
case Apply(Select(tree: New[T], nme.CONSTRUCTOR), Nil) if tree.tpt.typeOpt.typeSymbol.is(Module) => true
28+
case _ => false
29+
}
30+
31+
def elideExpr[T <: Untyped](tree: Tree[T], original: => Text): Text =
32+
if isElidableExpr(tree) then Str("_") else original
33+
34+
override protected def rhsValDef[T <: Untyped](rhs: Tree[T], original: => Text): Text =
35+
elideExpr(rhs, original)
36+
37+
override protected def rhsDefDef[T <: Untyped](rhs: Tree[T], original: => Text): Text =
38+
elideExpr(rhs, original)
39+
}

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import dotty.tools.dotc.util.SourcePosition
2929
import dotty.tools.dotc.ast.untpd.{MemberDef, Modifiers, PackageDef, RefTree, Template, TypeDef, ValOrDefDef}
3030
import cc.{CaptureSet, CapturingType, toCaptureSet, IllegalCaptureRef}
3131

32+
import scala.annotation.unused
33+
3234
class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
3335

3436
/** A stack of enclosing DefDef, TypeDef, or ClassDef, or ModuleDefs nodes */
@@ -920,7 +922,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
920922
dclTextOr(tree) {
921923
modText(tree.mods, tree.symbol, keywordStr(if (tree.mods.is(Mutable)) "var" else "val"), isType = false) ~~
922924
valDefText(nameIdText(tree)) ~ optAscription(tree.tpt) ~
923-
withEnclosingDef(tree) { optText(tree.rhs)(" = " ~ _) }
925+
withEnclosingDef(tree) { optText(tree.rhs)(rhs => " = " ~ rhsValDef(tree.rhs, rhs)) }
924926
}
925927
}
926928

@@ -977,11 +979,20 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
977979

978980
coreSig
979981
~ optAscription(tree.tpt)
980-
~ optText(tree.rhs)(" = " ~ keywordText("macro ").provided(tree.symbol.isScala2Macro) ~ _)
982+
~ optText(tree.rhs)(rhs =>
983+
" = " ~ rhsDefDef(tree.rhs, keywordText("macro ").provided(tree.symbol.isScala2Macro) ~ rhs))
981984
}
982985
}
983986
}
984987

988+
/** Inspect the rhs of a ValDef, overridden in OutlinePrinter */
989+
protected def rhsValDef[T <: Untyped](@unused("override may inspect rhs") rhs: Tree[T], original: => Text): Text =
990+
original
991+
992+
/** Inspect the rhs of a DefDef, overridden in OutlinePrinter */
993+
protected def rhsDefDef[T <: Untyped](@unused("override may inspect rhs") rhs: Tree[T], original: => Text): Text =
994+
original
995+
985996
protected def toTextTemplate(impl: Template, ofNew: Boolean = false): Text = {
986997
val Template(constr @ DefDef(_, paramss, _, _), _, self, _) = impl
987998
val tparamsTxt = withEnclosingDef(constr) {

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

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import config.Printers.{noPrinter, pickling}
1010
import config.Feature
1111
import java.io.PrintStream
1212
import io.ClassfileWriterOps
13-
import StdNames.str
13+
import StdNames.{str, nme}
1414
import Periods.*
1515
import Phases.*
1616
import Symbols.*
@@ -20,6 +20,7 @@ import collection.mutable
2020
import util.concurrent.{Executor, Future}
2121
import compiletime.uninitialized
2222
import dotty.tools.io.JarArchive
23+
import dotty.tools.dotc.printing.OutlinePrinter
2324

2425
object Pickler {
2526
val name: String = "pickler"
@@ -86,6 +87,15 @@ class Pickler extends Phase {
8687
Pickler.ParallelPickling && !ctx.settings.YtestPickler.value &&
8788
!ctx.settings.YjavaTasty.value // disable parallel pickling when `-Yjava-tasty` is set (internal testing only)
8889

90+
private def adjustPrinter(ictx: Context): Context =
91+
if ictx.compilationUnit.typedAsJava then
92+
// use special printer because Java parser will use `Predef.???` as rhs,
93+
// which conflicts with the unpickling of ELIDED as `Ident(nme.WILDCARD).withType(tpe)`
94+
// In the future we could modify the typer/parser to elide the rhs in the same way.
95+
ictx.fresh.setPrinterFn(OutlinePrinter(_))
96+
else
97+
ictx
98+
8999
override def run(using Context): Unit = {
90100
val unit = ctx.compilationUnit
91101
pickling.println(i"unpickling in run ${ctx.runId}")
@@ -94,7 +104,8 @@ class Pickler extends Phase {
94104
cls <- dropCompanionModuleClasses(topLevelClasses(unit.tpdTree))
95105
tree <- sliceTopLevel(unit.tpdTree, cls)
96106
do
97-
if ctx.settings.YtestPickler.value then beforePickling(cls) = tree.show
107+
if ctx.settings.YtestPickler.value then
108+
beforePickling(cls) = tree.show(using adjustPrinter(ctx))
98109

99110
val sourceRelativePath =
100111
val reference = ctx.settings.sourceroot.value
@@ -242,11 +253,14 @@ class Pickler extends Phase {
242253
pickling.println("************* entered toplevel ***********")
243254
val rootCtx = ctx
244255
for ((cls, (unit, unpickler)) <- unpicklers) do
256+
if unit.typedAsJava then
257+
if unpickler.unpickler.nameAtRef.contents.exists(_ == nme.FromJavaObject) then
258+
report.error(em"Pickled reference to FromJavaObject in Java defined $cls in ${cls.source}")
245259
val unpickled = unpickler.rootTrees
246260
val freshUnit = CompilationUnit(rootCtx.compilationUnit.source)
247261
freshUnit.needsCaptureChecking = unit.needsCaptureChecking
248262
freshUnit.knowsPureFuns = unit.knowsPureFuns
249-
inContext(rootCtx.fresh.setCompilationUnit(freshUnit)):
263+
inContext(adjustPrinter(rootCtx.fresh.setCompilationUnit(freshUnit))):
250264
testSame(i"$unpickled%\n%", beforePickling(cls), cls)
251265

252266
private def testSame(unpickled: String, previous: String, cls: ClassSymbol)(using Context) =

sbt-test/pipelining/Yjava-tasty-fromjavaobject/a-check/.keep

Whitespace-only changes.

sbt-test/pipelining/Yjava-tasty-fromjavaobject/build.sbt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ lazy val a = project.in(file("a"))
77
Compile / classDirectory := ((ThisBuild / baseDirectory).value / "a-enum-classes"), // send classfiles to a different directory
88
)
99

10+
// compiles the same sources as a, but with -Ytest-pickler
11+
lazy val aCheck = project.in(file("a-check"))
12+
.settings(
13+
scalacOptions += "-Ytest-pickler", // check that the pickler is correct
14+
Compile / sources := (a / Compile / sources).value, // use the same sources as a
15+
compileOrder := CompileOrder.Mixed, // ensure we send java sources to Scala compiler
16+
scalacOptions += "-Yjava-tasty", // enable pickling of java signatures
17+
scalacOptions ++= Seq("-Yjava-tasty-output", ((ThisBuild / baseDirectory).value / "a-enum-java-tasty-2.jar").toString),
18+
Compile / classDirectory := ((ThisBuild / baseDirectory).value / "a-enum-classes-2"), // send classfiles to a different directory
19+
)
20+
1021

1122
lazy val b = project.in(file("b"))
1223
.settings(

sbt-test/pipelining/Yjava-tasty-fromjavaobject/test

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
# compile Java sources, and send them to TASTy
12
> a/compile
3+
# compile Java sources, and check that they are pickled correctly
4+
> aCheck/compile
25
# test depending on a java compiled enum through TASTy
36
> b/run
47
# double check against the real java classes

0 commit comments

Comments
 (0)