summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala24
-rw-r--r--test/files/run/t6308.check16
-rw-r--r--test/files/run/t6308.scala41
3 files changed, 77 insertions, 4 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index cc4b2d544b..f43e42c027 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -1388,10 +1388,26 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
/* The specialized symbol of 'tree.symbol' for tree.tpe, if there is one */
def specSym(qual: Tree): Symbol = {
val env = unify(symbol.tpe, tree.tpe, emptyEnv, false)
- def isMatch(member: Symbol) = (
- doesConform(symbol, tree.tpe, qual.tpe memberType member, env)
- && TypeEnv.includes(typeEnv(member), env)
- )
+ def isMatch(member: Symbol) = {
+ val memberType = qual.tpe memberType member
+
+ val residualTreeType = tree match {
+ case TypeApply(fun, targs) if fun.symbol == symbol =>
+ // SI-6308 Handle methods with only some type parameters specialized.
+ // drop the specialized type parameters from the PolyType, and
+ // substitute in the type environment.
+ val GenPolyType(tparams, tpe) = fun.tpe
+ val (from, to) = env.toList.unzip
+ val residualTParams = tparams.filterNot(env.contains)
+ GenPolyType(residualTParams, tpe).substituteTypes(from, to)
+ case _ => tree.tpe
+ }
+
+ (
+ doesConform(symbol, residualTreeType, memberType, env)
+ && TypeEnv.includes(typeEnv(member), env)
+ )
+ }
if (env.isEmpty) NoSymbol
else qual.tpe member specializedName(symbol, env) suchThat isMatch
}
diff --git a/test/files/run/t6308.check b/test/files/run/t6308.check
new file mode 100644
index 0000000000..e2577db72a
--- /dev/null
+++ b/test/files/run/t6308.check
@@ -0,0 +1,16 @@
+- Unspecialized type args
+// Specialized
+f1 f1$mIc$sp
+f2 f2$mIc$sp
+f3 f3$mIc$sp
+f4 f4$mIc$sp
+f5 f5$mIc$sp
+
+// Unspecialized type args
+f4(Boolean) f4
+f4(String) f4
+
+// Ideally these would be specialized
+todo1 todo1
+todo2 todo2
+todo3 todo3
diff --git a/test/files/run/t6308.scala b/test/files/run/t6308.scala
new file mode 100644
index 0000000000..bcd89359b0
--- /dev/null
+++ b/test/files/run/t6308.scala
@@ -0,0 +1,41 @@
+import scala.{specialized => sp}
+
+object Test {
+ def caller = new Exception().getStackTrace()(1).getMethodName
+ def f1[@sp(Int) A](a: A, b: Any) = caller
+ def f2[@sp(Int) A, B](a: A, b: String) = caller
+ def f3[B, @sp(Int) A](a: A, b: List[B]) = caller
+ def f4[B, @sp(Int) A](a: A, b: List[(A, B)]) = caller
+
+ def f5[@sp(Int) A, B <: Object](a: A, b: B) = caller
+
+ // `uncurryTreeType` calls a TypeMap on the call to this method and we end up with new
+ // type parameter symbols, which are not found in `TypeEnv.includes(typeEnv(member), env)`
+ // in `specSym`. (One of `uncurry`'s tasks is to expand type aliases in signatures.)
+ type T = Object
+ def todo1[@sp(Int) A, B <: T](a: A, b: String) = caller
+ def todo2[@sp(Int) A, B <: AnyRef](a: A, b: String) = caller
+ def todo3[B <: List[A], @specialized(Int) A](a: A, b: B) = caller
+
+ def main(args: Array[String]) {
+ val s = ""
+ val result =
+ s"""|- Unspecialized type args
+ |// Specialized
+ |f1 ${f1(1,"some ref")}
+ |f2 ${f2(1,"some ref")}
+ |f3 ${f3(1,List("some ref"))}
+ |f4 ${f4(1,Nil)}
+ |f5 ${f5(1,s)}
+ |
+ |// Unspecialized type args
+ |f4(Boolean) ${f4(Boolean,Nil)}
+ |f4(String) ${f4("",Nil)}
+ |
+ |// Ideally these would be specialized
+ |todo1 ${todo1(1,s)}
+ |todo2 ${todo2(1,s)}
+ |todo3 ${todo3(1,List(0))}""".stripMargin
+ println(result)
+ }
+}