summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala58
-rw-r--r--src/library/scala/package.scala5
-rw-r--r--test/files/buildmanager/t2652/t2652.check2
-rw-r--r--test/files/run/t4794.check2
-rw-r--r--test/files/run/t5488-fn.check17
-rw-r--r--test/files/run/t5488-fn.scala49
-rw-r--r--test/files/run/t5488.check14
-rw-r--r--test/files/run/t5488.scala26
-rw-r--r--test/pending/run/t4770.check (renamed from test/files/run/t4770.check)0
-rw-r--r--test/pending/run/t4770.scala (renamed from test/files/run/t4770.scala)0
11 files changed, 148 insertions, 32 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index b4b0a7335d..d043230e48 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -70,8 +70,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
tpnme.Float -> FLOAT_TAG,
tpnme.Double -> DOUBLE_TAG,
tpnme.Boolean -> BOOL_TAG,
- tpnme.Unit -> VOID_TAG,
- tpnme.Object -> OBJECT_TAG
+ tpnme.Unit -> VOID_TAG
)
private def classesMap[T](f: Name => T) = symbolsMap(ScalaValueClassesNoUnit, f)
@@ -80,7 +79,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
private def boxedName(name: Name) = sn.Boxed(name.toTypeName)
- lazy val abbrvTag = symbolsMap(ObjectClass :: ScalaValueClasses, nameToTag)
+ lazy val abbrvTag = symbolsMap(ScalaValueClasses, nameToTag) withDefaultValue OBJECT_TAG
lazy val numericWeight = symbolsMapFilt(ScalaValueClasses, nameToWeight.keySet, nameToWeight)
lazy val boxedModule = classesMap(x => getModule(boxedName(x)))
lazy val boxedClass = classesMap(x => getClass(boxedName(x)))
@@ -213,7 +212,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
// Note: this is not the type alias AnyRef, it's a companion-like
// object used by the @specialize annotation.
- def AnyRefModule = getMember(ScalaPackageClass, nme.AnyRef)
+ lazy val AnyRefModule = getMember(ScalaPackageClass, nme.AnyRef)
@deprecated("Use AnyRefModule", "2.10.0")
def Predef_AnyRef = AnyRefModule
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 8c34a9139d..8b1d5b3295 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -121,9 +121,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// then pos/spec-List.scala fails - why? Does this kind of check fail
// for similar reasons? Does `sym.isAbstractType` make a difference?
private def isSpecializedAnyRefSubtype(tp: Type, sym: Symbol) = (
- (specializedOn(sym) contains AnyRefModule)
+ // !!! Come back to this, not sure it's recognizing AnyRefModule
+ (specializedOn(sym) exists (s => !isValueClass(s)))
&& !isValueClass(tp.typeSymbol)
&& isBoundedGeneric(tp)
+ // && (tp <:< AnyRefClass.tpe)
)
private def isBoundedGeneric(tp: Type) = tp match {
case TypeRef(_, sym, _) if sym.isAbstractType => (tp <:< AnyRefClass.tpe)
@@ -279,10 +281,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val pre1 = this(pre)
// when searching for a specialized class, take care to map all
// type parameters that are subtypes of AnyRef to AnyRef
- val args1 = map2(args, sym.typeParams) {
- case (tp, orig) if isSpecializedAnyRefSubtype(tp, orig) => AnyRefClass.tpe
- case (tp, _) => tp
- }
+ val args1 = map2(args, sym.info.typeParams)((tp, orig) =>
+ if (isSpecializedAnyRefSubtype(tp, orig)) AnyRefClass.tpe
+ else tp
+ )
specializedClass.get((sym, TypeEnv.fromSpecialization(sym, args1))) match {
case Some(sym1) => typeRef(pre1, sym1, survivingArgs(sym, args))
case None => typeRef(pre1, sym, args)
@@ -305,7 +307,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
else specializedTypeVars(sym).intersect(env.keySet)
)
val (methparams, others) = tvars.toList sortBy ("" + _.name) partition (_.owner.isMethod)
- debuglog("specName(" + sym + ") env: " + env + " tvars: " + tvars)
+ log("specName(" + sym + ") env: " + env + " tvars: " + tvars)
specializedName(sym.name, methparams map env, others map env)
}
@@ -322,10 +324,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
nme.getterToLocal(specializedName(nme.localToGetter(name), types1, types2))
else {
val (base, cs, ms) = nme.splitSpecializedName(name)
- val abbrevs = definitions.abbrvTag withDefaultValue definitions.abbrvTag(ObjectClass)
newTermName(base.toString + "$"
- + "m" + ms + types1.map(t => abbrevs(t.typeSymbol)).mkString("", "", "")
- + "c" + cs + types2.map(t => abbrevs(t.typeSymbol)).mkString("", "", "$sp"))
+ + "m" + ms + types1.map(t => definitions.abbrvTag(t.typeSymbol)).mkString("", "", "")
+ + "c" + cs + types2.map(t => definitions.abbrvTag(t.typeSymbol)).mkString("", "", "$sp"))
}
}
@@ -370,8 +371,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case set :: Nil => set map (x => List(x))
case set :: sets => for (x <- set ; xs <- loop(sets)) yield x :: xs
}
- // zip the keys with each permutation to create a TypeEnv
- loop(keys map concreteTypes) map (xss => Map(keys zip xss: _*))
+ // zip the keys with each permutation to create a TypeEnv.
+ // If we don't exclude the "all AnyRef" specialization, we will
+ // incur duplicate members and crash during mixin.
+ loop(keys map concreteTypes) filterNot (_ forall (_ <:< AnyRefClass.tpe)) map (xss => Map(keys zip xss: _*))
}
/** Does the given 'sym' need to be specialized in the environment 'env'?
@@ -962,6 +965,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
case object UnifyError extends scala.util.control.ControlThrowable
+ private[this] def unifyError(tp1: Any, tp2: Any): Nothing = {
+ log("unifyError" + ((tp1, tp2)))
+ throw UnifyError
+ }
/** Return the most general type environment that specializes tp1 to tp2.
* It only allows binding of type parameters annotated with @specialized.
@@ -972,29 +979,34 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean): TypeEnv = (tp1, tp2) match {
case (TypeRef(_, sym1, _), _) if isSpecialized(sym1) =>
debuglog("Unify - basic case: " + tp1 + ", " + tp2)
- if (isValueClass(tp2.typeSymbol) || isSpecializedAnyRefSubtype(tp2, sym1))
+ if (isValueClass(tp2.typeSymbol))
env + ((sym1, tp2))
+ else if (isSpecializedAnyRefSubtype(tp2, sym1))
+ env + ((sym1, tp2)) // env + ((sym1, AnyRefClass.tpe))
+ else if (strict)
+ unifyError(tp1, tp2)
else
- if (strict) throw UnifyError else env
+ env
case (TypeRef(_, sym1, args1), TypeRef(_, sym2, args2)) =>
debuglog("Unify TypeRefs: " + tp1 + " and " + tp2 + " with args " + (args1, args2) + " - ")
- if (strict && args1.length != args2.length) throw UnifyError
+ if (strict && args1.length != args2.length) unifyError(tp1, tp2)
val e = unify(args1, args2, env, strict)
debuglog("unified to: " + e)
e
case (TypeRef(_, sym1, _), _) if sym1.isTypeParameterOrSkolem =>
env
case (MethodType(params1, res1), MethodType(params2, res2)) =>
- if (strict && params1.length != params2.length) throw UnifyError
+ if (strict && params1.length != params2.length) unifyError(tp1, tp2)
debuglog("Unify MethodTypes: " + tp1 + " and " + tp2)
unify(res1 :: (params1 map (_.tpe)), res2 :: (params2 map (_.tpe)), env, strict)
case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
- if (strict && tparams1.length != tparams2.length) throw UnifyError
debuglog("Unify PolyTypes: " + tp1 + " and " + tp2)
- unify(res1, res2, env, strict)
- case (PolyType(_, res), other) =>
- unify(res, other, env, strict)
- case (ThisType(_), ThisType(_)) => env
+ if (strict && tparams1.length != tparams2.length)
+ unifyError(tp1, tp2)
+ else
+ unify(res1, res2, env, strict)
+ case (PolyType(_, res), other) => unify(res, other, env, strict)
+ case (ThisType(_), ThisType(_)) => env
case (_, SingleType(_, _)) => unify(tp1, tp2.underlying, env, strict)
case (SingleType(_, _), _) => unify(tp1.underlying, tp2, env, strict)
case (ThisType(_), _) => unify(tp1.widen, tp2, env, strict)
@@ -1016,7 +1028,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
if (env.keySet intersect nenv.keySet isEmpty) env ++ nenv
else {
debuglog("could not unify: u(" + args._1 + ", " + args._2 + ") yields " + nenv + ", env: " + env)
- throw UnifyError
+ unifyError(tp1, tp2)
}
}
}
@@ -1242,7 +1254,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
}
- def doesConform(origSymbol: Symbol, treeType: Type, memberType: Type, env: TypeEnv) =
+ def doesConform(origSymbol: Symbol, treeType: Type, memberType: Type, env: TypeEnv) = {
(treeType =:= memberType) || { // anyref specialization
memberType match {
case PolyType(_, resTpe) =>
@@ -1259,6 +1271,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case _ => false
}
}
+ }
override def transform(tree: Tree): Tree = {
val symbol = tree.symbol
@@ -1289,6 +1302,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
curTree = tree
tree match {
case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
+ // log("Attempting to specialize new %s(%s)".format(tpt, args.mkString(", ")))
if (findSpec(tpt.tpe).typeSymbol ne tpt.tpe.typeSymbol) {
// the ctor can be specialized
log("** instantiated specialized type: " + findSpec(tpt.tpe))
diff --git a/src/library/scala/package.scala b/src/library/scala/package.scala
index 9425eba232..06d7f46d52 100644
--- a/src/library/scala/package.scala
+++ b/src/library/scala/package.scala
@@ -29,10 +29,7 @@ package object scala {
type AbstractMethodError = java.lang.AbstractMethodError
// A dummy used by the specialization annotation.
- // Normally it's bad juju to place objects inside package objects,
- // but there's no choice here as we'd have to be AnyRef's companion
- // and defined in the same file - except there is no such file.
- object AnyRef extends Specializable {
+ val AnyRef = new Specializable {
override def toString = "object AnyRef"
}
diff --git a/test/files/buildmanager/t2652/t2652.check b/test/files/buildmanager/t2652/t2652.check
index b84c80205e..071281c6ff 100644
--- a/test/files/buildmanager/t2652/t2652.check
+++ b/test/files/buildmanager/t2652/t2652.check
@@ -3,7 +3,7 @@ compiling Set(A.scala, B.scala)
Changes: Map()
builder > A.scala
compiling Set(A.scala)
-Changes: Map(class A -> List(Added(Definition(A.x$mBc$sp)), Added(Definition(A.x$mCc$sp)), Added(Definition(A.x$mDc$sp)), Added(Definition(A.x$mFc$sp)), Added(Definition(A.x$mIc$sp)), Added(Definition(A.x$mJc$sp)), Added(Definition(A.x$mLc$sp)), Added(Definition(A.x$mSc$sp)), Added(Definition(A.x$mVc$sp)), Added(Definition(A.x$mZc$sp)), Changed(Definition(A.x))[method x changed from [T](t: T)T to [T](t: T)T flags: <method> <triedcooking>]))
+Changes: Map(class A -> List(Added(Definition(A.x$mBc$sp)), Added(Definition(A.x$mCc$sp)), Added(Definition(A.x$mDc$sp)), Added(Definition(A.x$mFc$sp)), Added(Definition(A.x$mIc$sp)), Added(Definition(A.x$mJc$sp)), Added(Definition(A.x$mSc$sp)), Added(Definition(A.x$mVc$sp)), Added(Definition(A.x$mZc$sp)), Changed(Definition(A.x))[method x changed from [T](t: T)T to [T](t: T)T flags: <method> <triedcooking>]))
invalidate B.scala because it references changed definition [Changed(Definition(A.x))[method x changed from [T](t: T)T to [T](t: T)T flags: <method> <triedcooking>]]
compiling Set(B.scala)
Changes: Map(object B -> List())
diff --git a/test/files/run/t4794.check b/test/files/run/t4794.check
index b4de394767..f599e28b8a 100644
--- a/test/files/run/t4794.check
+++ b/test/files/run/t4794.check
@@ -1 +1 @@
-11
+10
diff --git a/test/files/run/t5488-fn.check b/test/files/run/t5488-fn.check
new file mode 100644
index 0000000000..196f58d063
--- /dev/null
+++ b/test/files/run/t5488-fn.check
@@ -0,0 +1,17 @@
+B$mcII$sp
+B
+B$mcIV$sp
+B$mcLI$sp
+B
+B$mcLV$sp
+B$mcVI$sp
+B
+B$mcVV$sp
+C$mcIII$sp
+C
+C$mcILI$sp
+C
+C$mcLII$sp
+C
+C$mcLLI$sp
+C
diff --git a/test/files/run/t5488-fn.scala b/test/files/run/t5488-fn.scala
new file mode 100644
index 0000000000..9e4f60002b
--- /dev/null
+++ b/test/files/run/t5488-fn.scala
@@ -0,0 +1,49 @@
+class B[@specialized(Int, AnyRef, Unit) A, @specialized(Int, Unit) B](f: A => B)
+class C[@specialized(Int, AnyRef) A, @specialized(Int, AnyRef) B, @specialized(Int) C](f: (A, B) => C)
+// Not yet:
+// class B[@specialized(Int, AnyRef, Unit) A, @specialized(Int, AnyRef, Unit) B](f: A => B)
+// class C[@specialized(Int, AnyRef) A, @specialized(Int, AnyRef) B, @specialized(Int, AnyRef) C](f: (A, B) => C)
+
+object Test {
+ def main(args:Array[String]) {
+ def show(x: Any) = println(x.getClass.getName)
+
+ show(new B((x: Int) => 1))
+ show(new B((x: Int) => "abc"))
+ show(new B((x: Int) => ()))
+ show(new B((x: AnyRef) => 1))
+ show(new B((x: AnyRef) => "abc"))
+ show(new B((x: AnyRef) => ()))
+ show(new B((x: Unit) => 1))
+ show(new B((x: Unit) => "abc"))
+ show(new B((x: Unit) => ()))
+
+ show(new C((x: Int, y: Int) => 1))
+ show(new C((x: Int, y: Int) => "abc"))
+ show(new C((x: Int, y: AnyRef) => 1))
+ show(new C((x: Int, y: AnyRef) => "abc"))
+ show(new C((x: AnyRef, y: Int) => 1))
+ show(new C((x: AnyRef, y: Int) => "abc"))
+ show(new C((x: AnyRef, y: AnyRef) => 1))
+ show(new C((x: AnyRef, y: AnyRef) => "abc"))
+ }
+}
+/** If the return types are specialized on AnyRef as well:
+
+files/run/t5488-fn.scala:18: error: type mismatch;
+ found : Unit => String
+ required: Unit => B$sp
+ show(new B((x: Unit) => "abc"))
+ ^
+files/run/t5488-fn.scala:24: error: type mismatch;
+ found : (Int, Object) => String
+ required: (Int, B$sp) => C$sp
+ show(new C((x: Int, y: AnyRef) => "abc"))
+ ^
+files/run/t5488-fn.scala:26: error: type mismatch;
+ found : (Object, Int) => String
+ required: (A$sp, Int) => C$sp
+ show(new C((x: AnyRef, y: Int) => "abc"))
+ ^
+three errors found
+**/
diff --git a/test/files/run/t5488.check b/test/files/run/t5488.check
new file mode 100644
index 0000000000..ccd98c4dbc
--- /dev/null
+++ b/test/files/run/t5488.check
@@ -0,0 +1,14 @@
+A0$mcI$sp
+A0
+B0$mcII$sp
+B0$mcIL$sp
+B0$mcLI$sp
+B0
+C0$mcIII$sp
+C0$mcIIL$sp
+C0$mcILI$sp
+C0$mcILL$sp
+C0$mcLII$sp
+C0$mcLIL$sp
+C0$mcLLI$sp
+C0
diff --git a/test/files/run/t5488.scala b/test/files/run/t5488.scala
new file mode 100644
index 0000000000..7bab0cdc3c
--- /dev/null
+++ b/test/files/run/t5488.scala
@@ -0,0 +1,26 @@
+class A0[@specialized(Int, AnyRef) A]()
+class B0[@specialized(Int, AnyRef) A, @specialized(Int, AnyRef) B]()
+class C0[@specialized(Int, AnyRef) A, @specialized(Int, AnyRef) B, @specialized(Int, AnyRef) C]()
+
+object Test {
+ def main(args:Array[String]) {
+ def show(x: Any) = println(x.getClass.getName)
+
+ show(new A0[Int]())
+ show(new A0[AnyRef]())
+
+ show(new B0[Int, Int]())
+ show(new B0[Int, AnyRef]())
+ show(new B0[AnyRef, Int]())
+ show(new B0[AnyRef, AnyRef]())
+
+ show(new C0[Int, Int, Int]())
+ show(new C0[Int, Int, AnyRef]())
+ show(new C0[Int, AnyRef, Int]())
+ show(new C0[Int, AnyRef, AnyRef]())
+ show(new C0[AnyRef, Int, Int]())
+ show(new C0[AnyRef, Int, AnyRef]())
+ show(new C0[AnyRef, AnyRef, Int]())
+ show(new C0[AnyRef, AnyRef, AnyRef]())
+ }
+}
diff --git a/test/files/run/t4770.check b/test/pending/run/t4770.check
index 38e5a831fa..38e5a831fa 100644
--- a/test/files/run/t4770.check
+++ b/test/pending/run/t4770.check
diff --git a/test/files/run/t4770.scala b/test/pending/run/t4770.scala
index 25bf3050c3..25bf3050c3 100644
--- a/test/files/run/t4770.scala
+++ b/test/pending/run/t4770.scala