/*
* filter: inliner warning; re-run with -Yinline-warnings for details
*/
import scala.tools.nsc._
import scala.tools.partest.DirectTest
import scala.collection.{ mutable, immutable, generic }
import scala.language.{postfixOps, implicitConversions}
import scala.reflect.runtime.{universe => ru}
// necessary to avoid bincompat with scala-partest compiled against the old compiler
abstract class CompilerTest extends DirectTest {
def check(source: String, unit: global.CompilationUnit): Unit
lazy val global: Global = newCompiler()
lazy val units: List[global.CompilationUnit] = compilationUnits(global)(sources: _ *)
import global._
import definitions.{ compilerTypeFromTag }
override def extraSettings = "-feature -usejavacp -d " + testOutput.path
def show() = (sources, units).zipped foreach check
// Override at least one of these...
def code = ""
def sources: List[String] = List(code)
// Utility functions
class MkType(sym: Symbol) {
def apply[M](implicit t: ru.TypeTag[M]): Type =
if (sym eq NoSymbol) NoType
else appliedType(sym, compilerTypeFromTag(t))
}
implicit def mkMkType(sym: Symbol) = new MkType(sym)
def allMembers(root: Symbol): List[Symbol] = {
def loop(seen: Set[Symbol], roots: List[Symbol]): List[Symbol] = {
val latest = roots flatMap (_.info.members) filterNot (seen contains _)
if (latest.isEmpty) seen.toList.sortWith(_ isLess _)
else loop(seen ++ latest, latest)
}
loop(Set(), List(root))
}
class SymsInPackage(pkgName: String) {
def pkg = rootMirror.getPackage(TermName(pkgName))
def classes = allMembers(pkg) filter (_.isClass)
def modules = allMembers(pkg) filter (_.isModule)
def symbols = classes ++ terms filterNot (_ eq NoSymbol)
def terms = allMembers(pkg) filter (s => s.isTerm && !s.isConstructor)
def tparams = classes flatMap (_.info.typeParams)
def tpes = symbols map (_.tpe) distinct
}
}
/** 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.toList
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"))
}
}
}
}