From 4e4709a3b0dd869b98c1a8d854f4a54145ade2ff Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 25 Nov 2015 14:53:50 +1000 Subject: SI-9567 Fix latent bugs in patmat's reasoning about mutability Under -optimize, the pattern matcher tries to avoid local variables in favour of directly accessing to non-var case class accessors. However, the code that analysed the patterns failed to account properly for repeated parameters, which could either lead to a compiler crash (when assuming that the n-th subpattern must have a corresponding param accessor), or could lead to a correctness problem (when failing to eagerly the bound elements from the sequence.) The test case that tried to cover seems only to have been working because of a separate bug (the primary subject of SI-9567) related to method-local case classes: they were treated during typechecking as extractors, rather than native case classes. The subsequent commit will fix that problem, but first we must pave the way with this commit that emits local vals for bound elements of case class repeated params. --- test/files/run/t9567c.scala | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 test/files/run/t9567c.scala (limited to 'test/files') diff --git a/test/files/run/t9567c.scala b/test/files/run/t9567c.scala new file mode 100644 index 0000000000..560bea8821 --- /dev/null +++ b/test/files/run/t9567c.scala @@ -0,0 +1,29 @@ +case class CaseSequenceTopLevel(as: Int*) + +object Test { + def main(args: Array[String]): Unit = { + + val buffer1 = collection.mutable.Buffer(0, 0) + CaseSequenceTopLevel(buffer1: _*) match { + case CaseSequenceTopLevel(_, i) => + buffer1(1) = 1 + assert(i == 0, i) // fails in 2.11.7 -optimize + } + + case class CaseSequence(as: Int*) + val buffer2 = collection.mutable.Buffer(0, 0) + CaseSequence(buffer2: _*) match { + case CaseSequence(_, i) => + buffer2(1) = 1 + assert(i == 0, i) + } + + case class CaseSequenceWithVar(var x: Any, as: Int*) + val buffer3 = collection.mutable.Buffer(0, 0) + CaseSequenceWithVar("", buffer3: _*) match { + case CaseSequenceWithVar(_, _, i) => // crashes in 2.11.7 + buffer2(1) = 1 + assert(i == 0, i) + } + } +} -- cgit v1.2.3 From e07d62cdefd5b01734692fc549521e562984ccb0 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 25 Nov 2015 14:53:50 +1000 Subject: SI-9567 Fix pattern match on 23+ param, method local case class Typechecking constructor patterns of method local case classes was only working because of the existence of the unapply method in the companion, which is used if navigation to the case class companion object fails. We now support defintion of, and pattern matching on, case classes with more than 22 parameters. These have no `unapply` method in the companion, as we don't have a large enough tuple type to return. So for such case classes, the fallback that we inadvertently relied on would no longer save us, and we'd end up with a compile error advising that the identifier in the constructor pattern was neither a case class nor an extractor. This is due to the propensity of `Symbol#companionXxx` to return `NoSymbol` when in the midst of typechecking. That method should only be relied upon after typechecking. During typechecking, `Namers#companionSymbolOf` should be used instead, which looks in the scopes of enclosing contexts for symbol companionship. That's what I've done in this commit. --- .../scala/tools/nsc/typechecker/PatternTypers.scala | 2 +- test/files/run/t9567.scala | 18 ++++++++++++++++++ test/files/run/t9567b.scala | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 test/files/run/t9567.scala create mode 100644 test/files/run/t9567b.scala (limited to 'test/files') diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala index a702b3cdf5..f90e61ff92 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala @@ -79,7 +79,7 @@ trait PatternTypers { // do not update the symbol if the tree's symbol's type does not define an unapply member // (e.g. since it's some method that returns an object with an unapply member) val fun = inPlaceAdHocOverloadingResolution(fun0)(hasUnapplyMember) - val caseClass = fun.tpe.typeSymbol.linkedClassOfClass + val caseClass = companionSymbolOf(fun.tpe.typeSymbol.sourceModule, context) val member = unapplyMember(fun.tpe) def resultType = (fun.tpe memberType member).finalResultType def isEmptyType = resultOfMatchingMethod(resultType, nme.isEmpty)() diff --git a/test/files/run/t9567.scala b/test/files/run/t9567.scala new file mode 100644 index 0000000000..69896b8650 --- /dev/null +++ b/test/files/run/t9567.scala @@ -0,0 +1,18 @@ +object Test { + def testMethodLocalCaseClass { + case class MethodLocalWide( + f01: Int, f02: Int, f03: Int, f04: Int, f05: Int, f06: Int, f07: Int, f08: Int, f09: Int, f10: Int, + f11: Int, f12: Int, f13: Int, f14: Int, f15: Int, f16: Int, f17: Int, f18: Int, f19: Int, f20: Int, + f21: Int, f22: Int, f23: Int) + + val instance = MethodLocalWide(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + val result = instance match { + case MethodLocalWide(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) => true + case _ => false + } + assert(result) + } + def main(args: Array[String]) { + testMethodLocalCaseClass + } +} diff --git a/test/files/run/t9567b.scala b/test/files/run/t9567b.scala new file mode 100644 index 0000000000..88cef0a60e --- /dev/null +++ b/test/files/run/t9567b.scala @@ -0,0 +1,19 @@ +object Test { + def testMethodLocalCaseClass { + object MethodLocalWide + case class MethodLocalWide( + f01: Int, f02: Int, f03: Int, f04: Int, f05: Int, f06: Int, f07: Int, f08: Int, f09: Int, f10: Int, + f11: Int, f12: Int, f13: Int, f14: Int, f15: Int, f16: Int, f17: Int, f18: Int, f19: Int, f20: Int, + f21: Int, f22: Int, f23: Int) + + val instance = MethodLocalWide(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + val result = instance match { + case MethodLocalWide(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) => true + case _ => false + } + assert(result) + } + def main(args: Array[String]) { + testMethodLocalCaseClass + } +} -- cgit v1.2.3 From 780ac4124a5bf34a3297b563fa4ea09741aa2d7b Mon Sep 17 00:00:00 2001 From: Stefan Zeiger Date: Tue, 27 Oct 2015 14:07:52 +0100 Subject: Make all of partest work in the sbt build - Fix the scoping of files/lib/*.jar. These files were not on the classpath when running partest from sbt. - Pass the same standard Java options to partest as from the command line. This requires new versions of scala-partest and scala-partest-interface. - Fix the classpath scanning in jvm/innerClassEnclMethodJavaReflection. It only worked for JARs and relative directories but not for absolute directory paths (which are produced by sbt). --- build.sbt | 7 ++++--- test/files/jvm/innerClassEnclMethodJavaReflection.scala | 9 +++++---- versions.properties | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'test/files') diff --git a/build.sbt b/build.sbt index 6dae804a2a..75762696ef 100644 --- a/build.sbt +++ b/build.sbt @@ -68,7 +68,7 @@ val scalaParserCombinatorsDep = withoutScalaLang("org.scala-lang.modules" %% "sc val scalaSwingDep = withoutScalaLang("org.scala-lang.modules" %% "scala-swing" % versionNumber("scala-swing")) val scalaXmlDep = withoutScalaLang("org.scala-lang.modules" %% "scala-xml" % versionNumber("scala-xml")) val partestDep = withoutScalaLang("org.scala-lang.modules" %% "scala-partest" % versionNumber("partest")) -val partestInterfaceDep = withoutScalaLang("org.scala-lang.modules" %% "scala-partest-interface" % "0.5.0") +val partestInterfaceDep = withoutScalaLang("org.scala-lang.modules" %% "scala-partest-interface" % "0.7.0") val junitDep = "junit" % "junit" % "4.11" val junitIntefaceDep = "com.novocode" % "junit-interface" % "0.11" % "test" val asmDep = "org.scala-lang.modules" % "scala-asm" % versionProps("scala-asm.version") @@ -553,8 +553,8 @@ lazy val test = project .settings( publishArtifact := false, libraryDependencies ++= Seq(asmDep, partestDep, scalaXmlDep, partestInterfaceDep, scalacheckDep), - unmanagedBase in Test := baseDirectory.value / "files" / "lib", - unmanagedJars in Test <+= (unmanagedBase) (j => Attributed.blank(j)) map(identity), + unmanagedBase in IntegrationTest := baseDirectory.value / "files" / "lib", + unmanagedJars in IntegrationTest <+= (unmanagedBase) (j => Attributed.blank(j)) map(identity), // no main sources sources in Compile := Seq.empty, // test sources are compiled in partest run, not here @@ -563,6 +563,7 @@ lazy val test = project javaOptions in IntegrationTest += "-Xmx1G", testFrameworks += new TestFramework("scala.tools.partest.Framework"), testOptions in IntegrationTest += Tests.Setup( () => root.base.getAbsolutePath + "/pull-binary-libs.sh" ! ), + testOptions in IntegrationTest += Tests.Argument("-Dpartest.java_opts=-Xmx1024M -Xms64M -XX:MaxPermSize=128M"), definedTests in IntegrationTest += ( new sbt.TestDefinition( "partest", diff --git a/test/files/jvm/innerClassEnclMethodJavaReflection.scala b/test/files/jvm/innerClassEnclMethodJavaReflection.scala index a4d64d0b67..a60b5cac8e 100644 --- a/test/files/jvm/innerClassEnclMethodJavaReflection.scala +++ b/test/files/jvm/innerClassEnclMethodJavaReflection.scala @@ -25,12 +25,13 @@ object Test extends App { def testClasses(jarOrDirectory: String): Unit = { val classPath = AbstractFile.getDirectory(new java.io.File(jarOrDirectory)) + val basePath = classPath.path + "/" - def flatten(f: AbstractFile): Iterator[AbstractFile] = - if (f.isClassContainer) f.iterator.flatMap(flatten) - else Iterator(f) + def flatten(f: AbstractFile, s: String): Iterator[(AbstractFile, String)] = + if (f.isClassContainer) f.iterator.map(ch => (ch, (if(s.isEmpty) "" else s + "/") + ch.name)).flatMap((flatten _).tupled) + else Iterator((f, s)) - val classFullNames = flatten(classPath).filter(_.hasExtension("class")).map(_.path.replace("/", ".").replaceAll(".class$", "")) + val classFullNames = flatten(classPath, "").filter(_._1.hasExtension("class")).map(_._2.replace("/", ".").replaceAll(".class$", "")) // it seems that Class objects can only be GC'd together with their class loader // (http://stackoverflow.com/questions/2433261/when-and-how-are-classes-garbage-collected-in-java) diff --git a/versions.properties b/versions.properties index 2253921940..145881ab9b 100644 --- a/versions.properties +++ b/versions.properties @@ -36,7 +36,7 @@ jline.version=2.12.1 scala-asm.version=5.0.4-scala-3 # external modules, used internally (not shipped) -partest.version.number=1.0.9 +partest.version.number=1.0.11 scalacheck.version.number=1.11.6 # TODO: modularize the compiler -- cgit v1.2.3 From 8e52acdc1bdc74375cf6a23e9ff929690317c3c7 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Fri, 15 Jan 2016 19:00:59 -0500 Subject: disable flaky presentation compiler test on Windows see https://github.com/scala/scala-dev/issues/72 for details --- test/files/presentation/doc/doc.scala | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/files') diff --git a/test/files/presentation/doc/doc.scala b/test/files/presentation/doc/doc.scala index f2233f1828..ce431910ee 100644 --- a/test/files/presentation/doc/doc.scala +++ b/test/files/presentation/doc/doc.scala @@ -118,6 +118,12 @@ object Test extends InteractiveTest { } } + // The remainder of this test has been found to fail intermittently on Windows + // only. The problem is difficult to isolate and reproduce; see + // https://github.com/scala/scala-dev/issues/72 for details. + // So if we're on Windows, let's just bail out here. + if (scala.util.Properties.isWin) return + // Check inter-classes documentation one-time retrieved ok. val baseSource = findSource("Base.scala") val derivedSource = findSource("Derived.scala") -- cgit v1.2.3