summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-02-13 16:08:03 -0800
committerPaul Phillips <paulp@improving.org>2012-02-13 16:08:03 -0800
commit46408a6a44ed5f7592b5185589d5016e55c59cc2 (patch)
tree47092f0453ae87f7b2c346d52d6feaa8bdf996fa /src
parentadbe9ee345c620c59d34806032c9a00c8d04a634 (diff)
parent92fc4e351300e927ae1a8b0a6c383d00e3968c5d (diff)
downloadscala-46408a6a44ed5f7592b5185589d5016e55c59cc2.tar.gz
scala-46408a6a44ed5f7592b5185589d5016e55c59cc2.tar.bz2
scala-46408a6a44ed5f7592b5185589d5016e55c59cc2.zip
Merge branch 'master' into develop
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala28
-rw-r--r--src/compiler/scala/reflect/internal/SymbolTable.scala8
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala65
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala8
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala24
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala4
-rw-r--r--src/partest/scala/tools/partest/CompilerTest.scala27
-rw-r--r--src/partest/scala/tools/partest/DirectTest.scala32
8 files changed, 146 insertions, 50 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index e05ac1087b..5b2c61701d 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -586,14 +586,6 @@ trait Definitions extends reflect.api.StandardDefinitions {
case _ => NoType
}
- /** To avoid unchecked warnings on polymorphic classes, translate
- * a Foo[T] into a Foo[_] for use in the pattern matcher.
- */
- def typeCaseType(clazz: Symbol) = clazz.tpe.normalize match {
- case TypeRef(_, sym, args) if args.nonEmpty => newExistentialType(sym.typeParams, clazz.tpe)
- case tp => tp
- }
-
def seqType(arg: Type) = appliedType(SeqClass.typeConstructor, List(arg))
def arrayType(arg: Type) = appliedType(ArrayClass.typeConstructor, List(arg))
def byNameType(arg: Type) = appliedType(ByNameParamClass.typeConstructor, List(arg))
@@ -609,6 +601,26 @@ trait Definitions extends reflect.api.StandardDefinitions {
def vmClassType(arg: Type): Type = ClassType(arg)
def vmSignature(sym: Symbol, info: Type): String = signature(info) // !!!
+ /** Given a class symbol C with type parameters T1, T2, ... Tn
+ * which have upper/lower bounds LB1/UB1, LB1/UB2, ..., LBn/UBn,
+ * returns an existential type of the form
+ *
+ * C[E1, ..., En] forSome { E1 >: LB1 <: UB1 ... en >: LBn <: UBn }.
+ */
+ def classExistentialType(clazz: Symbol): Type =
+ newExistentialType(clazz.typeParams, clazz.tpe)
+
+ /** Given type U, creates a Type representing Class[_ <: U].
+ */
+ def boundedClassType(upperBound: Type) =
+ appliedTypeAsUpperBounds(ClassClass.typeConstructor, List(upperBound))
+
+ /** To avoid unchecked warnings on polymorphic classes, translate
+ * a Foo[T] into a Foo[_] for use in the pattern matcher.
+ */
+ @deprecated("Use classExistentialType", "2.10.0")
+ def typeCaseType(clazz: Symbol): Type = classExistentialType(clazz)
+
//
// .NET backend
//
diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala
index fb827b0658..1973a97279 100644
--- a/src/compiler/scala/reflect/internal/SymbolTable.scala
+++ b/src/compiler/scala/reflect/internal/SymbolTable.scala
@@ -120,9 +120,11 @@ abstract class SymbolTable extends api.Universe
try op
finally phase = current
}
-
- @inline final def afterPhase[T](ph: Phase)(op: => T): T =
- atPhase(ph.next)(op)
+ /** Since when it is to be "at" a phase is inherently ambiguous,
+ * a couple unambiguously named methods.
+ */
+ @inline final def beforePhase[T](ph: Phase)(op: => T): T = atPhase(ph)(op)
+ @inline final def afterPhase[T](ph: Phase)(op: => T): T = atPhase(ph.next)(op)
@inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T =
if (target != NoPhase && phase.id > target.id) atPhase(target)(op) else op
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index cd44b700c1..6295c089b2 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -2433,25 +2433,37 @@ trait Types extends api.Types { self: SymbolTable =>
case _ =>
List()
}
-
+ /** An existential can only be printed with wildcards if:
+ * - the underlying type is a typeref
+ * - where there is a 1-to-1 correspondence between underlying's typeargs and quantified
+ * - and none of the existential parameters is referenced from anywhere else in the type
+ * - and none of the existential parameters are singleton types
+ */
+ private def isRepresentableWithWildcards = !settings.debug.value && {
+ val qset = quantified.toSet
+ !qset.exists(_.isSingletonExistential) && (underlying match {
+ case TypeRef(_, sym, args) =>
+ sameLength(args, quantified) && {
+ args forall { arg =>
+ qset(arg.typeSymbol) && !qset.exists(arg.typeSymbol.info.bounds contains _)
+ }
+ }
+ case _ => false
+ })
+ }
override def safeToString: String = {
- if (!(quantified exists (_.isSingletonExistential)) && !settings.debug.value)
- // try to represent with wildcards first
- underlying match {
- case TypeRef(pre, sym, args) if args.nonEmpty =>
- val wargs = wildcardArgsString(quantified.toSet, args)
- if (sameLength(wargs, args))
- return TypeRef(pre, sym, List()) + wargs.mkString("[", ", ", "]")
- case _ =>
- }
- var ustr = underlying.toString
+ def clauses = {
+ val str = quantified map (_.existentialToString) mkString (" forSome { ", "; ", " }")
+ if (settings.explaintypes.value) "(" + str + ")" else str
+ }
underlying match {
- case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) => ustr = "("+ustr+")"
+ case TypeRef(pre, sym, args) if isRepresentableWithWildcards =>
+ "" + TypeRef(pre, sym, Nil) + wildcardArgsString(quantified.toSet, args).mkString("[", ", ", "]")
+ case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) =>
+ "(" + underlying + ")" + clauses
case _ =>
+ "" + underlying + clauses
}
- val str =
- ustr+(quantified map (_.existentialToString) mkString(" forSome { ", "; ", " }"))
- if (settings.explaintypes.value) "("+str+")" else str
}
override def cloneInfo(owner: Symbol) =
@@ -3260,6 +3272,25 @@ trait Types extends api.Types { self: SymbolTable =>
case WildcardType => tycon // needed for neg/t0226
case _ => abort(debugString(tycon))
}
+
+ /** A creator for existential types where the type arguments,
+ * rather than being applied directly, are interpreted as the
+ * upper bounds of unknown types. For instance if the type argument
+ * list given is List(AnyRefClass), the resulting type would be
+ * e.g. Set[_ <: AnyRef] rather than Set[AnyRef] .
+ */
+ def appliedTypeAsUpperBounds(tycon: Type, args: List[Type]): Type = {
+ tycon match {
+ case TypeRef(pre, sym, _) if sameLength(sym.typeParams, args) =>
+ val eparams = typeParamsToExistentials(sym)
+ val bounds = args map (TypeBounds upper _)
+ (eparams, bounds).zipped foreach (_ setInfo _)
+
+ newExistentialType(eparams, typeRef(pre, sym, eparams map (_.tpe)))
+ case _ =>
+ appliedType(tycon, args)
+ }
+ }
/** A creator for type parameterizations that strips empty type parameter lists.
* Use this factory method to indicate the type has kind * (it's a polymorphic value)
@@ -3845,6 +3876,8 @@ trait Types extends api.Types { self: SymbolTable =>
eparams map (_ substInfo (tparams, eparams))
}
+ def typeParamsToExistentials(clazz: Symbol): List[Symbol] =
+ typeParamsToExistentials(clazz, clazz.typeParams)
// note: it's important to write the two tests in this order,
// as only typeParams forces the classfile to be read. See #400
@@ -3876,7 +3909,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (expanded contains sym) AnyRefClass.tpe
else try {
expanded += sym
- val eparams = mapOver(typeParamsToExistentials(sym, sym.typeParams))
+ val eparams = mapOver(typeParamsToExistentials(sym))
existentialAbstraction(eparams, typeRef(apply(pre), sym, eparams map (_.tpe)))
} finally {
expanded -= sym
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 18735cafe2..4493188b31 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -807,6 +807,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
def currentRun: Run = curRun
def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit
def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile
+
+ @inline final def afterTyper[T](op: => T): T = afterPhase(currentRun.typerPhase)(op)
+ @inline final def beforeErasure[T](op: => T): T = beforePhase(currentRun.erasurePhase)(op)
+ @inline final def afterErasure[T](op: => T): T = afterPhase(currentRun.erasurePhase)(op)
/** Don't want to introduce new errors trying to report errors,
* so swallow exceptions.
@@ -1114,7 +1118,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
lazy val trackers = currentRun.units.toList map (x => SymbolTracker(x))
def snapshot() = {
inform("\n[[symbol layout at end of " + phase + "]]")
- atPhase(phase.next) {
+ afterPhase(phase) {
trackers foreach { t =>
t.snapshot()
inform(t.show("Heading from " + phase.prev.name + " to " + phase.name))
@@ -1389,7 +1393,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb
def printAllUnits() {
print("[[syntax trees at end of " + phase + "]]")
- atPhase(phase.next) { currentRun.units foreach (treePrinter.print(_)) }
+ afterPhase(phase) { currentRun.units foreach (treePrinter.print(_)) }
}
private def findMemberFromRoot(fullName: Name): Symbol = {
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index fe479a5375..5f84d765b9 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -44,22 +44,16 @@ abstract class Erasure extends AddInterfaces
// class object is that of java.lang.Integer, not Int.
//
// TODO: If T is final, return type could be Class[T]. Should it?
- def getClassReturnType(tp: Type): Type = {
- val sym = tp.typeSymbol
-
- if (phase.erasedTypes) ClassClass.tpe
- else if (isValueClass(sym)) ClassType(tp.widen)
- else {
- val eparams = typeParamsToExistentials(ClassClass, ClassClass.typeParams)
- val upperBound = (
- if (isPhantomClass(sym)) AnyClass.tpe
+ def getClassReturnType(tpe: Type): Type = {
+ if (phase.erasedTypes) ClassClass.tpe else {
+ val tp = tpe.widen.normalize
+ val sym = tp.typeSymbol
+
+ if (isValueClass(sym)) ClassType(tp)
+ else boundedClassType(
+ if (isPhantomClass(sym)) ObjectClass.tpe
else if (sym.isLocalClass) intersectionDominator(tp.parents)
- else tp.widen
- )
-
- existentialAbstraction(
- eparams,
- ClassType(eparams.head setInfo TypeBounds.upper(upperBound) tpe)
+ else tp
)
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 4ea21b1c44..cf90577959 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -116,7 +116,7 @@ trait SyntheticMethods extends ast.TreeDSL {
*/
def canEqualMethod: Tree = (
createMethod(nme.canEqual_, List(AnyClass.tpe), BooleanClass.tpe)(m =>
- Ident(m.firstParam) IS_OBJ typeCaseType(clazz))
+ Ident(m.firstParam) IS_OBJ classExistentialType(clazz))
)
/** The equality method for case classes.
@@ -132,7 +132,7 @@ trait SyntheticMethods extends ast.TreeDSL {
*/
def equalsClassMethod: Tree = createMethod(nme.equals_, List(AnyClass.tpe), BooleanClass.tpe) { m =>
val arg0 = Ident(m.firstParam)
- val thatTest = gen.mkIsInstanceOf(arg0, typeCaseType(clazz), true, false)
+ val thatTest = gen.mkIsInstanceOf(arg0, classExistentialType(clazz), true, false)
val thatCast = gen.mkCast(arg0, clazz.tpe)
def argsBody: Tree = {
diff --git a/src/partest/scala/tools/partest/CompilerTest.scala b/src/partest/scala/tools/partest/CompilerTest.scala
new file mode 100644
index 0000000000..dd06c051a4
--- /dev/null
+++ b/src/partest/scala/tools/partest/CompilerTest.scala
@@ -0,0 +1,27 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.partest
+
+import scala.tools.nsc._
+
+/** For testing compiler internals directly.
+ * Each source code string in "sources" will be compiled, and
+ * the check function will be called with the source code and the
+ * resulting CompilationUnit. The check implementation should
+ * test for what it wants to test and fail (via assert or other
+ * exception) if it is not happy.
+ */
+abstract class CompilerTest extends DirectTest {
+ def check(source: String, unit: global.CompilationUnit): Unit
+
+ lazy val global: Global = newCompiler()
+ lazy val units = compilationUnits(global)(sources: _ *)
+
+ override def extraSettings = "-usejavacp -d " + testOutput.path
+
+ def sources: List[String] = List(code)
+ def show() = (sources, units).zipped foreach check
+}
diff --git a/src/partest/scala/tools/partest/DirectTest.scala b/src/partest/scala/tools/partest/DirectTest.scala
index be8cac9147..74f511aa4e 100644
--- a/src/partest/scala/tools/partest/DirectTest.scala
+++ b/src/partest/scala/tools/partest/DirectTest.scala
@@ -35,13 +35,37 @@ abstract class DirectTest extends App {
s processArguments (allArgs, true)
s
}
- // compile the code, optionally first adding to the settings
- def compile(args: String*) = {
+ // new compiler
+ def newCompiler(args: String*): Global = {
val settings = newSettings((CommandLineParser tokenize extraSettings) ++ args.toList)
- val global = new Global(settings)
- new global.Run compileSources List(new BatchSourceFile("<partest>", code))
+ new Global(settings)
+ }
+ def newSources(sourceCodes: String*) = sourceCodes.toList.zipWithIndex map {
+ case (src, idx) => new BatchSourceFile("newSource" + (idx + 1), src)
+ }
+ def compileString(global: Global)(sourceCode: String): Boolean = {
+ withRun(global)(_ compileSources newSources(sourceCode))
!global.reporter.hasErrors
}
+ def compilationUnits(global: Global)(sourceCodes: String*): List[global.CompilationUnit] = {
+ val units = withRun(global) { run =>
+ run compileSources newSources(sourceCodes: _*)
+ run.units.toList
+ }
+ if (global.reporter.hasErrors) {
+ global.reporter.flush()
+ sys.error("Compilation failure.")
+ }
+ units
+ }
+
+ def withRun[T](global: Global)(f: global.Run => T): T = {
+ global.reporter.reset()
+ f(new global.Run)
+ }
+
+ // compile the code, optionally first adding to the settings
+ def compile(args: String*) = compileString(newCompiler(args: _*))(code)
/** Constructor/main body **/
try show()