Skip to content

Commit 08572ee

Browse files
authored
Eliminate FromJavaObject from TASTy of Java sources (#19259)
Do not pickle type references to `FromJavaObject` for Java sources, instead insert them at unpickling time. This ensures consistency of `IDENTtpt` (where `Object` is given an explicit type) and `SELECTtpt` where the type has to be resolved from just the name `Object`. modify `-Ytest-pickler` to check for the presence of `FromJavaObject` Also we compare unpicking Java signatures from TASTy to unpicking from class files to ensure consistency fixes #19246
2 parents b1d1fe8 + 67e94be commit 08572ee

File tree

36 files changed

+568
-63
lines changed

36 files changed

+568
-63
lines changed

compiler/src/dotty/tools/dotc/ast/untpd.scala

-1
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
510510
def scalaRuntimeDot(name: Name)(using SourceFile): Select = Select(scalaDot(nme.runtime), name)
511511
def scalaUnit(implicit src: SourceFile): Select = scalaDot(tpnme.Unit)
512512
def scalaAny(implicit src: SourceFile): Select = scalaDot(tpnme.Any)
513-
def javaDotLangDot(name: Name)(implicit src: SourceFile): Select = Select(Select(Ident(nme.java), nme.lang), name)
514513

515514
def captureRoot(using Context): Select =
516515
Select(scalaDot(nme.caps), nme.CAPTURE_ROOT)

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

+21-8
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import ast.{untpd, tpd}
1313
import Contexts.*, Symbols.*, Types.*, Names.*, Constants.*, Decorators.*, Annotations.*, Flags.*
1414
import Comments.{Comment, docCtx}
1515
import NameKinds.*
16-
import StdNames.nme
16+
import StdNames.{nme, tpnme}
1717
import config.Config
1818
import collection.mutable
1919
import reporting.{Profile, NoProfile}
@@ -49,6 +49,9 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
4949

5050
private var profile: Profile = NoProfile
5151

52+
private val isOutlinePickle: Boolean = attributes.isOutline
53+
private val isJavaPickle: Boolean = attributes.isJava
54+
5255
def treeAnnots(tree: untpd.MemberDef): List[Tree] =
5356
val ts = annotTrees.lookup(tree)
5457
if ts == null then Nil else ts.toList
@@ -188,19 +191,19 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
188191
def pickleExternalRef(sym: Symbol) = {
189192
val isShadowedRef =
190193
sym.isClass && tpe.prefix.member(sym.name).symbol != sym
191-
if (sym.is(Flags.Private) || isShadowedRef) {
194+
if sym.is(Flags.Private) || isShadowedRef then
192195
writeByte(if (tpe.isType) TYPEREFin else TERMREFin)
193196
withLength {
194197
pickleNameAndSig(sym.name, sym.signature, sym.targetName)
195198
pickleType(tpe.prefix)
196199
pickleType(sym.owner.typeRef)
197200
}
198-
}
199-
else {
201+
else if isJavaPickle && sym == defn.FromJavaObjectSymbol then
202+
pickleType(defn.ObjectType) // when unpickling Java TASTy, replace by <FromJavaObject>
203+
else
200204
writeByte(if (tpe.isType) TYPEREF else TERMREF)
201205
pickleNameAndSig(sym.name, tpe.signature, sym.targetName)
202206
pickleType(tpe.prefix)
203-
}
204207
}
205208
if (sym.is(Flags.Package)) {
206209
writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg)
@@ -342,7 +345,7 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
342345
case _: Template | _: Hole => pickleTree(tpt)
343346
case _ if tpt.isType => pickleTpt(tpt)
344347
}
345-
if attributes.isOutline && sym.isTerm && attributes.isJava then
348+
if isOutlinePickle && sym.isTerm && isJavaPickle then
346349
// TODO: if we introduce outline typing for Scala definitions
347350
// then we will need to update the check here
348351
pickleElidedUnlessEmpty(rhs, tpt.tpe)
@@ -358,7 +361,7 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
358361
else
359362
throw ex
360363
if sym.is(Method) && sym.owner.isClass then
361-
profile.recordMethodSize(sym, currentAddr.index - addr.index, mdef.span)
364+
profile.recordMethodSize(sym, (currentAddr.index - addr.index) max 1, mdef.span)
362365
for docCtx <- ctx.docCtx do
363366
val comment = docCtx.docstrings.lookup(sym)
364367
if comment != null then
@@ -614,7 +617,17 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
614617
}
615618
}
616619
}
617-
pickleStats(tree.constr :: rest)
620+
if isJavaPickle then
621+
val rest0 = rest.dropWhile:
622+
case stat: ValOrDefDef => stat.symbol.is(Flags.Invisible)
623+
case _ => false
624+
if tree.constr.symbol.is(Flags.Invisible) then
625+
writeByte(SPLITCLAUSE)
626+
pickleStats(rest0)
627+
else
628+
pickleStats(tree.constr :: rest0)
629+
else
630+
pickleStats(tree.constr :: rest)
618631
}
619632
case Import(expr, selectors) =>
620633
writeByte(IMPORT)

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

