summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJames Iry <jamesiry@gmail.com>2013-01-13 20:33:52 -0800
committerJames Iry <jamesiry@gmail.com>2013-01-13 20:39:13 -0800
commit3ef487ecb6733bfe3c13d89780ebcfc81f9a5ea0 (patch)
tree05816010e6607a5495c25010e4bca6836d960281 /src
parent5d65772762072aa950a488c666673dc248b01d6d (diff)
downloadscala-3ef487ecb6733bfe3c13d89780ebcfc81f9a5ea0.tar.gz
scala-3ef487ecb6733bfe3c13d89780ebcfc81f9a5ea0.tar.bz2
scala-3ef487ecb6733bfe3c13d89780ebcfc81f9a5ea0.zip
SI-5954 Implementation restriction preventing companions in package objs
Companion objects (and thus also case classes) in package objects caused an assert about an overloaded symbol when everything was compiled twice. It's a hairy problem that doesn't fit in 2.10.1. So this fix adds an implementation restriction. It also has a test to make sure the error messages are clean and reasonably friendly, and does not catch other things defined in package objects. The test includes a commented out test in case somebody thinks they've solved the underlying problem. A handful of tests were falling afoul of the new implementation restriction. I verified that they do in fact fail on second compile so they aren't false casualties. But they do test real things we'd like to work once the re-compile issue is fixed. So I added a -X flag to disable the implementation restriction and made all the tests accidentally clobbered by the restriction use that flag.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala26
-rw-r--r--src/reflect/scala/reflect/internal/settings/MutableSettings.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/Settings.scala1
4 files changed, 30 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index cfc7f14210..517b91dca8 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -174,6 +174,7 @@ 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 386eec207a..e3fd83f388 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1891,7 +1891,33 @@ trait Typers extends Modes with Adaptations with Tags {
})
}
val impl2 = finishMethodSynthesis(impl1, clazz, context)
+
+ // 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
+ // 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) {
+ // 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")
+ // 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")
+ }
+
+ def pkgObjectRestriction(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}.")
+ }
+ }
+ if (!settings.companionsInPkgObjs.value && mdef.symbol.isPackageObject)
+ restrictPackageObjectMembers(mdef)
+
treeCopy.ModuleDef(mdef, typedMods, mdef.name, impl2) setType NoType
}
/** In order to override this in the TreeCheckers Typer so synthetics aren't re-added
diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
index 81368df7a6..ec3501d5bc 100644
--- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
+++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
@@ -47,4 +47,6 @@ 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 0e0cf3fc40..2d5b76f094 100644
--- a/src/reflect/scala/reflect/runtime/Settings.scala
+++ b/src/reflect/scala/reflect/runtime/Settings.scala
@@ -43,6 +43,7 @@ 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)