From 3440d1bdbda4746756fa2c905aa2cc41eadbe5cf Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 17 Oct 2012 08:18:50 +0200 Subject: SI-6526 Tail call elimination should descend deeper. It wasn't traversing into Select nodes nor into the receiver of a tail call. --- test/files/neg/t6526.check | 13 +++++++++++++ test/files/neg/t6526.scala | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 test/files/neg/t6526.check create mode 100644 test/files/neg/t6526.scala (limited to 'test/files') diff --git a/test/files/neg/t6526.check b/test/files/neg/t6526.check new file mode 100644 index 0000000000..f4db0cc87a --- /dev/null +++ b/test/files/neg/t6526.check @@ -0,0 +1,13 @@ +t6526.scala:8: error: could not optimize @tailrec annotated method inner: it contains a recursive call not in tail position + @tailrec def inner(i: Int): Int = 1 + inner(i) + ^ +t6526.scala:14: error: could not optimize @tailrec annotated method inner: it contains a recursive call not in tail position + @tailrec def inner(i: Int): Int = 1 + inner(i) + ^ +t6526.scala:20: error: could not optimize @tailrec annotated method inner: it contains a recursive call not in tail position + @tailrec def inner(i: Int): Int = 1 + inner(i) + ^ +t6526.scala:30: error: could not optimize @tailrec annotated method inner: it contains a recursive call not in tail position + @tailrec def inner(i: Int): Int = 1 + inner(i) + ^ +four errors found diff --git a/test/files/neg/t6526.scala b/test/files/neg/t6526.scala new file mode 100644 index 0000000000..a34ba570d0 --- /dev/null +++ b/test/files/neg/t6526.scala @@ -0,0 +1,36 @@ +import scala.annotation.tailrec + +class TailRec { + def bar(f: => Any) = "" + + // transform the qualifier of a Select + bar { + @tailrec def inner(i: Int): Int = 1 + inner(i) + inner(0) + }.length + + // transform the body of a function + () => { + @tailrec def inner(i: Int): Int = 1 + inner(i) + inner(0) + } + + // transform the qualifier of a Select + { + @tailrec def inner(i: Int): Int = 1 + inner(i) + inner(0) + "" + }.length + + // The receiver of a tail recursive call must itself be transformed + object X { + @tailrec // okay, all other annotated methods should fail. + def foo: Any = { + { + @tailrec def inner(i: Int): Int = 1 + inner(i) + inner(0) + this + }.foo + } + } +} -- cgit v1.2.3 From 6ff9db6362c0b19c72b3b0ca2721367a85e13189 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 18 Oct 2012 04:02:27 -0700 Subject: Fix for SI-6537, inaccurate unchecked warning. I found a more direct expression of the unchecked logic, which should be much easier for others to verify. But the bug being fixed here is that the unchecked checking happens too early, and the sealed children of a symbol are not yet visible if it is being simultaneously compiled. --- .../scala/tools/nsc/typechecker/Checkable.scala | 67 +++++++++++----------- test/files/neg/unchecked-knowable.check | 7 ++- test/files/neg/unchecked-knowable.scala | 4 +- test/files/pos/t6537.flags | 1 + test/files/pos/t6537.scala | 16 ++++++ 5 files changed, 58 insertions(+), 37 deletions(-) create mode 100644 test/files/pos/t6537.flags create mode 100644 test/files/pos/t6537.scala (limited to 'test/files') diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala index 7e15cf91a7..ec097a9b08 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala @@ -165,41 +165,43 @@ trait Checkable { /** X, P, [P1], etc. are all explained at the top of the file. */ private object CheckabilityChecker { - /** A knowable class is one which is either effectively final - * itself, or sealed with only knowable children. - */ - def isKnowable(sym: Symbol): Boolean = /*logResult(s"isKnowable($sym)")*/( - sym.initialize.isEffectivelyFinal // pesky .initialize requirement, or we receive lies about isSealed - || sym.isSealed && (sym.children forall isKnowable) + /** Are these symbols classes with no subclass relationship? */ + def areUnrelatedClasses(sym1: Symbol, sym2: Symbol) = ( + sym1.isClass + && sym2.isClass + && !(sym1 isSubClass sym2) + && !(sym2 isSubClass sym1) ) - def knownSubclasses(sym: Symbol): List[Symbol] = /*logResult(s"knownSubclasses($sym)")*/(sym :: { - if (sym.isSealed) sym.children.toList flatMap knownSubclasses - else Nil - }) - def excludable(s1: Symbol, s2: Symbol) = /*logResult(s"excludable($s1, $s2)")*/( - isKnowable(s1) - && !(s2 isSubClass s1) - && knownSubclasses(s1).forall(child => !(child isSubClass s2)) + /** Are all children of these symbols pairwise irreconcilable? */ + def allChildrenAreIrreconcilable(sym1: Symbol, sym2: Symbol) = ( + sym1.children.toList forall (c1 => + sym2.children.toList forall (c2 => + areIrreconcilableAsParents(c1, c2) + ) + ) ) - - /** Given classes A and B, can it be shown that nothing which is - * an A will ever be a subclass of something which is a B? This - * entails not only showing that !(A isSubClass B) but that the - * same is true of all their subclasses. Restated for symmetry: - * the same value cannot be a member of both A and B. + /** Is it impossible for the given symbols to be parents in the same class? + * This means given A and B, can there be an instance of A with B? This is the + * case if neither A nor B is a subclass of the other, and one of the following + * additional conditions holds: + * - either A or B is effectively final + * - neither A nor B is a trait (i.e. both are actual classes, not eligible for mixin) + * - both A and B are sealed, and every possible pairing of their children is irreconcilable * - * 1) A must not be a subclass of B, nor B of A (the trivial check) - * 2) One of A or B must be completely knowable (see isKnowable) - * 3) Assuming A is knowable, the proposition is true if - * !(A' isSubClass B) for all A', where A' is a subclass of A. - * - * Due to symmetry, the last condition applies as well in reverse. + * TODO: the last two conditions of the last possibility (that the symbols are not of + * classes being compiled in the current run) are because this currently runs too early, + * and .children returns Nil for sealed classes because their children will not be + * populated until typer. It was too difficult to move things around for the moment, + * so I will consult with moors about the optimal time to be doing this. */ - def isNeverSubClass(sym1: Symbol, sym2: Symbol) = /*logResult(s"isNeverSubClass($sym1, $sym2)")*/( - sym1.isClass - && sym2.isClass - && (excludable(sym1, sym2) || excludable(sym2, sym1)) + def areIrreconcilableAsParents(sym1: Symbol, sym2: Symbol): Boolean = areUnrelatedClasses(sym1, sym2) && ( + sym1.initialize.isEffectivelyFinal // initialization important + || sym2.initialize.isEffectivelyFinal + || !sym1.isTrait && !sym2.isTrait + || sym1.isSealed && sym2.isSealed && allChildrenAreIrreconcilable(sym1, sym2) && !currentRun.compiles(sym1) && !currentRun.compiles(sym2) ) + def isNeverSubClass(sym1: Symbol, sym2: Symbol) = areIrreconcilableAsParents(sym1, sym2) + private def isNeverSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol]): Boolean = /*logResult(s"isNeverSubArgs($tps1, $tps2, $tparams)")*/ { def isNeverSubArg(t1: Type, t2: Type, variance: Int) = { if (variance > 0) isNeverSubType(t2, t1) @@ -210,10 +212,7 @@ trait Checkable { } private def isNeverSameType(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { case (TypeRef(_, sym1, args1), TypeRef(_, sym2, args2)) => - ( isNeverSubClass(sym1, sym2) - || isNeverSubClass(sym2, sym1) - || ((sym1 == sym2) && isNeverSubArgs(args1, args2, sym1.typeParams)) - ) + isNeverSubClass(sym1, sym2) || ((sym1 == sym2) && isNeverSubArgs(args1, args2, sym1.typeParams)) case _ => false } diff --git a/test/files/neg/unchecked-knowable.check b/test/files/neg/unchecked-knowable.check index 3a6ef994b5..d279427327 100644 --- a/test/files/neg/unchecked-knowable.check +++ b/test/files/neg/unchecked-knowable.check @@ -1,4 +1,7 @@ -unchecked-knowable.scala:17: error: fruitless type test: a value of type Bippy cannot also be a A1 +unchecked-knowable.scala:18: error: fruitless type test: a value of type Bippy cannot also be a A1 /* warn */ (new Bippy).isInstanceOf[A1] ^ -one error found +unchecked-knowable.scala:19: error: fruitless type test: a value of type Bippy cannot also be a B1 + /* warn */ (new Bippy).isInstanceOf[B1] + ^ +two errors found diff --git a/test/files/neg/unchecked-knowable.scala b/test/files/neg/unchecked-knowable.scala index 667b47f504..21624c4fb4 100644 --- a/test/files/neg/unchecked-knowable.scala +++ b/test/files/neg/unchecked-knowable.scala @@ -7,6 +7,7 @@ final class A4 extends A2 /** Unknowable */ sealed abstract class B1 sealed abstract class B2 extends B1 +sealed trait B2B extends B1 final class B3 extends B1 trait B4 extends B2 @@ -15,6 +16,7 @@ trait Dingus class A { /* warn */ (new Bippy).isInstanceOf[A1] - /* nowarn */ (new Bippy).isInstanceOf[B1] + /* warn */ (new Bippy).isInstanceOf[B1] + /* nowarn */ (null: Dingus).isInstanceOf[B1] /* nowarn */ ((new Bippy): Any).isInstanceOf[A1] } diff --git a/test/files/pos/t6537.flags b/test/files/pos/t6537.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/pos/t6537.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/pos/t6537.scala b/test/files/pos/t6537.scala new file mode 100644 index 0000000000..d0ca3ba435 --- /dev/null +++ b/test/files/pos/t6537.scala @@ -0,0 +1,16 @@ +package tester + +object PatMatWarning { + + sealed trait X + sealed trait Y + + def f(x: X) = x match { + case _: Y => false + case _ => true + } + + class X1 extends X + class Y1 extends Y + class Z1 extends X with Y +} -- cgit v1.2.3 From 74357d11837939f16820623e6a7a5e3483335b4c Mon Sep 17 00:00:00 2001 From: Roland Date: Thu, 18 Oct 2012 21:26:32 +0200 Subject: avoid single-art assert where harmful in duration-tck --- test/files/jvm/duration-tck.scala | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'test/files') diff --git a/test/files/jvm/duration-tck.scala b/test/files/jvm/duration-tck.scala index df1052fed3..d0f13816a6 100644 --- a/test/files/jvm/duration-tck.scala +++ b/test/files/jvm/duration-tck.scala @@ -170,11 +170,14 @@ object Test extends App { // test Deadline val dead = 2.seconds.fromNow val dead2 = 2 seconds fromNow - assert(dead.timeLeft > 1.second) - assert(dead2.timeLeft > 1.second) + + { val l = dead.timeLeft; assert(l > 1.second, s"$l <= 1.second") } + { val l = dead2.timeLeft; assert(l > 1.second, s"$l <= 1.second") } + Thread.sleep(1.second.toMillis) - assert(dead.timeLeft < 1.second) - assert(dead2.timeLeft < 1.second) + + { val l = dead.timeLeft; assert(l <= 1.second, s"$l > 1.second") } + { val l = dead2.timeLeft; assert(l <= 1.second, s"$l > 1.second") } // test integer mul/div -- cgit v1.2.3 From c130e19c1cb4f4a1126d543f29a6f0408f25763f Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 21 Oct 2012 07:30:38 -0700 Subject: Fix SI-6552, regression with self types. In 6eb55d4b7a we put in a remedy for an old issue SI-4560 which had accumulated a number of sketchy partial remedies which carried no tests to illustrate their necessity. Looks like at least one of those was doing something useful. Here's to reversion-reversion. This reverts commit c8bdf199, which itself reverted cb4fd6582. --- src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 1 + src/reflect/scala/reflect/internal/Types.scala | 8 +++++--- test/files/pos/t6552.scala | 8 ++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 test/files/pos/t6552.scala (limited to 'test/files') diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 211da044e6..b9b17c0277 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -558,6 +558,7 @@ trait Contexts { self: Analyzer => ( (ab.isTerm || ab == rootMirror.RootClass) || (accessWithin(ab) || accessWithinLinked(ab)) && ( !sym.hasLocalFlag + || sym.owner.isImplClass // allow private local accesses to impl classes || sym.isProtected && isSubThisType(pre, sym.owner) || pre =:= sym.owner.thisType ) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index ab33c29153..403bf7d492 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -1409,9 +1409,11 @@ trait Types extends api.Types { self: SymbolTable => final class UniqueThisType(sym: Symbol) extends ThisType(sym) { } object ThisType extends ThisTypeExtractor { - def apply(sym: Symbol): Type = - if (phase.erasedTypes) sym.tpe - else unique(new UniqueThisType(sym)) + def apply(sym: Symbol): Type = ( + if (!phase.erasedTypes) unique(new UniqueThisType(sym)) + else if (sym.isImplClass) sym.typeOfThis + else sym.tpe + ) } /** A class for singleton types of the form `..type`. diff --git a/test/files/pos/t6552.scala b/test/files/pos/t6552.scala new file mode 100644 index 0000000000..98e686a1ae --- /dev/null +++ b/test/files/pos/t6552.scala @@ -0,0 +1,8 @@ +object Repros { + class Bar {} + class Baz(val myFoo: Foo) { } + trait Foo { + this: Bar => + val thing = new Baz(this) + } +} -- cgit v1.2.3 From ff3e57beddfec9678b5be1c6031a45e483e1dd66 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 22 Oct 2012 22:11:22 +0200 Subject: SI-6526 Additional test case. --- test/files/neg/t6526.check | 5 ++++- test/files/neg/t6526.scala | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'test/files') diff --git a/test/files/neg/t6526.check b/test/files/neg/t6526.check index f4db0cc87a..606c18c301 100644 --- a/test/files/neg/t6526.check +++ b/test/files/neg/t6526.check @@ -10,4 +10,7 @@ t6526.scala:20: error: could not optimize @tailrec annotated method inner: it co t6526.scala:30: error: could not optimize @tailrec annotated method inner: it contains a recursive call not in tail position @tailrec def inner(i: Int): Int = 1 + inner(i) ^ -four errors found +t6526.scala:39: error: could not optimize @tailrec annotated method inner: it contains a recursive call not in tail position + def inner(i: Int): Int = 1 + inner(i) + ^ +5 errors found diff --git a/test/files/neg/t6526.scala b/test/files/neg/t6526.scala index a34ba570d0..0bc249aa98 100644 --- a/test/files/neg/t6526.scala +++ b/test/files/neg/t6526.scala @@ -33,4 +33,9 @@ class TailRec { }.foo } } + + Some(new AnyRef) map { phooie => + @tailrec + def inner(i: Int): Int = 1 + inner(i) + } getOrElse 42 } -- cgit v1.2.3 From d7f498ac9cccd7473be8f416a1620548ca8fca9b Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 16 Oct 2012 08:07:17 -0700 Subject: Disabled generation of _1, _2, etc. methods. This was part of the introduction of ProductN, which had to go back into pandora's box because of issues with cycles during typing. These should have been reverted along with it. --- .../tools/nsc/typechecker/SyntheticMethods.scala | 7 +- test/files/run/inline-ex-handlers.check | 130 ++++++++++----------- test/files/run/t1195-new.check | 4 +- test/files/run/virtpatmat_extends_product.scala | 7 +- test/files/scalap/caseClass/result.test | 2 - 5 files changed, 76 insertions(+), 74 deletions(-) (limited to 'test/files') diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 67afb0c118..cc3d980cf1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -206,7 +206,8 @@ trait SyntheticMethods extends ast.TreeDSL { Select(mkThisSelect(clazz.derivedValueClassUnbox), nme.hashCode_) } - /** The _1, _2, etc. methods to implement ProductN. + /** The _1, _2, etc. methods to implement ProductN, disabled + * until we figure out how to introduce ProductN without cycles. */ def productNMethods = { val accs = accessors.toIndexedSeq @@ -266,13 +267,13 @@ trait SyntheticMethods extends ast.TreeDSL { Any_equals -> (() => equalsDerivedValueClassMethod) ) - def caseClassMethods = productMethods ++ productNMethods ++ Seq( + def caseClassMethods = productMethods ++ /*productNMethods ++*/ Seq( Object_hashCode -> (() => chooseHashcode), Object_toString -> (() => forwardToRuntime(Object_toString)), Object_equals -> (() => equalsCaseClassMethod) ) - def valueCaseClassMethods = productMethods ++ productNMethods ++ valueClassMethods ++ Seq( + def valueCaseClassMethods = productMethods ++ /*productNMethods ++*/ valueClassMethods ++ Seq( Any_toString -> (() => forwardToRuntime(Object_toString)) ) diff --git a/test/files/run/inline-ex-handlers.check b/test/files/run/inline-ex-handlers.check index 2bc72893e7..e786c780d6 100644 --- a/test/files/run/inline-ex-handlers.check +++ b/test/files/run/inline-ex-handlers.check @@ -13,15 +13,15 @@ < 92 JUMP 2 < < 2: -383c382 +370c369 < locals: value args, variable result, value ex6, value x4, value x5, value message, value x --- > locals: value args, variable result, value ex6, value x4, value x5, value x -385c384 +372c371 < blocks: [1,2,3,4,5,8,11,13,14,16] --- > blocks: [1,2,3,5,8,11,13,14,16,17] -409c408,417 +396c395,404 < 103 THROW(MyException) --- > ? STORE_LOCAL(value ex6) @@ -34,25 +34,25 @@ > 106 LOAD_LOCAL(value x4) > 106 IS_INSTANCE REF(class MyException) > 106 CZJUMP (BOOL)NE ? 5 : 11 -422,424d429 +409,411d416 < 101 JUMP 4 < < 4: -438,441d442 +425,428d429 < 106 LOAD_LOCAL(value x5) < 106 CALL_METHOD MyException.message (dynamic) < 106 STORE_LOCAL(value message) < 106 SCOPE_ENTER value message -443c444,445 +430c431,432 < 106 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) > ? CALL_METHOD MyException.message (dynamic) -515c517 +502c504 < blocks: [1,2,3,4,6,7,8,9,10] --- > blocks: [1,2,3,4,6,7,8,9,10,11,12,13] -544c546,551 +531c533,538 < 306 THROW(MyException) --- > ? JUMP 11 @@ -61,11 +61,11 @@ > ? LOAD_LOCAL(variable monitor4) > 305 MONITOR_EXIT > ? JUMP 12 -550c557 +537c544 < ? THROW(Throwable) --- > ? JUMP 12 -556c563,570 +543c550,557 < ? THROW(Throwable) --- > ? STORE_LOCAL(value t) @@ -76,7 +76,7 @@ > 304 MONITOR_EXIT > ? STORE_LOCAL(value t) > ? JUMP 13 -571a586,597 +558a573,584 > 13: > 310 LOAD_MODULE object Predef > 310 CALL_PRIMITIVE(StartConcat) @@ -89,19 +89,19 @@ > 310 CALL_METHOD scala.Predef.println (dynamic) > 310 JUMP 2 > -580c606 +567c593 < catch (Throwable) in ArrayBuffer(7, 8, 9, 10) starting at: 6 --- > catch (Throwable) in ArrayBuffer(7, 8, 9, 10, 11) starting at: 6 -583c609 +570c596 < catch (Throwable) in ArrayBuffer(4, 6, 7, 8, 9, 10) starting at: 3 --- > catch (Throwable) in ArrayBuffer(4, 6, 7, 8, 9, 10, 11, 12) starting at: 3 -615c641 +602c628 < blocks: [1,2,3,4,5,6,7,9,10] --- > blocks: [1,2,3,4,5,6,7,9,10,11,12] -639c665,671 +626c652,658 < 78 THROW(IllegalArgumentException) --- > ? STORE_LOCAL(value e) @@ -111,12 +111,12 @@ > 81 LOAD_LOCAL(value e) > ? STORE_LOCAL(variable exc1) > ? JUMP 12 -668c700,701 +655c687,688 < 81 THROW(Exception) --- > ? STORE_LOCAL(variable exc1) > ? JUMP 12 -684a718,730 +671a705,717 > 12: > 83 LOAD_MODULE object Predef > 83 CONSTANT("finally") @@ -130,19 +130,19 @@ > 84 LOAD_LOCAL(variable exc1) > 84 THROW(Throwable) > -690c736 +677c723 < catch () in ArrayBuffer(4, 6, 7, 9) starting at: 3 --- > catch () in ArrayBuffer(4, 6, 7, 9, 11) starting at: 3 -714c760 +701c747 < locals: value args, variable result, value ex6, variable exc2, value x4, value x5, value message, value x, value ex6, value x4, value x5, value message, value x --- > locals: value args, variable result, value ex6, variable exc2, value x4, value x5, value x, value ex6, value x4, value x5, value x -716c762 +703c749 < blocks: [1,2,3,4,5,6,9,12,14,17,18,19,22,25,27,28,30,31] --- > blocks: [1,2,3,4,5,6,9,12,14,17,18,19,22,25,27,28,30,31,32,33,34] -740c786,793 +727c773,780 < 172 THROW(MyException) --- > ? STORE_LOCAL(value ex6) @@ -153,64 +153,64 @@ > 170 STORE_LOCAL(value x4) > 170 SCOPE_ENTER value x4 > 170 JUMP 18 -787,790d839 +774,777d826 < 175 LOAD_LOCAL(value x5) < 175 CALL_METHOD MyException.message (dynamic) < 175 STORE_LOCAL(value message) < 175 SCOPE_ENTER value message -792c841,842 +779c828,829 < 176 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) > ? CALL_METHOD MyException.message (dynamic) -796c846,847 +783c833,834 < 177 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) > ? CALL_METHOD MyException.message (dynamic) -798c849,850 +785c836,837 < 177 THROW(MyException) --- > ? STORE_LOCAL(value ex6) > ? JUMP 33 -802c854,855 +789c841,842 < 170 THROW(Throwable) --- > ? STORE_LOCAL(value ex6) > ? JUMP 33 -811a865,870 +798a852,857 > 33: > 169 LOAD_LOCAL(value ex6) > 169 STORE_LOCAL(value x4) > 169 SCOPE_ENTER value x4 > 169 JUMP 5 > -826,829d884 +813,816d871 < 180 LOAD_LOCAL(value x5) < 180 CALL_METHOD MyException.message (dynamic) < 180 STORE_LOCAL(value message) < 180 SCOPE_ENTER value message -831c886,887 +818c873,874 < 181 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) > ? CALL_METHOD MyException.message (dynamic) -835c891,892 +822c878,879 < 182 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) > ? CALL_METHOD MyException.message (dynamic) -837c894,895 +824c881,882 < 182 THROW(MyException) --- > ? STORE_LOCAL(variable exc2) > ? JUMP 34 -841c899,900 +828c886,887 < 169 THROW(Throwable) --- > ? STORE_LOCAL(variable exc2) > ? JUMP 34 -857a917,929 +844a904,916 > 34: > 184 LOAD_MODULE object Predef > 184 CONSTANT("finally") @@ -224,23 +224,23 @@ > 185 LOAD_LOCAL(variable exc2) > 185 THROW(Throwable) > -863c935 +850c922 < catch (Throwable) in ArrayBuffer(17, 18, 19, 22, 25, 27, 28, 30) starting at: 4 --- > catch (Throwable) in ArrayBuffer(17, 18, 19, 22, 25, 27, 28, 30, 32) starting at: 4 -866c938 +853c925 < catch () in ArrayBuffer(4, 5, 6, 9, 12, 17, 18, 19, 22, 25, 27, 28, 30) starting at: 3 --- > catch () in ArrayBuffer(4, 5, 6, 9, 12, 17, 18, 19, 22, 25, 27, 28, 30, 32, 33) starting at: 3 -890c962 +877c949 < locals: value args, variable result, value e, value ex6, value x4, value x5, value message, value x --- > locals: value args, variable result, value e, value ex6, value x4, value x5, value x -892c964 +879c951 < blocks: [1,2,3,6,7,8,11,14,16,17,19] --- > blocks: [1,2,3,6,7,8,11,14,16,17,19,20] -916c988,995 +903c975,982 < 124 THROW(MyException) --- > ? STORE_LOCAL(value ex6) @@ -251,29 +251,29 @@ > 122 STORE_LOCAL(value x4) > 122 SCOPE_ENTER value x4 > 122 JUMP 7 -945,948d1023 +932,935d1010 < 127 LOAD_LOCAL(value x5) < 127 CALL_METHOD MyException.message (dynamic) < 127 STORE_LOCAL(value message) < 127 SCOPE_ENTER value message -950c1025,1026 +937c1012,1013 < 127 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) > ? CALL_METHOD MyException.message (dynamic) -979c1055 +966c1042 < catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 11, 14, 16, 17, 19) starting at: 3 --- > catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 11, 14, 16, 17, 19, 20) starting at: 3 -1003c1079 +990c1066 < locals: value args, variable result, value ex6, value x4, value x5, value message, value x, value e --- > locals: value args, variable result, value ex6, value x4, value x5, value x, value e -1005c1081 +992c1068 < blocks: [1,2,3,4,5,8,11,15,16,17,19] --- > blocks: [1,2,3,5,8,11,15,16,17,19,20] -1029c1105,1114 +1016c1092,1101 < 148 THROW(MyException) --- > ? STORE_LOCAL(value ex6) @@ -286,25 +286,25 @@ > 154 LOAD_LOCAL(value x4) > 154 IS_INSTANCE REF(class MyException) > 154 CZJUMP (BOOL)NE ? 5 : 11 -1050,1052d1134 +1037,1039d1121 < 145 JUMP 4 < < 4: -1066,1069d1147 +1053,1056d1134 < 154 LOAD_LOCAL(value x5) < 154 CALL_METHOD MyException.message (dynamic) < 154 STORE_LOCAL(value message) < 154 SCOPE_ENTER value message -1071c1149,1150 +1058c1136,1137 < 154 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) > ? CALL_METHOD MyException.message (dynamic) -1288c1367 +1275c1354 < blocks: [1,2,3,4,5,7] --- > blocks: [1,2,3,4,5,7,8] -1312c1391,1398 +1299c1378,1385 < 38 THROW(IllegalArgumentException) --- > ? STORE_LOCAL(value e) @@ -315,20 +315,20 @@ > 42 CONSTANT("IllegalArgumentException") > 42 CALL_METHOD scala.Predef.println (dynamic) > 42 JUMP 2 -1359c1445 +1346c1432 < locals: value args, variable result, value ex6, value x4, value x5, value message, value x --- > locals: value args, variable result, value ex6, value x4, value x5, value x -1361c1447 +1348c1434 < blocks: [1,2,3,4,5,8,11,13,14,16,17,19] --- > blocks: [1,2,3,5,8,11,13,14,16,17,19,20] -1385c1471,1472 +1372c1458,1459 < 203 THROW(MyException) --- > ? STORE_LOCAL(value ex6) > ? JUMP 20 -1405c1492,1501 +1392c1479,1488 < 209 THROW(MyException) --- > ? STORE_LOCAL(value ex6) @@ -341,25 +341,25 @@ > 212 LOAD_LOCAL(value x4) > 212 IS_INSTANCE REF(class MyException) > 212 CZJUMP (BOOL)NE ? 5 : 11 -1418,1420d1513 +1405,1407d1500 < 200 JUMP 4 < < 4: -1434,1437d1526 +1421,1424d1513 < 212 LOAD_LOCAL(value x5) < 212 CALL_METHOD MyException.message (dynamic) < 212 STORE_LOCAL(value message) < 212 SCOPE_ENTER value message -1439c1528,1529 +1426c1515,1516 < 213 LOAD_LOCAL(value message) --- > ? LOAD_LOCAL(value x5) > ? CALL_METHOD MyException.message (dynamic) -1483c1573 +1470c1560 < blocks: [1,2,3,4,5,7] --- > blocks: [1,2,3,4,5,7,8] -1507c1597,1604 +1494c1584,1591 < 58 THROW(IllegalArgumentException) --- > ? STORE_LOCAL(value e) @@ -370,11 +370,11 @@ > 62 CONSTANT("RuntimeException") > 62 CALL_METHOD scala.Predef.println (dynamic) > 62 JUMP 2 -1556c1653 +1543c1640 < blocks: [1,2,3,4] --- > blocks: [1,2,3,4,5] -1576c1673,1678 +1563c1660,1665 < 229 THROW(MyException) --- > ? JUMP 5 @@ -383,19 +383,19 @@ > ? LOAD_LOCAL(variable monitor1) > 228 MONITOR_EXIT > 228 THROW(Throwable) -1582c1684 +1569c1671 < ? THROW(Throwable) --- > 228 THROW(Throwable) -1610c1712 +1597c1699 < locals: value args, variable result, variable monitor2, variable monitorResult1 --- > locals: value exception$1, value args, variable result, variable monitor2, variable monitorResult1 -1612c1714 +1599c1701 < blocks: [1,2,3,4] --- > blocks: [1,2,3,4,5] -1635c1737,1745 +1622c1724,1732 < 245 THROW(MyException) --- > ? STORE_LOCAL(value exception$1) @@ -407,7 +407,7 @@ > ? LOAD_LOCAL(variable monitor2) > 244 MONITOR_EXIT > 244 THROW(Throwable) -1641c1751 +1628c1738 < ? THROW(Throwable) --- > 244 THROW(Throwable) diff --git a/test/files/run/t1195-new.check b/test/files/run/t1195-new.check index e0c9ac07ff..0a3f434d62 100644 --- a/test/files/run/t1195-new.check +++ b/test/files/run/t1195-new.check @@ -1,6 +1,6 @@ Bar.type, underlying = <: scala.runtime.AbstractFunction1[Int,Bar] with Serializable{case def unapply(x$0: Bar): Option[Int]} with Singleton -Bar, underlying = <: Product with Serializable{val x: Int; def copy(x: Int): Bar; def copy$default$1: Int; def _1: Int} +Bar, underlying = <: Product with Serializable{val x: Int; def copy(x: Int): Bar; def copy$default$1: Int} Product with Serializable, underlying = Product with Serializable Bar.type, underlying = <: scala.runtime.AbstractFunction1[Int,Bar] with Serializable{case def unapply(x$0: Bar): Option[Int]} with Singleton -Bar, underlying = <: Product with Serializable{val x: Int; def copy(x: Int): Bar; def copy$default$1: Int; def _1: Int} +Bar, underlying = <: Product with Serializable{val x: Int; def copy(x: Int): Bar; def copy$default$1: Int} Product with Serializable, underlying = Product with Serializable diff --git a/test/files/run/virtpatmat_extends_product.scala b/test/files/run/virtpatmat_extends_product.scala index e564f4430b..4b4bc634a7 100644 --- a/test/files/run/virtpatmat_extends_product.scala +++ b/test/files/run/virtpatmat_extends_product.scala @@ -1,5 +1,8 @@ object Test extends App { - case class AnnotationInfo(a: String, b: Int) extends Product2[String, Int] + case class AnnotationInfo(a: String, b: Int) extends Product2[String, Int] { + def _1 = a + def _2 = b + } // if we're not careful in unapplyTypeListFromReturnType, the generated unapply is // thought to return two components instead of one, since AnnotationInfo (the result of the unapply) is a Product2 @@ -8,4 +11,4 @@ object Test extends App { NestedAnnotArg(AnnotationInfo("a", 1)) match { case NestedAnnotArg(x) => println(x) } -} \ No newline at end of file +} diff --git a/test/files/scalap/caseClass/result.test b/test/files/scalap/caseClass/result.test index 6165444026..7d7aa4fd8f 100644 --- a/test/files/scalap/caseClass/result.test +++ b/test/files/scalap/caseClass/result.test @@ -8,8 +8,6 @@ case class CaseClass[A <: scala.Seq[scala.Int]](i : A, s : scala.Predef.String) def productElement(x$1 : scala.Int) : scala.Any = { /* compiled code */ } override def productIterator : scala.collection.Iterator[scala.Any] = { /* compiled code */ } def canEqual(x$1 : scala.Any) : scala.Boolean = { /* compiled code */ } - def _1 : A = { /* compiled code */ } - def _2 : scala.Predef.String = { /* compiled code */ } override def hashCode() : scala.Int = { /* compiled code */ } override def toString() : java.lang.String = { /* compiled code */ } override def equals(x$1 : scala.Any) : scala.Boolean = { /* compiled code */ } -- cgit v1.2.3 From 74297159f5c4df42dcf6289f4daea79e7d4f7bb4 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 28 Oct 2012 13:44:10 +0100 Subject: SI-6575 Plug inference leak of AbstractPartialFun Usually this isn't needed, as partial functions can only be defined with an expected type. But if that expected type is and inherited method return type, the actual type of the partial function literal is used, and the implementation detail of `AbstractPartialFunction[A, B] with Serializable` leaks out. After this change, the inferred types match those from Scala 2.9.2. ticket/6575 ~/code/scala scalac29 -Xprint:typer test/files/pos/t6575a.scala | grep def > 29.txt ticket/6575 ~/code/scala squalac -Xprint:typer test/files/pos/t6575a.scala | grep def > 210.txt ticket/6575 ~/code/scala diff -u 29.txt 210.txt --- 29.txt 2012-10-28 13:51:07.000000000 +0100 +++ 210.txt 2012-10-28 13:51:20.000000000 +0100 @@ -1,7 +1,16 @@ def foo: PartialFunction[Int,Int] def /*Y*/$init$(): Unit = { - absoverride def foo: PartialFunction[Int,Int] = ((x0$1: Int) => x0$1 match { + absoverride def foo: PartialFunction[Int,Int] = { + def (): anonymous class $anonfun = { + final override def applyOrElse[A1 >: Nothing <: Int, B1 >: Int <: Any](x$1: A1, default: A1 => B1): B1 = (x$1: A1 @unchecked) match { + final def isDefinedAt(x$1: Int): Boolean = (x$1: Int @unchecked) match { def /*Z*/$init$(): Unit = { - absoverride def foo: PartialFunction[Int,Int] = ((x0$2: Int) => x0$2 match { + absoverride def foo: PartialFunction[Int,Int] = { + def (): anonymous class $anonfun = { + final override def applyOrElse[A1 >: Nothing <: Int, B1 >: Int <: Any](x$1: A1, default: A1 => B1): B1 = (x$1: A1 @unchecked) match { + final def isDefinedAt(x$1: Int): Boolean = (x$1: Int @unchecked) match { def /*Comb*/$init$(): Unit = { - absoverride def foo: PartialFunction[Int,Int] = ((x0$3: Int) => x0$3 match { + absoverride def foo: PartialFunction[Int,Int] = { + def (): anonymous class $anonfun = { + final override def applyOrElse[A1 >: Nothing <: Int, B1 >: Int <: Any](x$1: A1, default: A1 => B1): B1 = (x$1: A1 @unchecked) match { + final def isDefinedAt(x$1: Int): Boolean = (x$1: Int @unchecked) match { --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 10 +++++++++- test/files/pos/t6575a.scala | 15 +++++++++++++++ test/files/pos/t6575b.scala | 17 +++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 test/files/pos/t6575a.scala create mode 100644 test/files/pos/t6575b.scala (limited to 'test/files') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index f82786da35..8e06588ed8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2590,7 +2590,15 @@ trait Typers extends Modes with Adaptations with Tags { def translated = if (members.head eq EmptyTree) setError(tree) - else typed(atPos(tree.pos)(Block(List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, members, tree.pos.focus)), atPos(tree.pos.focus)(New(anonClass.tpe)))), mode, pt) + else { + val typedBlock = typed(atPos(tree.pos)( + Block(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, members, tree.pos.focus), atPos(tree.pos.focus)(New(anonClass.tpe))) + ), mode, pt) + // Don't leak implementation details into the type, see SI-6575 + if (isPartial && !typedBlock.isErrorTyped) + typedBlock modifyType (_ baseType PartialFunctionClass) + else typedBlock + } } // Function(params, Match(sel, cases)) ==> new Function { def apply(params) = `translateMatch('sel match { cases }')` } diff --git a/test/files/pos/t6575a.scala b/test/files/pos/t6575a.scala new file mode 100644 index 0000000000..f128714dab --- /dev/null +++ b/test/files/pos/t6575a.scala @@ -0,0 +1,15 @@ +trait X { def foo: PartialFunction[Int, Int] } + +trait Y extends X { + // Inferred type was AbstractPartialFunction[Int, Int] with Serializable + abstract override def foo = { case i => super.foo(i) * 2 } +} +trait Z extends X { + // ditto + abstract override def foo = { case i => super.foo(i) + 3 } +} + +trait Comb extends Y with Z { + // ... which led to a type error here. + abstract override def foo: PartialFunction[Int, Int] = { case i => super.foo(i) - 2 } +} diff --git a/test/files/pos/t6575b.scala b/test/files/pos/t6575b.scala new file mode 100644 index 0000000000..d3e58b2a16 --- /dev/null +++ b/test/files/pos/t6575b.scala @@ -0,0 +1,17 @@ +// inferred types were okay here as Function nodes aren't +// translated into anoymous subclasses of AbstractFunctionN +// until after the typer. +// +// So this test is just confirmation. +trait X { def foo: Function1[Int, Int] } + +trait Y extends X { + abstract override def foo = { case i => super.foo(i) * 2 } +} +trait Z extends X { + abstract override def foo = { case i => super.foo(i) + 3 } +} + +trait Comb extends Y with Z { + abstract override def foo: Function1[Int, Int] = { case i => super.foo(i) - 2 } +} -- cgit v1.2.3