+55-11
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ class TreeUnpickler(reader: TastyReader,
163163
def forkAt(start: Addr): TreeReader = new TreeReader(subReader(start, endAddr))
164164
def fork: TreeReader = forkAt(currentAddr)
165165

166+
def skipParentTree(tag: Int): Unit = {
167+
if tag == SPLITCLAUSE then ()
168+
else skipTree(tag)
169+
}
170+
def skipParentTree(): Unit = skipParentTree(readByte())
166171
def skipTree(tag: Int): Unit = {
167172
if (tag >= firstLengthTreeTag) goto(readEnd())
168173
else if (tag >= firstNatASTTreeTag) { readNat(); skipTree() }
@@ -441,7 +446,11 @@ class TreeUnpickler(reader: TastyReader,
441446
readPackageRef().termRef
442447
case TYPEREF =>
443448
val name = readName().toTypeName
444-
TypeRef(readType(), name)
449+
val pre = readType()
450+
if unpicklingJava && name == tpnme.Object && (pre.termSymbol eq defn.JavaLangPackageVal) then
451+
defn.FromJavaObjectType
452+
else
453+
TypeRef(pre, name)
445454
case TERMREF =>
446455
val sname = readName()
447456
val prefix = readType()
@@ -1007,7 +1016,7 @@ class TreeUnpickler(reader: TastyReader,
10071016
* parsed in this way as InferredTypeTrees.
10081017
*/
10091018
def readParents(withArgs: Boolean)(using Context): List[Tree] =
1010-
collectWhile(nextByte != SELFDEF && nextByte != DEFDEF) {
1019+
collectWhile({val tag = nextByte; tag != SELFDEF && tag != DEFDEF && tag != SPLITCLAUSE}) {
10111020
nextUnsharedTag match
10121021
case APPLY | TYPEAPPLY | BLOCK =>
10131022
if withArgs then readTree()
@@ -1034,7 +1043,8 @@ class TreeUnpickler(reader: TastyReader,
10341043
val bodyFlags = {
10351044
val bodyIndexer = fork
10361045
// The first DEFDEF corresponds to the primary constructor
1037-
while (bodyIndexer.reader.nextByte != DEFDEF) bodyIndexer.skipTree()
1046+
while ({val tag = bodyIndexer.reader.nextByte; tag != DEFDEF && tag != SPLITCLAUSE}) do
1047+
bodyIndexer.skipParentTree()
10381048
bodyIndexer.indexStats(end)
10391049
}
10401050
val parentReader = fork
@@ -1053,7 +1063,38 @@ class TreeUnpickler(reader: TastyReader,
10531063
cls.owner.thisType, cls, parentTypes, cls.unforcedDecls,
10541064
selfInfo = if (self.isEmpty) NoType else self.tpt.tpe
10551065
).integrateOpaqueMembers
1056-
val constr = readIndexedDef().asInstanceOf[DefDef]
1066+
1067+
val constr =
1068+
if nextByte == SPLITCLAUSE then
1069+
assert(unpicklingJava, s"unexpected SPLITCLAUSE at $start")
1070+
val tag = readByte()
1071+
def ta = ctx.typeAssigner
1072+
val flags = Flags.JavaDefined | Flags.PrivateLocal | Flags.Invisible
1073+
val ctorCompleter = new LazyType {
1074+
def complete(denot: SymDenotation)(using Context) =
1075+
val sym = denot.symbol
1076+
val pflags = flags | Flags.Param
1077+
val tparamRefs = tparams.map(_.symbol.asType)
1078+
lazy val derivedTparamSyms: List[TypeSymbol] = tparams.map: tdef =>
1079+
val completer = new LazyType {
1080+
def complete(denot: SymDenotation)(using Context) =
1081+
denot.info = tdef.symbol.asType.info.subst(tparamRefs, derivedTparamRefs)
1082+
}
1083+
newSymbol(sym, tdef.name, Flags.JavaDefined | Flags.Param, completer, coord = cls.coord)
1084+
lazy val derivedTparamRefs: List[Type] = derivedTparamSyms.map(_.typeRef)
1085+
val vparamSym =
1086+
newSymbol(sym, nme.syntheticParamName(1), pflags, defn.UnitType, coord = cls.coord)
1087+
val vparamSymss: List[List[Symbol]] = List(vparamSym) :: Nil
1088+
val paramSymss =
1089+
if derivedTparamSyms.nonEmpty then derivedTparamSyms :: vparamSymss else vparamSymss
1090+
val res = effectiveResultType(sym, paramSymss)
1091+
denot.info = methodType(paramSymss, res)
1092+
denot.setParamss(paramSymss)
1093+
}
1094+
val ctorSym = newSymbol(ctx.owner, nme.CONSTRUCTOR, flags, ctorCompleter, coord = coordAt(start))
1095+
tpd.DefDef(ctorSym, EmptyTree).setDefTree // fake primary constructor
1096+
else
1097+
readIndexedDef().asInstanceOf[DefDef]
10571098
val mappedParents: LazyTreeList =
10581099
if parents.exists(_.isInstanceOf[InferredTypeTree]) then
10591100
// parents were not read fully, will need to be read again later on demand
@@ -1174,6 +1215,9 @@ class TreeUnpickler(reader: TastyReader,
11741215

11751216
// ------ Reading trees -----------------------------------------------------
11761217

1218+
private def ElidedTree(tpe: Type)(using Context): Tree =
1219+
untpd.Ident(nme.WILDCARD).withType(tpe)
1220+
11771221
def readTree()(using Context): Tree = {
11781222
val sctx = sourceChangeContext()
11791223
if (sctx `ne` ctx) return readTree()(using sctx)
@@ -1202,12 +1246,11 @@ class TreeUnpickler(reader: TastyReader,
12021246

12031247
def completeSelect(name: Name, sig: Signature, target: Name): Select =
12041248
val qual = readTree()
1205-
val denot0 = accessibleDenot(qual.tpe.widenIfUnstable, name, sig, target)
12061249
val denot =
1207-
if unpicklingJava && name == tpnme.Object && denot0.symbol == defn.ObjectClass then
1208-
defn.FromJavaObjectType.denot
1250+
if unpicklingJava && name == tpnme.Object && qual.symbol == defn.JavaLangPackageVal then
1251+
defn.FromJavaObjectSymbol.denot
12091252
else
1210-
denot0
1253+
accessibleDenot(qual.tpe.widenIfUnstable, name, sig, target)
12111254
makeSelect(qual, name, denot)
12121255

12131256
def readQualId(): (untpd.Ident, TypeRef) =
@@ -1228,9 +1271,10 @@ class TreeUnpickler(reader: TastyReader,
12281271
untpd.Ident(readName()).withType(readType())
12291272
case ELIDED =>
12301273
if !isOutline then
1231-
report.error(
1232-
s"Illegal elided tree in unpickler without ${attributeTagToString(OUTLINEattr)}, ${ctx.source}")
1233-
untpd.Ident(nme.WILDCARD).withType(readType())
1274+
val msg =
1275+
s"Illegal elided tree in unpickler at $start without ${attributeTagToString(OUTLINEattr)}, ${ctx.source}"
1276+
report.error(msg)
1277+
ElidedTree(readType())
12341278
case IDENTtpt =>
12351279
untpd.Ident(readName().toTypeName).withType(readType())
12361280
case SELECT =>

0 commit comments

Comments
 (0)