summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@epfl.ch>2010-09-01 14:29:41 +0000
committerLukas Rytz <lukas.rytz@epfl.ch>2010-09-01 14:29:41 +0000
commit05676863c18d70e3b5c979ebe2f04000305e41cd (patch)
tree161a64bcf080632fd8e0e7261a3d94118f297f76
parent1c4a348aa34ec08d4a75dad3536b656d4c93994e (diff)
downloadscala-05676863c18d70e3b5c979ebe2f04000305e41cd.tar.gz
scala-05676863c18d70e3b5c979ebe2f04000305e41cd.tar.bz2
scala-05676863c18d70e3b5c979ebe2f04000305e41cd.zip
Merged revisions 22466,22851 via svnmerge from
https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk ........ r22466 | extempore | 2010-07-02 03:01:44 +0200 (Fri, 02 Jul 2010) | 2 lines Fail more gracefully on > 22 case class parameters. Closes #3631, no review. ........ r22851 | rytz | 2010-08-27 10:54:49 +0200 (Fri, 27 Aug 2010) | 10 lines partial fix for see #3772. remaining problem is when the explicit companion object is specified after the class: {{{ scala> def g { case class C(); object C; } <console>:5: error: C is already defined as (compiler-generated) case class companion object C def g { case class C(); object C; } ^ }}} review by odersky ........
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala36
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala19
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala7
-rw-r--r--test/files/neg/bug3631.check4
-rw-r--r--test/files/neg/bug3631.scala3
-rw-r--r--test/files/pos/caseClassInMethod.scala5
8 files changed, 58 insertions, 28 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index f349786712..394e9709a1 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -156,6 +156,12 @@ abstract class TreeInfo {
case _ :: stats1 => firstConstructor(stats1)
}
+ /** The arguments to the first constructor in `stats'. */
+ def firstConstructorArgs(stats: List[Tree]): List[Tree] = firstConstructor(stats) match {
+ case DefDef(_, _, _, args :: _, _, _) => args
+ case _ => Nil
+ }
+
/** The value definitions marked PRESUPER in this statement sequence */
def preSuperFields(stats: List[Tree]): List[ValDef] =
for (vdef @ ValDef(mods, _, _, _) <- stats if mods hasFlag PRESUPER) yield vdef
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 3157e5cc20..896e9aa658 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -1255,6 +1255,8 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
/** The class with the same name in the same package as this module or
* case class factory.
+ * Note: does not work for classes owned by methods, see
+ * Namers.companionClassOf
*/
final def companionClass: Symbol = {
if (this != NoSymbol)
@@ -1271,6 +1273,8 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
/** The module or case class factory with the same name in the same
* package as this class.
+ * Note: does not work for modules owned by methods, see
+ * Namers.companionModuleOf
*/
final def companionModule: Symbol =
if (this.isClass && !this.isAnonymousClass && !this.isRefinementClass)
@@ -1279,6 +1283,8 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
/** For a module its linked class, for a class its linked module or case
* factory otherwise.
+ * Note: does not work for modules owned by methods, see
+ * Namers.companionModuleOf / Namers.companionClassOf
*/
final def companionSymbol: Symbol =
if (isTerm) companionClass
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 6406ae2cb9..c0948a0752 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -287,13 +287,13 @@ trait Namers { self: Analyzer =>
* class definition tree.
* @return the companion object symbol.
*/
- def ensureCompanionObject(tree: ClassDef, creator: => Tree): Symbol = {
- val m: Symbol = context.scope.lookup(tree.name.toTermName).filter(! _.isSourceMethod)
- if (m.isModule && inCurrentScope(m) && currentRun.compiles(m)) m
- else
- /*util.trace("enter synthetic companion object for "+currentRun.compiles(m)+":")*/(
- enterSyntheticSym(creator))
- }
+ def ensureCompanionObject(tree: ClassDef, creator: => Tree): Symbol = {
+ val m = companionModuleOf(tree.symbol, context)
+ // @luc: not sure why "currentRun.compiles(m)" is needed, things breaks
+ // otherwise. documentation welcome.
+ if (m != NoSymbol && currentRun.compiles(m)) m
+ else enterSyntheticSym(creator)
+ }
private def enterSymFinishWith(tree: Tree, tparams: List[TypeDef]) {
val sym = tree.symbol
@@ -350,6 +350,9 @@ trait Namers { self: Analyzer =>
tree.symbol = enterClassSymbol(tree)
finishWith(tparams)
if (mods.isCase) {
+ if (treeInfo.firstConstructorArgs(impl.body).size > MaxFunctionArity)
+ context.error(tree.pos, "Implementation restriction: case classes cannot have more than " + MaxFunctionArity + " parameters.")
+
val m = ensureCompanionObject(tree, caseModuleDef(tree))
caseClassOfModuleClass(m.moduleClass) = tree
}
@@ -1368,6 +1371,25 @@ trait Namers { self: Analyzer =>
} else member.accessed
} else member
+ /**
+ * Finds the companion module of a class symbol. Calling .companionModule
+ * does not work for classes defined inside methods.
+ */
+ def companionModuleOf(clazz: Symbol, context: Context) = {
+ var res = clazz.companionModule
+ if (res == NoSymbol)
+ res = context.lookup(clazz.name.toTermName, clazz.owner).suchThat(sym =>
+ sym.hasFlag(MODULE) && sym.isCoDefinedWith(clazz))
+ res
+ }
+
+ def companionClassOf(module: Symbol, context: Context) = {
+ var res = module.companionClass
+ if (res == NoSymbol)
+ res = context.lookup(module.name.toTypeName, module.owner).suchThat(_.isCoDefinedWith(module))
+ res
+ }
+
/** An explanatory note to be added to error messages
* when there's a problem with abstract var defs */
def varNotice(sym: Symbol): String =
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 2cfbc928a9..fdad0f7bfb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -501,23 +501,4 @@ trait NamesDefaults { self: Analyzer =>
}
(namelessArgs, argPos)
}
-
- /**
- * Finds the companion module of a class symbol. Calling .companionModule
- * does not work for classes defined inside methods.
- */
- def companionModuleOf(clazz: Symbol, context: Context) = {
- var res = clazz.companionModule
- if (res == NoSymbol)
- res = context.lookup(clazz.name.toTermName, clazz.owner).suchThat(sym =>
- sym.hasFlag(MODULE) && sym.isCoDefinedWith(clazz))
- res
- }
-
- def companionClassOf(module: Symbol, context: Context) = {
- var res = module.companionClass
- if (res == NoSymbol)
- res = context.lookup(module.name.toTypeName, module.owner).suchThat(_.isCoDefinedWith(module))
- res
- }
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index bcbdb3d15d..9b78243910 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -133,8 +133,11 @@ trait Unapplies extends ast.TreeDSL
/** The module corresponding to a case class; without any member definitions
*/
def caseModuleDef(cdef: ClassDef): ModuleDef = {
- def inheritFromFun = !(cdef.mods hasFlag ABSTRACT) && cdef.tparams.isEmpty && constrParamss(cdef).length == 1
- def createFun = gen.scalaFunctionConstr(constrParamss(cdef).head map (_.tpt), toIdent(cdef), abstractFun = true)
+ // > MaxFunctionArity is caught in Namers, but for nice error reporting instead of
+ // an abrupt crash we trim the list here.
+ def primaries = constrParamss(cdef).head take MaxFunctionArity map (_.tpt)
+ def inheritFromFun = !cdef.mods.isAbstract && cdef.tparams.isEmpty && constrParamss(cdef).length == 1
+ def createFun = gen.scalaFunctionConstr(primaries, toIdent(cdef), abstractFun = true)
def parents = if (inheritFromFun) List(createFun) else Nil
companionModuleDef(cdef, parents)
diff --git a/test/files/neg/bug3631.check b/test/files/neg/bug3631.check
new file mode 100644
index 0000000000..12d94aa4dc
--- /dev/null
+++ b/test/files/neg/bug3631.check
@@ -0,0 +1,4 @@
+bug3631.scala:3: error: Implementation restriction: case classes cannot have more than 22 parameters.
+case class X23(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int) { }
+ ^
+one error found
diff --git a/test/files/neg/bug3631.scala b/test/files/neg/bug3631.scala
new file mode 100644
index 0000000000..bcf91619ee
--- /dev/null
+++ b/test/files/neg/bug3631.scala
@@ -0,0 +1,3 @@
+case class X22(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int) { }
+
+case class X23(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int) { } \ No newline at end of file
diff --git a/test/files/pos/caseClassInMethod.scala b/test/files/pos/caseClassInMethod.scala
new file mode 100644
index 0000000000..958e5dd473
--- /dev/null
+++ b/test/files/pos/caseClassInMethod.scala
@@ -0,0 +1,5 @@
+object t {
+ def f = { object C; case class C(); 1 }
+ // pending: def g = { case class D(x: Int); object D; 2 }
+ def h = { case class E(y: Int = 10); 3 }
+}