summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2011-01-20 09:43:18 +0000
committerAdriaan Moors <adriaan.moors@epfl.ch>2011-01-20 09:43:18 +0000
commitf0bff86d31c0ce9548e595c4b4b7fda8efe038c0 (patch)
treea01a425900de3bca3202bcfca1749099cb74a235 /src/library
parentf4f1738fe79193010c328371521ed554e7e8cf6d (diff)
downloadscala-f0bff86d31c0ce9548e595c4b4b7fda8efe038c0.tar.gz
scala-f0bff86d31c0ce9548e595c4b4b7fda8efe038c0.tar.bz2
scala-f0bff86d31c0ce9548e595c4b4b7fda8efe038c0.zip
introduce NullaryMethodType to disambiguate Pol...
introduce NullaryMethodType to disambiguate PolyType motivation: given `def foo[T]: (T, T)` and `type Foo[T] = (T, T)`, `foo.info` and `TypeRef(_, Foo, Nil).normalize` are both `PolyType(List(T), Pair[T, T])` uncurry has been relying on an ugly hack to distinguish these cases based on ad-hoc kind inference without this distinction, the type alias's info (a type function) would be transformed to `PolyType(List(T), MethodType(Nil, Pair[T, T]))` anonymous type functions are being used more often (see #2741, #4017, #4079, #3443, #3106), which makes a proper treatment of PolyTypes more pressing change to type representation: PolyType(Nil, tp) -> NullaryMethodType(tp) PolyType(tps, tp) -> PolyType(tps, NullaryMethodType(tp)) (if the polytype denoted a polymorphic nullary method) PolyType(Nil, tp) is now invalid the kind of a PolyType is * iff its resulttype is a NullaryMethodType or a MethodType (i.e., it's a polymorphic value) in all other cases a PolyType now denotes a type constructor NullaryMethodType is eliminated during uncurry pickling: for backwards compatibility, a NullaryMethodType(tp) is still pickled as a PolyType(Nil, tp), unpickling rewrites pre-2.9-pickled PolyTypes according to the expected kind of the unpickled type (similar to what we used to do in uncurry) a pickled PolyType(Nil, restpe) is unpickled to NullaryMethodType(restpe) a pickled PolyType(tps, restpe) is unpickled to PolyType(tps, NullaryMethodType(restpe)) when the type is expected to have kind * the rewrite probably isn't complete, but was validated by compiling against the old scalacheck jar (which has plenty of polymorphic nullary methods) nevertheless, this commit includes a new scalacheck jar summary of the refactoring: * PolyType(List(), tp) or PolyType(Nil, tp) or PolyType(parms, tp) if params.isEmpty ==> NullaryMethodType(tp) * whenever there was a case PolyType(tps, tp) (irrespective of tps isEmpty), now need to consider the case PolyType(tps, NullaryMethodType(tp)); just add a case NullaryMethodType(tp), since usually: - there already is a PolyType case that recurses on the result type, - the polytype case applied to empty and non-empty type parameter lists alike * tp.resultType, where tp was assumed to be a PolyType that represents a polymorphic nullary method type before, tp == PolyType(tps, res), now tp == PolyType(tps, NullaryMethodType(res)) * got bitten again (last time was dependent-method types refactoring) by a TypeMap not being the identity when dropNonConstraintAnnotations is true (despite having an identity apply method). Since asSeenFrom is skipped when isTrivial, the annotations aren't dropped. The cps plugin relies on asSeenFrom dropping these annotations for trivial types though. Therefore, NullaryMethodType pretends to never be trivial. Better fix(?) in AsSeenFromMap: `if(tp.isTrivial) dropNonContraintAnnotations(tp) else ...` TODO: scalap and eclipse review by odersky, rytz
Diffstat (limited to 'src/library')
-rw-r--r--src/library/scala/reflect/Print.scala2
-rw-r--r--src/library/scala/reflect/Type.scala3
-rwxr-xr-xsrc/library/scala/reflect/generic/Types.scala8
-rwxr-xr-xsrc/library/scala/reflect/generic/UnPickler.scala29
4 files changed, 36 insertions, 6 deletions
diff --git a/src/library/scala/reflect/Print.scala b/src/library/scala/reflect/Print.scala
index a84e024c36..1c51a8b2b1 100644
--- a/src/library/scala/reflect/Print.scala
+++ b/src/library/scala/reflect/Print.scala
@@ -101,6 +101,8 @@ object Print extends Function1[Any, String] {
"[" + Print(lo) + " ... " + Print(hi) + "]"
case reflect.MethodType(formals, resultType) =>
formals.map(Print).mkString("(", ", ", ")") + " => " + Print(resultType)
+ case reflect.NullaryMethodType(resultType) =>
+ " => " + Print(resultType)
case reflect.PolyType(typeParams, typeBounds, resultType) =>
val z = (typeParams, typeBounds).zipped map ((tp, tb) => "[" + Print(tb._1) + " :> " + Print(tp) + " :> " + Print(tb._2) + "]")
z.mkString("[", ", ", "]") + " -> " + Print(resultType)
diff --git a/src/library/scala/reflect/Type.scala b/src/library/scala/reflect/Type.scala
index 029bb3966e..0ec0b77fad 100644
--- a/src/library/scala/reflect/Type.scala
+++ b/src/library/scala/reflect/Type.scala
@@ -49,6 +49,8 @@ case class TypeBounds(lo: Type, hi: Type) extends Type
* <code>(formals1 ... formalsn) restpe</code> */
case class MethodType(formals: List[Symbol], restpe: Type) extends Type
+/** This type is required by the compiler and <b>should not be used in client code</b>. */
+case class NullaryMethodType(resultType: Type) extends Type
/** This type is required by the compiler and <b>should not be used in client code</b>. */
case class PolyType(typeParams: List[Symbol], typeBounds: List[(Type, Type)], resultType: Type) extends Type
@@ -71,5 +73,6 @@ extends MethodType(formals, restpe)
case reflect.AppliedType(tpe, args) =>
case reflect.TypeBounds(lo, hi) =>
case reflect.MethodType(formals, restpe) => //can also be ImplicitMethodType
+ case reflect.NullaryMethodType(restpe) =>
case reflect.PolyType(typeParams, typeBounds, resultType) =>
*/
diff --git a/src/library/scala/reflect/generic/Types.scala b/src/library/scala/reflect/generic/Types.scala
index 17e19715d7..6dcd90e66c 100755
--- a/src/library/scala/reflect/generic/Types.scala
+++ b/src/library/scala/reflect/generic/Types.scala
@@ -69,6 +69,9 @@ trait Types { self: Universe =>
type MethodType <: Type
val MethodType: MethodTypeExtractor
+ type NullaryMethodType <: Type
+ val NullaryMethodType: NullaryMethodTypeExtractor
+
type PolyType <: Type
val PolyType: PolyTypeExtractor
@@ -132,6 +135,11 @@ trait Types { self: Universe =>
def unapply(tpe: MethodType): Option[(List[Symbol], Type)]
}
+ abstract class NullaryMethodTypeExtractor {
+ def apply(resultType: Type): NullaryMethodType
+ def unapply(tpe: NullaryMethodType): Option[(Type)]
+ }
+
abstract class PolyTypeExtractor {
def apply(typeParams: List[Symbol], resultType: Type): PolyType
def unapply(tpe: PolyType): Option[(List[Symbol], Type)]
diff --git a/src/library/scala/reflect/generic/UnPickler.scala b/src/library/scala/reflect/generic/UnPickler.scala
index 7b7c34a767..86b73cf5fd 100755
--- a/src/library/scala/reflect/generic/UnPickler.scala
+++ b/src/library/scala/reflect/generic/UnPickler.scala
@@ -281,7 +281,7 @@ abstract class UnPickler {
sym
case MODULEsym =>
- val clazz = at(inforef, readType).typeSymbol
+ val clazz = at(inforef, () => readType()).typeSymbol // after the NMT_TRANSITION period, we can leave off the () => ... ()
if (isModuleRoot) moduleRoot
else {
val m = owner.newModule(name, clazz)
@@ -298,8 +298,13 @@ abstract class UnPickler {
})
}
- /** Read a type */
- protected def readType(): Type = {
+ /** Read a type
+ *
+ * @param forceProperType is used to ease the transition to NullaryMethodTypes (commentmarker: NMT_TRANSITION)
+ * the flag say that a type of kind * is expected, so that PolyType(tps, restpe) can be disambiguated to PolyType(tps, NullaryMethodType(restpe))
+ * (if restpe is not a ClassInfoType, a MethodType or a NullaryMethodType, which leaves TypeRef/SingletonType -- the latter would make the polytype a type constructor)
+ */
+ protected def readType(forceProperType: Boolean = false): Type = {
val tag = readByte()
val end = readNat() + readIndex
(tag: @switch) match {
@@ -341,7 +346,19 @@ abstract class UnPickler {
case POLYtpe =>
val restpe = readTypeRef()
val typeParams = until(end, readSymbolRef)
- PolyType(typeParams, restpe)
+ if(typeParams nonEmpty) {
+ // NMT_TRANSITION: old class files denoted a polymorphic nullary method as PolyType(tps, restpe), we now require PolyType(tps, NullaryMethodType(restpe))
+ // when a type of kind * is expected (forceProperType is true), we know restpe should be wrapped in a NullaryMethodType (if it wasn't suitably wrapped yet)
+ def transitionNMT(restpe: Type) = {
+ val resTpeCls = restpe.getClass.toString // what's uglier than isInstanceOf? right! -- isInstanceOf does not work since the concrete types are defined in the compiler (not in scope here)
+ if(forceProperType /*&& pickleformat < 2.9 */ && !(resTpeCls.endsWith("MethodType"))) { assert(!resTpeCls.contains("ClassInfoType"))
+ NullaryMethodType(restpe) }
+ else restpe
+ }
+ PolyType(typeParams, transitionNMT(restpe))
+ }
+ else
+ NullaryMethodType(restpe)
case EXISTENTIALtpe =>
val restpe = readTypeRef()
ExistentialType(until(end, readSymbolRef), restpe)
@@ -352,7 +369,7 @@ abstract class UnPickler {
typeRef = readNat()
s
} else NoSymbol // selfsym can go.
- val tp = at(typeRef, readType)
+ val tp = at(typeRef, () => readType(forceProperType)) // NMT_TRANSITION
val annots = until(end, readAnnotationRef)
if (selfsym == NoSymbol) AnnotatedType(annots, tp, selfsym)
else tp
@@ -739,7 +756,7 @@ abstract class UnPickler {
/* Read a reference to a pickled item */
protected def readNameRef(): Name = at(readNat(), readName)
protected def readSymbolRef(): Symbol = at(readNat(), readSymbol)
- protected def readTypeRef(): Type = at(readNat(), readType)
+ protected def readTypeRef(): Type = at(readNat(), () => readType()) // after the NMT_TRANSITION period, we can leave off the () => ... ()
protected def readConstantRef(): Constant = at(readNat(), readConstant)
protected def readAnnotationRef(): AnnotationInfo = at(readNat(), readAnnotation)
protected def readModifiersRef(): Modifiers = at(readNat(), readModifiers)