diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala | 32 | ||||
-rw-r--r-- | test/files/run/t5629.check | 2 | ||||
-rw-r--r-- | test/files/run/t5629.scala | 36 | ||||
-rw-r--r-- | test/files/run/t5629b.check | 10 | ||||
-rw-r--r-- | test/files/run/t5629b.scala | 41 |
5 files changed, 108 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index f6296acdca..e0f34b47c8 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -752,9 +752,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } } } - + val subclasses = specializations(clazz.info.typeParams) filter satisfiable - subclasses foreach { env => + subclasses foreach { + env => val spc = specializedClass(env, decls1) val existing = clazz.owner.info.decl(spc.name) @@ -928,7 +929,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (currentRun compiles overriding) checkOverriddenTParams(overridden) - val env = unify(overridden.info, overriding.info, emptyEnv, false) + val env = unify(overridden.info, overriding.info, emptyEnv, false, true) def atNext = afterSpecialize(overridden.owner.info.decl(specializedName(overridden, env))) if (TypeEnv.restrict(env, stvars).nonEmpty && TypeEnv.isValid(env, overridden) && atNext != NoSymbol) { @@ -990,8 +991,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * Fails if such an environment cannot be found. * * If `strict` is true, a UnifyError is thrown if unification is impossible. + * + * If `tparams` is true, then the methods tries to unify over type params in polytypes as well. */ - private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean): TypeEnv = (tp1, tp2) match { + private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean, tparams: Boolean = false): TypeEnv = (tp1, tp2) match { case (TypeRef(_, sym1, _), _) if sym1.isSpecialized => debuglog("Unify " + tp1 + ", " + tp2) if (isPrimitiveValueClass(tp2.typeSymbol) || isSpecializedAnyRefSubtype(tp2, sym1)) @@ -1020,17 +1023,20 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { debuglog("Unify polytypes " + tp1 + " and " + tp2) if (strict && tparams1.length != tparams2.length) unifyError(tp1, tp2) + else if (tparams && tparams1.length == tparams2.length) + unify(res1 :: tparams1.map(_.info), res2 :: tparams2.map(_.info), env, strict) 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) - case (_, ThisType(_)) => unify(tp1, tp2.widen, env, strict) - case (RefinedType(_, _), RefinedType(_, _)) => env - case (AnnotatedType(_, tp1, _), tp2) => unify(tp2, tp1, env, strict) - case (ExistentialType(_, res1), _) => unify(tp2, res1, 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) + case (_, ThisType(_)) => unify(tp1, tp2.widen, env, strict) + case (RefinedType(_, _), RefinedType(_, _)) => env + case (AnnotatedType(_, tp1, _), tp2) => unify(tp2, tp1, env, strict) + case (ExistentialType(_, res1), _) => unify(tp2, res1, env, strict) + case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => unify(List(lo1, hi1), List(lo2, hi2), env, strict) case _ => debuglog("don't know how to unify %s [%s] with %s [%s]".format(tp1, tp1.getClass, tp2, tp2.getClass)) env diff --git a/test/files/run/t5629.check b/test/files/run/t5629.check new file mode 100644 index 0000000000..6a2d630f4e --- /dev/null +++ b/test/files/run/t5629.check @@ -0,0 +1,2 @@ +int child got: 33 +any child got: 33 diff --git a/test/files/run/t5629.scala b/test/files/run/t5629.scala new file mode 100644 index 0000000000..69feddd3a5 --- /dev/null +++ b/test/files/run/t5629.scala @@ -0,0 +1,36 @@ + + + +import scala.{specialized => spec} + + + +trait GrandParent[@spec(Int) -A] { + def foo(a: A): Unit + def bar[B <: A](b: B): Unit = println("grandparent got: %s" format b) +} + + +trait Parent[@spec(Int) -A] extends GrandParent[A] { + def foo(a: A) = bar(a) +} + + +class IntChild extends Parent[Int] { + override def bar[B <: Int](b: B): Unit = println("int child got: %s" format b) +} + + +class AnyChild extends Parent[Any] { + override def bar[B <: Any](b: B): Unit = println("any child got: %s" format b) +} + + +object Test { + + def main(args: Array[String]) { + new IntChild().foo(33) + new AnyChild().foo(33) + } + +} diff --git a/test/files/run/t5629b.check b/test/files/run/t5629b.check new file mode 100644 index 0000000000..1bc0248c3d --- /dev/null +++ b/test/files/run/t5629b.check @@ -0,0 +1,10 @@ +=== pf(1): +MySmartPF.apply entered... +newPF.applyOrElse entered... +default +scala.MatchError: () (of class scala.runtime.BoxedUnit) +=== pf(42): +MySmartPF.apply entered... +newPF.applyOrElse entered... +ok +=== done diff --git a/test/files/run/t5629b.scala b/test/files/run/t5629b.scala new file mode 100644 index 0000000000..6c908081b9 --- /dev/null +++ b/test/files/run/t5629b.scala @@ -0,0 +1,41 @@ + + + + + +object Test extends App { + + trait MyPF[@specialized(Int) -A] extends (A => Unit) { + def isDefinedAt(x: A): Boolean + def applyOrElse[A1 <: A](x: A1, default: A1 => Unit): Unit = { + println("MyPF.applyOrElse entered...") + if (isDefinedAt(x)) apply(x) else default(x) + } + } + + trait MySmartPF[@specialized(Int) -A] extends MyPF[A] { + def apply(x: A): Unit = { + println("MySmartPF.apply entered...") + applyOrElse(x, { _: Any => throw new MatchError }) + } + } + + type T = Int + //type T = Any + + def newPF(test: T): MyPF[T] = new MySmartPF[T] { + def isDefinedAt(x: T): Boolean = x != test + override def applyOrElse[A1 <: T](x: A1, default: A1 => Unit): Unit = { + println("newPF.applyOrElse entered...") + if (x != test) { println("ok"); () } else { println("default"); default(x) } + } + } + + val pf = newPF(1) + println("=== pf(1):") + try { pf(1) } catch { case x => println(x) } + println("=== pf(42):") + pf(42) + println("=== done") + +} |