Skip to content

Commit

Permalink
restore print test for java tasty.
Browse files Browse the repository at this point in the history
Also do not make a fake param accessor for the fake param
of the fake constructor.
  • Loading branch information
bishabosha committed Dec 15, 2023
1 parent 7b09724 commit 67e94be
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 53 deletions.
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def scalaRuntimeDot(name: Name)(using SourceFile): Select = Select(scalaDot(nme.runtime), name)
def scalaUnit(implicit src: SourceFile): Select = scalaDot(tpnme.Unit)
def scalaAny(implicit src: SourceFile): Select = scalaDot(tpnme.Any)
def javaDotLangDot(name: Name)(implicit src: SourceFile): Select = Select(Select(Ident(nme.java), nme.lang), name)

def captureRoot(using Context): Select =
Select(scalaDot(nme.caps), nme.CAPTURE_ROOT)
Expand Down
28 changes: 14 additions & 14 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1064,37 +1064,37 @@ class TreeUnpickler(reader: TastyReader,
selfInfo = if (self.isEmpty) NoType else self.tpt.tpe
).integrateOpaqueMembers

val (constr, stats0) =
val constr =
if nextByte == SPLITCLAUSE then
assert(unpicklingJava, s"unexpected SPLITCLAUSE at $start")
val tag = readByte()
def ta = ctx.typeAssigner
val flags = Flags.JavaDefined | Flags.PrivateLocal | Flags.Invisible
val pflags = Flags.JavaDefined | Flags.Param
val tdefRefs = tparams.map(_.symbol.asType)
val ctorCompleter = new LazyType {
def complete(denot: SymDenotation)(using Context) =
val sym = denot.symbol
lazy val tparamSyms: List[TypeSymbol] = tparams.map: tdef =>
val pflags = flags | Flags.Param
val tparamRefs = tparams.map(_.symbol.asType)
lazy val derivedTparamSyms: List[TypeSymbol] = tparams.map: tdef =>
val completer = new LazyType {
def complete(denot: SymDenotation)(using Context) =
denot.info = tdef.symbol.asType.info.subst(tdefRefs, tparamSyms.map(_.typeRef))
denot.info = tdef.symbol.asType.info.subst(tparamRefs, derivedTparamRefs)
}
newSymbol(sym, tdef.name, pflags, completer, coord = cls.coord)
val paramSym =
newSymbol(sym, tdef.name, Flags.JavaDefined | Flags.Param, completer, coord = cls.coord)
lazy val derivedTparamRefs: List[Type] = derivedTparamSyms.map(_.typeRef)
val vparamSym =
newSymbol(sym, nme.syntheticParamName(1), pflags, defn.UnitType, coord = cls.coord)
val paramSymss = tparamSyms :: List(paramSym) :: Nil
val vparamSymss: List[List[Symbol]] = List(vparamSym) :: Nil
val paramSymss =
if derivedTparamSyms.nonEmpty then derivedTparamSyms :: vparamSymss else vparamSymss
val res = effectiveResultType(sym, paramSymss)
denot.info = methodType(paramSymss, res)
denot.setParamss(paramSymss)
}
val ctorSym = newSymbol(ctx.owner, nme.CONSTRUCTOR, flags, ctorCompleter, coord = coordAt(start))
val accSym = newSymbol(cls, nme.syntheticParamName(1), flags, defn.UnitType, coord = ctorSym.coord)
val ctorDef = tpd.DefDef(ctorSym, EmptyTree)
val accessor = tpd.ValDef(accSym, ElidedTree(accSym.info))
(ctorDef.setDefTree, accessor.setDefTree :: Nil)
tpd.DefDef(ctorSym, EmptyTree).setDefTree // fake primary constructor
else
readIndexedDef().asInstanceOf[DefDef] -> Nil
readIndexedDef().asInstanceOf[DefDef]
val mappedParents: LazyTreeList =
if parents.exists(_.isInstanceOf[InferredTypeTree]) then
// parents were not read fully, will need to be read again later on demand
Expand All @@ -1105,7 +1105,7 @@ class TreeUnpickler(reader: TastyReader,

val lazyStats = readLater(end, rdr => {
val stats = rdr.readIndexedStats(localDummy, end)
tparams ++ vparams ++ stats0 ++ stats
tparams ++ vparams ++ stats
})
defn.patchStdLibClass(cls)
NamerOps.addConstructorProxies(cls)
Expand Down
59 changes: 32 additions & 27 deletions compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Scanners.Offset
import Parsers.*
import core.*
import Contexts.*
import Symbols.defn
import Names.*
import Types.*
import ast.Trees.*
Expand All @@ -27,6 +28,9 @@ object JavaParsers {

import ast.untpd.*


val fakeFlags = Flags.JavaDefined | Flags.PrivateLocal | Flags.Invisible

class JavaParser(source: SourceFile)(using Context) extends ParserCommon(source) {

val definitions: Definitions = ctx.definitions
Expand Down Expand Up @@ -89,16 +93,16 @@ object JavaParsers {

// --------- tree building -----------------------------

def scalaAnnotationDot(name: Name): Select = Select(scalaDot(nme.annotation), name)

def javaDot(name: Name): Tree =
Select(rootDot(nme.java), name)

def javaLangDot(name: Name): Tree =
Select(javaDot(nme.lang), name)

/** Tree representing `java.lang.Object` */
def javaLangObject(): Tree = javaLangDot(tpnme.Object)
/** Synthetic tree representing `java.lang.Object`.
* The typer will type all references to `java.lang.Object` as `FromJavaObject`.
*/
def ObjectTpt(): Tree = TypeTree(defn.FromJavaObjectType) // javaLangDot(tpnme.Object)

/** Tree representing `java.lang.Record` */
def javaLangRecord(): Tree = javaLangDot(tpnme.Record)
Expand All @@ -107,6 +111,8 @@ object JavaParsers {
AppliedTypeTree(scalaDot(tpnme.Array), List(tpt))

def makeTemplate(parents: List[Tree], stats: List[Tree], tparams: List[TypeDef], needsDummyConstr: Boolean): Template = {
def UnitTpt(): Tree = TypeTree(defn.UnitType)

def pullOutFirstConstr(stats: List[Tree]): (Tree, List[Tree]) = stats match {
case (meth: DefDef) :: rest if meth.name == nme.CONSTRUCTOR => (meth, rest)
case first :: rest =>
Expand All @@ -120,10 +126,9 @@ object JavaParsers {
// can call it.
// This also avoids clashes between the constructor parameter names and member names.
if (needsDummyConstr) {
val fakeFlags = Flags.JavaDefined | Flags.PrivateLocal | Flags.Invisible
if (constr1 == EmptyTree) constr1 = makeConstructor(List(), Nil, Parsers.unimplementedExpr)
stats1 = constr1 :: stats1
constr1 = makeConstructor(List(scalaDot(tpnme.Unit)), tparams, EmptyTree, fakeFlags)
constr1 = makeConstructor(List(UnitTpt()), tparams, EmptyTree, fakeFlags)
}
else if (constr1 == EmptyTree) {
constr1 = makeConstructor(List(), tparams, EmptyTree)
Expand All @@ -134,11 +139,11 @@ object JavaParsers {
def makeSyntheticParam(count: Int, tpt: Tree): ValDef =
makeParam(nme.syntheticParamName(count), tpt)
def makeParam(name: TermName, tpt: Tree): ValDef =
ValDef(name, tpt, EmptyTree).withMods(Modifiers(Flags.JavaDefined | Flags.Param))
ValDef(name, tpt, EmptyTree).withFlags(Flags.JavaDefined | Flags.Param)

def makeConstructor(formals: List[Tree], tparams: List[TypeDef], body: Tree, flags: FlagSet = Flags.JavaDefined): DefDef = {
val vparams = formals.zipWithIndex.map { case (p, i) => makeSyntheticParam(i + 1, p).withMods(Modifiers(flags)) }
DefDef(nme.CONSTRUCTOR, joinParams(tparams, List(vparams)), TypeTree(), body).withMods(Modifiers(flags))
val vparams = formals.zipWithIndex.map { case (p, i) => makeSyntheticParam(i + 1, p).withAddedFlags(flags) }
DefDef(nme.CONSTRUCTOR, joinParams(tparams, List(vparams)), TypeTree(), body).withFlags(flags)
}

// ------------- general parsing ---------------------------
Expand Down Expand Up @@ -307,7 +312,7 @@ object JavaParsers {
if (in.token == QMARK) {
val offset = in.offset
in.nextToken()
val hi = if (in.token == EXTENDS) { in.nextToken() ; typ() } else javaLangObject()
val hi = if (in.token == EXTENDS) { in.nextToken() ; typ() } else ObjectTpt()
val lo = if (in.token == SUPER) { in.nextToken() ; typ() } else EmptyTree
atSpan(offset) {
/*
Expand Down Expand Up @@ -508,7 +513,7 @@ object JavaParsers {
atSpan(in.offset) {
annotations()
val name = identForType()
val hi = if (in.token == EXTENDS) { in.nextToken() ; bound() } else javaLangObject()
val hi = if (in.token == EXTENDS) { in.nextToken() ; bound() } else ObjectTpt()
TypeDef(name, TypeBoundsTree(EmptyTree, hi)).withMods(Modifiers(flags))
}

Expand Down Expand Up @@ -569,7 +574,7 @@ object JavaParsers {
if in.token == IDENTIFIER && in.name == jnme.RECORDid then
in.token = RECORD

def termDecl(start: Offset, mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = {
def termDecl(start: Offset, mods: Modifiers, parentToken: Int): List[Tree] = {
val inInterface = definesInterface(parentToken)
val tparams = if (in.token == LT) typeParams(Flags.JavaDefined | Flags.Param) else List()
val isVoid = in.token == VOID
Expand Down Expand Up @@ -741,11 +746,11 @@ object JavaParsers {
ValDef(name, tpt2, if (mods.is(Flags.Param)) EmptyTree else unimplementedExpr).withMods(mods1)
}

def memberDecl(start: Offset, mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = in.token match
def memberDecl(start: Offset, mods: Modifiers, parentToken: Int): List[Tree] = in.token match
case CLASS | ENUM | RECORD | INTERFACE | AT =>
typeDecl(start, if definesInterface(parentToken) then mods | Flags.JavaStatic else mods)
case _ =>
termDecl(start, mods, parentToken, parentTParams)
termDecl(start, mods, parentToken)

def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree =
atSpan(cdef.span) {
Expand Down Expand Up @@ -818,9 +823,9 @@ object JavaParsers {
typ()
}
else
javaLangObject()
ObjectTpt()
val interfaces = interfacesOpt()
val (statics, body) = typeBody(CLASS, name, tparams)
val (statics, body) = typeBody(CLASS, name)
val cls = atSpan(start, nameOffset) {
TypeDef(name, makeTemplate(superclass :: interfaces, body, tparams, needsDummyConstr = true)).withMods(mods)
}
Expand All @@ -835,7 +840,7 @@ object JavaParsers {
val header = formalParams()
val superclass = javaLangRecord() // records always extend java.lang.Record
val interfaces = interfacesOpt() // records may implement interfaces
val (statics, body) = typeBody(RECORD, name, tparams)
val (statics, body) = typeBody(RECORD, name)

// We need to generate accessors for every param, if no method with the same name is already defined

Expand Down Expand Up @@ -883,8 +888,8 @@ object JavaParsers {
repsep(() => typ(), COMMA)
}
else
List(javaLangObject())
val (statics, body) = typeBody(INTERFACE, name, tparams)
List(ObjectTpt())
val (statics, body) = typeBody(INTERFACE, name)
val iface = atSpan(start, nameOffset) {
TypeDef(
name,
Expand All @@ -893,14 +898,14 @@ object JavaParsers {
addCompanionObject(statics, iface)
}

def typeBody(leadingToken: Int, parentName: Name, parentTParams: List[TypeDef]): (List[Tree], List[Tree]) = {
def typeBody(leadingToken: Int, parentName: Name): (List[Tree], List[Tree]) = {
accept(LBRACE)
val defs = typeBodyDecls(leadingToken, parentName, parentTParams)
val defs = typeBodyDecls(leadingToken, parentName)
accept(RBRACE)
defs
}

def typeBodyDecls(parentToken: Int, parentName: Name, parentTParams: List[TypeDef]): (List[Tree], List[Tree]) = {
def typeBodyDecls(parentToken: Int, parentName: Name): (List[Tree], List[Tree]) = {
val inInterface = definesInterface(parentToken)
val statics = new ListBuffer[Tree]
val members = new ListBuffer[Tree]
Expand All @@ -916,7 +921,7 @@ object JavaParsers {
else {
adaptRecordIdentifier()
if (in.token == ENUM || in.token == RECORD || definesInterface(in.token)) mods |= Flags.JavaStatic
val decls = memberDecl(start, mods, parentToken, parentTParams)
val decls = memberDecl(start, mods, parentToken)
(if (mods.is(Flags.JavaStatic) || inInterface && !(decls exists (_.isInstanceOf[DefDef])))
statics
else
Expand All @@ -926,15 +931,15 @@ object JavaParsers {
(statics.toList, members.toList)
}
def annotationParents: List[Tree] = List(
javaLangObject(),
ObjectTpt(),
Select(javaLangDot(nme.annotation), tpnme.Annotation)
)
def annotationDecl(start: Offset, mods: Modifiers): List[Tree] = {
accept(AT)
accept(INTERFACE)
val nameOffset = in.offset
val name = identForType()
val (statics, body) = typeBody(AT, name, List())
val (statics, body) = typeBody(AT, name)
val constructorParams = body.collect {
case dd: DefDef =>
makeParam(dd.name, dd.tpt)
Expand Down Expand Up @@ -969,7 +974,7 @@ object JavaParsers {
val (statics, body) =
if (in.token == SEMI) {
in.nextToken()
typeBodyDecls(ENUM, name, List())
typeBodyDecls(ENUM, name)
}
else
(List(), List())
Expand Down Expand Up @@ -1093,7 +1098,7 @@ object JavaParsers {
*/
class OutlineJavaParser(source: SourceFile)(using Context) extends JavaParser(source) with OutlineParserCommon {
override def skipBracesHook(): Option[Tree] = None
override def typeBody(leadingToken: Int, parentName: Name, parentTParams: List[TypeDef]): (List[Tree], List[Tree]) = {
override def typeBody(leadingToken: Int, parentName: Name): (List[Tree], List[Tree]) = {
skipBraces()
(List(EmptyValDef), List(EmptyTree))
}
Expand Down
12 changes: 12 additions & 0 deletions compiler/src/dotty/tools/dotc/printing/OutlinePrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ object OutlinePrinter:
*/
class OutlinePrinter private (_ctx: Context) extends RefinedPrinter(_ctx) {

/** print the symbol infos of type params for the fake java constructor */
def shouldShowInfo(tsym: Symbol): Boolean =
tsym != NoSymbol && {
val ctor = tsym.owner
ctor.isAllOf(JavaDefined | PrivateLocal | Invisible) && ctor.isConstructor
}

override def paramsText[T <: Untyped](params: ParamClause[T]): Text = (params: @unchecked) match
case untpd.TypeDefs(tparams) if shouldShowInfo(tparams.head.symbol) =>
"[" ~ toText(tparams.map(_.symbol.info), ", ") ~ "]"
case _ => super.paramsText(params)

/* Typical patterns seen in output of typer for Java code, plus the output of unpickling an ELIDED tree */
def isElidableExpr[T <: Untyped](tree: Tree[T]): Boolean = tree match {
case tree if tree.isEmpty => false
Expand Down
13 changes: 11 additions & 2 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import config.{Config, Feature}
import dotty.tools.dotc.util.SourcePosition
import dotty.tools.dotc.ast.untpd.{MemberDef, Modifiers, PackageDef, RefTree, Template, TypeDef, ValOrDefDef}
import cc.{CaptureSet, CapturingType, toCaptureSet, IllegalCaptureRef}
import dotty.tools.dotc.parsing.JavaParsers

class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {

Expand Down Expand Up @@ -1015,10 +1016,18 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
val (params, rest) = impl.body partition {
case stat: TypeDef => stat.symbol.is(Param)
case stat: ValOrDefDef =>
stat.symbol.is(ParamAccessor) && !stat.symbol.isSetter
val sym = stat.symbol
sym.is(ParamAccessor) && !sym.isSetter
|| sym.isAllOf(JavaParsers.fakeFlags | Param)
case _ => false
}
params ::: rest
val params0 =
if constr.symbol.isAllOf(JavaParsers.fakeFlags) then
// filter out fake param accessors
params.filterNot(_.symbol.isAllOf(JavaParsers.fakeFlags | Param))
else
params
params0 ::: rest
}
else impl.body

Expand Down
23 changes: 14 additions & 9 deletions compiler/src/dotty/tools/dotc/transform/Pickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ class Pickler extends Phase {
Pickler.ParallelPickling && !ctx.settings.YtestPickler.value &&
!ctx.settings.YjavaTasty.value // disable parallel pickling when `-Yjava-tasty` is set (internal testing only)

private def printerContext(isOutline: Boolean)(using Context): Context =
if isOutline then ctx.fresh.setPrinterFn(OutlinePrinter(_))
else ctx

override def run(using Context): Unit = {
val unit = ctx.compilationUnit
pickling.println(i"unpickling in run ${ctx.runId}")
Expand All @@ -95,7 +99,8 @@ class Pickler extends Phase {
cls <- dropCompanionModuleClasses(topLevelClasses(unit.tpdTree))
tree <- sliceTopLevel(unit.tpdTree, cls)
do
if ctx.settings.YtestPickler.value then beforePickling(cls) = tree.show
if ctx.settings.YtestPickler.value then beforePickling(cls) =
tree.show(using printerContext(unit.typedAsJava))

val sourceRelativePath =
val reference = ctx.settings.sourceroot.value
Expand Down Expand Up @@ -243,16 +248,16 @@ class Pickler extends Phase {
pickling.println("************* entered toplevel ***********")
val rootCtx = ctx
for ((cls, (unit, unpickler)) <- unpicklers) do
if unit.typedAsJava then
val testJava = unit.typedAsJava
if testJava then
if unpickler.unpickler.nameAtRef.contents.exists(_ == nme.FromJavaObject) then
report.error(em"Pickled reference to FromJavaObject in Java defined $cls in ${cls.source}")
else
val unpickled = unpickler.rootTrees
val freshUnit = CompilationUnit(rootCtx.compilationUnit.source)
freshUnit.needsCaptureChecking = unit.needsCaptureChecking
freshUnit.knowsPureFuns = unit.knowsPureFuns
inContext(rootCtx.fresh.setCompilationUnit(freshUnit)):
testSame(i"$unpickled%\n%", beforePickling(cls), cls)
val unpickled = unpickler.rootTrees
val freshUnit = CompilationUnit(rootCtx.compilationUnit.source)
freshUnit.needsCaptureChecking = unit.needsCaptureChecking
freshUnit.knowsPureFuns = unit.knowsPureFuns
inContext(printerContext(testJava)(using rootCtx.fresh.setCompilationUnit(freshUnit))):
testSame(i"$unpickled%\n%", beforePickling(cls), cls)

private def testSame(unpickled: String, previous: String, cls: ClassSymbol)(using Context) =
import java.nio.charset.StandardCharsets.UTF_8
Expand Down

0 comments on commit 67e94be

Please sign in to comment.