diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2014-09-30 15:02:25 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2014-11-05 08:30:54 +0100 |
commit | 3f77202a0167f30454b3cc059a675cc9230ff603 (patch) | |
tree | 19c2d4ed3284012fbf22fb66dc59da2a678d31dc | |
parent | 10c745ae976f8e488dcde66587d0741890112c13 (diff) | |
download | scala-3f77202a0167f30454b3cc059a675cc9230ff603.tar.gz scala-3f77202a0167f30454b3cc059a675cc9230ff603.tar.bz2 scala-3f77202a0167f30454b3cc059a675cc9230ff603.zip |
SI-6541 valid wildcard existentials for case-module-unapply
Instead of letting the compiler infer the return type of case module
unapply methods, provide them explicitly.
This is enabled only under -Xsource:2.12, because the change is not
source compatible.
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Unapplies.scala | 25 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/StdNames.scala | 1 | ||||
-rw-r--r-- | test/files/run/t6541-option.scala | 19 | ||||
-rw-r--r-- | test/files/run/t6541.flags | 1 | ||||
-rw-r--r-- | test/files/run/t6541.scala | 25 |
5 files changed, 65 insertions, 6 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index cc2d9141ce..fc1f45e358 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -142,17 +142,30 @@ trait Unapplies extends ast.TreeDSL { /** The unapply method corresponding to a case class */ def caseModuleUnapplyMeth(cdef: ClassDef): DefDef = { - val tparams = constrTparamsInvariant(cdef) - val method = constrParamss(cdef) match { + val tparams = constrTparamsInvariant(cdef) + val method = constrParamss(cdef) match { case xs :: _ if xs.nonEmpty && isRepeatedParamType(xs.last.tpt) => nme.unapplySeq case _ => nme.unapply } - 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) }, ifNull)(Ident(unapplyParamName)) + val cparams = List(ValDef(Modifiers(PARAM | SYNTHETIC), unapplyParamName, classType(cdef, tparams), EmptyTree)) + val resultType = if (!settings.isScala212) TypeTree() else { // fix for SI-6541 under -Xsource:2.12 + def repeatedToSeq(tp: Tree) = tp match { + case AppliedTypeTree(Select(_, tpnme.REPEATED_PARAM_CLASS_NAME), tps) => AppliedTypeTree(gen.rootScalaDot(tpnme.Seq), tps) + case _ => tp + } + constrParamss(cdef) match { + case Nil | Nil :: _ => + gen.rootScalaDot(tpnme.Boolean) + case params :: _ => + val constrParamTypes = params.map(param => repeatedToSeq(param.tpt)) + AppliedTypeTree(gen.rootScalaDot(tpnme.Option), List(treeBuilder.makeTupleType(constrParamTypes))) + } + } + val ifNull = if (constrParamss(cdef).head.isEmpty) FALSE else REF(NoneModule) + val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef) }, ifNull)(Ident(unapplyParamName)) atPos(cdef.pos.focus)( - DefDef(caseMods, method, tparams, List(cparams), TypeTree(), body) + DefDef(caseMods, method, tparams, List(cparams), resultType, body) ) } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 99ff6a10b4..f2517fff54 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -128,6 +128,7 @@ trait StdNames { final val AnyRef: NameType = "AnyRef" final val Array: NameType = "Array" final val List: NameType = "List" + final val Option: NameType = "Option" final val Seq: NameType = "Seq" final val Symbol: NameType = "Symbol" final val WeakTypeTag: NameType = "WeakTypeTag" diff --git a/test/files/run/t6541-option.scala b/test/files/run/t6541-option.scala new file mode 100644 index 0000000000..2c10c9e09d --- /dev/null +++ b/test/files/run/t6541-option.scala @@ -0,0 +1,19 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ +:setting -Xsource:2.12 +case class C12(clazz: Class[_]) +val o: Option[Class[T] forSome { type T}] = C12.unapply(C12(classOf[String])) + +:setting -Xsource:2.11 +import scala.language.existentials +case class C11(clazz: Class[_]) +val o: Option[Class[T]] forSome { type T } = C11.unapply(C11(classOf[String])) + """ + + override def show() = { + val r = eval().mkString("\n") + assert(!(r.contains("warning") || r.contains("error")), r) + } +} diff --git a/test/files/run/t6541.flags b/test/files/run/t6541.flags new file mode 100644 index 0000000000..68d0ddfec2 --- /dev/null +++ b/test/files/run/t6541.flags @@ -0,0 +1 @@ +-feature -Xfatal-warnings -Xsource:2.12
\ No newline at end of file diff --git a/test/files/run/t6541.scala b/test/files/run/t6541.scala new file mode 100644 index 0000000000..f127143691 --- /dev/null +++ b/test/files/run/t6541.scala @@ -0,0 +1,25 @@ +class A +class B[T](x: T) +case class C(a: A, b: B[_]) + +case class D(a: A, b: B[_]*) + +case class E(c: Class[_]) + +object Test extends App { + def f1(c: C) = c match { + case C(a, b) => () + } + + def f2(d: D) = d match { + case D(a, b1, b2) => () + } + + def f3(e: E) = e match { + case E(c) => () + } + + f1(C(new A, new B(1))) + f2(D(new A, new B(1), new B(2))) + f3(E(classOf[E])) +} |