diff options
author | Lukas Rytz <lukas.rytz@epfl.ch> | 2010-09-01 14:29:41 +0000 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@epfl.ch> | 2010-09-01 14:29:41 +0000 |
commit | 05676863c18d70e3b5c979ebe2f04000305e41cd (patch) | |
tree | 161a64bcf080632fd8e0e7261a3d94118f297f76 | |
parent | 1c4a348aa34ec08d4a75dad3536b656d4c93994e (diff) | |
download | scala-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.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Symbols.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 36 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala | 19 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Unapplies.scala | 7 | ||||
-rw-r--r-- | test/files/neg/bug3631.check | 4 | ||||
-rw-r--r-- | test/files/neg/bug3631.scala | 3 | ||||
-rw-r--r-- | test/files/pos/caseClassInMethod.scala | 5 |
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 } +} |