From a6394e9ec72fa03cdcd19261743fbd1560a74300 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Sun, 14 Jan 2018 00:38:52 +0100 Subject: [PATCH 1/2] Tasty: Fix unpickling of a TEMPLATE with a SHARED parent --- compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- compiler/test/dotty/tools/dotc/FromTastyTests.scala | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index f07f1204ed18..a17b7984bfdf 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -760,7 +760,7 @@ class TreeUnpickler(reader: TastyReader, val tparams = readIndexedParams[TypeDef](TYPEPARAM) val vparams = readIndexedParams[ValDef](PARAM) val parents = collectWhile(nextByte != SELFDEF && nextByte != DEFDEF) { - nextByte match { + nextUnsharedTag match { case APPLY | TYPEAPPLY => readTerm()(parentCtx) case _ => readTpt()(parentCtx) } diff --git a/compiler/test/dotty/tools/dotc/FromTastyTests.scala b/compiler/test/dotty/tools/dotc/FromTastyTests.scala index 547b418b9ce1..e9253ad2ee91 100644 --- a/compiler/test/dotty/tools/dotc/FromTastyTests.scala +++ b/compiler/test/dotty/tools/dotc/FromTastyTests.scala @@ -33,7 +33,6 @@ class FromTastyTests extends ParallelTesting { "i2345.scala", "i2888.scala", "i2944.scala", - "i2980.scala", "i3000.scala", "i536.scala", "i974.scala", From 4c5b6ef1c9f26944f276fb0ff2c5d4da10d3ac62 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Mon, 15 Jan 2018 16:13:31 +0100 Subject: [PATCH 2/2] TASTY 3.0: Distinguish SHARED terms from types In general, this makes things easier to debug at virtually no cost. It also makes it much easier to properly set positions on unpickled TypeTrees: in TreeUnpickler#readTpt we can know make sure that the position of the TypeTree is unpickled from the address found after following all shared terms but before following any shared type. Note that the major version bump could have been avoided by adding some compatibility code, but that doesn't seem worthwhile until Tasty is used in the wild. --- .../tools/dotc/core/tasty/TastyFormat.scala | 50 ++++++++++--------- .../tools/dotc/core/tasty/TreePickler.scala | 4 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 12 ++--- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index a3ae450313ec..d0b5f03dc7b6 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -108,7 +108,7 @@ Standard-Section: "ASTs" TopLevelStat* ORtpt Length left_Term right_Term BYNAMEtpt underlying_Term EMPTYTREE - SHARED term_ASTRef + SHAREDterm term_ASTRef HOLE Length idx_Nat arg_Tree* Application = APPLY Length fn_Term arg_Term* @@ -125,7 +125,7 @@ Standard-Section: "ASTs" TopLevelStat* TERMREF possiblySigned_NameRef qual_Type THIS clsRef_Type RECthis recType_ASTRef - SHARED path_ASTRef + SHAREDtype path_ASTRef Constant = UNITconst FALSEconst @@ -165,7 +165,7 @@ Standard-Section: "ASTs" TopLevelStat* POLYtype Length result_Type NamesTypes METHODtype Length result_Type NamesTypes // needed for refinements TYPELAMBDAtype Length result_Type NamesTypes // variance encoded in front of name: +/-/(nothing) - SHARED type_ASTRef + SHAREDtype type_ASTRef NamesTypes = NameType* NameType = paramName_NameRef typeOrBounds_ASTRef @@ -226,8 +226,8 @@ Standard Section: "Positions" Assoc* object TastyFormat { final val header = Array(0x5C, 0xA1, 0xAB, 0x1F) - val MajorVersion = 2 - val MinorVersion = 1 + val MajorVersion = 3 + val MinorVersion = 0 /** Tags used to serialize names */ class NameTags { @@ -302,23 +302,24 @@ object TastyFormat { // Cat. 2: tag Nat - final val SHARED = 50 - final val TERMREFdirect = 51 - final val TYPEREFdirect = 52 - final val TERMREFpkg = 53 - final val TYPEREFpkg = 54 - final val RECthis = 55 - final val BYTEconst = 56 - final val SHORTconst = 57 - final val CHARconst = 58 - final val INTconst = 59 - final val LONGconst = 60 - final val FLOATconst = 61 - final val DOUBLEconst = 62 - final val STRINGconst = 63 - final val IMPORTED = 64 - final val RENAMED = 65 - final val SYMBOLconst = 66 + final val SHAREDterm = 50 + final val SHAREDtype = 51 + final val TERMREFdirect = 52 + final val TYPEREFdirect = 53 + final val TERMREFpkg = 54 + final val TYPEREFpkg = 55 + final val RECthis = 56 + final val BYTEconst = 57 + final val SHORTconst = 58 + final val CHARconst = 59 + final val INTconst = 60 + final val LONGconst = 61 + final val FLOATconst = 62 + final val DOUBLEconst = 63 + final val STRINGconst = 64 + final val IMPORTED = 65 + final val RENAMED = 66 + final val SYMBOLconst = 67 // Cat. 3: tag AST @@ -402,7 +403,7 @@ object TastyFormat { final val HOLE = 255 final val firstSimpleTreeTag = UNITconst - final val firstNatTreeTag = SHARED + final val firstNatTreeTag = SHAREDterm final val firstASTTreeTag = THIS final val firstNatASTTreeTag = IDENT final val firstLengthTreeTag = PACKAGE @@ -492,7 +493,8 @@ object TastyFormat { case DEFAULTparameterized => "DEFAULTparameterized" case STABLE => "STABLE" - case SHARED => "SHARED" + case SHAREDterm => "SHAREDterm" + case SHAREDtype => "SHAREDtype" case TERMREFdirect => "TERMREFdirect" case TYPEREFdirect => "TYPEREFdirect" case TERMREFpkg => "TERMREFpkg" diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index e7babd50ca31..da299fc61bf3 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -143,7 +143,7 @@ class TreePickler(pickler: TastyPickler) { pickleNewType(tpe, richTypes) } else { - writeByte(SHARED) + writeByte(SHAREDtype) writeRef(prev.asInstanceOf[Addr]) } } catch { @@ -330,7 +330,7 @@ class TreePickler(pickler: TastyPickler) { def pickleTree(tree: Tree)(implicit ctx: Context): Unit = { val addr = registerTreeAddr(tree) if (addr != currentAddr) { - writeByte(SHARED) + writeByte(SHAREDterm) writeRef(addr) } else diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index a17b7984bfdf..f7a78aff9949 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -152,7 +152,7 @@ class TreeUnpickler(reader: TastyReader, /** The next tag, following through SHARED tags */ def nextUnsharedTag: Int = { val tag = nextByte - if (tag == SHARED) { + if (tag == SHAREDtype || tag == SHAREDterm) { val lookAhead = fork lookAhead.reader.readByte() forkAt(lookAhead.reader.readAddr()).nextUnsharedTag @@ -321,7 +321,7 @@ class TreeUnpickler(reader: TastyReader, readTypeRef().asInstanceOf[RecType].recThis case TYPEALIAS => TypeAlias(readType()) - case SHARED => + case SHAREDtype => val ref = readAddr() typeAtAddr.getOrElseUpdate(ref, forkAt(ref).readType()) case UNITconst => @@ -899,7 +899,7 @@ class TreeUnpickler(reader: TastyReader, } def readSimpleTerm(): Tree = tag match { - case SHARED => + case SHAREDterm => forkAt(readAddr()).readTerm() case IDENT => untpd.Ident(readName()).withType(readType()) @@ -1051,7 +1051,7 @@ class TreeUnpickler(reader: TastyReader, } def readTpt()(implicit ctx: Context) = - if (isTypeTreeTag(nextUnsharedTag)) readTerm() + if (nextByte == SHAREDterm || isTypeTreeTag(nextUnsharedTag)) readTerm() else { val start = currentAddr val tp = readType() @@ -1059,8 +1059,8 @@ class TreeUnpickler(reader: TastyReader, } def readCases(end: Addr)(implicit ctx: Context): List[CaseDef] = - collectWhile((nextByte == CASEDEF || nextByte == SHARED) && currentAddr != end) { - if (nextByte == SHARED) { + collectWhile((nextByte == CASEDEF || nextByte == SHAREDterm) && currentAddr != end) { + if (nextByte == SHAREDterm) { readByte() forkAt(readAddr()).readCase()(ctx.fresh.setNewScope) }