From cbd73bc07c82108f413290a240446985e317e3c6 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Tue, 6 Sep 2016 15:43:51 -0700 Subject: remove outdated ENSIME info link to an external ENSIME page instead --- README.md | 5 +++-- src/ensime/.ensime.SAMPLE | 17 ----------------- src/ensime/README.md | 11 ----------- 3 files changed, 3 insertions(+), 30 deletions(-) delete mode 100644 src/ensime/.ensime.SAMPLE delete mode 100644 src/ensime/README.md diff --git a/README.md b/README.md index ea28ba7497..3ffd419aa9 100644 --- a/README.md +++ b/README.md @@ -156,8 +156,9 @@ be easily executed locally. ### IDE Setup -You may use IntelliJ IDEA ([src/intellij/README.md](src/intellij/README.md)) or the -Scala IDE for Eclipse (see [src/eclipse/README.md](src/eclipse/README.md)). +You may use IntelliJ IDEA (see [src/intellij/README.md](src/intellij/README.md)), +the Scala IDE for Eclipse (see [src/eclipse/README.md](src/eclipse/README.md)), +or ENSIME (see [this page on the ENSIME site](http://ensime.github.io//contributing/scalac/)). In order to use IntelliJ's incremental compiler: - run `dist/mkBin` in sbt to get a build and the runner scripts in `build/quick/bin` diff --git a/src/ensime/.ensime.SAMPLE b/src/ensime/.ensime.SAMPLE deleted file mode 100644 index 10801816b7..0000000000 --- a/src/ensime/.ensime.SAMPLE +++ /dev/null @@ -1,17 +0,0 @@ -( - :disable-source-load-on-startup t - :disable-scala-jars-on-classpath t - :root-dir "c:/Projects/Kepler" - :sources ( - "c:/Projects/Kepler/src/library" - "c:/Projects/Kepler/src/reflect" - "c:/Projects/Kepler/src/compiler" - ) - :compile-deps ( - "c:/Projects/Kepler/build/asm/classes" - "c:/Projects/Kepler/build/locker/classes/library" - "c:/Projects/Kepler/build/locker/classes/reflect" - "c:/Projects/Kepler/build/locker/classes/compiler" - ) - :target "c:/Projects/Kepler/build/classes" -) \ No newline at end of file diff --git a/src/ensime/README.md b/src/ensime/README.md deleted file mode 100644 index 302d47b8a7..0000000000 --- a/src/ensime/README.md +++ /dev/null @@ -1,11 +0,0 @@ -Ensime project files -===================== - -Rename .ensime.SAMPLE to .ensime and replace sample paths with real paths to your sources and build results. -After that you're good to go with one of the ENSIME-enabled text editors. - -Editors that know how to talk to ENSIME servers: -1) Emacs via https://github.com/aemoncannon/ensime -2) jEdit via https://github.com/djspiewak/ensime-sidekick -3) TextMate via https://github.com/mads379/ensime.tmbundle -4) Sublime Text 2 via https://github.com/sublimescala/sublime-ensime -- cgit v1.2.3 From 90314b36d121755c52c00a57088623eba734a123 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Sat, 10 Sep 2016 11:22:39 +0200 Subject: SI-9918 object in trait mixed into package object --- src/compiler/scala/tools/nsc/transform/Fields.scala | 2 +- test/files/pos/t9918/package.scala | 1 + test/files/pos/t9918/t9918.scala | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 test/files/pos/t9918/package.scala create mode 100644 test/files/pos/t9918/t9918.scala diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index a383b65192..10494f33d1 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -721,7 +721,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { val addedStats = - if (!currentOwner.isClass) Nil // TODO: || currentOwner.isPackageClass + if (!currentOwner.isClass || currentOwner.isPackageClass) Nil else afterOwnPhase { fieldsAndAccessors(currentOwner) } val inRealClass = currentOwner.isClass && !(currentOwner.isPackageClass || currentOwner.isTrait) diff --git a/test/files/pos/t9918/package.scala b/test/files/pos/t9918/package.scala new file mode 100644 index 0000000000..9bd8ac9a69 --- /dev/null +++ b/test/files/pos/t9918/package.scala @@ -0,0 +1 @@ +package object pkg extends T diff --git a/test/files/pos/t9918/t9918.scala b/test/files/pos/t9918/t9918.scala new file mode 100644 index 0000000000..ec9a146579 --- /dev/null +++ b/test/files/pos/t9918/t9918.scala @@ -0,0 +1,3 @@ +package pkg + +trait T { object O } -- cgit v1.2.3 From a919fd7fa1f3c39dc396e7758240354e6fb0e79b Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 12 Sep 2016 14:49:07 +1000 Subject: Avoid omitting constant typed vals in constructors Fix for regression in 2.12.0-RC1 compiling shapeless tests. They were given the same treatment as vals that are members of classes on the definition side without the requisite transformation of references to the val to fold the constant into references. This commit limits the transform to members of classes. Co-Authored-By: Miles Sabin --- src/compiler/scala/tools/nsc/transform/Fields.scala | 2 +- test/files/pos/shapeless-regression.scala | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 test/files/pos/shapeless-regression.scala diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index a383b65192..0c7bc742d9 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -694,7 +694,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor // drop the val for (a) constant (pure & not-stored) and (b) not-stored (but still effectful) fields case ValDef(mods, _, _, rhs) if (rhs ne EmptyTree) && !excludedAccessorOrFieldByFlags(statSym) - && fieldMemoizationIn(statSym, currOwner).constantTyped => + && currOwner.isClass && fieldMemoizationIn(statSym, currOwner).constantTyped => EmptyThicket case ModuleDef(_, _, impl) => diff --git a/test/files/pos/shapeless-regression.scala b/test/files/pos/shapeless-regression.scala new file mode 100644 index 0000000000..f3a1ed1ba0 --- /dev/null +++ b/test/files/pos/shapeless-regression.scala @@ -0,0 +1,16 @@ +class W[T <: AnyRef](val t: T) { + val v: T {} = t +} + +object W { + def apply[T <: AnyRef](t: T) = new W[t.type](t) +} + +object RightAssoc { + def ra_:[T](t: T): Unit = () +} + +object Boom { + W("fooo").v ra_: RightAssoc +} + -- cgit v1.2.3 From a5bb6e00f051bf93fe7df4a02583eba478fa5ca1 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 13 Sep 2016 22:45:10 +1000 Subject: SD-225 Use a "lzycompute" method for module initialization The monitors and module instantation were inliuned into the module accessor method in b2e0911. However, this seems to have had a detrimental impact on performance. This might be because the module accessors are now above the "always inline" HotSpot threshold of 35 bytes, or perhaps because they contain monitor-entry/exit and exception handlers. This commit returns to the the 2.11.8 appraoch of factoring the the second check of the doublecheck locking into a method. I've done this by declaring a nested method within the accessor; this will be lifted out to the class level by lambdalift. This represents a slight deviation from the implementation strategy used for lazy accessors, which create a symbol for the slowpath method in the info transform and generate the corresponding DefDef as a class member. I don't believe this deviation is particular worrisome, though. I have bootstrapped the compiler through this commit and found that the drastic regression in compiling the shapeless test suite is solved. --- src/compiler/scala/tools/nsc/transform/Fields.scala | 6 ++++-- test/files/run/delambdafy_t6028.check | 5 +++-- test/files/run/t6028.check | 5 +++-- .../scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala | 4 +++- .../scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala | 9 +++++++-- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index a383b65192..45741eb391 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -22,7 +22,7 @@ import symtab.Flags._ * in the first (closest in the subclassing lattice) subclass (not a trait) of a trait. * * For lazy vals and modules, we emit accessors that using double-checked locking (DCL) to balance thread safety - * and performance. A lazy val gets a compute method for the DCL's slow path, for a module it's all done in the accessor. + * and performance. For both lazy vals and modules, the a compute method contains the DCL's slow path. * * Local lazy vals do not receive bitmaps, but use a Lazy*Holder that has the volatile init bit and the computed value. * See `mkLazyLocalDef`. @@ -236,7 +236,9 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor * * TODO: optimize using local variable? */ - Block(If(needsInit, gen.mkSynchronized(monitorHolder)(If(needsInit, init, EmptyTree)), EmptyTree) :: Nil, moduleVarRef) + val computeName = nme.newLazyValSlowComputeName(module.name) + val computeMethod = DefDef(NoMods, computeName, Nil, ListOfNil, TypeTree(UnitTpe), gen.mkSynchronized(monitorHolder)(If(needsInit, init, EmptyTree))) + Block(computeMethod :: If(needsInit, Apply(Ident(computeName), Nil), EmptyTree) :: Nil, moduleVarRef) } // NoSymbol for lazy accessor sym with unit result type diff --git a/test/files/run/delambdafy_t6028.check b/test/files/run/delambdafy_t6028.check index eaba70ee1a..6a15b3b003 100644 --- a/test/files/run/delambdafy_t6028.check +++ b/test/files/run/delambdafy_t6028.check @@ -42,10 +42,11 @@ package { def $outer(): T = MethodLocalObject$2.this.$outer; def $outer(): T = MethodLocalObject$2.this.$outer }; + final private[this] def MethodLocalObject$lzycompute$1(barParam$1: String, MethodLocalObject$module$1: runtime.VolatileObjectRef): Unit = T.this.synchronized[Unit](if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) + MethodLocalObject$module$1.elem = new T#MethodLocalObject$2.type(T.this, barParam$1)); final private[this] def MethodLocalObject$1(barParam$1: String, MethodLocalObject$module$1: runtime.VolatileObjectRef): T#MethodLocalObject$2.type = { if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) - T.this.synchronized[Unit](if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) - MethodLocalObject$module$1.elem = new T#MethodLocalObject$2.type(T.this, barParam$1)); + T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1); MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]() }; final private[this] def $anonfun$tryy$1(tryyParam$1: String, tryyLocal$1: runtime.ObjectRef): Unit = try { diff --git a/test/files/run/t6028.check b/test/files/run/t6028.check index d6cc452bbf..80f8698ecf 100644 --- a/test/files/run/t6028.check +++ b/test/files/run/t6028.check @@ -54,10 +54,11 @@ package { def $outer(): T = MethodLocalObject$2.this.$outer; def $outer(): T = MethodLocalObject$2.this.$outer }; + final private[this] def MethodLocalObject$lzycompute$1(barParam$1: Int, MethodLocalObject$module$1: runtime.VolatileObjectRef): Unit = T.this.synchronized[Unit](if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) + MethodLocalObject$module$1.elem = new T#MethodLocalObject$2.type(T.this, barParam$1)); final private[this] def MethodLocalObject$1(barParam$1: Int, MethodLocalObject$module$1: runtime.VolatileObjectRef): T#MethodLocalObject$2.type = { if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) - T.this.synchronized[Unit](if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) - MethodLocalObject$module$1.elem = new T#MethodLocalObject$2.type(T.this, barParam$1)); + T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1); MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]() }; @SerialVersionUID(value = 0) final class $anonfun$tryy$1 extends scala.runtime.AbstractFunction0$mcV$sp with Serializable { diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala index 85b44d9fa0..95b47f7d04 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala @@ -198,7 +198,9 @@ class InlineWarningTest extends BytecodeTesting { |Note that class A is defined in a Java source (mixed compilation), no bytecode is available.""".stripMargin ) var c = 0 - compileClasses(sCode, javaCode = List((jCode, "A.java")), allowMessage = i => { c += 1; warns.exists(i.msg.contains)}) + compileClasses(sCode, javaCode = List((jCode, "A.java")), allowMessage = i => { c += 1; + warns.exists(i.msg.contains) + }) assert(c == 2) } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala index eae5385147..8861577366 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala @@ -107,7 +107,9 @@ class ScalaInlineInfoTest extends BytecodeTesting { ("x5$(LT;)I", MethodInlineInfo(true ,false,false)), ("L$1(Lscala/runtime/VolatileObjectRef;)LT$L$2$;", MethodInlineInfo(true, false,false)), ("nest$1()I", MethodInlineInfo(true, false,false)), - ("$init$(LT;)V", MethodInlineInfo(true,false,false))), + ("$init$(LT;)V", MethodInlineInfo(true,false,false)), + ("L$lzycompute$1(Lscala/runtime/VolatileObjectRef;)V", MethodInlineInfo(true,false,false)) + ), None // warning ) @@ -128,7 +130,9 @@ class ScalaInlineInfoTest extends BytecodeTesting { "x4()I" -> MethodInlineInfo(false,false,false), // "x5()I" -> MethodInlineInfo(true ,false,false), -- there is no x5 in the class as it's implemented fully in the interface "T$$super$toString()Ljava/lang/String;" -> MethodInlineInfo(true ,false,false), - "()V" -> MethodInlineInfo(false,false,false)), + "()V" -> MethodInlineInfo(false,false,false), + "O$lzycompute$1()V" -> MethodInlineInfo(true,false,false) + ), None) assert(infoC == expectC, mapDiff(expectC.methodInfos, infoC.methodInfos) + infoC) @@ -179,6 +183,7 @@ class ScalaInlineInfoTest extends BytecodeTesting { val infoC = inlineInfo(c) val expected = Map( "()V" -> MethodInlineInfo(false,false,false), + "O$lzycompute$1()V" -> MethodInlineInfo(true,false,false), "O()LC$O$;" -> MethodInlineInfo(true,false,false)) assert(infoC.methodInfos == expected, mapDiff(infoC.methodInfos, expected)) assertSameMethods(c, expected.keySet) -- cgit v1.2.3 From 51540c823ae85a7ec9c1400f3756701210269eae Mon Sep 17 00:00:00 2001 From: Raphael Jolly Date: Fri, 16 Sep 2016 21:01:02 +0200 Subject: Fixed reference to script engine factory in META-INF/services --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 1105902a9d..f6ddd9d7df 100644 --- a/build.sbt +++ b/build.sbt @@ -406,7 +406,7 @@ lazy val compiler = configureAsSubproject(project) ), // Generate the ScriptEngineFactory service definition. The Ant build does this when building // the JAR but sbt has no support for it and it is easier to do as a resource generator: - generateServiceProviderResources("javax.script.ScriptEngineFactory" -> "scala.tools.nsc.interpreter.IMain$Factory"), + generateServiceProviderResources("javax.script.ScriptEngineFactory" -> "scala.tools.nsc.interpreter.Scripted$Factory"), managedResourceDirectories in Compile := Seq((resourceManaged in Compile).value), fixPom( "/project/name" -> Scala Compiler, -- cgit v1.2.3 From d274405084d407b572ad12a9049af5fc979a8e1d Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 15 Sep 2016 15:23:37 +1000 Subject: Restarr on PR 5398, lzycompute performance fix --- versions.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.properties b/versions.properties index e75ec61f64..773999c485 100644 --- a/versions.properties +++ b/versions.properties @@ -8,7 +8,7 @@ # The scala version used for bootstrapping. This has no impact on the final classfiles: # there are two stages (locker and quick), so compiler and library are always built # with themselves. Stability is ensured by building a third stage (strap). -starr.version=2.12.0-RC1 +starr.version=2.12.0-RC1-be43eb5 # These are the versions of the modules that go with this release. # These properties are used during PR validation and in dbuild builds. -- cgit v1.2.3 From 4874a242cbb72eb94ed71824e81314980cbff024 Mon Sep 17 00:00:00 2001 From: Antoine Gourlay Date: Tue, 20 Sep 2016 16:00:53 +0200 Subject: SD-220 building without being in a git repository This allows building from the scala sources tarball or similar situations where there is no local git repository: - the git commit date becomes the local date - the short git sha1 becomes "unknown" ``` Welcome to Scala 2.12.0-20160920-155429-unknown (OpenJDK 64-Bit Server VM, Java 1.8.0_102). ``` --- tools/get-scala-commit-date | 9 +++++++-- tools/get-scala-commit-sha | 14 +++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/tools/get-scala-commit-date b/tools/get-scala-commit-date index b2e4e10770..6511ed98ca 100755 --- a/tools/get-scala-commit-date +++ b/tools/get-scala-commit-date @@ -10,8 +10,13 @@ [[ $# -eq 0 ]] || cd "$1" -lastcommitdate=$(git log --format="%ci" HEAD | head -n 1 | cut -d ' ' -f 1) -lastcommithours=$(git log --format="%ci" HEAD | head -n 1 | cut -d ' ' -f 2) +if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then + lastcommitdate=$(git log --format="%ci" HEAD | head -n 1 | cut -d ' ' -f 1) + lastcommithours=$(git log --format="%ci" HEAD | head -n 1 | cut -d ' ' -f 2) +else + lastcommitdate=$(date +%Y-%m-%d) + lastcommithours=$(date +%H:%M:%S) +fi # 20120324 echo "${lastcommitdate//-/}-${lastcommithours//:/}" diff --git a/tools/get-scala-commit-sha b/tools/get-scala-commit-sha index eab90a4215..18289c7ca8 100755 --- a/tools/get-scala-commit-sha +++ b/tools/get-scala-commit-sha @@ -10,9 +10,13 @@ [[ $# -eq 0 ]] || cd "$1" -# printf %016s is not portable for 0-padding, has to be a digit. -# so we're stuck disassembling it. -hash=$(git log -1 --format="%H" HEAD) -hash=${hash#g} -hash=${hash:0:10} +if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then + # printf %016s is not portable for 0-padding, has to be a digit. + # so we're stuck disassembling it. + hash=$(git log -1 --format="%H" HEAD) + hash=${hash#g} + hash=${hash:0:10} +else + hash="unknown" +fi echo "$hash" -- cgit v1.2.3 From c0450f0c12f265674bc657cfb469778cd35d1c40 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 19 Sep 2016 11:51:58 +1000 Subject: SD-226 Be lazier in Fields info transform for better performance Only mixin fields + accessors into class infos of classes that are either in the current run, or appear in a superclass chain of a class in the current run. This is analagous to what happens in the mixin phase. --- src/compiler/scala/tools/nsc/transform/Fields.scala | 9 ++++++++- src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index 894d0a1701..c39491cf9e 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -305,6 +305,10 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor lazyCallingSuper setInfo tp } + private def needsMixin(cls: Symbol): Boolean = { + !(cls.isPackageClass || cls.isJavaDefined) && (currentRun.compiles(cls) || refChecks.isSeparatelyCompiledScalaSuperclass(cls)) + } + def apply(tp0: Type): Type = tp0 match { // TODO: make less destructive (name changes, decl additions, flag setting -- // none of this is actually undone when travelling back in time using atPhase) @@ -360,9 +364,12 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor ClassInfoType(parents, allDecls, clazz) } else tp + + case tp@ClassInfoType(parents, oldDecls, clazz) if !needsMixin(clazz) => tp + // mix in fields & accessors for all mixed in traits + case tp@ClassInfoType(parents, oldDecls, clazz) => - case tp@ClassInfoType(parents, oldDecls, clazz) if !clazz.isPackageClass => val site = clazz.thisType // setter conflicts cannot arise independently from a getter conflict, since a setter without a getter does not a val definition make diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 8034d056d7..24b4334ec4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -95,6 +95,9 @@ abstract class RefChecks extends Transform { ) } + private val separatelyCompiledScalaSuperclass = perRunCaches.newAnyRefMap[Symbol, Unit]() + final def isSeparatelyCompiledScalaSuperclass(sym: Symbol) = separatelyCompiledScalaSuperclass.contains(sym) + class RefCheckTransformer(unit: CompilationUnit) extends Transformer { var localTyper: analyzer.Typer = typer @@ -854,6 +857,8 @@ abstract class RefChecks extends Transform { // println("validate base type "+tp) val baseClass = tp.typeSymbol if (baseClass.isClass) { + if (!baseClass.isTrait && !baseClass.isJavaDefined && !currentRun.compiles(baseClass) && !separatelyCompiledScalaSuperclass.contains(baseClass)) + separatelyCompiledScalaSuperclass.update(baseClass, ()) val index = clazz.info.baseTypeIndex(baseClass) if (index >= 0) { if (seenTypes(index) forall (tp1 => !(tp1 <:< tp))) -- cgit v1.2.3 From 891353e709806a1f8a7005b1c65827dd6194f5a2 Mon Sep 17 00:00:00 2001 From: Stefan Zeiger Date: Thu, 22 Sep 2016 14:37:02 +0200 Subject: Do not build partest-javaagent and partest-extras for `pack` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building them as part of `dist/mkQuick` (and thus, by extension, `dist/mkPack`) was not necessary in the first place. Partest does not rely on these tasks for its dependencies. And when we do build the jars, they now go into their standard location under `target` instead of `build/pack/lib` so they don’t confuse sbt (see https://github.com/sbt/sbt/issues/2748). --- build.sbt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.sbt b/build.sbt index 1105902a9d..8d28b1c1a5 100644 --- a/build.sbt +++ b/build.sbt @@ -510,8 +510,10 @@ lazy val scalap = configureAsSubproject(project) ) .dependsOn(compiler) -lazy val partestExtras = configureAsSubproject(Project("partest-extras", file(".") / "src" / "partest-extras")) +lazy val partestExtras = Project("partest-extras", file(".") / "src" / "partest-extras") .dependsOn(replJlineEmbedded) + .settings(commonSettings: _*) + .settings(generatePropertiesFileSettings: _*) .settings(clearSourceAndResourceDirectories: _*) .settings(disableDocs: _*) .settings(disablePublishing: _*) @@ -597,8 +599,6 @@ lazy val partestJavaAgent = Project("partest-javaagent", file(".") / "src" / "pa // Setting name to "scala-partest-javaagent" so that the jar file gets that name, which the Runner relies on name := "scala-partest-javaagent", description := "Scala Compiler Testing Tool (compiler-specific java agent)", - // writing jar file to $buildDirectory/pack/lib because that's where it's expected to be found - setJarLocation, // add required manifest entry - previously included from file packageOptions in (Compile, packageBin) += Package.ManifestAttributes( "Premain-Class" -> "scala.tools.partest.javaagent.ProfilingAgent" ), @@ -829,7 +829,7 @@ lazy val root: Project = (project in file(".")) ) // The following subprojects' binaries are required for building "pack": -lazy val distDependencies = Seq(replJline, replJlineEmbedded, compiler, library, partestExtras, partestJavaAgent, reflect, scalap, scaladoc) +lazy val distDependencies = Seq(replJline, replJlineEmbedded, compiler, library, reflect, scalap, scaladoc) lazy val dist = (project in file("dist")) .settings(commonSettings) -- cgit v1.2.3 From 87b3d2cc41b175742da9301210299c3b1524a287 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 18 Sep 2016 15:31:15 +1000 Subject: Optimize javaBinaryName callers ... by calling javaBinaryNameString, instead. They all are happy with a throw away String, there is no advantage to interning this into the name table. --- src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala | 6 +++--- src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala | 2 +- src/compiler/scala/tools/nsc/transform/Erasure.scala | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala index 09e82de89b..edb75514e8 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala @@ -114,7 +114,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { if (classSym == NothingClass) srNothingRef else if (classSym == NullClass) srNullRef else { - val internalName = classSym.javaBinaryName.toString + val internalName = classSym.javaBinaryNameString classBTypeFromInternalName.getOrElse(internalName, { // The new ClassBType is added to the map in its constructor, before we set its info. This // allows initializing cyclic dependencies, see the comment on variable ClassBType._info. @@ -625,7 +625,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { */ def mirrorClassClassBType(moduleClassSym: Symbol): ClassBType = { assert(isTopLevelModuleClass(moduleClassSym), s"not a top-level module class: $moduleClassSym") - val internalName = moduleClassSym.javaBinaryName.dropModule.toString + val internalName = moduleClassSym.javaBinaryNameString.stripSuffix(nme.MODULE_SUFFIX_STRING) classBTypeFromInternalName.getOrElse(internalName, { val c = ClassBType(internalName) // class info consistent with BCodeHelpers.genMirrorClass @@ -642,7 +642,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { } def beanInfoClassClassBType(mainClass: Symbol): ClassBType = { - val internalName = mainClass.javaBinaryName.toString + "BeanInfo" + val internalName = mainClass.javaBinaryNameString + "BeanInfo" classBTypeFromInternalName.getOrElse(internalName, { val c = ClassBType(internalName) c.info = Right(ClassInfo( diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala index 0a54767f76..6593d4b725 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala @@ -337,7 +337,7 @@ abstract class GenBCode extends BCodeSyncAndTry { bTypes.initializeCoreBTypes() bTypes.javaDefinedClasses.clear() bTypes.javaDefinedClasses ++= currentRun.symSource collect { - case (sym, _) if sym.isJavaDefined => sym.javaBinaryName.toString + case (sym, _) if sym.isJavaDefined => sym.javaBinaryNameString } Statistics.stopTimer(BackendStats.bcodeInitTimer, initStart) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 69240b07a1..cc234eb623 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -258,7 +258,7 @@ abstract class Erasure extends InfoTransform // Anything which could conceivably be a module (i.e. isn't known to be // a type parameter or similar) must go through here or the signature is // likely to end up with Foo.Empty where it needs Foo.Empty$. - def fullNameInSig(sym: Symbol) = "L" + enteringJVM(sym.javaBinaryName) + def fullNameInSig(sym: Symbol) = "L" + enteringJVM(sym.javaBinaryNameString) def jsig(tp0: Type, existentiallyBound: List[Symbol] = Nil, toplevel: Boolean = false, primitiveOK: Boolean = true): String = { val tp = tp0.dealias -- cgit v1.2.3 From e994c1c0becddc0d91fd4428f0d673bfac8941a3 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 26 Sep 2016 09:47:49 +1000 Subject: SD-233 synchronized blocks are JIT-friendly again GenBCode, the new backend in Scala 2.12, subtly changed the way that synchronized blocks are emitted. It used `java/lang/Throwable` as an explicitly named exception type, rather than implying the same by omitting this in bytecode. This appears to confuse HotSpot JIT, which reports a error parsing the bytecode into its IR which leaves the enclosing method stuck in interpreted mode. This commit passes a `null` descriptor to restore the old pattern (the same one used by javac.) I've checked that the JIT warnings are gone and that the method can be compiled again. --- src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala | 4 +++- test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala index 3e53419573..466793010f 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala @@ -73,9 +73,11 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder { /* ------ (4) exception-handler version of monitor-exit code. * Reached upon abrupt termination of (2). * Protected by whatever protects the whole synchronized expression. + * null => "any" exception in bytecode, like we emit for finally. + * Important not to use j/l/Throwable which dooms the method to a life of interpretation! (SD-233) * ------ */ - protect(startProtected, endProtected, currProgramPoint(), jlThrowableRef) + protect(startProtected, endProtected, currProgramPoint(), null) locals.load(monitor) emit(asm.Opcodes.MONITOREXIT) emit(asm.Opcodes.ATHROW) diff --git a/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala index b09a41969e..00b6d1cc42 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala @@ -187,4 +187,12 @@ class BytecodeTest extends BytecodeTesting { List(Label(0), LineNumber(2, Label(0)), VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "T", "t", "()V", true), Op(RETURN), Label(4)) ) } + + @Test + def sd233(): Unit = { + val code = "def f = { println(1); synchronized(println(2)) }" + val m = compileMethod(code) + val List(ExceptionHandler(_, _, _, desc)) = m.handlers + assert(desc == None, desc) + } } -- cgit v1.2.3 From 9a39e0c283ac60edabb8dba9ad8513199112882a Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 8 Sep 2016 18:17:45 +0200 Subject: Avoid mismatched symbols in fields phase The info of the var that stores a trait's lazy val's computed value is expressed in terms of symbols that exist before the fields phase. When we're implementing the lazy val in a subclass of that trait, we now see symbols created by the fields phase, which results in mismatches between the types of the lhs and rhs in the assignment of `lazyVar = super.lazyImpl`. So, type check the super-call to the trait's lazy accessor before our own phase. If the lazy var's info depends on a val that is now implemented by an accessor synthesize by our info transformer, we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`, unless we also run before our own phase (like when we were creating the info for the lazy var). This was revealed by Hanns Holger Rutz's efforts in compiling scala-refactoring's test suite (reported on scala-internals). Fixes scala/scala-dev#219 --- src/compiler/scala/tools/nsc/transform/Fields.scala | 17 +++++++++++++++-- test/files/pos/sd219.scala | 11 +++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 test/files/pos/sd219.scala diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index 894d0a1701..44ea52f801 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -633,8 +633,21 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor val synthAccessorInClass = new SynthLazyAccessorsIn(clazz) def superLazy(getter: Symbol): List[ValOrDefDef] = { assert(!clazz.isTrait) - // this contortion was the only way I can get the super select to be type checked correctly.. TODO: why does SelectSuper not work? - val rhs = Apply(Select(Super(This(clazz), tpnme.EMPTY), getter.name), Nil) + // this contortion was the only way I can get the super select to be type checked correctly.. + // TODO: why does SelectSuper not work? + val selectSuper = Select(Super(This(clazz), tpnme.EMPTY), getter.name) + + // scala/scala-dev#219 + // Type check the super-call to the trait's lazy accessor before our own phase, + // so that we don't see other accessor symbols we mix into the class. + // The lazy var's info will not refer to symbols created during our info transformer, + // so if its type depends on a val that is now implemented after the info transformer, + // we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`, + // unless we also run before our own phase (like when we were creating the info for the lazy var). + // + // TODO: are there other spots where we may get a mismatch like this? + val rhs = exitingUncurry(typedPos(getter.pos.focus)(Apply(selectSuper, Nil))) + explodeThicket(synthAccessorInClass.expandLazyClassMember(lazyVarOf(getter), getter, rhs, Map.empty)).asInstanceOf[List[ValOrDefDef]] } diff --git a/test/files/pos/sd219.scala b/test/files/pos/sd219.scala new file mode 100644 index 0000000000..3c3f4962f0 --- /dev/null +++ b/test/files/pos/sd219.scala @@ -0,0 +1,11 @@ +class Global { class Name } + +trait CommonPrintUtils { + val global: Global + + lazy val precedence: global.Name => Int = ??? +} + +trait CompilerProvider { val global: Global = ??? } + +class AbstractPrinter extends CommonPrintUtils with CompilerProvider \ No newline at end of file -- cgit v1.2.3 From 5f64ee5ad1148563409c4e7cfbdd51577589d3e1 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Fri, 9 Sep 2016 09:20:39 +0200 Subject: Cast more pro-actively in synthetic accessor trees. Also narrow scope of afterOwnPhase. --- .../scala/tools/nsc/transform/Fields.scala | 113 +++++++++++---------- test/files/run/delambdafy_t6028.check | 2 +- test/files/run/t6028.check | 2 +- 3 files changed, 64 insertions(+), 53 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index 44ea52f801..f75e6f5efa 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -207,9 +207,8 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor moduleVar } - private def moduleInit(module: Symbol) = { + private def moduleInit(module: Symbol, moduleVar: Symbol) = { // println(s"moduleInit for $module in ${module.ownerChain} --> ${moduleVarOf.get(module)}") - val moduleVar = moduleOrLazyVarOf(module) def moduleVarRef = gen.mkAttributedRef(moduleVar) // for local modules, we synchronize on the owner of the method that owns the module @@ -238,7 +237,8 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor */ val computeName = nme.newLazyValSlowComputeName(module.name) val computeMethod = DefDef(NoMods, computeName, Nil, ListOfNil, TypeTree(UnitTpe), gen.mkSynchronized(monitorHolder)(If(needsInit, init, EmptyTree))) - Block(computeMethod :: If(needsInit, Apply(Ident(computeName), Nil), EmptyTree) :: Nil, moduleVarRef) + Block(computeMethod :: If(needsInit, Apply(Ident(computeName), Nil), EmptyTree) :: Nil, + gen.mkCast(moduleVarRef, module.info.resultType)) } // NoSymbol for lazy accessor sym with unit result type @@ -590,75 +590,81 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor } // synth trees for accessors/fields and trait setters when they are mixed into a class - def fieldsAndAccessors(clazz: Symbol): List[ValOrDefDef] = { - def fieldAccess(accessor: Symbol): List[Tree] = { - val fieldName = accessor.localName - val field = clazz.info.decl(fieldName) - // The `None` result denotes an error, but it's refchecks' job to report it (this fallback is for robustness). - // This is the result of overriding a val with a def, so that no field is found in the subclass. - if (field.exists) List(Select(This(clazz), field)) - else Nil - } - - def getterBody(getter: Symbol): List[Tree] = { + def fieldsAndAccessors(clazz: Symbol): List[Tree] = { + // scala/scala-dev#219 + // Cast to avoid spurious mismatch in paths containing trait vals that have + // not been rebound to accessors in the subclass we're in now. + // For example, for a lazy val mixed into a class, the lazy var's info + // will not refer to symbols created during our info transformer, + // so if its type depends on a val that is now implemented after the info transformer, + // we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`. + // TODO: could we rebind more aggressively? consider overriding in type equality? + def cast(tree: Tree, pt: Type) = gen.mkAsInstanceOf(tree, pt) + + // Could be NoSymbol, which denotes an error, but it's refchecks' job to report it (this fallback is for robustness). + // This is the result of overriding a val with a def, so that no field is found in the subclass. + def fieldAccess(accessor: Symbol): Symbol = + afterOwnPhase { clazz.info.decl(accessor.localName) } + + def getterBody(getter: Symbol): Tree = // accessor created by newMatchingModuleAccessor for a static module that does need an accessor // (because there's a matching member in a super class) - if (getter.asTerm.referenced.isModule) { - List(gen.mkAttributedRef(clazz.thisType, getter.asTerm.referenced)) - } else { + if (getter.asTerm.referenced.isModule) + mkAccessor(getter)(cast(Select(This(clazz), getter.asTerm.referenced), getter.info.resultType)) + else { val fieldMemoization = fieldMemoizationIn(getter, clazz) - if (fieldMemoization.constantTyped) List(gen.mkAttributedQualifier(fieldMemoization.tp)) // TODO: drop when we no longer care about producing identical bytecode - else fieldAccess(getter) + // TODO: drop getter for constant? (when we no longer care about producing identical bytecode?) + if (fieldMemoization.constantTyped) mkAccessor(getter)(gen.mkAttributedQualifier(fieldMemoization.tp)) + else fieldAccess(getter) match { + case NoSymbol => EmptyTree + case fieldSel => mkAccessor(getter)(cast(Select(This(clazz), fieldSel), getter.info.resultType)) + } } - } // println(s"accessorsAndFieldsNeedingTrees for $templateSym: $accessorsAndFieldsNeedingTrees") - def setterBody(setter: Symbol): List[Tree] = { + def setterBody(setter: Symbol): Tree = // trait setter in trait - if (clazz.isTrait) List(EmptyTree) + if (clazz.isTrait) mkAccessor(setter)(EmptyTree) // trait setter for overridden val in class - else if (checkAndClearOverriddenTraitSetter(setter)) List(mkTypedUnit(setter.pos)) + else if (checkAndClearOverriddenTraitSetter(setter)) mkAccessor(setter)(mkTypedUnit(setter.pos)) // trait val/var setter mixed into class - else fieldAccess(setter) map (fieldSel => Assign(fieldSel, Ident(setter.firstParam))) - } + else fieldAccess(setter) match { + case NoSymbol => EmptyTree + case fieldSel => afterOwnPhase { // the assign only type checks after our phase (assignment to val) + mkAccessor(setter)(Assign(Select(This(clazz), fieldSel), cast(Ident(setter.firstParam), fieldSel.info))) + } + } - def moduleAccessorBody(module: Symbol): List[Tree] = List( + def moduleAccessorBody(module: Symbol): Tree = // added during synthFieldsAndAccessors using newModuleAccessor // a module defined in a trait by definition can't be static (it's a member of the trait and thus gets a new instance for every outer instance) - if (clazz.isTrait) EmptyTree + if (clazz.isTrait) mkAccessor(module)(EmptyTree) // symbol created by newModuleAccessor for a (non-trait) class - else moduleInit(module) - ) + else { + mkAccessor(module)(moduleInit(module, moduleOrLazyVarOf(module))) + } val synthAccessorInClass = new SynthLazyAccessorsIn(clazz) - def superLazy(getter: Symbol): List[ValOrDefDef] = { + def superLazy(getter: Symbol): Tree = { assert(!clazz.isTrait) // this contortion was the only way I can get the super select to be type checked correctly.. // TODO: why does SelectSuper not work? val selectSuper = Select(Super(This(clazz), tpnme.EMPTY), getter.name) - // scala/scala-dev#219 - // Type check the super-call to the trait's lazy accessor before our own phase, - // so that we don't see other accessor symbols we mix into the class. - // The lazy var's info will not refer to symbols created during our info transformer, - // so if its type depends on a val that is now implemented after the info transformer, - // we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`, - // unless we also run before our own phase (like when we were creating the info for the lazy var). - // - // TODO: are there other spots where we may get a mismatch like this? - val rhs = exitingUncurry(typedPos(getter.pos.focus)(Apply(selectSuper, Nil))) - - explodeThicket(synthAccessorInClass.expandLazyClassMember(lazyVarOf(getter), getter, rhs, Map.empty)).asInstanceOf[List[ValOrDefDef]] + val lazyVar = lazyVarOf(getter) + val rhs = cast(Apply(selectSuper, Nil), lazyVar.info) + + synthAccessorInClass.expandLazyClassMember(lazyVar, getter, rhs, Map.empty) } - clazz.info.decls.toList.filter(checkAndClearNeedsTrees) flatMap { - case module if module hasAllFlags (MODULE | METHOD) => moduleAccessorBody(module) map mkAccessor(module) + (afterOwnPhase { clazz.info.decls } toList) filter checkAndClearNeedsTrees map { + case module if module hasAllFlags (MODULE | METHOD) => moduleAccessorBody(module) case getter if getter hasAllFlags (LAZY | METHOD) => superLazy(getter) - case setter if setter.isSetter => setterBody(setter) map mkAccessor(setter) - case getter if getter.hasFlag(ACCESSOR) => getterBody(getter) map mkAccessor(getter) - case field if !(field hasFlag METHOD) => Some(mkTypedValDef(field)) // vals/vars and module vars (cannot have flags PACKAGE | JAVA since those never receive NEEDS_TREES) - case _ => None - } + case setter if setter.isSetter => setterBody(setter) + case getter if getter.hasFlag(ACCESSOR) => getterBody(getter) + case field if !(field hasFlag METHOD) => mkTypedValDef(field) // vals/vars and module vars (cannot have flags PACKAGE | JAVA since those never receive NEEDS_TREES) + case _ => EmptyTree + } filterNot (_ == EmptyTree) // there will likely be many EmptyTrees, but perhaps no thicket blocks that need expanding } def rhsAtOwner(stat: ValOrDefDef, newOwner: Symbol): Tree = @@ -718,7 +724,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor if (currOwner.isClass) cd else { // local module -- symbols cannot be generated by info transformer, so do it all here val moduleVar = newModuleVarSymbol(currOwner, statSym, statSym.info.resultType) - Thicket(cd :: mkTypedValDef(moduleVar) :: mkAccessor(statSym)(moduleInit(statSym)) :: Nil) + Thicket(cd :: mkTypedValDef(moduleVar) :: mkAccessor(statSym)(moduleInit(statSym, moduleVar)) :: Nil) } case tree => @@ -737,7 +743,12 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { val addedStats = if (!currentOwner.isClass || currentOwner.isPackageClass) Nil - else afterOwnPhase { fieldsAndAccessors(currentOwner) } + else { + val thickets = fieldsAndAccessors(currentOwner) + if (thickets exists mustExplodeThicket) + thickets flatMap explodeThicket + else thickets + } val inRealClass = currentOwner.isClass && !(currentOwner.isPackageClass || currentOwner.isTrait) if (inRealClass) diff --git a/test/files/run/delambdafy_t6028.check b/test/files/run/delambdafy_t6028.check index 6a15b3b003..7b319c92dd 100644 --- a/test/files/run/delambdafy_t6028.check +++ b/test/files/run/delambdafy_t6028.check @@ -47,7 +47,7 @@ package { final private[this] def MethodLocalObject$1(barParam$1: String, MethodLocalObject$module$1: runtime.VolatileObjectRef): T#MethodLocalObject$2.type = { if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1); - MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]() + (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type](): T#MethodLocalObject$2.type) }; final private[this] def $anonfun$tryy$1(tryyParam$1: String, tryyLocal$1: runtime.ObjectRef): Unit = try { tryyLocal$1.elem = tryyParam$1 diff --git a/test/files/run/t6028.check b/test/files/run/t6028.check index 80f8698ecf..903ea3b753 100644 --- a/test/files/run/t6028.check +++ b/test/files/run/t6028.check @@ -59,7 +59,7 @@ package { final private[this] def MethodLocalObject$1(barParam$1: Int, MethodLocalObject$module$1: runtime.VolatileObjectRef): T#MethodLocalObject$2.type = { if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1); - MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]() + (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type](): T#MethodLocalObject$2.type) }; @SerialVersionUID(value = 0) final class $anonfun$tryy$1 extends scala.runtime.AbstractFunction0$mcV$sp with Serializable { def ($outer: T, tryyParam$1: Int, tryyLocal$1: runtime.IntRef): <$anon: Function0> = { -- cgit v1.2.3 From e07585c256b3dd2ab4d197c5480d1d962607879e Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 27 Sep 2016 09:40:17 +1000 Subject: Make isSeparateCompiled... robust against rogue phase time travel We don't hit this code path during bootstrapping, but we could conceivably hit it with macros or compiler plugins peering into the future through atPhase before refchecks as run. Also rename a method to reflect the generality of the info transform (it does more than mixin, now.) --- src/compiler/scala/tools/nsc/transform/Fields.scala | 4 ++-- src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index c39491cf9e..b8b2b64fb8 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -305,7 +305,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor lazyCallingSuper setInfo tp } - private def needsMixin(cls: Symbol): Boolean = { + private def classNeedsInfoTransform(cls: Symbol): Boolean = { !(cls.isPackageClass || cls.isJavaDefined) && (currentRun.compiles(cls) || refChecks.isSeparatelyCompiledScalaSuperclass(cls)) } @@ -365,7 +365,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor } else tp - case tp@ClassInfoType(parents, oldDecls, clazz) if !needsMixin(clazz) => tp + case tp@ClassInfoType(parents, oldDecls, clazz) if !classNeedsInfoTransform(clazz) => tp // mix in fields & accessors for all mixed in traits case tp@ClassInfoType(parents, oldDecls, clazz) => diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 24b4334ec4..106b076eef 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -96,7 +96,13 @@ abstract class RefChecks extends Transform { } private val separatelyCompiledScalaSuperclass = perRunCaches.newAnyRefMap[Symbol, Unit]() - final def isSeparatelyCompiledScalaSuperclass(sym: Symbol) = separatelyCompiledScalaSuperclass.contains(sym) + final def isSeparatelyCompiledScalaSuperclass(sym: Symbol) = if (globalPhase.refChecked){ + separatelyCompiledScalaSuperclass.contains(sym) + } else { + // conservative approximation in case someone in pre-refchecks phase asks for `exitingFields(someClass.info)` + // and we haven't run the refchecks tree transform which populates `separatelyCompiledScalaSuperclass` + false + } class RefCheckTransformer(unit: CompilationUnit) extends Transformer { -- cgit v1.2.3 From e3e1e30c08d8bb532ac1d36d191fc8d4dbab0eb9 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 13 Sep 2016 13:43:43 +1000 Subject: SI-9920 Avoid linkage errors with captured local objects + self types An outer parameter of a nested class is typed with the self type of the enclosing class: ``` class C; trait T { _: C => def x = 42; class D { x } } ``` leads to: ``` class D extends Object { def ($outer: C): T.this.D = { D.super.(); () }; D.this.$outer().$asInstanceOf[T]().x(); ``` Note that a cast is inserted before the call to `x`. If we modify that a little, to instead capture a local module: ``` class C; trait T { _: C => def y { object O; class D { O } } } ``` Scala 2.11 used to generate (after lambdalift): ``` class D$1 extends Object { def ($outer: C, O$module$1: runtime.VolatileObjectRef): C#D$1 = { D$1.super.(); () }; D$1.this.$outer().O$1(O$module$1); ``` That isn't type correct, `D$1.this.$outer() : C` does not have a member `O$1`. However, the old trait encoding would rewrite this in mixin to: ``` T$class.O$1($outer, O$module$1); ``` Trait implementation methods also used to accept the self type: ``` trait T$class { final def O$1($this: C, O$module$1: runtime.VolatileObjectRef): T$O$2.type } ``` So the problem was hidden. This commit changes replaces manual typecheckin of the selection in LambdaLift with a use of the local (erasure) typer, which will add casts as needed. For `run/t9220.scala`, this changes the post LambdaLift AST as follows: ``` class C1$1 extends Object { def ($outer: C0, Local$module$1: runtime.VolatileObjectRef): T#C1$1 = { C1$1.super.(); () }; - C1$1.this.$outer.Local$1(Local$module$1); + C1$1.this.$outer.$asInstanceOf[T]().Local$1(Local$module$1); private[this] val $outer: C0 = _; def $outer(): C0 = C1$1.this.$outer } ``` --- .../scala/tools/nsc/transform/ExplicitOuter.scala | 2 +- .../scala/tools/nsc/transform/LambdaLift.scala | 9 ++++++++- test/files/pos/t9920.scala | 6 ++++++ test/files/run/t9920.scala | 17 +++++++++++++++++ test/files/run/t9920b.scala | 17 +++++++++++++++++ test/files/run/t9920c.scala | 21 +++++++++++++++++++++ test/files/run/t9920d.scala | 14 ++++++++++++++ 7 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 test/files/pos/t9920.scala create mode 100644 test/files/run/t9920.scala create mode 100644 test/files/run/t9920b.scala create mode 100644 test/files/run/t9920c.scala create mode 100644 test/files/run/t9920d.scala diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index f3d5ceb0f0..7d50c12852 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -8,7 +8,7 @@ package tools.nsc package transform import symtab._ -import Flags.{ CASE => _, _ } +import Flags.{CASE => _, _} import scala.collection.mutable.ListBuffer /** This class ... diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 74e6c58388..10d9c5627b 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -319,7 +319,14 @@ abstract class LambdaLift extends InfoTransform { else if (clazz.isStaticOwner) gen.mkAttributedQualifier(clazz.thisType) else outerValue match { case EmptyTree => prematureSelfReference() - case o => outerPath(o, currentClass.outerClass, clazz) + case o => + val path = outerPath(o, currentClass.outerClass, clazz) + if (path.tpe <:< clazz.tpeHK) path + else { + // SI-9920 The outer accessor might have an erased type of the self type of a trait, + // rather than the trait itself. Add a cast if necessary. + gen.mkAttributedCast(path, clazz.tpeHK) + } } } diff --git a/test/files/pos/t9920.scala b/test/files/pos/t9920.scala new file mode 100644 index 0000000000..8612618cc4 --- /dev/null +++ b/test/files/pos/t9920.scala @@ -0,0 +1,6 @@ +object Test { + def o = { + def i: Int = { i; 0 } + i + } +} diff --git a/test/files/run/t9920.scala b/test/files/run/t9920.scala new file mode 100644 index 0000000000..5dc32e99b7 --- /dev/null +++ b/test/files/run/t9920.scala @@ -0,0 +1,17 @@ +class C0 +trait T { self: C0 => + def test = { + object Local + + class C1 { + Local + } + new C1() + } +} + +object Test extends C0 with T { + def main(args: Array[String]): Unit = { + test + } +} diff --git a/test/files/run/t9920b.scala b/test/files/run/t9920b.scala new file mode 100644 index 0000000000..fab196b669 --- /dev/null +++ b/test/files/run/t9920b.scala @@ -0,0 +1,17 @@ +class C0 +trait T { + def test = { + object Local + + class C1 { + Local + } + new C1() + } +} + +object Test extends C0 with T { + def main(args: Array[String]): Unit = { + test + } +} diff --git a/test/files/run/t9920c.scala b/test/files/run/t9920c.scala new file mode 100644 index 0000000000..9541dc650a --- /dev/null +++ b/test/files/run/t9920c.scala @@ -0,0 +1,21 @@ +class C0 +trait T { self: C0 => + def test = { + object Local + + class C2 { + class C1 { + Local + } + T.this.toString + new C1 + } + new C2() + } +} + +object Test extends C0 with T { + def main(args: Array[String]): Unit = { + test + } +} diff --git a/test/files/run/t9920d.scala b/test/files/run/t9920d.scala new file mode 100644 index 0000000000..debc99e199 --- /dev/null +++ b/test/files/run/t9920d.scala @@ -0,0 +1,14 @@ +class C { object O } +trait T { _: C => + def foo { + class D { O } + new D + } +} + + +object Test extends C with T { + def main(args: Array[String]): Unit = { + foo + } +} -- cgit v1.2.3 From c8468f966ae9f4b96c26a72a18d5c4a41e887c3f Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 27 Sep 2016 14:27:16 +1000 Subject: Restarr to JITtablity of generated synchronized blocks Depends on this build completing and being promoted to Maven Central. https://scala-ci.typesafe.com/view/scala-2.12.0/job/scala-2.12.0-release-main/86/console --- versions.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.properties b/versions.properties index 773999c485..7c357f7fa7 100644 --- a/versions.properties +++ b/versions.properties @@ -8,7 +8,7 @@ # The scala version used for bootstrapping. This has no impact on the final classfiles: # there are two stages (locker and quick), so compiler and library are always built # with themselves. Stability is ensured by building a third stage (strap). -starr.version=2.12.0-RC1-be43eb5 +starr.version=2.12.0-RC1-ceaf419 # These are the versions of the modules that go with this release. # These properties are used during PR validation and in dbuild builds. -- cgit v1.2.3 From 315e6a996e0c634412df3e5a21a7b9f49122a790 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 27 Sep 2016 15:26:52 -0700 Subject: Including Lightbend in `-version` message. Also consistently use "LAMP/EPFL" and not "EPFL LAMP". --- build.sbt | 2 +- project/VersionUtil.scala | 2 +- src/library/scala/util/Properties.scala | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.sbt b/build.sbt index 5d93804cbb..ce7bbb9c1c 100644 --- a/build.sbt +++ b/build.sbt @@ -160,7 +160,7 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings + lamp - EPFL LAMP + LAMP/EPFL Lightbend diff --git a/project/VersionUtil.scala b/project/VersionUtil.scala index 1c2fff27b7..5613520e27 100644 --- a/project/VersionUtil.scala +++ b/project/VersionUtil.scala @@ -18,7 +18,7 @@ object VersionUtil { ) lazy val generatePropertiesFileSettings = Seq[Setting[_]]( - copyrightString := "Copyright 2002-2016, LAMP/EPFL", + copyrightString := "Copyright 2002-2016, LAMP/EPFL and Lightbend, Inc.", resourceGenerators in Compile += generateVersionPropertiesFile.map(file => Seq(file)).taskValue, generateVersionPropertiesFile := generateVersionPropertiesFileImpl.value ) diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala index a176748cd6..fc2302d148 100644 --- a/src/library/scala/util/Properties.scala +++ b/src/library/scala/util/Properties.scala @@ -105,7 +105,7 @@ private[scala] trait PropertiesTrait { * or "version (unknown)" if it cannot be determined. */ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)") - val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2016, LAMP/EPFL") + val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2016, LAMP/EPFL and Lightbend, Inc.") /** This is the encoding to use reading in source files, overridden with -encoding. * Note that it uses "prop" i.e. looks in the scala jar, not the system properties. -- cgit v1.2.3 From 19f6209e5b1db295320bfbd3ef00eeaa729c1eec Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Mon, 26 Sep 2016 22:11:40 +0200 Subject: SI-9697 / SD-229 Fix DelayedInit subclass capturing local value When a class captures an outer value, a field for that value is created in the class. The class also gets a constructor parameter for the captured value, the constructor will assign the field. LambdaLift re-writes accesses to the local value (Ident trees) to the field. However, if the statement accessing the local value will end up inside the constructor, the access is re-written to the constructor parameter instead. This is the case for constructor statements: class C { { println(capturedLocal) } } If C extends DelayedInit, the statement does not end up in C's constructor, but into a new synthetic method. The access to `capturedLocal` needs to be re-written to the field instead of the constructor parameter. LambdaLift takes the decision (field or constructor parameter) based on the owner chain of `currentOwner`. For the constructor statement block, the owner is a local dummy, for which `logicallyEnclosingMember` returns the constructor symbol. This commit introduces a special case in LambdaLift for local dummies of DelayedInit subclasses: instead of the constructor, we use a temporary symbol representing the synthetic method holding the initializer statements. --- .../scala/tools/nsc/transform/LambdaLift.scala | 44 +++++-- src/reflect/scala/reflect/internal/Symbols.scala | 1 - test/files/run/t9697.check | 1 + test/files/run/t9697.scala | 127 +++++++++++++++++++++ 4 files changed, 162 insertions(+), 11 deletions(-) create mode 100644 test/files/run/t9697.check create mode 100644 test/files/run/t9697.scala diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 74e6c58388..1ec3d4d4cb 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -104,8 +104,31 @@ abstract class LambdaLift extends InfoTransform { /** Buffers for lifted out classes and methods */ private val liftedDefs = new LinkedHashMap[Symbol, List[Tree]] + val delayedInitDummies = new mutable.HashMap[Symbol, Symbol] + + /** + * For classes capturing locals, LambdaLift uses `local.logicallyEnclosingMember` to decide + * whether an access to the local is re-written to the field or constructor parameter. If the + * access is in a constructor statement, the constructor parameter is used. + * + * For DelayedInit subclasses, constructor statements end up in the synthetic init method + * instead of the constructor itself, so the access should go to the field. This method changes + * `logicallyEnclosingMember` in this case to return a temprorary symbol corresponding to that + * method. + */ + private def logicallyEnclosingMember(sym: Symbol): Symbol = { + if (sym.isLocalDummy) { + val enclClass = sym.enclClass + if (enclClass.isSubClass(DelayedInitClass)) + delayedInitDummies.getOrElseUpdate(enclClass, enclClass.newMethod(nme.delayedInit)) + else + enclClass.primaryConstructor + } else if (sym.isMethod || sym.isClass || sym == NoSymbol) sym + else logicallyEnclosingMember(sym.owner) + } + private def isSameOwnerEnclosure(sym: Symbol) = - sym.owner.logicallyEnclosingMember == currentOwner.logicallyEnclosingMember + logicallyEnclosingMember(sym.owner) == logicallyEnclosingMember(currentOwner) /** Mark symbol `sym` as being free in `enclosure`, unless `sym` * is defined in `enclosure` or there is a class between `enclosure`s owner @@ -139,9 +162,9 @@ abstract class LambdaLift extends InfoTransform { */ private def markFree(sym: Symbol, enclosure: Symbol): Boolean = { // println(s"mark free: ${sym.fullLocationString} marked free in $enclosure") - (enclosure == sym.owner.logicallyEnclosingMember) || { - debuglog("%s != %s".format(enclosure, sym.owner.logicallyEnclosingMember)) - if (enclosure.isPackageClass || !markFree(sym, enclosure.skipConstructor.owner.logicallyEnclosingMember)) false + (enclosure == logicallyEnclosingMember(sym.owner)) || { + debuglog("%s != %s".format(enclosure, logicallyEnclosingMember(sym.owner))) + if (enclosure.isPackageClass || !markFree(sym, logicallyEnclosingMember(enclosure.skipConstructor.owner))) false else { val ss = symSet(free, enclosure) if (!ss(sym)) { @@ -184,14 +207,14 @@ abstract class LambdaLift extends InfoTransform { if (sym == NoSymbol) { assert(name == nme.WILDCARD) } else if (sym.isLocalToBlock) { - val owner = currentOwner.logicallyEnclosingMember + val owner = logicallyEnclosingMember(currentOwner) if (sym.isTerm && !sym.isMethod) markFree(sym, owner) else if (sym.isMethod) markCalled(sym, owner) //symSet(called, owner) += sym } case Select(_, _) => if (sym.isConstructor && sym.owner.isLocalToBlock) - markCalled(sym, currentOwner.logicallyEnclosingMember) + markCalled(sym, logicallyEnclosingMember(currentOwner)) case _ => } super.traverse(tree) @@ -283,17 +306,18 @@ abstract class LambdaLift extends InfoTransform { private def proxy(sym: Symbol) = { def searchIn(enclosure: Symbol): Symbol = { - if (enclosure eq NoSymbol) throw new IllegalArgumentException("Could not find proxy for "+ sym.defString +" in "+ sym.ownerChain +" (currentOwner= "+ currentOwner +" )") - debuglog("searching for " + sym + "(" + sym.owner + ") in " + enclosure + " " + enclosure.logicallyEnclosingMember) + if (enclosure eq NoSymbol) + throw new IllegalArgumentException("Could not find proxy for "+ sym.defString +" in "+ sym.ownerChain +" (currentOwner= "+ currentOwner +" )") + debuglog("searching for " + sym + "(" + sym.owner + ") in " + enclosure + " " + logicallyEnclosingMember(enclosure)) val proxyName = proxyNames.getOrElse(sym, sym.name) - val ps = (proxies get enclosure.logicallyEnclosingMember).toList.flatten find (_.name == proxyName) + val ps = (proxies get logicallyEnclosingMember(enclosure)).toList.flatten find (_.name == proxyName) ps getOrElse searchIn(enclosure.skipConstructor.owner) } debuglog("proxy %s from %s has logical enclosure %s".format( sym.debugLocationString, currentOwner.debugLocationString, - sym.owner.logicallyEnclosingMember.debugLocationString) + logicallyEnclosingMember(sym.owner).debugLocationString) ) if (isSameOwnerEnclosure(sym)) sym diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index ac025e50ae..f870ecfc15 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -2166,7 +2166,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def logicallyEnclosingMember: Symbol = if (isLocalDummy) enclClass.primaryConstructor else if (isMethod || isClass || this == NoSymbol) this - else if (this == NoSymbol) { devWarningDumpStack("NoSymbol.logicallyEnclosingMember", 15); this } else owner.logicallyEnclosingMember /** The top-level class containing this symbol. */ diff --git a/test/files/run/t9697.check b/test/files/run/t9697.check new file mode 100644 index 0000000000..bbd9fd19cf --- /dev/null +++ b/test/files/run/t9697.check @@ -0,0 +1 @@ +warning: there were 6 deprecation warnings (since 2.11.0); re-run with -deprecation for details diff --git a/test/files/run/t9697.scala b/test/files/run/t9697.scala new file mode 100644 index 0000000000..b837feb237 --- /dev/null +++ b/test/files/run/t9697.scala @@ -0,0 +1,127 @@ +object log { + val b = new collection.mutable.StringBuilder + def apply(s: Any): Unit = b.append(s) + def check(s: String) = { + val bs = b.toString + assert(s == bs, bs) + b.clear() + } +} + +package t9697 { + abstract class WA extends DelayedInit { + override def delayedInit(x: => Unit): Unit = x + val waField = "4" + } + + class C { + def b(s: String) = log(s) + val cField = "1" + + { + val dummyLocal = "2" + new WA { + val anonField = "3" + b(cField) + b(dummyLocal) + b(anonField) + b(waField) + } + } + } +} + +package sd229 { + class Broken { + def is(ee: AnyRef) = { + new Delayed { + log(ee) + } + } + } + + class Delayed extends DelayedInit { + def delayedInit(x: => Unit): Unit = x + } +} + + +// already fixed in 2.11.8, crashes in 2.10.6 +package t4683a { + class A { log("a") } + class B { log("b") } + class Bug extends DelayedInit { + log("bug") + def foo(a: A): B = new B + def delayedInit(init: => Unit): Unit = init + } +} + +// already fixed in 2.12.0-RC1, crashes in 2.11.8 +package t4683b { + class Entity extends DelayedInit { + def delayedInit(x: => Unit): Unit = x + + class Field + + protected def EntityField[T <: Entity: reflect.ClassTag] = new Field + + def find[T <: Entity: reflect.ClassTag] { + Nil.map(dbo => { + class EntityHolder extends Entity { + val entity = EntityField[T] + } + }) + log("find") + } + } +} + +package t4683c { + trait T extends DelayedInit { + def delayedInit(body: => Unit) = { + log("init") + body + } + } +} + +package t4683d { + class C extends DelayedInit { + def delayedInit(body: => Unit): Unit = body + } + class Injector { + def test: Object = { + val name = "k" + class crash extends C { + log(name) + } + new crash() + } + } +} + +object Test extends App { + new t9697.C() + log.check("1234") + + new sd229.Broken().is("hi") + log.check("hi") + + val a: t4683a.A = new t4683a.A + var b: t4683a.B = null + new t4683a.Bug { + val b = foo(a) + } + log.check("abugb") + + new t4683b.Entity().find[t4683b.Entity] + log.check("find") + + val f = (p1: Int) => new t4683c.T { log(p1) } + f(5) + log.check("init5") + + new t4683d.Injector().test + log.check("k") +} -- cgit v1.2.3 From ad6bf3033fbdbd1d2c8bdea245f8347cfe292c1b Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 27 Sep 2016 08:05:47 +0200 Subject: SI-4683 fix $outer accesses in class bodies extending DelayedInit Constructors rewrites references to parameter accessor methods in the constructor to references to parameters. It avoids doing so for subclasses of DelayedInit. This commit makes sure the rewrite does not happen for the $outer paramter, a case that was simply forgotten. --- .../scala/tools/nsc/transform/Constructors.scala | 2 +- test/files/run/t9697.check | 2 +- test/files/run/t9697.scala | 77 ++++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 8d362f13dd..daf645fd20 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -527,7 +527,7 @@ abstract class Constructors extends Statics with Transform with TypingTransforme super.transform(tree) else if (canBeSupplanted(tree.symbol)) gen.mkAttributedIdent(parameter(tree.symbol)) setPos tree.pos - else if (tree.symbol.outerSource == clazz) + else if (tree.symbol.outerSource == clazz && !isDelayedInitSubclass) gen.mkAttributedIdent(parameterNamed(nme.OUTER)) setPos tree.pos else super.transform(tree) diff --git a/test/files/run/t9697.check b/test/files/run/t9697.check index bbd9fd19cf..2a4f01c14f 100644 --- a/test/files/run/t9697.check +++ b/test/files/run/t9697.check @@ -1 +1 @@ -warning: there were 6 deprecation warnings (since 2.11.0); re-run with -deprecation for details +warning: there were 9 deprecation warnings (since 2.11.0); re-run with -deprecation for details diff --git a/test/files/run/t9697.scala b/test/files/run/t9697.scala index b837feb237..eb8e44f8fc 100644 --- a/test/files/run/t9697.scala +++ b/test/files/run/t9697.scala @@ -101,6 +101,57 @@ package t4683d { } } +package t4683e { + class DelayedInitTest { + def a = log("uh") + class B extends DelayedInit { + a + def delayedInit(body: => Unit): Unit = body + } + } +} + +package t4683f { + class Foo extends DelayedInit { + log("fooInit") + def delayedInit(newBody: => Unit): Unit = { + log("delayedInit") + inits = { + val f = () => newBody + if (inits == null) { + log("initsNull") + List(f) + } else + f :: inits + } + } + def foo = log("foo") + var inits: List[() => Unit] = Nil + } + + class Bar extends Foo { + log("barInit") + def bar = foo + def newBaz: Foo = new Baz + private class Baz extends Foo { + log("bazInit") + bar + } + } +} + +package t4683g { + trait MatExpWorld { self => + class T extends Runner { val expWorld: self.type = self } + } + + trait Runner extends DelayedInit { + def delayedInit(init: => Unit): Unit = init + val expWorld: MatExpWorld + } +} + + object Test extends App { new t9697.C() log.check("1234") @@ -124,4 +175,30 @@ object Test extends App { new t4683d.Injector().test log.check("k") + + val dit = new t4683e.DelayedInitTest() + new dit.B() + log.check("uh") + + val fuu = new t4683f.Foo + log.check("delayedInitinitsNull") + fuu.inits.foreach(_.apply()) + log.check("fooInit") + assert(fuu.inits == Nil) // the (delayed) initializer of Foo sets the inits field to Nil + + val brr = new t4683f.Bar + log.check("delayedInitinitsNulldelayedInit") // delayedInit is called once for each constructor + brr.inits.foreach(_.apply()) + log.check("barInitfooInit") + assert(brr.inits == Nil) + + val bzz = brr.newBaz + log.check("delayedInitinitsNulldelayedInit") + bzz.inits.foreach(_.apply()) + log.check("bazInitfoofooInit") + assert(bzz.inits == Nil) + + val mew = new t4683g.MatExpWorld { } + val mt = new mew.T + assert(mt.expWorld == mew) } -- cgit v1.2.3 From d04cda14d722ff365b4c3b543de008d93772410b Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Wed, 28 Sep 2016 10:15:12 -0700 Subject: Make some name suffixes constants There's still a lot of duplication, as well as plenty of opportunities for constant folding / simplification. --- src/library/scala/reflect/NameTransformer.scala | 19 ++++++++++--------- src/reflect/scala/reflect/internal/StdNames.scala | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/library/scala/reflect/NameTransformer.scala b/src/library/scala/reflect/NameTransformer.scala index ae36f5edc2..bdf5165df5 100644 --- a/src/library/scala/reflect/NameTransformer.scala +++ b/src/library/scala/reflect/NameTransformer.scala @@ -13,15 +13,16 @@ package reflect * Also provides some constants. */ object NameTransformer { - // XXX Short term: providing a way to alter these without having to recompile - // the compiler before recompiling the compiler. - val MODULE_SUFFIX_STRING = sys.props.getOrElse("SCALA_MODULE_SUFFIX_STRING", "$") - val NAME_JOIN_STRING = sys.props.getOrElse("SCALA_NAME_JOIN_STRING", "$") - val MODULE_INSTANCE_NAME = "MODULE$" - val LOCAL_SUFFIX_STRING = " " - val LAZY_LOCAL_SUFFIX_STRING = "$lzy" - val SETTER_SUFFIX_STRING = "_$eq" - val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$" + // TODO: reduce duplication with and in StdNames + // I made these constants because we cannot change them without bumping our major version anyway. + final val NAME_JOIN_STRING = "$" + final val MODULE_SUFFIX_STRING = "$" + final val MODULE_INSTANCE_NAME = "MODULE$" + final val LOCAL_SUFFIX_STRING = " " + final val LAZY_LOCAL_SUFFIX_STRING = "$lzy" + final val MODULE_VAR_SUFFIX_STRING = "$module" + final val SETTER_SUFFIX_STRING = "_$eq" + final val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$" private val nops = 128 private val ncodes = 26 * 26 diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 1a6c84b19e..2e820a68e0 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -92,14 +92,15 @@ trait StdNames { def flattenedName(segments: Name*): NameType = compactify(segments mkString NAME_JOIN_STRING) - val NAME_JOIN_STRING: String = NameTransformer.NAME_JOIN_STRING - val MODULE_SUFFIX_STRING: String = NameTransformer.MODULE_SUFFIX_STRING - val LOCAL_SUFFIX_STRING: String = NameTransformer.LOCAL_SUFFIX_STRING - val LAZY_LOCAL_SUFFIX_STRING: String = NameTransformer.LAZY_LOCAL_SUFFIX_STRING - - val TRAIT_SETTER_SEPARATOR_STRING: String = NameTransformer.TRAIT_SETTER_SEPARATOR_STRING - - val SINGLETON_SUFFIX: String = ".type" + // TODO: what is the purpose of all this duplication!?!?! + // I made these constants because we cannot change them without bumping our major version anyway. + final val NAME_JOIN_STRING = NameTransformer.NAME_JOIN_STRING + final val MODULE_SUFFIX_STRING = NameTransformer.MODULE_SUFFIX_STRING + final val MODULE_VAR_SUFFIX_STRING = NameTransformer.MODULE_VAR_SUFFIX_STRING + final val LOCAL_SUFFIX_STRING = NameTransformer.LOCAL_SUFFIX_STRING + final val LAZY_LOCAL_SUFFIX_STRING = NameTransformer.LAZY_LOCAL_SUFFIX_STRING + final val TRAIT_SETTER_SEPARATOR_STRING = NameTransformer.TRAIT_SETTER_SEPARATOR_STRING + final val SINGLETON_SUFFIX = ".type" val ANON_CLASS_NAME: NameType = "$anon" val DELAMBDAFY_LAMBDA_CLASS_NAME: NameType = "$lambda" @@ -108,7 +109,7 @@ trait StdNames { val EMPTY_PACKAGE_NAME: NameType = "" val IMPORT: NameType = "" val MODULE_SUFFIX_NAME: NameType = MODULE_SUFFIX_STRING - val MODULE_VAR_SUFFIX: NameType = "$module" + val MODULE_VAR_SUFFIX: NameType = MODULE_VAR_SUFFIX_STRING val PACKAGE: NameType = "package" val ROOT: NameType = "" val SPECIALIZED_SUFFIX: NameType = "$sp" -- cgit v1.2.3 From 3bce35e5ce36ca912762375da27e94275aead023 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Wed, 28 Sep 2016 20:55:33 -0700 Subject: don't deprecate Either.left and Either.right yet for two reasons: * to facilitate warning-free cross-compilation between Scala 2.11 and 2.12 * because it's not clear that .swap is a good replacement for .left Either.right seems almost certain to be deprecated in 2.13. Either.left's future is uncertain; see discussion (and links to additional discussions) at https://github.com/scala/scala/pull/5135 --- src/library/scala/util/Either.scala | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/library/scala/util/Either.scala b/src/library/scala/util/Either.scala index 169786d31b..c332f18295 100644 --- a/src/library/scala/util/Either.scala +++ b/src/library/scala/util/Either.scala @@ -95,13 +95,15 @@ sealed abstract class Either[+A, +B] extends Product with Serializable { /** * Projects this `Either` as a `Left`. */ - @deprecated("use swap instead", "2.12.0") def left = Either.LeftProjection(this) /** * Projects this `Either` as a `Right`. + * + * Because `Either` is right-biased, this method is not normally needed. + * (It is retained in the API for now for easy cross-compilation between Scala + * 2.11 and 2.12.) */ - @deprecated("Either is now right-biased", "2.12.0") def right = Either.RightProjection(this) /** @@ -245,7 +247,7 @@ sealed abstract class Either[+A, +B] extends Product with Serializable { /** * Returns `true` if `Left` or returns the result of the application of - * the given function to the `Right` value. + * the given predicate to the `Right` value. * * {{{ * Right(12).forall(_ > 10) // true @@ -260,7 +262,7 @@ sealed abstract class Either[+A, +B] extends Product with Serializable { /** * Returns `false` if `Left` or returns the result of the application of - * the given function to the `Right` value. + * the given predicate to the `Right` value. * * {{{ * Right(12).exists(_ > 10) // true @@ -426,7 +428,10 @@ object Either { /** * Projects an `Either` into a `Left`. * - * This allows for-comprehensions over Either instances - for example {{{ + * This allows for-comprehensions over the left side of Either instances, + * reversing Either's usual right-bias. + * + * For example {{{ * for (s <- Left("flower").left) yield s.length // Left(6) * }}} * @@ -472,7 +477,6 @@ object Either { * @author Tony Morris, Workingmouse * @version 1.0, 11/10/2008 */ - @deprecated("use swap instead", "2.12.0") final case class LeftProjection[+A, +B](e: Either[A, B]) { /** * Returns the value from this `Left` or throws `java.util.NoSuchElementException` @@ -624,19 +628,13 @@ object Either { /** * Projects an `Either` into a `Right`. * - * This allows for-comprehensions over Either instances - for example {{{ - * for (s <- Right("flower").right) yield s.length // Right(6) - * }}} - * - * Continuing the analogy with [[scala.Option]], a `RightProjection` declares - * that `Right` should be analogous to `Some` in some code. - * - * Analogous to `LeftProjection`, see example usage in its documentation above. + * Because `Either` is already right-biased, this class is not normally needed. + * (It is retained in the library for now for easy cross-compilation between Scala + * 2.11 and 2.12.) * * @author Tony Morris, Workingmouse * @version 1.0, 11/10/2008 */ - @deprecated("Either is now right-biased", "2.12.0") final case class RightProjection[+A, +B](e: Either[A, B]) { /** -- cgit v1.2.3 From 8c735bfbd5b8e25ad3471540562d32d500eb3847 Mon Sep 17 00:00:00 2001 From: Stefan Zeiger Date: Mon, 19 Sep 2016 18:42:35 +0200 Subject: Enable MiMa for 2.12.0 --- build.sbt | 2 +- project/plugins.sbt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index ce7bbb9c1c..59d5289f38 100644 --- a/build.sbt +++ b/build.sbt @@ -88,7 +88,7 @@ lazy val publishSettings : Seq[Setting[_]] = Seq( globalVersionSettings baseVersion in Global := "2.12.0" baseVersionSuffix in Global := "SNAPSHOT" -mimaReferenceVersion in Global := None +mimaReferenceVersion in Global := Some("2.12.0-RC1") lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings ++ Seq[Setting[_]]( organization := "org.scala-lang", diff --git a/project/plugins.sbt b/project/plugins.sbt index 0a5b8f3dd4..da84d48915 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -19,4 +19,4 @@ buildInfoKeys := Seq[BuildInfoKey](buildClasspath) buildInfoPackage := "scalabuild" -libraryDependencies += "com.typesafe" %% "mima-reporter" % "0.1.8" +libraryDependencies += "com.typesafe" %% "mima-reporter" % "0.1.10" -- cgit v1.2.3 From 493e22f321d6e7774e74419242b6e3d61eff6bad Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 27 Sep 2016 16:58:25 -0700 Subject: Emit local module like lazy val The motivation is to use the new fine-grained lock scoping that local lazies have since #5294. Fixes scala/scala-dev#235 Co-Authored-By: Jason Zaugg --- .../scala/tools/nsc/transform/Fields.scala | 42 +++++++++++----------- test/files/run/SD-235.scala | 39 ++++++++++++++++++++ test/files/run/delambdafy_t6028.check | 17 ++++----- test/files/run/local_obj.scala | 9 +++++ test/files/run/t6028.check | 17 ++++----- .../nsc/backend/jvm/opt/ScalaInlineInfoTest.scala | 4 +-- 6 files changed, 88 insertions(+), 40 deletions(-) create mode 100644 test/files/run/SD-235.scala create mode 100644 test/files/run/local_obj.scala diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index 6cf6a5abce..0c6982384d 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -193,20 +193,6 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor // not be emitted as ACC_FINAL. They are FINAL in the Scala sense, though: cannot be overridden. private final val ModuleOrLazyFieldFlags = FINAL | PrivateLocal | SYNTHETIC | NEEDS_TREES - private def newModuleVarSymbol(owner: Symbol, module: Symbol, tp: Type): TermSymbol = { -// println(s"new module var in $site for $module of type $tp") - val flags = MODULEVAR | (if (owner.isClass) ModuleOrLazyFieldFlags else 0) - - val moduleVar = - (owner.newVariable(nme.moduleVarName(module.name.toTermName), module.pos.focus, flags) - setInfo tp - addAnnotation VolatileAttr) - - moduleOrLazyVarOf(module) = moduleVar - - moduleVar - } - private def moduleInit(module: Symbol, moduleVar: Symbol) = { // println(s"moduleInit for $module in ${module.ownerChain} --> ${moduleVarOf.get(module)}") def moduleVarRef = gen.mkAttributedRef(moduleVar) @@ -380,8 +366,16 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor (existingGetter ne NoSymbol) && (tp matches (site memberInfo existingGetter).resultType) // !existingGetter.isDeferred && -- see (3) } - def newModuleVarMember(member: Symbol): TermSymbol = - newModuleVarSymbol(clazz, member, site.memberType(member).resultType) + def newModuleVarMember(module: Symbol): TermSymbol = { + val moduleVar = + (clazz.newVariable(nme.moduleVarName(module.name.toTermName), module.pos.focus, MODULEVAR | ModuleOrLazyFieldFlags) + setInfo site.memberType(module).resultType + addAnnotation VolatileAttr) + + moduleOrLazyVarOf(module) = moduleVar + + moduleVar + } def newLazyVarMember(member: Symbol): TermSymbol = Fields.this.newLazyVarMember(clazz, member, site.memberType(member).resultType) @@ -531,7 +525,8 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor def mkTypedValDef(sym: Symbol, rhs: Tree = EmptyTree) = typedPos(sym.pos)(ValDef(sym, rhs)).asInstanceOf[ValDef] /** - * Desugar a local `lazy val x: Int = rhs` into + * Desugar a local `lazy val x: Int = rhs` or a local object into + * * ``` * val x$lzy = new scala.runtime.LazyInt() * def x$lzycompute(): Int = @@ -541,10 +536,13 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor * } * def x(): Int = if (x$lzy.initialized()) x$lzy.value() else x$lzycompute() * ``` + * + * The expansion is the same for local lazy vals and local objects, + * except for the name of the val ($lzy or */ private def mkLazyLocalDef(lazyVal: Symbol, rhs: Tree): Tree = { import CODE._ - import scala.reflect.NameTransformer.LAZY_LOCAL_SUFFIX_STRING + import scala.reflect.{NameTransformer => nx} val owner = lazyVal.owner val lazyValType = lazyVal.tpe.resultType @@ -555,8 +553,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor val lazyName = lazyVal.name.toTermName val pos = lazyVal.pos.focus - // used twice: once in the same owner as the lazy val, another time inside the compute method - val localLazyName = lazyName append LAZY_LOCAL_SUFFIX_STRING + val localLazyName = lazyName append (if (lazyVal.isModule) nx.MODULE_VAR_SUFFIX_STRING else nx.LAZY_LOCAL_SUFFIX_STRING) // The lazy holder val need not be mutable, as we write to its field. // In fact, it MUST not be mutable to avoid capturing it as an ObjectRef in lambdalift @@ -730,8 +727,9 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor val cd = super.transform(ClassDef(statSym.moduleClass, impl) setType NoType) if (currOwner.isClass) cd else { // local module -- symbols cannot be generated by info transformer, so do it all here - val moduleVar = newModuleVarSymbol(currOwner, statSym, statSym.info.resultType) - Thicket(cd :: mkTypedValDef(moduleVar) :: mkAccessor(statSym)(moduleInit(statSym, moduleVar)) :: Nil) + val Block(stats, _) = mkLazyLocalDef(statSym, gen.newModule(statSym, statSym.info.resultType)) + + Thicket(cd :: stats) } case tree => diff --git a/test/files/run/SD-235.scala b/test/files/run/SD-235.scala new file mode 100644 index 0000000000..eb79c6fe71 --- /dev/null +++ b/test/files/run/SD-235.scala @@ -0,0 +1,39 @@ +class C { + var ORef: Object = null + def test = { + object O { + assert(!Thread.holdsLock(C.this)) + assert(Thread.holdsLock(ORef)) + } + val captor = new { def oh = O } + val refField = captor.getClass.getDeclaredFields.last + refField.setAccessible(true) + assert(refField.getType.toString.contains("LazyRef"), refField) + ORef = refField.get(captor) + O + } +} + +class D { + var ORef: Object = null + def test = { + lazy val O = { + assert(!Thread.holdsLock(D.this)) + assert(Thread.holdsLock(ORef)) + "O" + } + val captor = new { def oh = O } + val refField = captor.getClass.getDeclaredFields.last + refField.setAccessible(true) + assert(refField.getType.toString.contains("LazyRef"), refField) + ORef = refField.get(captor) + O + } +} + +object Test { + def main(args: Array[String]): Unit = { + new C().test + new D().test + } +} diff --git a/test/files/run/delambdafy_t6028.check b/test/files/run/delambdafy_t6028.check index 7b319c92dd..86cb1d5e97 100644 --- a/test/files/run/delambdafy_t6028.check +++ b/test/files/run/delambdafy_t6028.check @@ -15,7 +15,7 @@ package { } }; def bar(barParam: String): Object = { - @volatile var MethodLocalObject$module: runtime.VolatileObjectRef = scala.runtime.VolatileObjectRef.zero(); + lazy val MethodLocalObject$module: scala.runtime.LazyRef = new scala.runtime.LazyRef(); T.this.MethodLocalObject$1(barParam, MethodLocalObject$module) }; def tryy(tryyParam: String): Function0 = { @@ -42,13 +42,14 @@ package { def $outer(): T = MethodLocalObject$2.this.$outer; def $outer(): T = MethodLocalObject$2.this.$outer }; - final private[this] def MethodLocalObject$lzycompute$1(barParam$1: String, MethodLocalObject$module$1: runtime.VolatileObjectRef): Unit = T.this.synchronized[Unit](if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) - MethodLocalObject$module$1.elem = new T#MethodLocalObject$2.type(T.this, barParam$1)); - final private[this] def MethodLocalObject$1(barParam$1: String, MethodLocalObject$module$1: runtime.VolatileObjectRef): T#MethodLocalObject$2.type = { - if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) - T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1); - (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type](): T#MethodLocalObject$2.type) - }; + final private[this] def MethodLocalObject$lzycompute$1(barParam$1: String, MethodLocalObject$module$1: scala.runtime.LazyRef): T#MethodLocalObject$2.type = MethodLocalObject$module$1.synchronized[T#MethodLocalObject$2.type](if (MethodLocalObject$module$1.initialized()) + MethodLocalObject$module$1.value().$asInstanceOf[T#MethodLocalObject$2.type]() + else + MethodLocalObject$module$1.initialize(new T#MethodLocalObject$2.type(T.this, barParam$1)).$asInstanceOf[T#MethodLocalObject$2.type]()); + final private[this] def MethodLocalObject$1(barParam$1: String, MethodLocalObject$module$1: scala.runtime.LazyRef): T#MethodLocalObject$2.type = if (MethodLocalObject$module$1.initialized()) + MethodLocalObject$module$1.value().$asInstanceOf[T#MethodLocalObject$2.type]() + else + T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1); final private[this] def $anonfun$tryy$1(tryyParam$1: String, tryyLocal$1: runtime.ObjectRef): Unit = try { tryyLocal$1.elem = tryyParam$1 } finally () diff --git a/test/files/run/local_obj.scala b/test/files/run/local_obj.scala new file mode 100644 index 0000000000..25123f7078 --- /dev/null +++ b/test/files/run/local_obj.scala @@ -0,0 +1,9 @@ +class C { + val z = 2 + def mod = { object x { val y = z } ; x.y } +} + +object Test extends App { + val c = new C + assert(c.mod == c.z, s"${c.mod} != ${c.z}") +} diff --git a/test/files/run/t6028.check b/test/files/run/t6028.check index 903ea3b753..05634fa8eb 100644 --- a/test/files/run/t6028.check +++ b/test/files/run/t6028.check @@ -15,7 +15,7 @@ package { } }; def bar(barParam: Int): Object = { - @volatile var MethodLocalObject$module: runtime.VolatileObjectRef = scala.runtime.VolatileObjectRef.zero(); + lazy val MethodLocalObject$module: scala.runtime.LazyRef = new scala.runtime.LazyRef(); T.this.MethodLocalObject$1(barParam, MethodLocalObject$module) }; def tryy(tryyParam: Int): Function0 = { @@ -54,13 +54,14 @@ package { def $outer(): T = MethodLocalObject$2.this.$outer; def $outer(): T = MethodLocalObject$2.this.$outer }; - final private[this] def MethodLocalObject$lzycompute$1(barParam$1: Int, MethodLocalObject$module$1: runtime.VolatileObjectRef): Unit = T.this.synchronized[Unit](if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) - MethodLocalObject$module$1.elem = new T#MethodLocalObject$2.type(T.this, barParam$1)); - final private[this] def MethodLocalObject$1(barParam$1: Int, MethodLocalObject$module$1: runtime.VolatileObjectRef): T#MethodLocalObject$2.type = { - if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null)) - T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1); - (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type](): T#MethodLocalObject$2.type) - }; + final private[this] def MethodLocalObject$lzycompute$1(barParam$1: Int, MethodLocalObject$module$1: scala.runtime.LazyRef): T#MethodLocalObject$2.type = MethodLocalObject$module$1.synchronized[T#MethodLocalObject$2.type](if (MethodLocalObject$module$1.initialized()) + MethodLocalObject$module$1.value().$asInstanceOf[T#MethodLocalObject$2.type]() + else + MethodLocalObject$module$1.initialize(new T#MethodLocalObject$2.type(T.this, barParam$1)).$asInstanceOf[T#MethodLocalObject$2.type]()); + final private[this] def MethodLocalObject$1(barParam$1: Int, MethodLocalObject$module$1: scala.runtime.LazyRef): T#MethodLocalObject$2.type = if (MethodLocalObject$module$1.initialized()) + MethodLocalObject$module$1.value().$asInstanceOf[T#MethodLocalObject$2.type]() + else + T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1); @SerialVersionUID(value = 0) final class $anonfun$tryy$1 extends scala.runtime.AbstractFunction0$mcV$sp with Serializable { def ($outer: T, tryyParam$1: Int, tryyLocal$1: runtime.IntRef): <$anon: Function0> = { $anonfun$tryy$1.super.(); diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala index 8861577366..5cedc483cd 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala @@ -105,10 +105,10 @@ class ScalaInlineInfoTest extends BytecodeTesting { ("x4$(LT;)I", MethodInlineInfo(true ,false,false)), ("x5()I", MethodInlineInfo(true, false,false)), ("x5$(LT;)I", MethodInlineInfo(true ,false,false)), - ("L$1(Lscala/runtime/VolatileObjectRef;)LT$L$2$;", MethodInlineInfo(true, false,false)), + ("L$1(Lscala/runtime/LazyRef;)LT$L$2$;", MethodInlineInfo(true, false,false)), ("nest$1()I", MethodInlineInfo(true, false,false)), ("$init$(LT;)V", MethodInlineInfo(true,false,false)), - ("L$lzycompute$1(Lscala/runtime/VolatileObjectRef;)V", MethodInlineInfo(true,false,false)) + ("L$lzycompute$1(Lscala/runtime/LazyRef;)LT$L$2$;", MethodInlineInfo(true,false,false)) ), None // warning ) -- cgit v1.2.3 From 515bc60e028c6d1c204e914b0869b4f0bd6dab8e Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 29 Sep 2016 11:54:45 -0700 Subject: Clarify docs, variable name A local lazy val and a local object are expanded in the same way. --- .../scala/tools/nsc/transform/Fields.scala | 23 +++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index 0c6982384d..aa2ccd9788 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -525,7 +525,8 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor def mkTypedValDef(sym: Symbol, rhs: Tree = EmptyTree) = typedPos(sym.pos)(ValDef(sym, rhs)).asInstanceOf[ValDef] /** - * Desugar a local `lazy val x: Int = rhs` or a local object into + * Desugar a local `lazy val x: Int = rhs` + * or a local `object x { ...}` (the rhs will be instantiating the module's class) into: * * ``` * val x$lzy = new scala.runtime.LazyInt() @@ -538,22 +539,22 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor * ``` * * The expansion is the same for local lazy vals and local objects, - * except for the name of the val ($lzy or + * except for the suffix of the underlying val's name ($lzy or $module) */ - private def mkLazyLocalDef(lazyVal: Symbol, rhs: Tree): Tree = { + private def mkLazyLocalDef(lazySym: Symbol, rhs: Tree): Tree = { import CODE._ import scala.reflect.{NameTransformer => nx} - val owner = lazyVal.owner + val owner = lazySym.owner - val lazyValType = lazyVal.tpe.resultType + val lazyValType = lazySym.tpe.resultType val refClass = lazyHolders.getOrElse(lazyValType.typeSymbol, LazyRefClass) val isUnit = refClass == LazyUnitClass val refTpe = if (refClass != LazyRefClass) refClass.tpe else appliedType(refClass.typeConstructor, List(lazyValType)) - val lazyName = lazyVal.name.toTermName - val pos = lazyVal.pos.focus + val lazyName = lazySym.name.toTermName + val pos = lazySym.pos.focus - val localLazyName = lazyName append (if (lazyVal.isModule) nx.MODULE_VAR_SUFFIX_STRING else nx.LAZY_LOCAL_SUFFIX_STRING) + val localLazyName = lazyName append (if (lazySym.isModule) nx.MODULE_VAR_SUFFIX_STRING else nx.LAZY_LOCAL_SUFFIX_STRING) // The lazy holder val need not be mutable, as we write to its field. // In fact, it MUST not be mutable to avoid capturing it as an ObjectRef in lambdalift @@ -573,14 +574,14 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor val computerSym = owner.newMethod(lazyName append nme.LAZY_SLOW_SUFFIX, pos, ARTIFACT | PRIVATE) setInfo MethodType(Nil, lazyValType) - val rhsAtComputer = rhs.changeOwner(lazyVal -> computerSym) + val rhsAtComputer = rhs.changeOwner(lazySym -> computerSym) val computer = mkAccessor(computerSym)(gen.mkSynchronized(Ident(holderSym))( If(initialized, getValue, if (isUnit) Block(rhsAtComputer :: Nil, Apply(initialize, Nil)) else Apply(initialize, rhsAtComputer :: Nil)))) - val accessor = mkAccessor(lazyVal)( + val accessor = mkAccessor(lazySym)( If(initialized, getValue, Apply(Ident(computerSym), Nil))) @@ -588,7 +589,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor // remove STABLE: prevent replacing accessor call of type Unit by BoxedUnit.UNIT in erasure // remove ACCESSOR: prevent constructors from eliminating the method body if the lazy val is // lifted into a trait (TODO: not sure about the details here) - lazyVal.resetFlag(STABLE | ACCESSOR) + lazySym.resetFlag(STABLE | ACCESSOR) Thicket(mkTypedValDef(holderSym, New(refTpe)) :: computer :: accessor :: Nil) } -- cgit v1.2.3 From da660071143de9ec763b47a9c67c0623b4b4edc6 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Thu, 29 Sep 2016 15:20:05 -0700 Subject: make the 2.12 spec available on scala-lang.org reference: https://github.com/scala/scala-lang/issues/479 --- .travis.yml | 2 +- spec/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 236e002a5e..42099ec988 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,4 +20,4 @@ after_success: - openssl aes-256-cbc -pass "pass:$PRIV_KEY_SECRET" -in spec/id_dsa_travis.enc -out spec/id_dsa_travis -d -a - chmod 600 spec/id_dsa_travis - eval "$(ssh-agent)" - - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && ssh-add -D && ssh-add spec/id_dsa_travis && rsync -e "ssh -o StrictHostKeyChecking=no" -rzv build/spec/ scalatest@chara.epfl.ch:/home/linuxsoft/archives/scala/spec/2.11/' + - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && ssh-add -D && ssh-add spec/id_dsa_travis && rsync -e "ssh -o StrictHostKeyChecking=no" -rzv build/spec/ scalatest@chara.epfl.ch:/home/linuxsoft/archives/scala/spec/2.12/' diff --git a/spec/README.md b/spec/README.md index 1a201fc97c..9fd7c9f6ae 100644 --- a/spec/README.md +++ b/spec/README.md @@ -12,7 +12,7 @@ We use Jekyll 2 and [Redcarpet](https://github.com/vmg/redcarpet) to generate th ## Building -Travis CI builds the spec automatically on every commit to master and publishes to http://www.scala-lang.org/files/archive/spec/2.11/. +Travis CI builds the spec automatically after every merged pull release and publishes to http://www.scala-lang.org/files/archive/spec/2.12/. To preview locally, run `bundle exec jekyll serve -d build/spec/ -s spec/ -w --baseurl=""` (in the root of your checkout of scala/scala), and open http://0.0.0.0:4000/. Jekyll will rebuild as you edit the markdown, but make sure to restart it when you change `_config.yml`. -- cgit v1.2.3 From fc0f424f32c0f660c4891865d822dd7aeeb11d40 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Thu, 29 Sep 2016 16:49:26 -0700 Subject: bump version number in spec from 2.11 to 2.12 --- spec/_config.yml | 2 +- spec/_layouts/default.yml | 2 +- spec/_layouts/toc.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/_config.yml b/spec/_config.yml index 74ec602f8f..60e80ee05c 100644 --- a/spec/_config.yml +++ b/spec/_config.yml @@ -1,4 +1,4 @@ -baseurl: /files/archive/spec/2.11 +baseurl: /files/archive/spec/2.12 safe: true lsi: false highlighter: null diff --git a/spec/_layouts/default.yml b/spec/_layouts/default.yml index 7e205f8835..1cd7b8b78a 100644 --- a/spec/_layouts/default.yml +++ b/spec/_layouts/default.yml @@ -31,7 +31,7 @@
- +
diff --git a/spec/_layouts/toc.yml b/spec/_layouts/toc.yml index 4da7d41bea..eed90c1905 100644 --- a/spec/_layouts/toc.yml +++ b/spec/_layouts/toc.yml @@ -19,9 +19,9 @@
Scala Language Specification - Edit at Github + Edit at Github
-
Version 2.11
+
Version 2.12
{{ content }} -- cgit v1.2.3 From 3d699031f258bf938fdaf2079c718a0ae53b5cab Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Thu, 29 Sep 2016 16:49:57 -0700 Subject: capitalize GitHub correctly --- spec/_layouts/default.yml | 2 +- spec/_layouts/toc.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/_layouts/default.yml b/spec/_layouts/default.yml index 1cd7b8b78a..06d8c1c118 100644 --- a/spec/_layouts/default.yml +++ b/spec/_layouts/default.yml @@ -31,7 +31,7 @@
- +
diff --git a/spec/_layouts/toc.yml b/spec/_layouts/toc.yml index eed90c1905..dfd92eb114 100644 --- a/spec/_layouts/toc.yml +++ b/spec/_layouts/toc.yml @@ -19,7 +19,7 @@
Scala Language Specification - Edit at Github + Edit at GitHub
Version 2.12
-- cgit v1.2.3 From 1f6006d0d4f8edf4db04915702f8b7e3c8ca1f5e Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 29 Sep 2016 17:43:04 -0700 Subject: Update keypair used to rsync spec to chara So that we can rsync to the 2.12 spec directory. (also updated the forced command in scalatest@chara.epfl.ch:~/.ssh/authorized_keys2) --- .travis.yml | 13 +++++--- spec/id_dsa_travis.enc | 83 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 77 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 42099ec988..c27b362a6c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,15 +9,20 @@ rvm: script: bundle exec jekyll build -s spec/ -d build/spec install: bundle install -# https://gist.github.com/kzap/5819745, http://docs.travis-ci.com/user/travis-pro/ +# cat /dev/urandom | head -c 10000 | openssl sha1 > ./secret +# openssl aes-256-cbc -pass "file:./secret" -in id_dsa_spec212_b4096 -out spec/id_dsa_travis.enc -a +# travis encrypt "PRIV_KEY_SECRET=`cat ./secret`" env: - - secure: "WWU490z7DWAI8MidMyTE+i+Ppgjg46mdr7PviF6P6ulrPlRRKOtKXpLvzgJoQmluwzEK6/+iH7D5ybCUYMLdKkQM9kSqaXJ0jeqjOelaaa1LmuOQ8IbuT8O9DwHzjjp/n4Lj/KRvvN4nGxCMI7HLla4gunvPA7M6WK7FA+YKCOU=" # set PRIV_KEY_SECRET to password used to encrypt spec/id_dsa_travis.enc + - secure: "TuJOUtALynPd+MV1AuMeIpVb8BUBHr7Ul7FS48XhS2PyuTRpEBkSWybYcNg3AXyzmWDAuOjUxbaNMQBvP8vvehTbIYls5H5wTGKvj0D0TNVaPIXjF8bA8KyNat9xGNzhnWm2/2BMaWpKBJWRF7Jb+zHhijMYCJEbkMtoiE5R/mY=" + +# ^^^ set PRIV_KEY_SECRET to password used to encrypt spec/id_dsa_travis.enc -# using S3 would be simpler, but we want to upload to scala-lang.org -# after_success: bundle exec s3_website push --headless # the key is restricted using forced commands so that it can only upload to the directory we need here after_success: - openssl aes-256-cbc -pass "pass:$PRIV_KEY_SECRET" -in spec/id_dsa_travis.enc -out spec/id_dsa_travis -d -a - chmod 600 spec/id_dsa_travis - eval "$(ssh-agent)" - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && ssh-add -D && ssh-add spec/id_dsa_travis && rsync -e "ssh -o StrictHostKeyChecking=no" -rzv build/spec/ scalatest@chara.epfl.ch:/home/linuxsoft/archives/scala/spec/2.12/' + +# using S3 would be simpler, but we want to upload to scala-lang.org +# after_success: bundle exec s3_website push --headless diff --git a/spec/id_dsa_travis.enc b/spec/id_dsa_travis.enc index a9a4036807..16bbd569dc 100644 --- a/spec/id_dsa_travis.enc +++ b/spec/id_dsa_travis.enc @@ -1,15 +1,68 @@ -U2FsdGVkX1/RKhLZeL93vFQikKRRkoa3rqt6Kbs7cJStmcTI+DohoRUidRaeSULa -+xXQCwaSDs4+l1HdW2R4ZV62AVGhvIeKEZxc449c6qT9+wUd2PKkDghuJCy1dLTo -2OdFLDeop0X32bsauzPQGWwrpb/Llck4KeKffJq2257Hu6T/HnzSfDnvXbjAsVeH -ZLeXURAyDAdK9vFmFzFiEEztLkW8E3ZVyrk7Qa3GPNpmATiBdhVM8d0JJptKVgwQ -mZfhbItLrj490sPd5zpUFKAxJjPoKIa75n/+u4butn+ON97vr7xOy6ElX7HSJUgr -FJdVJgcO7lki0j+lfJVAP0zLnH80CgOkOJSq0Sso/ofs+lQIobo8fQqIdmoqV3z2 -KpYrgnqap1U2+ekIUKsUxk4LuO8uJhwPeMJs6FoDb+O4Aauqpy9242+P05gWkQVd -KVWRcHVE7DulS8Fp/o5GXJUdw+rdxvQ/voJ8i0HbYpp6UcmQwBheQMSmqtp5+ML9 -rBiBe2sr7pahqI5NKoF3iZCkZW74ge3/GP2d6m2tpOzD+IfdFDXQ/r8DbK2Dvwvz -eutOb0zrUtua2e2zvvpVxldPVpXA7A1hE0P3lns9o+TqNhEauTQimQ8/X51BHO6E -Ap4odrf2odocacY5VC4LFYDO3vat0wSTpi6SxkemUMX5yB7euqwD3ZrMcbpPFR1B -IU5XxW20NxUo8n+WuMUNkXTgk/Cr4OUiavVv4oLsHkmgD9LN3IYI6Rj/DSCzSbDx -hyWc7R47iu9f5okQScx62DwVK3AyAuVWer94x0Kj8AcIRwU/VwiXjnZ59I89AKTN -sjZJw1FfpJPqYs7fPtEiotUdaJHzJH8tiEWFrtOTuOg3h6fy0KJTPVh0WjcGXfb6 -Uh1SEgeHtMSUVhq8nd8LGQ== +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 -- cgit v1.2.3