diff options
author | Martin Odersky <odersky@gmail.com> | 2015-03-04 13:52:44 +0100 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2015-03-18 11:14:14 +0100 |
commit | 96fbd7bfe252026f59d1f5e8aa33f2d8fae65769 (patch) | |
tree | c4a53211dbf23913eb8174f74e248c16f1c26bab | |
parent | e926f3167f8d9a1407f131abcb33a02b07477597 (diff) | |
download | dotty-96fbd7bfe252026f59d1f5e8aa33f2d8fae65769.tar.gz dotty-96fbd7bfe252026f59d1f5e8aa33f2d8fae65769.tar.bz2 dotty-96fbd7bfe252026f59d1f5e8aa33f2d8fae65769.zip |
Allow several units to be pickle-tested at once.
Also: Make Pickler a plain phase; it is neither a macro transformer nor
a miniphase.
Add tests to pickleOK that are known to be stable under pickling/unpicking
by comparing tree representations via show.
-rw-r--r-- | src/dotty/tools/dotc/transform/Pickler.scala | 51 | ||||
-rw-r--r-- | tests/pos/pickleOK/Coder.scala | 59 | ||||
-rw-r--r-- | tests/pos/pickleOK/alias.scala | 3 | ||||
-rw-r--r-- | tests/pos/pickleOK/new-array.scala | 17 | ||||
-rw-r--r-- | tests/pos/pickleOK/templateParents.scala | 24 | ||||
-rw-r--r-- | tests/pos/pickleOK/unapply.scala | 11 | ||||
-rw-r--r-- | tests/pos/pickleOK/zoo.scala | 41 |
7 files changed, 187 insertions, 19 deletions
diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala index 7bc41321c..79240c957 100644 --- a/src/dotty/tools/dotc/transform/Pickler.scala +++ b/src/dotty/tools/dotc/transform/Pickler.scala @@ -2,16 +2,17 @@ package dotty.tools.dotc package transform import core._ -import TreeTransforms._ import Contexts.Context import Decorators._ import pickling._ import config.Printers.{noPrinter, pickling} import java.io.PrintStream import Periods._ +import Phases._ +import collection.mutable /** This miniphase pickles trees */ -class Pickler extends MiniPhaseTransform { thisTransform => +class Pickler extends Phase { import ast.tpd._ override def phaseName: String = "pickler" @@ -22,36 +23,48 @@ class Pickler extends MiniPhaseTransform { thisTransform => s.close } - override def transformUnit(tree: Tree)(implicit ctx: Context, info: TransformerInfo): Tree = { - if (!ctx.compilationUnit.isJava) { - val pickler = new TastyPickler + private val beforePickling = new mutable.HashMap[CompilationUnit, String] + + override def run(implicit ctx: Context): Unit = { + val unit = ctx.compilationUnit + if (!unit.isJava) { + val tree = unit.tpdTree pickling.println(i"unpickling in run ${ctx.runId}") - val previous = if (ctx.settings.YtestPickler.value) tree.show else "" - + if (ctx.settings.YtestPickler.value) beforePickling(unit) = tree.show + + val pickler = new TastyPickler val treePkl = new TreePickler(pickler) treePkl.pickle(tree :: Nil) if (tree.pos.exists) new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos) - val bytes = pickler.assembleParts() - ctx.compilationUnit.pickled = bytes + unit.pickled = pickler.assembleParts() def rawBytes = // not needed right now, but useful to print raw format. - bytes.iterator.grouped(10).toList.zipWithIndex.map { + unit.pickled.iterator.grouped(10).toList.zipWithIndex.map { case (row, i) => s"${i}0: ${row.mkString(" ")}" } // println(i"rawBytes = \n$rawBytes%\n%") // DEBUG - if (pickling ne noPrinter) new TastyPrinter(bytes).printContents() - - if (ctx.settings.YtestPickler.value) - unpickle(bytes, previous)(ctx.fresh.setPeriod(Period(ctx.runId + 1, FirstPhaseId))) + if (pickling ne noPrinter) new TastyPrinter(unit.pickled).printContents() + } + } + + override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { + val result = super.runOn(units) + if (ctx.settings.YtestPickler.value) + testUnpickler(units)(ctx.fresh.setPeriod(Period(ctx.runId + 1, FirstPhaseId))) + result + } + + private def testUnpickler(units: List[CompilationUnit])(implicit ctx: Context): Unit = { + println(i"testing unpickler at run ${ctx.runId}") + ctx.definitions.init + for (unit <- units) { + unpickle(unit.pickled, beforePickling(unit)) } - tree } - + private def unpickle(bytes: Array[Byte], previous: String)(implicit ctx: Context) = { - println(i"unpickle run = ${ctx.runId}") - ctx.definitions.init - val unpickled = i"${new DottyUnpickler(bytes, readPositions = false).result}%\n%" + val unpickled = i"${new DottyUnpickler(bytes, Set(), readPositions = false).result}%\n%" println(i"previous :\n $previous") println(i"unpickled:\n $unpickled") if (previous != unpickled) { diff --git a/tests/pos/pickleOK/Coder.scala b/tests/pos/pickleOK/Coder.scala new file mode 100644 index 000000000..77bbd134c --- /dev/null +++ b/tests/pos/pickleOK/Coder.scala @@ -0,0 +1,59 @@ +import collection.mutable.HashMap + +class Coder(words: List[String]) { + + (2 -> "ABC", new ArrowAssoc('3') -> "DEF") + + private val mnemonics = Map( + '2' -> "ABC", '3' -> "DEF", '4' -> "GHI", '5' -> "JKL", + '6' -> "MNO", '7' -> "PQRS", '8' -> "TUV", '9' -> "WXYZ") + + + ('1', "1") match { + case (digit, str) => true + case _ => false + } + + /** Invert the mnemonics map to give a map from chars 'A' ... 'Z' to '2' ... '9' */ + private val charCode0: Map[Char, Char] = mnemonics withFilter { + case (digit, str) => true + case _ => false + } flatMap { x$1 => + x$1 match { + case (digit, str) => str map (ltr => ltr -> digit) + } + } + + private val charCode: Map[Char, Char] = + for ((digit, str) <- mnemonics; ltr <- str) yield ltr -> digit + + /** Maps a word to the digit string it can represent */ + private def wordCode(word: String): String = word map charCode + + /** A map from digit strings to the words that represent them */ + private val wordsForNum: Map[String, List[String]] = + words groupBy wordCode withDefaultValue Nil + + /** All ways to encode a number as a list of words */ + def encode(number: String): Set[List[String]] = + if (number.isEmpty) Set(Nil) + else { + for { + splitPoint <- 1 to number.length + word <- wordsForNum(number take splitPoint) + rest <- encode(number drop splitPoint) + } yield word :: rest + }.toSet + + /** Maps a number to a list of all word phrases that can represent it */ + def translate(number: String): Set[String] = encode(number) map (_ mkString " ") + +} + +object Coder { + def main(args : Array[String]) : Unit = { + val coder = new Coder(List("Scala", "sobls", "Python", "Ruby", "C", "A", "rocks", "sucks", "works", "Racka")) +// println(coder.wordsForNum) + println(coder.translate("7225276257")) + } +} diff --git a/tests/pos/pickleOK/alias.scala b/tests/pos/pickleOK/alias.scala new file mode 100644 index 000000000..a66edc73a --- /dev/null +++ b/tests/pos/pickleOK/alias.scala @@ -0,0 +1,3 @@ +class A(val x: Int) + +class B(x: Int) extends A(x) diff --git a/tests/pos/pickleOK/new-array.scala b/tests/pos/pickleOK/new-array.scala new file mode 100644 index 000000000..a323783de --- /dev/null +++ b/tests/pos/pickleOK/new-array.scala @@ -0,0 +1,17 @@ +package newArray + +object Test { + val w = new Array[String](10) + val x = new Array[Int](10) + def f[T: reflect.ClassTag] = new Array[T](10) + val y = new Array[Any](10) + val z = new Array[Unit](10) +} +object Test2 { + val w: Array[Any] = new Array(10) + val x: Array[Int] = new Array(10) + def f[T: reflect.ClassTag]: Array[T] = new Array(10) + val y: Array[Any] = new Array(10) + val z: Array[Unit] = new Array(10) +} + diff --git a/tests/pos/pickleOK/templateParents.scala b/tests/pos/pickleOK/templateParents.scala new file mode 100644 index 000000000..316d8c81c --- /dev/null +++ b/tests/pos/pickleOK/templateParents.scala @@ -0,0 +1,24 @@ +object templateParents { + + // traits do not call a constructor + class C[+T](val x: T) + trait D extends C[String] + trait E extends C[Int] + class F extends C[Boolean](true) { + def foo = x + } + new C("abc") with D + +} + +object templateParents1 { + // tests inference of synthesized class type + class C[+T] + trait D extends C[String] + trait E extends C[Int] + + val x = new D with E + + val y: C[Int & String] = x +} + diff --git a/tests/pos/pickleOK/unapply.scala b/tests/pos/pickleOK/unapply.scala new file mode 100644 index 000000000..ba885be73 --- /dev/null +++ b/tests/pos/pickleOK/unapply.scala @@ -0,0 +1,11 @@ +object test { + class Foo[T](val arg : T) + + object Foo { + def unapply [a](m : Foo[a]) = Some (m.arg) + } + def matchAndGetArgFromFoo[b]( e:Foo[b]):b = {e match { case Foo(x) => x }} +// Unapply node here will have type argument [a] instantiated to scala.Nothing: +// UnApply(TypeApply(Select(Ident(Foo),unapply),List(TypeTree[TypeVar(PolyParam(a) -> TypeRef(ThisType(TypeRef(NoPrefix,scala)),Nothing))])),List(),List(Bind(x,Ident(_)))) +// but the type of the UnApply node itself is correct: RefinedType(TypeRef(ThisType(TypeRef(ThisType(TypeRef(NoPrefix,<empty>)),test$)),Foo), test$$Foo$$a, TypeAlias(TypeRef(NoPrefix,a))) +} diff --git a/tests/pos/pickleOK/zoo.scala b/tests/pos/pickleOK/zoo.scala new file mode 100644 index 000000000..02dac8f5b --- /dev/null +++ b/tests/pos/pickleOK/zoo.scala @@ -0,0 +1,41 @@ +object Test { +trait FoodStuff +trait Meat extends FoodStuff { + type IsMeat = Any +} +trait Grass extends FoodStuff { + type IsGrass = Any +} +trait Animal { + type Food <: FoodStuff + def eats(food: Food): Unit + def gets: Food +} +trait Cow extends Animal { + type IsMeat = Any + type Food <: Grass + def eats(food: Grass): Unit + def gets: Food +} +trait Lion extends Animal { + type Food = Meat + def eats(food: Meat): Unit + def gets: Meat +} +def newMeat: Meat = new Meat { +} +def newGrass: Grass = new Grass { +} +def newCow: Cow = new Cow { + type Food = Grass + def eats(food: Grass) = () + def gets = newGrass +} +def newLion: Lion = new Lion { + def eats(food: Meat) = () + def gets = newMeat +} +val milka = newCow +val leo = newLion +//leo.eats(milka) // structural select not supported +} |