1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
import scala.{specialized => sp}
// NOTE: `{ val c = caller; print(""); c }` is used instead of a simple `caller`,
// because we want to prevent tail-call optimization from eliding the stack-
// frames we want to inspect.
object Test {
def caller = new Exception().getStackTrace()(1).getMethodName
def f1[@sp(Int) A](a: A, b: Any) = { val c = caller; print(""); c }
def f2[@sp(Int) A, B](a: A, b: String) = { val c = caller; print(""); c }
def f3[B, @sp(Int) A](a: A, b: List[B]) = { val c = caller; print(""); c }
def f4[B, @sp(Int) A](a: A, b: List[(A, B)]) = { val c = caller; print(""); c }
def f5[@sp(Int) A, B <: Object](a: A, b: B) = { val c = caller; print(""); c }
// `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) = { val c = caller; print(""); c }
def todo2[@sp(Int) A, B <: AnyRef](a: A, b: String) = { val c = caller; print(""); c }
def todo3[B <: List[A], @specialized(Int) A](a: A, b: B) = { val c = caller; print(""); c }
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)
}
}
|