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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
import scala.tools.nsc._
import scala.tools.partest.CompilerTest
import scala.collection.{ mutable, immutable, generic }
/** It's too messy but it's better than not having it.
*/
object Test extends CompilerTest {
import global._
import definitions._
override def sources = List(lambdaLift)
def lambdaLift = """
package ll {
class A1
class A2
class X
class C[T1]() {
class I[T2]() {
def t1(): T1 = ???
def t2(): T2 = ???
def thisC(): C.this.type = ???
def thisI(): I.this.type = ???
}
}
class D[T3]() extends C[T3]() {
val cD: C[List[T3]] = ???
class J[T4]() extends cD.I[T4]()
}
object Z {
val dZ: D[A1] = ???
val jZ: dZ.J[A2] = ???
def kz[P <: dZ.J[A2]]: dZ.J[P] = ???
}
}
"""
object syms extends SymsInPackage("ll") {
def isPossibleEnclosure(encl: Symbol, sym: Symbol) = sym.enclClassChain drop 1 exists (_ isSubClass encl)
def isInterestingPrefix(pre: Type) = pre.typeConstructor.typeParams.nonEmpty && pre.members.exists(_.isType)
def asSeenPrefixes = tpes map (_.finalResultType) distinct
def typeRefPrefixes = asSeenPrefixes filter isInterestingPrefix
def nestsIn(outer: Symbol) = classes filter (c => c.enclClassChain drop 1 exists(_ isSubClass outer))
def typeRefs(targs: List[Type]) = (
for (p <- typeRefPrefixes ; c <- classes filter (isPossibleEnclosure(p.typeSymbol, _)) ; a <- targs) yield
typeRef(p, c, List(a))
)
val wfmt = "%-" + 25 + "s"
def to_s(x: Any): String = wfmt.format(x.toString.replaceAll("""\bll\.""", ""))
def fmt(args: Any*): String = {
(args map to_s mkString " ").replaceAll("""\s+$""", "")
}
def fname(sym: Symbol) = {
val p = "" + sym.owner.name
val x = if (sym.owner.isPackageClass || sym.owner.isModuleClass || sym.owner.isTerm) "." else "#"
sym.kindString + " " + p + x + sym.name
}
def permuteAsSeenFrom(targs: List[Type]) = (
for {
tp <- typeRefs(targs filterNot (_ eq NoType))
prefix <- asSeenPrefixes
if tp.prefix != prefix
site <- classes
seen = tp.asSeenFrom(prefix, site)
if tp != seen
if !seen.isInstanceOf[ExistentialType]
}
yield ((site, tp, prefix, seen))
)
def block(label: Any)(lines: List[String]): List[String] = {
val first = "" + label + " {"
val last = "}"
first +: lines.map(" " + _) :+ last
}
def permute(targs: List[Type]): List[String] = {
permuteAsSeenFrom(targs).groupBy(_._1).toList.sortBy(_._1.toString) flatMap {
case (site, xs) =>
block(fmt(site)) {
fmt("type", "seen from prefix", "is") ::
fmt("----", "----------------", "--") :: {
xs.groupBy(_._2).toList.sortBy(_._1.toString) flatMap {
case (tp, ys) =>
(ys map { case (_, _, prefix, seen) => fmt(tp, prefix, seen) }).sorted.distinct
}
}
}
}
}
}
def pretty(xs: List[_]) = if (xs.isEmpty) "" else xs.mkString("\n ", "\n ", "\n")
def signaturesIn(info: Type): List[String] = (
info.members
filterNot (s => s.isType || s.owner == ObjectClass || s.owner == AnyClass || s.isConstructor)
map (_.defString)
)
def check(source: String, unit: global.CompilationUnit) = {
import syms._
exitingTyper {
val typeArgs = List[Type](IntClass.tpe, ListClass[Int]) ++ tparams.map(_.tpe)
permute(typeArgs) foreach println
}
for (x <- classes ++ terms) {
afterEachPhase(signaturesIn(x.tpe)) collect {
case (ph, sigs) if sigs.nonEmpty =>
println(sigs.mkString(x + " { // after " + ph + "\n ", "\n ", "\n}\n"))
}
}
true
}
}
|