diff options
Diffstat (limited to 'test')
40 files changed, 714 insertions, 114 deletions
diff --git a/test/files/instrumented/inline-in-constructors.flags b/test/files/instrumented/inline-in-constructors.flags index 068318e8ac..d1ebc4c940 100644 --- a/test/files/instrumented/inline-in-constructors.flags +++ b/test/files/instrumented/inline-in-constructors.flags @@ -1 +1 @@ --optimise -Ydelambdafy:inline +-optimise -Ydelambdafy:inline -Ybackend:GenASM diff --git a/test/files/jvm/constant-optimization/Foo_1.flags b/test/files/jvm/constant-optimization/Foo_1.flags index 86f52af447..67a1dbe8da 100644 --- a/test/files/jvm/constant-optimization/Foo_1.flags +++ b/test/files/jvm/constant-optimization/Foo_1.flags @@ -1 +1 @@ --Ynooptimise -Yconst-opt
\ No newline at end of file +-Ynooptimise -Yconst-opt -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/jvm/innerClassAttribute.check b/test/files/jvm/innerClassAttribute.check index bb532e4f36..41448f359b 100644 --- a/test/files/jvm/innerClassAttribute.check +++ b/test/files/jvm/innerClassAttribute.check @@ -14,27 +14,27 @@ A19 / null / null A19 / null / null A19 / null / null -- A20 -- -A20$$anonfun$6 / null / null / 17 +A20$$anonfun$4 / null / null / 17 fun1: attribute for itself and the two child closures `() => ()` and `() => () => 1` -A20$$anonfun$6 / null / null / 17 -A20$$anonfun$6$$anonfun$apply$1 / null / null / 17 -A20$$anonfun$6$$anonfun$apply$3 / null / null / 17 +A20$$anonfun$4 / null / null / 17 +A20$$anonfun$4$$anonfun$apply$1 / null / null / 17 +A20$$anonfun$4$$anonfun$apply$2 / null / null / 17 fun2 () => (): itself and the outer closure -A20$$anonfun$6 / null / null / 17 -A20$$anonfun$6$$anonfun$apply$1 / null / null / 17 +A20$$anonfun$4 / null / null / 17 +A20$$anonfun$4$$anonfun$apply$1 / null / null / 17 fun3 () => () => (): itself, the outer closure and its child closure -A20$$anonfun$6 / null / null / 17 -A20$$anonfun$6$$anonfun$apply$3 / null / null / 17 -A20$$anonfun$6$$anonfun$apply$3$$anonfun$apply$2 / null / null / 17 +A20$$anonfun$4 / null / null / 17 +A20$$anonfun$4$$anonfun$apply$2 / null / null / 17 +A20$$anonfun$4$$anonfun$apply$2$$anonfun$apply$3 / null / null / 17 fun4: () => 1: itself and the two outer closures -A20$$anonfun$6 / null / null / 17 -A20$$anonfun$6$$anonfun$apply$3 / null / null / 17 -A20$$anonfun$6$$anonfun$apply$3$$anonfun$apply$2 / null / null / 17 +A20$$anonfun$4 / null / null / 17 +A20$$anonfun$4$$anonfun$apply$2 / null / null / 17 +A20$$anonfun$4$$anonfun$apply$2$$anonfun$apply$3 / null / null / 17 enclosing: nested closures have outer class defined, but no outer method A20 / null / null -A20$$anonfun$6 / null / null -A20$$anonfun$6 / null / null -A20$$anonfun$6$$anonfun$apply$3 / null / null +A20$$anonfun$4 / null / null +A20$$anonfun$4 / null / null +A20$$anonfun$4$$anonfun$apply$2 / null / null #partest -Ydelambdafy:method -- A4 -- null / null / null diff --git a/test/files/jvm/innerClassAttribute/Classes_1.scala b/test/files/jvm/innerClassAttribute/Classes_1.scala index fb1f32aa3d..62c7d94d90 100644 --- a/test/files/jvm/innerClassAttribute/Classes_1.scala +++ b/test/files/jvm/innerClassAttribute/Classes_1.scala @@ -12,8 +12,8 @@ object A3 { } class A4 { - def f(l: List[Int]): List[Int] = { - l map (_ + 1) + def f(l: List[String]): List[String] = { + l map (_ + "1") } } @@ -114,21 +114,21 @@ class A18 { } class A19 { - ((x: Int) => x + 3) + ((x: String) => x + "3") val x = { - ((x: Int) => x + 1) + ((x: String) => x + "1") } { - ((x: Int) => x + 2) + ((x: String) => x + "2") } } class A20 { - () => { - {() => ()} - {() => () => 1} + (s: String) => { + {(s: String) => ()} + {(s: String) => (s: String) => 1} } } @@ -189,13 +189,13 @@ trait A24 extends A24Base { class SI_9105 { // the EnclosingMethod attributes depend on the delambdafy strategy (inline vs method) - // outerClass-inline enclMeth-inline outerClass-method enclMeth-method - val fun = () => { + // outerClass-inline enclMeth-inline outerClass-method enclMeth-method + val fun = (s: String) => { class A // closure null (*) SI_9105 null def m: Object = { class B; new B } // closure m$1 SI_9105 m$1 val f: Object = { class C; new C } // closure null (*) SI_9105 null } - def met = () => { + def met = (s: String) => { class D // closure null (*) SI_9105 met def m: Object = { class E; new E } // closure m$1 SI_9105 m$1 val f: Object = { class F; new F } // closure null (*) SI_9105 met @@ -210,17 +210,19 @@ class SI_9105 { // So using `null` looks more like the situation in the source code: C / F are nested classes of the anon-fun, and // there's no method in between. - def byName[T](op: => T) = 0 + def byName(op: => Any) = 0 val bnV = byName { class G // closure null (*) SI_9105 null def m: Object = { class H; new H } // closure m$1 SI_9105 m$1 val f: Object = { class I; new I } // closure null (*) SI_9105 null + "" } def bnM = byName { class J // closure null (*) SI_9105 bnM def m: Object = { class K; new K } // closure m$1 SI_9105 m$1 val f: Object = { class L; new L } // closure null (*) SI_9105 bnM + "" } } @@ -283,8 +285,8 @@ object NestedInValueClass { class A(val arg: String) extends AnyVal { // A has InnerClass entries for the two closures (and for A and A$). not for B / C def f = { - def g = List().map(x => (() => x)) // outer class A, no outer method (g is moved to the companion, doesn't exist in A) - g.map(x => (() => x)) // outer class A, outer method f + def g = List().map(x => ((s: String) => x)) // outer class A, no outer method (g is moved to the companion, doesn't exist in A) + g.map(x => ((s: String) => x)) // outer class A, outer method f } // statements and field declarations are not allowed in value classes } diff --git a/test/files/jvm/innerClassAttribute/Test.scala b/test/files/jvm/innerClassAttribute/Test.scala index bc9aa2376a..376b3c895b 100644 --- a/test/files/jvm/innerClassAttribute/Test.scala +++ b/test/files/jvm/innerClassAttribute/Test.scala @@ -5,11 +5,14 @@ import asm.{Opcodes => Flags} import scala.collection.JavaConverters._ object Test extends BytecodeTest { + // Helpful for debugging the test: + // println(new java.io.File(classpath.asURLs.head.toURI).list().sorted.mkString("\n")) + def assertSame(a: Any, b: Any) = { assert(a == b, s"\na: $a\nb: $b") } - val publicStatic = Flags.ACC_PUBLIC | Flags.ACC_STATIC + val publicStatic = Flags.ACC_PUBLIC | Flags.ACC_STATIC val publicAbstractInterface = Flags.ACC_PUBLIC | Flags.ACC_ABSTRACT | Flags.ACC_INTERFACE def innerClassNodes(className: String): List[InnerClassNode] = { @@ -266,10 +269,10 @@ object Test extends BytecodeTest { printInnerClassNodes("A20") - val fun1 = lambdaClass("A20$$anonfun$6", "A20$lambda$1") - val fun2 = lambdaClass("A20$$anonfun$6$$anonfun$apply$1", "A20$lambda$$$nestedInAnonfun$5$1") - val fun3 = lambdaClass("A20$$anonfun$6$$anonfun$apply$3", "A20$lambda$$$nestedInAnonfun$5$2") - val fun4 = lambdaClass("A20$$anonfun$6$$anonfun$apply$3$$anonfun$apply$2", "A20$lambda$$$nestedInAnonfun$7$1") + val fun1 = lambdaClass("A20$$anonfun$4", "A20$lambda$1") + val fun2 = lambdaClass("A20$$anonfun$4$$anonfun$apply$1", "A20$lambda$$$nestedInAnonfun$5$1") + val fun3 = lambdaClass("A20$$anonfun$4$$anonfun$apply$2", "A20$lambda$$$nestedInAnonfun$5$2") + val fun4 = lambdaClass("A20$$anonfun$4$$anonfun$apply$2$$anonfun$apply$3", "A20$lambda$$$nestedInAnonfun$7$1") println("fun1: attribute for itself and the two child closures `() => ()` and `() => () => 1`") printInnerClassNodes(fun1) @@ -339,9 +342,9 @@ object Test extends BytecodeTest { assertEnclosingMethod ("SI_9105$A$3" , "SI_9105", null , null) assertEnclosingMethod ("SI_9105$B$5" , "SI_9105", "m$1", "()Ljava/lang/Object;") assertEnclosingMethod ("SI_9105$C$1" , "SI_9105", null , null) - assertEnclosingMethod ("SI_9105$D$1" , "SI_9105", "met", "()Lscala/Function0;") + assertEnclosingMethod ("SI_9105$D$1" , "SI_9105", "met", "()Lscala/Function1;") assertEnclosingMethod ("SI_9105$E$1" , "SI_9105", "m$3", "()Ljava/lang/Object;") - assertEnclosingMethod ("SI_9105$F$1" , "SI_9105", "met", "()Lscala/Function0;") + assertEnclosingMethod ("SI_9105$F$1" , "SI_9105", "met", "()Lscala/Function1;") assertNoEnclosingMethod("SI_9105$lambda$$met$1") assertNoEnclosingMethod("SI_9105$lambda$1") assertNoEnclosingMethod("SI_9105") @@ -366,35 +369,35 @@ object Test extends BytecodeTest { assert(innerClassNodes("SI_9105").length == 12) // the 12 local classes } else { // comment in innerClassAttribute/Classes_1.scala explains the difference between A / C and D / F. - assertEnclosingMethod ("SI_9105$$anonfun$4$A$3" , "SI_9105$$anonfun$4" , null , null) - assertEnclosingMethod ("SI_9105$$anonfun$4$B$5" , "SI_9105$$anonfun$4" , "m$1" , "()Ljava/lang/Object;") - assertEnclosingMethod ("SI_9105$$anonfun$4$C$1" , "SI_9105$$anonfun$4" , null , null) + assertEnclosingMethod ("SI_9105$$anonfun$5$A$3" , "SI_9105$$anonfun$5" , null , null) + assertEnclosingMethod ("SI_9105$$anonfun$5$B$5" , "SI_9105$$anonfun$5" , "m$1" , "()Ljava/lang/Object;") + assertEnclosingMethod ("SI_9105$$anonfun$5$C$1" , "SI_9105$$anonfun$5" , null , null) assertEnclosingMethod ("SI_9105$$anonfun$met$1$D$1", "SI_9105$$anonfun$met$1", null , null) assertEnclosingMethod ("SI_9105$$anonfun$met$1$E$1", "SI_9105$$anonfun$met$1", "m$3" , "()Ljava/lang/Object;") assertEnclosingMethod ("SI_9105$$anonfun$met$1$F$1", "SI_9105$$anonfun$met$1", null , null) - assertEnclosingMethod ("SI_9105$$anonfun$4" , "SI_9105" , null , null) - assertEnclosingMethod ("SI_9105$$anonfun$met$1" , "SI_9105" , "met" , "()Lscala/Function0;") + assertEnclosingMethod ("SI_9105$$anonfun$5" , "SI_9105" , null , null) + assertEnclosingMethod ("SI_9105$$anonfun$met$1" , "SI_9105" , "met" , "()Lscala/Function1;") assertNoEnclosingMethod("SI_9105") - assertLocal(ownInnerClassNode("SI_9105$$anonfun$4$A$3"), "SI_9105$$anonfun$4$A$3" , "A$3") - assertLocal(ownInnerClassNode("SI_9105$$anonfun$4$B$5"), "SI_9105$$anonfun$4$B$5" , "B$5") - assertLocal(ownInnerClassNode("SI_9105$$anonfun$4$C$1"), "SI_9105$$anonfun$4$C$1" , "C$1") + assertLocal(ownInnerClassNode("SI_9105$$anonfun$5$A$3"), "SI_9105$$anonfun$5$A$3" , "A$3") + assertLocal(ownInnerClassNode("SI_9105$$anonfun$5$B$5"), "SI_9105$$anonfun$5$B$5" , "B$5") + assertLocal(ownInnerClassNode("SI_9105$$anonfun$5$C$1"), "SI_9105$$anonfun$5$C$1" , "C$1") assertLocal(ownInnerClassNode("SI_9105$$anonfun$met$1$D$1"), "SI_9105$$anonfun$met$1$D$1", "D$1") assertLocal(ownInnerClassNode("SI_9105$$anonfun$met$1$E$1"), "SI_9105$$anonfun$met$1$E$1", "E$1") assertLocal(ownInnerClassNode("SI_9105$$anonfun$met$1$F$1"), "SI_9105$$anonfun$met$1$F$1", "F$1") // by-name - assertEnclosingMethod("SI_9105$$anonfun$5$G$1", "SI_9105$$anonfun$5", null, null) - assertEnclosingMethod("SI_9105$$anonfun$5$H$1", "SI_9105$$anonfun$5", "m$2", "()Ljava/lang/Object;") - assertEnclosingMethod("SI_9105$$anonfun$5$I$1", "SI_9105$$anonfun$5", null, null) + assertEnclosingMethod("SI_9105$$anonfun$6$G$1", "SI_9105$$anonfun$6", null, null) + assertEnclosingMethod("SI_9105$$anonfun$6$H$1", "SI_9105$$anonfun$6", "m$2", "()Ljava/lang/Object;") + assertEnclosingMethod("SI_9105$$anonfun$6$I$1", "SI_9105$$anonfun$6", null, null) assertEnclosingMethod("SI_9105$$anonfun$bnM$1$J$1", "SI_9105$$anonfun$bnM$1", null, null) assertEnclosingMethod("SI_9105$$anonfun$bnM$1$K$2", "SI_9105$$anonfun$bnM$1", "m$4", "()Ljava/lang/Object;") assertEnclosingMethod("SI_9105$$anonfun$bnM$1$L$1", "SI_9105$$anonfun$bnM$1", null, null) - assertAnonymous(ownInnerClassNode("SI_9105$$anonfun$4"), "SI_9105$$anonfun$4") + assertAnonymous(ownInnerClassNode("SI_9105$$anonfun$5"), "SI_9105$$anonfun$5") assertAnonymous(ownInnerClassNode("SI_9105$$anonfun$met$1"), "SI_9105$$anonfun$met$1") - assert(innerClassNodes("SI_9105$$anonfun$4").length == 4) // itself and three of the local classes + assert(innerClassNodes("SI_9105$$anonfun$5").length == 4) // itself and three of the local classes assert(innerClassNodes("SI_9105$$anonfun$met$1").length == 4) // itself and three of the local classes assert(innerClassNodes("SI_9105").length == 4) // the four anon funs } @@ -474,7 +477,7 @@ object Test extends BytecodeTest { testInner("ImplClassesAreTopLevel$B2$1$class", b2) testInner("ImplClassesAreTopLevel$B3$1$class", b3) testInner("ImplClassesAreTopLevel$B4$class", b4) - + testInner("ImplClassesAreTopLevel$B1", b1) testInner("ImplClassesAreTopLevel$B2$1", b2) testInner("ImplClassesAreTopLevel$B3$1", b3) @@ -533,13 +536,13 @@ object Test extends BytecodeTest { "NestedInValueClass$A$lambda$$g$2$1", "NestedInValueClass$A$lambda$$f$extension$1", "NestedInValueClass$A$lambda$$$nestedInAnonfun$13$1", - "NestedInValueClass$A$lambda$$$nestedInAnonfun$15$1").foreach(assertNoEnclosingMethod) + "NestedInValueClass$A$lambda$$NestedInValueClass$A$$$nestedInAnonfun$15$1").foreach(assertNoEnclosingMethod) testInner("NestedInValueClass$A", a, am) testInner("NestedInValueClass$A$", a, am, b, c) testInner("NestedInValueClass$A$lambda$$g$2$1", am) testInner("NestedInValueClass$A$lambda$$f$extension$1", am) testInner("NestedInValueClass$A$lambda$$$nestedInAnonfun$13$1", am) - testInner("NestedInValueClass$A$lambda$$$nestedInAnonfun$15$1", am) + testInner("NestedInValueClass$A$lambda$$NestedInValueClass$A$$$nestedInAnonfun$15$1", am) } else { assertEnclosingMethod("NestedInValueClass$A$$anonfun$g$2$1" , "NestedInValueClass$A" , null, null) assertEnclosingMethod("NestedInValueClass$A$$anonfun$g$2$1$$anonfun$apply$4" , "NestedInValueClass$A$$anonfun$g$2$1" , null, null) diff --git a/test/files/jvm/javaReflection/Classes_1.scala b/test/files/jvm/javaReflection/Classes_1.scala index 11963e2770..e9cd4f756a 100644 --- a/test/files/jvm/javaReflection/Classes_1.scala +++ b/test/files/jvm/javaReflection/Classes_1.scala @@ -13,7 +13,7 @@ class A { trait C object D new T { } - (() => -1) + (() => "-1") def f = { class KB } } @@ -21,21 +21,21 @@ class A { new T { } // anonymous function, not a member - (() => 1) + (() => "1") def f = { class E trait F object G new T { } - (() => 2) + (() => "2") if (new Object().hashCode == 1) { class H trait I object J new T { } - (() => 3) + (() => "3") } else { () } @@ -46,7 +46,7 @@ class A { trait L object M new T { } - (() => 4) + (() => "4") } val x = { @@ -54,7 +54,7 @@ class A { trait O object P new T { } - (() => 5) + (() => "5") } def this(x: Int) { @@ -63,7 +63,7 @@ class A { trait R object S new T { } - (() => () => 5) + (() => () => "5") } } @@ -72,7 +72,7 @@ object AO { trait C object D new T { } - (() => 1) + (() => "1") } trait AT { @@ -80,5 +80,5 @@ trait AT { trait C object D new T { } - (() => 1) + (() => "1") } diff --git a/test/files/jvm/patmat_opt_ignore_underscore.flags b/test/files/jvm/patmat_opt_ignore_underscore.flags index 1182725e86..2cd4b38726 100644 --- a/test/files/jvm/patmat_opt_ignore_underscore.flags +++ b/test/files/jvm/patmat_opt_ignore_underscore.flags @@ -1 +1 @@ --optimize
\ No newline at end of file +-optimize -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/jvm/patmat_opt_no_nullcheck.flags b/test/files/jvm/patmat_opt_no_nullcheck.flags index 1182725e86..2cd4b38726 100644 --- a/test/files/jvm/patmat_opt_no_nullcheck.flags +++ b/test/files/jvm/patmat_opt_no_nullcheck.flags @@ -1 +1 @@ --optimize
\ No newline at end of file +-optimize -Ybackend:GenASM
\ No newline at end of file diff --git a/test/files/jvm/patmat_opt_primitive_typetest.flags b/test/files/jvm/patmat_opt_primitive_typetest.flags index 49d036a887..b9bb09167e 100644 --- a/test/files/jvm/patmat_opt_primitive_typetest.flags +++ b/test/files/jvm/patmat_opt_primitive_typetest.flags @@ -1 +1 @@ --optimize +-optimize -Ybackend:GenASM diff --git a/test/files/jvm/t7006/Foo_1.flags b/test/files/jvm/t7006/Foo_1.flags index 37b2116413..29a9d424f0 100644 --- a/test/files/jvm/t7006/Foo_1.flags +++ b/test/files/jvm/t7006/Foo_1.flags @@ -1 +1 @@ --optimise -Ydebug -Xfatal-warnings +-optimise -Ydebug -Xfatal-warnings -Ybackend:GenASM diff --git a/test/files/neg/inlineMaxSize.check b/test/files/neg/inlineMaxSize.check index d218a8b6e2..9d790e154c 100644 --- a/test/files/neg/inlineMaxSize.check +++ b/test/files/neg/inlineMaxSize.check @@ -2,8 +2,8 @@ inlineMaxSize.scala:7: warning: C::i()I is annotated @inline but could not be in The size of the callsite method C::j()I would exceed the JVM method size limit after inlining C::i()I. - @inline final def j = i + i - ^ + @inline final def j = i + i + i + ^ error: No warnings can be incurred under -Xfatal-warnings. one warning found one error found diff --git a/test/files/neg/inlineMaxSize.scala b/test/files/neg/inlineMaxSize.scala index 16dc0d9538..9d2db1a357 100644 --- a/test/files/neg/inlineMaxSize.scala +++ b/test/files/neg/inlineMaxSize.scala @@ -4,5 +4,5 @@ class C { @inline final def g = f + f + f + f + f + f + f + f + f + f @inline final def h = g + g + g + g + g + g + g + g + g + g @inline final def i = h + h + h + h + h + h + h + h + h + h - @inline final def j = i + i + @inline final def j = i + i + i } diff --git a/test/files/neg/t3234.flags b/test/files/neg/t3234.flags index cc3d9fb6f0..406231bd96 100644 --- a/test/files/neg/t3234.flags +++ b/test/files/neg/t3234.flags @@ -1 +1 @@ --Yinline -Yinline-warnings -Xfatal-warnings +-Yinline -Yinline-warnings -Xfatal-warnings -Ybackend:GenASM diff --git a/test/files/neg/t7623.check b/test/files/neg/t7623.check index db368dd369..de35023664 100644 --- a/test/files/neg/t7623.check +++ b/test/files/neg/t7623.check @@ -1,21 +1,15 @@ -t7623.scala:19: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). - def f = "" match { case X(s) => } +t7623.scala:21: warning: A repeated case parameter or extracted sequence is not matched by a sequence wildcard (_*), and may fail at runtime. + def g = "" match { case X(s, t) => } // warn ^ -t7623.scala:21: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). - def g = "" match { case X(s, t) => } +t7623.scala:23: warning: Sequence wildcard (_*) does not align with repeated case parameter or extracted sequence; the result may be unexpected. + def h = "" match { case X(s, t, u @ _*) => } // warn ^ -t7623.scala:23: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). - def h = "" match { case X(s, t, u @ _*) => } - ^ -t7623.scala:9: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). - def f = C("") match { case C(s) => } - ^ -t7623.scala:11: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). - def g = C("") match { case C(s, t) => } +t7623.scala:11: warning: A repeated case parameter or extracted sequence is not matched by a sequence wildcard (_*), and may fail at runtime. + def g = C("") match { case C(s, t) => } // warn ^ -t7623.scala:13: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). - def h = C("") match { case C(s, t, u @ _*) => } +t7623.scala:13: warning: Sequence wildcard (_*) does not align with repeated case parameter or extracted sequence; the result may be unexpected. + def h = C("") match { case C(s, t, u @ _*) => } // warn ^ error: No warnings can be incurred under -Xfatal-warnings. -6 warnings found +four warnings found one error found diff --git a/test/files/neg/t7623.scala b/test/files/neg/t7623.scala index 5c40f37bc1..5334cc5f69 100644 --- a/test/files/neg/t7623.scala +++ b/test/files/neg/t7623.scala @@ -8,9 +8,9 @@ object X { def unapplySeq(a: Any): Option[(String, Seq[Int])] = Some("", List(1, trait Ctest { def f = C("") match { case C(s) => } - def g = C("") match { case C(s, t) => } + def g = C("") match { case C(s, t) => } // warn - def h = C("") match { case C(s, t, u @ _*) => } + def h = C("") match { case C(s, t, u @ _*) => } // warn def ok = C("") match { case C(s, u @ _*) => } } @@ -18,9 +18,9 @@ trait Ctest { trait Xtest { def f = "" match { case X(s) => } - def g = "" match { case X(s, t) => } + def g = "" match { case X(s, t) => } // warn - def h = "" match { case X(s, t, u @ _*) => } + def h = "" match { case X(s, t, u @ _*) => } // warn def ok = "" match { case X(s, u @ _*) => } } diff --git a/test/files/pos/t9321.scala b/test/files/pos/t9321.scala new file mode 100644 index 0000000000..ed3a816656 --- /dev/null +++ b/test/files/pos/t9321.scala @@ -0,0 +1,10 @@ +object p { + trait A { + private[p] val qualifiedPrivateMember = 1 + } + + def useQualifiedPrivate(b: Mix) = + b.qualifiedPrivateMember // allowed +} + +trait Mix extends p.A diff --git a/test/files/pos/t9356/Foo_2.scala b/test/files/pos/t9356/Foo_2.scala new file mode 100644 index 0000000000..ab7bb44d0e --- /dev/null +++ b/test/files/pos/t9356/Foo_2.scala @@ -0,0 +1,6 @@ +class C + +trait Foo { + @annot.MyAnnotation(cls = classOf[C]) + def function: Any = ??? +} diff --git a/test/files/pos/t9356/MyAnnotation.java b/test/files/pos/t9356/MyAnnotation.java new file mode 100644 index 0000000000..b6c00e7356 --- /dev/null +++ b/test/files/pos/t9356/MyAnnotation.java @@ -0,0 +1,12 @@ +package annot; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface MyAnnotation { + Class<?> cls(); +} diff --git a/test/files/pos/t9356/Test_3.scala b/test/files/pos/t9356/Test_3.scala new file mode 100644 index 0000000000..fa1b76c9e1 --- /dev/null +++ b/test/files/pos/t9356/Test_3.scala @@ -0,0 +1,3 @@ +class Foo1 extends Foo + +class Foo2 extends Foo
\ No newline at end of file diff --git a/test/files/run/private-inline.flags b/test/files/run/private-inline.flags index 00d3643fd4..c550fdce16 100644 --- a/test/files/run/private-inline.flags +++ b/test/files/run/private-inline.flags @@ -1 +1 @@ --optimise -Yinline-warnings +-optimise -Yinline-warnings -Ybackend:GenASM diff --git a/test/files/run/range.scala b/test/files/run/range.scala index 4637ab874d..e50d0ac6a5 100644 --- a/test/files/run/range.scala +++ b/test/files/run/range.scala @@ -36,16 +36,19 @@ object Test { def gr1 = NumericRange(x, x, x) def gr2 = NumericRange.inclusive(x, x, x) - def gr3 = NumericRange(x, x * fromInt(10), x) - def gr4 = NumericRange.inclusive(x, x * fromInt(10), x) - def gr5 = gr3.toList ::: negated.gr3.toList + def gr3 = NumericRange(x, x * fromInt(4), x * fromInt(2)) // SI-9348 + def gr4 = NumericRange(x, x * fromInt(-2), x * fromInt(-2)) + def gr5 = NumericRange(x, x * fromInt(10), x) + def gr6 = NumericRange.inclusive(x, x * fromInt(10), x) + def gr7 = gr3.toList ::: negated.gr3.toList def check = { assert(gr1.isEmpty && !gr2.isEmpty) - assert(gr3.size == 9 && gr4.size == 10) - assert(gr5.sum == num.zero, gr5.toString) - assert(!(gr3 contains (x * fromInt(10)))) - assert((gr4 contains (x * fromInt(10)))) + assert(gr3.size == 2 && gr4.size == 2) + assert(gr5.size == 9 && gr6.size == 10) + assert(gr7.sum == num.zero, gr7.toString) + assert(!(gr5 contains (x * fromInt(10)))) + assert(gr6 contains (x * fromInt(10))) } } @@ -55,6 +58,7 @@ object Test { val _grs = List[GR[_]]( GR(BigDecimal(5.0)), + GR(BigDecimal(0.25)), // SI-9348 GR(BigInt(5)), GR(5L), GR(5.0d), diff --git a/test/files/run/repl-serialization.check b/test/files/run/repl-serialization.check new file mode 100644 index 0000000000..eb62729f5c --- /dev/null +++ b/test/files/run/repl-serialization.check @@ -0,0 +1,25 @@ +== evaluating lines +extract: AnyRef => Unit = <function1> + evaluating x +x: Int = 0 +getX: ()Int +defined class U +y: Int = <lazy> + evaluating z + evaluating zz +defined class D +z: Int = 0 +zz: Int = 0 +defined object O +defined class A +defined type alias AA +constructing U +u: U = U +== evaluating lambda + evaluating y + evaluating O + constructing A +== reconstituting into a fresh classloader + evaluating O +== evaluating reconstituted lambda + constructing A diff --git a/test/files/run/repl-serialization.scala b/test/files/run/repl-serialization.scala new file mode 100644 index 0000000000..55b7519631 --- /dev/null +++ b/test/files/run/repl-serialization.scala @@ -0,0 +1,68 @@ +import java.io._ + +import scala.reflect.io.AbstractFile +import scala.tools.nsc.Settings +import scala.tools.nsc.interpreter.IMain +import scala.tools.nsc.util._ +import scala.reflect.internal.util.AbstractFileClassLoader + +object Test { + def main(args: Array[String]) { + run() + } + + def run(): Unit = { + val settings = new Settings() + settings.Yreplclassbased.value = true + settings.usejavacp.value = true + + var imain: IMain = null + object extract extends ((AnyRef) => Unit) with Serializable { + var value: AnyRef = null + + def apply(a: AnyRef) = value = a + } + + val code = + """val x = {println(" evaluating x"); 0 } + |def getX() = x + |class U extends Serializable { println("constructing U"); val x = 0 ; override def toString = "U" } + |lazy val y = {println(" evaluating y"); 0 } + |class D; val z = {println(" evaluating z"); 0}; val zz = {println(" evaluating zz"); 0} + |object O extends Serializable { val apply = {println(" evaluating O"); 0} } + |class A(i: Int) { println(" constructing A") } + |type AA = A + |val u = new U() + |extract(() => new AA(x + getX() + y + z + zz + O.apply + u.x)) + """.stripMargin + + imain = new IMain(settings) + println("== evaluating lines") + imain.directBind("extract", "(AnyRef => Unit)", extract) + code.lines.foreach(imain.interpret) + + val virtualFile: AbstractFile = extract.value.getClass.getClassLoader.asInstanceOf[AbstractFileClassLoader].root + val newLoader = new AbstractFileClassLoader(virtualFile, getClass.getClassLoader) + + def deserializeInNewLoader(string: Array[Byte]): AnyRef = { + val bis = new ByteArrayInputStream(string) + val in = new ObjectInputStream(bis) { + override def resolveClass(desc: ObjectStreamClass) = Class.forName(desc.getName, false, newLoader) + } + in.readObject() + } + def serialize(o: AnyRef): Array[Byte] = { + val bos = new ByteArrayOutputStream() + val out = new ObjectOutputStream(bos) + out.writeObject(o) + out.close() + bos.toByteArray + } + println("== evaluating lambda") + extract.value.asInstanceOf[() => Any].apply() + println("== reconstituting into a fresh classloader") + val reconstituted = deserializeInNewLoader(serialize(extract.value)).asInstanceOf[() => Any] + println("== evaluating reconstituted lambda") + reconstituted.apply() // should not print("evaluating x") a second time + } +} diff --git a/test/files/run/synchronized.check b/test/files/run/synchronized.check index 9add05ea0c..dd9f4ef424 100644 --- a/test/files/run/synchronized.check +++ b/test/files/run/synchronized.check @@ -1,8 +1,3 @@ -#partest !-Ybackend:GenBCode -warning: there were 14 inliner warnings; re-run with -Yinline-warnings for details -#partest -Ybackend:GenBCode -warning: there were 14 inliner warnings; re-run with -Yopt-warnings for details -#partest .|. c1.f1: OK .|. c1.fi: OK .|... c1.fv: OK diff --git a/test/files/run/synchronized.scala b/test/files/run/synchronized.scala index 1f0e32992b..077e9d02e8 100644 --- a/test/files/run/synchronized.scala +++ b/test/files/run/synchronized.scala @@ -1,3 +1,6 @@ +/* + * filter: inliner warnings; re-run with + */ import java.lang.Thread.holdsLock import scala.collection.mutable.StringBuilder diff --git a/test/files/run/t6102.check b/test/files/run/t6102.check index aa3e6cc9e2..07378f5ed4 100644 --- a/test/files/run/t6102.check +++ b/test/files/run/t6102.check @@ -28,5 +28,10 @@ [running phase constopt on t6102.scala] #partest [running phase dce on t6102.scala] +#partest !-Ybackend:GenBCode [running phase jvm on icode] +#partest -Ybackend:GenBCode +[running phase jvm on t6102.scala] +[running phase jvm on t6102.scala] +#partest hello diff --git a/test/files/run/t7747-repl.check b/test/files/run/t7747-repl.check index 105b238d01..5f436ba6b1 100644 --- a/test/files/run/t7747-repl.check +++ b/test/files/run/t7747-repl.check @@ -112,7 +112,7 @@ scala> 55 ; ((2 + 2)) ; (1, 2, 3) res15: (Int, Int, Int) = (1,2,3) scala> 55 ; (x: Int) => x + 1 ; () => ((5)) -<console>:8: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses +<console>:9: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses 55 ; (x: Int) => x + 1 ;; ^ res16: () => Int = <function0> @@ -258,12 +258,12 @@ class $read extends Serializable { super.<init>; () }; - import $line44.$read.$iw.$iw.BippyBups; - import $line44.$read.$iw.$iw.BippyBups; - import $line45.$read.$iw.$iw.PuppyPups; - import $line45.$read.$iw.$iw.PuppyPups; - import $line46.$read.$iw.$iw.Bingo; - import $line46.$read.$iw.$iw.Bingo; + import $line44.$read.INSTANCE.$iw.$iw.BippyBups; + import $line44.$read.INSTANCE.$iw.$iw.BippyBups; + import $line45.$read.INSTANCE.$iw.$iw.PuppyPups; + import $line45.$read.INSTANCE.$iw.$iw.PuppyPups; + import $line46.$read.INSTANCE.$iw.$iw.Bingo; + import $line46.$read.INSTANCE.$iw.$iw.Bingo; class $iw extends Serializable { def <init>() = { super.<init>; @@ -275,12 +275,35 @@ class $read extends Serializable { }; val $iw = new $iw.<init> } -object $read extends $read { +object $read extends scala.AnyRef { def <init>() = { super.<init>; () - } + }; + val INSTANCE = new $read.<init> } res3: List[Product with Serializable] = List(BippyBups(), PuppyPups(), Bingo()) +scala> case class Sum(exp: String, exp2: String) +defined class Sum + +scala> val a = Sum("A", "B") +a: Sum = Sum(A,B) + +scala> def b(a: Sum): String = a match { case Sum(_, _) => "Found Sum" } +b: (a: Sum)String + +scala> b(a) +res4: String = Found Sum + +scala> :power +** Power User mode enabled - BEEP WHIR GYVE ** +** :phase has been set to 'typer'. ** +** scala.tools.nsc._ has been imported ** +** global._, definitions._ also imported ** +** Try :help, :vals, power.<tab> ** + +scala> intp.lastRequest +res5: $r.intp.Request = Request(line=def $ires3 = intp.global, 1 trees) + scala> :quit diff --git a/test/files/run/t7747-repl.scala b/test/files/run/t7747-repl.scala index 0e64210460..141c2d9844 100644 --- a/test/files/run/t7747-repl.scala +++ b/test/files/run/t7747-repl.scala @@ -65,5 +65,11 @@ object Test extends ReplTest { |case class PuppyPups() |case class Bingo() |List(BippyBups(), PuppyPups(), Bingo()) // show + |case class Sum(exp: String, exp2: String) + |val a = Sum("A", "B") + |def b(a: Sum): String = a match { case Sum(_, _) => "Found Sum" } + |b(a) + |:power + |intp.lastRequest |""".stripMargin } diff --git a/test/files/run/t8601-closure-elim.flags b/test/files/run/t8601-closure-elim.flags index 2b5fd8a7b2..9158076b71 100644 --- a/test/files/run/t8601-closure-elim.flags +++ b/test/files/run/t8601-closure-elim.flags @@ -1 +1 @@ --optimize -Ydelambdafy:inline +-optimize -Ydelambdafy:inline -Ybackend:GenASM diff --git a/test/files/run/toolbox-varargs/Test.scala b/test/files/run/toolbox-varargs/Test.scala new file mode 100644 index 0000000000..be5ab45768 --- /dev/null +++ b/test/files/run/toolbox-varargs/Test.scala @@ -0,0 +1,13 @@ +object Test { + def main(args: Array[String]): Unit = { + import scala.tools.reflect.ToolBox + val m = reflect.runtime.currentMirror + val u = m.universe + import u._ + val tb = m.mkToolBox(); + tb.compile(q"new p.Varargs(null, null)") + tb.compile(q"p.Varargs.staticMethod(null, null)") + tb.compile(q"(null: p.Varargs).instanceMethod(null, null)") + } +} + diff --git a/test/files/run/toolbox-varargs/Varargs.java b/test/files/run/toolbox-varargs/Varargs.java new file mode 100644 index 0000000000..da1dbbacc9 --- /dev/null +++ b/test/files/run/toolbox-varargs/Varargs.java @@ -0,0 +1,8 @@ +package p; + +public class Varargs { + public Varargs(String... args) {} + public static void staticMethod(String... args) {} + + public void instanceMethod(String... args) {} +} diff --git a/test/junit/scala/collection/IteratorTest.scala b/test/junit/scala/collection/IteratorTest.scala index d5389afd0c..1c1e50aed9 100644 --- a/test/junit/scala/collection/IteratorTest.scala +++ b/test/junit/scala/collection/IteratorTest.scala @@ -154,4 +154,14 @@ class IteratorTest { results += (Stream from 1).toIterator.drop(10).toStream.drop(10).toIterator.next() assertSameElements(List(1,1,21), results) } + // SI-9332 + @Test def spanExhaustsLeadingIterator(): Unit = { + def it = Iterator.iterate(0)(_ + 1).take(6) + val (x, y) = it.span(_ != 1) + val z = x.toList + assertEquals(1, z.size) + assertFalse(x.hasNext) + assertEquals(1, y.next) + assertFalse(x.hasNext) // was true, after advancing underlying iterator + } } diff --git a/test/junit/scala/collection/immutable/RangeConsistencyTest.scala b/test/junit/scala/collection/immutable/RangeConsistencyTest.scala index 3980c31577..135796979d 100644 --- a/test/junit/scala/collection/immutable/RangeConsistencyTest.scala +++ b/test/junit/scala/collection/immutable/RangeConsistencyTest.scala @@ -137,4 +137,15 @@ class RangeConsistencyTest { assert( (-3 to Int.MaxValue).dropWhile(_ <= 0).length == Int.MaxValue ) assert( (-3 to Int.MaxValue).span(_ <= 0) match { case (a,b) => a.length == 4 && b.length == Int.MaxValue } ) } + + @Test + def testSI9348() { + // Test exclusive range with (end-start) != 0 (mod step) + assert( (0.0f until 0.4f by 0.25f) sameElements List(0.0f, 0.25f) ) + assert( (1.0 until 2.2 by 0.5) sameElements List(1.0, 1.5, 2.0) ) + + def bd(d: Double) = BigDecimal(d) + val bdRange = bd(-10.0) until bd(0.0) by bd(4.5) + assert( bdRange sameElements List(bd(-10.0), bd(-5.5), bd(-1.0)) ) + } } diff --git a/test/junit/scala/math/BigDecimalTest.scala b/test/junit/scala/math/BigDecimalTest.scala index c7a63da890..a9e2481f37 100644 --- a/test/junit/scala/math/BigDecimalTest.scala +++ b/test/junit/scala/math/BigDecimalTest.scala @@ -228,4 +228,36 @@ class BigDecimalTest { def test_SI8970() { assert((0.1).## == BigDecimal(0.1).##) } + + // Motivated by the problem of MathContext lost + @Test + def testMathContext() { + def testPrecision() { + val p = 1000 + val n = BigDecimal("1.1", MC.UNLIMITED).pow(p) + + // BigDecimal(x: Float, mc: MC), which may not do what you want, is deprecated + assert(BigDecimal(1.1f, MC.UNLIMITED).pow(p) == BigDecimal(java.lang.Double.toString(1.1f.toDouble), MC.UNLIMITED).pow(p)) + assert(BigDecimal(1.1d, MC.UNLIMITED).pow(p) == n) + assert(BigDecimal(new BD("1.1"), MC.UNLIMITED).pow(p) == n) + + assert(BigDecimal.decimal(1.1f, MC.UNLIMITED).pow(p) == n) + assert(BigDecimal.decimal(1.1d, MC.UNLIMITED).pow(p) == n) + assert(BigDecimal.decimal(new BD("1.1"), MC.UNLIMITED).pow(p) == n) + + assert((BigDecimal(11, MC.UNLIMITED) / 10).pow(p) == n) + assert((BigDecimal.decimal(11, MC.UNLIMITED) / 10).pow(p) == n) + } + + def testRounded() { + // the default rounding mode is HALF_UP + assert((BigDecimal(1.23f, new MC(3)) + BigDecimal("0.005")).rounded == BigDecimal("1.24")) // deprecated api + assert((BigDecimal(1.23d, new MC(3)) + BigDecimal("0.005")).rounded == BigDecimal("1.24")) + assert((BigDecimal.decimal(1.23f, new MC(3)) + BigDecimal("0.005")).rounded == BigDecimal("1.24")) + assert((BigDecimal.decimal(1.23d, new MC(3)) + BigDecimal("0.005")).rounded == BigDecimal("1.24")) + } + + testPrecision() + testRounded() + } } diff --git a/test/junit/scala/math/NumericTest.scala b/test/junit/scala/math/NumericTest.scala index 9bf7d4f1e4..682dcbfd75 100644 --- a/test/junit/scala/math/NumericTest.scala +++ b/test/junit/scala/math/NumericTest.scala @@ -5,6 +5,9 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import scala.math.Numeric.FloatAsIfIntegral + + @RunWith(classOf[JUnit4]) class NumericTest { @@ -14,5 +17,28 @@ class NumericTest { assertTrue(-0.0.abs equals 0.0) assertTrue(-0.0f.abs equals 0.0f) } -} + + /* Test for SI-9348 */ + @Test + def testFloatAsIfIntegral { + val num = scala.math.Numeric.FloatAsIfIntegral + assertTrue(num.quot(1.0f, 0.5f) equals 2.0f) + assertTrue(num.quot(1.0f, 0.3f) equals 3.0f) + } + + /* Test for SI-9348 */ + @Test + def testDoubleAsIfIntegral { + val num = scala.math.Numeric.DoubleAsIfIntegral + assertTrue(num.quot(1.0, 0.25) equals 4.0) + assertTrue(num.quot(0.5, 0.15) equals 3.0) + } + + /* Test for SI-9348 */ + @Test + def testBigDecimalAsIfIntegral { + val num = scala.math.Numeric.BigDecimalAsIfIntegral + assertTrue(num.quot(BigDecimal(2.5), BigDecimal(0.5)) equals BigDecimal(5.0)) + assertTrue(num.quot(BigDecimal(5.0), BigDecimal(2.0)) equals BigDecimal(2.0)) + }} diff --git a/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala new file mode 100644 index 0000000000..3a85f03da2 --- /dev/null +++ b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala @@ -0,0 +1,231 @@ +package scala.tools.nsc +package backend.jvm +package analysis + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import scala.tools.asm.Opcodes._ +import org.junit.Assert._ + +import CodeGenTools._ +import scala.tools.asm.tree.{AbstractInsnNode, MethodNode} +import scala.tools.nsc.backend.jvm.BTypes._ +import scala.tools.partest.ASMConverters +import ASMConverters._ +import scala.tools.testing.ClearAfterClass +import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._ +import AsmUtils._ + +import scala.collection.convert.decorateAsScala._ + +object NullnessAnalyzerTest extends ClearAfterClass.Clearable { + var noOptCompiler = newCompiler(extraArgs = "-Ybackend:GenBCode -Yopt:l:none") + + def clear(): Unit = { + noOptCompiler = null + } +} + +@RunWith(classOf[JUnit4]) +class NullnessAnalyzerTest extends ClearAfterClass { + ClearAfterClass.stateToClear = NullnessAnalyzerTest + val noOptCompiler = NullnessAnalyzerTest.noOptCompiler + + def newNullnessAnalyzer(methodNode: MethodNode, classInternalName: InternalName = "C"): NullnessAnalyzer = { + val nullnessAnalyzer = new NullnessAnalyzer + nullnessAnalyzer.analyze(classInternalName, methodNode) + nullnessAnalyzer + } + + /** + * Instructions that match `query` when textified. + * If `query` starts with a `+`, the next instruction is returned. + */ + def findInstr(method: MethodNode, query: String): List[AbstractInsnNode] = { + val useNext = query(0) == '+' + val instrPart = if (useNext) query.drop(1) else query + val insns = method.instructions.iterator.asScala.find(i => textify(i) contains instrPart).toList + if (useNext) insns.map(_.getNext) else insns + } + + def testNullness(analyzer: NullnessAnalyzer, method: MethodNode, query: String, index: Int, nullness: Nullness): Unit = { + for (i <- findInstr(method, query)) { + val r = analyzer.frameAt(i, method).getValue(index).nullness + assertTrue(s"Expected: $nullness, found: $r. At instr ${textify(i)}", nullness == r) + } + } + + // debug / helper for writing tests + def showAllNullnessFrames(analyzer: NullnessAnalyzer, method: MethodNode): String = { + val instrLength = method.instructions.iterator.asScala.map(textify(_).length).max + val lines = for (i <- method.instructions.iterator.asScala) yield { + val f = analyzer.frameAt(i, method) + val frameString = { + if (f == null) "null" + else (0 until (f.getLocals + f.getStackSize)).iterator + .map(f.getValue(_).toString) + .map(s => "%8s".format(s)) + .zipWithIndex.map({case (s, i) => s"$i: $s"}) + .mkString(", ") + } + ("%"+ instrLength +"s: %s").format(textify(i), frameString) + } + lines.mkString("\n") + } + + @Test + def showNullnessFramesTest(): Unit = { + val List(m) = compileMethods(noOptCompiler)("def f = this.toString") + + // NOTE: the frame for an instruction represents the state *before* executing that instr. + // So in the frame for `ALOAD 0`, the stack is still empty. + + val res = + """ L0: 0: NotNull + | LINENUMBER 1 L0: 0: NotNull + | ALOAD 0: 0: NotNull + |INVOKEVIRTUAL java/lang/Object.toString ()Ljava/lang/String;: 0: NotNull, 1: NotNull + | ARETURN: 0: NotNull, 1: Unknown1 + | L0: null""".stripMargin + assertEquals(showAllNullnessFrames(newNullnessAnalyzer(m), m), res) + } + + @Test + def thisNonNull(): Unit = { + val List(m) = compileMethods(noOptCompiler)("def f = this.toString") + val a = newNullnessAnalyzer(m) + testNullness(a, m, "ALOAD 0", 0, NotNull) + } + + @Test + def instanceMethodCall(): Unit = { + val List(m) = compileMethods(noOptCompiler)("def f(a: String) = a.trim") + val a = newNullnessAnalyzer(m) + testNullness(a, m, "INVOKEVIRTUAL java/lang/String.trim", 1, Unknown) + testNullness(a, m, "ARETURN", 1, NotNull) + } + + @Test + def constructorCall(): Unit = { + val List(m) = compileMethods(noOptCompiler)("def f = { val a = new Object; a.toString }") + val a = newNullnessAnalyzer(m) + + // for reference, the output of showAllNullnessFrames(a, m) - note that the frame represents the state *before* executing the instr. + // NEW java/lang/Object: 0: NotNull, 1: Unknown + // DUP: 0: NotNull, 1: Unknown, 2: Unknown + // INVOKESPECIAL java/lang/Object.<init>: 0: NotNull, 1: Unknown, 2: Unknown, 3: Unknown + // ASTORE 1: 0: NotNull, 1: Unknown, 2: NotNull + // ALOAD 1: 0: NotNull, 1: NotNull + // INVOKEVIRTUAL java/lang/Object.toString: 0: NotNull, 1: NotNull, 2: NotNull + // ARETURN: 0: NotNull, 1: NotNull, 2: Unknown + + for ((insn, index, nullness) <- List( + ("+NEW", 2, Unknown), // new value at slot 2 on the stack + ("+DUP", 3, Unknown), + ("+INVOKESPECIAL java/lang/Object", 2, NotNull), // after calling the initializer on 3, the value at 2 becomes NotNull + ("ASTORE 1", 1, Unknown), // before the ASTORE 1, nullness of the value in local 1 is Unknown + ("+ASTORE 1", 1, NotNull), // after storing the value at 2 in local 1, the local 1 is NotNull + ("+ALOAD 1", 2, NotNull), // loading the value 1 puts a NotNull value on the stack (at 2) + ("+INVOKEVIRTUAL java/lang/Object.toString", 2, Unknown) // nullness of value returned by `toString` is Unknown + )) testNullness(a, m, insn, index, nullness) + } + + @Test + def explicitNull(): Unit = { + val List(m) = compileMethods(noOptCompiler)("def f = { var a: Object = null; a }") + val a = newNullnessAnalyzer(m) + for ((insn, index, nullness) <- List( + ("+ACONST_NULL", 2, Null), + ("+ASTORE 1", 1, Null), + ("+ALOAD 1", 2, Null) + )) testNullness(a, m, insn, index, nullness) + } + + @Test + def stringLiteralsNotNull(): Unit = { + val List(m) = compileMethods(noOptCompiler)("""def f = { val a = "hi"; a.trim }""") + val a = newNullnessAnalyzer(m) + testNullness(a, m, "+ASTORE 1", 1, NotNull) + } + + @Test + def newArraynotNull() { + val List(m) = compileMethods(noOptCompiler)("def f = { val a = new Array[Int](2); a(0) }") + val a = newNullnessAnalyzer(m) + testNullness(a, m, "+NEWARRAY T_INT", 2, NotNull) // new array on stack + testNullness(a, m, "+ASTORE 1", 1, NotNull) // local var (a) + } + + @Test + def aliasBranching(): Unit = { + val code = + """def f(o: Object) = { + | var a: Object = o // a and o are aliases + | var b: Object = null + | var c: Object = null + | var d: Object = o + | if ("".trim == "") { + | b = o + | c = o // a, o, b, aliases + | d = null + | } else { + | b = a // a, o, b aliases + | d = null + | } + | b.toString // a, o, b aliases (so they become NotNull), but not c + | // d is null here, assinged in both branches. + |} + """.stripMargin + val List(m) = compileMethods(noOptCompiler)(code) + val a = newNullnessAnalyzer(m) + + val trim = "INVOKEVIRTUAL java/lang/String.trim" + val toSt = "INVOKEVIRTUAL java/lang/Object.toString" + val end = s"+$toSt" + for ((insn, index, nullness) <- List( + (trim, 0, NotNull), // this + (trim, 1, Unknown), // parameter o + (trim, 2, Unknown), // a + (trim, 3, Null), // b + (trim, 4, Null), // c + (trim, 5, Unknown), // d + + (toSt, 2, Unknown), // a, still the same + (toSt, 3, Unknown), // b, was re-assinged in both branches to Unknown + (toSt, 4, Unknown), // c, was re-assigned in one branch to Unknown + (toSt, 5, Null), // d, was assigned to null in both branches + + (end, 2, NotNull), // a, NotNull (alias of b) + (end, 3, NotNull), // b, receiver of toString + (end, 4, Unknown), // c, no change (not an alias of b) + (end, 5, Null) // d, no change + )) testNullness(a, m, insn, index, nullness) + } + + @Test + def testInstanceOf(): Unit = { + val code = + """def f(a: Object) = { + | val x = a + | x.isInstanceOf[Throwable] // x and a remain unknown - INSTANCEOF doesn't throw a NPE on null + | x.toString // x and a are not null + | a.asInstanceOf[String].trim // the stack value (LOAD of local a) is still not-null after the CHECKCAST + |} + """.stripMargin + val List(m) = compileMethods(noOptCompiler)(code) + val a = newNullnessAnalyzer(m) + + val instof = "+INSTANCEOF" + val tost = "+INVOKEVIRTUAL java/lang/Object.toString" + val trim = "INVOKEVIRTUAL java/lang/String.trim" + + for ((insn, index, nullness) <- List( + (instof, 1, Unknown), // a after INSTANCEOF + (instof, 2, Unknown), // x after INSTANCEOF + (tost, 1, NotNull), + (tost, 2, NotNull), + (trim, 3, NotNull) // receiver at `trim` + )) testNullness(a, m, insn, index, nullness) + } +} diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala index 0fc3601603..b8c5f85c49 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala @@ -975,4 +975,20 @@ class InlinerTest extends ClearAfterClass { val List(c) = compile(code) assertInvoke(getSingleMethod(c, "t"), "java/lang/Error", "<init>") } + + @Test + def noRedunantNullChecks(): Unit = { + val code = + """class C { + | @inline final def f: String = "hai!" + | def t(c: C) = {c.f; c.f} // null check on the first, but not the second + |} + """.stripMargin + + val List(c) = compile(code) + val t = getSingleMethod(c, "t").instructions + assertNoInvoke(t) + assert(2 == t.collect({case Ldc(_, "hai!") => }).size) // twice the body of f + assert(1 == t.collect({case Jump(IFNONNULL, _) => }).size) // one single null check + } } diff --git a/test/junit/scala/util/SortingTest.scala b/test/junit/scala/util/SortingTest.scala new file mode 100644 index 0000000000..15a00c8903 --- /dev/null +++ b/test/junit/scala/util/SortingTest.scala @@ -0,0 +1,69 @@ +package scala.util + +import org.junit.Test +import org.junit.Assert._ +import scala.math.{ Ordered, Ordering } +import scala.reflect.ClassTag + +class SortingTest { + case class N(i: Int, j: Int) extends Ordered[N] { def compare(n: N) = if (i < n.i) -1 else if (i > n.i) 1 else 0 } + + def mkA(n: Int, max: Int) = Array.tabulate(n)(i => N(util.Random.nextInt(max), i)) + + def isStable(a: Array[N]): Boolean = { var i = 1; while (i < a.length) { if (a(i).i < a(i-1).i || (a(i).i == a(i-1).i && a(i).j < a(i-1).j)) return false; i += 1 }; true } + + def isAntistable(a: Array[N]): Boolean = + { var i = 1; while (i < a.length) { if (a(i).i > a(i-1).i || (a(i).i == a(i-1).i && a(i).j < a(i-1).j)) return false; i += 1 }; true } + + def isSorted(a: Array[N]): Boolean = { var i = 1; while (i < a.length) { if (a(i).i < a(i-1).i) return false; i += 1 }; true } + + def isAntisorted(a: Array[N]): Boolean = { var i = 1; while (i < a.length) { if (a(i).i > a(i-1).i) return false; i += 1 }; true } + + val sizes = Seq.range(0, 65) ++ Seq(256, 1024, 9121, 65539) + val variety = Seq(1, 2, 10, 100, 1000, Int.MaxValue) + val workLimit = 1e6 + val rng = new util.Random(198571) + + val backwardsN = Ordering by ((n: N) => -n.i) + + def runOneTest(size: Int, variety: Int): Unit = { + val xs = Array.tabulate(size)(i => N(rng.nextInt(variety), i)) + val ys = Array.range(0, xs.length) + val zs = { val temp = xs.clone; java.util.Arrays.sort(temp, new java.util.Comparator[N] { def compare(a: N, b: N) = a.compare(b) }); temp } + val qxs = { val temp = xs.clone; Sorting.quickSort(temp); temp } + val pxs = { val temp = xs.clone; Sorting.quickSort(temp)(backwardsN); temp } + val sxs = { val temp = xs.clone; Sorting.stableSort(temp); temp } + val rxs = { val temp = xs.clone; Sorting.stableSort(temp)(implicitly[ClassTag[N]], backwardsN); temp } + val sys = Sorting.stableSort(ys.clone: Seq[Int], (i: Int) => xs(i)) + + assertTrue("Quicksort should be in order", isSorted(qxs)) + assertTrue("Quicksort should be in reverse order", isAntisorted(pxs)) + assertTrue("Stable sort should be sorted and stable", isStable(sxs)) + assertTrue("Stable sort should be reverse sorted but stable", isAntistable(rxs)) + assertTrue("Stable sorting by proxy should produce sorted stable list", isStable(sys.map(i => xs(i)))) + assertTrue("Quicksort should produce canonical ordering", (qxs zip zs).forall{ case (a,b) => a.i == b.i }) + assertTrue("Reverse quicksort should produce canonical ordering", (pxs.reverse zip zs).forall{ case (a,b) => a.i == b.i }) + assertTrue("Stable sort should produce exact ordering", (sxs zip zs).forall{ case (a,b) => a == b }) + assertTrue("Reverse stable sort should produce canonical ordering", (rxs.reverse zip zs).forall{ case (a,b) => a.i == b.i }) + assertTrue("Proxy sort and direct sort should produce exactly the same thing", (sxs zip sys.map(i => xs(i))).forall{ case (a,b) => a == b }) + } + + @Test def testSortConsistency: Unit = { + for { + size <- sizes + v <- variety + i <- 0 until math.min(100, math.max(math.min(math.floor(math.pow(v, size)/2), math.ceil(workLimit / (math.log(math.max(2,size))/math.log(2) * size))), 1).toInt) + } runOneTest(size, v) + + for (size <- sizes) { + val b = Array.fill(size)(rng.nextBoolean) + val bfwd = Sorting.stableSort(b.clone: Seq[Boolean]) + val bbkw = Sorting.stableSort(b.clone: Seq[Boolean], (x: Boolean, y: Boolean) => x && !y) + assertTrue("All falses should be first", bfwd.dropWhile(_ == false).forall(_ == true)) + assertTrue("All falses should be last when sorted backwards", bbkw.dropWhile(_ == true).forall(_ == false)) + assertTrue("Sorting booleans should preserve the number of trues", b.count(_ == true) == bfwd.count(_ == true)) + assertTrue("Backwards sorting booleans should preserve the number of trues", b.count(_ == true) == bbkw.count(_ == true)) + assertTrue("Sorting should not change the sizes of arrays", b.length == bfwd.length && b.length == bbkw.length) + } + } +} diff --git a/test/scaladoc/run/SI-8210.check b/test/scaladoc/run/SI-8210.check new file mode 100644 index 0000000000..619c56180b --- /dev/null +++ b/test/scaladoc/run/SI-8210.check @@ -0,0 +1 @@ +Done. diff --git a/test/scaladoc/run/SI-8210.scala b/test/scaladoc/run/SI-8210.scala new file mode 100644 index 0000000000..3bd818473f --- /dev/null +++ b/test/scaladoc/run/SI-8210.scala @@ -0,0 +1,24 @@ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + override def code = """ +object Foo { + trait Config { + /** The bar obviously. */ + def bar: Int + } + class ConfigBuilder extends Config { + /** @inheritdoc + * + * The default value is 1234. + */ + var bar: Int = 1234 + } +} + """ + + def scaladocSettings = "" + + def testModel(root: Package) = () +} |