diff options
author | James Iry <jamesiry@gmail.com> | 2013-02-07 21:32:54 -0800 |
---|---|---|
committer | James Iry <jamesiry@gmail.com> | 2013-02-07 21:32:54 -0800 |
commit | 20b92e050365b8086a2ff368ef3e31f3a56c872c (patch) | |
tree | 710eb2dd92035a9a7349ae4165e3f37428d68a96 | |
parent | bbac0c06020db47dc46e3df7eb083b4f9f70a260 (diff) | |
parent | a0ee6e996e602bf5729687d7301f60b340d57061 (diff) | |
download | scala-20b92e050365b8086a2ff368ef3e31f3a56c872c.tar.gz scala-20b92e050365b8086a2ff368ef3e31f3a56c872c.tar.bz2 scala-20b92e050365b8086a2ff368ef3e31f3a56c872c.zip |
Merge pull request #1995 from retronym/ticket/5082
SI-5082 Cycle avoidance between case companions
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Unapplies.scala | 33 | ||||
-rw-r--r-- | test/files/pos/t5082.scala | 14 |
3 files changed, 47 insertions, 6 deletions
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 69074e4c0c..b51dc0ccd5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -94,12 +94,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: _*) } } @@ -158,7 +179,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 +} |