From 1426fec358342e0b052c5a96ee2b7e60d4d4066b Mon Sep 17 00:00:00 2001 From: James Iry Date: Mon, 4 Feb 2013 14:48:23 -0800 Subject: SI-7070 Turn restriction on companions in pkg objs into warning The implementation restriction created from SI-5954 in 3ef487ecb6733bfe3c13d89780ebcfc81f9a5ea0 has two problems. 1) The problematic code works fine if compile with sbt. That means the restriction is breaking some people needlessly. 2) It's not binary compatible. To fix all that this commit changes the error into a warning and removes the setting used to get around the restriction. --- .../scala/tools/nsc/settings/ScalaSettings.scala | 1 - src/compiler/scala/tools/nsc/typechecker/Typers.scala | 16 ++++++++-------- .../reflect/internal/settings/MutableSettings.scala | 2 -- src/reflect/scala/reflect/runtime/Settings.scala | 1 - test/files/neg/t5954.check | 10 +++++----- test/files/neg/t5954.flags | 1 + test/files/neg/t5954.scala | 2 +- test/files/pos/package-case.flags | 1 - test/files/pos/t2130-1.flags | 1 - test/files/pos/t2130-2.flags | 1 - test/files/pos/t3999b.flags | 1 - test/files/pos/t4052.flags | 1 - 12 files changed, 15 insertions(+), 23 deletions(-) create mode 100644 test/files/neg/t5954.flags delete mode 100644 test/files/pos/package-case.flags delete mode 100644 test/files/pos/t2130-1.flags delete mode 100644 test/files/pos/t2130-2.flags delete mode 100644 test/files/pos/t3999b.flags delete mode 100644 test/files/pos/t4052.flags diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 0a98d45cac..3df6334ec1 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -175,7 +175,6 @@ trait ScalaSettings extends AbsScalaSettings val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.") val Yinvalidate = StringSetting ("-Yinvalidate", "classpath-entry", "Invalidate classpath entry before run", "") val noSelfCheck = BooleanSetting ("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.") - val companionsInPkgObjs = BooleanSetting("-Ycompanions-in-pkg-objs", "Allow companion objects and case classes in package objects. See issue SI-5954.") val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes") val exposeEmptyPackage = BooleanSetting("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly() diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 026c130a87..795ad7e5c7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1914,29 +1914,29 @@ trait Typers extends Modes with Adaptations with Tags { // SI-5954. On second compile of a companion class contained in a package object we end up // with some confusion of names which leads to having two symbols with the same name in the - // same owner. Until that can be straightened out we can't allow companion objects in package + // same owner. Until that can be straightened out we will warn on companion objects in package // objects. But this code also tries to be friendly by distinguishing between case classes and // user written companion pairs - def restrictPackageObjectMembers(mdef : ModuleDef) = for (m <- mdef.symbol.info.members) { + def warnPackageObjectMembers(mdef : ModuleDef) = for (m <- mdef.symbol.info.members) { // ignore synthetic objects, because the "companion" object to a case class is synthetic and // we only want one error per case class if (!m.isSynthetic) { // can't handle case classes in package objects - if (m.isCaseClass) pkgObjectRestriction(m, mdef, "case") + if (m.isCaseClass) pkgObjectWarning(m, mdef, "case") // can't handle companion class/object pairs in package objects else if ((m.isClass && m.companionModule != NoSymbol && !m.companionModule.isSynthetic) || (m.isModule && m.companionClass != NoSymbol && !m.companionClass.isSynthetic)) - pkgObjectRestriction(m, mdef, "companion") + pkgObjectWarning(m, mdef, "companion") } - def pkgObjectRestriction(m : Symbol, mdef : ModuleDef, restricted : String) = { + def pkgObjectWarning(m : Symbol, mdef : ModuleDef, restricted : String) = { val pkgName = mdef.symbol.ownerChain find (_.isPackage) map (_.decodedName) getOrElse mdef.symbol.toString - context.error(if (m.pos.isDefined) m.pos else mdef.pos, s"implementation restriction: package object ${pkgName} cannot contain ${restricted} ${m}. Instead, ${m} should be placed directly in package ${pkgName}.") + context.warning(if (m.pos.isDefined) m.pos else mdef.pos, s"${m} should be placed directly in package ${pkgName} instead of package object ${pkgName}. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954.") } } - if (!settings.companionsInPkgObjs.value && mdef.symbol.isPackageObject) - restrictPackageObjectMembers(mdef) + if (mdef.symbol.isPackageObject) + warnPackageObjectMembers(mdef) treeCopy.ModuleDef(mdef, typedMods, mdef.name, impl2) setType NoType } diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala index ec3501d5bc..81368df7a6 100644 --- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala @@ -47,6 +47,4 @@ abstract class MutableSettings extends AbsSettings { def XoldPatmat: BooleanSetting def XnoPatmatAnalysis: BooleanSetting def XfullLubs: BooleanSetting - def companionsInPkgObjs: BooleanSetting - } diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala index 2d5b76f094..0e0cf3fc40 100644 --- a/src/reflect/scala/reflect/runtime/Settings.scala +++ b/src/reflect/scala/reflect/runtime/Settings.scala @@ -43,7 +43,6 @@ private[reflect] class Settings extends MutableSettings { val printtypes = new BooleanSetting(false) val uniqid = new BooleanSetting(false) val verbose = new BooleanSetting(false) - val companionsInPkgObjs = new BooleanSetting(false) val Yrecursion = new IntSetting(0) val maxClassfileName = new IntSetting(255) diff --git a/test/files/neg/t5954.check b/test/files/neg/t5954.check index 3ca47cd430..ed10658b24 100644 --- a/test/files/neg/t5954.check +++ b/test/files/neg/t5954.check @@ -1,16 +1,16 @@ -t5954.scala:36: error: implementation restriction: package object A cannot contain case class D. Instead, class D should be placed directly in package A. +t5954.scala:36: error: class D should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. case class D() ^ -t5954.scala:35: error: implementation restriction: package object A cannot contain companion object C. Instead, object C should be placed directly in package A. +t5954.scala:35: error: object C should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. object C ^ -t5954.scala:34: error: implementation restriction: package object A cannot contain companion trait C. Instead, trait C should be placed directly in package A. +t5954.scala:34: error: trait C should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. trait C ^ -t5954.scala:33: error: implementation restriction: package object A cannot contain companion object B. Instead, object B should be placed directly in package A. +t5954.scala:33: error: object B should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. object B ^ -t5954.scala:32: error: implementation restriction: package object A cannot contain companion class B. Instead, class B should be placed directly in package A. +t5954.scala:32: error: class B should be placed directly in package A instead of package object A. Under some circumstances companion objects and case classes in package objects can fail to recompile. See https://issues.scala-lang.org/browse/SI-5954. class B ^ 5 errors found diff --git a/test/files/neg/t5954.flags b/test/files/neg/t5954.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/t5954.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/t5954.scala b/test/files/neg/t5954.scala index 9e6f5392c7..3ccb5ed3ff 100644 --- a/test/files/neg/t5954.scala +++ b/test/files/neg/t5954.scala @@ -1,4 +1,4 @@ -// if you ever think you've fixed the underlying reason for the implementation restrictions +// if you ever think you've fixed the underlying reason for the warning // imposed by SI-5954, then here's a test that should pass with two "succes"es // //import scala.tools.partest._ diff --git a/test/files/pos/package-case.flags b/test/files/pos/package-case.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/package-case.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t2130-1.flags b/test/files/pos/t2130-1.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t2130-1.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t2130-2.flags b/test/files/pos/t2130-2.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t2130-2.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t3999b.flags b/test/files/pos/t3999b.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t3999b.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs diff --git a/test/files/pos/t4052.flags b/test/files/pos/t4052.flags deleted file mode 100644 index 2f174c4732..0000000000 --- a/test/files/pos/t4052.flags +++ /dev/null @@ -1 +0,0 @@ --Ycompanions-in-pkg-objs -- cgit v1.2.3 From 79e774f584d5afed72f62b0a7f93f63765d0cb99 Mon Sep 17 00:00:00 2001 From: Mads Hartmann Jensen Date: Sat, 26 Jan 2013 20:01:36 +0100 Subject: SI-7026: parseTree should never return a typed one This commit fixes ticket SI-7026. This makes it safe to use parseTree outside of the presentation compiler thread. Solved it with an implementation that just parses the source every time without trying to memorize anything. Added tests that checks that 1. You get a new parse tree every time you ask for one. 2. You always get a parse tree, never a typed tree. 3. A parse tree should never contain any symbols or types [1]. 4. If you ask for a parse tree and then ask for a typed tree it shouldn't change the parse tree you originally asked for, i.e. property 3 still holds. Additionally the parser is now only interruptible when running on the presentation compiler thread. [1] There is an exception to this though. Some of the nodes that the compiler generates will actually contain symbols. I've chosen to just ignore these special cases for now. --- .../tools/nsc/interactive/CompilerControl.scala | 13 ++-- .../scala/tools/nsc/interactive/Global.scala | 7 +- test/files/presentation/ide-t1001326.check | 4 + test/files/presentation/ide-t1001326/Test.scala | 91 ++++++++++++++++++++++ test/files/presentation/ide-t1001326/src/a/A.scala | 5 ++ 5 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 test/files/presentation/ide-t1001326.check create mode 100644 test/files/presentation/ide-t1001326/Test.scala create mode 100644 test/files/presentation/ide-t1001326/src/a/A.scala diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index b4af8f00d6..73414ea6ed 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -240,15 +240,12 @@ trait CompilerControl { self: Global => } /** Returns parse tree for source `source`. No symbols are entered. Syntax errors are reported. - * Can be called asynchronously from presentation compiler. + * + * This method is thread-safe and as such can safely run outside of the presentation + * compiler thread. */ - def parseTree(source: SourceFile): Tree = ask { () => - getUnit(source) match { - case Some(unit) if unit.status >= JustParsed => - unit.body - case _ => - new UnitParser(new CompilationUnit(source)).parse() - } + def parseTree(source: SourceFile): Tree = { + new UnitParser(new CompilationUnit(source)).parse() } /** Asks for a computation to be done quickly on the presentation compiler thread */ diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 4ab7b98b3d..b804d45b31 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -225,7 +225,10 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") /** Called from parser, which signals hereby that a method definition has been parsed. */ override def signalParseProgress(pos: Position) { - checkForMoreWork(pos) + // We only want to be interruptible when running on the PC thread. + if(onCompilerThread) { + checkForMoreWork(pos) + } } /** Called from typechecker, which signals hereby that a node has been completely typechecked. @@ -447,7 +450,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") */ @elidable(elidable.WARNING) override def assertCorrectThread() { - assert(initializing || (Thread.currentThread() eq compileRunner), + assert(initializing || onCompilerThread, "Race condition detected: You are running a presentation compiler method outside the PC thread.[phase: %s]".format(globalPhase) + " Please file a ticket with the current stack trace at https://www.assembla.com/spaces/scala-ide/support/tickets") } diff --git a/test/files/presentation/ide-t1001326.check b/test/files/presentation/ide-t1001326.check new file mode 100644 index 0000000000..0ac15faed4 --- /dev/null +++ b/test/files/presentation/ide-t1001326.check @@ -0,0 +1,4 @@ +Unique OK +Unattributed OK +NeverModify OK +AlwaysParseTree OK \ No newline at end of file diff --git a/test/files/presentation/ide-t1001326/Test.scala b/test/files/presentation/ide-t1001326/Test.scala new file mode 100644 index 0000000000..3091da4b40 --- /dev/null +++ b/test/files/presentation/ide-t1001326/Test.scala @@ -0,0 +1,91 @@ +import scala.tools.nsc.interactive.tests.InteractiveTest +import scala.reflect.internal.util.SourceFile +import scala.tools.nsc.interactive.Response + +object Test extends InteractiveTest { + + override def execute(): Unit = { + val sf = sourceFiles.find(_.file.name == "A.scala").head + uniqueParseTree_t1001326(sf) + unattributedParseTree_t1001326(sf) + neverModifyParseTree_t1001326(sf) + shouldAlwaysReturnParseTree_t1001326(sf) + } + + /** + * Asking twice for a parseTree on the same source should always return a new tree + */ + private def uniqueParseTree_t1001326(sf: SourceFile) { + val parseTree1 = compiler.parseTree(sf) + val parseTree2 = compiler.parseTree(sf) + if (parseTree1 != parseTree2) { + reporter.println("Unique OK") + } else { + reporter.println("Unique FAILED") + } + } + + /** + * A parseTree should never contain any symbols or types + */ + private def unattributedParseTree_t1001326(sf: SourceFile) { + if (noSymbolsOrTypes(compiler.parseTree(sf))) { + reporter.println("Unattributed OK") + } else { + reporter.println("Unattributed FAILED") + } + } + + /** + * Once you have obtained a parseTree it should never change + */ + private def neverModifyParseTree_t1001326(sf: SourceFile) { + val parsedTree = compiler.parseTree(sf) + loadSourceAndWaitUntilTypechecked(sf) + if (noSymbolsOrTypes(parsedTree)) { + reporter.println("NeverModify OK") + } else { + reporter.println("NeverModify FAILED") + } + } + + /** + * Should always return a parse tree + */ + private def shouldAlwaysReturnParseTree_t1001326(sf: SourceFile) { + loadSourceAndWaitUntilTypechecked(sf) + if (noSymbolsOrTypes(compiler.parseTree(sf))) { + reporter.println("AlwaysParseTree OK") + } else { + reporter.println("AlwaysParseTree FAILED") + } + } + + /** + * Load a source and block while it is type-checking. + */ + private def loadSourceAndWaitUntilTypechecked(sf: SourceFile): Unit = { + compiler.askToDoFirst(sf) + val res = new Response[Unit] + compiler.askReload(List(sf), res) + res.get + askLoadedTyped(sf).get + } + + /** + * Traverses a tree and makes sure that there are no types or symbols present in the tree with + * the exception of the symbol for the package 'scala'. This is because that symbol will be + * present in some of the nodes that the compiler generates. + */ + private def noSymbolsOrTypes(tree: compiler.Tree): Boolean = { + tree.forAll { t => + (t.symbol == null || + t.symbol == compiler.NoSymbol || + t.symbol == compiler.definitions.ScalaPackage // ignore the symbol for the scala package for now + ) && ( + t.tpe == null || + t.tpe == compiler.NoType) + } + } + +} \ No newline at end of file diff --git a/test/files/presentation/ide-t1001326/src/a/A.scala b/test/files/presentation/ide-t1001326/src/a/A.scala new file mode 100644 index 0000000000..c82ca02231 --- /dev/null +++ b/test/files/presentation/ide-t1001326/src/a/A.scala @@ -0,0 +1,5 @@ +package a + +class A { + def foo(s: String) = s + s +} \ No newline at end of file -- cgit v1.2.3 From 96b0eff51e18a1abd9761451e08e63c9a3eb9ea6 Mon Sep 17 00:00:00 2001 From: Evgeny Kotelnikov Date: Sat, 19 Jan 2013 17:42:12 +0400 Subject: SI-5824 Fix crashes in reify with _* Reification crashes if "foo: _*" construct is used. This happens besause type tree is represented either with TypeTree, or with Ident (present case), and `toPreTyperTypedOrAnnotated' only matches of the former. The fix is to cover the latter too. A test is included. --- src/compiler/scala/reflect/reify/codegen/GenTrees.scala | 2 +- src/compiler/scala/reflect/reify/phases/Reshape.scala | 12 ++++++++---- src/reflect/scala/reflect/internal/TreeInfo.scala | 7 +++++++ test/files/run/t5824.check | 1 + test/files/run/t5824.scala | 8 ++++++++ 5 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 test/files/run/t5824.check create mode 100644 test/files/run/t5824.scala diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index 31974b5b76..45865268cd 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -177,7 +177,7 @@ trait GenTrees { // then we can reify the scrutinee as a symless AST and that will definitely be hygienic // why? because then typechecking of a scrutinee doesn't depend on the environment external to the quasiquote // otherwise we need to reify the corresponding type - if (sym.isLocalToReifee || tpe.isLocalToReifee) + if (sym.isLocalToReifee || tpe.isLocalToReifee || treeInfo.isWildcardStarType(tree)) reifyProduct(tree) else { if (reifyDebug) println("reifying bound type %s (underlying type is %s)".format(sym, tpe)) diff --git a/src/compiler/scala/reflect/reify/phases/Reshape.scala b/src/compiler/scala/reflect/reify/phases/Reshape.scala index 1b7509fdbe..7406f5d02d 100644 --- a/src/compiler/scala/reflect/reify/phases/Reshape.scala +++ b/src/compiler/scala/reflect/reify/phases/Reshape.scala @@ -188,8 +188,12 @@ trait Reshape { } private def toPreTyperTypedOrAnnotated(tree: Tree): Tree = tree match { - case ty @ Typed(expr1, tt @ TypeTree()) => + case ty @ Typed(expr1, tpt) => if (reifyDebug) println("reify typed: " + tree) + val original = tpt match { + case tt @ TypeTree() => tt.original + case tpt => tpt + } val annotatedArg = { def loop(tree: Tree): Tree = tree match { case annotated1 @ Annotated(ann, annotated2 @ Annotated(_, _)) => loop(annotated2) @@ -197,15 +201,15 @@ trait Reshape { case _ => EmptyTree } - loop(tt.original) + loop(original) } if (annotatedArg != EmptyTree) { if (annotatedArg.isType) { if (reifyDebug) println("verdict: was an annotated type, reify as usual") ty } else { - if (reifyDebug) println("verdict: was an annotated value, equivalent is " + tt.original) - toPreTyperTypedOrAnnotated(tt.original) + if (reifyDebug) println("verdict: was an annotated value, equivalent is " + original) + toPreTyperTypedOrAnnotated(original) } } else { if (reifyDebug) println("verdict: wasn't annotated, reify as usual") diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 98c1afb323..44dd92e62b 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -431,6 +431,13 @@ abstract class TreeInfo { case _ => false } + /** Is the argument a wildcard star type of the form `_*`? + */ + def isWildcardStarType(tree: Tree): Boolean = tree match { + case Ident(tpnme.WILDCARD_STAR) => true + case _ => false + } + /** Is this pattern node a catch-all (wildcard or variable) pattern? */ def isDefaultCase(cdef: CaseDef) = cdef match { case CaseDef(pat, EmptyTree, _) => isWildcardArg(pat) diff --git a/test/files/run/t5824.check b/test/files/run/t5824.check new file mode 100644 index 0000000000..3774da60e5 --- /dev/null +++ b/test/files/run/t5824.check @@ -0,0 +1 @@ +a b c diff --git a/test/files/run/t5824.scala b/test/files/run/t5824.scala new file mode 100644 index 0000000000..2ad169e2d1 --- /dev/null +++ b/test/files/run/t5824.scala @@ -0,0 +1,8 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object Test extends App { + reify { + println("%s %s %s".format(List("a", "b", "c"): _*)) + }.eval +} -- cgit v1.2.3 From 0d68a874e2158d9739abd3977ae0d9edd4a76e59 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Thu, 7 Feb 2013 18:45:34 +0100 Subject: SI-6113 typeOf now works for type lambdas It's not a problem to have an abstract type symbol in a ground type tag if that symbol is defined in the type being reified. This mechanics was already built in for existentials, now we extend it to include type params of poly types. Credit goes to @katefree --- src/compiler/scala/reflect/reify/codegen/GenTypes.scala | 3 +-- src/compiler/scala/reflect/reify/phases/Reify.scala | 5 ++++- test/files/run/t6113.check | 1 + test/files/run/t6113.scala | 6 ++++++ 4 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 test/files/run/t6113.check create mode 100644 test/files/run/t6113.scala diff --git a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala index 7aa87dc2f8..bb7e1f9b56 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala @@ -69,8 +69,7 @@ trait GenTypes { def reificationIsConcrete: Boolean = state.reificationIsConcrete def spliceType(tpe: Type): Tree = { - val quantified = currentQuantified - if (tpe.isSpliceable && !(quantified contains tpe.typeSymbol)) { + if (tpe.isSpliceable && !(boundSymbolsInCallstack contains tpe.typeSymbol)) { if (reifyDebug) println("splicing " + tpe) val tagFlavor = if (concrete) tpnme.TypeTag.toString else tpnme.WeakTypeTag.toString diff --git a/src/compiler/scala/reflect/reify/phases/Reify.scala b/src/compiler/scala/reflect/reify/phases/Reify.scala index dc0028be38..8e13a45cdb 100644 --- a/src/compiler/scala/reflect/reify/phases/Reify.scala +++ b/src/compiler/scala/reflect/reify/phases/Reify.scala @@ -28,7 +28,10 @@ trait Reify extends GenSymbols finally currents = currents.tail } } - def currentQuantified = flatCollect(reifyStack.currents)({ case ExistentialType(quantified, _) => quantified }) + def boundSymbolsInCallstack = flatCollect(reifyStack.currents) { + case ExistentialType(quantified, _) => quantified + case PolyType(typeParams, _) => typeParams + } def current = reifyStack.currents.head def currents = reifyStack.currents diff --git a/test/files/run/t6113.check b/test/files/run/t6113.check new file mode 100644 index 0000000000..65fb3cd090 --- /dev/null +++ b/test/files/run/t6113.check @@ -0,0 +1 @@ +Foo[[X](Int, X)] diff --git a/test/files/run/t6113.scala b/test/files/run/t6113.scala new file mode 100644 index 0000000000..321cae86a3 --- /dev/null +++ b/test/files/run/t6113.scala @@ -0,0 +1,6 @@ +trait Foo[C[_]] + +object Test extends App { + import scala.reflect.runtime.universe._ + println(typeOf[Foo[({type l[X] = (Int, X)})#l]]) +} \ No newline at end of file -- cgit v1.2.3 From a0ee6e996e602bf5729687d7301f60b340d57061 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 28 Jan 2013 16:36:27 +0100 Subject: SI-5082 Cycle avoidance between case companions We can synthesize the case companion unapply without forcing the info of the case class, by looking at the parameters in the `ClassDef` tree, rather than at `sym.caseFieldAccessors`. Access to non-public case class fields routed through the already-renamed case accessor methods. The renamings are conveyed via a back-channel (a per-run map, `renamedCaseAccessors`), rather than via the types to give us enough slack to avoid the cycle. Some special treatment of private[this] parameters is needed to avoid a misleading error message. Fortunately, we can determine this without forcing the info of the case class, by inspecting the parameter accessor trees. This change may allow us to resurrect the case class ProductN parentage, which was trialled but abandoned in the lead up to 2.10.0. --- .../tools/nsc/typechecker/SyntheticMethods.scala | 6 ++++ .../scala/tools/nsc/typechecker/Unapplies.scala | 33 ++++++++++++++++++---- test/files/pos/t5082.scala | 14 +++++++++ 3 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 test/files/pos/t5082.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 39f6f764e7..242eb9c9fe 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -50,6 +50,10 @@ trait SyntheticMethods extends ast.TreeDSL { else if (clazz.isDerivedValueClass) valueSymbols else Nil } + private lazy val renamedCaseAccessors = perRunCaches.newMap[Symbol, mutable.Map[TermName, TermName]]() + /** Does not force the info of `caseclazz` */ + final def caseAccessorName(caseclazz: Symbol, paramName: TermName) = + (renamedCaseAccessors get caseclazz).fold(paramName)(_(paramName)) /** Add the synthetic methods to case classes. */ @@ -384,6 +388,8 @@ trait SyntheticMethods extends ast.TreeDSL { // TODO: shouldn't the next line be: `original resetFlag CASEACCESSOR`? ddef.symbol resetFlag CASEACCESSOR lb += logResult("case accessor new")(newAcc) + val renamedInClassMap = renamedCaseAccessors.getOrElseUpdate(clazz, mutable.Map() withDefault(x => x)) + renamedInClassMap(original.name.toTermName) = newAcc.symbol.name.toTermName } (lb ++= templ.body ++= synthesize()).toList diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 8f607e9f67..e143015bbb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -93,12 +93,33 @@ trait Unapplies extends ast.TreeDSL * @param param The name of the parameter of the unapply method, assumed to be of type C[Ts] * @param caseclazz The case class C[Ts] */ - private def caseClassUnapplyReturnValue(param: Name, caseclazz: Symbol) = { - def caseFieldAccessorValue(selector: Symbol): Tree = Ident(param) DOT selector + private def caseClassUnapplyReturnValue(param: Name, caseclazz: ClassDef) = { + def caseFieldAccessorValue(selector: ValDef): Tree = { + val accessorName = selector.name + val privateLocalParamAccessor = caseclazz.impl.body.collectFirst { + case dd: ValOrDefDef if dd.name == accessorName && dd.mods.isPrivateLocal => dd.symbol + } + privateLocalParamAccessor match { + case None => + // Selecting by name seems to be the most straight forward way here to + // avoid forcing the symbol of the case class in order to list the accessors. + val maybeRenamedAccessorName = caseAccessorName(caseclazz.symbol, accessorName) + Ident(param) DOT maybeRenamedAccessorName + case Some(sym) => + // But, that gives a misleading error message in neg/t1422.scala, where a case + // class has an illegal private[this] parameter. We can detect this by checking + // the modifiers on the param accessors. + // + // We just generate a call to that param accessor here, which gives us an inaccessible + // symbol error, as before. + Ident(param) DOT sym + } + } - caseclazz.caseFieldAccessors match { - case Nil => TRUE - case xs => SOME(xs map caseFieldAccessorValue: _*) + // Working with trees, rather than symbols, to avoid cycles like SI-5082 + constrParamss(caseclazz).take(1).flatten match { + case Nil => TRUE + case xs => SOME(xs map caseFieldAccessorValue: _*) } } @@ -157,7 +178,7 @@ trait Unapplies extends ast.TreeDSL } val cparams = List(ValDef(Modifiers(PARAM | SYNTHETIC), unapplyParamName, classType(cdef, tparams), EmptyTree)) val ifNull = if (constrParamss(cdef).head.isEmpty) FALSE else REF(NoneModule) - val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef.symbol) }, ifNull)(Ident(unapplyParamName)) + val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef) }, ifNull)(Ident(unapplyParamName)) atPos(cdef.pos.focus)( DefDef(caseMods, method, tparams, List(cparams), TypeTree(), body) diff --git a/test/files/pos/t5082.scala b/test/files/pos/t5082.scala new file mode 100644 index 0000000000..63eeda38ba --- /dev/null +++ b/test/files/pos/t5082.scala @@ -0,0 +1,14 @@ +trait Something[T] +object Test { class A } +case class Test() extends Something[Test.A] + +object User { + val Test() = Test() +} + +object Wrap { + trait Something[T] + object Test { class A } + case class Test(a: Int, b: Int)(c: String) extends Something[Test.A] + val Test(x, y) = Test(1, 2)(""); (x + y).toString +} -- cgit v1.2.3 From 55c9b9c280ac9bc36bbac09397c7646f8dcf4583 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 31 Jan 2013 00:33:19 +0100 Subject: SI-6146 More accurate prefixes for sealed subtypes. When analysing exhaustivity/reachability of type tests and equality tests, the pattern matcher must construct a set of sealed subtypes based on the prefix of the static type of and the set of sealed descendent symbols of that type. Previously, it was using `memberType` for this purpose. In simple cases, this is sufficient: scala> class C { class I1; object O { class I2 } }; object D extends C defined class C defined module D scala> typeOf[D.type] memberType typeOf[C#I1].typeSymbol res0: u.Type = D.I1 But, as reported in this bug, it fails when there is an additional level of nesting: scala> typeOf[D.type] memberType typeOf[c.O.I2 forSome { val c: C }].typeSymbol res5: u.Type = C.O.I2 This commit introduces `nestedMemberType`, which uses `memberType` recursively up the prefix chain prefix chain. scala> nestedMemberType(typeOf[c.O.I2 forSome { val c: C }].typeSymbol, typeOf[D.type], typeOf[C].typeSymbol) res6: u.Type = D.O.Id --- .../scala/tools/nsc/interpreter/IMain.scala | 4 +- .../tools/nsc/typechecker/PatternMatching.scala | 4 +- src/reflect/scala/reflect/internal/Types.scala | 51 ++++++++++++++++-- test/files/pos/t6146.flags | 1 + test/files/pos/t6146.scala | 60 ++++++++++++++++++++++ test/files/run/t6146b.check | 52 +++++++++++++++++++ test/files/run/t6146b.scala | 39 ++++++++++++++ 7 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 test/files/pos/t6146.flags create mode 100644 test/files/pos/t6146.scala create mode 100644 test/files/run/t6146b.check create mode 100644 test/files/run/t6146b.scala diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index a55f0af116..bed8570bd0 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -262,7 +262,9 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends protected def newCompiler(settings: Settings, reporter: Reporter): ReplGlobal = { settings.outputDirs setSingleOutput virtualDirectory settings.exposeEmptyPackage.value = true - new Global(settings, reporter) with ReplGlobal + new Global(settings, reporter) with ReplGlobal { + override def toString: String = "" + } } /** Parent classloader. Overridable. */ diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index 452957745a..4a765ea22e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -2818,7 +2818,9 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // compare to the fully known type `tp` (modulo abstract types), // so that we can rule out stuff like: sealed trait X[T]; class XInt extends X[Int] --> XInt not valid when enumerating X[String] // however, must approximate abstract types in - val subTp = appliedType(pre.memberType(sym), sym.typeParams.map(_ => WildcardType)) + + val memberType = nestedMemberType(sym, pre, tpApprox.typeSymbol.owner) + val subTp = appliedType(memberType, sym.typeParams.map(_ => WildcardType)) val subTpApprox = typer.infer.approximateAbstracts(subTp) // TODO: needed? // patmatDebug("subtp"+(subTpApprox <:< tpApprox, subTpApprox, tpApprox)) if (subTpApprox <:< tpApprox) Some(checkableType(subTp)) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 0dd98fb6ae..b708ca0fd6 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -586,9 +586,9 @@ trait Types extends api.Types { self: SymbolTable => * Expands type aliases and converts higher-kinded TypeRefs to PolyTypes. * Functions on types are also implemented as PolyTypes. * - * Example: (in the below, is the type constructor of List) - * TypeRef(pre, , List()) is replaced by - * PolyType(X, TypeRef(pre, , List(X))) + * Example: (in the below, `` is the type constructor of List) + * TypeRef(pre, ``, List()) is replaced by + * PolyType(X, TypeRef(pre, ``, List(X))) */ def normalize = this // @MAT @@ -4974,6 +4974,51 @@ trait Types extends api.Types { self: SymbolTable => } } + /** + * A more persistent version of `Type#memberType` which does not require + * that the symbol is a direct member of the prefix. + * + * For instance: + * + * {{{ + * class C[T] { + * sealed trait F[A] + * object X { + * object S1 extends F[T] + * } + * class S2 extends F[T] + * } + * object O extends C[Int] { + * def foo(f: F[Int]) = f match {...} // need to enumerate sealed subtypes of the scrutinee here. + * } + * class S3 extends O.F[String] + * + * nestedMemberType(, , ) = O.X.S1.type + * nestedMemberType(, , ) = O.S2.type + * nestedMemberType(, , ) = S3.type + * }}} + * + * @param sym The symbol of the subtype + * @param pre The prefix from which the symbol is seen + * @param owner + */ + def nestedMemberType(sym: Symbol, pre: Type, owner: Symbol): Type = { + def loop(tp: Type): Type = + if (tp.isTrivial) tp + else if (tp.prefix.typeSymbol isNonBottomSubClass owner) { + val widened = tp match { + case _: ConstantType => tp // Java enum constants: don't widen to the enum type! + case _ => tp.widen // C.X.type widens to C.this.X.type, otherwise `tp asSeenFrom (pre, C)` has no effect. + } + widened asSeenFrom (pre, tp.typeSymbol.owner) + } + else loop(tp.prefix) memberType tp.typeSymbol + + val result = loop(sym.tpeHK) + assert(sym.isTerm || result.typeSymbol == sym, s"($result).typeSymbol = ${result.typeSymbol}; expected ${sym}") + result + } + /** The most deeply nested owner that contains all the symbols * of thistype or prefixless typerefs/singletype occurrences in given type. */ diff --git a/test/files/pos/t6146.flags b/test/files/pos/t6146.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/pos/t6146.flags @@ -0,0 +1 @@ +-Xfatal-warnings \ No newline at end of file diff --git a/test/files/pos/t6146.scala b/test/files/pos/t6146.scala new file mode 100644 index 0000000000..b5bde826b1 --- /dev/null +++ b/test/files/pos/t6146.scala @@ -0,0 +1,60 @@ +// No unreachable or exhaustiveness warnings, please. + +// +// The reported bug +// + +trait AxisCompanion { + sealed trait Format + object Format { + case object Decimal extends Format + case object Integer extends Format + // Gives an unrelated warning: The outer reference in this type test cannot be checked at run time. + //final case class Time( hours: Boolean = false, millis: Boolean = true ) extends Format + } +} +object Axis extends AxisCompanion +class Axis { + import Axis._ + def test( f: Format ) = f match { + case Format.Integer => "Int" + // case Format.Time( hours, millis ) => "Time" + case Format.Decimal => "Dec" + } +} + + +// +// Some tricksier variations +// + +trait T1[X] { + trait T2[Y] { + sealed trait Format + object Format { + case object Decimal extends Format + case object Integer extends Format + } + } +} + +object O1 extends T1[Any] { + object O2 extends T2[Any] { + + } +} + +case object Shorty extends O1.O2.Format + +class Test1 { + import O1.O2._ + val FI: Format.Integer.type = Format.Integer + def test( f: Format ) = { + val ff: f.type = f + ff match { + case FI => "Int" + case Format.Decimal => "Dec" + case Shorty => "Sho" + } + } +} diff --git a/test/files/run/t6146b.check b/test/files/run/t6146b.check new file mode 100644 index 0000000000..b664d1152a --- /dev/null +++ b/test/files/run/t6146b.check @@ -0,0 +1,52 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> :power +** Power User mode enabled - BEEP WHIR GYVE ** +** :phase has been set to 'typer'. ** +** scala.tools.nsc._ has been imported ** +** global._, definitions._ also imported ** +** Try :help, :vals, power. ** + +scala> val u = rootMirror.universe; import u._, language._ +u: $r.intp.global.type = +import u._ +import language._ + +scala> val S1 = typeOf[c.X.S1.type forSome { val c: C[_] }].typeSymbol.tpeHK +S1: u.Type = C.X.S1.type + +scala> val S2 = typeOf[O.S2].typeSymbol.tpeHK +S2: u.Type = C.this.S2 + +scala> val S3 = typeOf[O.S3].typeSymbol.tpeHK +S3: u.Type = O.S3 + +scala> val S4 = typeOf[S4].typeSymbol.tpeHK +S4: u.Type = S4 + +scala> val F = typeOf[c.F[_] forSome { val c: C[_] }].typeSymbol.tpeHK +F: u.Type = C.this.F + +scala> val fTpe = typeOf[O.type].decl(newTermName("foo")).paramss.head.head.tpe +fTpe: u.Type = O.F[Int] + +scala> def memType(sub: Type, scrut: Type): Type = + nestedMemberType(sub.typeSymbol, scrut.prefix, scrut.typeSymbol.owner) +memType: (sub: u.Type, scrut: u.Type)u.Type + +scala> + +scala> memType(S1, fTpe) +res0: u.Type = O.X.S1.type + +scala> memType(S2, fTpe) +res1: u.Type = O.S2 + +scala> memType(S3, fTpe) +res2: u.Type = O.S3 + +scala> memType(S4, fTpe) +res3: u.Type = S4 + +scala> diff --git a/test/files/run/t6146b.scala b/test/files/run/t6146b.scala new file mode 100644 index 0000000000..adcd40d2ee --- /dev/null +++ b/test/files/run/t6146b.scala @@ -0,0 +1,39 @@ +import scala.tools.partest.ReplTest + +class A { + sealed trait F[A] +} + +class C[T] extends A { + sealed trait F[A] + object X { + object S1 extends F[T] + } + class S2 extends F[T] +} +object O extends C[Int] { + def foo(f: F[Int]) = f match { case X.S1 => } + + class S3 extends F[Int] +} +class S4 extends O.F[String] + +object Test extends ReplTest { + override def code = """ +:power +val u = rootMirror.universe; import u._, language._ +val S1 = typeOf[c.X.S1.type forSome { val c: C[_] }].typeSymbol.tpeHK +val S2 = typeOf[O.S2].typeSymbol.tpeHK +val S3 = typeOf[O.S3].typeSymbol.tpeHK +val S4 = typeOf[S4].typeSymbol.tpeHK +val F = typeOf[c.F[_] forSome { val c: C[_] }].typeSymbol.tpeHK +val fTpe = typeOf[O.type].decl(newTermName("foo")).paramss.head.head.tpe +def memType(sub: Type, scrut: Type): Type = + nestedMemberType(sub.typeSymbol, scrut.prefix, scrut.typeSymbol.owner) + +memType(S1, fTpe) +memType(S2, fTpe) +memType(S3, fTpe) +memType(S4, fTpe) + """.stripMargin.trim +} \ No newline at end of file -- cgit v1.2.3 From a53e1508660f849e86e34808e5d4230b078f7a3e Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Thu, 7 Feb 2013 23:33:07 +0100 Subject: SI-7100 Fixed infinite recursion in duplicators --- src/compiler/scala/tools/nsc/typechecker/Duplicators.scala | 2 +- test/files/pos/SI-7100.scala | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 test/files/pos/SI-7100.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 0b46582cbf..f6142a81be 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -388,7 +388,7 @@ abstract class Duplicators extends Analyzer { cases } - super.typedPos(tree.pos, mode, pt)(Match(scrut, cases1)) + super.typed(atPos(tree.pos)(Match(scrut, cases1)), mode, pt) case EmptyTree => // no need to do anything, in particular, don't set the type to null, EmptyTree.tpe_= asserts diff --git a/test/files/pos/SI-7100.scala b/test/files/pos/SI-7100.scala new file mode 100644 index 0000000000..7cb6356ec8 --- /dev/null +++ b/test/files/pos/SI-7100.scala @@ -0,0 +1,6 @@ +class Buffer { + def f[@specialized(Int) T](): T = 0 match { + case 0 => 0.asInstanceOf[T] + case 1 => 0.asInstanceOf[T] + } +} -- cgit v1.2.3 From 6052e19292c95270ac0a4bf30b6df47a257f88d4 Mon Sep 17 00:00:00 2001 From: James Roper Date: Fri, 5 Oct 2012 12:22:24 +1000 Subject: [backport] SI-6478 Fixing JavaTokenParser ident Backport of 256934160007079f473131469af2df4d023c2cfc from PR https://github.com/scala/scala/pull/1466 --- .../util/parsing/combinator/JavaTokenParsers.scala | 7 +++--- test/files/run/parserJavaIdent.check | 26 ++++++++++++++++++++++ test/files/run/parserJavaIdent.scala | 26 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 test/files/run/parserJavaIdent.check create mode 100644 test/files/run/parserJavaIdent.scala diff --git a/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala b/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala index 78817cfb67..89832d3fb2 100644 --- a/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala +++ b/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala @@ -21,11 +21,12 @@ import scala.annotation.migration * - `floatingPointNumber` */ trait JavaTokenParsers extends RegexParsers { - /** Anything starting with an ASCII alphabetic character or underscore, - * followed by zero or more repetitions of regex's `\w`. + /** Anything that is a valid Java identifier, according to + * The Java Language Spec. + * Generally, this means a letter, followed by zero or more letters or numbers. */ def ident: Parser[String] = - """[a-zA-Z_]\w*""".r + """\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*""".r /** An integer, without sign or with a negative sign. */ def wholeNumber: Parser[String] = """-?\d+""".r diff --git a/test/files/run/parserJavaIdent.check b/test/files/run/parserJavaIdent.check new file mode 100644 index 0000000000..597ddbee47 --- /dev/null +++ b/test/files/run/parserJavaIdent.check @@ -0,0 +1,26 @@ +[1.7] parsed: simple +[1.8] parsed: with123 +[1.6] parsed: with$ +[1.10] parsed: withøßöèæ +[1.6] parsed: with_ +[1.6] parsed: _with +[1.1] failure: java identifier expected + +3start +^ +[1.1] failure: java identifier expected + +-start +^ +[1.5] failure: java identifier expected + +with-s + ^ +[1.3] failure: java identifier expected + +we♥scala + ^ +[1.6] failure: java identifier expected + +with space + ^ diff --git a/test/files/run/parserJavaIdent.scala b/test/files/run/parserJavaIdent.scala new file mode 100644 index 0000000000..c068075e4e --- /dev/null +++ b/test/files/run/parserJavaIdent.scala @@ -0,0 +1,26 @@ +object Test extends scala.util.parsing.combinator.JavaTokenParsers { + + def test[A](s: String) { + val res = parseAll(ident, s) match { + case Failure(_, in) => Failure("java identifier expected", in) + case o => o + } + println(res) + } + + def main(args: Array[String]) { + // Happy tests + test("simple") + test("with123") + test("with$") + test("withøßöèæ") + test("with_") + test("_with") + // Sad tests + test("3start") + test("-start") + test("with-s") + test("we♥scala") + test("with space") + } +} -- cgit v1.2.3 From dfbaaa179fddd3d37abf66a08080f646b8557b6f Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 27 Jan 2013 13:31:06 +0100 Subject: SI-6187 Make partial functions re-typable - `New(tpe)` doesn't survive a `resetAttrs` / typecheck; use a name instead. - Abandon the tree attachment that passed the default case from `typer` to `patmat`; this tree eluded the attribute reset performed in the macro. Instead, add it to the match. Apart from making the tree re-typable, it also exposes the true code structure to macros, which is important if they need to perform other code transformations. - Install original trees on the declared types of the parameters of the `applyOrElse` method to ensure that references to them within the method pick up the correct type parameter skolems upon retypechecking. - Propagate `TypeTree#original` through `copyAttrs`, which is called during tree duplication / `TreeCopiers`. Without this, the original trees that we installed were not visible anymore during `ResetAttrs`. We are not able to reify partial functions yet -- the particular sticking point is reification of the parentage which is only available in the `ClassInfoType`. --- .../tools/nsc/typechecker/PatternMatching.scala | 23 +++--- .../scala/tools/nsc/typechecker/Typers.scala | 85 ++++++++++++++++++---- src/reflect/scala/reflect/internal/StdNames.scala | 1 + src/reflect/scala/reflect/internal/TreeInfo.scala | 7 ++ src/reflect/scala/reflect/internal/Trees.scala | 18 ++++- test/files/run/idempotency-partial-functions.scala | 25 ------- test/files/run/t6187.check | 32 ++++++++ test/files/run/t6187.scala | 18 +++++ test/files/run/t6187b.scala | 5 ++ .../run/idempotency-partial-functions.scala | 28 +++++++ 10 files changed, 192 insertions(+), 50 deletions(-) delete mode 100644 test/files/run/idempotency-partial-functions.scala create mode 100644 test/files/run/t6187.check create mode 100644 test/files/run/t6187.scala create mode 100644 test/files/run/t6187b.scala create mode 100644 test/pending/run/idempotency-partial-functions.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index 452957745a..80d628d7ac 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -109,9 +109,6 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL import definitions._ import analyzer._ //Typer - - case class DefaultOverrideMatchAttachment(default: Tree) - object vpmName { val one = newTermName("one") val drop = newTermName("drop") @@ -222,11 +219,11 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // However this is a pain (at least the way I'm going about it) // and I have to think these detailed errors are primarily useful // for beginners, not people writing nested pattern matches. - def checkMatchVariablePatterns(m: Match) { + def checkMatchVariablePatterns(cases: List[CaseDef]) { // A string describing the first variable pattern var vpat: String = null // Using an iterator so we can recognize the last case - val it = m.cases.iterator + val it = cases.iterator def addendum(pat: Tree) = { matchingSymbolInScope(pat) match { @@ -269,7 +266,15 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL */ def translateMatch(match_ : Match): Tree = { val Match(selector, cases) = match_ - checkMatchVariablePatterns(match_) + + val (nonSyntheticCases, defaultOverride) = cases match { + case init :+ last if treeInfo isSyntheticDefaultCase last => + (init, Some(((scrut: Tree) => last.body))) + case _ => + (cases, None) + } + + checkMatchVariablePatterns(nonSyntheticCases) // we don't transform after uncurry // (that would require more sophistication when generating trees, @@ -296,14 +301,10 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // val packedPt = repeatedToSeq(typer.packedType(match_, context.owner)) - // the alternative to attaching the default case override would be to simply - // append the default to the list of cases and suppress the unreachable case error that may arise (once we detect that...) - val matchFailGenOverride = match_.attachments.get[DefaultOverrideMatchAttachment].map{case DefaultOverrideMatchAttachment(default) => ((scrut: Tree) => default)} - val selectorSym = freshSym(selector.pos, pureType(selectorTp)) setFlag treeInfo.SYNTH_CASE_FLAGS // pt = Any* occurs when compiling test/files/pos/annotDepMethType.scala with -Xexperimental - val combined = combineCases(selector, selectorSym, cases map translateCase(selectorSym, pt), pt, matchOwner, matchFailGenOverride) + val combined = combineCases(selector, selectorSym, nonSyntheticCases map translateCase(selectorSym, pt), pt, matchOwner, defaultOverride) if (Statistics.canEnable) Statistics.stopTimer(patmatNanos, start) combined diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index f518712701..5add9b4991 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -30,7 +30,6 @@ trait Typers extends Modes with Adaptations with Tags { import global._ import definitions._ import TypersStats._ - import patmat.DefaultOverrideMatchAttachment final def forArgMode(fun: Tree, mode: Int) = if (treeInfo.isSelfOrSuperConstrCall(fun)) mode | SCCmode @@ -2604,8 +2603,13 @@ trait Typers extends Modes with Adaptations with Tags { def mkParam(methodSym: Symbol, tp: Type = argTp) = methodSym.newValueParameter(paramName, paramPos.focus, SYNTHETIC) setInfo tp + def mkDefaultCase(body: Tree) = + atPos(tree.pos.makeTransparent) { + CaseDef(Bind(nme.DEFAULT_CASE, Ident(nme.WILDCARD)), body) + } + // `def applyOrElse[A1 <: $argTp, B1 >: $matchResTp](x: A1, default: A1 => B1): B1 = - // ${`$selector match { $cases }` updateAttachment DefaultOverrideMatchAttachment(REF(default) APPLY (REF(x)))}` + // ${`$selector match { $cases; case default$ => default(x) }` def applyOrElseMethodDef = { val methodSym = anonClass.newMethod(nme.applyOrElse, tree.pos, FINAL | OVERRIDE) @@ -2614,7 +2618,7 @@ trait Typers extends Modes with Adaptations with Tags { val x = mkParam(methodSym, A1.tpe) // applyOrElse's default parameter: - val B1 = methodSym newTypeParameter (newTypeName("B1")) setInfo TypeBounds.empty //lower(resTp) + val B1 = methodSym newTypeParameter (newTypeName("B1")) setInfo TypeBounds.empty val default = methodSym newValueParameter (newTermName("default"), tree.pos.focus, SYNTHETIC) setInfo functionType(List(A1.tpe), B1.tpe) val paramSyms = List(x, default) @@ -2624,19 +2628,72 @@ trait Typers extends Modes with Adaptations with Tags { // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) paramSyms foreach (methodBodyTyper.context.scope enter _) - val match_ = methodBodyTyper.typedMatch(selector, cases, mode, resTp) + // First, type without the default case; only the cases provided + // by the user are typed. The LUB of these becomes `B`, the lower + // bound of `B1`, which in turn is the result type of the default + // case + val match0 = methodBodyTyper.typedMatch(selector, cases, mode, resTp) + val matchResTp = match0.tpe - val matchResTp = match_.tpe B1 setInfo TypeBounds.lower(matchResTp) // patch info + // the default uses applyOrElse's first parameter since the scrut's type has been widened + val match_ = { + val defaultCase = methodBodyTyper.typedCase( + mkDefaultCase(methodBodyTyper.typed1(REF(default) APPLY (REF(x)), mode, B1.tpe).setType(B1.tpe)), argTp, B1.tpe) + treeCopy.Match(match0, match0.selector, match0.cases :+ defaultCase) + } match_ setType B1.tpe - // the default uses applyOrElse's first parameter since the scrut's type has been widened - val matchWithDefault = match_ updateAttachment DefaultOverrideMatchAttachment(REF(default) APPLY (REF(x))) - (DefDef(methodSym, methodBodyTyper.virtualizedMatch(matchWithDefault, mode, B1.tpe)), matchResTp) + // SI-6187 Do you really want to know? Okay, here's what's going on here. + // + // Well behaved trees satisfy the property: + // + // typed(tree) == typed(resetLocalAttrs(typed(tree)) + // + // Trees constructed without low-level symbol manipulation get this for free; + // references to local symbols are cleared by `ResetAttrs`, but bind to the + // corresponding symbol in the re-typechecked tree. But PartialFunction synthesis + // doesn't play by these rules. + // + // During typechecking of method bodies, references to method type parameter from + // the declared types of the value parameters should bind to a fresh set of skolems, + // which have been entered into scope by `Namer#methodSig`. A comment therein: + // + // "since the skolemized tparams are in scope, the TypeRefs in vparamSymss refer to skolemized tparams" + // + // But, if we retypecheck the reset `applyOrElse`, the TypeTree of the `default` + // parameter contains no type. Somehow (where?!) it recovers a type that is _almost_ okay: + // `A1 => B1`. But it should really be `A1&0 => B1&0`. In the test, run/t6187.scala, this + // difference results in a type error, as `default.apply(x)` types as `B1`, which doesn't + // conform to the required `B1&0` + // + // I see three courses of action. + // + // 1) synthesize a `asInstanceOf[B1]` below (I tried this first. But... ewwww.) + // 2) install an 'original' TypeTree that will used after ResetAttrs (the solution below) + // 3) Figure out how the almost-correct type is recovered on re-typechecking, and + // substitute in the skolems. + // + // For 2.11, we'll probably shift this transformation back a phase or two, so macros + // won't be affected. But in any case, we should satisfy retypecheckability. + // + val originals: Map[Symbol, Tree] = { + def typedIdent(sym: Symbol) = methodBodyTyper.typedType(Ident(sym), mode) + val A1Tpt = typedIdent(A1) + val B1Tpt = typedIdent(B1) + Map( + x -> A1Tpt, + default -> gen.scalaFunctionConstr(List(A1Tpt), B1Tpt) + ) + } + val rhs = methodBodyTyper.virtualizedMatch(match_, mode, B1.tpe) + val defdef = DefDef(methodSym, Modifiers(methodSym.flags), originals, rhs) + + (defdef, matchResTp) } - // `def isDefinedAt(x: $argTp): Boolean = ${`$selector match { $casesTrue ` updateAttachment DefaultOverrideMatchAttachment(FALSE_typed)}` + // `def isDefinedAt(x: $argTp): Boolean = ${`$selector match { $casesTrue; case default$ => false } }` def isDefinedAtMethod = { val methodSym = anonClass.newMethod(nme.isDefinedAt, tree.pos.makeTransparent, FINAL) val paramSym = mkParam(methodSym) @@ -2645,10 +2702,10 @@ trait Typers extends Modes with Adaptations with Tags { methodBodyTyper.context.scope enter paramSym methodSym setInfo MethodType(List(paramSym), BooleanClass.tpe) - val match_ = methodBodyTyper.typedMatch(selector, casesTrue, mode, BooleanClass.tpe) + val defaultCase = mkDefaultCase(FALSE_typed) + val match_ = methodBodyTyper.typedMatch(selector, casesTrue :+ defaultCase, mode, BooleanClass.tpe) - val matchWithDefault = match_ updateAttachment DefaultOverrideMatchAttachment(FALSE_typed) - DefDef(methodSym, methodBodyTyper.virtualizedMatch(matchWithDefault, mode, BooleanClass.tpe)) + DefDef(methodSym, methodBodyTyper.virtualizedMatch(match_, mode, BooleanClass.tpe)) } // only used for @cps annotated partial functions @@ -2693,7 +2750,9 @@ trait Typers extends Modes with Adaptations with Tags { members foreach (m => anonClass.info.decls enter m.symbol) val typedBlock = typedPos(tree.pos, mode, pt) { - Block(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, members, tree.pos.focus), atPos(tree.pos.focus)(New(anonClass.tpe))) + Block(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, members, tree.pos.focus), atPos(tree.pos.focus)( + Apply(Select(New(Ident(anonClass.name).setSymbol(anonClass)), nme.CONSTRUCTOR), List()) + )) } if (typedBlock.isErrorTyped) typedBlock diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 5e7f5777b2..ddc5d94e70 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -297,6 +297,7 @@ trait StdNames { // Compiler internal names val ANYname: NameType = "" val CONSTRUCTOR: NameType = "" + val DEFAULT_CASE: NameType = "defaultCase$" val EQEQ_LOCAL_VAR: NameType = "eqEqTemp$" val FAKE_LOCAL_THIS: NameType = "this$" val INITIALIZER: NameType = CONSTRUCTOR // Is this buying us something? diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 2cc848d458..bccad69638 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -434,6 +434,13 @@ abstract class TreeInfo { case _ => false } + /** Is this pattern node a synthetic catch-all case, added during PartialFuction synthesis before we know + * whether the user provided cases are exhaustive. */ + def isSyntheticDefaultCase(cdef: CaseDef) = cdef match { + case CaseDef(Bind(nme.DEFAULT_CASE, _), EmptyTree, _) => true + case _ => false + } + /** Does this CaseDef catch Throwable? */ def catchesThrowable(cdef: CaseDef) = catchesAllOf(cdef, ThrowableClass.tpe) diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 5522c47cfa..754adcb80d 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -523,7 +523,11 @@ trait Trees extends api.Trees { self: SymbolTable => override private[scala] def copyAttrs(tree: Tree) = { super.copyAttrs(tree) tree match { - case other: TypeTree => wasEmpty = other.wasEmpty // SI-6648 Critical for correct operation of `resetAttrs`. + case other: TypeTree => + // SI-6648 Critical for correct operation of `resetAttrs`. + wasEmpty = other.wasEmpty + if (other.orig != null) + orig = other.orig.duplicate case _ => } this @@ -984,6 +988,18 @@ trait Trees extends api.Trees { self: SymbolTable => def DefDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef = DefDef(sym, mods, mapParamss(sym)(ValDef), rhs) + /** A DefDef with original trees attached to the TypeTree of each parameter */ + def DefDef(sym: Symbol, mods: Modifiers, originalParamTpts: Symbol => Tree, rhs: Tree): DefDef = { + val paramms = mapParamss(sym){ sym => + val vd = ValDef(sym, EmptyTree) + (vd.tpt : @unchecked) match { + case tt: TypeTree => tt setOriginal (originalParamTpts(sym) setPos sym.pos.focus) + } + vd + } + DefDef(sym, mods, paramms, rhs) + } + def DefDef(sym: Symbol, rhs: Tree): DefDef = DefDef(sym, Modifiers(sym.flags), rhs) diff --git a/test/files/run/idempotency-partial-functions.scala b/test/files/run/idempotency-partial-functions.scala deleted file mode 100644 index dd5f1167f1..0000000000 --- a/test/files/run/idempotency-partial-functions.scala +++ /dev/null @@ -1,25 +0,0 @@ -import scala.reflect.runtime.universe._ -import scala.reflect.runtime.{currentMirror => cm} -import scala.tools.reflect.{ToolBox, ToolBoxError} -import scala.tools.reflect.Eval - -object Test extends App { - val partials = reify { - List((false,true)) collect { case (x,true) => x } - } - try { - println(partials.eval) - } catch { - case _: ToolBoxError => println("error!!") - } - try { - val tb = cm.mkToolBox() - val tpartials = tb.typeCheck(partials.tree) - println(tpartials) - val rtpartials = tb.resetAllAttrs(tpartials) - println(tb.eval(rtpartials)) - } catch { - // this is the current behaviour, rather than the desired behavior; see SI-6187 - case _: ToolBoxError => println("error!") - } -} \ No newline at end of file diff --git a/test/files/run/t6187.check b/test/files/run/t6187.check new file mode 100644 index 0000000000..c0ca02923b --- /dev/null +++ b/test/files/run/t6187.check @@ -0,0 +1,32 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> import language.experimental.macros, reflect.macros.Context +import language.experimental.macros +import reflect.macros.Context + +scala> def macroImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[List[T]] = { + val r = c.universe.reify { List(t.splice) } + c.Expr[List[T]]( c.resetLocalAttrs(r.tree) ) +} +macroImpl: [T](c: scala.reflect.macros.Context)(t: c.Expr[T])(implicit evidence$1: c.WeakTypeTag[T])c.Expr[List[T]] + +scala> def demo[T](t: T): List[T] = macro macroImpl[T] +demo: [T](t: T)List[T] + +scala> def m[T](t: T): List[List[T]] = + demo( List((t,true)) collect { case (x,true) => x } ) +m: [T](t: T)List[List[T]] + +scala> m(List(1)) +res0: List[List[List[Int]]] = List(List(List(1))) + +scala> // Showing we haven't added unreachable warnings + +scala> List(1) collect { case x => x } +res1: List[Int] = List(1) + +scala> List("") collect { case x => x } +res2: List[String] = List("") + +scala> diff --git a/test/files/run/t6187.scala b/test/files/run/t6187.scala new file mode 100644 index 0000000000..ae642917e7 --- /dev/null +++ b/test/files/run/t6187.scala @@ -0,0 +1,18 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + override def code = """ +import language.experimental.macros, reflect.macros.Context +def macroImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[List[T]] = { + val r = c.universe.reify { List(t.splice) } + c.Expr[List[T]]( c.resetLocalAttrs(r.tree) ) +} +def demo[T](t: T): List[T] = macro macroImpl[T] +def m[T](t: T): List[List[T]] = + demo( List((t,true)) collect { case (x,true) => x } ) +m(List(1)) +// Showing we haven't added unreachable warnings +List(1) collect { case x => x } +List("") collect { case x => x } + """.trim +} diff --git a/test/files/run/t6187b.scala b/test/files/run/t6187b.scala new file mode 100644 index 0000000000..d2d3e9797d --- /dev/null +++ b/test/files/run/t6187b.scala @@ -0,0 +1,5 @@ +object Test extends App { + val x: PartialFunction[Int, Int] = { case 1 => 1 } + val o: Any = "" + assert(x.applyOrElse(0, (_: Int) => o) == "") +} diff --git a/test/pending/run/idempotency-partial-functions.scala b/test/pending/run/idempotency-partial-functions.scala new file mode 100644 index 0000000000..bc0ca706dd --- /dev/null +++ b/test/pending/run/idempotency-partial-functions.scala @@ -0,0 +1,28 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.{ToolBox, ToolBoxError} +import scala.tools.reflect.Eval + +// Related to SI-6187 +// +// Moved to pending as we are currently blocked by the inability +// to reify the parent types of the anoymous function class, +// which are not part of the tree, but rather only part of the +// ClassInfoType. +object Test extends App { + val partials = reify { + List((false,true)) collect { case (x,true) => x } + } + println(Seq(show(partials), showRaw(partials)).mkString("\n\n")) + try { + println(partials.eval) + } catch { + case e: ToolBoxError => println(e) + } + val tb = cm.mkToolBox() + val tpartials = tb.typeCheck(partials.tree) + println(tpartials) + val rtpartials = tb.resetAllAttrs(tpartials) + println(tb.eval(rtpartials)) +} +Test.main(null) \ No newline at end of file -- cgit v1.2.3 From fa3b8040ebfedc721a538476be28a6217f1dec56 Mon Sep 17 00:00:00 2001 From: Aleksandar Prokopec Date: Thu, 7 Feb 2013 15:52:40 -0800 Subject: SI-6961 no structural sharing in list serialization Revert list serialization back to what it was in 2.9.x and before. Partial revert of a6fcd70b60 e234978dfd, which fixed SI-5374. The ListBuffer part of the fix remains in place. --- src/library/scala/collection/immutable/List.scala | 33 +++------- test/files/run/t5374.check | 6 -- test/files/run/t5374.scala | 76 ----------------------- 3 files changed, 9 insertions(+), 106 deletions(-) delete mode 100644 test/files/run/t5374.check delete mode 100644 test/files/run/t5374.scala diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 55ac3995e9..9765e7c52f 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -55,6 +55,12 @@ import java.io._ * val shorter = mainList.tail // costs nothing as it uses the same 2::1::Nil instances as mainList * }}} * + * @note The functional list is characterized by persistence and structural sharing, thus offering considerable + * performance and space consumption benefits in some scenarios if used correctly. + * However, note that objects having multiple references into the same functional list (that is, + * objects that rely on structural sharing), will be serialized and deserialized with multiple lists, one for + * each reference to it. I.e. structural sharing is lost after serialization/deserialization. + * * @author Martin Odersky and others * @version 2.8 * @since 1.0 @@ -352,25 +358,8 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend override def tail : List[B] = tl override def isEmpty: Boolean = false - private def writeObject(out: ObjectOutputStream) { - out.writeObject(ListSerializeStart) // needed to differentiate with the legacy `::` serialization - out.writeObject(this.hd) - out.writeObject(this.tl) - } - private def readObject(in: ObjectInputStream) { - val obj = in.readObject() - if (obj == ListSerializeStart) { - this.hd = in.readObject().asInstanceOf[B] - this.tl = in.readObject().asInstanceOf[List[B]] - } else oldReadObject(in, obj) - } - - /* The oldReadObject method exists here for compatibility reasons. - * :: objects used to be serialized by serializing all the elements to - * the output stream directly, but this was broken (see SI-5374). - */ - private def oldReadObject(in: ObjectInputStream, firstObject: AnyRef) { + val firstObject = in.readObject() hd = firstObject.asInstanceOf[B] assert(hd != ListSerializeEnd) var current: ::[B] = this @@ -378,14 +367,14 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend case ListSerializeEnd => current.tl = Nil return - case a : Any => + case a => val list : ::[B] = new ::(a.asInstanceOf[B], Nil) current.tl = list current = list } } - private def oldWriteObject(out: ObjectOutputStream) { + private def writeObject(out: ObjectOutputStream) { var xs: List[B] = this while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail } out.writeObject(ListSerializeEnd) @@ -653,10 +642,6 @@ object List extends SeqFactory[List] { } } -/** Only used for list serialization */ -@SerialVersionUID(0L - 8287891243975527522L) -private[scala] case object ListSerializeStart - /** Only used for list serialization */ @SerialVersionUID(0L - 8476791151975527571L) private[scala] case object ListSerializeEnd diff --git a/test/files/run/t5374.check b/test/files/run/t5374.check deleted file mode 100644 index 6be88d77ec..0000000000 --- a/test/files/run/t5374.check +++ /dev/null @@ -1,6 +0,0 @@ -ListBuffer(1, 2, 3, 1) -ListBuffer(1, 2, 3, 1) -ListBuffer() -List(1, 2, 3, 4, 5) -List(1, 2, 3) -ok \ No newline at end of file diff --git a/test/files/run/t5374.scala b/test/files/run/t5374.scala deleted file mode 100644 index 9b1671e795..0000000000 --- a/test/files/run/t5374.scala +++ /dev/null @@ -1,76 +0,0 @@ - - - -import collection.mutable.ListBuffer -import java.io._ - - - -object Test { - - def main(args: Array[String]) { - ticketExample() - emptyListBuffer() - list() - legacyList() - objectWithMultipleLists() - } - - def inAndOut[T <: AnyRef](obj: T): T = { - val baos = new ByteArrayOutputStream - val oos = new ObjectOutputStream(baos) - oos.writeObject( obj ) - val bais = new ByteArrayInputStream( baos.toByteArray ) - val ois = new ObjectInputStream(bais) - ois.readObject.asInstanceOf[T] - } - - def ticketExample() { - val lb = inAndOut(ListBuffer(1, 2, 3)) - val lb2 = ListBuffer[Int]() ++= lb - - lb2 ++= List(1) - lb ++= List(1) - println(lb) - println(lb2) - } - - def emptyListBuffer() { - val lb = inAndOut(ListBuffer[Int]()) - - println(lb) - } - - def list() { - val l = inAndOut(List(1, 2, 3, 4, 5)) - - println(l) - } - - // this byte array corresponds to what List(1, 2, 3) used to be serialized to prior to this fix - val listBytes = Array[Byte](-84, -19, 0, 5, 115, 114, 0, 39, 115, 99, 97, 108, 97, 46, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 46, 105, 109, 109, 117, 116, 97, 98, 108, 101, 46, 36, 99, 111, 108, 111, 110, 36, 99, 111, 108, 111, 110, -118, 92, 99, 91, -10, -40, -7, 109, 3, 0, 2, 76, 0, 43, 115, 99, 97, 108, 97, 36, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 36, 105, 109, 109, 117, 116, 97, 98, 108, 101, 36, 36, 99, 111, 108, 111, 110, 36, 99, 111, 108, 111, 110, 36, 36, 104, 100, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 59, 76, 0, 2, 116, 108, 116, 0, 33, 76, 115, 99, 97, 108, 97, 47, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 47, 105, 109, 109, 117, 116, 97, 98, 108, 101, 47, 76, 105, 115, 116, 59, 120, 112, 115, 114, 0, 17, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 73, 110, 116, 101, 103, 101, 114, 18, -30, -96, -92, -9, -127, -121, 56, 2, 0, 1, 73, 0, 5, 118, 97, 108, 117, 101, 120, 114, 0, 16, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 78, 117, 109, 98, 101, 114, -122, -84, -107, 29, 11, -108, -32, -117, 2, 0, 0, 120, 112, 0, 0, 0, 1, 115, 113, 0, 126, 0, 4, 0, 0, 0, 2, 115, 113, 0, 126, 0, 4, 0, 0, 0, 3, 115, 114, 0, 44, 115, 99, 97, 108, 97, 46, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 46, 105, 109, 109, 117, 116, 97, 98, 108, 101, 46, 76, 105, 115, 116, 83, 101, 114, 105, 97, 108, 105, 122, 101, 69, 110, 100, 36, -118, 92, 99, 91, -9, 83, 11, 109, 2, 0, 0, 120, 112, 120) - - def legacyList() { - val bais = new ByteArrayInputStream(listBytes) - val ois = new ObjectInputStream(bais) - val l = ois.readObject() - - println(l) - } - - class Foo extends Serializable { - val head = List(1, 2, 3) - val last = head.tail.tail - def structuralSharing: Boolean = head.tail.tail eq last - - assert(structuralSharing) - } - - def objectWithMultipleLists() { - val foo = inAndOut(new Foo) - - if (foo.structuralSharing) println("ok") - else println("no structural sharing") - } - -} -- cgit v1.2.3 From 5258b63740c9fb1be3c531e1dc1399fb0dc55569 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Fri, 8 Feb 2013 00:05:55 +0100 Subject: SI-7096 SubstSymMap copies trees before modifying their symbols I removed some strange code in a06d31f6a2 and replaced it by something incorrect: SubstSymMap should never have side-effects: otherwise, calling 'tpe1 <: tpe2' for instance would modify the symbols in annotations of tpe2. SubstSymMap now always creates new trees before changing them. --- src/reflect/scala/reflect/internal/Types.scala | 42 ++++++++++++++++++-------- test/files/run/t7096.check | 2 ++ test/files/run/t7096.scala | 36 ++++++++++++++++++++++ 3 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 test/files/run/t7096.check create mode 100644 test/files/run/t7096.scala diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 0dd98fb6ae..b06ab6c929 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -4698,23 +4698,39 @@ trait Types extends api.Types { self: SymbolTable => } } - override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = { - object trans extends TypeMapTransformer { + object mapTreeSymbols extends TypeMapTransformer { + val strictCopy = newStrictTreeCopier - def termMapsTo(sym: Symbol) = from indexOf sym match { - case -1 => None - case idx => Some(to(idx)) - } + def termMapsTo(sym: Symbol) = from indexOf sym match { + case -1 => None + case idx => Some(to(idx)) + } - override def transform(tree: Tree) = { - termMapsTo(tree.symbol) match { - case Some(tosym) => tree.symbol = tosym - case None => () - } - super.transform(tree) + // if tree.symbol is mapped to another symbol, passes the new symbol into the + // constructor `trans` and sets the symbol and the type on the resulting tree. + def transformIfMapped(tree: Tree)(trans: Symbol => Tree) = termMapsTo(tree.symbol) match { + case Some(toSym) => trans(toSym) setSymbol toSym setType tree.tpe + case None => tree + } + + // changes trees which refer to one of the mapped symbols. trees are copied before attributes are modified. + override def transform(tree: Tree) = { + // super.transform maps symbol references in the types of `tree`. it also copies trees where necessary. + super.transform(tree) match { + case id @ Ident(_) => + transformIfMapped(id)(toSym => + strictCopy.Ident(id, toSym.name)) + + case sel @ Select(qual, name) => + transformIfMapped(sel)(toSym => + strictCopy.Select(sel, qual, toSym.name)) + + case tree => tree } } - trans.transform(tree) + } + override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = { + mapTreeSymbols.transform(tree) } } diff --git a/test/files/run/t7096.check b/test/files/run/t7096.check new file mode 100644 index 0000000000..6f1cef6c43 --- /dev/null +++ b/test/files/run/t7096.check @@ -0,0 +1,2 @@ +testing symbol List(method foo, class Base, package ano, package ), param value x, xRefs List(x) +testing symbol List(method foo, class Sub, package ano, package ), param value x, xRefs List(x) diff --git a/test/files/run/t7096.scala b/test/files/run/t7096.scala new file mode 100644 index 0000000000..e9c0323c2e --- /dev/null +++ b/test/files/run/t7096.scala @@ -0,0 +1,36 @@ +import scala.tools.partest._ +import scala.tools.nsc._ + +object Test extends CompilerTest { + import global._ + import definitions._ + + override def code = """ +package ano + +class ann(x: Any) extends annotation.TypeConstraint + +abstract class Base { + def foo(x: String): String @ann(x.trim()) +} + +class Sub extends Base { + def foo(x: String): String @ann(x.trim()) = x +} + """ + + object syms extends SymsInPackage("ano") + import syms._ + + def check(source: String, unit: global.CompilationUnit) { + afterTyper { + terms.filter(_.name.toString == "foo").foreach(sym => { + val xParam = sym.tpe.paramss.flatten.head + val annot = sym.tpe.finalResultType.annotations.head + val xRefs = annot.args.head.filter(t => t.symbol == xParam) + println(s"testing symbol ${sym.ownerChain}, param $xParam, xRefs $xRefs") + assert(xRefs.length == 1, xRefs) + }) + } + } +} -- cgit v1.2.3 From 09ef8730d13eff1cf200bbfb0f6fda7f6d72524a Mon Sep 17 00:00:00 2001 From: Dmitry Bushev Date: Fri, 14 Dec 2012 17:09:55 +0400 Subject: SI-6591 Reify and path-dependent types Reification scheme changed. Now Select an SelectFromTypeTree trees reified appropriately, as Select and SelectFromTypeTree accordingly. Packages and Predef object was excluded in order not to break the existing reification scheme and not to break tests which rely on it. Reified free terms can contain flag to make reified values become stable identifiers. For example in the case of reify_newimpl_15.scala class C { type T reify { val v: List[T] = List(2) } } class C reified as free term C$value, and List[C.T] becomes List[C$value().T], so C$value.apply() need to pass stability test isExprSafeToInline at scala.reflect.internal.TreeInfo. For this purpose special case for reified free terms was added to isExprSafeToInline function. test run/reify_newipl_30 disabled due to SI-7082 test t6591_4 moved to pending due to SI-7083 --- .../scala/reflect/reify/codegen/GenSymbols.scala | 2 ++ .../scala/reflect/reify/codegen/GenTrees.scala | 24 ++++++++++++++-------- .../scala/reflect/reify/utils/Extractors.scala | 8 ++++---- .../scala/tools/reflect/ToolBoxFactory.scala | 7 +++++-- src/reflect/scala/reflect/internal/Flags.scala | 2 +- src/reflect/scala/reflect/internal/StdNames.scala | 1 + src/reflect/scala/reflect/internal/TreeInfo.scala | 6 ++++++ test/files/run/reify_newimpl_30.check | 3 ++- test/files/run/reify_newimpl_30.scala | 7 ++++--- test/files/run/t6591_1.check | 1 + test/files/run/t6591_1.scala | 19 +++++++++++++++++ test/files/run/t6591_2.check | 1 + test/files/run/t6591_2.scala | 19 +++++++++++++++++ test/files/run/t6591_3.check | 1 + test/files/run/t6591_3.scala | 17 +++++++++++++++ test/files/run/t6591_5.check | 1 + test/files/run/t6591_5.scala | 23 +++++++++++++++++++++ test/files/run/t6591_6.check | 1 + test/files/run/t6591_6.scala | 24 ++++++++++++++++++++++ test/pending/run/t6591_4.check | 1 + test/pending/run/t6591_4.scala | 17 +++++++++++++++ 21 files changed, 165 insertions(+), 20 deletions(-) create mode 100644 test/files/run/t6591_1.check create mode 100644 test/files/run/t6591_1.scala create mode 100644 test/files/run/t6591_2.check create mode 100644 test/files/run/t6591_2.scala create mode 100644 test/files/run/t6591_3.check create mode 100644 test/files/run/t6591_3.scala create mode 100644 test/files/run/t6591_5.check create mode 100644 test/files/run/t6591_5.scala create mode 100644 test/files/run/t6591_6.check create mode 100644 test/files/run/t6591_6.scala create mode 100644 test/pending/run/t6591_4.check create mode 100644 test/pending/run/t6591_4.scala diff --git a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala index 22a834d2e4..0d795e3783 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala @@ -100,6 +100,8 @@ trait GenSymbols { reifyIntoSymtab(binding.symbol) { sym => if (reifyDebug) println("Free term" + (if (sym.isCapturedVariable) " (captured)" else "") + ": " + sym + "(" + sym.accurateKindString + ")") val name = newTermName(nme.REIFY_FREE_PREFIX + sym.name + (if (sym.isType) nme.REIFY_FREE_THIS_SUFFIX else "")) + // Flag is set here to make reified free value pass stability test during reflective compilation + if (!sym.isMutable) sym setFlag reflect.internal.Flags.STABLE if (sym.isCapturedVariable) { assert(binding.isInstanceOf[Ident], showRaw(binding)) val capturedBinding = referenceCapturedVariable(sym) diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index 06e287f62f..7c7a79e774 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -163,11 +163,11 @@ trait GenTrees { } } - private def reifyBoundType(tree: Tree): Tree = { + private def reifyBoundType(tree: RefTree): Tree = { val sym = tree.symbol val tpe = tree.tpe - def reifyBoundType(tree: Tree): Tree = { + def reifyBoundType(tree: RefTree): Tree = { assert(tpe != null, "unexpected: bound type that doesn't have a tpe: " + showRaw(tree)) // if a symbol or a type of the scrutinee are local to reifee @@ -196,13 +196,19 @@ trait GenTrees { mirrorBuildCall(nme.TypeTree, spliced) } } - else if (sym.isLocatable) { - if (reifyDebug) println("tpe is locatable: reify as Ident(%s)".format(sym)) - mirrorBuildCall(nme.Ident, reify(sym)) - } - else { - if (reifyDebug) println("tpe is not locatable: reify as TypeTree(%s)".format(tpe)) - mirrorBuildCall(nme.TypeTree, reify(tpe)) + else tree match { + case Select(qual, name) if !qual.symbol.isPackage && !qual.symbol.isPackageObject && qual.symbol != definitions.PredefModule => + if (reifyDebug) println(s"reifying Select($qual, $name)") + mirrorCall(nme.Select, reify(qual), reify(name)) + case SelectFromTypeTree(qual, name) => + if (reifyDebug) println(s"reifying SelectFromTypeTree($qual, $name)") + mirrorCall(nme.SelectFromTypeTree, reify(qual), reify(name)) + case _ if sym.isLocatable => + if (reifyDebug) println(s"tpe is locatable: reify as Ident($sym)") + mirrorBuildCall(nme.Ident, reify(sym)) + case _ => + if (reifyDebug) println(s"tpe is not locatable: reify as TypeTree($tpe)") + mirrorBuildCall(nme.TypeTree, reify(tpe)) } } } diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala index ebbcb95481..134ae13890 100644 --- a/src/compiler/scala/reflect/reify/utils/Extractors.scala +++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala @@ -263,12 +263,12 @@ trait Extractors { } object BoundType { - def unapply(tree: Tree): Option[Tree] = tree match { - case Select(_, name) if name.isTypeName => + def unapply(tree: Tree): Option[RefTree] = tree match { + case tree @ Select(_, name) if name.isTypeName => Some(tree) - case SelectFromTypeTree(_, name) if name.isTypeName => + case tree @ SelectFromTypeTree(_, _) => Some(tree) - case Ident(name) if name.isTypeName => + case tree @ Ident(name) if name.isTypeName => Some(tree) case _ => None diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 95135b84e0..fdc790a920 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -212,7 +212,11 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val meth = obj.moduleClass.newMethod(newTermName(wrapperMethodName)) def makeParam(schema: (FreeTermSymbol, TermName)) = { val (fv, name) = schema - meth.newValueParameter(name) setInfo appliedType(definitions.FunctionClass(0).tpe, List(fv.tpe.resultType)) + /* Free term symbol `fv` can contain flag which was set by + * `scala.reflect.reify.codegen.GenSymbols.reifyFreeTerm` method. + * It is recovered here, so value parameter can pass `isExprSafeToInline` + * test in `scala.reflect.internal.TreeInfo`. */ + meth.newValueParameter(name, newFlags = if (fv.hasStableFlag) Flags.STABLE else 0) setInfo appliedType(definitions.FunctionClass(0).tpe, List(fv.tpe.resultType)) } meth setInfo MethodType(freeTerms.map(makeParam).toList, AnyClass.tpe) minfo.decls enter meth @@ -418,4 +422,3 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => def eval(tree: u.Tree): Any = compile(tree)() } } - diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index a0362c8921..5853315479 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -274,7 +274,7 @@ class Flags extends ModifierFlags { * from Modifiers. Others which may be applied at creation time are: * SYNTHETIC. */ - final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM + final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM | STABLE final val BeanPropertyFlags = DEFERRED | OVERRIDE | STATIC final val VarianceFlags = COVARIANT | CONTRAVARIANT diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index ddc5d94e70..bcda2bc1ae 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -607,6 +607,7 @@ trait StdNames { val RootPackage: NameType = "RootPackage" val RootClass: NameType = "RootClass" val Select: NameType = "Select" + val SelectFromTypeTree: NameType = "SelectFromTypeTree" val StringContext: NameType = "StringContext" val This: NameType = "This" val ThisType: NameType = "ThisType" diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 8b5dc80c83..f83106aaef 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -89,6 +89,12 @@ abstract class TreeInfo { tree.symbol.isStable && isExprSafeToInline(qual) case TypeApply(fn, _) => isExprSafeToInline(fn) + /* Special case for reified free terms. During reflective compilation, + * reified value recovered flag from free term and wrapped into a + * Function object, so it can pass stability check here to become a stable + * identifier.*/ + case Apply(Select(free @ Ident(_), nme.apply), _) if free.symbol.name endsWith nme.REIFY_FREE_VALUE_SUFFIX => + free.symbol.hasStableFlag && isExprSafeToInline(free) case Apply(fn, List()) => /* Note: After uncurry, field accesses are represented as Apply(getter, Nil), * so an Apply can also be pure. diff --git a/test/files/run/reify_newimpl_30.check b/test/files/run/reify_newimpl_30.check index c23af69b08..29baac911e 100644 --- a/test/files/run/reify_newimpl_30.check +++ b/test/files/run/reify_newimpl_30.check @@ -1 +1,2 @@ -List(2) +reflective toolbox has failed: +unresolved free type variables (namely: C defined by in reify_newimpl_30.scala:7:11). have you forgot to use TypeTag annotations for type parameters external to a reifee? if you have troubles tracking free type variables, consider using -Xlog-free-types diff --git a/test/files/run/reify_newimpl_30.scala b/test/files/run/reify_newimpl_30.scala index 573d05a630..bc34f1bb6c 100644 --- a/test/files/run/reify_newimpl_30.scala +++ b/test/files/run/reify_newimpl_30.scala @@ -1,5 +1,5 @@ import scala.reflect.runtime.universe._ -import scala.tools.reflect.ToolBox +import scala.tools.reflect.{ ToolBox, ToolBoxError } import scala.tools.reflect.Eval object Test extends App { @@ -9,9 +9,10 @@ object Test extends App { val code = reify { List[C#T](2) } - println(code.eval) + try { println(code.eval) } + catch { case e: ToolBoxError => println(e.getMessage) } } new C } -} \ No newline at end of file +} diff --git a/test/files/run/t6591_1.check b/test/files/run/t6591_1.check new file mode 100644 index 0000000000..b6cb6c286d --- /dev/null +++ b/test/files/run/t6591_1.check @@ -0,0 +1 @@ +Block(List(ValDef(Modifiers(), newTermName("v"), Select(Ident(A), newTypeName("I")), Select(Ident(A), newTermName("impl")))), Ident(newTermName("v"))) diff --git a/test/files/run/t6591_1.scala b/test/files/run/t6591_1.scala new file mode 100644 index 0000000000..6dd9a1d9fb --- /dev/null +++ b/test/files/run/t6591_1.scala @@ -0,0 +1,19 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.ToolBox +import scala.tools.reflect.Eval + +trait O { trait I } + +object A extends O { + val impl = new I {} +} + +object Test extends App { + val code = reify { + val v: A.I = A.impl + v + } + println(showRaw(code.tree)) + + val v: A.I = code.eval +} diff --git a/test/files/run/t6591_2.check b/test/files/run/t6591_2.check new file mode 100644 index 0000000000..b2d5797cbf --- /dev/null +++ b/test/files/run/t6591_2.check @@ -0,0 +1 @@ +Block(List(ValDef(Modifiers(), newTermName("v"), SelectFromTypeTree(Ident(A), newTypeName("I")), Select(Apply(Select(New(Ident(A)), nme.CONSTRUCTOR), List()), newTermName("impl")))), Ident(newTermName("v"))) diff --git a/test/files/run/t6591_2.scala b/test/files/run/t6591_2.scala new file mode 100644 index 0000000000..6214308dab --- /dev/null +++ b/test/files/run/t6591_2.scala @@ -0,0 +1,19 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.ToolBox +import scala.tools.reflect.Eval + +trait O { trait I } + +class A extends O { + val impl = new I {} +} + +object Test extends App { + val code = reify { + val v: A#I = (new A).impl + v + } + println(showRaw(code.tree)) + + val v: A#I = code.eval +} diff --git a/test/files/run/t6591_3.check b/test/files/run/t6591_3.check new file mode 100644 index 0000000000..a7b594ba65 --- /dev/null +++ b/test/files/run/t6591_3.check @@ -0,0 +1 @@ +Block(List(ValDef(Modifiers(), newTermName("v"), Select(This(newTypeName("A")), newTypeName("I")), Apply(Select(New(Select(This(newTypeName("A")), newTypeName("I"))), nme.CONSTRUCTOR), List()))), Ident(newTermName("v"))) diff --git a/test/files/run/t6591_3.scala b/test/files/run/t6591_3.scala new file mode 100644 index 0000000000..b73a7baf48 --- /dev/null +++ b/test/files/run/t6591_3.scala @@ -0,0 +1,17 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.ToolBox +import scala.tools.reflect.Eval + +class O { class I } + +object A extends O { + val code = reify { + val v: I = new I + v + } + println(showRaw(code.tree)) +} + +object Test extends App { + val v: A.I = A.code.eval +} diff --git a/test/files/run/t6591_5.check b/test/files/run/t6591_5.check new file mode 100644 index 0000000000..8f1c2b3ede --- /dev/null +++ b/test/files/run/t6591_5.check @@ -0,0 +1 @@ +Expr(Block(List(ValDef(Modifiers(), newTermName("v"), Select(Select(This(newTypeName("A")), newTermName("x")), newTypeName("I")), Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("$qmark$qmark$qmark")))), Ident(newTermName("v")))) diff --git a/test/files/run/t6591_5.scala b/test/files/run/t6591_5.scala new file mode 100644 index 0000000000..18d6f90a9b --- /dev/null +++ b/test/files/run/t6591_5.scala @@ -0,0 +1,23 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.ToolBox +import scala.tools.reflect.Eval +import java.lang.reflect.InvocationTargetException + +class O { class I } + +object A extends O { + val x = new O + val code = reify { + val v: x.I = ??? + v + } + println(showRaw(code)) +} + +object Test extends App { + try { + val v: A.x.I = A.code.eval + } catch { + case ex: InvocationTargetException if ex.getCause.isInstanceOf[NotImplementedError] => + } +} diff --git a/test/files/run/t6591_6.check b/test/files/run/t6591_6.check new file mode 100644 index 0000000000..5ddf7600f1 --- /dev/null +++ b/test/files/run/t6591_6.check @@ -0,0 +1 @@ +Expr(Block(List(ValDef(Modifiers(), newTermName("v"), Select(Select(Ident(newTermName("A")), newTermName("x")), newTypeName("I")), Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("$qmark$qmark$qmark")))), Ident(newTermName("v")))) diff --git a/test/files/run/t6591_6.scala b/test/files/run/t6591_6.scala new file mode 100644 index 0000000000..2eee87928d --- /dev/null +++ b/test/files/run/t6591_6.scala @@ -0,0 +1,24 @@ +import scala.language.existentials +import scala.reflect.runtime.universe._ +import scala.tools.reflect.ToolBox +import scala.tools.reflect.Eval +import java.lang.reflect.InvocationTargetException + +class O { class I } + +class A extends O { + val x = new O + val code = reify { + val v: x.I = ??? + v + } + println(showRaw(code)) +} + +object Test extends App { + try { + val v = (new A).code.eval + } catch { + case ex: InvocationTargetException if ex.getCause.isInstanceOf[NotImplementedError] => + } +} diff --git a/test/pending/run/t6591_4.check b/test/pending/run/t6591_4.check new file mode 100644 index 0000000000..0f1c0489e9 --- /dev/null +++ b/test/pending/run/t6591_4.check @@ -0,0 +1 @@ +Expr(Block(List(ValDef(Modifiers(), newTermName("v"), Select(Ident(newTermName("A")), newTypeName("I")), Apply(Select(New(Select(Ident(newTermName("A")), newTypeName("I"))), nme.CONSTRUCTOR), List()))), Ident(newTermName("v")))) diff --git a/test/pending/run/t6591_4.scala b/test/pending/run/t6591_4.scala new file mode 100644 index 0000000000..f20c8e6127 --- /dev/null +++ b/test/pending/run/t6591_4.scala @@ -0,0 +1,17 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.ToolBox +import scala.tools.reflect.Eval + +class O { class I } + +class A extends O { + val code = reify { + val v: I = new I + v + } + println(showRaw(code)) +} + +object Test extends App { + val v: A#I = (new A).code.eval +} -- cgit v1.2.3 From ce867c74572b51cfcb6ac3e3bfa9dce36cc0b638 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 8 Feb 2013 14:08:54 +0100 Subject: term and type reftrees are now reified uniformly Top-level (i.e. owned by a package) => Ident(symbol) Nested (i.e. owned by an object or a package object) => Select(owner, symbol) Inner (i.e. owned by a static class) => selectTerm/selectType(owner, name) Non-locatable (i.e. everything else) => see GenTrees.scala for more details Changes w.r.t the previous approaches: * Top-level refs are no longer reified as Select(This(package), symbol). Proposed reification scheme is as resistant to resetAttrs as previous one, but is at the same time much shorter. * Refs to definitions from package objects are no longer Ident(symbol). Otherwise reflective compilation of things like `_ :: _` fails. * Contents of Predef._ and scala._ are no longer treated specially. This increases the size of reificode, but is more hygienic. --- .../scala/reflect/reify/codegen/GenTrees.scala | 12 ++++++---- test/files/run/freetypes_false_alarm1.check | 2 +- test/files/run/idempotency-case-classes.check | 2 +- test/files/run/idempotency-lazy-vals.check | 2 +- test/files/run/idempotency-this.check | 6 ++--- .../run/macro-typecheck-macrosdisabled2.check | 2 +- test/files/run/reify_ann1a.check | 24 +++++++++---------- test/files/run/reify_ann2a.check | 28 +++++++++++----------- test/files/run/reify_copypaste2.check | 2 +- test/files/run/reify_newimpl_35.check | 2 +- test/files/run/showraw_tree.check | 4 ++-- test/files/run/showraw_tree_ids.check | 4 ++-- test/files/run/showraw_tree_kinds.check | 4 ++-- test/files/run/showraw_tree_types_ids.check | 20 +++++++++------- test/files/run/showraw_tree_types_typed.check | 20 +++++++++------- test/files/run/showraw_tree_types_untyped.check | 4 ++-- test/files/run/showraw_tree_ultimate.check | 20 +++++++++------- test/files/run/t2886.check | 2 +- test/files/run/t5225_2.check | 2 +- test/files/run/t5271_2.check | 2 +- test/files/run/t5271_3.check | 2 +- test/files/run/t6591_5.check | 2 +- test/files/run/t6591_6.check | 2 +- .../run/toolbox_typecheck_macrosdisabled2.check | 2 +- 24 files changed, 90 insertions(+), 82 deletions(-) diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index 7c7a79e774..9894e359b4 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -153,10 +153,12 @@ trait GenTrees { else mirrorCall(nme.Ident, reify(name)) case Select(qual, name) => - if (sym == NoSymbol || sym.name == name) - reifyProduct(tree) - else - reifyProduct(Select(qual, sym.name)) + if (qual.symbol != null && qual.symbol.isPackage) { + mirrorBuildCall(nme.Ident, reify(sym)) + } else { + val effectiveName = if (sym != null && sym != NoSymbol) sym.name else name + reifyProduct(Select(qual, effectiveName)) + } case _ => throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass)) @@ -197,7 +199,7 @@ trait GenTrees { } } else tree match { - case Select(qual, name) if !qual.symbol.isPackage && !qual.symbol.isPackageObject && qual.symbol != definitions.PredefModule => + case Select(qual, name) if !qual.symbol.isPackage => if (reifyDebug) println(s"reifying Select($qual, $name)") mirrorCall(nme.Select, reify(qual), reify(name)) case SelectFromTypeTree(qual, name) => diff --git a/test/files/run/freetypes_false_alarm1.check b/test/files/run/freetypes_false_alarm1.check index a9df3544ac..085b3ee50b 100644 --- a/test/files/run/freetypes_false_alarm1.check +++ b/test/files/run/freetypes_false_alarm1.check @@ -1 +1 @@ -List[Int] +scala.List[Int] diff --git a/test/files/run/idempotency-case-classes.check b/test/files/run/idempotency-case-classes.check index 80d178cba3..e0453883ff 100644 --- a/test/files/run/idempotency-case-classes.check +++ b/test/files/run/idempotency-case-classes.check @@ -50,6 +50,6 @@ C(2,3) Some.apply[(Int, Int)](Tuple2.apply[Int, Int](x$0.x, x$0.y)); private def readResolve(): Object = C }; - scala.this.Predef.println(C.apply(2, 3)) + Predef.println(C.apply(2, 3)) } error! diff --git a/test/files/run/idempotency-lazy-vals.check b/test/files/run/idempotency-lazy-vals.check index 4dcbf96184..15afa5303c 100644 --- a/test/files/run/idempotency-lazy-vals.check +++ b/test/files/run/idempotency-lazy-vals.check @@ -18,6 +18,6 @@ }; val c: C = new C(); import c._; - c.x.*(scala.this.Predef.implicitly[Int](c.y)) + c.x.*(Predef.implicitly[Int](c.y)) } error! diff --git a/test/files/run/idempotency-this.check b/test/files/run/idempotency-this.check index 08738c4565..8faf703d97 100644 --- a/test/files/run/idempotency-this.check +++ b/test/files/run/idempotency-this.check @@ -1,4 +1,4 @@ List() -immutable.this.List.apply[String]("") -Apply(TypeApply(Select(Select(This(newTypeName("immutable")), scala.collection.immutable.List), newTermName("apply")), List(TypeTree().setOriginal(Ident(newTypeName("String"))))), List(Literal(Constant("")))) -error! +List.apply[String]("") +Apply(TypeApply(Select(Ident(scala.collection.immutable.List), newTermName("apply")), List(TypeTree().setOriginal(Select(Ident(scala.Predef), newTypeName("String"))))), List(Literal(Constant("")))) +List() diff --git a/test/files/run/macro-typecheck-macrosdisabled2.check b/test/files/run/macro-typecheck-macrosdisabled2.check index 7bdd1d6a3a..27d15d47af 100644 --- a/test/files/run/macro-typecheck-macrosdisabled2.check +++ b/test/files/run/macro-typecheck-macrosdisabled2.check @@ -10,7 +10,7 @@ def apply[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Tree = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; - $u.Apply.apply($u.Select.apply($u.Select.apply($u.build.Ident($m.staticPackage("scala")), $u.newTermName("Array")), $u.newTermName("apply")), scala.collection.immutable.List.apply[$u.Literal]($u.Literal.apply($u.Constant.apply(2)))) + $u.Apply.apply($u.Select.apply($u.build.Ident($m.staticModule("scala.Array")), $u.newTermName("apply")), scala.collection.immutable.List.apply[$u.Literal]($u.Literal.apply($u.Constant.apply(2)))) } }; new $treecreator1() diff --git a/test/files/run/reify_ann1a.check b/test/files/run/reify_ann1a.check index 244be27aa7..99a966f38b 100644 --- a/test/files/run/reify_ann1a.check +++ b/test/files/run/reify_ann1a.check @@ -1,28 +1,28 @@ { - @new ann(immutable.this.List.apply("1a")) @new ann(immutable.this.List.apply("1b")) class C[@new ann(immutable.this.List.apply("2a")) @new ann(immutable.this.List.apply("2b")) T >: Nothing <: Any] extends AnyRef { - @new ann(immutable.this.List.apply("3a")) @new ann(immutable.this.List.apply("3b")) private[this] val x: T @ann(immutable.this.List.apply("4a")) @ann(immutable.this.List.apply("4b")) = _; - def (@new ann(immutable.this.List.apply("3a")) @new ann(immutable.this.List.apply("3b")) x: T @ann(immutable.this.List.apply("4a")) @ann(immutable.this.List.apply("4b"))) = { + @new ann(List.apply("1a")) @new ann(List.apply("1b")) class C[@new ann(List.apply("2a")) @new ann(List.apply("2b")) T >: Nothing <: Any] extends AnyRef { + @new ann(List.apply("3a")) @new ann(List.apply("3b")) private[this] val x: T @ann(List.apply("4a")) @ann(List.apply("4b")) = _; + def (@new ann(List.apply("3a")) @new ann(List.apply("3b")) x: T @ann(List.apply("4a")) @ann(List.apply("4b"))) = { super.(); () }; - @new ann(immutable.this.List.apply("5a")) @new ann(immutable.this.List.apply("5b")) def f(x: Int @ann(immutable.this.List.apply("6a")) @ann(immutable.this.List.apply("6b"))) = { - @new ann(immutable.this.List.apply("7a")) @new ann(immutable.this.List.apply("7b")) val r = x.$plus(3): @ann(immutable.this.List.apply("8a")): @ann(immutable.this.List.apply("8b")); - val s = (4: Int @ann(immutable.this.List.apply("9a")) @ann(immutable.this.List.apply("9b"))); + @new ann(List.apply("5a")) @new ann(List.apply("5b")) def f(x: Int @ann(List.apply("6a")) @ann(List.apply("6b"))) = { + @new ann(List.apply("7a")) @new ann(List.apply("7b")) val r = x.$plus(3): @ann(List.apply("8a")): @ann(List.apply("8b")); + val s = (4: Int @ann(List.apply("9a")) @ann(List.apply("9b"))); r.$plus(s) } }; () } { - @ann(immutable.this.List.apply[String]("1a")) @ann(immutable.this.List.apply[String]("1b")) class C[@ann(immutable.this.List.apply[String]("2a")) @ann(immutable.this.List.apply[String]("2b")) T] extends AnyRef { - @ann(immutable.this.List.apply[String]("3a")) @ann(immutable.this.List.apply[String]("3b")) private[this] val x: T @ann(immutable.this.List.apply[String]("4b")) @ann(immutable.this.List.apply[String]("4a")) = _; - def (@ann(immutable.this.List.apply[String]("3a")) @ann(immutable.this.List.apply[String]("3b")) x: T @ann(immutable.this.List.apply[String]("4b")) @ann(immutable.this.List.apply[String]("4a"))): C[T] = { + @ann(List.apply[String]("1a")) @ann(List.apply[String]("1b")) class C[@ann(List.apply[String]("2a")) @ann(List.apply[String]("2b")) T] extends AnyRef { + @ann(List.apply[String]("3a")) @ann(List.apply[String]("3b")) private[this] val x: T @ann(List.apply[String]("4b")) @ann(List.apply[String]("4a")) = _; + def (@ann(List.apply[String]("3a")) @ann(List.apply[String]("3b")) x: T @ann(List.apply[String]("4b")) @ann(List.apply[String]("4a"))): C[T] = { C.super.(); () }; - @ann(immutable.this.List.apply[String]("5a")) @ann(immutable.this.List.apply[String]("5b")) def f(x: Int @ann(immutable.this.List.apply[String]("6b")) @ann(immutable.this.List.apply[String]("6a"))): Int = { - @ann(immutable.this.List.apply[String]("7a")) @ann(immutable.this.List.apply[String]("7b")) val r: Int @ann(immutable.this.List.apply[String]("8b")) @ann(immutable.this.List.apply[String]("8a")) = ((x.+(3): Int @ann(immutable.this.List.apply[String]("8a"))): Int @ann(immutable.this.List.apply[String]("8b")) @ann(immutable.this.List.apply[String]("8a"))); - val s: Int @ann(immutable.this.List.apply[String]("9b")) @ann(immutable.this.List.apply[String]("9a")) = (4: Int @ann(immutable.this.List.apply[String]("9b")) @ann(immutable.this.List.apply[String]("9a"))); + @ann(List.apply[String]("5a")) @ann(List.apply[String]("5b")) def f(x: Int @ann(List.apply[String]("6b")) @ann(List.apply[String]("6a"))): Int = { + @ann(List.apply[String]("7a")) @ann(List.apply[String]("7b")) val r: Int @ann(List.apply[String]("8b")) @ann(List.apply[String]("8a")) = ((x.+(3): Int @ann(List.apply[String]("8a"))): Int @ann(List.apply[String]("8b")) @ann(List.apply[String]("8a"))); + val s: Int @ann(List.apply[String]("9b")) @ann(List.apply[String]("9a")) = (4: Int @ann(List.apply[String]("9b")) @ann(List.apply[String]("9a"))); r.+(s) } }; diff --git a/test/files/run/reify_ann2a.check b/test/files/run/reify_ann2a.check index 934af54802..ccbcb4c31e 100644 --- a/test/files/run/reify_ann2a.check +++ b/test/files/run/reify_ann2a.check @@ -1,20 +1,20 @@ { class ann extends StaticAnnotation { - private[this] val bar: List[String] = _; - def (bar: List[String]) = { + private[this] val bar: `package`.List[Predef.String] = _; + def (bar: `package`.List[Predef.String]) = { super.(); () } }; - @new ann(immutable.this.List.apply("1a")) @new ann(immutable.this.List.apply("1b")) class C[@new ann(immutable.this.List.apply("2a")) @new ann(immutable.this.List.apply("2b")) T >: Nothing <: Any] extends AnyRef { - @new ann(immutable.this.List.apply("3a")) @new ann(immutable.this.List.apply("3b")) private[this] val x: T @ann(immutable.this.List.apply("4a")) @ann(immutable.this.List.apply("4b")) = _; - def (@new ann(immutable.this.List.apply("3a")) @new ann(immutable.this.List.apply("3b")) x: T @ann(immutable.this.List.apply("4a")) @ann(immutable.this.List.apply("4b"))) = { + @new ann(List.apply("1a")) @new ann(List.apply("1b")) class C[@new ann(List.apply("2a")) @new ann(List.apply("2b")) T >: Nothing <: Any] extends AnyRef { + @new ann(List.apply("3a")) @new ann(List.apply("3b")) private[this] val x: T @ann(List.apply("4a")) @ann(List.apply("4b")) = _; + def (@new ann(List.apply("3a")) @new ann(List.apply("3b")) x: T @ann(List.apply("4a")) @ann(List.apply("4b"))) = { super.(); () }; - @new ann(immutable.this.List.apply("5a")) @new ann(immutable.this.List.apply("5b")) def f(x: Int @ann(immutable.this.List.apply("6a")) @ann(immutable.this.List.apply("6b"))) = { - @new ann(immutable.this.List.apply("7a")) @new ann(immutable.this.List.apply("7b")) val r = x.$plus(3): @ann(immutable.this.List.apply("8a")): @ann(immutable.this.List.apply("8b")); - val s = (4: Int @ann(immutable.this.List.apply("9a")) @ann(immutable.this.List.apply("9b"))); + @new ann(List.apply("5a")) @new ann(List.apply("5b")) def f(x: Int @ann(List.apply("6a")) @ann(List.apply("6b"))) = { + @new ann(List.apply("7a")) @new ann(List.apply("7b")) val r = x.$plus(3): @ann(List.apply("8a")): @ann(List.apply("8b")); + val s = (4: Int @ann(List.apply("9a")) @ann(List.apply("9b"))); r.$plus(s) } }; @@ -28,15 +28,15 @@ () } }; - @ann(immutable.this.List.apply[String]("1a")) @ann(immutable.this.List.apply[String]("1b")) class C[@ann(immutable.this.List.apply[String]("2a")) @ann(immutable.this.List.apply[String]("2b")) T] extends AnyRef { - @ann(immutable.this.List.apply[String]("3a")) @ann(immutable.this.List.apply[String]("3b")) private[this] val x: T @ann(immutable.this.List.apply[String]("4b")) @ann(immutable.this.List.apply[String]("4a")) = _; - def (@ann(immutable.this.List.apply[String]("3a")) @ann(immutable.this.List.apply[String]("3b")) x: T @ann(immutable.this.List.apply[String]("4b")) @ann(immutable.this.List.apply[String]("4a"))): C[T] = { + @ann(List.apply[String]("1a")) @ann(List.apply[String]("1b")) class C[@ann(List.apply[String]("2a")) @ann(List.apply[String]("2b")) T] extends AnyRef { + @ann(List.apply[String]("3a")) @ann(List.apply[String]("3b")) private[this] val x: T @ann(List.apply[String]("4b")) @ann(List.apply[String]("4a")) = _; + def (@ann(List.apply[String]("3a")) @ann(List.apply[String]("3b")) x: T @ann(List.apply[String]("4b")) @ann(List.apply[String]("4a"))): C[T] = { C.super.(); () }; - @ann(immutable.this.List.apply[String]("5a")) @ann(immutable.this.List.apply[String]("5b")) def f(x: Int @ann(immutable.this.List.apply[String]("6b")) @ann(immutable.this.List.apply[String]("6a"))): Int = { - @ann(immutable.this.List.apply[String]("7a")) @ann(immutable.this.List.apply[String]("7b")) val r: Int @ann(immutable.this.List.apply[String]("8b")) @ann(immutable.this.List.apply[String]("8a")) = ((x.+(3): Int @ann(immutable.this.List.apply[String]("8a"))): Int @ann(immutable.this.List.apply[String]("8b")) @ann(immutable.this.List.apply[String]("8a"))); - val s: Int @ann(immutable.this.List.apply[String]("9b")) @ann(immutable.this.List.apply[String]("9a")) = (4: Int @ann(immutable.this.List.apply[String]("9b")) @ann(immutable.this.List.apply[String]("9a"))); + @ann(List.apply[String]("5a")) @ann(List.apply[String]("5b")) def f(x: Int @ann(List.apply[String]("6b")) @ann(List.apply[String]("6a"))): Int = { + @ann(List.apply[String]("7a")) @ann(List.apply[String]("7b")) val r: Int @ann(List.apply[String]("8b")) @ann(List.apply[String]("8a")) = ((x.+(3): Int @ann(List.apply[String]("8a"))): Int @ann(List.apply[String]("8b")) @ann(List.apply[String]("8a"))); + val s: Int @ann(List.apply[String]("9b")) @ann(List.apply[String]("9a")) = (4: Int @ann(List.apply[String]("9b")) @ann(List.apply[String]("9a"))); r.+(s) } }; diff --git a/test/files/run/reify_copypaste2.check b/test/files/run/reify_copypaste2.check index 9c34f5179b..f5c1076962 100644 --- a/test/files/run/reify_copypaste2.check +++ b/test/files/run/reify_copypaste2.check @@ -1 +1 @@ -scala.reflect.runtime.`package`.universe.reify(Test.this.x) +`package`.universe.reify(Test.this.x) diff --git a/test/files/run/reify_newimpl_35.check b/test/files/run/reify_newimpl_35.check index 5545e6e005..52aaa171e0 100644 --- a/test/files/run/reify_newimpl_35.check +++ b/test/files/run/reify_newimpl_35.check @@ -10,7 +10,7 @@ scala> def foo[T: TypeTag] = reify{List[T]()} foo: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.Expr[List[T]] scala> println(foo) -Expr[List[Nothing]](immutable.this.Nil) +Expr[List[Nothing]](Nil) scala> diff --git a/test/files/run/showraw_tree.check b/test/files/run/showraw_tree.check index dca272684e..b71018d4fe 100644 --- a/test/files/run/showraw_tree.check +++ b/test/files/run/showraw_tree.check @@ -1,2 +1,2 @@ -Apply(Select(New(AppliedTypeTree(Ident(scala.collection.immutable.HashMap), List(Ident(newTypeName("String")), Ident(newTypeName("String"))))), nme.CONSTRUCTOR), List()) -Apply(Select(New(AppliedTypeTree(Ident(scala.collection.mutable.HashMap), List(Ident(newTypeName("String")), Ident(newTypeName("String"))))), nme.CONSTRUCTOR), List()) +Apply(Select(New(AppliedTypeTree(Ident(scala.collection.immutable.HashMap), List(Select(Ident(scala.Predef), newTypeName("String")), Select(Ident(scala.Predef), newTypeName("String"))))), nme.CONSTRUCTOR), List()) +Apply(Select(New(AppliedTypeTree(Ident(scala.collection.mutable.HashMap), List(Select(Ident(scala.Predef), newTypeName("String")), Select(Ident(scala.Predef), newTypeName("String"))))), nme.CONSTRUCTOR), List()) diff --git a/test/files/run/showraw_tree_ids.check b/test/files/run/showraw_tree_ids.check index d25599c7fc..5835ffa6de 100644 --- a/test/files/run/showraw_tree_ids.check +++ b/test/files/run/showraw_tree_ids.check @@ -1,2 +1,2 @@ -Apply(Select(New(AppliedTypeTree(Ident(scala.collection.immutable.HashMap#), List(Ident(newTypeName("String")#), Ident(newTypeName("String")#)))), nme.CONSTRUCTOR), List()) -Apply(Select(New(AppliedTypeTree(Ident(scala.collection.mutable.HashMap#), List(Ident(newTypeName("String")#), Ident(newTypeName("String")#)))), nme.CONSTRUCTOR), List()) +Apply(Select(New(AppliedTypeTree(Ident(scala.collection.immutable.HashMap#), List(Select(Ident(scala.Predef#), newTypeName("String")), Select(Ident(scala.Predef#), newTypeName("String"))))), nme.CONSTRUCTOR), List()) +Apply(Select(New(AppliedTypeTree(Ident(scala.collection.mutable.HashMap#), List(Select(Ident(scala.Predef#), newTypeName("String")), Select(Ident(scala.Predef#), newTypeName("String"))))), nme.CONSTRUCTOR), List()) diff --git a/test/files/run/showraw_tree_kinds.check b/test/files/run/showraw_tree_kinds.check index d0d4cd0058..c4d66856d4 100644 --- a/test/files/run/showraw_tree_kinds.check +++ b/test/files/run/showraw_tree_kinds.check @@ -1,2 +1,2 @@ -Apply(Select(New(AppliedTypeTree(Ident(scala.collection.immutable.HashMap#CLS), List(Ident(newTypeName("String")#TPE), Ident(newTypeName("String")#TPE)))), nme.CONSTRUCTOR), List()) -Apply(Select(New(AppliedTypeTree(Ident(scala.collection.mutable.HashMap#CLS), List(Ident(newTypeName("String")#TPE), Ident(newTypeName("String")#TPE)))), nme.CONSTRUCTOR), List()) +Apply(Select(New(AppliedTypeTree(Ident(scala.collection.immutable.HashMap#CLS), List(Select(Ident(scala.Predef#MOD), newTypeName("String")), Select(Ident(scala.Predef#MOD), newTypeName("String"))))), nme.CONSTRUCTOR), List()) +Apply(Select(New(AppliedTypeTree(Ident(scala.collection.mutable.HashMap#CLS), List(Select(Ident(scala.Predef#MOD), newTypeName("String")), Select(Ident(scala.Predef#MOD), newTypeName("String"))))), nme.CONSTRUCTOR), List()) diff --git a/test/files/run/showraw_tree_types_ids.check b/test/files/run/showraw_tree_types_ids.check index 92ee45a1e6..fccb81d8df 100644 --- a/test/files/run/showraw_tree_types_ids.check +++ b/test/files/run/showraw_tree_types_ids.check @@ -1,10 +1,12 @@ -Apply[1](Select[2](New[1](TypeTree[1]().setOriginal(AppliedTypeTree(Ident[3](scala.collection.immutable.HashMap#), List(TypeTree[4]().setOriginal(Ident[4](newTypeName("String")#)), TypeTree[4]().setOriginal(Ident[4](newTypeName("String")#)))))), nme.CONSTRUCTOR#), List()) -[1] TypeRef(ThisType(scala.collection.immutable#), scala.collection.immutable.HashMap#, List(TypeRef(ThisType(scala.Predef#), newTypeName("String")#, List()), TypeRef(ThisType(scala.Predef#), newTypeName("String")#, List()))) -[2] MethodType(List(), TypeRef(ThisType(scala.collection.immutable#), scala.collection.immutable.HashMap#, List(TypeRef(ThisType(scala.Predef#), newTypeName("String")#, List()), TypeRef(ThisType(scala.Predef#), newTypeName("String")#, List())))) +Apply[1](Select[2](New[1](TypeTree[1]().setOriginal(AppliedTypeTree(Ident[3](scala.collection.immutable.HashMap#), List(TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef#), newTypeName("String")#)), TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef#), newTypeName("String")#)))))), nme.CONSTRUCTOR#), List()) +[1] TypeRef(ThisType(scala.collection.immutable#), scala.collection.immutable.HashMap#, List(TypeRef(SingleType(ThisType(scala#), scala.Predef#), newTypeName("String")#, List()), TypeRef(SingleType(ThisType(scala#), scala.Predef#), newTypeName("String")#, List()))) +[2] MethodType(List(), TypeRef(ThisType(scala.collection.immutable#), scala.collection.immutable.HashMap#, List(TypeRef(SingleType(ThisType(scala#), scala.Predef#), newTypeName("String")#, List()), TypeRef(SingleType(ThisType(scala#), scala.Predef#), newTypeName("String")#, List())))) [3] TypeRef(ThisType(scala.collection.immutable#), scala.collection.immutable.HashMap#, List()) -[4] TypeRef(ThisType(scala.Predef#), newTypeName("String")#, List()) -Apply[5](Select[6](New[5](TypeTree[5]().setOriginal(AppliedTypeTree(Ident[7](scala.collection.mutable.HashMap#), List(TypeTree[4]().setOriginal(Ident[4](newTypeName("String")#)), TypeTree[4]().setOriginal(Ident[4](newTypeName("String")#)))))), nme.CONSTRUCTOR#), List()) -[4] TypeRef(ThisType(scala.Predef#), newTypeName("String")#, List()) -[5] TypeRef(ThisType(scala.collection.mutable#), scala.collection.mutable.HashMap#, List(TypeRef(ThisType(scala.Predef#), newTypeName("String")#, List()), TypeRef(ThisType(scala.Predef#), newTypeName("String")#, List()))) -[6] MethodType(List(), TypeRef(ThisType(scala.collection.mutable#), scala.collection.mutable.HashMap#, List(TypeRef(ThisType(scala.Predef#), newTypeName("String")#, List()), TypeRef(ThisType(scala.Predef#), newTypeName("String")#, List())))) -[7] TypeRef(ThisType(scala.collection.mutable#), scala.collection.mutable.HashMap#, List()) +[4] TypeRef(SingleType(ThisType(scala#), scala.Predef#), newTypeName("String")#, List()) +[5] SingleType(ThisType(scala#), scala.Predef#) +Apply[6](Select[7](New[6](TypeTree[6]().setOriginal(AppliedTypeTree(Ident[8](scala.collection.mutable.HashMap#), List(TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef#), newTypeName("String")#)), TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef#), newTypeName("String")#)))))), nme.CONSTRUCTOR#), List()) +[4] TypeRef(SingleType(ThisType(scala#), scala.Predef#), newTypeName("String")#, List()) +[5] SingleType(ThisType(scala#), scala.Predef#) +[6] TypeRef(ThisType(scala.collection.mutable#), scala.collection.mutable.HashMap#, List(TypeRef(SingleType(ThisType(scala#), scala.Predef#), newTypeName("String")#, List()), TypeRef(SingleType(ThisType(scala#), scala.Predef#), newTypeName("String")#, List()))) +[7] MethodType(List(), TypeRef(ThisType(scala.collection.mutable#), scala.collection.mutable.HashMap#, List(TypeRef(SingleType(ThisType(scala#), scala.Predef#), newTypeName("String")#, List()), TypeRef(SingleType(ThisType(scala#), scala.Predef#), newTypeName("String")#, List())))) +[8] TypeRef(ThisType(scala.collection.mutable#), scala.collection.mutable.HashMap#, List()) diff --git a/test/files/run/showraw_tree_types_typed.check b/test/files/run/showraw_tree_types_typed.check index c6c20409dc..f3e0f8c5f6 100644 --- a/test/files/run/showraw_tree_types_typed.check +++ b/test/files/run/showraw_tree_types_typed.check @@ -1,10 +1,12 @@ -Apply[1](Select[2](New[1](TypeTree[1]().setOriginal(AppliedTypeTree(Ident[3](scala.collection.immutable.HashMap), List(TypeTree[4]().setOriginal(Ident[4](newTypeName("String"))), TypeTree[4]().setOriginal(Ident[4](newTypeName("String"))))))), nme.CONSTRUCTOR), List()) -[1] TypeRef(ThisType(scala.collection.immutable), scala.collection.immutable.HashMap, List(TypeRef(ThisType(scala.Predef), newTypeName("String"), List()), TypeRef(ThisType(scala.Predef), newTypeName("String"), List()))) -[2] MethodType(List(), TypeRef(ThisType(scala.collection.immutable), scala.collection.immutable.HashMap, List(TypeRef(ThisType(scala.Predef), newTypeName("String"), List()), TypeRef(ThisType(scala.Predef), newTypeName("String"), List())))) +Apply[1](Select[2](New[1](TypeTree[1]().setOriginal(AppliedTypeTree(Ident[3](scala.collection.immutable.HashMap), List(TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef), newTypeName("String"))), TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef), newTypeName("String"))))))), nme.CONSTRUCTOR), List()) +[1] TypeRef(ThisType(scala.collection.immutable), scala.collection.immutable.HashMap, List(TypeRef(SingleType(ThisType(scala), scala.Predef), newTypeName("String"), List()), TypeRef(SingleType(ThisType(scala), scala.Predef), newTypeName("String"), List()))) +[2] MethodType(List(), TypeRef(ThisType(scala.collection.immutable), scala.collection.immutable.HashMap, List(TypeRef(SingleType(ThisType(scala), scala.Predef), newTypeName("String"), List()), TypeRef(SingleType(ThisType(scala), scala.Predef), newTypeName("String"), List())))) [3] TypeRef(ThisType(scala.collection.immutable), scala.collection.immutable.HashMap, List()) -[4] TypeRef(ThisType(scala.Predef), newTypeName("String"), List()) -Apply[5](Select[6](New[5](TypeTree[5]().setOriginal(AppliedTypeTree(Ident[7](scala.collection.mutable.HashMap), List(TypeTree[4]().setOriginal(Ident[4](newTypeName("String"))), TypeTree[4]().setOriginal(Ident[4](newTypeName("String"))))))), nme.CONSTRUCTOR), List()) -[4] TypeRef(ThisType(scala.Predef), newTypeName("String"), List()) -[5] TypeRef(ThisType(scala.collection.mutable), scala.collection.mutable.HashMap, List(TypeRef(ThisType(scala.Predef), newTypeName("String"), List()), TypeRef(ThisType(scala.Predef), newTypeName("String"), List()))) -[6] MethodType(List(), TypeRef(ThisType(scala.collection.mutable), scala.collection.mutable.HashMap, List(TypeRef(ThisType(scala.Predef), newTypeName("String"), List()), TypeRef(ThisType(scala.Predef), newTypeName("String"), List())))) -[7] TypeRef(ThisType(scala.collection.mutable), scala.collection.mutable.HashMap, List()) +[4] TypeRef(SingleType(ThisType(scala), scala.Predef), newTypeName("String"), List()) +[5] SingleType(ThisType(scala), scala.Predef) +Apply[6](Select[7](New[6](TypeTree[6]().setOriginal(AppliedTypeTree(Ident[8](scala.collection.mutable.HashMap), List(TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef), newTypeName("String"))), TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef), newTypeName("String"))))))), nme.CONSTRUCTOR), List()) +[4] TypeRef(SingleType(ThisType(scala), scala.Predef), newTypeName("String"), List()) +[5] SingleType(ThisType(scala), scala.Predef) +[6] TypeRef(ThisType(scala.collection.mutable), scala.collection.mutable.HashMap, List(TypeRef(SingleType(ThisType(scala), scala.Predef), newTypeName("String"), List()), TypeRef(SingleType(ThisType(scala), scala.Predef), newTypeName("String"), List()))) +[7] MethodType(List(), TypeRef(ThisType(scala.collection.mutable), scala.collection.mutable.HashMap, List(TypeRef(SingleType(ThisType(scala), scala.Predef), newTypeName("String"), List()), TypeRef(SingleType(ThisType(scala), scala.Predef), newTypeName("String"), List())))) +[8] TypeRef(ThisType(scala.collection.mutable), scala.collection.mutable.HashMap, List()) diff --git a/test/files/run/showraw_tree_types_untyped.check b/test/files/run/showraw_tree_types_untyped.check index dca272684e..b71018d4fe 100644 --- a/test/files/run/showraw_tree_types_untyped.check +++ b/test/files/run/showraw_tree_types_untyped.check @@ -1,2 +1,2 @@ -Apply(Select(New(AppliedTypeTree(Ident(scala.collection.immutable.HashMap), List(Ident(newTypeName("String")), Ident(newTypeName("String"))))), nme.CONSTRUCTOR), List()) -Apply(Select(New(AppliedTypeTree(Ident(scala.collection.mutable.HashMap), List(Ident(newTypeName("String")), Ident(newTypeName("String"))))), nme.CONSTRUCTOR), List()) +Apply(Select(New(AppliedTypeTree(Ident(scala.collection.immutable.HashMap), List(Select(Ident(scala.Predef), newTypeName("String")), Select(Ident(scala.Predef), newTypeName("String"))))), nme.CONSTRUCTOR), List()) +Apply(Select(New(AppliedTypeTree(Ident(scala.collection.mutable.HashMap), List(Select(Ident(scala.Predef), newTypeName("String")), Select(Ident(scala.Predef), newTypeName("String"))))), nme.CONSTRUCTOR), List()) diff --git a/test/files/run/showraw_tree_ultimate.check b/test/files/run/showraw_tree_ultimate.check index 46ccd4df8f..a6286ba754 100644 --- a/test/files/run/showraw_tree_ultimate.check +++ b/test/files/run/showraw_tree_ultimate.check @@ -1,10 +1,12 @@ -Apply[1](Select[2](New[1](TypeTree[1]().setOriginal(AppliedTypeTree(Ident[3](scala.collection.immutable.HashMap##CLS), List(TypeTree[4]().setOriginal(Ident[4](newTypeName("String")##TPE)), TypeTree[4]().setOriginal(Ident[4](newTypeName("String")##TPE)))))), nme.CONSTRUCTOR##PCTOR), List()) -[1] TypeRef(ThisType(scala.collection.immutable##PK), scala.collection.immutable.HashMap##CLS, List(TypeRef(ThisType(scala.Predef##MODC), newTypeName("String")##TPE, List()), TypeRef(ThisType(scala.Predef##MODC), newTypeName("String")##TPE, List()))) -[2] MethodType(List(), TypeRef(ThisType(scala.collection.immutable##PK), scala.collection.immutable.HashMap##CLS, List(TypeRef(ThisType(scala.Predef##MODC), newTypeName("String")##TPE, List()), TypeRef(ThisType(scala.Predef##MODC), newTypeName("String")##TPE, List())))) +Apply[1](Select[2](New[1](TypeTree[1]().setOriginal(AppliedTypeTree(Ident[3](scala.collection.immutable.HashMap##CLS), List(TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef##MOD), newTypeName("String")##TPE)), TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef##MOD), newTypeName("String")##TPE)))))), nme.CONSTRUCTOR##PCTOR), List()) +[1] TypeRef(ThisType(scala.collection.immutable##PK), scala.collection.immutable.HashMap##CLS, List(TypeRef(SingleType(ThisType(scala##PK), scala.Predef##MOD), newTypeName("String")##TPE, List()), TypeRef(SingleType(ThisType(scala##PK), scala.Predef##MOD), newTypeName("String")##TPE, List()))) +[2] MethodType(List(), TypeRef(ThisType(scala.collection.immutable##PK), scala.collection.immutable.HashMap##CLS, List(TypeRef(SingleType(ThisType(scala##PK), scala.Predef##MOD), newTypeName("String")##TPE, List()), TypeRef(SingleType(ThisType(scala##PK), scala.Predef##MOD), newTypeName("String")##TPE, List())))) [3] TypeRef(ThisType(scala.collection.immutable##PK), scala.collection.immutable.HashMap##CLS, List()) -[4] TypeRef(ThisType(scala.Predef##MODC), newTypeName("String")##TPE, List()) -Apply[5](Select[6](New[5](TypeTree[5]().setOriginal(AppliedTypeTree(Ident[7](scala.collection.mutable.HashMap##CLS), List(TypeTree[4]().setOriginal(Ident[4](newTypeName("String")##TPE)), TypeTree[4]().setOriginal(Ident[4](newTypeName("String")##TPE)))))), nme.CONSTRUCTOR##CTOR), List()) -[4] TypeRef(ThisType(scala.Predef##MODC), newTypeName("String")##TPE, List()) -[5] TypeRef(ThisType(scala.collection.mutable##PK), scala.collection.mutable.HashMap##CLS, List(TypeRef(ThisType(scala.Predef##MODC), newTypeName("String")##TPE, List()), TypeRef(ThisType(scala.Predef##MODC), newTypeName("String")##TPE, List()))) -[6] MethodType(List(), TypeRef(ThisType(scala.collection.mutable##PK), scala.collection.mutable.HashMap##CLS, List(TypeRef(ThisType(scala.Predef##MODC), newTypeName("String")##TPE, List()), TypeRef(ThisType(scala.Predef##MODC), newTypeName("String")##TPE, List())))) -[7] TypeRef(ThisType(scala.collection.mutable##PK), scala.collection.mutable.HashMap##CLS, List()) +[4] TypeRef(SingleType(ThisType(scala##PK), scala.Predef##MOD), newTypeName("String")##TPE, List()) +[5] SingleType(ThisType(scala##PK), scala.Predef##MOD) +Apply[6](Select[7](New[6](TypeTree[6]().setOriginal(AppliedTypeTree(Ident[8](scala.collection.mutable.HashMap##CLS), List(TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef##MOD), newTypeName("String")##TPE)), TypeTree[4]().setOriginal(Select[4](Ident[5](scala.Predef##MOD), newTypeName("String")##TPE)))))), nme.CONSTRUCTOR##CTOR), List()) +[4] TypeRef(SingleType(ThisType(scala##PK), scala.Predef##MOD), newTypeName("String")##TPE, List()) +[5] SingleType(ThisType(scala##PK), scala.Predef##MOD) +[6] TypeRef(ThisType(scala.collection.mutable##PK), scala.collection.mutable.HashMap##CLS, List(TypeRef(SingleType(ThisType(scala##PK), scala.Predef##MOD), newTypeName("String")##TPE, List()), TypeRef(SingleType(ThisType(scala##PK), scala.Predef##MOD), newTypeName("String")##TPE, List()))) +[7] MethodType(List(), TypeRef(ThisType(scala.collection.mutable##PK), scala.collection.mutable.HashMap##CLS, List(TypeRef(SingleType(ThisType(scala##PK), scala.Predef##MOD), newTypeName("String")##TPE, List()), TypeRef(SingleType(ThisType(scala##PK), scala.Predef##MOD), newTypeName("String")##TPE, List())))) +[8] TypeRef(ThisType(scala.collection.mutable##PK), scala.collection.mutable.HashMap##CLS, List()) diff --git a/test/files/run/t2886.check b/test/files/run/t2886.check index ce31bc7408..a70f9935ed 100644 --- a/test/files/run/t2886.check +++ b/test/files/run/t2886.check @@ -1,4 +1,4 @@ -((x: String) => { +((x: Predef.String) => { val x$1 = x; val x$2 = x; Test.this.test(x$2, x$1) diff --git a/test/files/run/t5225_2.check b/test/files/run/t5225_2.check index 8ed54a14bb..5faa365bce 100644 --- a/test/files/run/t5225_2.check +++ b/test/files/run/t5225_2.check @@ -1,4 +1,4 @@ { - def foo(@new cloneable() x: Int) = ""; + def foo(@new `package`.cloneable() x: Int) = ""; () } diff --git a/test/files/run/t5271_2.check b/test/files/run/t5271_2.check index 585331be65..1df88872a7 100644 --- a/test/files/run/t5271_2.check +++ b/test/files/run/t5271_2.check @@ -8,7 +8,7 @@ } }; val c = C.apply(2, 2); - scala.this.Predef.println(c.foo.$times(c.bar)) + Predef.println(c.foo.$times(c.bar)) } 4 () diff --git a/test/files/run/t5271_3.check b/test/files/run/t5271_3.check index b02acd21f9..99aacc2cee 100644 --- a/test/files/run/t5271_3.check +++ b/test/files/run/t5271_3.check @@ -15,7 +15,7 @@ } }; val c = C.apply(2, 2); - scala.this.Predef.println(c.foo.$times(c.bar).$eq$eq(C.qwe)) + Predef.println(c.foo.$times(c.bar).$eq$eq(C.qwe)) } true () diff --git a/test/files/run/t6591_5.check b/test/files/run/t6591_5.check index 8f1c2b3ede..e0b6d06e6b 100644 --- a/test/files/run/t6591_5.check +++ b/test/files/run/t6591_5.check @@ -1 +1 @@ -Expr(Block(List(ValDef(Modifiers(), newTermName("v"), Select(Select(This(newTypeName("A")), newTermName("x")), newTypeName("I")), Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("$qmark$qmark$qmark")))), Ident(newTermName("v")))) +Expr(Block(List(ValDef(Modifiers(), newTermName("v"), Select(Select(This(newTypeName("A")), newTermName("x")), newTypeName("I")), Select(Ident(scala.Predef), newTermName("$qmark$qmark$qmark")))), Ident(newTermName("v")))) diff --git a/test/files/run/t6591_6.check b/test/files/run/t6591_6.check index 5ddf7600f1..0c4847b628 100644 --- a/test/files/run/t6591_6.check +++ b/test/files/run/t6591_6.check @@ -1 +1 @@ -Expr(Block(List(ValDef(Modifiers(), newTermName("v"), Select(Select(Ident(newTermName("A")), newTermName("x")), newTypeName("I")), Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("$qmark$qmark$qmark")))), Ident(newTermName("v")))) +Expr(Block(List(ValDef(Modifiers(), newTermName("v"), Select(Select(Ident(newTermName("A")), newTermName("x")), newTypeName("I")), Select(Ident(scala.Predef), newTermName("$qmark$qmark$qmark")))), Ident(newTermName("v")))) diff --git a/test/files/run/toolbox_typecheck_macrosdisabled2.check b/test/files/run/toolbox_typecheck_macrosdisabled2.check index f5c9b6eeab..e7011d1ae2 100644 --- a/test/files/run/toolbox_typecheck_macrosdisabled2.check +++ b/test/files/run/toolbox_typecheck_macrosdisabled2.check @@ -19,7 +19,7 @@ def apply[U <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.api.Mirror[U]): U#Tree = { val $u: U = $m$untyped.universe; val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror]; - $u.Apply.apply($u.Select.apply($u.Select.apply($u.build.Ident($m.staticPackage("scala")), $u.newTermName("Array")), $u.newTermName("apply")), scala.collection.immutable.List.apply[$u.Literal]($u.Literal.apply($u.Constant.apply(2)))) + $u.Apply.apply($u.Select.apply($u.build.Ident($m.staticModule("scala.Array")), $u.newTermName("apply")), scala.collection.immutable.List.apply[$u.Literal]($u.Literal.apply($u.Constant.apply(2)))) } }; new $treecreator1() -- cgit v1.2.3 From 57c0e63ba18c5845772d737570342e4054af459f Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 8 Feb 2013 14:08:30 +0100 Subject: accommodates pull request feedback https://github.com/scala/scala/pull/2072 --- .../scala/reflect/reify/codegen/GenSymbols.scala | 31 ++++++++++++++++++++-- .../scala/tools/reflect/ToolBoxFactory.scala | 9 +++---- src/reflect/scala/reflect/internal/TreeInfo.scala | 15 +++++------ test/files/run/t6591_7.check | 4 +++ test/files/run/t6591_7.scala | 26 ++++++++++++++++++ 5 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 test/files/run/t6591_7.check create mode 100644 test/files/run/t6591_7.scala diff --git a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala index 0d795e3783..47c966ea24 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala @@ -1,6 +1,8 @@ package scala.reflect.reify package codegen +import scala.reflect.internal.Flags._ + trait GenSymbols { self: Reifier => @@ -100,8 +102,33 @@ trait GenSymbols { reifyIntoSymtab(binding.symbol) { sym => if (reifyDebug) println("Free term" + (if (sym.isCapturedVariable) " (captured)" else "") + ": " + sym + "(" + sym.accurateKindString + ")") val name = newTermName(nme.REIFY_FREE_PREFIX + sym.name + (if (sym.isType) nme.REIFY_FREE_THIS_SUFFIX else "")) - // Flag is set here to make reified free value pass stability test during reflective compilation - if (!sym.isMutable) sym setFlag reflect.internal.Flags.STABLE + // We need to note whether the free value being reified is stable or not to guide subsequent reflective compilation. + // Here's why reflection compilation needs our help. + // + // When dealing with a tree, which contain free values, toolboxes extract those and wrap the entire tree in a Function + // having parameters defined for every free values in the tree. For example, evaluating + // + // Ident(setTypeSignature(newFreeTerm("x", 2), )) + // + // Will generate something like + // + // object wrapper { + // def wrapper(x: () => Int) = { + // x() + // } + // } + // + // Note that free values get transformed into, effectively, by-name parameters. This is done to make sure + // that evaluation order is kept intact. And indeed, we cannot just evaluate all free values at once in order + // to obtain arguments for wrapper.wrapper, because if some of the free values end up being unused during evaluation, + // we might end up doing unnecessary calculations. + // + // So far, so good - we didn't need any flags at all. However, if the code being reified contains path-dependent types, + // we're in trouble, because valid code like `free.T` ends up being transformed into `free.apply().T`, which won't compile. + // + // To overcome this glitch, we note whether a given free term is stable or not (because vars can also end up being free terms). + // Then, if a free term is stable, we tell the compiler to treat `free.apply()` specially and assume that it's stable. + if (!sym.isMutable) sym setFlag STABLE if (sym.isCapturedVariable) { assert(binding.isInstanceOf[Ident], showRaw(binding)) val capturedBinding = referenceCapturedVariable(sym) diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index fdc790a920..c05c59d5ff 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -8,7 +8,7 @@ import scala.tools.nsc.typechecker.Modes import scala.tools.nsc.io.VirtualDirectory import scala.tools.nsc.interpreter.AbstractFileClassLoader import scala.tools.nsc.util.FreshNameCreator -import scala.reflect.internal.Flags +import scala.reflect.internal.Flags._ import scala.reflect.internal.util.{BatchSourceFile, NoSourceFile, NoFile} import java.lang.{Class => jClass} import scala.compat.Platform.EOL @@ -211,12 +211,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val meth = obj.moduleClass.newMethod(newTermName(wrapperMethodName)) def makeParam(schema: (FreeTermSymbol, TermName)) = { + // see a detailed explanation of the STABLE trick in `GenSymbols.reifyFreeTerm` val (fv, name) = schema - /* Free term symbol `fv` can contain flag which was set by - * `scala.reflect.reify.codegen.GenSymbols.reifyFreeTerm` method. - * It is recovered here, so value parameter can pass `isExprSafeToInline` - * test in `scala.reflect.internal.TreeInfo`. */ - meth.newValueParameter(name, newFlags = if (fv.hasStableFlag) Flags.STABLE else 0) setInfo appliedType(definitions.FunctionClass(0).tpe, List(fv.tpe.resultType)) + meth.newValueParameter(name, newFlags = if (fv.hasStableFlag) STABLE else 0) setInfo appliedType(definitions.FunctionClass(0).tpe, List(fv.tpe.resultType)) } meth setInfo MethodType(freeTerms.map(makeParam).toList, AnyClass.tpe) minfo.decls enter meth diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index f83106aaef..3040486076 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -89,18 +89,15 @@ abstract class TreeInfo { tree.symbol.isStable && isExprSafeToInline(qual) case TypeApply(fn, _) => isExprSafeToInline(fn) - /* Special case for reified free terms. During reflective compilation, - * reified value recovered flag from free term and wrapped into a - * Function object, so it can pass stability check here to become a stable - * identifier.*/ case Apply(Select(free @ Ident(_), nme.apply), _) if free.symbol.name endsWith nme.REIFY_FREE_VALUE_SUFFIX => + // see a detailed explanation of this trick in `GenSymbols.reifyFreeTerm` free.symbol.hasStableFlag && isExprSafeToInline(free) case Apply(fn, List()) => - /* Note: After uncurry, field accesses are represented as Apply(getter, Nil), - * so an Apply can also be pure. - * However, before typing, applications of nullary functional values are also - * Apply(function, Nil) trees. To prevent them from being treated as pure, - * we check that the callee is a method. */ + // Note: After uncurry, field accesses are represented as Apply(getter, Nil), + // so an Apply can also be pure. + // However, before typing, applications of nullary functional values are also + // Apply(function, Nil) trees. To prevent them from being treated as pure, + // we check that the callee is a method. fn.symbol.isMethod && !fn.symbol.isLazy && isExprSafeToInline(fn) case Typed(expr, _) => isExprSafeToInline(expr) diff --git a/test/files/run/t6591_7.check b/test/files/run/t6591_7.check new file mode 100644 index 0000000000..e21a3669b6 --- /dev/null +++ b/test/files/run/t6591_7.check @@ -0,0 +1,4 @@ +name = x, stable = true +name = y, stable = true +name = z, stable = false +name = C, stable = true diff --git a/test/files/run/t6591_7.scala b/test/files/run/t6591_7.scala new file mode 100644 index 0000000000..b6c8d399a0 --- /dev/null +++ b/test/files/run/t6591_7.scala @@ -0,0 +1,26 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object Test extends App { + locally { + val x = 2 + def y = 3 + var z = 4 + class C { + var w = 5 + locally { + val expr = reify(x + y + z + w) + // blocked by SI-7103, though it's not the focus of this test + // therefore I'm just commenting out the evaluation + // println(expr.eval) + expr.tree.freeTerms foreach (ft => { + // blocked by SI-7104, though it's not the focus of this test + // therefore I'm just commenting out the call to typeSignature + // println(s"name = ${ft.name}, sig = ${ft.typeSignature}, stable = ${ft.isStable}") + println(s"name = ${ft.name}, stable = ${ft.isStable}") + }) + } + } + new C() + } +} \ No newline at end of file -- cgit v1.2.3 From e0068b908517768e900a3945e483e9c379d728d8 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 5 Feb 2013 00:46:58 +0100 Subject: SI-5675 Discard duplicate feature warnings at a position When -feature has not been enabled, we were double counting identical feature warnings that were emitted at the same position. Normal error reporting only reports the first time a warning appears at a position; feature warning counter incrementing should behave the same way. @hubertp: Fixed .check files that were broken in the original commit. --- src/compiler/scala/tools/nsc/Global.scala | 6 +++--- test/files/buildmanager/t2650_1/t2650_1.check | 2 +- test/files/buildmanager/t2657/t2657.check | 2 +- test/files/jvm/interpreter.check | 4 ++-- test/files/neg/t3234.check | 2 +- test/files/neg/t5675.check | 2 ++ test/files/neg/t5675.flags | 1 + test/files/neg/t5675.scala | 7 +++++++ test/files/run/constrained-types.check | 8 ++++---- test/files/run/reflection-magicsymbols-repl.check | 2 +- test/files/run/t4172.check | 2 +- test/files/run/t4710.check | 2 +- test/files/run/t6028.check | 2 +- test/files/run/t6329_repl.check | 2 +- 14 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 test/files/neg/t5675.check create mode 100644 test/files/neg/t5675.flags create mode 100644 test/files/neg/t5675.scala diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 757ac94dbd..116684c161 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1193,13 +1193,13 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Collects for certain classes of warnings during this run. */ class ConditionalWarning(what: String, option: Settings#BooleanSetting) { - val warnings = new mutable.ListBuffer[(Position, String)] + val warnings = mutable.LinkedHashMap[Position, String]() def warn(pos: Position, msg: String) = if (option.value) reporter.warning(pos, msg) - else warnings += ((pos, msg)) + else if (!(warnings contains pos)) warnings += ((pos, msg)) def summarize() = if (option.isDefault && warnings.nonEmpty) - reporter.warning(NoPosition, "there were %d %s warnings; re-run with %s for details".format(warnings.size, what, option.name)) + reporter.warning(NoPosition, "there were %d %s warning(s); re-run with %s for details".format(warnings.size, what, option.name)) } def newUnitParser(code: String) = new syntaxAnalyzer.UnitParser(newCompilationUnit(code)) diff --git a/test/files/buildmanager/t2650_1/t2650_1.check b/test/files/buildmanager/t2650_1/t2650_1.check index f1e4b1b8bc..2f9dd124af 100644 --- a/test/files/buildmanager/t2650_1/t2650_1.check +++ b/test/files/buildmanager/t2650_1/t2650_1.check @@ -1,6 +1,6 @@ builder > A.scala B.scala compiling Set(A.scala, B.scala) -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details Changes: Map() builder > A.scala compiling Set(A.scala) diff --git a/test/files/buildmanager/t2657/t2657.check b/test/files/buildmanager/t2657/t2657.check index 0d6709e58b..7bff078f56 100644 --- a/test/files/buildmanager/t2657/t2657.check +++ b/test/files/buildmanager/t2657/t2657.check @@ -1,6 +1,6 @@ builder > A.scala B.scala compiling Set(A.scala, B.scala) -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details Changes: Map() builder > A.scala compiling Set(A.scala) diff --git a/test/files/jvm/interpreter.check b/test/files/jvm/interpreter.check index 6145b6c4d2..96b57c7742 100644 --- a/test/files/jvm/interpreter.check +++ b/test/files/jvm/interpreter.check @@ -97,7 +97,7 @@ scala> case class Bar(n: Int) defined class Bar scala> implicit def foo2bar(foo: Foo) = Bar(foo.n) -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details foo2bar: (foo: Foo)Bar scala> val bar: Bar = Foo(3) @@ -271,7 +271,7 @@ scala> xs map (x => x) res6: Array[_] = Array(1, 2) scala> xs map (x => (x, x)) -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details res7: Array[(_$1, _$1)] forSome { type _$1 } = Array((1,1), (2,2)) scala> diff --git a/test/files/neg/t3234.check b/test/files/neg/t3234.check index 477b021e5e..4339950ecb 100644 --- a/test/files/neg/t3234.check +++ b/test/files/neg/t3234.check @@ -1,2 +1,2 @@ -error: there were 1 inliner warnings; re-run with -Yinline-warnings for details +error: there were 1 inliner warning(s); re-run with -Yinline-warnings for details one error found diff --git a/test/files/neg/t5675.check b/test/files/neg/t5675.check new file mode 100644 index 0000000000..da608a2b78 --- /dev/null +++ b/test/files/neg/t5675.check @@ -0,0 +1,2 @@ +error: there were 1 feature warning(s); re-run with -feature for details +one error found diff --git a/test/files/neg/t5675.flags b/test/files/neg/t5675.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/t5675.flags @@ -0,0 +1 @@ +-Xfatal-warnings \ No newline at end of file diff --git a/test/files/neg/t5675.scala b/test/files/neg/t5675.scala new file mode 100644 index 0000000000..238ed0fcae --- /dev/null +++ b/test/files/neg/t5675.scala @@ -0,0 +1,7 @@ +class PostFix { + val list = List(1, 2, 3) + def main(args: Array[String]) { + val a = list filter (2 !=) + val b = list filter (2 != _) + } +} diff --git a/test/files/run/constrained-types.check b/test/files/run/constrained-types.check index da97a378e6..85c4f41872 100644 --- a/test/files/run/constrained-types.check +++ b/test/files/run/constrained-types.check @@ -75,11 +75,11 @@ scala> var four = "four" four: String = four scala> val four2 = m(four) // should have an existential bound -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details four2: String @Annot(x) forSome { val x: String } = four scala> val four3 = four2 // should have the same type as four2 -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details four3: String @Annot(x) forSome { val x: String } = four scala> val stuff = m("stuff") // should not crash @@ -102,7 +102,7 @@ scala> def m = { val y : String @Annot(x) = x y } // x should not escape the local scope with a narrow type -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details m: String @Annot(x) forSome { val x: String } scala> @@ -116,7 +116,7 @@ scala> def n(y: String) = { } m("stuff".stripMargin) } // x should be existentially bound -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details n: (y: String)String @Annot(x) forSome { val x: String } scala> diff --git a/test/files/run/reflection-magicsymbols-repl.check b/test/files/run/reflection-magicsymbols-repl.check index d3cd26f25f..2535e3f43d 100644 --- a/test/files/run/reflection-magicsymbols-repl.check +++ b/test/files/run/reflection-magicsymbols-repl.check @@ -23,7 +23,7 @@ scala> def test(n: Int): Unit = { val x = sig.asInstanceOf[MethodType].params.head println(x.typeSignature) } -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details test: (n: Int)Unit scala> for (i <- 1 to 8) test(i) diff --git a/test/files/run/t4172.check b/test/files/run/t4172.check index 94cdff4870..b48c9ca056 100644 --- a/test/files/run/t4172.check +++ b/test/files/run/t4172.check @@ -4,7 +4,7 @@ Type :help for more information. scala> scala> val c = { class C { override def toString = "C" }; ((new C, new C { def f = 2 })) } -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details c: (C, C{def f: Int}) forSome { type C <: AnyRef } = (C,C) scala> diff --git a/test/files/run/t4710.check b/test/files/run/t4710.check index 7c2b10b098..f2335d1bdd 100644 --- a/test/files/run/t4710.check +++ b/test/files/run/t4710.check @@ -2,7 +2,7 @@ Type in expressions to have them evaluated. Type :help for more information. scala> def method : String = { implicit def f(s: Symbol) = "" ; 'symbol } -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details method: String scala> diff --git a/test/files/run/t6028.check b/test/files/run/t6028.check index 79deaacf3a..94013efd36 100644 --- a/test/files/run/t6028.check +++ b/test/files/run/t6028.check @@ -81,4 +81,4 @@ package { } } -warning: there were 1 feature warnings; re-run with -feature for details +warning: there were 1 feature warning(s); re-run with -feature for details diff --git a/test/files/run/t6329_repl.check b/test/files/run/t6329_repl.check index 8663184bde..693263a5c2 100644 --- a/test/files/run/t6329_repl.check +++ b/test/files/run/t6329_repl.check @@ -4,7 +4,7 @@ Type :help for more information. scala> scala> classManifest[List[_]] -warning: there were 1 deprecation warnings; re-run with -deprecation for details +warning: there were 1 deprecation warning(s); re-run with -deprecation for details res0: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List[Any] scala> scala.reflect.classTag[List[_]] -- cgit v1.2.3 From 22341e7ab9722cf212c01e9830014648849f8e70 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 8 Feb 2013 13:52:58 -0800 Subject: Expanded bytecode testing code. def sameMethodAndFieldSignatures compares two classes to verify they have all the same methods and fields, and no others. --- src/partest/scala/tools/partest/AsmNode.scala | 60 ++++++++++++++++++++++ src/partest/scala/tools/partest/BytecodeTest.scala | 33 ++++++++++-- 2 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 src/partest/scala/tools/partest/AsmNode.scala diff --git a/src/partest/scala/tools/partest/AsmNode.scala b/src/partest/scala/tools/partest/AsmNode.scala new file mode 100644 index 0000000000..d181436676 --- /dev/null +++ b/src/partest/scala/tools/partest/AsmNode.scala @@ -0,0 +1,60 @@ +package scala.tools.partest + +import scala.collection.JavaConverters._ +import scala.tools.asm +import asm._ +import asm.tree._ +import java.lang.reflect.Modifier + +sealed trait AsmNode[+T] { + def node: T + def access: Int + def desc: String + def name: String + def signature: String + def attrs: List[Attribute] + def visibleAnnotations: List[AnnotationNode] + def invisibleAnnotations: List[AnnotationNode] + def characteristics = f"$name%15s $desc%-30s$accessString$sigString" + + private def accessString = if (access == 0) "" else " " + Modifier.toString(access) + private def sigString = if (signature == null) "" else " " + signature + override def toString = characteristics +} + +object AsmNode { + type AsmMethod = AsmNode[MethodNode] + type AsmField = AsmNode[FieldNode] + type AsmMember = AsmNode[_] + + implicit class ClassNodeOps(val node: ClassNode) { + def fieldsAndMethods: List[AsmMember] = { + val xs: List[AsmMember] = ( + node.methods.asScala.toList.map(x => (x: AsmMethod)) + ++ node.fields.asScala.toList.map(x => (x: AsmField)) + ) + xs sortBy (_.characteristics) + } + } + implicit class AsmMethodNode(val node: MethodNode) extends AsmNode[MethodNode] { + def access: Int = node.access + def desc: String = node.desc + def name: String = node.name + def signature: String = node.signature + def attrs: List[Attribute] = node.attrs.asScala.toList + def visibleAnnotations: List[AnnotationNode] = node.visibleAnnotations.asScala.toList + def invisibleAnnotations: List[AnnotationNode] = node.invisibleAnnotations.asScala.toList + } + implicit class AsmFieldNode(val node: FieldNode) extends AsmNode[FieldNode] { + def access: Int = node.access + def desc: String = node.desc + def name: String = node.name + def signature: String = node.signature + def attrs: List[Attribute] = node.attrs.asScala.toList + def visibleAnnotations: List[AnnotationNode] = node.visibleAnnotations.asScala.toList + def invisibleAnnotations: List[AnnotationNode] = node.invisibleAnnotations.asScala.toList + } + + def apply(node: MethodNode): AsmMethodNode = new AsmMethodNode(node) + def apply(node: FieldNode): AsmFieldNode = new AsmFieldNode(node) +} diff --git a/src/partest/scala/tools/partest/BytecodeTest.scala b/src/partest/scala/tools/partest/BytecodeTest.scala index 41329a8264..2699083069 100644 --- a/src/partest/scala/tools/partest/BytecodeTest.scala +++ b/src/partest/scala/tools/partest/BytecodeTest.scala @@ -3,9 +3,10 @@ package scala.tools.partest import scala.tools.nsc.util.JavaClassPath import scala.collection.JavaConverters._ import scala.tools.asm -import asm.ClassReader +import asm.{ ClassReader } import asm.tree.{ClassNode, MethodNode, InsnList} import java.io.InputStream +import AsmNode._ /** * Provides utilities for inspecting bytecode using ASM library. @@ -29,13 +30,14 @@ import java.io.InputStream * */ abstract class BytecodeTest extends ASMConverters { + import instructions._ /** produce the output to be compared against a checkfile */ protected def show(): Unit def main(args: Array[String]): Unit = show -// asserts + // asserts def sameBytecode(methA: MethodNode, methB: MethodNode) = { val isa = instructions.fromMethod(methA) val isb = instructions.fromMethod(methB) @@ -43,7 +45,32 @@ abstract class BytecodeTest extends ASMConverters { else diffInstructions(isa, isb) } - import instructions._ + // Do these classes have all the same methods, with the same names, access, + // descriptors and generic signatures? Method bodies are not considered, and + // the names of the classes containing the methods are substituted so they do + // not appear as differences. + def sameMethodAndFieldSignatures(clazzA: ClassNode, clazzB: ClassNode): Boolean = { + val ms1 = clazzA.fieldsAndMethods.toIndexedSeq + val ms2 = clazzB.fieldsAndMethods.toIndexedSeq + val name1 = clazzA.name + val name2 = clazzB.name + + if (ms1.length != ms2.length) { + println("Different member counts in $name1 and $name2") + false + } + else (ms1, ms2).zipped forall { (m1, m2) => + val c1 = m1.characteristics + val c2 = m2.characteristics.replaceAllLiterally(name2, name1) + if (c1 == c2) + println(s"[ok] $m1") + else + println(s"[fail]\n in $name1: $c1\n in $name2: $c2") + + c1 == c2 + } + } + // bytecode is equal modulo local variable numbering def equalsModuloVar(a: Instruction, b: Instruction) = (a, b) match { case _ if a == b => true -- cgit v1.2.3 From 13caa498fb856ac1de3b851ddc413e36d728c3a6 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 8 Feb 2013 13:10:46 -0800 Subject: Fix for paramaccessor alias regression. A binary incompatibility with 2.10.0 revealed a bug I had introduced in c58647f5f2. --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 2 +- test/files/run/t7106.check | 6 ++++++ test/files/run/t7106/Analyzed_1.scala | 14 ++++++++++++++ test/files/run/t7106/test.scala | 10 ++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 test/files/run/t7106.check create mode 100644 test/files/run/t7106/Analyzed_1.scala create mode 100644 test/files/run/t7106/test.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index dc5491a509..478312116a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2037,7 +2037,7 @@ trait Typers extends Modes with Adaptations with Tags { val alias = ( superAcc.initialize.alias orElse (superAcc getter superAcc.owner) - filter (alias => superClazz.info.nonPrivateMember(alias.name) != alias) + filter (alias => superClazz.info.nonPrivateMember(alias.name) == alias) ) if (alias.exists && !alias.accessed.isVariable) { val ownAcc = clazz.info decl name suchThat (_.isParamAccessor) match { diff --git a/test/files/run/t7106.check b/test/files/run/t7106.check new file mode 100644 index 0000000000..9a4bb430fd --- /dev/null +++ b/test/files/run/t7106.check @@ -0,0 +1,6 @@ +[ok] q1 I private final +[ok] q3 I private final +[ok] (III)V public +[ok] bippy1 ()I public +[ok] bippy2 ()I public +[ok] bippy3 ()I public diff --git a/test/files/run/t7106/Analyzed_1.scala b/test/files/run/t7106/Analyzed_1.scala new file mode 100644 index 0000000000..a2ddebceed --- /dev/null +++ b/test/files/run/t7106/Analyzed_1.scala @@ -0,0 +1,14 @@ + +abstract class Base0 { def p2: Int } +class Base(p1: Int, override val p2: Int) extends Base0 + +abstract class Sub1(q1: Int, q2: Int, q3: Int) extends Base(q1, q2) { + def bippy1 = q1 + def bippy2 = q2 + def bippy3 = q3 +} +abstract class Sub2(q1: Int, q2: Int, q3: Int) extends Base(q1, q2) { + def bippy1 = q1 + def bippy2 = p2 + def bippy3 = q3 +} diff --git a/test/files/run/t7106/test.scala b/test/files/run/t7106/test.scala new file mode 100644 index 0000000000..3584a272db --- /dev/null +++ b/test/files/run/t7106/test.scala @@ -0,0 +1,10 @@ +import scala.tools.partest.BytecodeTest + +object Test extends BytecodeTest { + def show { + val node1 = loadClassNode("Sub1") + val node2 = loadClassNode("Sub2") + + sameMethodAndFieldSignatures(node1, node2) + } +} -- cgit v1.2.3