From 723993e0745d1fc209d434b8fcfeb3d93809f9da Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Sun, 12 Nov 2017 12:16:34 +0100 Subject: [PATCH] Avoid loading compilation units twice For some class name foo.Foo we need to try to load the tasty from the its class. If the class is not definded, we try load it from the obeject. Previously, if both the class and the object extists we were loading the compilation unit twice. Which would duplicate symbols and then fail with duplicated symbol definitions. --- compiler/src/dotty/tools/dotc/FromTasty.scala | 18 ++++++++++++------ tests/pos-from-tasty/simpleCaseObject.scala | 3 +++ .../pos-from-tasty/simpleClassWithObject.scala | 4 ++++ 3 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 tests/pos-from-tasty/simpleCaseObject.scala create mode 100644 tests/pos-from-tasty/simpleClassWithObject.scala diff --git a/compiler/src/dotty/tools/dotc/FromTasty.scala b/compiler/src/dotty/tools/dotc/FromTasty.scala index f3816c5e6480..a9114826b86d 100644 --- a/compiler/src/dotty/tools/dotc/FromTasty.scala +++ b/compiler/src/dotty/tools/dotc/FromTasty.scala @@ -67,16 +67,22 @@ object FromTasty extends Driver { override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = units.flatMap(readTASTY) - def readTASTY(unit: CompilationUnit)(implicit ctx: Context): List[CompilationUnit] = unit match { + def readTASTY(unit: CompilationUnit)(implicit ctx: Context): Option[CompilationUnit] = unit match { case unit: TASTYCompilationUnit => assert(ctx.settings.YretainTrees.value) val className = unit.className.toTypeName - val compilationUnits = List(tree(className), tree(className.moduleClassName)).flatMap { - case Some((clsd, unpickled)) if !unpickled.isEmpty => - List(CompilationUnit.mkCompilationUnit(clsd, unpickled, forceTrees = true)) - case _ => Nil + def compilationUnit(className: TypeName): Option[CompilationUnit] = { + tree(className).flatMap { case (clsd, unpickled) => + if (unpickled.isEmpty) None + else Some(CompilationUnit.mkCompilationUnit(clsd, unpickled, forceTrees = true)) + } } - compilationUnits + // The TASTY section in a/b/C.class may either contain a class a.b.C, an object a.b.C, or both. + // We first try to load the class and fallback to loading the object if the class doesn't exist. + // Note that if both the class and the object are present, then loading the class will also load + // the object, this is why we use orElse here, otherwise we could load the object twice and + // create ambiguities! + compilationUnit(className).orElse(compilationUnit(className.moduleClassName)) } private def tree(className: TypeName)(implicit ctx: Context): Option[(ClassDenotation, tpd.Tree)] = { diff --git a/tests/pos-from-tasty/simpleCaseObject.scala b/tests/pos-from-tasty/simpleCaseObject.scala new file mode 100644 index 000000000000..a6eb6f356137 --- /dev/null +++ b/tests/pos-from-tasty/simpleCaseObject.scala @@ -0,0 +1,3 @@ +package foo + +case object Foo diff --git a/tests/pos-from-tasty/simpleClassWithObject.scala b/tests/pos-from-tasty/simpleClassWithObject.scala new file mode 100644 index 000000000000..41cf70e2e806 --- /dev/null +++ b/tests/pos-from-tasty/simpleClassWithObject.scala @@ -0,0 +1,4 @@ +package foo + +class Foo +object Foo