summaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala2
-rw-r--r--src/compiler/scala/tools/nsc/dependencies/Changes.scala2
-rw-r--r--src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala4
-rw-r--r--src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala10
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala6
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala14
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala5
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala181
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala8
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Reifiers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala33
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala43
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala20
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala14
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Variances.scala2
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala5
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala4
-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
36 files changed, 279 insertions, 174 deletions
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index e5bc1cf732..e36877837c 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -156,7 +156,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
else null
}
- import compiler.{ Traverser, CompilationUnit, Symbol, Name, TermName, TypeName, Type, TypeRef, PolyType }
+ import compiler.{ Traverser, CompilationUnit, Symbol, Name, TermName, TypeName, Type, TypeRef, NullaryMethodType }
import compiler.{
Tree, TermTree, ValOrDefDef, ValDef, DefDef, Assign, ClassDef,
ModuleDef, Ident, BackQuotedIdent, Select, TypeDef, Import, MemberDef, DocDef,
@@ -1008,7 +1008,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
def toType(name: Name): T = {
// the types are all =>T; remove the =>
val tp1 = afterTyper(resObjSym.info.nonPrivateDecl(name).tpe match {
- case PolyType(Nil, tp) => tp
+ case NullaryMethodType(tp) => tp
case tp => tp
})
// normalize non-public types so we don't see protected aliases like Self
diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
index 8fa27c04f6..969790eabc 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
@@ -652,6 +652,12 @@ abstract class TreeBrowsers {
toDocument(result) :: ")")
)
+ case NullaryMethodType(result) =>
+ Document.group(
+ Document.nest(4,"NullaryMethodType(" :/:
+ toDocument(result) :: ")")
+ )
+
case PolyType(tparams, result) =>
Document.group(
Document.nest(4,"PolyType(" :/:
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index c2623ca5cc..78c7c9e3f0 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -97,7 +97,7 @@ abstract class TreeInfo {
}
def mayBeVarGetter(sym: Symbol) = sym.info match {
- case PolyType(Nil, _) => sym.owner.isClass && !sym.isStable
+ case NullaryMethodType(_) => sym.owner.isClass && !sym.isStable
case mt @ MethodType(_, _) => mt.isImplicit && sym.owner.isClass && !sym.isStable
case _ => false
}
diff --git a/src/compiler/scala/tools/nsc/dependencies/Changes.scala b/src/compiler/scala/tools/nsc/dependencies/Changes.scala
index 9794d71db1..42ccb2de0b 100644
--- a/src/compiler/scala/tools/nsc/dependencies/Changes.scala
+++ b/src/compiler/scala/tools/nsc/dependencies/Changes.scala
@@ -116,6 +116,8 @@ abstract class Changes {
mt1.isImplicit == mt2.isImplicit
case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
sameTypeParams(tparams1, tparams2) && sameType(res1, res2)
+ case (NullaryMethodType(res1), NullaryMethodType(res2)) =>
+ sameType(res1, res2)
case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) =>
sameTypeParams(tparams1, tparams2)(false) && sameType(res1, res2)(false)
case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) =>
diff --git a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala
index e9cc191167..3e8c9cfea7 100644
--- a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala
@@ -234,6 +234,10 @@ trait DependencyAnalysis extends SubComponent with Files {
checkType(t.resultType)
updateReferences(t.typeSymbol.fullName)
+ case t: NullaryMethodType =>
+ checkType(t.resultType)
+ updateReferences(t.typeSymbol.fullName)
+
case t =>
updateReferences(t.typeSymbol.fullName)
}
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
index 449fdca7b9..fb6d20848f 100644
--- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
+++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala
@@ -132,6 +132,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
def resultTpe(tpe: Type): Type = tpe match { // similar to finalResultType, except that it leaves singleton types alone
case PolyType(_, res) => resultTpe(res)
case MethodType(_, res) => resultTpe(res)
+ case NullaryMethodType(res) => resultTpe(res)
case _ => tpe
}
makeType(resultTpe(sym.tpe), inTemplate, sym)
@@ -577,8 +578,12 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
if (!defs.isEmpty) {
nameBuffer append " {...}" // TODO: actually print the refinement
}
+ /* Eval-by-name types */
+ case NullaryMethodType(result) =>
+ nameBuffer append '⇒'
+ appendType0(result)
/* Polymorphic types */
- case PolyType(tparams, result) if tparams nonEmpty =>
+ case PolyType(tparams, result) => assert(tparams nonEmpty)
// throw new Error("Polymorphic type '" + tpe + "' cannot be printed as a type")
def typeParamsToString(tps: List[Symbol]): String = if(tps isEmpty) "" else
tps.map{tparam =>
@@ -586,9 +591,6 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory
}.mkString("[", ", ", "]")
nameBuffer append typeParamsToString(tparams)
appendType0(result)
- case PolyType(tparams, result) if (tparams.isEmpty) =>
- nameBuffer append '⇒'
- appendType0(result)
case tpen =>
nameBuffer append tpen.toString
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index 971146ea14..bb177a9946 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -66,9 +66,9 @@ class Completion(val repl: Interpreter) extends CompletionOutput {
trait CompilerCompletion {
def tp: Type
def effectiveTp = tp match {
- case MethodType(Nil, resType) => resType
- case PolyType(Nil, resType) => resType
- case _ => tp
+ case MethodType(Nil, resType) => resType
+ case NullaryMethodType(resType) => resType
+ case _ => tp
}
// for some reason any's members don't show up in subclasses, which
diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
index e0d678b961..e977e28922 100644
--- a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
@@ -77,7 +77,7 @@ trait CompletionOutput {
def methodString() =
method.keyString + " " + method.nameString + (method.info.normalize match {
- case PolyType(Nil, resType) => ": " + typeToString(resType) // nullary method
+ case NullaryMethodType(resType) => ": " + typeToString(resType)
case PolyType(tparams, resType) => tparamsString(tparams) + typeToString(resType)
case mt @ MethodType(_, _) => methodTypeToString(mt)
case x =>
diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala
index 2429f53aa1..24672cc411 100644
--- a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala
+++ b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala
@@ -107,6 +107,8 @@ trait AnnotationInfos extends reflect.generic.AnnotationInfos { self: SymbolTabl
this
}
+ lazy val isTrivial: Boolean = atp.isTrivial && !(args exists (_.exists(_.isInstanceOf[This]))) // see annotationArgRewriter
+
override def toString: String = atp +
(if (!args.isEmpty) args.mkString("(", ", ", ")") else "") +
(if (!assocs.isEmpty) (assocs map { case (x, y) => x+" = "+y } mkString ("(", ", ", ")")) else "")
diff --git a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
index 72dc5b9e91..5c0fe74967 100644
--- a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
+++ b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
@@ -149,6 +149,8 @@ trait BaseTypeSeqs {
max(maxDpth(lo), maxDpth(hi))
case MethodType(paramtypes, result) =>
maxDpth(result)
+ case NullaryMethodType(result) =>
+ maxDpth(result)
case PolyType(tparams, result) =>
max(maxDpth(result), maxDpth(tparams map (_.info)) + 1)
case ExistentialType(tparams, result) =>
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 340ab09c81..ecda252ec6 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -28,7 +28,7 @@ trait Definitions extends reflect.generic.StandardDefinitions {
lazy val RootPackage: Symbol = {
val rp = NoSymbol.newValue(NoPosition, nme.ROOTPKG)
.setFlag(FINAL | MODULE | PACKAGE | JAVA)
- .setInfo(PolyType(List(), RootClass.tpe))
+ .setInfo(NullaryMethodType(RootClass.tpe))
RootClass.sourceModule = rp
rp
}
@@ -227,7 +227,7 @@ trait Definitions extends reflect.generic.StandardDefinitions {
)
lazy val EqualsPatternClass = {
val clazz = newClass(ScalaPackageClass, tpnme.EQUALS_PATTERN_NAME, Nil)
- clazz setInfo PolyType(List(newTypeParam(clazz, 0)), ClassInfoType(anyparam, new Scope, clazz))
+ clazz setInfo polyType(List(newTypeParam(clazz, 0)), ClassInfoType(anyparam, new Scope, clazz))
}
// collections classes
@@ -587,7 +587,7 @@ trait Definitions extends reflect.generic.StandardDefinitions {
else*/ List(p)
println("creating " + name + " with parents " + parents) */
clazz.setInfo(
- PolyType(
+ polyType(
List(tparam),
ClassInfoType(List(AnyRefClass.tpe, p), new Scope, clazz)))
}
@@ -619,11 +619,11 @@ trait Definitions extends reflect.generic.StandardDefinitions {
private def newPolyMethodCon(owner: Symbol, name: TermName, tcon: Symbol => Symbol => Type): Symbol = {
val msym = newMethod(owner, name)
val tparam = newTypeParam(msym, 0)
- msym.setInfo(PolyType(List(tparam), tcon(tparam)(msym)))
+ msym.setInfo(polyType(List(tparam), tcon(tparam)(msym)))
}
private def newParameterlessMethod(owner: Symbol, name: TermName, restpe: Type) =
- newMethod(owner, name).setInfo(PolyType(List(),restpe))
+ newMethod(owner, name).setInfo(NullaryMethodType(restpe))
private def newTypeParam(owner: Symbol, index: Int): Symbol =
owner.newTypeParameter(NoPosition, newTypeName("T" + index)) setInfo TypeBounds.empty
@@ -889,9 +889,9 @@ trait Definitions extends reflect.generic.StandardDefinitions {
Any_## = newMethod(AnyClass, nme.HASHHASH, Nil, inttype) setFlag FINAL
Any_isInstanceOf = newPolyMethod(
- AnyClass, nme.isInstanceOf_, tparam => booltype) setFlag FINAL
+ AnyClass, nme.isInstanceOf_, tparam => NullaryMethodType(booltype)) setFlag FINAL
Any_asInstanceOf = newPolyMethod(
- AnyClass, nme.asInstanceOf_, tparam => tparam.typeConstructor) setFlag FINAL
+ AnyClass, nme.asInstanceOf_, tparam => NullaryMethodType(tparam.typeConstructor)) setFlag FINAL
// members of class java.lang.{ Object, String }
Object_## = newMethod(ObjectClass, nme.HASHHASH, Nil, inttype) setFlag FINAL
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index c269472aa3..12f044aafe 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -510,6 +510,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
case ConstantType(_) => true
case PolyType(_, ConstantType(_)) => true
case MethodType(_, ConstantType(_)) => true
+ case NullaryMethodType(ConstantType(_)) => true
case _ => false
})
@@ -1604,8 +1605,10 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
tp match {
case PolyType(tparams, res) =>
typeParamsString + infoString(res)
+ case NullaryMethodType(res) =>
+ infoString(res)
case MethodType(params, res) =>
- params.map(_.defString).mkString("(", ",", ")") + infoString(res)
+ params.map(_.defString).mkString("(", ",", ")") + infoString(res)
case _ =>
": " + tp
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index f302f5c6ea..cbecd073f6 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -50,14 +50,13 @@ import scala.annotation.tailrec
case MethodType(paramtypes, result) =>
// (paramtypes)result
// For instance def m(): T is represented as MethodType(List(), T)
+ case NullaryMethodType(result) => // eliminated by uncurry
+ // an eval-by-name type
+ // For instance def m: T is represented as NullaryMethodType(T)
case PolyType(tparams, result) =>
- // [tparams]result where result is a MethodType or ClassInfoType
- // or
- // []T for a eval-by-name type
- // For instance def m: T is represented as PolyType(List(), T)
+ // [tparams]result where result is a (Nullary)MethodType or ClassInfoType
// The remaining types are not used after phase `typer'.
-
case OverloadedType(pre, tparams, alts) =>
// all alternatives of an overloaded ident
case AntiPolyType(pre, targs) =>
@@ -365,7 +364,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
/** For a typeref, its arguments. The empty list for all other types */
def typeArgs: List[Type] = List()
- /** For a method or poly type, its direct result type,
+ /** For a (nullary) method or poly type, its direct result type,
* the type itself for all other types. */
def resultType: Type = this
@@ -379,11 +378,11 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
*/
def remove(clazz: Symbol): Type = this
- /** For a curried method or poly type its non-method result type,
+ /** For a curried/nullary method or poly type its non-method result type,
* the type itself for all other types */
def finalResultType: Type = this
- /** For a method or poly type, the number of its value parameter sections,
+ /** For a method type, the number of its value parameter sections,
* 0 for all other types */
def paramSectionCount: Int = 0
@@ -708,7 +707,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
* - Either both types are polytypes with the same number of
* type parameters and their result types match after renaming
* corresponding type parameters
- * - Or both types are method types with equivalent type parameter types
+ * - Or both types are (nullary) method types with equivalent type parameter types
* and matching result types
* - Or both types are equivalent
* - Or phase.erasedTypes is false and both types are neither method nor
@@ -1137,14 +1136,6 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
else sym.tpe
}
- // case class DeBruijnIndex(level: Int, paramId: Int) extends Type {
- // override def isTrivial = true
- // override def isStable = true
- // override def safeToString = "<param "+level+"."+paramId+">"
- // override def kind = "DeBruijnIndex"
- // // todo: this should be a subtype, which forwards to underlying
- // }
-
/** A class for singleton types of the form <prefix>.<sym.name>.type.
* Cannot be created directly; one should always use
* `singleType' for creation.
@@ -1416,7 +1407,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
*/
override def normalize = {
if (isHigherKinded) {
- PolyType(
+ typeFun(
typeParams,
RefinedType(
parents map {
@@ -1807,11 +1798,10 @@ A type's typeSymbol should never be inspected directly.
transform(sym.info.resultType)
}
- // @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function*
// @M: initialize (by sym.info call) needed (see test/files/pos/ticket0137.scala)
@inline private def etaExpand: Type = {
val tpars = sym.info.typeParams // must go through sym.info for typeParams to initialise symbol
- PolyType(tpars, typeRef(pre, sym, tpars map (_.tpeHK))) // todo: also beta-reduce?
+ typeFunAnon(tpars, typeRef(pre, sym, tpars map (_.tpeHK))) // todo: also beta-reduce?
}
override def dealias: Type =
@@ -1963,11 +1953,10 @@ A type's typeSymbol should never be inspected directly.
}
/** A class representing a method type with parameters.
- * Note that a parameterless method is instead encoded
- * as a PolyType, as shown here:
+ * Note that a parameterless method is represented by a NullaryMethodType:
*
* def m(): Int MethodType(Nil, Int)
- * def m: Int PolyType(Nil, Int)
+ * def m: Int NullaryMethodType(Int)
*/
case class MethodType(override val params: List[Symbol],
override val resultType: Type) extends Type {
@@ -1989,6 +1978,7 @@ A type's typeSymbol should never be inspected directly.
override def boundSyms = immutable.Set[Symbol](params ++ resultType.boundSyms: _*)
+ // AM to TR: #dropNonContraintAnnotations
// this is needed for plugins to work correctly, only TypeConstraint annotations are supposed to be carried over
// TODO: this should probably be handled in a more structured way in adapt -- remove this map in resultType and watch the continuations tests fail
object dropNonContraintAnnotations extends TypeMap {
@@ -2040,18 +2030,47 @@ A type's typeSymbol should never be inspected directly.
override def isJava = true
}
- /** A class representing a polymorphic type or, if typeParams.isEmpty, a parameterless method type.
+ case class NullaryMethodType(override val resultType: Type) extends Type {
+ // AM to TR: #dropNonContraintAnnotations
+ // change isTrivial to the commented version and watch continuations-run/t3225.scala fail
+ // isTrivial implies asSeenFrom is bypassed, since it's supposed to be the identity map
+ // it's not really the identity due to dropNonContraintAnnotations
+ override def isTrivial: Boolean = false //resultType.isTrivial -- `false` to make continuations plugin work (so that asSeenFromMap drops non-constrain annotations even when type doesn't change otherwise)
+ override def prefix: Type = resultType.prefix
+ override def narrow: Type = resultType.narrow
+ override def finalResultType: Type = resultType.finalResultType
+ override def termSymbol: Symbol = resultType.termSymbol
+ override def typeSymbol: Symbol = resultType.typeSymbol
+ override def parents: List[Type] = resultType.parents
+ override def decls: Scope = resultType.decls
+ override def baseTypeSeq: BaseTypeSeq = resultType.baseTypeSeq
+ override def baseTypeSeqDepth: Int = resultType.baseTypeSeqDepth
+ override def baseClasses: List[Symbol] = resultType.baseClasses
+ override def baseType(clazz: Symbol): Type = resultType.baseType(clazz)
+ override def boundSyms = resultType.boundSyms
+ override def isVolatile = resultType.isVolatile
+ override def safeToString: String = "=> "+ resultType
+ override def kind = "NullaryMethodType"
+ }
+
+ object NullaryMethodType extends NullaryMethodTypeExtractor
+
+ /** A type function or the type of a polymorphic value (and thus of kind *).
+ *
+ * Before the introduction of NullaryMethodType, a polymorphic nullary method (e.g, def isInstanceOf[T]: Boolean)
+ * used to be typed as PolyType(tps, restpe), and a monomorphic one as PolyType(Nil, restpe)
+ * This is now: PolyType(tps, NullaryMethodType(restpe)) and NullaryMethodType(restpe)
+ * by symmetry to MethodTypes: PolyType(tps, MethodType(params, restpe)) and MethodType(params, restpe)
+ *
+ * Thus, a PolyType(tps, TypeRef(...)) unambiguously indicates a type function (which results from eta-expanding a type constructor alias).
+ * Similarly, PolyType(tps, ClassInfoType(...)) is a type constructor.
*
- * (@M: note that polymorphic nullary methods have non-empty tparams,
- * e.g., isInstanceOf or def makeList[T] = new List[T].
- * Ideally, there would be a NullaryMethodType, but since the only polymorphic values are methods, it's not that problematic.
- * More pressingly, we should add a TypeFunction type for anonymous type constructors -- for now, PolyType is used in:
- * - normalize: for eta-expansion of type aliases
- * - typeDefSig )
+ * A polytype is of kind * iff its resultType is a (nullary) method type.
*/
case class PolyType(override val typeParams: List[Symbol], override val resultType: Type)
extends Type {
- // assert(!(typeParams contains NoSymbol), this)
+ //assert(!(typeParams contains NoSymbol), this)
+ assert(typeParams nonEmpty, this) // used to be a marker for nullary method type, illegal now (see @NullaryMethodType)
override def paramSectionCount: Int = resultType.paramSectionCount
override def paramss: List[List[Symbol]] = resultType.paramss
@@ -2071,19 +2090,18 @@ A type's typeSymbol should never be inspected directly.
override def isVolatile = resultType.isVolatile
override def finalResultType: Type = resultType.finalResultType
- /** @M: typeDefSig now wraps a TypeBounds in a PolyType
+ /** @M: typeDefSig wraps a TypeBounds in a PolyType
* to represent a higher-kinded type parameter
* wrap lo&hi in polytypes to bind variables
*/
override def bounds: TypeBounds =
- TypeBounds(PolyType(typeParams, resultType.bounds.lo),
- PolyType(typeParams, resultType.bounds.hi))
+ TypeBounds(typeFun(typeParams, resultType.bounds.lo),
+ typeFun(typeParams, resultType.bounds.hi))
override def isHigherKinded = !typeParams.isEmpty
override def safeToString: String =
- (if (typeParams.isEmpty) "=> "
- else (typeParams map (_.defString) mkString ("[", ",", "]")))+resultType
+ (typeParams map (_.defString) mkString ("[", ",", "]"))+ resultType
override def cloneInfo(owner: Symbol) = {
val tparams = cloneSymbols(typeParams, owner)
@@ -2167,7 +2185,7 @@ A type's typeSymbol should never be inspected directly.
}
var ustr = underlying.toString
underlying match {
- case MethodType(_, _) | PolyType(_, _) => ustr = "("+ustr+")"
+ case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) => ustr = "("+ustr+")"
case _ =>
}
val str =
@@ -2439,8 +2457,7 @@ A type's typeSymbol should never be inspected directly.
override def normalize: Type =
if (constr.instValid) constr.inst
else if (isHigherKinded) { // get here when checking higher-order subtyping of the typevar by itself (TODO: check whether this ever happens?)
- // @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function*
- PolyType(params, applyArgs(params map (_.typeConstructor)))
+ typeFun(params, applyArgs(params map (_.typeConstructor)))
} else {
super.normalize
}
@@ -2483,6 +2500,9 @@ A type's typeSymbol should never be inspected directly.
override protected def rewrap(tp: Type) = AnnotatedType(annotations, tp, selfsym)
+ override def isTrivial: Boolean = isTrivial0
+ private lazy val isTrivial0 = underlying.isTrivial && (annotations forall (_.isTrivial))
+
override def safeToString: String = {
val attString =
if (annotations.isEmpty)
@@ -2725,16 +2745,24 @@ A type's typeSymbol should never be inspected directly.
case _ => abort(debugString(tycon))
}
- /** A creator for type parameterizations
- * If tparams is empty, simply returns result type
+ /** 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)
+ * until we start tracking explicit kinds equivalent to typeFun (except that the latter requires tparams nonEmpty)
*/
def polyType(tparams: List[Symbol], tpe: Type): Type =
- if (tparams.isEmpty) tpe
- else
- PolyType(tparams, tpe match {
- case PolyType(List(), tpe1) => tpe1
- case _ => tpe
- })
+ if (tparams nonEmpty) typeFun(tparams, tpe)
+ else tpe // it's okay to be forgiving here
+
+ /** A creator for anonymous type functions, where the symbol for the type function still needs to be created
+ * TODO_NMT:
+ * - can we avoid this whole synthetic owner business? harden ASF instead to deal with orphan type params
+ * - orthogonally: try to recycle the class symbol in the common case type C[X] = Class[X] (where appliedType(this, dummyArgs) =:= appliedType(sym.info, dummyArgs))
+ */
+ def typeFunAnon(tps: List[Symbol], body: Type): Type = typeFun(tps, body)
+
+ /** A creator for a type functions, assuming the type parameters tps already have the right owner
+ */
+ def typeFun(tps: List[Symbol], body: Type): Type = PolyType(tps, body)
/** A creator for existential types. This generates:
*
@@ -3011,8 +3039,11 @@ A type's typeSymbol should never be inspected directly.
var result1 = this(result)
if ((tparams1 eq tparams) && (result1 eq result)) tp
else PolyType(tparams1, result1.substSym(tparams, tparams1))
+ case NullaryMethodType(result) =>
+ val result1 = this(result)
+ if (result1 eq result) tp
+ else NullaryMethodType(result1)
case ConstantType(_) => tp
- // case DeBruijnIndex(_, _) => tp
case SuperType(thistp, supertp) =>
val thistp1 = this(thistp)
val supertp1 = this(supertp)
@@ -3251,13 +3282,13 @@ A type's typeSymbol should never be inspected directly.
override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = {
object annotationArgRewriter extends TypeMapTransformer {
- /** Rewrite "this" trees as needed for asSeenFrom */
+ /** Rewrite `This` trees in annotation argument trees */
def rewriteThis(tree: Tree): Tree =
tree match {
case This(_)
if (tree.symbol isNonBottomSubClass clazz) &&
(pre.widen.typeSymbol isNonBottomSubClass tree.symbol) =>
- if (pre.isStable) {
+ if (pre.isStable) { // XXX why is this in this method? pull it out and guard the call `annotationArgRewriter.transform(tree)`?
val termSym =
pre.typeSymbol.owner.newValue(
pre.typeSymbol.pos,
@@ -3846,6 +3877,10 @@ A type's typeSymbol should never be inspected directly.
val restp1 = this(restp)
if (restp1 eq restp) tp
else copyMethodType(tp, params, restp1)
+ case NullaryMethodType(restp) =>
+ val restp1 = this(restp)
+ if (restp1 eq restp) tp
+ else NullaryMethodType(restp1)
case PolyType(tparams, restp) =>
val restp1 = this(restp)
if (restp1 eq restp) tp
@@ -4235,6 +4270,14 @@ A type's typeSymbol should never be inspected directly.
return isSameTypes(mt1.paramTypes, mt2.paramTypes) &&
mt1.resultType =:= mt2.resultType &&
mt1.isImplicit == mt2.isImplicit
+ // note: no case NullaryMethodType(restpe) => return mt1.params.isEmpty && mt1.resultType =:= restpe
+ case _ =>
+ }
+ case NullaryMethodType(restpe1) =>
+ tp2 match {
+ // note: no case mt2: MethodType => return mt2.params.isEmpty && restpe =:= mt2.resultType
+ case NullaryMethodType(restpe2) =>
+ return restpe1 =:= restpe2
case _ =>
}
case PolyType(tparams1, res1) =>
@@ -4584,13 +4627,14 @@ A type's typeSymbol should never be inspected directly.
matchingParams(params1, params2, mt1.isJava, mt2.isJava) &&
(res1 <:< res2) &&
mt1.isImplicit == mt2.isImplicit)
+ // TODO: if mt1.params.isEmpty, consider NullaryMethodType?
case _ =>
false
}
- case pt2 @ PolyType(List(), _) =>
+ case pt2 @ NullaryMethodType(_) =>
tp1 match {
- case pt1 @ PolyType(List(), _) =>
- // other polytypes were already checked in isHKSubType
+ // TODO: consider MethodType mt for which mt.params.isEmpty??
+ case pt1 @ NullaryMethodType(_) =>
pt1.resultType <:< pt2.resultType
case _ =>
false
@@ -4706,7 +4750,7 @@ A type's typeSymbol should never be inspected directly.
matchingParams(params1, params2, mt1.isJava, mt2.isJava) &&
matchesType(res1, res2, alwaysMatchSimple) &&
mt1.isImplicit == mt2.isImplicit
- case PolyType(List(), res2) =>
+ case NullaryMethodType(res2) =>
if (params1.isEmpty) matchesType(res1, res2, alwaysMatchSimple)
else matchesType(tp1, res2, alwaysMatchSimple)
case ExistentialType(_, res2) =>
@@ -4714,16 +4758,25 @@ A type's typeSymbol should never be inspected directly.
case _ =>
false
}
+ case mt1 @ NullaryMethodType(res1) =>
+ tp2 match {
+ case mt2 @ MethodType(Nil, res2) => // could never match if params nonEmpty, and !mt2.isImplicit is implied by empty param list
+ matchesType(res1, res2, alwaysMatchSimple)
+ case NullaryMethodType(res2) =>
+ matchesType(res1, res2, alwaysMatchSimple)
+ case ExistentialType(_, res2) =>
+ alwaysMatchSimple && matchesType(tp1, res2, true)
+ case _ =>
+ matchesType(res1, tp2, alwaysMatchSimple)
+ }
case PolyType(tparams1, res1) =>
tp2 match {
case PolyType(tparams2, res2) =>
matchesQuantified(tparams1, tparams2, res1, res2)
- case MethodType(List(), res2) if (tparams1.isEmpty) =>
- matchesType(res1, res2, alwaysMatchSimple)
case ExistentialType(_, res2) =>
alwaysMatchSimple && matchesType(tp1, res2, true)
case _ =>
- tparams1.isEmpty && matchesType(res1, tp2, alwaysMatchSimple)
+ false // remember that tparams1.nonEmpty is now an invariant of PolyType
}
case ExistentialType(tparams1, res1) =>
tp2 match {
@@ -4752,9 +4805,9 @@ A type's typeSymbol should never be inspected directly.
tp1.isImplicit == tp2.isImplicit
case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
matchesQuantified(tparams1, tparams2, res1, res2)
- case (PolyType(List(), rtp1), MethodType(List(), rtp2)) =>
+ case (NullaryMethodType(rtp1), MethodType(List(), rtp2)) =>
matchesType(rtp1, rtp2, alwaysMatchSimple)
- case (MethodType(List(), rtp1), PolyType(List(), rtp2)) =>
+ case (MethodType(List(), rtp1), NullaryMethodType(rtp2)) =>
matchesType(rtp1, rtp2, alwaysMatchSimple)
case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) =>
matchesQuantified(tparams1, tparams2, res1, res2)
@@ -4762,9 +4815,9 @@ A type's typeSymbol should never be inspected directly.
matchesType(res1, tp2, alwaysMatchSimple)
case (_, ExistentialType(_, res2)) if alwaysMatchSimple =>
matchesType(tp1, res2, alwaysMatchSimple)
- case (PolyType(List(), rtp1), _) =>
+ case (NullaryMethodType(rtp1), _) =>
matchesType(rtp1, tp2, alwaysMatchSimple)
- case (_, PolyType(List(), rtp2)) =>
+ case (_, NullaryMethodType(rtp2)) =>
matchesType(tp1, rtp2, alwaysMatchSimple)
case (MethodType(_, _), _) => false
case (PolyType(_, _), _) => false
@@ -5077,6 +5130,8 @@ A type's typeSymbol should never be inspected directly.
PolyType(tparams1, lub0(matchingInstTypes(ts, tparams1)))
case ts @ MethodType(params, _) :: rest =>
MethodType(params, lub0(matchingRestypes(ts, params map (_.tpe))))
+ case ts @ NullaryMethodType(_) :: rest =>
+ NullaryMethodType(lub0(matchingRestypes(ts, Nil)))
case ts @ TypeBounds(_, _) :: rest =>
TypeBounds(glb(ts map (_.bounds.lo), depth), lub(ts map (_.bounds.hi), depth))
case ts =>
@@ -5192,6 +5247,8 @@ A type's typeSymbol should never be inspected directly.
PolyType(tparams1, glb0(matchingInstTypes(ts, tparams1)))
case ts @ MethodType(params, _) :: rest =>
MethodType(params, glb0(matchingRestypes(ts, params map (_.tpe))))
+ case ts @ NullaryMethodType(_) :: rest =>
+ NullaryMethodType(glb0(matchingRestypes(ts, Nil)))
case ts @ TypeBounds(_, _) :: rest =>
TypeBounds(lub(ts map (_.bounds.lo), depth), glb(ts map (_.bounds.hi), depth))
case ts =>
@@ -5433,6 +5490,8 @@ A type's typeSymbol should never be inspected directly.
tps map {
case MethodType(params1, res) if (isSameTypes(params1 map (_.tpe), pts)) =>
res
+ case NullaryMethodType(res) if pts isEmpty =>
+ res
case _ =>
throw new NoCommonType(tps)
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 253ebb708d..20f990d057 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -1261,7 +1261,7 @@ abstract class ClassfileParser {
override def complete(sym: Symbol) {
alias.initialize
val tparams1 = cloneSymbols(alias.typeParams)
- sym.setInfo(polyType(tparams1, alias.tpe.substSym(alias.typeParams, tparams1)))
+ sym.setInfo(typeFun(tparams1, alias.tpe.substSym(alias.typeParams, tparams1)))
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 246bb6a88d..050b59118d 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -182,6 +182,8 @@ abstract class Pickler extends SubComponent {
putSymbol(clazz); putTypes(parents); putSymbols(decls.toList)
case MethodType(params, restpe) =>
putType(restpe); putSymbols(params)
+ case NullaryMethodType(restpe) =>
+ putType(restpe)
case PolyType(tparams, restpe) =>
/** no longer needed since all params are now local
tparams foreach { tparam =>
@@ -575,7 +577,11 @@ abstract class Pickler extends SubComponent {
writeRef(restpe); writeRefs(formals)
if (mt.isImplicit) IMPLICITMETHODtpe
else METHODtpe
- case PolyType(tparams, restpe) =>
+ case mt @ NullaryMethodType(restpe) => // reuse POLYtpe since those can never have an empty list of tparams -- TODO: is there any way this can come back and bite us in the bottom?
+ // ugliness and thrift aside, this should make this somewhat more backward compatible
+ // (I'm not sure how old scalac's would deal with nested PolyTypes, as these used to be folded into one)
+ writeRef(restpe); writeRefs(Nil); POLYtpe
+ case PolyType(tparams, restpe) => // invar: tparams nonEmpty
writeRef(restpe); writeRefs(tparams); POLYtpe
case ExistentialType(tparams, restpe) =>
writeRef(restpe); writeRefs(tparams); EXISTENTIALtpe
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
index afafce5abe..3427701899 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
@@ -50,7 +50,7 @@ abstract class UnPickler extends reflect.generic.UnPickler {
private val definedAtRunId = currentRunId
private val p = phase
override def complete(sym: Symbol) : Unit = {
- val tp = at(i, readType)
+ val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType`
if (p != phase) atPhase(p) (sym setInfo tp)
else sym setInfo tp
if (currentRunId != definedAtRunId) sym.setInfo(adaptToNewRunMap(tp))
diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
index 3f5fc6fdcb..80092af22e 100644
--- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala
@@ -309,8 +309,8 @@ abstract class TypeParser {
val flags = translateAttributes(getter);
val owner: Symbol = if (getter.IsStatic) statics else clazz;
val methodSym = owner.newMethod(NoPosition, name).setFlag(flags)
- val mtype: Type = if (gparamsLength == 0) PolyType(List(), propType) // .NET properties can't be polymorphic
- else methodType(getter, getter.ReturnType)(methodSym)
+ val mtype: Type = if (gparamsLength == 0) NullaryMethodType(propType) // .NET properties can't be polymorphic
+ else methodType(getter, getter.ReturnType)(methodSym)
methodSym.setInfo(mtype);
methodSym.setFlag(Flags.ACCESSOR);
(if (getter.IsStatic) staticDefs else instanceDefs).enter(methodSym)
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 998cf69f5e..46707fe445 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -402,7 +402,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
val deconstMap = new TypeMap {
def apply(tp: Type): Type = tp match {
case PolyType(_, _) => mapOver(tp)
- case MethodType(_, _) => mapOver(tp)
+ case MethodType(_, _) => mapOver(tp) // nullarymethod was eliminated during uncurry
case _ => tp.deconst
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/Reifiers.scala b/src/compiler/scala/tools/nsc/transform/Reifiers.scala
index 49ae43e1fe..e0ee4d3af8 100644
--- a/src/compiler/scala/tools/nsc/transform/Reifiers.scala
+++ b/src/compiler/scala/tools/nsc/transform/Reifiers.scala
@@ -79,6 +79,8 @@ trait Reifiers {
if (_log_reify_type_) println("cannot handle ClassInfoType "+tp); reflect.NoType
case MethodType(params, result) =>
reflect.MethodType(params.map(reify), reify(result))
+ case NullaryMethodType(result) =>
+ reflect.NullaryMethodType(reify(result))
case PolyType(tparams, result) =>
val boundss =
for {
@@ -146,6 +148,8 @@ trait Reifiers {
TypeBounds(unreify(lo), unreify(hi))
case reflect.MethodType(params, restpe) =>
MethodType(params.map(unreify), unreify(restpe))
+ case reflect.NullaryMethodType(restpe) =>
+ NullaryMethodType(unreify(restpe))
case reflect.PolyType(typeParams, typeBounds, resultType) =>
PolyType(typeParams.map(unreify), unreify(resultType))
//todo: treat ExistentialType
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 387f069875..d8c5370df6 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -327,6 +327,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case PolyType(tparams, resTpe) =>
specializedTypeVars(tparams map (_.info)) ++ specializedTypeVars(resTpe)
+ case NullaryMethodType(resTpe) => // since this method may be run at phase typer (before uncurry, where NMTs are eliminated)
+ specializedTypeVars(resTpe)
case MethodType(argSyms, resTpe) =>
specializedTypeVars(argSyms map (_.tpe)) ++ specializedTypeVars(resTpe)
@@ -889,7 +891,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
if (settings.debug.value) log("transformInfo (poly) " + clazz + " with parents1: " + parents + " ph: " + phase)
// if (clazz.name.toString == "$colon$colon")
// (new Throwable).printStackTrace
- PolyType(targs, ClassInfoType(parents,
+ polyType(targs, ClassInfoType(parents,
new Scope(specializeClass(clazz, typeEnv(clazz)) ::: specialOverrides(clazz)),
clazz))
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 1a6a36691d..3c8997657c 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -66,10 +66,8 @@ abstract class UnCurry extends InfoTransform with TypingTransformers with ast.Tr
tp0
case MethodType(h :: t, restpe) if h.isImplicit =>
apply(MethodType(h.cloneSymbol.resetFlag(IMPLICIT) :: t, restpe))
- case PolyType(List(), restpe) => // nullary method type
+ case NullaryMethodType(restpe) =>
apply(MethodType(List(), restpe))
- case PolyType(tparams, restpe) => // polymorphic nullary method type, since it didn't occur in a higher-kinded position
- PolyType(tparams, apply(MethodType(List(), restpe)))
case TypeRef(pre, ByNameParamClass, List(arg)) =>
apply(functionType(List(), arg))
case TypeRef(pre, RepeatedParamClass, args) =>
@@ -81,29 +79,6 @@ abstract class UnCurry extends InfoTransform with TypingTransformers with ast.Tr
expandAlias(mapOver(tp))
}
}
-
-//@M TODO: better fix for the gross hack that conflates polymorphic nullary method types with type functions
-// `[tpars] tref` (PolyType(tpars, tref)) could uncurry to either:
-// - `[tpars]() tref` (PolyType(tpars, MethodType(List(), tref))
-// a nullary method types uncurry to a method with an empty argument list
-// - `[tpars] tref` (PolyType(tpars, tref))
-// a proper type function -- see mapOverArgs: can only occur in args of TypeRef (right?))
-// the issue comes up when a partial type application gets normalised to a polytype, like `[A] Function1[X, A]`
-// should not apply the uncurry transform to such a type
-// see #2594 for an example
-
- // decide whether PolyType represents a nullary method type (only if type has kind *)
- // for higher-kinded types, leave PolyType intact
- override def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] =
- map2Conserve(args, tparams) { (arg, tparam) =>
- arg match {
- // is this a higher-kinded position? (TODO: confirm this is the only case)
- case PolyType(tparams, restpe) if tparam.typeParams.nonEmpty => // higher-kinded type param
- PolyType(tparams, apply(restpe)) // could not be a nullary method type
- case _ =>
- this(arg)
- }
- }
}
private val uncurryType = new TypeMap {
@@ -640,10 +615,10 @@ abstract class UnCurry extends InfoTransform with TypingTransformers with ast.Tr
def postTransform(tree: Tree): Tree = atPhase(phase.next) {
def applyUnary(): Tree = {
- def needsParens = tree.symbol.isMethod && (!tree.tpe.isInstanceOf[PolyType] || tree.tpe.typeParams.isEmpty)
+ def needsParens = tree.symbol.isMethod && !tree.tpe.isInstanceOf[PolyType] // TODO_NMT: verify that the inner tree of a type-apply also gets parens if the whole tree is a polymorphic nullary method application
def repair = {
- if (!tree.tpe.isInstanceOf[MethodType])
- tree.tpe = MethodType(Nil, tree.tpe)
+ if (!tree.tpe.isInstanceOf[MethodType]) // i.e., it's a NullaryMethodType
+ tree.tpe = MethodType(Nil, tree.tpe.resultType) // TODO_NMT: I think the original `tree.tpe` was wrong, since that would set the method's resulttype to PolyType(Nil, restp) instead of restp
atPos(tree.pos)(Apply(tree, Nil) setType tree.tpe.resultType)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
index c473df5333..34ba6f6da9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
@@ -232,7 +232,7 @@ abstract class DeVirtualize /* extends InfoTransform with TypingTransformers {
val param = clazz.newMethod(clazz.pos, paramFieldName(clazz, index))
.setFlag(PROTECTED | LOCAL | DEFERRED | EXPANDEDNAME | SYNTHETIC | STABLE)
atPhase(ownPhase.next) {
- param.setInfo(PolyType(List(), tpe))
+ param.setInfo(NullaryMethodType(tpe))
}
param
}
@@ -294,7 +294,7 @@ abstract class DeVirtualize /* extends InfoTransform with TypingTransformers {
factory setInfo new PolyTypeCompleter(factory, clazz) {
private def copyType(tpe: Type): Type = tpe match {
case MethodType(formals, restpe) => MethodType(formals, copyType(restpe))
- case PolyType(List(), restpe) => PolyType(List(), copyType(restpe))
+ case NullaryMethodType(restpe) => NullaryMethodType(copyType(restpe))
case PolyType(_, _) => abort("bad case: "+tpe)
case _ => owner.thisType.memberType(abstractType(clazz))
}
@@ -394,7 +394,7 @@ abstract class DeVirtualize /* extends InfoTransform with TypingTransformers {
case (pt, i) =>
val pfield = cclazz.newMethod(cclazz.pos, paramFieldName(clazz, i))
.setFlag(PROTECTED | LOCAL | EXPANDEDNAME | SYNTHETIC | STABLE)
- .setInfo(PolyType(List(), pt))
+ .setInfo(NullaryMethodType(pt))
cclazz.info.decls enter pfield
atPos(factory.pos) {
DefDef(pfield, Ident(fixParamName(i)))
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 6a708a873c..8ad6830e4c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -114,6 +114,8 @@ trait Implicits {
private def containsError(tp: Type): Boolean = tp match {
case PolyType(tparams, restpe) =>
containsError(restpe)
+ case NullaryMethodType(restpe) =>
+ containsError(restpe)
case MethodType(params, restpe) =>
params.exists(_.tpe.isError) || containsError(restpe)
case _ =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 84c770b553..15996923b2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -175,7 +175,7 @@ trait Infer {
normalize(restpe)
case mt @ MethodType(params, restpe) if !restpe.isDependent =>
functionType(params map (_.tpe), normalize(restpe))
- case PolyType(List(), restpe) => // nullary method type
+ case NullaryMethodType(restpe) =>
normalize(restpe)
case ExistentialType(tparams, qtpe) =>
ExistentialType(tparams, normalize(qtpe))
@@ -350,6 +350,7 @@ trait Infer {
case tr: TypeRef => mtcheck(mt, tr)
case _ => lastChanceCheck(tp, pt)
}
+ case NullaryMethodType(restpe) => apply(restpe, pt)
case PolyType(_, restpe) => apply(restpe, pt)
case ExistentialType(_, qtpe) => apply(qtpe, pt)
case _ => argumentCheck(tp, pt)
@@ -367,7 +368,6 @@ trait Infer {
def lastChanceCheck(tp: Type, pt: Type) = tp <:< pt
override def apply(tp: Type, pt: Type): Boolean = tp match {
- case PolyType(tparams, restpe) => tparams.isEmpty && normSubType(restpe, pt)
case ExistentialType(_, _) => normalize(tp) <:< pt
case _ => super.apply(tp, pt)
}
@@ -659,7 +659,7 @@ trait Infer {
}
private[typechecker] def followApply(tp: Type): Type = tp match {
- case PolyType(List(), restp) =>
+ case NullaryMethodType(restp) =>
val restp1 = followApply(restp)
if (restp1 eq restp) tp else restp1
case _ =>
@@ -816,6 +816,8 @@ trait Infer {
else tryTupleApply
}
+ case NullaryMethodType(restpe) => // strip nullary method type, which used to be done by the polytype case below
+ isApplicable(undetparams, restpe, argtpes0, pt)
case PolyType(tparams, restpe) =>
val tparams1 = cloneSymbols(tparams)
isApplicable(tparams1 ::: undetparams, restpe.substSym(tparams, tparams1), argtpes0, pt)
@@ -860,18 +862,24 @@ trait Infer {
case et: ExistentialType =>
isAsSpecific(ftpe1.skolemizeExistential, ftpe2)
//et.withTypeVars(isAsSpecific(_, ftpe2))
+ case NullaryMethodType(res) =>
+ isAsSpecific(res, ftpe2)
case mt: MethodType if mt.isImplicit =>
isAsSpecific(ftpe1.resultType, ftpe2)
- case MethodType(params @ (x :: xs), _) =>
+ case MethodType(params, _) if params nonEmpty =>
var argtpes = params map (_.tpe)
if (isVarArgsList(params) && isVarArgsList(ftpe2.params))
argtpes = argtpes map (argtpe =>
if (isRepeatedParamType(argtpe)) argtpe.typeArgs.head else argtpe)
isApplicable(List(), ftpe2, argtpes, WildcardType)
+ case PolyType(tparams, NullaryMethodType(res)) =>
+ isAsSpecific(PolyType(tparams, res), ftpe2)
case PolyType(tparams, mt: MethodType) if mt.isImplicit =>
isAsSpecific(PolyType(tparams, mt.resultType), ftpe2)
- case PolyType(_, MethodType(params @ (x :: xs), _)) =>
+ case PolyType(_, MethodType(params, _)) if params nonEmpty =>
isApplicable(List(), ftpe2, params map (_.tpe), WildcardType)
+ // case NullaryMethodType(res) =>
+ // isAsSpecific(res, ftpe2)
case ErrorType =>
true
case _ =>
@@ -882,12 +890,25 @@ trait Infer {
et.withTypeVars(isAsSpecific(ftpe1, _))
case mt: MethodType =>
!mt.isImplicit || isAsSpecific(ftpe1, mt.resultType)
+ case NullaryMethodType(res) =>
+ isAsSpecific(ftpe1, res)
+ case PolyType(tparams, NullaryMethodType(res)) =>
+ isAsSpecific(ftpe1, PolyType(tparams, res))
case PolyType(tparams, mt: MethodType) =>
!mt.isImplicit || isAsSpecific(ftpe1, PolyType(tparams, mt.resultType))
case _ =>
isAsSpecificValueType(ftpe1, ftpe2, List(), List())
}
}
+ private def isAsSpecificValueType(tpe1: Type, tpe2: Type, undef1: List[Symbol], undef2: List[Symbol]): Boolean = (tpe1, tpe2) match {
+ case (PolyType(tparams1, rtpe1), _) =>
+ isAsSpecificValueType(rtpe1, tpe2, undef1 ::: tparams1, undef2)
+ case (_, PolyType(tparams2, rtpe2)) =>
+ isAsSpecificValueType(tpe1, rtpe2, undef1, undef2 ::: tparams2)
+ case _ =>
+ existentialAbstraction(undef1, tpe1) <:< existentialAbstraction(undef2, tpe2)
+ }
+
/*
def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type): Boolean =
@@ -943,16 +964,6 @@ trait Infer {
case _ =>
false
}
-
- private def isAsSpecificValueType(tpe1: Type, tpe2: Type, undef1: List[Symbol], undef2: List[Symbol]): Boolean = (tpe1, tpe2) match {
- case (PolyType(tparams1, rtpe1), _) =>
- isAsSpecificValueType(rtpe1, tpe2, undef1 ::: tparams1, undef2)
- case (_, PolyType(tparams2, rtpe2)) =>
- isAsSpecificValueType(tpe1, rtpe2, undef1, undef2 ::: tparams2)
- case _ =>
- existentialAbstraction(undef1, tpe1) <:< existentialAbstraction(undef2, tpe2)
- }
-
/*
/** Is type `tpe1' a strictly better expression alternative than type `tpe2'?
*/
@@ -1120,7 +1131,7 @@ trait Infer {
if (targs eq null) {
if (!tree.tpe.isErroneous && !pt.isErroneous)
error(tree.pos, "polymorphic expression cannot be instantiated to expected type" +
- foundReqMsg(PolyType(undetparams, skipImplicit(tree.tpe)), pt))
+ foundReqMsg(polyType(undetparams, skipImplicit(tree.tpe)), pt))
} else {
new TreeTypeSubstituter(undetparams, targs).traverse(tree)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 775731df2b..9b27b35e82 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -578,7 +578,7 @@ trait Namers { self: Analyzer =>
def getterTypeCompleter(vd: ValDef) = mkTypeCompleter(vd) { sym =>
if (settings.debug.value) log("defining " + sym)
val tp = typeSig(vd)
- sym.setInfo(PolyType(List(), tp))
+ sym.setInfo(NullaryMethodType(tp))
if (settings.debug.value) log("defined " + sym)
validate(sym)
}
@@ -862,7 +862,7 @@ trait Namers { self: Analyzer =>
polyType(
tparamSyms, // deSkolemized symbols -- TODO: check that their infos don't refer to method args?
- if (vparamSymss.isEmpty) PolyType(List(), restpe) // nullary method type
+ if (vparamSymss.isEmpty) NullaryMethodType(restpe)
// vparamss refer (if they do) to skolemized tparams
else (vparamSymss :\ restpe) (makeMethodType))
}
@@ -907,7 +907,7 @@ trait Namers { self: Analyzer =>
resultPt = resultPt.resultType
}
resultPt match {
- case PolyType(List(), rtpe) => resultPt = rtpe
+ case NullaryMethodType(rtpe) => resultPt = rtpe
case MethodType(List(), rtpe) => resultPt = rtpe
case _ =>
}
@@ -1264,22 +1264,8 @@ trait Namers { self: Analyzer =>
}
result match {
case PolyType(tparams @ (tp :: _), _) if tp.owner.isTerm =>
- // ||
- // Adriaan: The added condition below is quite a hack. It seems that HK type parameters is relying
- // on a pass that forces all infos in the type to get everything right.
- // The problem is that the same pass causes cyclic reference errors in
- // test pos/cyclics.scala. It turned out that deSkolemize is run way more often than necessary,
- // running it only when needed fixes the cyclic reference errors.
- // But correcting deSkolemize broke HK types, because we don't do the traversal anymore.
- // For the moment I made a special hack to do the traversal if we have HK type parameters.
- // Maybe it's not a hack, then we need to document it better. But ideally, we should find
- // a way to deal with HK types that's not dependent on accidental side
- // effects like this.
- // tparams.exists(!_.typeParams.isEmpty)) =>
new DeSkolemizeMap(tparams) mapOver result
case _ =>
-// println("not skolemizing "+result+" in "+context.owner)
-// new DeSkolemizeMap(List()) mapOver result
result
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index adc7813b9c..df8ec9c762 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -66,7 +66,7 @@ abstract class RefChecks extends InfoTransform {
sym.setFlag(LAZY | ACCESSOR)
}
}
- PolyType(List(), tp)
+ NullaryMethodType(tp)
} else tp
}
@@ -244,12 +244,12 @@ abstract class RefChecks extends InfoTransform {
}
def overridesType(tp1: Type, tp2: Type): Boolean = (tp1.normalize, tp2.normalize) match {
- case (MethodType(List(), rtp1), PolyType(List(), rtp2)) =>
+ case (MethodType(List(), rtp1), NullaryMethodType(rtp2)) =>
rtp1 <:< rtp2
- case (PolyType(List(), rtp1), MethodType(List(), rtp2)) =>
+ case (NullaryMethodType(rtp1), MethodType(List(), rtp2)) =>
rtp1 <:< rtp2
case (TypeRef(_, sym, _), _) if (sym.isModuleClass) =>
- overridesType(PolyType(List(), tp1), tp2)
+ overridesType(NullaryMethodType(tp1), tp2)
case _ =>
tp1 <:< tp2
}
@@ -753,6 +753,8 @@ abstract class RefChecks extends InfoTransform {
validateVariance(hi, variance)
case MethodType(formals, result) =>
validateVariance(result, variance)
+ case NullaryMethodType(result) =>
+ validateVariance(result, variance)
case PolyType(tparams, result) =>
// type parameters will be validated separately, because they are defined explicitly.
validateVariance(result, variance)
@@ -1006,7 +1008,7 @@ abstract class RefChecks extends InfoTransform {
if (!sym.allOverriddenSymbols.isEmpty) {
val factory = sym.owner.newMethod(sym.pos, sym.name.toTermName)
.setFlag(sym.flags | STABLE).resetFlag(MODULE)
- .setInfo(PolyType(List(), sym.moduleClass.tpe))
+ .setInfo(NullaryMethodType(sym.moduleClass.tpe))
sym.owner.info.decls.enter(factory)
val ddef =
atPhase(phase.next) {
@@ -1043,7 +1045,7 @@ abstract class RefChecks extends InfoTransform {
sym.resetFlag(MODULE | FINAL | CASE)
sym.setFlag(LAZY | ACCESSOR | SYNTHETIC)
- sym.setInfo(PolyType(List(), sym.tpe))
+ sym.setInfo(NullaryMethodType(sym.tpe))
sym setFlag (lateMETHOD | STABLE)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 3e8f7bd2c7..6f3bb9e976 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -103,7 +103,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
var superAccTpe = clazz.thisType.memberType(sym)
if (sym.isModule && !sym.isMethod) {
// the super accessor always needs to be a method. See #231
- superAccTpe = PolyType(List(), superAccTpe)
+ superAccTpe = NullaryMethodType(superAccTpe)
}
superAcc.setInfo(superAccTpe.cloneInfo(superAcc))
//println("creating super acc "+superAcc+":"+superAcc.tpe)//DEBUG
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 2d544ba1d1..03b080398f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -86,12 +86,12 @@ trait SyntheticMethods extends ast.TreeDSL {
import CODE._
def productPrefixMethod: Tree = typer.typed {
- val method = syntheticMethod(nme.productPrefix, 0, sym => PolyType(Nil, StringClass.tpe))
+ val method = syntheticMethod(nme.productPrefix, 0, sym => NullaryMethodType(StringClass.tpe))
DEF(method) === LIT(clazz.name.decode)
}
def productArityMethod(nargs: Int): Tree = {
- val method = syntheticMethod(nme.productArity, 0, sym => PolyType(Nil, IntClass.tpe))
+ val method = syntheticMethod(nme.productArity, 0, sym => NullaryMethodType(IntClass.tpe))
typer typed { DEF(method) === LIT(nargs) }
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 3337584420..19fc981035 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -568,6 +568,7 @@ trait Typers extends Modes {
case ExistentialType(_, tpe1) => isNarrowable(tpe1)
case AnnotatedType(_, tpe1, _) => isNarrowable(tpe1)
case PolyType(_, tpe1) => isNarrowable(tpe1)
+ case NullaryMethodType(tpe1) => isNarrowable(tpe1)
case _ => !phase.erasedTypes
}
@@ -702,7 +703,7 @@ trait Typers extends Modes {
case OverloadedType(pre, alts) if !inFunMode(mode) => // (1)
inferExprAlternative(tree, pt)
adapt(tree, mode, pt, original)
- case PolyType(List(), restpe) => // (2)
+ case NullaryMethodType(restpe) => // (2)
adapt(tree setType restpe, mode, pt, original)
case TypeRef(_, ByNameParamClass, List(arg))
if ((mode & EXPRmode) != 0) => // (2)
@@ -1591,6 +1592,8 @@ trait Typers extends Modes {
if (meth.owner.isStructuralRefinement && meth.allOverriddenSymbols.isEmpty && !(meth.isPrivate || meth.hasAccessBoundary)) {
val tp: Type = meth.tpe match {
case mt: MethodType => mt
+ case NullaryMethodType(res) => res
+ // TODO_NMT: drop NullaryMethodType from resultType?
case pt: PolyType => pt.resultType
case _ => NoType
}
@@ -1624,7 +1627,7 @@ trait Typers extends Modes {
case tpt: Tree =>
val alias = enclClass.newAliasType(useCase.pos, name.toTypeName)
val tparams = cloneSymbols(tpt.tpe.typeSymbol.typeParams, alias)
- alias setInfo polyType(tparams, appliedType(tpt.tpe, tparams map (_.tpe)))
+ alias setInfo typeFun(tparams, appliedType(tpt.tpe, tparams map (_.tpe)))
context.scope.enter(alias)
case _ =>
}
@@ -2175,6 +2178,7 @@ trait Typers extends Modes {
}
def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Int, pt: Type): Tree = {
+ // TODO_NMT: check the assumption that args nonEmpty
var fun = fun0
if (fun.hasSymbol && fun.symbol.isOverloaded) {
// remove alternatives with wrong number of parameters without looking at types.
@@ -3148,7 +3152,7 @@ trait Typers extends Modes {
val expr2 = Function(List(), expr1) setPos expr1.pos
new ChangeOwnerTraverser(context.owner, expr2.symbol).traverse(expr2)
typed1(expr2, mode, pt)
- case PolyType(List(), restpe) =>
+ case NullaryMethodType(restpe) =>
val expr2 = Function(List(), expr1) setPos expr1.pos
new ChangeOwnerTraverser(context.owner, expr2.symbol).traverse(expr2)
typed1(expr2, mode, pt)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Variances.scala b/src/compiler/scala/tools/nsc/typechecker/Variances.scala
index 4ad5c9057f..e29d96e663 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Variances.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Variances.scala
@@ -78,6 +78,8 @@ trait Variances {
varianceInTypes(parents)(tparam) & varianceInSyms(defs.toList)(tparam)
case MethodType(params, restpe) =>
flip(varianceInSyms(params)(tparam)) & varianceInType(restpe)(tparam)
+ case NullaryMethodType(restpe) =>
+ varianceInType(restpe)(tparam)
case PolyType(tparams, restpe) =>
flip(varianceInSyms(tparams)(tparam)) & varianceInType(restpe)(tparam)
case ExistentialType(tparams, restpe) =>
diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
index 5151f1eeee..2df538fe85 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala
@@ -373,9 +373,10 @@ abstract class CPSAnnotationChecker extends CPSUtils {
transChildrenInOrder(tree, tpe, qual::(transArgList(fun, args).flatten), Nil)
case TypeApply(fun @ Select(qual, name), args) if fun.isTyped =>
+ def stripNullaryMethodType(tp: Type) = tp match { case NullaryMethodType(restpe) => restpe case tp => tp }
vprintln("[checker] checking select apply " + tree + "/" + tpe)
- transChildrenInOrder(tree, tpe, List(qual, fun), Nil)
+ transChildrenInOrder(tree, stripNullaryMethodType(tpe), List(qual, fun), Nil)
case Apply(fun, args) if fun.isTyped =>
@@ -406,7 +407,7 @@ abstract class CPSAnnotationChecker extends CPSUtils {
// we have to do it here so we don't lose the cps information (wouldn't trigger our
// adapt and there is no Apply/TypeApply created)
tpe match {
- case PolyType(List(), restpe) =>
+ case NullaryMethodType(restpe) =>
//println("yep: " + restpe + "," + restpe.getClass)
transChildrenInOrder(tree, restpe, List(qual), Nil)
case _ : PolyType => tpe
diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
index 07a9e5fed5..78cc8f7ff7 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala
@@ -50,8 +50,8 @@ abstract class SelectiveCPSTransform extends PluginComponent with
def transformCPSType(tp: Type): Type = { // TODO: use a TypeMap? need to handle more cases?
tp match {
case PolyType(params,res) => PolyType(params, transformCPSType(res))
- case MethodType(params,res) =>
- MethodType(params, transformCPSType(res))
+ case NullaryMethodType(res) => NullaryMethodType(transformCPSType(res))
+ case MethodType(params,res) => MethodType(params, transformCPSType(res))
case TypeRef(pre, sym, args) => TypeRef(pre, sym, args.map(transformCPSType(_)))
case _ =>
getExternalAnswerTypeAnn(tp) match {
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)