summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore10
-rw-r--r--README.md59
-rw-r--r--build-ant-macros.xml832
-rw-r--r--build.number13
-rw-r--r--build.sbt56
-rw-r--r--build.xml1786
-rw-r--r--compare-build-dirs-ignore-patterns8
-rwxr-xr-xcompare-build-dirs.sh5
-rw-r--r--project/MiMa.scala5
-rw-r--r--project/Osgi.scala6
-rw-r--r--project/ScalaOptionParser.scala2
-rw-r--r--project/ScalaTool.scala2
-rw-r--r--project/build.sbt2
-rwxr-xr-xpull-binary-libs.sh20
-rwxr-xr-xpush-binary-libs.sh13
-rw-r--r--src/build/bnd/scala-compiler-doc.bnd8
-rw-r--r--src/build/bnd/scala-compiler-interactive.bnd8
-rw-r--r--src/build/bnd/scala-compiler.bnd12
-rw-r--r--src/build/bnd/scala-library.bnd8
-rw-r--r--src/build/bnd/scala-parser-combinators.bnd8
-rw-r--r--src/build/bnd/scala-reflect.bnd10
-rw-r--r--src/build/bnd/scala-swing.bnd8
-rw-r--r--src/build/bnd/scala-xml.bnd8
-rw-r--r--src/build/maven/scala-compiler-doc-pom.xml53
-rw-r--r--src/build/maven/scala-compiler-interactive-pom.xml48
-rw-r--r--src/build/maven/scala-compiler-pom.xml65
-rw-r--r--src/build/maven/scala-dist-pom.xml69
-rw-r--r--src/build/maven/scala-library-all-pom.xml68
-rw-r--r--src/build/maven/scala-library-pom.xml46
-rw-r--r--src/build/maven/scala-reflect-pom.xml51
-rw-r--r--src/build/maven/scalap-pom.xml48
-rw-r--r--src/compiler/scala/reflect/reify/phases/Reshape.scala36
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala2
-rw-r--r--src/compiler/scala/tools/nsc/CompilerCommand.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala12
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala22
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala46
-rw-r--r--src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala4
-rw-r--r--src/compiler/scala/tools/nsc/settings/AbsSettings.scala6
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala35
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala27
-rw-r--r--src/compiler/scala/tools/nsc/settings/Warnings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala465
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala5
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala19
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala5
-rw-r--r--src/compiler/scala/tools/nsc/transform/Fields.scala395
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala318
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala709
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala11
-rw-r--r--src/compiler/scala/tools/nsc/transform/TailCalls.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Duplicators.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala298
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala152
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala35
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala23
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala53
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala1
-rw-r--r--src/interactive/scala/tools/nsc/interactive/Global.scala2
-rw-r--r--src/library/scala/runtime/LazyRef.scala157
-rw-r--r--src/manual/scala/man1/scalac.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala8
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala22
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala20
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala4
-rw-r--r--src/reflect/scala/reflect/internal/transform/Erasure.scala52
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala5
-rw-r--r--src/repl/scala/tools/nsc/interpreter/Phased.scala4
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/Settings.scala2
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala23
-rw-r--r--test/files/jvm/innerClassAttribute/Test.scala12
-rw-r--r--test/files/jvm/javaReflection.check8
-rw-r--r--test/files/neg/anytrait.check5
-rw-r--r--test/files/neg/choices.check3
-rw-r--r--test/files/neg/names-defaults-neg.check8
-rw-r--r--test/files/neg/nowarnDefaultJunitMethods.check6
-rw-r--r--test/files/neg/nowarnDefaultJunitMethods.flags1
-rw-r--r--test/files/neg/nowarnDefaultJunitMethods/C_1.scala5
-rw-r--r--test/files/neg/nowarnDefaultJunitMethods/Test.java3
-rw-r--r--test/files/neg/protected-constructors.check18
-rw-r--r--test/files/neg/sabin2.check2
-rw-r--r--test/files/neg/t1838.check6
-rw-r--r--test/files/neg/t4158.check6
-rw-r--r--test/files/neg/t6446-additional.check21
-rw-r--r--test/files/neg/t6446-missing.check19
-rw-r--r--test/files/neg/t6446-show-phases.check19
-rw-r--r--test/files/neg/t6666.check4
-rw-r--r--test/files/neg/t6829.check12
-rw-r--r--test/files/neg/t712.check3
-rw-r--r--test/files/neg/t7494-no-options.check21
-rw-r--r--test/files/neg/t8217-local-alias-requires-rhs.check6
-rw-r--r--test/files/neg/t963.check10
-rw-r--r--test/files/pos/t5240.scala8
-rw-r--r--test/files/pos/t8873.scala1
-rw-r--r--test/files/pos/trait_lazy_accessboundary.scala2
-rw-r--r--test/files/presentation/t5708.check2
-rw-r--r--test/files/presentation/t8459.check1
-rw-r--r--test/files/run/analyzerPlugins.check53
-rw-r--r--test/files/run/compiler-asSeenFrom.check20
-rw-r--r--test/files/run/delambdafy_t6028.check14
-rw-r--r--test/files/run/existential-rangepos.check2
-rw-r--r--test/files/run/idempotency-lazy-vals.check14
-rw-r--r--test/files/run/junitForwarders/C_1.scala15
-rw-r--r--test/files/run/junitForwarders/Test.java10
-rw-r--r--test/files/run/lazy-locals-2.scala322
-rw-r--r--test/files/run/lazy-locals.check3
-rw-r--r--test/files/run/lazy_local_labels.check9
-rw-r--r--test/files/run/lazy_local_labels.scala28
-rw-r--r--test/files/run/programmatic-main.check19
-rw-r--r--test/files/run/showraw_mods.check2
-rw-r--r--test/files/run/t3569.check2
-rw-r--r--test/files/run/t3569.scala8
-rw-r--r--test/files/run/t5552.check4
-rw-r--r--test/files/run/t5552.scala10
-rw-r--r--test/files/run/t6023.check4
-rw-r--r--test/files/run/t6028.check14
-rw-r--r--test/files/run/t6733.check2
-rw-r--r--test/files/run/trait-fields-override-lazy.check2
-rw-r--r--test/files/run/trait-fields-override-lazy.scala13
-rw-r--r--test/files/scalacheck/quasiquotes/TypecheckedProps.scala2
-rw-r--r--test/junit/scala/lang/traits/BytecodeTest.scala119
-rw-r--r--test/junit/scala/reflect/internal/PrintersTest.scala25
-rw-r--r--test/junit/scala/runtime/LambdaDeserializerTest.java1
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala2
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala8
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala3
-rw-r--r--test/junit/scala/tools/testing/ClearAfterClass.java1
-rw-r--r--test/scaladoc/run/t7767.scala42
-rwxr-xr-xtools/binary-repo-lib.sh234
-rwxr-xr-xtools/deploy-local-maven-snapshot11
-rwxr-xr-xtools/new-starr6
-rw-r--r--tools/push.jar.desired.sha11
135 files changed, 2272 insertions, 5312 deletions
diff --git a/.gitignore b/.gitignore
index 0fff976e90..d9710a65cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,7 +10,7 @@
#
#
-# JARs aren't checked in, they are fetched by Ant / pull_binary_libs.sh
+# JARs aren't checked in, they are fetched by sbt
#
# We could be more concise with /lib/**/*.jar but that assumes
# a late-model git.
@@ -22,23 +22,20 @@
/test/files/speclib/instrumented.jar
/tools/*.jar
-# Developer specific Ant properties
+# Developer specific properties
/build.properties
/buildcharacter.properties
# might get generated when testing Jenkins scripts locally
/jenkins.properties
-# target directories for ant build
-/build
+# target directory for build
/build/
-/dists/
# other
/out/
/bin/
/sandbox/
-/.ant-targets-build.xml
# eclipse, intellij
/.classpath
@@ -59,3 +56,4 @@
/project/project/target/
/project/project/project/target/
/build-sbt/
+local.sbt
diff --git a/README.md b/README.md
index ed42eadaaa..ea28ba7497 100644
--- a/README.md
+++ b/README.md
@@ -43,8 +43,6 @@ P.S.: If you have some spare time to help out around here, we would be delighted
```
scala/
+--build.sbt The main sbt build script
-+--build.xml The deprecated Ant build script
-+--pull-binary-libs.sh Pulls binary artifacts from remote repository, used by build scripts
+--lib/ Pre-compiled libraries for the build
+--src/ All sources
+---/library Scala Standard Library
@@ -65,13 +63,11 @@ scala/
## Requirements
You need the following tools:
- - A Java SDK. The baseline version is 6 for 2.11.x, 8 for 2.12.x. It's possible
- to use a later SDK for local development, but the CI will verify against the baseline
- version.
- - sbt, we recommend the [sbt-extras](https://github.com/paulp/sbt-extras) runner
- script. It provides sensible default jvm options (stack and heap size).
- - curl (for `./pull-binary-libs.sh`, used by the sbt / ant build).
- - Apache Ant (version 1.9.3 or above) if you need to use the (deprecated) ant build.
+ - Java SDK. The baseline version is 8 for 2.12.x. It may be possible to use a
+ later SDK for local development, but the CI will verify against the baseline
+ version.
+ - sbt. We recommend the [sbt-extras](https://github.com/paulp/sbt-extras) runner
+ script. It provides sensible default jvm options (stack and heap size).
Mac OS X and Linux work. Windows may work if you use Cygwin. Community help with keeping
the build working on Windows is appreciated.
@@ -80,32 +76,25 @@ the build working on Windows is appreciated.
### Basics
-Scala is built in layers, where each layer is a complete Scala compiler and library.
-Here is a short description of the layers, from bottom to top:
-
- - `starr`: the stable reference Scala release. We use an official release of
- Scala (specified by `starr.version` in [versions.properties](versions.properties)),
- downloaded from the Central Repository.
- - `locker` (deprecated, only in ant): an intermediate layer that existed in the
- ant build to perform a bootstrap.
- - `quick`: the development layer which is incrementally built when working on
- changes in the compiler or library.
- - `strap` (deprecated, only in ant) : a test layer used to check stability of
- the build.
-
-The sbt build uses `starr` to build `quick`. This is sufficient for most development
-scenarios: changes to the library or the compiler can be tested by running the `quick`
-Scala (see below for how to do that).
-
-However, a full build of Scala (a *bootstrap*, as performed by our CI) requires two
-layers. This guarantees that every Scala version can build itself. If you change the
-code generation part of the Scala compiler, your changes will only reflect in the
-bytecode of the library and compiler after a bootstrap. See below for how to create
-a bootstrap build locally.
+During ordinary development, a new Scala build is built by the
+previously released version. For short we call the previous release
+"starr": the stable reference Scala release. Building with starr is
+sufficient for most kinds of changes.
+
+However, a full build of Scala (a *bootstrap*, as performed by our CI)
+requires two layers. This guarantees that every Scala version can
+build itself. If you change the code generation part of the Scala
+compiler, your changes will only show up in the bytecode of the
+library and compiler after a bootstrap. See below for how to do a
+bootstrap build locally.
+
+For history on how the current scheme was arrived at, see
+https://groups.google.com/d/topic/scala-internals/gp5JsM1E0Fo/discussion.
### Using the Sbt Build
Core commands:
+
- `compile` compiles all sub-projects (library, reflect, compiler, scaladoc, etc)
- `scala` / `scalac` run the REPL / compiler directly from sbt (accept options /
arguments)
@@ -115,7 +104,7 @@ Core commands:
- `partest` runs partest tests (accepts options, try `partest --help`)
- `publishLocal` publishes a distribution locally (can be used as `scalaVersion` in
other sbt projects)
- - Optionally `set VersionUtil.baseVersionSuffix in Global := "abcd123-SNAPSHOT"`
+ - Optionally `set baseVersionSuffix := "abcd123-SNAPSHOT"`
where `abcd123` is the git hash of the revision being published. You can also
use something custom like `"mypatch"`. This changes the version number from
`2.12.0-SNAPSHOT` to something more stable (`2.12.0-abcd123-SNAPSHOT`).
@@ -133,13 +122,13 @@ Note that sbt's incremental compilation is often too coarse for the Scala compil
codebase and re-compiles too many files, resulting in long build times (check
[sbt#1104](https://github.com/sbt/sbt/issues/1104) for progress on that front). In the
meantime you can:
- - Enable "ant mode" in which sbt only re-compiles source files that were modified.
+ - Enable "Ant mode" in which sbt only re-compiles source files that were modified.
Create a file `local.sbt` containing the line `antStyle := true`.
Add an entry `local.sbt` to your `~/.gitignore`.
- Use IntelliJ IDEA for incremental compiles (see [IDE Setup](#ide-setup) below) - its
incremental compiler is a bit less conservative, but usually correct.
-#### Local Bootstrap Build
+#### Bootstrapping Locally
To perform a bootstrap using sbt
- first a build is published either locally or on a temporary repository,
@@ -176,7 +165,7 @@ In order to use IntelliJ's incremental compiler:
Now you can edit and build in IntelliJ and use the scripts (compiler, REPL) to
directly test your changes. You can also run the `scala`, `scalac` and `partest`
-commands in sbt. Enable "ant mode" (explained above) to prevent sbt's incremental
+commands in sbt. Enable "Ant mode" (explained above) to prevent sbt's incremental
compiler from re-compiling (too many) files before each `partest` invocation.
# Coding Guidelines
diff --git a/build-ant-macros.xml b/build-ant-macros.xml
deleted file mode 100644
index e077cfbb4c..0000000000
--- a/build-ant-macros.xml
+++ /dev/null
@@ -1,832 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="build-support" xmlns:artifact="urn:maven-artifact-ant">
- <description> Macros for Scala's ant build </description>
-
- <macrodef name="optimized">
- <attribute name="name"/>
- <sequential>
- <antcall target="@{name}">
- <param name="scalac.args.optimise" value="-opt:l:classpath"/>
- </antcall>
- </sequential>
- </macrodef>
-
- <macrodef name="copy-deps" description="Copy a file set based on maven dependency resolution to a directory. Currently used by the IntelliJ config files.">
- <attribute name="project"/>
- <attribute name="refid" default="@{project}.fileset"/>
- <sequential>
- <delete dir="${build-deps.dir}/@{project}" includes="*.jar"/>
- <copy todir="${build-deps.dir}/@{project}">
- <resources refid="@{refid}"/>
- <mapper type="flatten"/>
- </copy>
- </sequential>
- </macrodef>
-
- <!-- Set a property @{name}.cross to the actual cross suffix that should be
- used when resolving the module "@{name}". If the (user-supplied)
- @{name}.cross.suffix property exists then use that value, otherwise use
- "_${scala.binary.version}". -->
- <macrodef name="prepareCross">
- <attribute name="name" />
- <sequential>
- <if>
- <isset property="@{name}.cross.suffix" />
- <then>
- <property name="@{name}.cross" value="${@{name}.cross.suffix}" />
- </then>
- <else>
- <property name="@{name}.cross" value="_${scala.binary.version}" />
- </else>
- </if>
- </sequential>
- </macrodef>
-
- <!-- Set property named @{name} to the jar resolved as @{jar}_${scala.binary.version}:jar.
- @{jar}_${scala.binary.version} must be a maven dependency. -->
- <macrodef name="propertyForCrossedArtifact">
- <attribute name="name"/>
- <attribute name="jar"/>
- <attribute name="suffix" default="${@{name}.cross}"/>
- <sequential>
- <readProperty name="@{name}" property="@{jar}@{suffix}:jar"/>
- <readProperty name="@{name}-sources" property="@{jar}@{suffix}:java-source:sources"/>
- <readProperty name="@{name}-javadoc" property="@{jar}@{suffix}:java-source:javadoc"/>
- </sequential>
- </macrodef>
-
- <!-- Set property named @{name} to the value of the property named @{property}.
- Helper for performing nested property expansion without using the ant props lib -->
- <macrodef name="readProperty">
- <attribute name="name"/>
- <attribute name="property"/>
- <sequential>
- <property name="@{name}" value="${@{property}}"/>
- </sequential>
- </macrodef>
-
- <macrodef name="init-project-prop">
- <attribute name="project"/>
- <attribute name="name"/>
- <attribute name="default"/>
- <sequential>
- <local name="@{name}"/>
- <if>
- <not>
- <isset property="@{project}.@{name}"/>
- </not>
- <then>
- <property name="@{project}.@{name}" value="@{default}"/>
- </then>
- </if>
- </sequential>
- </macrodef>
-
- <macrodef name="clean">
- <attribute name="build"/>
- <sequential>
- <delete dir="${build-@{build}.dir}" includeemptydirs="yes" quiet="yes" failonerror="no"/>
- </sequential>
- </macrodef>
-
- <macrodef name="simple-javac">
- <attribute name="project"/>
- <attribute name="args" default=""/>
- <attribute name="jar" default="yes"/>
- <sequential>
- <uptodate property="@{project}.available" targetfile="${build-libs.dir}/@{project}.complete">
- <srcfiles dir="${src.dir}/@{project}"/>
- </uptodate>
- <if>
- <not>
- <isset property="@{project}.available"/>
- </not>
- <then>
- <stopwatch name="@{project}.timer"/>
- <mkdir dir="${@{project}-classes}"/>
- <javac debug="true" srcdir="${src.dir}/@{project}" destdir="${@{project}-classes}" classpath="${@{project}-classes}" includes="**/*.java" target="1.8" source="1.8" compiler="javac1.8">
- <compilerarg line="${javac.args} @{args}"/>
- </javac>
- <if>
- <equals arg1="@{jar}" arg2="yes"/>
- <then>
- <jar whenmanifestonly="fail" destfile="${build-libs.dir}/@{project}.jar" basedir="${@{project}-classes}"/>
- </then>
- </if>
- <stopwatch name="@{project}.timer" action="total"/>
- <mkdir dir="${build-libs.dir}"/>
- <touch file="${build-libs.dir}/@{project}.complete" verbose="no"/>
- </then>
- </if>
- </sequential>
- </macrodef>
-
- <macrodef name="staged-javac">
- <attribute name="stage"/>
- <!-- current stage (locker, quick, strap) -->
- <attribute name="project"/>
- <!-- project: library/reflect/compiler -->
- <attribute name="destproject" default="@{project}"/>
- <!-- overrides the output directory; used when building multiple projects into the same directory-->
- <attribute name="args" default=""/>
- <attribute name="excludes" default=""/>
- <sequential>
- <javac debug="true" srcdir="${src.dir}/@{project}" destdir="${build-@{stage}.dir}/classes/@{destproject}" includes="**/*.java" excludes="@{excludes}" target="1.8" source="1.8">
- <compilerarg line="${javac.args} @{args}"/>
- <classpath refid="@{stage}.@{destproject}.build.path"/>
- </javac>
- </sequential>
- </macrodef>
-
- <!-- Zinc assumes a one-to-one correspondence of output folder to set of source files.
- When compiling different sets of source files in multiple compilations to the same output directory,
- Zinc thinks source files that appeared in an earlier compilation but are absent in the current one,
- were deleted and thus deletes the corresponding output files.
-
- Note that zinc also requires each arg to scalac to be prefixed by -S.
- -->
- <macrodef name="zinc">
- <attribute name="compilerpathref"/>
- <attribute name="destdir"/>
- <attribute name="srcdir"/>
- <attribute name="srcpath" default="NOT SET"/>
- <!-- needed to compile the library, "NOT SET" is just a convention to denote an optional attribute -->
- <attribute name="buildpathref"/>
- <attribute name="params" default=""/>
- <attribute name="java-excludes" default=""/>
- <sequential>
- <local name="sources"/>
- <pathconvert pathsep=" " property="sources">
- <fileset dir="@{srcdir}">
- <include name="**/*.java"/>
- <include name="**/*.scala"/>
- <exclude name="@{java-excludes}"/>
- </fileset>
- </pathconvert>
- <local name="args"/>
- <local name="sargs"/>
- <if>
- <not>
- <equals arg1="@{srcpath}" arg2="NOT SET"/>
- </not>
- <then>
- <property name="args" value="@{params} -sourcepath @{srcpath}"/>
- </then>
- </if>
- <property name="args" value="@{params}"/>
- <!-- default -->
- <!-- HACK: prefix scalac args by -S -->
- <script language="javascript">
- project.setProperty("sargs", project.getProperty("args").trim().replaceAll(" ", " -S"));
- </script>
- <exec osfamily="unix" executable="tools/zinc" failifexecutionfails="true" failonerror="true">
- <arg line="-nailed -compile-order JavaThenScala -scala-path ${ant.refid:@{compilerpathref}} -d @{destdir} -classpath ${toString:@{buildpathref}} ${sargs} ${sources}"/>
- </exec>
- </sequential>
- </macrodef>
-
- <!-- STAGED COMPILATION MACROS -->
- <macrodef name="staged-scalac">
- <attribute name="with"/>
- <!-- will use path `@{with}.compiler.path` to locate scalac -->
- <attribute name="stage"/>
- <!-- current stage (locker, quick, strap) -->
- <attribute name="project"/>
- <!-- project: library/reflect/compiler -->
- <attribute name="srcpath" default="NOT SET"/>
- <!-- needed to compile the library -->
- <attribute name="args" default=""/>
- <!-- additional args -->
- <attribute name="destproject" default="@{project}"/>
- <!-- overrides the output directory; used when building multiple projects into the same directory-->
- <attribute name="srcdir" default="@{project}"/>
- <attribute name="java-excludes" default=""/>
- <attribute name="mixed" default="NOPE"/>
- <sequential>
- <local name="mixed.true"/><condition property="mixed.true"><equals arg1="@{mixed}" arg2="true"/></condition>
- <!-- TODO: detect zinc anywhere on PATH
- use zinc for the quick stage if it's available;
- would use it for locker but something is iffy in sbt: get a class cast error on global phase -->
- <if>
- <and>
- <available file="tools/zinc"/>
- <equals arg1="@{stage}" arg2="quick"/>
- </and>
- <then>
- <zinc taskname="Z.@{stage}.@{project}" compilerpathref="@{with}.compiler.path" destdir="${build-@{stage}.dir}/classes/@{destproject}" srcdir="${src.dir}/@{srcdir}" srcpath="@{srcpath}" buildpathref="@{stage}.@{project}.build.path" params="${scalac.args.@{stage}} @{args}" java-excludes="@{java-excludes}"/>
- </then>
- <else>
- <if>
- <equals arg1="@{srcpath}" arg2="NOT SET"/>
- <then>
- <scalacfork taskname="@{stage}.@{project}" jvmargs="${scalacfork.jvmargs}" compilerpathref="@{with}.compiler.path" destdir="${build-@{stage}.dir}/classes/@{destproject}" srcdir="${src.dir}/@{srcdir}" params="${scalac.args.@{stage}} @{args}">
- <include name="**/*.scala"/>
- <include name="**/*.java" if="mixed.true"/>
- <compilationpath refid="@{stage}.@{project}.build.path"/>
- </scalacfork>
- </then>
- <else>
- <scalacfork taskname="@{stage}.@{project}" jvmargs="${scalacfork.jvmargs}" compilerpathref="@{with}.compiler.path" destdir="${build-@{stage}.dir}/classes/@{destproject}" srcdir="${src.dir}/@{srcdir}" srcpath="@{srcpath}" params="${scalac.args.@{stage}} @{args}">
- <include name="**/*.scala"/>
- <include name="**/*.java" if="mixed.true"/>
- <compilationpath refid="@{stage}.@{project}.build.path"/>
- </scalacfork>
- </else>
- </if>
- </else>
- </if>
- </sequential>
- </macrodef>
-
- <macrodef name="staged-uptodate">
- <attribute name="stage"/>
- <attribute name="project"/>
- <element name="check"/>
- <element name="do"/>
- <sequential>
- <uptodate property="@{stage}.@{project}.available" targetfile="${build-@{stage}.dir}/@{project}.complete">
- <check/>
- </uptodate>
- <if>
- <not>
- <isset property="@{stage}.@{project}.available"/>
- </not>
- <then>
- <do/>
- <touch file="${build-@{stage}.dir}/@{project}.complete" verbose="no"/>
- </then>
- </if>
- </sequential>
- </macrodef>
-
- <macrodef name="staged-build">
- <attribute name="with"/>
- <!-- will use path `@{with}.compiler.path` to locate scalac -->
- <attribute name="stage"/>
- <!-- current stage (locker, quick, strap) -->
- <attribute name="project"/>
- <!-- project: library/reflect/compiler -->
- <attribute name="srcpath" default="NOT SET"/>
- <!-- needed to compile the library -->
- <attribute name="args" default=""/>
- <!-- additional args -->
- <attribute name="includes" default="comp.includes"/>
- <attribute name="java-excludes" default=""/>
- <attribute name="version" default=""/>
- <attribute name="mixed" default="NOPE"/>
- <!-- non-empty for scaladoc: use @{version}.version.number in property file-->
- <sequential>
- <staged-uptodate stage="@{stage}" project="@{project}">
- <check>
- <srcfiles dir="${src.dir}/@{project}"/>
- </check>
- <do>
- <stopwatch name="@{stage}.@{project}.timer"/>
- <mkdir dir="${build-@{stage}.dir}/classes/@{project}"/>
- <if>
- <equals arg1="@{mixed}" arg2="true"/>
- <then>
- <staged-scalac with="@{with}" stage="@{stage}" project="@{project}" srcpath="@{srcpath}" args="@{args}" java-excludes="@{java-excludes}" mixed="@{mixed}"/>
- <staged-javac stage="@{stage}" project="@{project}" excludes="@{java-excludes}"/>
- </then>
- <else>
- <staged-javac stage="@{stage}" project="@{project}" excludes="@{java-excludes}"/>
- <!-- always compile with javac for simplicity and regularity; it's cheap -->
- <staged-scalac with="@{with}" stage="@{stage}" project="@{project}" srcpath="@{srcpath}" args="@{args}" java-excludes="@{java-excludes}"/>
- </else>
- </if>
- <if>
- <equals arg1="@{version}" arg2=""/>
- <then>
- <propertyfile file="${build-@{stage}.dir}/classes/@{project}/@{project}.properties">
- <entry key="version.number" value="${version.number}"/>
- <entry key="maven.version.number" value="${maven.version.number}"/>
- <entry key="osgi.version.number" value="${osgi.version.number}"/>
- <entry key="copyright.string" value="${copyright.string}"/>
- </propertyfile>
- </then>
- <else>
- <propertyfile file="${build-@{stage}.dir}/classes/@{project}/@{project}.properties">
- <entry key="version.number" value="${@{version}.version.number}"/>
- <entry key="copyright.string" value="${copyright.string}"/>
- </propertyfile>
- </else>
- </if>
- <copy todir="${build-@{stage}.dir}/classes/@{project}">
- <fileset dir="${src.dir}/@{project}">
- <patternset refid="@{includes}"/>
- </fileset>
- </copy>
- <stopwatch name="@{stage}.@{project}.timer" action="total"/>
- </do>
- </staged-uptodate>
- </sequential>
- </macrodef>
-
- <macrodef name="staged-bin">
- <attribute name="stage"/>
- <attribute name="classpathref" default="NOT SET"/>
- <sequential>
- <staged-uptodate stage="@{stage}" project="bin">
- <check>
- <srcfiles dir="${src.dir}">
- <include name="compiler/scala/tools/ant/templates/**"/>
- </srcfiles>
- </check>
- <do>
- <taskdef name="mk-bin" classname="scala.tools.ant.ScalaTool" classpathref="@{stage}.bin.tool.path"/>
- <mkdir dir="${build-@{stage}.dir}/bin"/>
- <if>
- <equals arg1="@{classpathref}" arg2="NOT SET"/>
- <then>
- <mk-bin file="${build-@{stage}.dir}/bin/scala" class="scala.tools.nsc.MainGenericRunner" javaFlags="${java.flags}"/>
- <mk-bin file="${build-@{stage}.dir}/bin/scalac" class="scala.tools.nsc.Main" javaFlags="${java.flags}"/>
- <mk-bin file="${build-@{stage}.dir}/bin/scaladoc" class="scala.tools.nsc.ScalaDoc" javaFlags="${java.flags}"/>
- <mk-bin file="${build-@{stage}.dir}/bin/fsc" class="scala.tools.nsc.CompileClient" javaFlags="${java.flags}"/>
- <mk-bin file="${build-@{stage}.dir}/bin/scalap" class="scala.tools.scalap.Main" javaFlags="${java.flags}"/>
- </then>
- <else>
- <mk-bin file="${build-@{stage}.dir}/bin/scala" class="scala.tools.nsc.MainGenericRunner" javaFlags="${java.flags}" classpathref="@{classpathref}"/>
- <mk-bin file="${build-@{stage}.dir}/bin/scalac" class="scala.tools.nsc.Main" javaFlags="${java.flags}" classpathref="@{classpathref}"/>
- <mk-bin file="${build-@{stage}.dir}/bin/scaladoc" class="scala.tools.nsc.ScalaDoc" javaFlags="${java.flags}" classpathref="@{classpathref}"/>
- <mk-bin file="${build-@{stage}.dir}/bin/fsc" class="scala.tools.nsc.CompileClient" javaFlags="${java.flags}" classpathref="@{classpathref}"/>
- <mk-bin file="${build-@{stage}.dir}/bin/scalap" class="scala.tools.scalap.Main" javaFlags="${java.flags}" classpathref="@{classpathref}"/>
- </else>
- </if>
- <chmod perm="ugo+rx" file="${build-@{stage}.dir}/bin/scala"/>
- <chmod perm="ugo+rx" file="${build-@{stage}.dir}/bin/scalac"/>
- <chmod perm="ugo+rx" file="${build-@{stage}.dir}/bin/scaladoc"/>
- <chmod perm="ugo+rx" file="${build-@{stage}.dir}/bin/fsc"/>
- <chmod perm="ugo+rx" file="${build-@{stage}.dir}/bin/scalap"/>
- </do>
- </staged-uptodate>
- </sequential>
- </macrodef>
-
- <macrodef name="staged-pack">
- <attribute name="project"/>
- <attribute name="manifest" default=""/>
- <element name="pre" optional="true"/>
- <element name="jar-opts" optional="true"/>
- <sequential>
- <local name="destfile"/>
- <property name="destfile" value="${build-pack.dir}/${@{project}.targetdir}/${@{project}.targetjar}"/>
- <uptodate property="pack.@{project}.available" targetfile="${destfile}">
- <srcresources>
- <resources refid="pack.@{project}.files"/>
- <!-- <path><pathelement location="${build-quick.dir}/@{project}.complete"/></path> -->
- </srcresources>
- </uptodate>
- <if>
- <not>
- <isset property="pack.@{project}.available"/>
- </not>
- <then>
- <mkdir dir="${build-pack.dir}/${@{project}.targetdir}"/>
- <pre/>
- <!-- can't check if a fileset is defined, so we have an additional property -->
- <if><not><isset property="pack.@{project}.include-jars.defined"/></not><then>
- <fileset id="pack.@{project}.include-jars" dir="." excludes="**" />
- </then></if>
- <if>
- <not>
- <equals arg1="@{manifest}" arg2=""/>
- </not>
- <then>
- <jar whenmanifestonly="fail" destfile="${destfile}" manifest="@{manifest}">
- <!-- update="true" makes no difference on my machine, so starting from scratch-->
- <jar-opts/>
- <path refid="pack.@{project}.files"/>
- <zipgroupfileset refid="pack.@{project}.include-jars"/>
- </jar>
- </then>
- <else>
- <jar whenmanifestonly="fail" destfile="${destfile}">
- <jar-opts/>
- <path refid="pack.@{project}.files"/>
- </jar>
- </else>
- </if>
- </then>
- </if>
- </sequential>
- </macrodef>
-
- <macrodef name="staged-docs">
- <attribute name="project"/>
- <element name="includes" implicit="true"/>
- <sequential>
- <staged-uptodate stage="docs" project="@{project}">
- <check>
- <srcfiles dir="${src.dir}/${@{project}.srcdir}"/>
- </check>
- <do>
- <stopwatch name="docs.@{project}.timer"/>
- <mkdir dir="${build-docs.dir}/@{project}"/>
- <if>
- <equals arg1="${@{project}.docroot}" arg2="NOT SET"/>
- <then>
- <scaladoc
- destdir="${build-docs.dir}/@{project}"
- doctitle="${@{project}.description}"
- docfooter="epfl"
- docversion="${version.number}"
- sourcepath="${src.dir}"
- classpathref="docs.@{project}.build.path"
- srcdir="${src.dir}/${@{project}.srcdir}"
- addparams="${scalac.args.all}"
- docsourceurl="${scaladoc.url}€{FILE_PATH}.scala#L1"
- implicits="on"
- diagrams="on"
- groups="on"
- rawOutput="${scaladoc.raw.output}"
- noPrefixes="${scaladoc.no.prefixes}"
- docUncompilable="${src.dir}/library-aux"
- skipPackages="${@{project}.skipPackages}">
- <includes/>
- </scaladoc>
- </then>
- <else>
- <scaladoc docRootContent="${src.dir}/@{project}/${@{project}.docroot}"
- destdir="${build-docs.dir}/@{project}"
- doctitle="${@{project}.description}"
- docfooter="epfl"
- docversion="${version.number}"
- sourcepath="${src.dir}"
- classpathref="docs.@{project}.build.path"
- srcdir="${src.dir}/${@{project}.srcdir}"
- addparams="${scalac.args.all}"
- docsourceurl="${scaladoc.url}€{FILE_PATH}.scala#L1"
- implicits="on"
- diagrams="on"
- groups="on"
- rawOutput="${scaladoc.raw.output}"
- noPrefixes="${scaladoc.no.prefixes}"
- docUncompilable="${src.dir}/library-aux"
- skipPackages="${@{project}.skipPackages}">
- <includes/>
- </scaladoc>
- </else>
- </if>
- <stopwatch name="docs.@{project}.timer" action="total"/>
- </do>
- </staged-uptodate>
- </sequential>
- </macrodef>
-
- <macrodef name="make-bundle">
- <attribute name="project"/>
- <element name="srcs" description="Sources for this bundle" optional="true" implicit="true"/>
- <sequential>
- <copy file="${src.dir}/build/bnd/${@{project}.name}.bnd" tofile="${build-osgi.dir}/${@{project}.name}.bnd" overwrite="true">
- <filterset>
- <filter token="VERSION" value="${osgi.version.number}"/>
- <filter token="SCALA_BINARY_VERSION" value="${scala.binary.version}"/>
- <filter token="SCALA_FULL_VERSION" value="${scala.full.version}"/>
- <filter token="SCALA_COMPILER_DOC_VERSION" value="${scala-compiler-doc.version.number}"/>
- <filter token="SCALA_COMPILER_INTERACTIVE_VERSION" value="${scala-compiler-interactive.version.number}"/>
- <filter token="XML_VERSION" value="${scala-xml.version.number}" />
- <filter token="PARSER_COMBINATORS_VERSION" value="${scala-parser-combinators.version.number}" />
- <filter token="SCALA_SWING_VERSION" value="${scala-swing.version.osgi}" />
- <filter token="SOURCE_JARNAME" value="${@{project}.targetjar}"/>
- </filterset>
- </copy>
- <bnd classpath="${@{project}.jar}" eclipse="false" failok="false" exceptions="true" files="${build-osgi.dir}/${@{project}.name}.bnd" output="${build-osgi.dir}"/>
- <if>
- <equals arg1="${@{project}.src}" arg2="true"/>
- <then>
- <!--
- A jar-like task that creates an OSGi source bundle. It adds the required MANIFEST.MF headers that allow
- Eclipse to match sources with the corresponding binaries.
- -->
- <jar whenmanifestonly="fail" destfile="${build-osgi.dir}/${@{project}.name}-src.jar">
- <srcs/>
- <manifest>
- <attribute name="Manifest-Version" value="1.0"/>
- <attribute name="Bundle-Name" value="${@{project}.description} Sources"/>
- <attribute name="Bundle-SymbolicName" value="org.scala-lang.${@{project}.package}${@{project}.name}${@{project}.namesuffix}.source"/>
- <attribute name="Bundle-Version" value="${@{project}.version}"/>
- <attribute name="Eclipse-SourceBundle" value="org.scala-lang.${@{project}.package}${@{project}.name}${@{project}.namesuffix};version=&quot;${@{project}.version}&quot;;roots:=&quot;.&quot;"/>
- </manifest>
- </jar>
- </then>
- </if>
- </sequential>
- </macrodef>
-
- <macrodef name="copy-bundle">
- <attribute name="project"/>
- <sequential>
- <copy tofile="${dist.dir}/${@{project}.targetdir}/${@{project}.name}.jar" file="${build-osgi.dir}/org.scala-lang.${@{project}.package}${@{project}.name}.jar" overwrite="true"/>
- <copy tofile="${dist.dir}/src/${@{project}.name}-src.jar" file="${@{project}.srcjar}" overwrite="true"/>
- </sequential>
- </macrodef>
-
- <macrodef name="mvn-package">
- <attribute name="project"/>
- <sequential>
- <local name="artifact-base"/>
- <property name="artifact-base" value="${dist.maven}/${@{project}.dir}${@{project}.name}/${@{project}.name}"/>
- <mkdir dir="${dist.maven}/${@{project}.dir}${@{project}.name}"/>
- <copy tofile="${artifact-base}.jar" file="${build-osgi.dir}/org.scala-lang.${@{project}.package}${@{project}.name}${@{project}.namesuffix}.jar" overwrite="true"/>
- <copy tofile="${artifact-base}-src.jar" file="${build-osgi.dir}/${@{project}.name}-src.jar" overwrite="true"/>
- <copy tofile="${artifact-base}-pom.xml" file="${src.dir}/build/maven/${@{project}.dir}/${@{project}.name}-pom.xml" overwrite="true"/>
- <if>
- <not>
- <isset property="docs.skip"/>
- </not>
- <then>
- <jar destfile="${artifact-base}-docs.jar" basedir="${build-docs.dir}/@{project}" whenmanifestonly="fail">
- <include name="**/*"/>
- </jar>
- </then>
- </if>
- </sequential>
- </macrodef>
-
- <macrodef name="deploy-remote">
- <attribute name="jar" default=""/>
- <attribute name="pom"/>
- <element name="artifacts" implicit="true" optional="true"/>
- <sequential>
- <if><equals arg1="@{jar}" arg2="true"/><then>
- <artifact:deploy settingsFile="${settings.file}">
- <artifact:remoteRepository url="${remote.repository}" id="${repository.credentials.id}" />
- <artifact:pom refid="@{pom}" />
- <artifacts/>
- </artifact:deploy>
- </then><else>
- <artifact:deploy file="@{jar}" settingsFile="${settings.file}">
- <artifact:remoteRepository url="${remote.repository}" id="${repository.credentials.id}" />
- <artifact:pom refid="@{pom}" />
- <artifacts/>
- </artifact:deploy>
- </else></if>
- </sequential>
- </macrodef>
-
- <macrodef name="deploy-local">
- <attribute name="jar" default=""/>
- <attribute name="pom"/>
- <element name="artifacts" implicit="true" optional="true"/>
- <sequential>
- <if><equals arg1="@{jar}" arg2="true"/><then>
- <artifact:install>
- <artifact:localRepository path="${local.repository}" id="${repository.credentials.id}" />
- <artifact:pom refid="@{pom}" />
- <artifacts/>
- </artifact:install>
- </then><else>
- <artifact:install file="@{jar}">
- <artifact:localRepository path="${local.repository}" id="${repository.credentials.id}" />
- <artifact:pom refid="@{pom}" />
- <artifacts/>
- </artifact:install>
- </else></if>
- </sequential>
- </macrodef>
-
- <macrodef name="deploy-to">
- <attribute name="jar" default=""/>
- <attribute name="pom"/>
- <attribute name="local"/>
- <element name="artifacts" implicit="true" optional="true"/>
- <sequential>
- <if><equals arg1="@{local}" arg2="true"/><then>
- <deploy-local jar="@{jar}" pom="@{pom}"> <artifacts/> </deploy-local>
- </then><else>
- <deploy-remote jar="@{jar}" pom="@{pom}"> <artifacts/> </deploy-remote>
- </else></if>
- </sequential>
- </macrodef>
-
- <macrodef name="filter-pom">
- <attribute name="path" />
- <attribute name="name" />
-
- <sequential>
- <copy file="${path}-pom.xml" tofile="${path}-pom-filtered.xml" overwrite="true">
- <filterset>
- <filter token="VERSION" value="${maven.version.number}" />
- <filter token="SCALA_BINARY_VERSION" value="${scala.binary.version}" />
- <filter token="SCALA_FULL_VERSION" value="${scala.full.version}" />
- <filter token="XML_VERSION" value="${scala-xml.version.number}" />
- <filter token="PARSER_COMBINATORS_VERSION" value="${scala-parser-combinators.version.number}" />
- <filter token="SCALA_SWING_VERSION" value="${scala-swing.version.number}" />
- <filter token="RELEASE_REPOSITORY" value="${remote.release.repository}" />
- <filter token="SNAPSHOT_REPOSITORY" value="${remote.snapshot.repository}" />
- <filter token="JLINE_VERSION" value="${jline.version}" />
-
- <!-- TODO modularize compiler.
- <filter token="SCALA_COMPILER_DOC_VERSION" value="${scala-compiler-doc.version.number}" />
- <filter token="SCALA_COMPILER_INTERACTIVE_VERSION" value="${scala-compiler-interactive.version.number}" />
- -->
- </filterset>
- </copy>
- <artifact:pom id="@{name}.pom" file="${path}-pom-filtered.xml" />
- </sequential>
- </macrodef>
-
- <macrodef name="deploy-one">
- <attribute name="name" />
- <attribute name="local" default="false"/>
- <attribute name="signed" default="false"/>
-
- <sequential>
- <local name="path"/> <property name="path" value="${dist.maven}/@{name}/@{name}"/>
-
- <echo>Deploying ${path}-[pom.xml|src.jar|docs.jar].</echo>
-
- <filter-pom name="@{name}" path="@{path}"/>
-
- <if><equals arg1="@{signed}" arg2="false"/><then>
- <if><isset property="docs.skip"/><then>
- <deploy-to local="@{local}" jar="${path}.jar" pom="@{name}.pom">
- <artifact:attach type="jar" file="${path}-src.jar" classifier="sources" />
- </deploy-to>
- </then><else>
- <deploy-to local="@{local}" jar="${path}.jar" pom="@{name}.pom">
- <artifact:attach type="jar" file="${path}-src.jar" classifier="sources" />
- <artifact:attach type="jar" file="${path}-docs.jar" classifier="javadoc" />
- </deploy-to>
- </else></if>
- </then><else>
- <local name="repo"/>
- <if><equals arg1="@{local}" arg2="false"/><then>
- <property name="repo" value="${remote.repository}"/>
- </then><else>
- <property name="repo" value="${local.repository}"/>
- </else></if>
- <artifact:mvn failonerror="true">
- <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
- <arg value="-Durl=${repo}" />
- <arg value="-DrepositoryId=${repository.credentials.id}" />
- <arg value="-DpomFile=${path}-pom-filtered.xml" />
- <arg value= "-Dfile=${path}.jar" />
- <arg value="-Dsources=${path}-src.jar" />
- <arg value="-Djavadoc=${path}-docs.jar" />
- <arg value="-Pgpg" />
- <arg value="-Dgpg.useagent=true" />
- </artifact:mvn>
- </else></if>
- </sequential>
- </macrodef>
-
- <macrodef name="deploy-jar">
- <attribute name="name" />
- <attribute name="local" default="false"/>
- <attribute name="signed" default="false"/>
-
- <sequential>
- <local name="path"/> <property name="path" value="${dist.maven}/@{name}/@{name}"/>
-
- <echo>Deploying ${path}.jar with ${path}-pom.xml.</echo>
-
- <filter-pom name="@{name}" path="@{path}"/>
-
- <if><equals arg1="@{signed}" arg2="false"/><then>
- <deploy-to local="@{local}" jar="${path}.jar" pom="@{name}.pom"/>
- </then><else>
- <local name="repo"/>
- <if><equals arg1="@{local}" arg2="false"/><then>
- <property name="repo" value="${remote.repository}"/>
- </then><else>
- <property name="repo" value="${local.repository}"/>
- </else></if>
- <artifact:mvn failonerror="true">
- <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
- <arg value="-Durl=${repo}" />
- <arg value="-DrepositoryId=${repository.credentials.id}" />
- <arg value="-DpomFile=${path}-pom-filtered.xml" />
- <arg value= "-Dfile=${path}.jar" />
- <arg value="-Pgpg" />
- <arg value="-Dgpg.useagent=true" />
- </artifact:mvn>
- </else></if>
- </sequential>
- </macrodef>
-
- <macrodef name="deploy-pom">
- <attribute name="name" />
- <attribute name="local" default="false"/>
- <attribute name="signed" default="false"/>
-
- <sequential>
- <local name="path"/> <property name="path" value="${dist.maven}/@{name}/@{name}"/>
-
- <echo>Deploying ${path}-pom.xml.</echo>
-
- <filter-pom name="@{name}" path="@{path}"/>
-
- <if><equals arg1="@{signed}" arg2="false"/><then>
- <deploy-to local="@{local}" pom="@{name}.pom"/>
- </then><else>
- <local name="repo"/>
- <if><equals arg1="@{local}" arg2="false"/><then>
- <property name="repo" value="${remote.repository}"/>
- </then><else>
- <property name="repo" value="${local.repository}"/>
- </else></if>
- <artifact:mvn failonerror="true">
- <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
- <arg value="-Durl=${repo}" />
- <arg value="-DrepositoryId=${repository.credentials.id}" />
- <arg value="-DpomFile=${path}-pom-filtered.xml" />
- <arg value= "-Dfile=${path}-pom-filtered.xml" />
- <arg value="-Pgpg" />
- <arg value="-Dgpg.useagent=true" />
- </artifact:mvn>
- </else></if>
- </sequential>
- </macrodef>
-
- <macrodef name="deploy">
- <attribute name="local" default="false"/>
- <attribute name="signed" default="false"/>
-
- <sequential>
- <deploy-one name="scala-library" local="@{local}" signed="@{signed}"/>
- <deploy-one name="scala-reflect" local="@{local}" signed="@{signed}"/>
- <deploy-one name="scala-compiler" local="@{local}" signed="@{signed}"/>
-
- <!-- TODO modularize compiler.
- <deploy-one name="scala-compiler-doc" local="@{local}" signed="@{signed}"/>
- <deploy-one name="scala-compiler-interactive" local="@{local}" signed="@{signed}"/>
- -->
-
- <deploy-one name="scalap" local="@{local}" signed="@{signed}"/>
- </sequential>
- </macrodef>
-
- <macrodef name="testSuite">
- <attribute name="dir" default="${partest.dir}"/>
- <attribute name="srcdir" default="files"/> <!-- TODO: make targets for `pending` and other subdirs -->
- <attribute name="colors" default="${partest.colors}"/>
- <attribute name="scalacOpts" default="${partest.scalac_opts} ${scalac.args.optimise}"/>
- <attribute name="javaOpts" default="${env.ANT_OPTS}"/>
- <attribute name="pcp" default="${toString:partest.compilation.path}"/>
- <attribute name="kinds"/>
- <sequential>
- <property name="partest.dir" value="@{dir}" />
- <partest srcdir="@{srcdir}"
- kinds="@{kinds}"
- colors="@{colors}"
- scalacOpts="@{scalacOpts}"
- javaOpts="@{javaOpts}"
- compilationpath="@{pcp}"/>
- </sequential>
- </macrodef>
-
- <macrodef name="bc.run-mima">
- <attribute name="jar-name"/>
- <attribute name="prev"/>
- <attribute name="curr"/>
- <attribute name="direction"/>
- <sequential>
- <echo message="Checking @{direction} binary compatibility for @{jar-name} (against ${bc-reference-version})"/>
- <java taskname="mima" fork="true" failonerror="true" classname="com.typesafe.tools.mima.cli.Main">
- <arg value="--prev"/>
- <arg value="@{prev}"/>
- <arg value="--curr"/>
- <arg value="@{curr}"/>
- <arg value="--filters"/>
- <arg value="${basedir}/bincompat-@{direction}.whitelist.conf"/>
- <arg value="--generate-filters"/>
- <classpath>
- <path refid="mima.classpath"/>
- </classpath>
- </java>
- </sequential>
- </macrodef>
-
- <macrodef name="bc.check">
- <attribute name="project"/>
- <sequential>
- <bc.run-mima jar-name="scala-@{project}" prev="${org.scala-lang:scala-@{project}:jar}" curr="${@{project}.jar}" direction="backward"/>
- <bc.run-mima jar-name="scala-@{project}" prev="${@{project}.jar}" curr="${org.scala-lang:scala-@{project}:jar}" direction="forward"/>
- </sequential>
- </macrodef>
-
- <macrodef name="tarz">
- <attribute name="name" description="The tar file name (without extension)."/>
- <element name="file-sets" description="A sequence of fileset elements to be included in the tar balls." optional="false" implicit="true"/>
- <sequential>
- <tar destfile="@{name}.tar" compression="none" longfile="gnu">
- <file-sets/>
- </tar>
- <gzip src="@{name}.tar" destfile="@{name}.tgz"/>
- <if>
- <not>
- <equals arg1="${archives.skipxz}" arg2="true"/>
- </not>
- <then>
- <exec executable="xz" failifexecutionfails="false">
- <arg line="-k -9e -S .xz @{name}.tar"/>
- </exec>
- <move file="@{name}.tar.xz" tofile="@{name}.txz" failonerror="false"/>
- </then>
- </if>
- <delete file="@{name}.tar"/>
- </sequential>
- </macrodef>
-</project>
diff --git a/build.number b/build.number
deleted file mode 100644
index 7c7e26fd09..0000000000
--- a/build.number
+++ /dev/null
@@ -1,13 +0,0 @@
-# The version number in this file should be the next un-released minor version,
-# e.g., 2.11.7, 2.12.0, 2.12.1. It's used to determine version numbers for
-# SNAPSHOT / nightly builds and local builds of source checkouts.
-
-version.major=2
-version.minor=12
-version.patch=0
-
-# This is the -N part of a version (2.9.1-1). If it's 0, it's dropped from maven versions. It should not be used again.
-version.bnum=0
-
-# To build a release, see scripts/jobs/scala-release-2.11.x-build
-# (normally run by the eponymous job on scala-ci.typesafe.com).
diff --git a/build.sbt b/build.sbt
index 9fdd40a1f6..1105902a9d 100644
--- a/build.sbt
+++ b/build.sbt
@@ -17,40 +17,19 @@
* This nicely leads me to explaining goal and non-goals of this build definition. Goals are:
*
* - to be easy to tweak it in case a bug or small inconsistency is found
- * - to mimic Ant's behavior as closely as possible
* - to be super explicit about any departure from standard sbt settings
- * - to achieve functional parity with Ant build as quickly as possible
* - to be readable and not necessarily succinct
* - to provide the nicest development experience for people hacking on Scala
+ * - originally, to mimic Ant's behavior as closely as possible, so the
+ * sbt and Ant builds could be maintained in parallel. the Ant build
+ * has now been removed, so we are now free to depart from that history.
*
* Non-goals are:
*
- * - to have the shortest sbt build definition possible; we'll beat Ant definition
- * easily and that will thrill us already
+ * - to have the shortest sbt build definition possible
* - to remove irregularities from our build process right away
+ * (but let's keep making gradual progress on this)
* - to modularize the Scala compiler or library further
- *
- * It boils down to simple rules:
- *
- * - project layout is set in stone for now
- * - if you need to work on convincing sbt to follow non-standard layout then
- * explain everything you did in comments
- * - constantly check where Ant build produces class files, artifacts, what kind of other
- * files generates and port all of that to here
- *
- * Note on bootstrapping:
- *
- * Let's start with reminder what bootstrapping means in our context. It's an answer
- * to this question: which version of Scala are using to compile Scala? The fact that
- * the question sounds circular suggests trickiness. Indeed, bootstrapping Scala
- * compiler is a tricky process.
- *
- * Ant build used to have involved system of bootstrapping Scala. It would consist of
- * three layers: starr, locker and quick. The sbt build for Scala ditches layering
- * and strives to be as standard sbt project as possible. This means that we are simply
- * building Scala with latest stable release of Scala.
- * See this discussion for more details behind this decision:
- * https://groups.google.com/d/topic/scala-internals/gp5JsM1E0Fo/discussion
*/
import VersionUtil._
@@ -69,8 +48,8 @@ val asmDep = "org.scala-lang.modules" % "scala-asm" % versionPr
val jlineDep = "jline" % "jline" % versionProps("jline.version")
val antDep = "org.apache.ant" % "ant" % "1.9.4"
-/** Publish to ./dists/maven-sbt, similar to the ANT build which publishes to ./dists/maven. This
- * can be used to compare the output of the sbt and ANT builds during the transition period. Any
+/** Publish to ./dists/maven-sbt, similar to the Ant build which publishes to ./dists/maven. This
+ * can be used to compare the output of the sbt and Ant builds during the transition period. Any
* real publishing should be done with sbt's standard `publish` task. */
lazy val publishDists = taskKey[Unit]("Publish to ./dists/maven-sbt.")
@@ -133,11 +112,8 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings +
// we always assume that Java classes are standalone and do not have any dependency
// on Scala classes
compileOrder := CompileOrder.JavaThenScala,
- javacOptions in Compile ++= Seq("-g", "-source", "1.8", "-target", "1.8"),
- // we don't want any unmanaged jars; as a reminder: unmanaged jar is a jar stored
- // directly on the file system and it's not resolved through Ivy
- // Ant's build stored unmanaged jars in `lib/` directory
- unmanagedJars in Compile := Seq.empty,
+ javacOptions in Compile ++= Seq("-g", "-source", "1.8", "-target", "1.8", "-Xlint:unchecked"),
+ unmanagedJars in Compile := Seq.empty, // no JARs in version control!
sourceDirectory in Compile := baseDirectory.value,
unmanagedSourceDirectories in Compile := List(baseDirectory.value),
unmanagedResourceDirectories in Compile += (baseDirectory in ThisBuild).value / "src" / thisProject.value.id,
@@ -217,7 +193,7 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings +
)
/** Extra post-processing for the published POM files. These are needed to create POMs that
- * are equivalent to the ones from the ANT build. In the long term this should be removed and
+ * are equivalent to the ones from the Ant build. In the long term this should be removed and
* POMs, scaladocs, OSGi manifests, etc. should all use the same metadata. */
def fixPom(extra: (String, scala.xml.Node)*): Setting[_] = {
/** Find elements in an XML document by a simple XPath and replace them */
@@ -314,8 +290,6 @@ def filterDocSources(ff: FileFilter): Seq[Setting[_]] = Seq(
// always required because otherwise the compiler cannot even initialize Definitions without
// binaries of the library on the classpath. Specifically, we get this error:
// (library/compile:doc) scala.reflect.internal.FatalError: package class scala does not have a member Int
- // Ant build does the same thing always: it puts binaries for documented classes on the classpath
- // sbt never does this by default (which seems like a good default)
dependencyClasspath in (Compile, doc) += (classDirectory in Compile).value,
doc in Compile <<= doc in Compile dependsOn (compile in Compile)
)
@@ -398,8 +372,8 @@ lazy val compiler = configureAsSubproject(project)
// These are only needed for the POM:
libraryDependencies ++= Seq(scalaXmlDep, jlineDep % "optional"),
// this a way to make sure that classes from interactive and scaladoc projects
- // end up in compiler jar (that's what Ant build does)
- // we need to use LocalProject references (with strings) to deal with mutual recursion
+ // end up in compiler jar. note that we need to use LocalProject references
+ // (with strings) to deal with mutual recursion
products in Compile in packageBin :=
(products in Compile in packageBin).value ++
Seq((dependencyClasspath in Compile).value.find(_.get(moduleID.key) == Some(asmDep)).get.data) ++
@@ -430,7 +404,7 @@ lazy val compiler = configureAsSubproject(project)
"*"),
"Class-Path" -> "scala-reflect.jar scala-library.jar"
),
- // Generate the ScriptEngineFactory service definition. The ant build does this when building
+ // 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"),
managedResourceDirectories in Compile := Seq((resourceManaged in Compile).value),
@@ -482,7 +456,7 @@ lazy val replJlineEmbedded = Project("repl-jline-embedded", file(".") / "target"
// There is nothing to compile for this project. Instead we use the compile task to create
// shaded versions of repl-jline and jline.jar. dist/mkBin puts all of quick/repl,
// quick/repl-jline and quick/repl-jline-shaded on the classpath for quick/bin scripts.
- // This is different from the ant build where all parts are combined into quick/repl, but
+ // This is different from the Ant build where all parts are combined into quick/repl, but
// it is cleaner because it avoids circular dependencies.
compile in Compile <<= (compile in Compile).dependsOn(Def.task {
import java.util.jar._
@@ -741,7 +715,7 @@ lazy val scalaDist = Project("scala-dist", file(".") / "target" / "scala-dist-di
(manOut ** "*.1" pair rebase(manOut, fixedManOut)).foreach { case (in, out) =>
// Generated manpages should always use LF only. There doesn't seem to be a good reason
// for generating them with the platform EOL first and then converting them but that's
- // what the ant build does.
+ // what the Ant build does.
IO.write(out, IO.readBytes(in).filterNot(_ == '\r'))
}
(htmlOut ** "*.html").get ++ (fixedManOut ** "*.1").get
diff --git a/build.xml b/build.xml
deleted file mode 100644
index 7c6f525c1c..0000000000
--- a/build.xml
+++ /dev/null
@@ -1,1786 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<project name="sabbus" default="build"
- xmlns:artifact="urn:maven-artifact-ant"
- xmlns:rsel="antlib:org.apache.tools.ant.types.resources.selectors">
- <include file="build-ant-macros.xml" as="macros"/>
-
- <description>
-SuperSabbus for Scala core, builds the scala library and compiler. It can also package it as a simple distribution, tests it for stable bootstrapping and against the Scala test suite.
- </description>
-
-<!-- HINTS
- - for faster builds, have a build.properties in the same directory as build.xml that says:
- locker.skip=1
--->
-
-<!-- USAGE FROM JENKINS SCRIPTS IS (CURRENTLY) AS FOLLOWS:
-ant $antArgs $scalacArgs $targets
-
-antArgs tend to be:
- -Darchives.skipxz=true
- -Dscalac.args.optimise=-opt:l:classpath
-
-scalacArgs examples:
- "-Dscalac.args=\"-Yrangepos\" -Dpartest.scalac_opts=\"-Yrangepos\""
-
-supported/exercised targets
- to publish: nightly publish-opt-nodocs
- to build: build build-opt locker.done
- to run tests: test.suite test.scaladoc
-
-DO NOT RELY ON ANY OTHER TARGETS (ok, you're probably ok assuming the ones defined in the first 100 lines of this file)
-
-To build your own Scala distribution, do, e.g.:
-
- ant publish-local-opt -Dmaven.version.suffix="-foo"
- cd ~/git
- hub clone scala/scala-dist
- cd scala-dist
- sbt 'set version := "2.11.0-foo"' 'set resolvers += Resolver.mavenLocal' universal:package-bin
-
-NOTE: `ant build` builds the essence of a Scala distribution under build/pack
- (The only thing missing are the docs; see `pack.doc` and `docs.done`.)
-
--->
-
-<!-- To use Zinc with the ant build:
- - install zinc and symlink the installed zinc script to ${basedir}/tools/zinc (${basedir} is where build.xml and the rest of your checkout resides)
- - make sure to set ZINC_OPTS to match ANT_OPTS!
--->
-
-<!--
-TODO:
- - detect zinc anywhere on PATH
- - automatically set ZINC_OPTS
- - skip locker (and test.stability) by default to speed up PR validation, still do full build & testing during nightly
- - (rework the build to pack locker and build using that when using zinc)
--->
-
-
-<!-- ===========================================================================
- END-USER TARGETS
-============================================================================ -->
- <target name="build" depends="pack.done" description="Builds the Scala compiler and library. Executables are in 'build/pack/bin'."/>
- <target name="test" depends="test.done" description="Runs test suite and bootstrapping test on Scala compiler and library."/>
- <target name="docs" depends="docs.done" description="Builds documentation for the Scala library. Scaladoc is in 'build/scaladoc/library'."/>
- <target name="docscomp" depends="docs.comp" description="Builds documentation for the Scala compiler and library. Scaladoc is in 'build/scaladoc'."/>
-
- <target name="build-opt" description="Optimized version of build."> <optimized name="build"/></target>
- <target name="test-opt" description="Optimized version of test."> <optimized name="test"/></target>
- <target name="test-core-opt" description="Optimized version of test.core."> <optimized name="test.core"/></target>
- <target name="test-stab-opt" description="Optimized version of test.stability."> <optimized name="test.stability"/></target>
-
- <target name="all.done" depends="test.done, pack-maven.done"/>
- <target name="nightly"><optimized name="all.done"/></target>
- <target name="nightly.checkall"> <antcall target="all.done"> <param name="partest.scalac_opts" value="-Ycheck:all"/></antcall></target>
-
- <!-- The IDE build requires swing, so need to publish them during PR validation until they are modules -->
- <target name="publish-opt-nodocs" description="Publishes Scala (optimized) without generating docs/testing (library/reflect/compiler/swing).">
- <antcall target="publish">
- <param name="docs.skip" value="1"/>
- <param name="scalac.args.optimise" value="-opt:l:classpath"/>
- </antcall>
- </target>
- <target name="publish-core-opt-nodocs" description="Builds an untested, undocumented optimised core (library/reflect/compiler) and publishes to maven.">
- <antcall target="publish-core">
- <param name="docs.skip" value="1"/>
- <param name="scalac.args.optimise" value="-opt:l:classpath"/>
- </antcall>
- </target>
- <target name="publish-core-local-nodocs" description="Builds an untested, undocumented core (library/reflect/compiler) and locally publishes to maven">
- <antcall target="publish-core-local">
- <param name="docs.skip" value="1"/>
- </antcall>
- </target>
-
- <!-- prefer the sbt names, but the dotted names are used in jenkins;
- rename there first before dropping the dotted ones -->
- <target name="publish-local" depends="publish.local"/>
- <target name="publish-local-opt"><optimized name="publish-local"/></target>
- <target name="publish-signed" depends="publish.signed"/>
-
-
-
-
-
-
-
-
-
-<!-- DEPRECATED -->
- <target name="dist" depends="all.clean, all.done" description="Cleans all and builds and tests a new distribution."/>
- <target name="partialdist" depends="pack.done" description="Makes a new distribution without testing it or removing partially build elements."/>
- <target name="fastdist" depends="pack.done, pack.doc" description="Makes a new distribution without testing it or removing partially build elements."/>
- <target name="dist-opt" description="Optimized version of dist."> <optimized name="dist"/></target>
- <target name="partialdist-opt" description="Optimized version of partialdist."> <optimized name="partialdist"/></target>
- <target name="fastdist-opt" description="Optimized version of fastdist."> <optimized name="fastdist"/></target>
-
- <!-- packaging -->
- <target name="distpack" depends="pack-maven.done"/>
- <target name="distpack-maven" depends="pack-maven.done"/>
- <target name="distpack-opt" description="Builds an optimised distribution."> <optimized name="distpack"/></target>
- <target name="distpack-maven-opt" description="Builds an optimised maven distribution."><optimized name="distpack-maven"/></target>
- <target name="distclean" depends="dist.clean" description="Removes all distributions. Binaries and documentation are untouched."/>
-
- <target name="nightly-nopt" depends="all.done"/>
-
- <target name="clean" depends="quick.clean" description="Removes binaries of compiler and library. Locker and distributions are untouched."/>
- <target name="docsclean" depends="docs.clean" description="Removes generated documentation. Distributions are untouched."/>
-
-
-
-<!-- ===========================================================================
- PROPERTIES
-============================================================================ -->
-
- <property environment="env"/>
- <!-- Prevents system classpath from being used -->
- <property name="build.sysclasspath" value="ignore"/>
-
- <!-- Defines the repository layout -->
- <property name="doc.dir" value="${basedir}/doc"/>
- <property name="lib.dir" value="${basedir}/lib"/>
- <property name="src.dir" value="${basedir}/src"/>
- <property name="partest.dir" value="${basedir}/test"/>
-
- <property name="lib-ant.dir" value="${lib.dir}/ant"/>
- <!-- For developers: any jars placed in this dir will be added to the classpath
- of all targets and copied into quick/pack/etc builds. -->
- <property name="lib-extra.dir" value="${lib.dir}/extra"/>
-
- <!-- Loads custom properties definitions -->
- <property file="${basedir}/build.properties"/>
-
- <!-- Generating version number -->
- <property file="${basedir}/build.number"/>
-
- <!-- read versions.properties -->
- <property file="${basedir}/versions.properties"/>
-
- <!-- Sets location of pre-compiled libraries -->
- <property name="ant.jar" value="${ant.home}/lib/ant.jar"/>
-
- <!-- Sets location of build folders -->
- <property name="build.dir" value="${basedir}/build"/>
- <property name="build-deps.dir" value="${build.dir}/deps"/>
- <property name="build-libs.dir" value="${build.dir}/libs"/>
- <property name="build-locker.dir" value="${build.dir}/locker"/>
- <property name="build-quick.dir" value="${build.dir}/quick"/>
- <property name="build-pack.dir" value="${build.dir}/pack"/>
- <property name="build-manual.dir" value="${build.dir}/manual"/>
- <property name="build-osgi.dir" value="${build.dir}/osgi"/>
- <property name="build-junit.dir" value="${build.dir}/junit"/>
- <property name="build-strap.dir" value="${build.dir}/strap"/>
- <property name="build-docs.dir" value="${build.dir}/scaladoc"/>
- <property name="build-sbt.dir" value="${build.dir}/sbt-interface"/>
-
- <property name="test.osgi.src" value="${partest.dir}/osgi/src"/>
- <property name="test.osgi.classes" value="${build-osgi.dir}/classes"/>
-
- <property name="test.junit.src" value="${partest.dir}/junit"/>
- <property name="test.junit.classes" value="${build-junit.dir}/classes"/>
-
- <property name="dists.dir" value="${basedir}/dists"/>
-
- <property name="copyright.string" value="Copyright 2002-2016, LAMP/EPFL"/>
-
- <!-- These are NOT the flags used to run SuperSabbus, but the ones written
- into the script runners created with scala.tools.ant.ScalaTool -->
- <property name="java.flags" value="-Xmx256M -Xms32M"/>
- <property name="jvm.opts" value=""/>
-
- <!-- if ANT_OPTS is already set by the environment, it will be unaltered,
- but if it is unset it will take this default value. -->
- <property name="env.ANT_OPTS" value="-Xms1536M -Xmx1536M -Xss1M -XX:+UseParallelGC" />
-
- <property name="scalacfork.jvmargs" value="${env.ANT_OPTS} ${jvm.opts}"/>
-
-<!-- ===========================================================================
- INITIALIZATION
-============================================================================ -->
- <target name="desired.jars.uptodate">
- <patternset id="desired.jars">
- <include name="lib/**/*.desired.sha1"/>
- <include name="test/files/**/*.desired.sha1"/>
- <include name="tools/**/*.desired.sha1"/>
- </patternset>
-
- <uptodate property="lib.jars.uptodate">
- <srcfiles dir="${basedir}"><patternset refid="desired.jars"/></srcfiles>
- <mapper type="glob" from="*.desired.sha1" to="*"/>
- </uptodate>
- </target>
-
- <target name="boot" depends="desired.jars.uptodate" unless="lib.jars.uptodate">
- <echo level="warn" message="Updating bootstrap libs. (To do this by hand, run ./pull-binary-libs.sh)"/>
- <exec osfamily="unix" vmlauncher="false" executable="./pull-binary-libs.sh" failifexecutionfails="true" />
- <exec osfamily="windows" vmlauncher="false" executable="pull-binary-libs.sh" failifexecutionfails="true" />
- <!-- uptodate task needs to know these are what's in the sha. -->
- <touch>
- <fileset dir="${basedir}"><patternset refid="desired.jars"/></fileset>
- <mapper type="glob" from="*.desired.sha1" to="*"/>
- </touch>
- </target>
-
- <target name="init.git" depends="boot">
- <!-- replacestarr needs git.commit.sha, but doesn't want to run the init target (it computes maven.version.number) -->
- <exec osfamily="unix" executable="tools/get-scala-commit-sha" outputproperty="git.commit.sha" failifexecutionfails="false" />
- <exec osfamily="windows" executable="cmd.exe" outputproperty="git.commit.sha" failifexecutionfails="false">
- <arg value="/c"/>
- <arg value="tools\get-scala-commit-sha.bat"/>
- <arg value="-p"/>
- </exec>
- <exec osfamily="unix" executable="tools/get-scala-commit-date" outputproperty="git.commit.date" failifexecutionfails="false" />
- <exec osfamily="windows" executable="cmd.exe" outputproperty="git.commit.date" failifexecutionfails="false">
- <arg value="/c"/>
- <arg value="tools\get-scala-commit-date.bat"/>
- <arg value="-p"/>
- </exec>
-
- <!-- some default in case something went wrong getting the revision -->
- <property name="git.commit.sha" value="unknown"/>
- <property name="git.commit.date" value="unknown"/>
- </target>
-
- <target name="init" depends="init.git">
- <!-- Set up Ant contrib tasks so we can use <if><then><else> instead of the clunky `unless` attribute -->
- <taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${lib-ant.dir}/ant-contrib.jar"/>
-
- <property name="scala.ant.min.version" value="1.8.2"/>
- <if><not><antversion atleast="${scala.ant.min.version}"/></not>
- <then><fail message="Ant version ${scala.ant.min.version} is required. You are running ${ant.version}"/></then>
- </if>
-
- <!-- Add our maven ant tasks -->
- <path id="maven-ant-tasks.classpath" path="${lib-ant.dir}/maven-ant-tasks-2.1.1.jar" />
- <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant" classpathref="maven-ant-tasks.classpath" />
-
- <!-- Resolve maven dependencies -->
-
- <!-- work around http://jira.codehaus.org/browse/MANTTASKS-203:
- java.lang.ClassCastException: org.codehaus.plexus.DefaultPlexusContainer cannot be cast to org.codehaus.plexus.PlexusContainer
- on repeated use of artifact:dependencies
- -->
- <if><not><isset property="maven-deps-done"></isset></not><then>
- <mkdir dir="${user.home}/.m2/repository"/>
- <!-- This task has an issue where if the user directory does not exist, so we create it above. UGH. -->
- <artifact:dependencies pathId="extra.tasks.classpath" filesetId="extra.tasks.fileset">
- <dependency groupId="biz.aQute.bnd" artifactId="biz.aQute.bnd" version="2.4.1"/>
- </artifact:dependencies>
-
- <artifact:dependencies pathId="jarjar.classpath">
- <dependency groupId="org.pantsbuild" artifactId="jarjar" version="1.6.0"/>
- </artifact:dependencies>
-
- <artifact:dependencies pathId="jarlister.classpath">
- <dependency groupId="com.github.rjolly" artifactId="jarlister_2.11" version="1.0"/>
- </artifact:dependencies>
-
- <!-- JUnit -->
- <property name="junit.version" value="4.12"/>
- <artifact:dependencies pathId="junit.classpath" filesetId="junit.fileset">
- <dependency groupId="junit" artifactId="junit" version="${junit.version}"/>
- <dependency groupId="org.openjdk.jol" artifactId="jol-core" version="0.5"/>
- </artifact:dependencies>
- <copy-deps project="junit"/>
-
- <!-- Pax runner -->
- <property name="pax.exam.version" value="4.5.0"/>
- <property name="osgi.felix.version" value="5.0.1"/>
- <property name="osgi.equinox.version" value="3.10.100.v20150521-1310"/>
- <artifact:dependencies pathId="pax.exam.classpath" filesetId="pax.exam.fileset">
- <dependency groupId="org.ops4j.pax.exam" artifactId="pax-exam-container-native" version="${pax.exam.version}"/>
- <dependency groupId="org.ops4j.pax.exam" artifactId="pax-exam-junit4" version="${pax.exam.version}"/>
- <dependency groupId="org.ops4j.pax.exam" artifactId="pax-exam-link-assembly" version="${pax.exam.version}"/>
- <dependency groupId="org.ops4j.pax.url" artifactId="pax-url-aether" version="2.4.1"/>
- <dependency groupId="org.ops4j.pax.swissbox" artifactId="pax-swissbox-tracker" version="1.8.1"/>
- <dependency groupId="ch.qos.logback" artifactId="logback-core" version="1.1.3"/>
- <dependency groupId="ch.qos.logback" artifactId="logback-classic" version="1.1.3"/>
- <dependency groupId="junit" artifactId="junit" version="${junit.version}"/>
- <dependency groupId="org.slf4j" artifactId="slf4j-api" version="1.7.12"/>
- </artifact:dependencies>
- <copy-deps project="pax.exam"/>
-
- <artifact:dependencies pathId="osgi.framework.felix">
- <dependency groupId="org.apache.felix" artifactId="org.apache.felix.framework" version="${osgi.felix.version}"/>
- </artifact:dependencies>
-
- <artifact:dependencies pathId="osgi.framework.equinox">
- <dependency groupId="org.eclipse.tycho" artifactId="org.eclipse.osgi" version="${osgi.equinox.version}"/>
- </artifact:dependencies>
-
- <artifact:remoteRepository id="sonatype-release" url="https://oss.sonatype.org/content/repositories/releases"/>
- <artifact:remoteRepository id="extra-repo" url="${extra.repo.url}"/>
-
- <!-- prepare, for each of the names below, the property "@{name}.cross", set to the
- necessary cross suffix (usually something like "_2.11.0-M6". -->
- <prepareCross name="scala-xml" />
- <prepareCross name="scala-parser-combinators" />
- <prepareCross name="scala-swing"/>
- <prepareCross name="partest"/>
-
- <artifact:dependencies pathId="asm.classpath" filesetId="asm.fileset">
- <dependency groupId="org.scala-lang.modules" artifactId="scala-asm" version="${scala-asm.version}"/>
- </artifact:dependencies>
- <copy-deps project="asm"/>
-
- <!-- TODO: delay until absolutely necessary to allow minimal build, also move out partest dependency from scaladoc -->
- <artifact:dependencies pathId="partest.classpath" filesetId="partest.fileset" versionsId="partest.versions">
- <!-- uncomment the following if you're deploying your own partest locally -->
- <!-- <localRepository path="${user.home}/.m2/repository"/> -->
- <!-- so we don't have to wait for artifacts to synch to maven central
- (we don't distribute partest with Scala, so the risk of sonatype and maven being out of synch is irrelevant):
- -->
- <artifact:remoteRepository refid="sonatype-release"/>
- <artifact:remoteRepository refid="extra-repo"/>
- <dependency groupId="org.scala-lang.modules" artifactId="scala-partest${partest.cross}" version="${partest.version.number}" />
- </artifact:dependencies>
- <copy-deps project="partest"/>
-
- <artifact:dependencies pathId="repl.deps.classpath" filesetId="repl.fileset" versionsId="repl.deps.versions">
- <dependency groupId="jline" artifactId="jline" version="${jline.version}"/>
- </artifact:dependencies>
- <copy-deps project="repl"/>
-
- <!-- used by the test.osgi target to create osgi bundles for the xml, parser-combinator jars
- must specify sourcesFilesetId, javadocFilesetId to download these types of artifacts -->
- <artifact:dependencies pathId="external-modules.deps.classpath" sourcesFilesetId="external-modules.sources.fileset" javadocFilesetId="external-modules.javadoc.fileset">
- <artifact:remoteRepository refid="extra-repo"/>
- <dependency groupId="org.scala-lang.modules" artifactId="scala-xml${scala-xml.cross}" version="${scala-xml.version.number}"/>
- <dependency groupId="org.scala-lang.modules" artifactId="scala-parser-combinators${scala-parser-combinators.cross}" version="${scala-parser-combinators.version.number}"/>
- <dependency groupId="org.scala-lang.modules" artifactId="scala-swing${scala-swing.cross}" version="${scala-swing.version.number}"/>
- </artifact:dependencies>
-
- <!-- External modules, excluding the core -->
- <path id="external-modules-nocore">
- <restrict>
- <path refid="external-modules.deps.classpath"/>
- <rsel:not><rsel:or>
- <rsel:name name="scala-library*.jar"/>
- <rsel:name name="scala-reflect*.jar"/>
- <rsel:name name="scala-compiler*.jar"/>
- </rsel:or></rsel:not>
- </restrict>
- </path>
- <copy-deps refid="external-modules-nocore" project="scaladoc"/>
-
- <propertyForCrossedArtifact name="scala-parser-combinators" jar="org.scala-lang.modules:scala-parser-combinators"/>
- <propertyForCrossedArtifact name="scala-xml" jar="org.scala-lang.modules:scala-xml"/>
- <propertyForCrossedArtifact name="scala-swing" jar="org.scala-lang.modules:scala-swing"/>
-
- <!-- BND support -->
- <typedef resource="aQute/bnd/ant/taskdef.properties" classpathref="extra.tasks.classpath" />
-
- <echo message="Using Scala ${starr.version} for STARR."/>
- <artifact:dependencies pathId="starr.compiler.path" filesetId="starr.fileset">
- <artifact:remoteRepository refid="extra-repo"/>
- <dependency groupId="org.scala-lang" artifactId="scala-library" version="${starr.version}"/>
- <dependency groupId="org.scala-lang" artifactId="scala-reflect" version="${starr.version}"/>
- <dependency groupId="org.scala-lang" artifactId="scala-compiler" version="${starr.version}"/>
- </artifact:dependencies>
- <copy-deps project="starr"/>
-
- <property name="maven-deps-done" value="yep!"/>
- </then></if>
-
-
- <!-- NOTE: ant properties are write-once: second writes are silently discarded; the logic below relies on this -->
-
- <!-- Compute defaults (i.e., if not specified on command-line) for OSGi/maven version suffixes.
- Try to establish the invariant (verified below):
- `version.suffix == maven.version.suffix == osgi.version.suffix`,
- except for:
- - snapshot builds, where:
- - `maven.suffix == "-SNAPSHOT"`
- - `version.suffix == osgi.version.suffix == ""`
- - final builds, where:
- - `osgi.suffix == "-VFINAL"`
- - `version.suffix == maven.version.suffix == ""`
- -->
- <if><not><equals arg1="${version.bnum}" arg2="0"/></not><then>
- <property name="version.suffix" value="-${version.bnum}"/>
- </then></if>
-
- <if><or><not><isset property="version.suffix"/></not><equals arg1="${version.suffix}" arg2=""/></or><then>
- <if><isset property="build.release"/><then>
- <property name="maven.version.suffix" value=""/>
- <property name="version.suffix" value="${maven.version.suffix}"/>
- <if><equals arg1="${maven.version.suffix}" arg2=""/><then>
- <property name="osgi.version.suffix" value="-VFINAL"/></then>
- <else>
- <property name="osgi.version.suffix" value="${maven.version.suffix}"/></else></if></then></if></then>
- <else> <!-- version.suffix set and not empty -->
- <property name="maven.version.suffix" value="${version.suffix}"/>
- <property name="osgi.version.suffix" value="${version.suffix}"/></else></if>
-
- <!-- if a maven version suffix was set (or inferred), assume we're building a release -->
- <if><isset property="maven.version.suffix"/><then>
- <property name="build.release" value="1"/></then></if>
-
- <!-- not building a release and no version.suffix specified -->
- <property name="maven.version.suffix" value="-SNAPSHOT"/>
-
- <if><equals arg1="${maven.version.suffix}" arg2="-SNAPSHOT"/><then>
- <property name="osgi.version.suffix" value=""/>
- <property name="version.suffix" value=""/></then>
- <else>
- <property name="osgi.version.suffix" value="${maven.version.suffix}"/>
- <property name="version.suffix" value="${maven.version.suffix}"/></else></if>
-
- <!-- We use the git describe to determine the OSGi modifier for our build. -->
- <property name="maven.version.number"
- value="${version.major}.${version.minor}.${version.patch}${maven.version.suffix}"/>
- <property name="osgi.version.number"
- value="${version.major}.${version.minor}.${version.patch}.v${git.commit.date}${osgi.version.suffix}-${git.commit.sha}"/>
-
- <if><isset property="build.release"/><then>
- <property name="version.number" value="${maven.version.number}"/>
- </then><else>
- <property name="version.number" value="${version.major}.${version.minor}.${version.patch}${version.suffix}-${git.commit.date}-${git.commit.sha}"/>
- </else></if>
-
- <!-- some default in case something went wrong getting the revision -->
- <property name="version.number" value="-unknown-"/>
-
- <condition property="has.java8">
- <equals arg1="${ant.java.version}" arg2="1.8"/>
- </condition>
- <condition property="has.unsupported.jdk">
- <not><or>
- <isset property="has.java8" />
- </or></not>
- </condition>
-
- <fail if="has.unsupported.jdk" message="JDK ${ant.java.version} is not supported by this build!"/>
- <fail message="Ant 1.9+ required">
- <condition>
- <not><antversion atleast="1.9" /></not>
- </condition>
- </fail>
-
- <!-- Allow this to be overridden simply -->
- <property name="sbt.latest.version" value="0.13.11"/>
-
- <property name="sbt.src.dir" value="${build-sbt.dir}/${sbt.latest.version}/src"/>
- <property name="sbt.lib.dir" value="${build-sbt.dir}/${sbt.latest.version}/lib"/>
-
- <property name="sbt.interface.jar" value="${sbt.lib.dir}/interface.jar"/>
- <property name="sbt.interface.url" value="http://dl.bintray.com/typesafe/ivy-releases/org.scala-sbt/interface/${sbt.latest.version}/jars/interface.jar"/>
- <property name="sbt.interface.src.jar" value="${sbt.src.dir}/compiler-interface-src.jar"/>
- <property name="sbt.interface.src.url" value="http://dl.bintray.com/typesafe/ivy-releases/org.scala-sbt/compiler-interface/${sbt.latest.version}/srcs/compiler-interface-sources.jar"/>
-
-
- <!-- Additional command line arguments for scalac. They are added to all build targets -->
- <property name="scalac.args" value=""/>
- <property name="javac.args" value=""/>
-
- <property name="scalac.args.always" value="-feature" />
- <property name="scalac.args.optimise" value=""/> <!-- scalac.args.optimise is selectively overridden in certain antcall tasks. -->
- <property name="scalac.args.all" value="${scalac.args.always} ${scalac.args} ${scalac.args.optimise}"/>
- <property name="scalac.args.locker" value="${scalac.args.all}"/>
- <property name="scalac.args.quick" value="${scalac.args.all}"/>
- <property name="scalac.args.strap" value="${scalac.args.quick}"/>
-
- <property name="partest.scalac_opts" value=""/> <!-- set default value, otherwise the property name will be passed to partest if undefined -->
-
- <!-- This is the start time for the distribution -->
- <tstamp prefix="time">
- <format property="human" pattern="d MMMM yyyy, HH:mm:ss" locale="en,US"/>
- <format property="short" pattern="yyyyMMddHHmmss"/>
- </tstamp>
-
- <!-- Local libs (developer use.) -->
- <mkdir dir="${lib-extra.dir}"/>
-
- <!-- Auxiliary libs placed on every classpath. -->
- <path id="aux.libs">
- <pathelement location="${ant.jar}"/>
- <!-- needs ant 1.7.1 -->
- <!-- <fileset dir="${lib-extra.dir}" erroronmissingdir="false"> -->
- <fileset dir="${lib-extra.dir}">
- <include name="**/*.jar"/>
- </fileset>
- </path>
-
- <!-- And print-out what we are building -->
- <echo message=" build time: ${time.human}" />
- <echo message=" java version: ${java.vm.name} ${java.version} (${ant.java.version})" />
- <echo message=" java args: ${env.ANT_OPTS} ${jvm.opts}" />
- <echo message=" javac args: ${javac.args}" />
- <echo message=" scalac args: ${scalac.args.all}" />
- <echo message="scalac quick args: ${scalac.args.quick}" />
- <echo message=" git date: ${git.commit.date}" />
- <echo message=" git hash: ${git.commit.sha}" />
- <echo message=" maven version: ${maven.version.number}"/>
- <echo message=" OSGi version: ${osgi.version.number}" />
- <echo message="canonical version: ${version.number}" />
-
- <echoproperties destfile="buildcharacter.properties">
- <propertyset>
- <propertyref regex="time.*" />
- <propertyref regex="git.*" />
- <propertyref name="java.vm.name" />
- <propertyref regex=".*version.*" />
- <propertyref regex="scalac.args.*" />
- <propertyref name="scalacfork.jvmargs" />
- </propertyset>
- </echoproperties>
-
- <!-- validate version suffixes -->
- <if><equals arg1="${maven.version.suffix}" arg2="-SNAPSHOT"/><then>
- <condition property="version.suffixes.consistent"><and>
- <equals arg1="${osgi.version.suffix}" arg2=""/>
- <equals arg1="${version.suffix}" arg2=""/>
- </and></condition></then>
- <else>
- <if><equals arg1="${osgi.version.suffix}" arg2="-VFINAL"/><then>
- <condition property="version.suffixes.consistent"><and>
- <equals arg1="${maven.version.suffix}" arg2=""/>
- <equals arg1="${version.suffix}" arg2=""/>
- </and></condition></then>
- <else>
- <condition property="version.suffixes.consistent"><and>
- <equals arg1="${osgi.version.suffix}" arg2="${maven.version.suffix}"/>
- <equals arg1="${version.suffix}" arg2="${maven.version.suffix}"/>
- </and></condition></else></if></else></if>
-
- <!-- <echo message=" maven suffix: ${maven.version.suffix}"/>
- <echo message=" OSGi suffix: ${osgi.version.suffix}" />
- <echo message="canonical suffix: ${version.suffix}" /> -->
- <fail unless="version.suffixes.consistent" message="Version suffixes inconsistent!"/>
-
-
- <!-- used during releases to bump versions in versions.properties -->
- <if><isset property="update.versions"/><then>
- <echo message="Updating `versions.properties`:"/>
- <echo message="starr.version = ${starr.version}"/>
- <echo message="scala.binary.version = ${scala.binary.version}"/>
- <echo message="scala-xml.version.number = ${scala-xml.version.number}"/>
- <echo message="scala-parser-combinators.version.number = ${scala-parser-combinators.version.number}"/>
- <echo message="scala-swing.version.number = ${scala-swing.version.number}"/>
- <echo message="jline.version = ${jline.version}"/>
- <echo message="partest.version.number = ${partest.version.number}"/>
-
- <propertyfile file="versions.properties">
- <entry key="starr.version" value="${starr.version}"/>
- <entry key="scala.binary.version" value="${scala.binary.version}"/>
- <entry key="scala-xml.version.number" value="${scala-xml.version.number}"/>
- <entry key="scala-parser-combinators.version.number" value="${scala-parser-combinators.version.number}"/>
- <entry key="scala-swing.version.number" value="${scala-swing.version.number}"/>
- <entry key="jline.version" value="${jline.version}"/>
- <entry key="partest.version.number" value="${partest.version.number}"/>
- </propertyfile>
- </then></if>
-
- <!-- the following properties fully define staged-docs, staged-pack, make-bundle, copy-bundle and mvn-package for each of the projects -->
- <property name="library.description" value="Scala Standard Library"/>
- <property name="library.docroot" value="rootdoc.txt"/>
- <property name="library.skipPackages" value="scala.concurrent.impl"/>
-
- <property name="reflect.description" value="Scala Reflection Library"/>
- <property name="reflect.skipPackages" value="scala.reflect.macros.internal:scala.reflect.internal:scala.reflect.io"/>
-
- <property name="compiler.description" value="Scala Compiler"/>
- <property name="compiler.docroot" value="rootdoc.txt"/>
-
- <!-- these are not used used, preparation for the 'TODO modularize compiler' task -->
- <property name="interactive.description" value="Scala Interactive Compiler" />
- <property name="interactive.package" value="modules." />
- <property name="interactive.name" value="scala-compiler-interactive"/>
- <property name="interactive.namesuffix" value="_${scala.binary.version}"/>
- <property name="interactive.version" value="${scala-compiler-interactive.version.number}"/>
- <property name="interactive.targetjar" value="scala-compiler-interactive_${scala.binary.version}-${scala-compiler-interactive.version.number}.jar"/>
-
- <property name="scaladoc.description" value="Scala Documentation Generator"/>
- <property name="scaladoc.package" value="modules." />
- <property name="scaladoc.name" value="scala-compiler-doc" />
- <property name="scaladoc.namesuffix" value="_${scala.binary.version}"/>
- <property name="scaladoc.version" value="${scala-compiler-doc.version.number}"/>
- <property name="scaladoc.targetjar" value="scala-compiler-doc_${scala.binary.version}-${scala-compiler-doc.version.number}.jar"/>
-
- <property name="swing.description" value="Scala Swing Library"/>
- <property name="swing.package" value="modules."/>
- <property name="swing.targetjar" value="scala-swing${scala-swing.cross}-${scala-swing.version.number}.jar"/>
- <property name="swing.jar" value="${scala-swing}"/>
- <property name="swing.src" value="false"/>
- <property name="swing.srcjar" value="${scala-swing-sources}"/>
-
- <property name="parser-combinators.description" value="Scala Parser Combinators Library"/>
- <property name="parser-combinators.package" value="modules."/>
- <property name="parser-combinators.targetjar" value="scala-parser-combinators${scala-parser-combinators.cross}-${scala-parser-combinators.version.number}.jar"/>
- <property name="parser-combinators.jar" value="${scala-parser-combinators}"/>
- <property name="parser-combinators.src" value="false"/>
- <property name="parser-combinators.srcjar" value="${scala-parser-combinators-sources}"/>
-
- <property name="xml.description" value="Scala XML Library"/>
- <property name="xml.package" value="modules."/>
- <property name="xml.targetjar" value="scala-xml${scala-xml.cross}-${scala-xml.version.number}.jar"/>
- <property name="xml.jar" value="${scala-xml}"/>
- <property name="xml.src" value="false"/>
- <property name="xml.srcjar" value="${scala-xml-sources}"/>
-
- <property name="scalap.description" value="Scala Bytecode Parser"/>
- <property name="scalap.targetjar" value="scalap.jar"/>
-
- <property name="partest.description" value="Scala Compiler Testing Tool"/>
- <property name="partest-extras.description" value="Scala Compiler Testing Tool (compiler-specific extras)"/>
- <property name="partest-javaagent.description" value="Scala Compiler Testing Tool (compiler-specific java agent)"/>
-
- <!-- projects without project-specific options: manual, bin, repl -->
- <for list="compiler,interactive,scaladoc,library,parser-combinators,partest,partest-extras,partest-javaagent,reflect,scalap,swing,xml,repl-jline" param="project">
- <sequential>
- <!-- description is mandatory -->
- <init-project-prop project="@{project}" name="package" default=""/> <!-- used by mvn-package, copy-bundle, make-bundle -->
- <init-project-prop project="@{project}" name="dir" default=""/> <!-- used by mvn-package -->
- <init-project-prop project="@{project}" name="name" default="scala-@{project}"/> <!-- used for defaults in this block and by mvn-package, copy-bundle, make-bundle -->
- <init-project-prop project="@{project}" name="namesuffix" default=""/>
- <init-project-prop project="@{project}" name="version" default="${osgi.version.number}"/>
- <init-project-prop project="@{project}" name="targetdir" default="lib"/>
- <init-project-prop project="@{project}" name="targetjar" default="${@{project}.name}.jar"/>
- <init-project-prop project="@{project}" name="jar" default="${build-pack.dir}/${@{project}.targetdir}/${@{project}.targetjar}" />
- <init-project-prop project="@{project}" name="docroot" default="NOT SET"/>
- <init-project-prop project="@{project}" name="skipPackages" default=""/>
- <init-project-prop project="@{project}" name="srcdir" default="@{project}"/>
- <init-project-prop project="@{project}" name="src" default="true"/>
- <init-project-prop project="@{project}" name="srcjar" default="${build-osgi.dir}/${@{project}.name}-src.jar"/>
- </sequential>
- </for>
-
-
- <!-- Compilers to use for the various stages.
- There must be a variable of the shape @{stage}.compiler.path for all @{stage} in starr, locker, quick, strap.
- -->
-
- <!-- starr is resolved (to starr.compiler.path) in the block protected by maven-deps-done
- the maven task must not be executed twice, or you get a java.lang.ClassCastException:
- org.apache.maven.artifact.ant.RemoteRepository cannot be cast to org.apache.maven.artifact.ant.Repository
- -->
-
- <!-- To skip locker, use -Dlocker.skip=1 -->
- <if><isset property="locker.skip"/><then>
- <echo message="Using STARR to build the quick stage (skipping locker)."/>
- <path id="locker.compiler.path" refid="starr.compiler.path"/>
- <!-- this is cheating (we don't know the classpath used to build starr)
- but should be close enough: -->
- <path id="locker.compiler.build.path" refid="starr.compiler.path"/>
- <property name="locker.locked" value="locker skipped"/></then>
- <else>
- <path id="locker.compiler.path"><path refid="locker.compiler.build.path"/></path></else></if>
-
- <!-- compilerpathref for compiling with quick -->
- <path id="quick.compiler.path"> <path refid="quick.compiler.build.path"/></path>
-
-
- <!-- What to have on the compilation path when compiling during certain phases.
-
- There must be a variable of the shape @{stage}.@{project}.build.path
- for all @{stage} in locker, quick, strap
- and all @{project} in library, reflect, compiler
- when stage is quick, @{project} also includes: repl, scalap
-
- NOTE: interactive, scaladoc, are only used upto quick; they are still packed into the compiler jar
- -->
-
- <!-- LOCKER -->
- <path id="locker.library.build.path">
- <pathelement location="${build-locker.dir}/classes/library"/>
- <path refid="aux.libs"/>
- </path>
-
- <path id="locker.reflect.build.path">
- <path refid="locker.library.build.path"/>
- <pathelement location="${build-locker.dir}/classes/reflect"/>
- </path>
-
- <if><not><isset property="locker.skip"/></not><then>
- <path id="locker.compiler.build.path">
- <path refid="locker.reflect.build.path"/>
- <pathelement location="${build-locker.dir}/classes/compiler"/>
- <path refid="asm.classpath"/>
- </path>
- </then></if>
- <!-- else, locker.compiler.build.path is set above -->
-
- <!-- QUICK -->
- <path id="quick.library.build.path">
- <pathelement location="${build-quick.dir}/classes/library"/>
- <path refid="aux.libs"/>
- </path>
-
- <path id="quick.reflect.build.path">
- <path refid="quick.library.build.path"/>
- <pathelement location="${build-quick.dir}/classes/reflect"/>
- </path>
-
- <path id="quick.compiler.build.path">
- <path refid="quick.reflect.build.path"/>
- <pathelement location="${build-quick.dir}/classes/compiler"/>
- <path refid="asm.classpath"/>
- </path>
-
- <path id="quick.repl.build.path">
- <path refid="quick.compiler.build.path"/>
- <path refid="quick.interactive.build.path"/>
- <pathelement location="${build-quick.dir}/classes/repl"/>
- </path>
-
- <path id="quick.repl-jline.build.path">
- <path refid="quick.repl.build.path"/>
- <pathelement location="${build-quick.dir}/classes/repl-jline"/>
- <path refid="repl.deps.classpath"/>
- </path>
-
- <path id="quick.scalap.build.path">
- <path refid="quick.compiler.build.path"/>
- <pathelement location="${build-quick.dir}/classes/scalap"/>
- </path>
-
- <path id="quick.partest-extras.build.path">
- <path refid="asm.classpath"/>
- <restrict>
- <path refid="partest.classpath"/>
- <rsel:not><rsel:or>
- <rsel:name name="scala-library*.jar"/>
- </rsel:or></rsel:not>
- </restrict>
-
- <path refid="quick.compiler.build.path"/>
- <pathelement location="${build-quick.dir}/classes/repl"/>
- <!-- for the java dependency: Profiler.java -->
- <pathelement location="${build-quick.dir}/classes/partest-extras"/>
- </path>
-
- <path id="quick.partest-javaagent.build.path">
- <path refid="asm.classpath"/>
- </path>
-
- <path id="quick.scaladoc.build.path">
- <path refid="quick.compiler.build.path"/>
- <path refid="partest.classpath"/>
- <path refid="external-modules-nocore"/>
- <pathelement location="${build-quick.dir}/classes/scaladoc"/>
- </path>
-
- <path id="quick.interactive.build.path">
- <path refid="quick.compiler.build.path"/>
- <pathelement location="${build-quick.dir}/classes/interactive"/>
- </path>
-
- <path id="quick.bin.tool.path">
- <path refid="quick.repl-jline.build.path"/>
- <pathelement location="${build-quick.dir}/classes/scalap"/>
- <pathelement location="${build-quick.dir}/classes/scaladoc"/>
- <path refid="external-modules-nocore"/>
- </path>
-
- <!-- PACK -->
- <path id="pack.compiler.path">
- <pathelement location="${library.jar}"/>
- <pathelement location="${reflect.jar}"/>
- <pathelement location="${compiler.jar}"/>
- <pathelement location="${ant.jar}"/>
- <path refid="aux.libs"/>
- </path>
-
- <path id="pack.lib.path">
- <pathelement location="${library.jar}"/>
- <path refid="jarlister.classpath"/>
- </path>
-
- <path id="pack.bin.tool.path">
- <pathelement location="${library.jar}"/>
- <pathelement location="${xml.jar}"/>
- <pathelement location="${reflect.jar}"/>
- <pathelement location="${compiler.jar}"/>
- <!-- TODO modularize compiler: <pathelement location="${scaladoc.jar}"/> -->
- <pathelement location="${scalap.jar}"/>
- <path refid="repl.deps.classpath"/>
- <path refid="aux.libs"/>
- </path>
-
- <path id="pack.library.files">
- <fileset dir="${build-quick.dir}/classes/library"/>
- </path>
-
- <path id="pack.repl-jline.files">
- <fileset dir="${build-quick.dir}/classes/repl-jline"/>
- </path>
-
- <path id="pack.compiler.files">
- <fileset dir="${build-quick.dir}/classes/compiler"/>
-
- <!-- TODO modularize compiler. Remove the other class dirs as soon as they become modules -->
- <fileset dir="${build-quick.dir}/classes/scaladoc"/>
- <fileset dir="${build-quick.dir}/classes/interactive"/>
- <fileset dir="${build-quick.dir}/classes/repl"/>
- </path>
- <fileset id="pack.compiler.include-jars" refid="asm.fileset"/>
- <property name="pack.compiler.include-jars.defined" value="yeah"/>
-
- <!-- TODO modularize compiler.
- <path id="pack.scaladoc.files"> <fileset dir="${build-quick.dir}/classes/scaladoc"/> </path>
- <path id="pack.interactive.files"><fileset dir="${build-quick.dir}/classes/interactive"/> </path>
- -->
-
- <path id="pack.reflect.files"> <fileset dir="${build-quick.dir}/classes/reflect"/> </path>
- <path id="pack.scalap.files"> <fileset dir="${build-quick.dir}/classes/scalap"/> </path>
-
- <path id="pack.partest-extras.files"> <fileset dir="${build-quick.dir}/classes/partest-extras"/> </path>
- <path id="pack.partest-javaagent.files"> <fileset dir="${build-quick.dir}/classes/partest-javaagent"/> </path>
-
- <!-- STRAP -->
- <path id="strap.library.build.path">
- <pathelement location="${build-strap.dir}/classes/library"/>
- <path refid="aux.libs"/>
- </path>
-
- <path id="strap.reflect.build.path">
- <path refid="strap.library.build.path"/>
- <pathelement location="${build-strap.dir}/classes/reflect"/>
- </path>
-
- <path id="strap.compiler.build.path">
- <path refid="strap.reflect.build.path"/>
- <pathelement location="${build-strap.dir}/classes/compiler"/>
- <path refid="asm.classpath"/>
- </path>
-
- <!-- DOCS -->
- <path id="docs.library.build.path"> <path refid="quick.library.build.path"/> </path>
- <path id="docs.reflect.build.path"> <path refid="quick.reflect.build.path"/> </path>
- <path id="docs.compiler.build.path"> <path refid="quick.compiler.build.path"/> </path>
- <path id="docs.scaladoc.build.path"> <path refid="quick.scaladoc.build.path"/> </path>
- <path id="docs.interactive.build.path"> <path refid="quick.interactive.build.path"/> </path>
- <path id="docs.scalap.build.path"> <path refid="quick.scalap.build.path"/> </path>
-
- <!-- run-time classpath for scaladoc TODO: resolve through maven -->
- <path id="scaladoc.classpath">
- <path refid="external-modules-nocore"/>
- <pathelement location="${library.jar}"/>
- <pathelement location="${reflect.jar}"/>
- <pathelement location="${compiler.jar}"/>
-
- <!-- TODO modularize compiler
- <pathelement location="${interactive.jar}"/>
- <pathelement location="${scaladoc.jar}"/>
- -->
-
- <pathelement location="${ant.jar}"/>
- <path refid="aux.libs"/>
- </path>
-
- <path id="manual.build.path">
- <path refid="external-modules-nocore"/> <!-- xml -->
- <pathelement location="${library.jar}"/>
- <pathelement location="${build.dir}/manmaker/classes"/>
- <path refid="aux.libs"/> <!-- for ant -->
- </path>
-
- <!-- MISC -->
- <path id="sbt.compile.build.path">
- <path refid="scaladoc.classpath"/>
- <!-- TODO modularize compiler: bring back when repl leaves compiler jar
- <pathelement location="${build-quick.dir}/classes/repl"/>
- -->
- <pathelement location="${sbt.interface.jar}"/>
- </path>
-
-
- <!--
- This is the classpath used to run partest, which is what it uses to run the compiler and find other required jars.
- "What's on the compiler's compilation path when compiling partest tests," you ask?
- Why, the compiler we're testing, of course, and partest with all its dependencies.
- -->
- <path id="partest.compilation.path">
- <path refid="partest.compilation.path.core"/>
- <path refid="partest.compilation.path.noncore"/>
- </path>
- <path id="partest.compilation.path.core">
- <pathelement location="${library.jar}"/>
- <pathelement location="${reflect.jar}"/>
- <pathelement location="${compiler.jar}"/>
- </path>
- <path id="partest.compilation.path.noncore">
-
- <!-- TODO modularize compiler
- <pathelement location="${scaladoc.jar}"/>
- <pathelement location="${interactive.jar}"/>
- -->
-
- <!-- TODO: move scalap out of repo -->
- <pathelement location="${scalap.jar}"/>
-
- <!-- partest's dependencies, which marks most of its dependencies as provided,
- (but not scala-library, so we filter that one out...)
- so we provide them: scala-[library/reflect/compiler], scalap built here,
- scala-xml via external-modules-nocore, as part of `partest.classpath` -->
- <restrict>
- <path refid="partest.classpath"/>
- <rsel:not><rsel:or>
- <rsel:name name="scala-library*.jar"/>
- </rsel:or></rsel:not>
- </restrict>
- <pathelement location="${scala-xml}"/>
- <!-- <pathelement location="${scala-swing}"/> -->
-
- <!-- partest classes specific to the core compiler build -->
- <pathelement location="${partest-extras.jar}"/>
- <pathelement location="${partest-javaagent.jar}"/>
-
- <!-- sneaky extras used in tests -->
- <fileset dir="${partest.dir}/files/lib" includes="*.jar" />
- </path>
-
- <path id="test.junit.compiler.build.path">
- <pathelement location="${test.junit.classes}"/>
- <path refid="quick.compiler.build.path"/>
- <path refid="quick.repl.build.path"/>
- <path refid="quick.scaladoc.build.path"/>
- <path refid="quick.partest-extras.build.path"/>
- <path refid="junit.classpath"/>
- </path>
-
- <path id="test.osgi.compiler.build.path">
- <pathelement location="${test.osgi.classes}"/>
- <pathelement location="${build-osgi.dir}/org.scala-lang.scala-library.jar"/>
- <pathelement location="${build-osgi.dir}/org.scala-lang.scala-reflect.jar"/>
- <pathelement location="${build-osgi.dir}/org.scala-lang.scala-compiler.jar"/>
- <path refid="pax.exam.classpath"/>
- </path>
-
- <path id="test.osgi.compiler.build.path.felix">
- <path refid="test.osgi.compiler.build.path"/>
- <path refid="osgi.framework.felix"/>
- </path>
-
- <path id="test.osgi.compiler.build.path.equinox">
- <path refid="test.osgi.compiler.build.path"/>
- <path refid="osgi.framework.equinox"/>
- </path>
-
- <path id="test.positions.sub.build.path" path="${build-quick.dir}/classes/library"/>
-
- <!-- TODO: consolidate *.includes -->
- <patternset id="lib.includes">
- <include name="**/*.tmpl"/>
- <include name="**/*.xml"/>
- <include name="**/*.js"/>
- <include name="**/*.css"/>
- </patternset>
-
- <patternset id="lib.rootdoc.includes">
- <include name="**/*.tmpl"/>
- <include name="**/*.xml"/>
- <include name="**/*.js"/>
- <include name="**/*.css"/>
- <include name="rootdoc.txt"/>
- </patternset>
-
- <patternset id="comp.includes">
- <include name="**/*.tmpl"/>
- <include name="**/*.xml"/>
- <include name="**/*.js"/>
- <include name="**/*.css"/>
- <include name="**/*.html"/>
- <include name="**/*.properties"/>
- <include name="**/*.swf"/>
- <include name="**/*.png"/>
- <include name="**/*.gif"/>
- <include name="**/*.txt"/>
- <include name="**/*.eot"/>
- <include name="**/*.ttf"/>
- <include name="**/*.woff"/>
- <include name="**/*.svg"/>
- </patternset>
-
- <taskdef resource="scala/tools/ant/sabbus/antlib.xml" classpathref="starr.compiler.path"/>
- <taskdef name="jarjar" classname="org.pantsbuild.jarjar.JarJarTask" classpathref="jarjar.classpath" />
- </target>
-
-<!-- ===========================================================================
- CLEANLINESS
-=============================================================================-->
- <target name="libs.clean"> <clean build="libs"/> </target>
- <target name="quick.clean" depends="libs.clean"> <clean build="quick"/> <clean build="pack"/> <clean build="strap"/> </target>
- <target name="locker.clean" depends="quick.clean"> <clean build="locker"/> </target>
-
- <target name="docs.clean"> <clean build="docs"/> <delete dir="${build.dir}/manmaker" includeemptydirs="yes" quiet="yes" failonerror="no"/> </target>
- <target name="dist.clean"> <delete dir="${dists.dir}" includeemptydirs="yes" quiet="yes" failonerror="no"/> </target>
-
- <target name="junit.clean"> <clean build="junit"/> </target>
-
- <target name="all.clean" depends="locker.clean, docs.clean, junit.clean">
- <clean build="sbt"/> <clean build="osgi"/>
- </target>
-
- <!-- Used by the scala-installer script -->
- <target name="allallclean" depends="all.clean, dist.clean"/>
-
-<!-- ===========================================================================
- LOCAL DEPENDENCIES
-============================================================================ -->
-
- <!-- For local development only. We only allow released versions of Scala for STARR.
- This builds quick (core only) and publishes it with a generated version number,
- saving it as starr.version in build.properties, so this compiler will be used as STARR in your next build
- NOTES:
- - to speed things up, you can also pass -Dlocker.skip=1
- -->
- <target name="replacestarr" depends="init.git" description="Produces a new STARR from current sources. Publishes core locally with a generated version number,
- stored in build.properties as starr.version (overriding the one in versions.properties).">
- <antcall target="publish-core-local">
- <param name="maven.version.suffix" value="-STARR-${git.commit.sha}-SNAPSHOT"/>
- <param name="docs.skip" value="1"/>
- <param name="scalac.args.optimise" value="-opt:l:classpath"/>
- <param name="update.starr.version" value="alright then"/>
- </antcall>
- </target>
-
-
-<!-- ===========================================================================
- LOCAL REFERENCE BUILD (LOCKER)
-============================================================================ -->
- <target name="locker.start" depends="init">
- <condition property="locker.locked"><available file="${build-locker.dir}/locker.locked"/></condition></target>
-
- <target name="locker.lib" depends="locker.start" unless="locker.locked">
- <!-- "mixed" needed for JFunction classes in scala.runtime.java8 -->
- <staged-build with="starr" stage="locker" project="library" srcpath="${src.dir}/library" includes="lib.includes" mixed="true"/></target>
-
- <target name="locker.reflect" depends="locker.lib" unless="locker.locked">
- <staged-build with="starr" stage="locker" project="reflect"/></target>
-
- <target name="locker.comp" depends="locker.reflect" unless="locker.locked">
- <staged-build with="starr" stage="locker" project="compiler"/></target>
-
- <target name="locker.done" depends="locker.comp">
- <mkdir dir="${build-locker.dir}"/>
- <touch file="${build-locker.dir}/locker.locked" verbose="no"/>
- </target>
- <target name="locker.unlock"> <delete file="${build-locker.dir}/locker.locked"/>
- <delete file="${build-locker.dir}/*.complete"/></target>
-
-<!-- ===========================================================================
- QUICK BUILD (QUICK)
-============================================================================ -->
- <target name="quick.start" depends="locker.done"/>
-
- <target name="quick.lib" depends="quick.start">
- <!-- "mixed" needed for JFunction classes in scala.runtime.java8 -->
- <staged-build with="locker" stage="quick" project="library" srcpath="${src.dir}/library" includes="lib.rootdoc.includes" mixed="true"/></target>
-
- <target name="quick.reflect" depends="quick.lib">
- <staged-build with="locker" stage="quick" project="reflect"/> </target>
-
- <target name="quick.comp" depends="quick.reflect">
- <staged-build with="locker" stage="quick" project="compiler"/> </target>
-
- <target name="quick.repl" depends="quick.comp, quick.interactive">
- <staged-build with="locker" stage="quick" project="repl"/>
- <staged-build with="locker" stage="quick" project="repl-jline"/>
-
- <staged-pack project="repl-jline"/>
-
- <!-- make jline_embedded jar with classes of repl-jline and jline, then shade-->
- <jarjar jarfile="${build-pack.dir}/${repl-jline.targetdir}/scala-repl-jline-embedded.jar" whenmanifestonly="fail">
- <zipfileset src="${jline:jline:jar}"/>
- <zipfileset src="${build-pack.dir}/${repl-jline.targetdir}/${repl-jline.targetjar}"/>
-
- <rule pattern="org.fusesource.**" result="scala.tools.fusesource_embedded.@1"/>
- <rule pattern="jline.**" result="scala.tools.jline_embedded.@1"/>
- <rule pattern="scala.tools.nsc.interpreter.jline.**" result="scala.tools.nsc.interpreter.jline_embedded.@1"/>
- <keep pattern="scala.tools.**"/>
- </jarjar>
-
- <!-- unzip jar to repl's class dir to obtain
- - standard repl-jline
- - a shaded repl-jline (scala/tools/nsc/interpreter/jline_embedded) & jline (scala.tools.jline_embedded)
- -->
- <copy todir="${build-quick.dir}/classes/repl">
- <zipfileset src="${build-pack.dir}/${repl-jline.targetdir}/${repl-jline.targetjar}"/>
- <zipfileset src="${build-pack.dir}/${repl-jline.targetdir}/scala-repl-jline-embedded.jar"/>
- </copy>
- </target>
-
- <target name="quick.scaladoc" depends="quick.comp">
- <staged-build with="locker" stage="quick" project="scaladoc"/> </target>
-
- <target name="quick.interactive" depends="quick.comp, quick.scaladoc">
- <staged-build with="locker" stage="quick" project="interactive"/> </target>
-
- <target name="quick.scalap" depends="quick.repl">
- <staged-build with="locker" stage="quick" project="scalap"/> </target>
-
-
-
- <target name="quick.modules" depends="quick.repl, quick.scaladoc, quick.interactive, quick.scalap"/>
-
- <target name="quick.bin" depends="quick.lib, quick.reflect, quick.comp, quick.modules">
- <staged-bin stage="quick" classpathref="quick.bin.tool.path"/>
- </target>
-
- <target name="quick.done" depends="quick.bin"/>
- <target name="quick-opt" description="Optimized version of quick.done."> <optimized name="quick.done"/></target>
-
-
-<!-- ===========================================================================
- PACKED QUICK BUILD (PACK)
-============================================================================ -->
- <target name="pack.lib" depends="quick.lib"> <staged-pack project="library"/>
- <taskdef resource="scala/tools/ant/antlib.xml" classpathref="pack.lib.path"/>
- <jarlister file="${library.jar}"/>
- </target>
-
- <target name="pack.reflect" depends="quick.reflect"> <staged-pack project="reflect"/> </target>
-
- <!-- TODO modularize compiler. Remove other quick targets when they become modules. -->
- <target name="pack.comp" depends="quick.comp, quick.scaladoc, quick.interactive, quick.repl">
- <staged-pack project="compiler" manifest="${build-pack.dir}/META-INF/MANIFEST.MF">
- <pre> <!-- TODO the files copied here do not influence actuality of this target (nor does the manifest) -->
- <copy todir="${build-pack.dir}/lib">
- <resources refid="repl.fileset"/>
- <mapper classpathref="maven-ant-tasks.classpath" classname="org.apache.maven.artifact.ant.VersionMapper" from="${repl.deps.versions}" to="flatten"/>
- </copy>
- <copy todir="${build-pack.dir}/lib">
- <fileset dir="${lib-extra.dir}">
- <include name="**/*.jar"/>
- </fileset>
- </copy>
- <mkdir dir="${build-pack.dir}/META-INF"/>
- <copy file="${basedir}/META-INF/MANIFEST.MF" toDir="${build-pack.dir}/META-INF"/>
- <manifest file="${build-pack.dir}/META-INF/MANIFEST.MF" mode="update">
- <attribute name="Bundle-Version" value="${version.number}"/>
- <attribute name="Class-Path" value="scala-reflect.jar scala-library.jar"/>
- </manifest>
- </pre>
- <!-- JSR-223 support introduced in 2.11 -->
- <jar-opts>
- <service type="javax.script.ScriptEngineFactory" provider="scala.tools.nsc.interpreter.Scripted$Factory"/>
- </jar-opts>
- </staged-pack>
- </target>
-
- <!-- TODO modularize compiler. These targets are currently not used.
- <target name="pack.scaladoc" depends="quick.scaladoc"> <staged-pack project="scaladoc"/> </target>
- <target name="pack.interactive" depends="quick.interactive"> <staged-pack project="interactive"/> </target>
- -->
-
- <target name="pack.scalap" depends="quick.scalap"> <staged-pack project="scalap"/> </target>
-
- <target name="pack.core" depends="pack.reflect, pack.comp, pack.lib"/>
-
- <!-- TODO modularize compiler: pack.scaladoc, pack.interactive, -->
- <target name="pack.modules" depends="pack.scalap">
- <copy todir="${build-pack.dir}/lib">
- <path refid="external-modules-nocore" />
- <mapper type="flatten" />
- </copy>
- </target>
-
- <!-- depends on pack.core for scaladoc -->
- <target name="scaladoc.task" depends="pack.core, pack.modules" unless="docs.skip">
- <taskdef resource="scala/tools/ant/antlib.xml" classpathref="scaladoc.classpath"/>
- </target>
-
- <target name="pack.partest-extras" depends="quick.comp">
- <!-- compile compiler-specific parts of partest -->
- <staged-build with="quick" stage="quick" project="partest-extras" />
- <staged-build with="quick" stage="quick" project="partest-javaagent" />
-
- <staged-pack project="partest-extras"/>
- <staged-pack project="partest-javaagent"
- manifest="${src.dir}/partest-javaagent/scala/tools/partest/javaagent/MANIFEST.MF"/>
- </target>
-
- <target name="pack.bin" depends="pack.core, pack.modules, pack.partest-extras">
- <staged-bin stage="pack"/>
- </target>
-
- <!-- depend on quick.done so quick.bin is run when pack.done is -->
- <target name="pack.done" depends="quick.done, pack.bin"/>
-
-
-<!-- ===========================================================================
- BOOTSTRAPPING BUILD (STRAP)
-============================================================================ -->
- <target name="strap.done" depends="pack.done">
- <!-- "mixed" needed for JFunction classes in scala.runtime.java8 -->
- <staged-build with="pack" stage="strap" project="library" srcpath="${src.dir}/library" includes="lib.rootdoc.includes" mixed="true"/>
- <staged-build with="pack" stage="strap" project="reflect"/>
- <staged-build with="pack" stage="strap" project="compiler"/>
- </target>
-
- <target name="strap-opt" description="Optimized version of strap.done."> <optimized name="strap.done"/></target>
-
-
-<!-- ===========================================================================
- OSGi Artifacts
-============================================================================ -->
- <!-- This task takes the output of the pack stage and OSGi-fies the jars based on the bnd files in src/build/bnd
- This means adding manifests and enforcing the Exports clauses (removing non-exported classes!)
- These jars are then copied to the distribution and published to maven.
- -->
-
-
- <target name="osgi.core" depends="pack.core">
- <mkdir dir="${build-osgi.dir}"/>
-
- <uptodate property="osgi.bundles.available" targetfile="${build-osgi.dir}/bundles.core.complete">
- <srcresources>
- <fileset dir="${basedir}">
- <include name="build.xml"/>
- <include name="build-ant-macros.xml"/>
- <include name="src/build/bnd/*.bnd"/>
- </fileset>
- <filelist>
- <file name="${library.jar}"/>
- <file name="${reflect.jar}"/>
- <file name="${compiler.jar}"/>
- </filelist>
- </srcresources>
- </uptodate>
-
- <if><not><isset property="osgi.bundles.available"/></not><then>
- <stopwatch name="osgi.core.timer"/>
- <make-bundle project="library">
- <fileset dir="${src.dir}/library"/>
- </make-bundle>
-
- <make-bundle project="reflect">
- <fileset dir="${src.dir}/reflect"/>
- </make-bundle>
-
- <!-- TODO modularize compiler. Remove the other class dirs as soon as they become modules -->
- <make-bundle project="compiler">
- <fileset dir="${src.dir}/compiler"/>
- <fileset dir="${src.dir}/scaladoc"/>
- <fileset dir="${src.dir}/interactive"/>
- <fileset dir="${src.dir}/repl"/>
- </make-bundle>
-
- <touch file="${build-osgi.dir}/bundles.core.complete" verbose="no"/>
- <stopwatch name="osgi.core.timer" action="total"/>
- </then></if>
- </target>
-
- <target name="osgi.done" depends="pack.done, osgi.core">
- <uptodate property="osgi.all.bundles.available" targetfile="${build-osgi.dir}/bundles.all.complete">
- <srcresources>
- <fileset dir="${basedir}">
- <include name="build.xml"/>
- <include name="build-ant-macros.xml"/>
- <include name="src/build/bnd/*.bnd"/>
- </fileset>
- <filelist>
- <!-- TODO modularize compiler
- <include name="${interactive.jar}"/>
- <include name="${scaladoc.jar}"/>
- -->
- <file name="${xml.jar}"/>
- <file name="${swing.jar}"/>
- </filelist>
- </srcresources>
- </uptodate>
-
- <if><not><isset property="osgi.all.bundles.available"/></not><then>
- <stopwatch name="osgi.all.timer"/>
-
- <!-- TODO modularize compiler
- TODO: refactor so that we can restrict exported packages to scala.tools.nsc.doc.*
- move ant task, partest stuff to other jars,
- and move scala.tools.nsc.ScalaDoc main class to scala.tools.nsc.doc
- <make-bundle project="scaladoc">
- <fileset dir="${src.dir}/scaladoc"/>
- </make-bundle>
-
- TODO: refactor so that we can restrict exported packages to scala.tools.nsc.interactive.*
- <make-bundle project="interactive">
- <fileset dir="${src.dir}/interactive"/>
- </make-bundle>
- -->
-
- <make-bundle project="parser-combinators"/>
- <make-bundle project="xml"/>
- <make-bundle project="swing"/>
-
- <touch file="${build-osgi.dir}/bundles.all.complete" verbose="no"/>
- <stopwatch name="osgi.all.timer" action="total"/>
- </then></if>
- </target>
-
-
-<!-- ===========================================================================
- TEST SUITE
-============================================================================ -->
- <!-- bootstrapping stability: compare {quick,strap}/(lib|reflect|comp) -->
- <target name="test.stability" depends="strap.done">
- <exec osfamily="unix" vmlauncher="false" executable="${basedir}/tools/stability-test.sh" failonerror="true" />
- <!-- I think doing it this way means it will auto-pass on windows... that's the idea. If not, something like this. -->
- <!-- <exec osfamily="windows" executable="foo" failonerror="false" failifexecutionfails="false" /> -->
- </target>
-
- <target name="test.stability-opt" description="Optimized version of test.stability."> <optimized name="test.stability"/></target>
-
- <target name="test.osgi.init" depends="osgi.done">
- <uptodate property="test.osgi.available" targetfile="${build-osgi.dir}/test-compile.complete">
- <srcfiles dir="${test.osgi.src}">
- <include name="**/*.scala"/>
- </srcfiles>
- </uptodate>
- </target>
-
- <target name="test.osgi.comp" depends="test.osgi.init, quick.done" unless="test.osgi.available">
- <stopwatch name="test.osgi.compiler.timer"/>
- <mkdir dir="${test.osgi.classes}"/>
- <scalacfork
- destdir="${test.osgi.classes}"
- compilerpathref="quick.compiler.path"
- params="${scalac.args.quick}"
- srcdir="${test.osgi.src}"
- jvmargs="${scalacfork.jvmargs}">
- <include name="**/*.scala"/>
- <compilationpath refid="test.osgi.compiler.build.path.felix"/>
- </scalacfork>
- <touch file="${build-osgi.dir}/test-compile.complete" verbose="no"/>
- <stopwatch name="test.osgi.compiler.timer" action="total"/>
- </target>
-
- <target name="test.osgi" depends="test.osgi.comp">
- <if><isset property="test.osgi.skip"/><then>
- <echo message="Skipping OSGi JUnit tests"/>
- </then><else>
- <echo message="Running OSGi JUnit tests. Output in ${build-osgi.dir}"/>
- <stopwatch name="test.osgi.timer"/>
- <mkdir dir="${test.osgi.classes}"/>
-
- <echo message="Test pass 1 of 2 using Apache Felix ${osgi.felix.version}"/>
- <junit fork="yes" haltonfailure="yes">
- <classpath refid="test.osgi.compiler.build.path.felix"/>
- <jvmarg value="-Duser.home=${user.home}"/>
- <batchtest fork="yes" todir="${build-osgi.dir}">
- <fileset dir="${test.osgi.classes}">
- <include name="**/*Test.class"/>
- </fileset>
- </batchtest>
- <formatter type="xml" />
- </junit>
-
- <echo message="Test pass 2 of 2 using Eclipse Equinox ${osgi.equinox.version}"/>
- <junit fork="yes" haltonfailure="yes">
- <classpath refid="test.osgi.compiler.build.path.equinox"/>
- <jvmarg value="-Duser.home=${user.home}"/>
- <batchtest fork="yes" todir="${build-osgi.dir}">
- <fileset dir="${test.osgi.classes}">
- <include name="**/*Test.class"/>
- </fileset>
- </batchtest>
- <formatter type="xml" /> <!-- silenced by having it use a file; I tried for an hour to use other formatters but classpath issues drove me to this usefile="false" -->
- </junit>
- <stopwatch name="test.osgi.timer" action="total"/>
- </else></if>
- </target>
-
-
-<!-- ===========================================================================
- SBT Compiler Interface
-============================================================================ -->
- <target name="test.sbt" depends="quick.done">
- <if><not><and>
- <available file="${sbt.interface.jar}"/>
- <available file="${sbt.interface.src.jar}"/></and></not>
- <then>
- <!-- Ensure directories exist -->
- <mkdir dir="${sbt.src.dir}"/>
- <mkdir dir="${sbt.lib.dir}"/>
-
- <get src="${sbt.interface.url}" dest="${sbt.interface.jar}"/>
- <get src="${sbt.interface.src.url}" dest="${sbt.interface.src.jar}"/>
-
- <!-- Explode sources -->
- <unzip src="${sbt.interface.src.jar}" dest="${sbt.src.dir}"/>
- </then></if>
-
- <stopwatch name="quick.sbt-interface.timer"/>
- <mkdir dir="${build-sbt.dir}/classes"/>
- <scalacfork
- destdir="${build-sbt.dir}/classes"
- compilerpathref="quick.compiler.path"
- params="${scalac.args.quick}"
- srcdir="${sbt.src.dir}"
- jvmargs="${scalacfork.jvmargs}">
- <include name="**/*.scala"/>
- <compilationpath refid="sbt.compile.build.path"/>
- </scalacfork>
- <touch file="${build-sbt.dir}/sbt-interface.complete" verbose="no"/>
- <stopwatch name="quick.sbt-interface.timer" action="total"/>
- </target>
-
- <target name="test.junit.comp" depends="pack.done">
- <stopwatch name="test.junit.compiler.timer"/>
- <mkdir dir="${test.junit.classes}"/>
- <javac
- debug="true"
- srcdir="${test.junit.src}"
- destdir="${test.junit.classes}"
- classpathref="test.junit.compiler.build.path"
- target="1.8"
- source="1.8"
- compiler="javac1.8"
- includes="**/*.java"/>
- <scalacfork
- destdir="${test.junit.classes}"
- compilerpathref="quick.compiler.path"
- params="${scalac.args.quick}"
- srcdir="${test.junit.src}"
- jvmargs="${scalacfork.jvmargs}">
- <include name="**/*.scala"/>
- <compilationpath refid="test.junit.compiler.build.path"/>
- </scalacfork>
- <touch file="${build-junit.dir}/test-compile.complete" verbose="no"/>
- <stopwatch name="test.junit.compiler.timer" action="total"/>
- </target>
-
- <target name="test.junit" depends="test.junit.comp">
- <stopwatch name="test.junit.timer"/>
- <mkdir dir="${test.junit.classes}"/>
- <echo message="Note: details of failed tests will be output to ${build-junit.dir}"/>
-
- <propertyfile file = "${test.junit.classes}/classpath.properties">
- <entry key = "test.junit.compiler.build.path" value="${toString:test.junit.compiler.build.path}"/>
- </propertyfile>
-
- <if><isset property="test.method" /><then><property name="test.methods" value="${test.method}" /></then></if>
- <junit fork="yes" haltonfailure="yes" printsummary="on">
- <classpath refid="test.junit.compiler.build.path"/>
- <test fork="yes" todir="${build-junit.dir}" if="test.class" unless="test.methods" name="${test.class}" />
- <test fork="yes" todir="${build-junit.dir}" if="test.methods" name="${test.class}" methods="${test.methods}" />
- <batchtest fork="yes" todir="${build-junit.dir}" unless="test.class">
- <fileset dir="${test.junit.classes}">
- <include name="**/*Test.class"/>
- </fileset>
- </batchtest>
- <formatter type="plain"/>
- </junit>
- <stopwatch name="test.junit.timer" action="total"/>
- </target>
-
- <!-- See test/build-partest.xml for the macro(s) being used here. -->
- <target name="partest.task" depends="pack.done">
- <!-- note the classpathref! this is the classpath used to run partest,
- so it must have the new compiler.... -->
- <taskdef
- classpathref="partest.compilation.path"
- resource="scala/tools/partest/antlib.xml"/>
- </target>
-
- <target name="test.suite.init" depends="partest.task">
- <!-- read by test/partest to determine classpath used to run partest -->
- <propertyfile file = "build/pack/partest.properties">
- <!-- TODO: change "partest.classpath" to "partest.runtime.classpath" or something -->
- <entry key = "partest.classpath" value="${toString:partest.compilation.path}"/>
- </propertyfile>
- </target>
-
- <target name="test.suite" depends="test.suite.init">
- <testSuite kinds="pos neg run jvm res scalap scalacheck specialized instrumented"/>
- </target>
-
- <target name="test.suite.color" depends="test.suite.init">
- <testSuite colors="8" kinds="pos neg run jvm res scalap scalacheck specialized instrumented"/>
- </target>
-
- <target name="test.suite.quick" depends="init, quick.done">
- <path id="test.suite.path">
- <path refid="quick.bin.tool.path"/>
- <path refid="quick.interactive.build.path"/>
- <path refid="partest.compilation.path.noncore"/>
- </path>
- <property name="pcp" value="${toString:test.suite.path}"/>
- <taskdef classpathref="test.suite.path" resource="scala/tools/partest/antlib.xml"/>
- <testSuite colors="8" kinds="pos neg run jvm res scalap scalacheck specialized instrumented" pcp="${pcp}"/>
- </target>
-
- <target name="test.run" depends="test.suite.init">
- <testSuite kinds="run jvm"/>
- </target>
-
- <target name="test.scaladoc" depends="test.suite.init">
- <testSuite kinds="run scalacheck" srcdir="scaladoc"/>
- </target>
-
- <target name="test.interactive" depends="test.suite.init">
- <testSuite kinds="presentation"/>
- </target>
-
- <!-- for use in PR validation, where stability is rarely broken, so we're going to use starr for locker,
- and skip test.stability (which requires locker == quick) -->
- <target name="test.core" depends="test.osgi, test.sbt, test.bc, test.junit, test.interactive, test.scaladoc, test.suite"/>
- <target name="test.done" depends="test.core, test.stability"/>
-
-<!-- ===========================================================================
- BINARY COMPATIBILITY TESTING
-============================================================================ -->
- <target name="bc.init" depends="init" if="test.bc.skip">
- <!-- if test.bc.skip is set, make sure that pc.prepare is not executed either -->
- <property name="maven-deps-done-mima" value="true"/>
- </target>
-
- <target name="bc.prepare" depends="bc.init" unless="maven-deps-done-mima">
- <property name="bc-reference-version" value="2.11.0"/>
-
- <property name="bc-build.dir" value="${build.dir}/bc"/>
- <!-- Obtain mima -->
- <mkdir dir="${bc-build.dir}"/>
- <!-- Pull down MIMA -->
- <artifact:dependencies pathId="mima.classpath">
- <dependency groupId="com.typesafe" artifactId="mima-reporter_2.10" version="0.1.8"/>
- </artifact:dependencies>
- <artifact:dependencies pathId="old.bc.classpath">
- <dependency groupId="org.scala-lang" artifactId="scala-library" version="${bc-reference-version}"/>
- <dependency groupId="org.scala-lang" artifactId="scala-reflect" version="${bc-reference-version}"/>
- </artifact:dependencies>
- <property name="maven-deps-done-mima" value="true"/>
- </target>
-
- <target name="test.bc-opt" description="Optimized version of test.bc."> <optimized name="test.bc"/></target>
- <target name="test.bc" depends="bc.prepare, pack.lib, pack.reflect" unless="test.bc.skip">
- <echo message="binary compatibility testing disabled in the 2.12.x branch"/>
- <!-- <bc.check project="library"/> -->
- <!-- <bc.check project="reflect"/> -->
- </target>
-
-<!-- ===========================================================================
- DOCUMENTATION
-============================================================================ -->
- <target name="docs.start" depends="scaladoc.task" unless="docs.skip">
- <!-- Set the github commit scaladoc sources point to -->
- <!-- For releases, look for the tag with the same name as the maven version -->
- <condition property="scaladoc.git.commit" value="v${maven.version.number}">
- <isset property="build.release"/>
- </condition>
- <!-- For snapshots, if we know the commit, point scaladoc to that particular commit instead of master -->
- <condition property="scaladoc.git.commit" value="${git.commit.sha}">
- <not><equals arg1="${git.commit.sha}" arg2="unknown"/></not>
- </condition>
- <!-- Fallback: point scaladoc to master -->
- <property name="scaladoc.git.commit" value="master"/>
- <!-- Compute the URL and show it -->
- <property name="scaladoc.url" value="https://github.com/scala/scala/tree/${scaladoc.git.commit}/src"/>
- <echo message="Scaladoc will point to ${scaladoc.url} for source files."/>
-
- <!-- Unless set with -Dscaladoc.<...>, these won't be activated -->
- <property name="scaladoc.raw.output" value="no"/>
- <property name="scaladoc.no.prefixes" value="no"/>
- </target>
-
- <target name="docs.lib" depends="docs.start" unless="docs.skip">
- <staged-docs project="library">
- <include name="**/*.scala"/>
- <exclude name="**/runtime/*$.scala"/>
- <exclude name="**/runtime/ScalaRunTime.scala"/>
- <exclude name="**/runtime/StringAdd.scala"/>
- </staged-docs>
- </target>
-
- <target name="docs.reflect" depends="docs.start" unless="docs.skip">
- <staged-docs project="reflect">
- <include name="**/*.scala"/>
- </staged-docs>
- </target>
-
- <target name="docs.comp" depends="docs.start" unless="docs.skip">
- <staged-docs project="compiler">
- <include name="**/*.scala"/>
- </staged-docs>
- </target>
-
- <!-- TODO modularize compiler. These targets are currently not used.
- <target name="docs.scaladoc" depends="docs.start" unless="docs.skip">
- <staged-docs project="scaladoc">
- <include name="**/*.scala"/>
- </staged-docs>
- </target>
-
- <target name="docs.interactive" depends="docs.start" unless="docs.skip">
- <staged-docs project="interactive">
- <include name="**/*.scala"/>
- </staged-docs>
- </target>
- -->
-
- <target name="docs.scalap" depends="docs.start" unless="docs.skip">
- <staged-docs project="scalap">
- <include name="**/*.scala"/>
- </staged-docs>
- </target>
-
- <target name="docs.core" depends="docs.lib, docs.reflect, docs.comp" unless="docs.skip"/>
- <!-- TODO modularize compiler: docs.scaladoc, docs.interactive, -->
- <target name="docs.done" depends="docs.core, docs.scalap" unless="docs.skip"/>
-
- <!-- doc/ and man/ -->
- <target name="pack.doc" depends="scaladoc.task" unless="docs.skip"> <!-- depends on scaladoc.task for scalac taskdef -->
- <mkdir dir="${build-pack.dir}/doc"/>
- <copy toDir="${build-pack.dir}/doc" overwrite="true">
- <fileset dir="${doc.dir}"/>
- </copy>
-
- <mkdir dir="${build-pack.dir}/doc/tools"/>
- <mkdir dir="${build-pack.dir}/man/man1"/>
- <staged-uptodate stage="manual" project="manual">
- <check><srcfiles dir="${src.dir}/manual"/></check>
- <do>
- <mkdir dir="${build.dir}/manmaker/classes"/>
- <scalac
- destdir="${build.dir}/manmaker/classes"
- classpathref="manual.build.path"
- srcdir="${src.dir}/manual"
- includes="**/*.scala"
- addparams="${scalac.args.all} -language:implicitConversions"/>
- <mkdir dir="${build-manual.dir}/genman/man1"/>
- <taskdef name="genman"
- classname="scala.tools.docutil.ManMaker"
- classpathref="manual.build.path"/>
- <genman command="fsc, scala, scalac, scaladoc, scalap"
- htmlout="${build-pack.dir}/doc/tools"
- manout="${build-manual.dir}/genman"/>
- </do>
- </staged-uptodate>
-
- <!-- On Windows source and target files can't be the same ! -->
- <fixcrlf
- srcdir="${build-manual.dir}/genman"
- destdir="${build-pack.dir}/man"
- eol="unix" includes="**/*.1"/>
- <copy todir="${build-pack.dir}/doc/tools" overwrite="true">
- <fileset dir="${src.dir}/manual/scala/tools/docutil/resources">
- <include name="**/*.html"/>
- <include name="**/*.css"/>
- <include name="**/*.gif"/>
- <include name="**/*.png"/>
- <include name="**/*.eot"/>
- <include name="**/*.ttf"/>
- <include name="**/*.woff"/>
- <include name="**/*.svg"/>
- </fileset>
- </copy>
- </target>
-
-<!-- ===========================================================================
-MAIN DISTRIBUTION PACKAGING
-============================================================================ -->
- <target name="pack-maven.core" depends="osgi.core, docs.core">
- <property name="dist.maven" value="${dists.dir}/maven/${version.number}"/>
- <mkdir dir="${dist.maven}"/>
-
- <mvn-package project="library"/>
- <mvn-package project="reflect"/>
- <mvn-package project="compiler"/>
-
- <copy tofile="${dist.maven}/scala-library-all/scala-library-all-pom.xml"
- file="${src.dir}/build/maven/scala-library-all-pom.xml" overwrite="true"/>
-
- <!-- for replacestarr -->
- <if><isset property="update.starr.version"/><then>
- <echo message="From now on, ${maven.version.number} will be used as STARR (`build.properties`'s `starr.version` was modified)."/>
- <propertyfile file = "build.properties">
- <entry key = "starr.version" value="${maven.version.number}"/>
- </propertyfile>
- </then></if>
- </target>
-
- <target name="pack-maven.done" depends="pack-maven.core, osgi.done, docs.done, pack.bin, pack.doc">
- <!-- TODO modularize compiler
- <mvn-package project="interactive"/>
- <mvn-package project="scaladoc"/>
- -->
-
- <!-- don't bother fitting scalap into the mould: it will move out soon -->
- <copy tofile="${dist.maven}/scalap/scalap-pom.xml" file="${src.dir}/build/maven/scalap-pom.xml" overwrite="true"/>
- <copy tofile="${dist.maven}/scalap/scalap.jar" file="${scalap.jar}" overwrite="true"/>
- <jar destfile="${dist.maven}/scalap/scalap-src.jar" basedir="${src.dir}/scalap" whenmanifestonly="fail"/>
- <if><not><isset property="docs.skip"/></not><then>
- <jar destfile="${dist.maven}/scalap/scalap-docs.jar" basedir="${build-docs.dir}/scalap"/>
- </then></if>
-
- <copy tofile="${dist.maven}/scala-dist/scala-dist-pom.xml" file="${src.dir}/build/maven/scala-dist-pom.xml" overwrite="true"/>
- <jar whenmanifestonly="fail" destfile="${dist.maven}/scala-dist/scala-dist.jar" basedir="${build-pack.dir}">
- <include name="bin/" />
- <include name="doc/" />
- <include name="man/" />
- </jar>
- </target>
-
-<!-- ===========================================================================
- MAVEN PUBLISHING
-============================================================================ -->
- <target name="init.maven" depends="init">
- <property name="remote.snapshot.repository" value="https://oss.sonatype.org/content/repositories/snapshots" />
- <property name="remote.release.repository" value="https://oss.sonatype.org/service/local/staging/deploy/maven2" />
-
- <property name="local.snapshot.repository" value="${user.home}/.m2/repository" />
- <property name="local.release.repository" value="${user.home}/.m2/repository" />
-
- <property name="repository.credentials.id" value="sonatype-nexus" />
- <property name="settings.file" value="${user.home}/.m2/settings.xml" />
-
- <if><contains string="${maven.version.number}" substring="-SNAPSHOT"/><then>
- <property name="remote.repository" value="${remote.snapshot.repository}"/>
- <property name="local.repository" value="${local.snapshot.repository}"/>
- </then><else>
- <property name="remote.repository" value="${remote.release.repository}"/>
- <property name="local.repository" value="${local.release.repository}"/>
- </else></if>
- </target>
-
- <target name="publish" depends="pack-maven.done, init.maven" description="Publishes unsigned artifacts to the maven repo.">
- <deploy />
- <deploy-pom name="scala-library-all"/>
- <deploy-jar name="scala-dist"/>
- </target>
-
- <target name="publish.local" depends="pack-maven.done, init.maven" description="Publishes unsigned artifacts to the local maven repo.">
- <deploy local="true"/>
- <deploy-pom name="scala-library-all" local="true"/>
- <deploy-jar name="scala-dist" local="true"/>
- </target>
-
- <target name="publish.signed" depends="pack-maven.done, init.maven" description="Publishes signed artifacts to the remote maven repo.">
- <deploy signed="true"/>
- <deploy-pom name="scala-library-all" signed="true"/>
- <deploy-jar name="scala-dist" signed="true"/>
- </target>
-
- <target name="publish-core" depends="pack-maven.core, init.maven">
- <deploy-one name="scala-compiler" />
- <deploy-one name="scala-library" />
- <deploy-one name="scala-reflect" />
- </target>
-
- <target name="publish-core-local" depends="pack-maven.core, init.maven">
- <deploy-one name="scala-compiler" local="true"/>
- <deploy-one name="scala-library" local="true"/>
- <deploy-one name="scala-reflect" local="true"/>
- </target>
-
- <target name="publish-core-opt" description="Builds an untested optimised core (library/reflect/compiler) and publishes to maven.">
- <optimized name="publish-core"/>
- </target>
-
-<!-- ===========================================================================
- VISUALIZATION
-============================================================================ -->
-
- <target name="graph.init">
- <taskdef name="vizant" classname="vizant.Vizant" classpath="${lib-ant.dir}/vizant.jar"/>
- </target>
-
- <target name="graph.all" depends="graph.init">
- <vizant antfile="${ant.file}" outfile="${ant.project.name}.dot" from="all.done"/>
- </target>
-
- <target name="graph.sabbus" depends="graph.init">
- <vizant antfile="${ant.file}" outfile="${ant.project.name}.dot"/>
- </target>
-</project>
diff --git a/compare-build-dirs-ignore-patterns b/compare-build-dirs-ignore-patterns
deleted file mode 100644
index 8c8160ba15..0000000000
--- a/compare-build-dirs-ignore-patterns
+++ /dev/null
@@ -1,8 +0,0 @@
-.DS_Store
-*.complete
-locker
-deps
-scala-continuations-*.jar
-scala-parser-combinators*.jar
-scala-swing*.jar
-scala-xml*.jar
diff --git a/compare-build-dirs.sh b/compare-build-dirs.sh
deleted file mode 100755
index f6806dd422..0000000000
--- a/compare-build-dirs.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-# Compares build directories generated by Ant and sbt build definitions
-# This let's us to see how far are we from achieving perfect parity
-# between the builds
-
-diff -X compare-build-dirs-ignore-patterns -qr build/ build-sbt/
diff --git a/project/MiMa.scala b/project/MiMa.scala
index 66442fc725..6c6f5efd51 100644
--- a/project/MiMa.scala
+++ b/project/MiMa.scala
@@ -4,7 +4,7 @@
// both forwards and backwards incompatibilities (possibly fixed as of
// https://github.com/typesafehub/migration-manager/commit/2844ffa48b6d2255aa64bd687703aec21dadd55e)
// * ability to pass a filter file (https://github.com/typesafehub/migration-manager/issues/102)
-// So we invoke the MiMa CLI directly; it's also what the Ant build did.
+// So we invoke the MiMa CLI directly.
import sbt._
import sbt.Keys._
@@ -29,8 +29,7 @@ object MiMa {
prev = if (isForward) curr else prev,
curr = if (isForward) prev else curr,
// TODO: it would be nicer if each subproject had its own whitelist, but for now
- // for compatibility with how Ant did things, there's just one at the root.
- // once Ant is gone we'd be free to split it up.
+ // there's just one at the root. with the Ant build gone, we would be free now to split it.
filter = (baseDirectory in ThisBuild).value / s"bincompat-$direction.whitelist.conf",
log)
}
diff --git a/project/Osgi.scala b/project/Osgi.scala
index 4177251aa4..8a62c9128a 100644
--- a/project/Osgi.scala
+++ b/project/Osgi.scala
@@ -9,9 +9,9 @@ import VersionUtil.versionProperties
/** OSGi packaging for the Scala build, distilled from sbt-osgi. We do not use sbt-osgi because it
* depends on a newer version of BND which gives slightly different output (probably OK to upgrade
- * in the future but for now it would make comparing the sbt and ant build output harder) and does
- * not allow a crucial bit of configuration that we need: Setting the classpath for BND. In sbt-osgi
- * this is always `fullClasspath in Compile` whereas we want `products in Compile in packageBin`. */
+ * in the future, now that the Ant build has been removed) and does not allow a crucial bit of
+ * configuration that we need: Setting the classpath for BND. In sbt-osgi this is always
+ * `fullClasspath in Compile` whereas we want `products in Compile in packageBin`. */
object Osgi {
val bundle = TaskKey[File]("osgiBundle", "Create an OSGi bundle.")
val bundleName = SettingKey[String]("osgiBundleName", "The Bundle-Name for the manifest.")
diff --git a/project/ScalaOptionParser.scala b/project/ScalaOptionParser.scala
index 77c9d765e9..af82f8fce5 100644
--- a/project/ScalaOptionParser.scala
+++ b/project/ScalaOptionParser.scala
@@ -94,7 +94,7 @@ object ScalaOptionParser {
private def stringSettingNames = List("-Xgenerate-phase-graph", "-Xmain-class", "-Xpluginsdir", "-Xshow-class", "-Xshow-object", "-Xsource-reader", "-Ydump-classes", "-Ygen-asmp",
"-Ypresentation-log", "-Ypresentation-replay", "-Yrepl-outdir", "-d", "-dependencyfile", "-encoding", "-Xscript")
private def pathSettingNames = List("-bootclasspath", "-classpath", "-extdirs", "-javabootclasspath", "-javaextdirs", "-sourcepath", "-toolcp")
- private val phases = List("all", "parser", "namer", "packageobjects", "typer", "patmat", "superaccessors", "extmethods", "pickler", "refchecks", "uncurry", "tailcalls", "specialize", "explicitouter", "erasure", "posterasure", "lazyvals", "lambdalift", "constructors", "flatten", "mixin", "cleanup", "delambdafy", "icode", "jvm", "terminal")
+ private val phases = List("all", "parser", "namer", "packageobjects", "typer", "patmat", "superaccessors", "extmethods", "pickler", "refchecks", "uncurry", "tailcalls", "specialize", "explicitouter", "erasure", "posterasure", "fields", "lambdalift", "constructors", "flatten", "mixin", "cleanup", "delambdafy", "icode", "jvm", "terminal")
private val phaseSettings = List("-Xprint-icode", "-Ystop-after", "-Yskip", "-Yshow", "-Ystop-before", "-Ybrowse", "-Ylog", "-Ycheck", "-Xprint")
private def multiStringSettingNames = List("-Xmacro-settings", "-Xplugin", "-Xplugin-disable", "-Xplugin-require")
private def intSettingNames = List("-Xmax-classfile-name", "-Xelide-below", "-Ypatmat-exhaust-depth", "-Ypresentation-delay", "-Yrecursion")
diff --git a/project/ScalaTool.scala b/project/ScalaTool.scala
index 5e3f20b1ba..98e18235c4 100644
--- a/project/ScalaTool.scala
+++ b/project/ScalaTool.scala
@@ -4,8 +4,6 @@ import org.apache.commons.lang3.StringUtils.replaceEach
/**
* A class that generates a shell or batch script to execute a Scala program.
- *
- * This is a simplified copy of Ant task (see scala.tools.ant.ScalaTool).
*/
case class ScalaTool(mainClass: String,
classpath: List[String],
diff --git a/project/build.sbt b/project/build.sbt
index b19238f577..a604896ded 100644
--- a/project/build.sbt
+++ b/project/build.sbt
@@ -1,2 +1,2 @@
-// Add genprod to the build; It should be moved from `src/build` to `project` once the ANT build is gone
+// Add genprod to the build; It should be moved from `src/build` to `project` now that the Ant build is gone
sources in Compile += ((baseDirectory).value.getParentFile / "src" / "build" / "genprod.scala")
diff --git a/pull-binary-libs.sh b/pull-binary-libs.sh
deleted file mode 100755
index 6c94e39fe7..0000000000
--- a/pull-binary-libs.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env bash
-#
-# Script to pull binary artifacts for scala from the remote repository.
-
-# Avoid corrupting the jar cache in ~/.sbt and the ugly crash when curl is not installed
-# This affects Linux systems mostly, because wget is the default download tool and curl
-# is not installed at all.
-curl --version &> /dev/null
-if [ $? -ne 0 ]
-then
- echo ""
- echo "Please install curl to download the jar files necessary for building Scala."
- echo ""
- exit 1
-fi
-
-. $(dirname $0)/tools/binary-repo-lib.sh
-
-# TODO - argument parsing...
-pullJarFiles $(pwd)
diff --git a/push-binary-libs.sh b/push-binary-libs.sh
deleted file mode 100755
index 0a1c62a1db..0000000000
--- a/push-binary-libs.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env bash
-#
-# Script to push binary artifacts for scala from the remote repository.
-
-. $(dirname $0)/tools/binary-repo-lib.sh
-
-if test $# -lt 2; then
- echo "Usage: $0 <username> <password>"
- exit 1
-fi
-
-# TODO - Argument parsing for username/password.
-pushJarFiles $(pwd) $1 $2
diff --git a/src/build/bnd/scala-compiler-doc.bnd b/src/build/bnd/scala-compiler-doc.bnd
deleted file mode 100644
index 5b662e8cef..0000000000
--- a/src/build/bnd/scala-compiler-doc.bnd
+++ /dev/null
@@ -1,8 +0,0 @@
-Bundle-Name: Scala Documentation Generator
-Bundle-SymbolicName: org.scala-lang.modules.scala-compiler-doc_@SCALA_BINARY_VERSION@
-ver: @SCALA_COMPILER_DOC_VERSION@
-Bundle-Version: ${ver}
-Export-Package: *;version=${ver}
-Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Include-Resource: @@SOURCE_JARNAME@
diff --git a/src/build/bnd/scala-compiler-interactive.bnd b/src/build/bnd/scala-compiler-interactive.bnd
deleted file mode 100644
index fbfff60801..0000000000
--- a/src/build/bnd/scala-compiler-interactive.bnd
+++ /dev/null
@@ -1,8 +0,0 @@
-Bundle-Name: Scala Interactive Compiler
-Bundle-SymbolicName: org.scala-lang.modules.scala-compiler-interactive_@SCALA_BINARY_VERSION@
-ver: @SCALA_COMPILER_INTERACTIVE_VERSION@
-Bundle-Version: ${ver}
-Export-Package: *;version=${ver}
-Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Include-Resource: @@SOURCE_JARNAME@
diff --git a/src/build/bnd/scala-compiler.bnd b/src/build/bnd/scala-compiler.bnd
deleted file mode 100644
index c12c84c3f9..0000000000
--- a/src/build/bnd/scala-compiler.bnd
+++ /dev/null
@@ -1,12 +0,0 @@
-Bundle-Name: Scala Compiler
-Bundle-SymbolicName: org.scala-lang.scala-compiler
-ver: @VERSION@
-Bundle-Version: ${ver}
-Export-Package: *;version=${ver}
-Import-Package: jline.*;resolution:=optional, \
- org.apache.tools.ant.*;resolution:=optional, \
- scala.xml.*;version="${range;[====,====];@XML_VERSION@}";resolution:=optional, \
- scala.*;version="${range;[==,=+);${ver}}", \
- *
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Include-Resource: @@SOURCE_JARNAME@
diff --git a/src/build/bnd/scala-library.bnd b/src/build/bnd/scala-library.bnd
deleted file mode 100644
index e211c5d1ad..0000000000
--- a/src/build/bnd/scala-library.bnd
+++ /dev/null
@@ -1,8 +0,0 @@
-Bundle-Name: Scala Standard Library
-Bundle-SymbolicName: org.scala-lang.scala-library
-ver: @VERSION@
-Bundle-Version: ${ver}
-Export-Package: *;version=${ver}
-Import-Package: sun.misc;resolution:=optional, *
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Include-Resource: @@SOURCE_JARNAME@
diff --git a/src/build/bnd/scala-parser-combinators.bnd b/src/build/bnd/scala-parser-combinators.bnd
deleted file mode 100644
index 515084f4a8..0000000000
--- a/src/build/bnd/scala-parser-combinators.bnd
+++ /dev/null
@@ -1,8 +0,0 @@
-Bundle-Name: Scala Parser Combinators Library
-Bundle-SymbolicName: org.scala-lang.modules.scala-parser-combinators
-ver: @PARSER_COMBINATORS_VERSION@
-Bundle-Version: ${ver}
-Export-Package: *;version=${ver}
-Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Include-Resource: @@SOURCE_JARNAME@
diff --git a/src/build/bnd/scala-reflect.bnd b/src/build/bnd/scala-reflect.bnd
deleted file mode 100644
index 59db311f8d..0000000000
--- a/src/build/bnd/scala-reflect.bnd
+++ /dev/null
@@ -1,10 +0,0 @@
-Bundle-Name: Scala Reflect
-Bundle-SymbolicName: org.scala-lang.scala-reflect
-ver: @VERSION@
-Bundle-Version: ${ver}
-Export-Package: *;version=${ver}
-Import-Package: scala.*;version="${range;[==,=+);${ver}}", \
- scala.tools.nsc;resolution:=optional;version="${range;[==,=+);${ver}}", \
- *
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Include-Resource: @@SOURCE_JARNAME@
diff --git a/src/build/bnd/scala-swing.bnd b/src/build/bnd/scala-swing.bnd
deleted file mode 100644
index 24cd9f6f90..0000000000
--- a/src/build/bnd/scala-swing.bnd
+++ /dev/null
@@ -1,8 +0,0 @@
-Bundle-Name: Scala Swing
-Bundle-SymbolicName: org.scala-lang.modules.scala-swing
-ver: @SCALA_SWING_VERSION@
-Bundle-Version: ${ver}
-Export-Package: *;version=${ver}
-Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Include-Resource: @@SOURCE_JARNAME@
diff --git a/src/build/bnd/scala-xml.bnd b/src/build/bnd/scala-xml.bnd
deleted file mode 100644
index b7b19824e8..0000000000
--- a/src/build/bnd/scala-xml.bnd
+++ /dev/null
@@ -1,8 +0,0 @@
-Bundle-Name: Scala XML Library
-Bundle-SymbolicName: org.scala-lang.modules.scala-xml
-ver: @XML_VERSION@
-Bundle-Version: ${ver}
-Export-Package: *;version=${ver}
-Import-Package: scala.*;version="${range;[==,=+);@VERSION@}",*
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Include-Resource: @@SOURCE_JARNAME@
diff --git a/src/build/maven/scala-compiler-doc-pom.xml b/src/build/maven/scala-compiler-doc-pom.xml
deleted file mode 100644
index 86ca3f865b..0000000000
--- a/src/build/maven/scala-compiler-doc-pom.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0"?>
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.scala-lang.modules</groupId>
- <artifactId>scala-compiler-doc_@SCALA_BINARY_VERSION@</artifactId>
- <packaging>jar</packaging>
- <version>@SCALA_COMPILER_DOC_VERSION@</version>
- <name>Scala Documentation Generator</name>
- <description>Documentation generator for the Scala Programming Language</description>
- <url>http://www.scala-lang.org/</url>
- <inceptionYear>2002</inceptionYear>
- <organization>
- <name>LAMP/EPFL</name>
- <url>http://lamp.epfl.ch/</url>
- </organization>
- <licenses>
- <license>
- <name>BSD 3-Clause</name>
- <url>http://www.scala-lang.org/license.html</url>
- <distribution>repo</distribution>
- </license>
- </licenses>
- <scm>
- <connection>scm:git:git://github.com/scala/scala.git</connection>
- <url>https://github.com/scala/scala.git</url>
- </scm>
- <issueManagement>
- <system>JIRA</system>
- <url>https://issues.scala-lang.org/</url>
- </issueManagement>
- <dependencies>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-compiler</artifactId>
- <version>@VERSION@</version>
- </dependency>
- <dependency>
- <groupId>org.scala-lang.modules</groupId>
- <artifactId>scala-xml_@SCALA_BINARY_VERSION@</artifactId>
- <version>@XML_VERSION@</version>
- </dependency>
- </dependencies>
- <developers>
- <developer>
- <id>lamp</id>
- <name>EPFL LAMP</name>
- </developer>
- <developer>
- <id>Lightbend</id>
- <name>Lightbend, Inc.</name>
- </developer>
- </developers>
-</project>
diff --git a/src/build/maven/scala-compiler-interactive-pom.xml b/src/build/maven/scala-compiler-interactive-pom.xml
deleted file mode 100644
index d3e5e0b834..0000000000
--- a/src/build/maven/scala-compiler-interactive-pom.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0"?>
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.scala-lang.modules</groupId>
- <artifactId>scala-compiler-interactive_@SCALA_BINARY_VERSION@</artifactId>
- <packaging>jar</packaging>
- <version>@SCALA_COMPILER_INTERACTIVE_VERSION@</version>
- <name>Scala Interactive Compiler</name>
- <description>Interactive Compiler for the Scala Programming Language</description>
- <url>http://www.scala-lang.org/</url>
- <inceptionYear>2002</inceptionYear>
- <organization>
- <name>LAMP/EPFL</name>
- <url>http://lamp.epfl.ch/</url>
- </organization>
- <licenses>
- <license>
- <name>BSD 3-Clause</name>
- <url>http://www.scala-lang.org/license.html</url>
- <distribution>repo</distribution>
- </license>
- </licenses>
- <scm>
- <connection>scm:git:git://github.com/scala/scala.git</connection>
- <url>https://github.com/scala/scala.git</url>
- </scm>
- <issueManagement>
- <system>JIRA</system>
- <url>https://issues.scala-lang.org/</url>
- </issueManagement>
- <dependencies>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-compiler</artifactId>
- <version>@VERSION@</version>
- </dependency>
- </dependencies>
- <developers>
- <developer>
- <id>lamp</id>
- <name>EPFL LAMP</name>
- </developer>
- <developer>
- <id>Lightbend</id>
- <name>Lightbend, Inc.</name>
- </developer>
- </developers>
-</project>
diff --git a/src/build/maven/scala-compiler-pom.xml b/src/build/maven/scala-compiler-pom.xml
deleted file mode 100644
index 9c157d17d9..0000000000
--- a/src/build/maven/scala-compiler-pom.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0"?>
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-compiler</artifactId>
- <packaging>jar</packaging>
- <version>@VERSION@</version>
- <name>Scala Compiler</name>
- <description>Compiler for the Scala Programming Language</description>
- <url>http://www.scala-lang.org/</url>
- <inceptionYear>2002</inceptionYear>
- <organization>
- <name>LAMP/EPFL</name>
- <url>http://lamp.epfl.ch/</url>
- </organization>
- <licenses>
- <license>
- <name>BSD 3-Clause</name>
- <url>http://www.scala-lang.org/license.html</url>
- <distribution>repo</distribution>
- </license>
- </licenses>
- <scm>
- <connection>scm:git:git://github.com/scala/scala.git</connection>
- <url>https://github.com/scala/scala.git</url>
- </scm>
- <issueManagement>
- <system>JIRA</system>
- <url>https://issues.scala-lang.org/</url>
- </issueManagement>
- <dependencies>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-library</artifactId>
- <version>@VERSION@</version>
- </dependency>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-reflect</artifactId>
- <version>@VERSION@</version>
- </dependency>
- <!-- TODO modularize compiler: these dependencies will disappear when the compiler is modularized -->
- <dependency> <!-- for scala-compiler-doc -->
- <groupId>org.scala-lang.modules</groupId>
- <artifactId>scala-xml_@SCALA_BINARY_VERSION@</artifactId>
- <version>@XML_VERSION@</version>
- </dependency>
- <dependency> <!-- for scala-compiler-repl; once it moves there, make it required -->
- <groupId>jline</groupId>
- <artifactId>jline</artifactId>
- <version>@JLINE_VERSION@</version>
- <optional>true</optional>
- </dependency>
- </dependencies>
- <developers>
- <developer>
- <id>lamp</id>
- <name>EPFL LAMP</name>
- </developer>
- <developer>
- <id>Lightbend</id>
- <name>Lightbend, Inc.</name>
- </developer>
- </developers>
-</project>
diff --git a/src/build/maven/scala-dist-pom.xml b/src/build/maven/scala-dist-pom.xml
deleted file mode 100644
index ce511661b0..0000000000
--- a/src/build/maven/scala-dist-pom.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0"?>
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-dist</artifactId>
- <packaging>jar</packaging>
- <version>@VERSION@</version>
- <name>Scala Distribution Artifacts</name>
- <description>The Artifacts Distributed with Scala</description>
- <url>http://www.scala-lang.org/</url>
- <inceptionYear>2002</inceptionYear>
- <organization>
- <name>LAMP/EPFL</name>
- <url>http://lamp.epfl.ch/</url>
- </organization>
- <licenses>
- <license>
- <name>BSD 3-Clause</name>
- <url>http://www.scala-lang.org/license.html</url>
- <distribution>repo</distribution>
- </license>
- </licenses>
- <scm>
- <connection>scm:git:git://github.com/scala/scala.git</connection>
- <url>https://github.com/scala/scala.git</url>
- </scm>
- <issueManagement>
- <system>JIRA</system>
- <url>https://issues.scala-lang.org/</url>
- </issueManagement>
- <dependencies>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-library-all</artifactId>
- <version>@VERSION@</version>
- </dependency>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-compiler</artifactId>
- <version>@VERSION@</version>
- </dependency>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scalap</artifactId>
- <version>@VERSION@</version>
- </dependency>
- <!-- duplicated from scala-compiler, where it's optional,
- so that resolving scala-dist's transitive dependencies does not include jline,
- even though we need to include it in the dist, but macros depending on the compiler
- shouldn't have to require jline...
- another reason to modularize and move the dependency to scala-compiler-repl
- TODO: remove duplication once we have the scala-compiler-repl module -->
- <dependency>
- <groupId>jline</groupId>
- <artifactId>jline</artifactId>
- <version>@JLINE_VERSION@</version>
- </dependency>
- </dependencies>
- <developers>
- <developer>
- <id>lamp</id>
- <name>EPFL LAMP</name>
- </developer>
- <developer>
- <id>Lightbend</id>
- <name>Lightbend, Inc.</name>
- </developer>
- </developers>
-</project>
diff --git a/src/build/maven/scala-library-all-pom.xml b/src/build/maven/scala-library-all-pom.xml
deleted file mode 100644
index 4620c620dc..0000000000
--- a/src/build/maven/scala-library-all-pom.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0"?>
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-library-all</artifactId>
- <packaging>pom</packaging>
- <version>@VERSION@</version>
- <name>Scala Library Powerpack</name>
- <description>The Scala Standard Library and Official Modules</description>
- <url>http://www.scala-lang.org/</url>
- <inceptionYear>2002</inceptionYear>
- <organization>
- <name>LAMP/EPFL</name>
- <url>http://lamp.epfl.ch/</url>
- </organization>
- <licenses>
- <license>
- <name>BSD 3-Clause</name>
- <url>http://www.scala-lang.org/license.html</url>
- <distribution>repo</distribution>
- </license>
- </licenses>
- <scm>
- <connection>scm:git:git://github.com/scala/scala.git</connection>
- <url>https://github.com/scala/scala.git</url>
- </scm>
- <issueManagement>
- <system>JIRA</system>
- <url>https://issues.scala-lang.org/</url>
- </issueManagement>
- <dependencies>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-library</artifactId>
- <version>@VERSION@</version>
- </dependency>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-reflect</artifactId>
- <version>@VERSION@</version>
- </dependency>
- <dependency>
- <groupId>org.scala-lang.modules</groupId>
- <artifactId>scala-xml_@SCALA_BINARY_VERSION@</artifactId>
- <version>@XML_VERSION@</version>
- </dependency>
- <dependency>
- <groupId>org.scala-lang.modules</groupId>
- <artifactId>scala-parser-combinators_@SCALA_BINARY_VERSION@</artifactId>
- <version>@PARSER_COMBINATORS_VERSION@</version>
- </dependency>
- <dependency>
- <groupId>org.scala-lang.modules</groupId>
- <artifactId>scala-swing_@SCALA_BINARY_VERSION@</artifactId>
- <version>@SCALA_SWING_VERSION@</version>
- </dependency>
- </dependencies>
- <developers>
- <developer>
- <id>lamp</id>
- <name>EPFL LAMP</name>
- </developer>
- <developer>
- <id>Lightbend</id>
- <name>Lightbend, Inc.</name>
- </developer>
- </developers>
-</project>
diff --git a/src/build/maven/scala-library-pom.xml b/src/build/maven/scala-library-pom.xml
deleted file mode 100644
index e27f8fb12f..0000000000
--- a/src/build/maven/scala-library-pom.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0"?>
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-library</artifactId>
- <packaging>jar</packaging>
- <version>@VERSION@</version>
- <name>Scala Library</name>
- <description>Standard library for the Scala Programming Language</description>
- <url>http://www.scala-lang.org/</url>
- <inceptionYear>2002</inceptionYear>
- <organization>
- <name>LAMP/EPFL</name>
- <url>http://lamp.epfl.ch/</url>
- </organization>
- <licenses>
- <license>
- <name>BSD 3-Clause</name>
- <url>http://www.scala-lang.org/license.html</url>
- <distribution>repo</distribution>
- </license>
- </licenses>
- <scm>
- <connection>scm:git:git://github.com/scala/scala.git</connection>
- <url>https://github.com/scala/scala.git</url>
- </scm>
- <issueManagement>
- <system>JIRA</system>
- <url>https://issues.scala-lang.org/</url>
- </issueManagement>
- <properties>
- <info.apiURL>http://www.scala-lang.org/api/@VERSION@/</info.apiURL>
- </properties>
- <dependencies>
- </dependencies>
- <developers>
- <developer>
- <id>lamp</id>
- <name>EPFL LAMP</name>
- </developer>
- <developer>
- <id>Lightbend</id>
- <name>Lightbend, Inc.</name>
- </developer>
- </developers>
-</project>
diff --git a/src/build/maven/scala-reflect-pom.xml b/src/build/maven/scala-reflect-pom.xml
deleted file mode 100644
index f7f3c8bc08..0000000000
--- a/src/build/maven/scala-reflect-pom.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0"?>
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-reflect</artifactId>
- <packaging>jar</packaging>
- <version>@VERSION@</version>
- <name>Scala Compiler</name>
- <description>Compiler for the Scala Programming Language</description>
- <url>http://www.scala-lang.org/</url>
- <inceptionYear>2002</inceptionYear>
- <organization>
- <name>LAMP/EPFL</name>
- <url>http://lamp.epfl.ch/</url>
- </organization>
- <licenses>
- <license>
- <name>BSD 3-Clause</name>
- <url>http://www.scala-lang.org/license.html</url>
- <distribution>repo</distribution>
- </license>
- </licenses>
- <scm>
- <connection>scm:git:git://github.com/scala/scala.git</connection>
- <url>https://github.com/scala/scala.git</url>
- </scm>
- <issueManagement>
- <system>JIRA</system>
- <url>https://issues.scala-lang.org/</url>
- </issueManagement>
- <properties>
- <info.apiURL>http://www.scala-lang.org/api/@VERSION@/</info.apiURL>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-library</artifactId>
- <version>@VERSION@</version>
- </dependency>
- </dependencies>
- <developers>
- <developer>
- <id>lamp</id>
- <name>EPFL LAMP</name>
- </developer>
- <developer>
- <id>Lightbend</id>
- <name>Lightbend, Inc.</name>
- </developer>
- </developers>
-</project>
diff --git a/src/build/maven/scalap-pom.xml b/src/build/maven/scalap-pom.xml
deleted file mode 100644
index acdd44f19b..0000000000
--- a/src/build/maven/scalap-pom.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0"?>
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.scala-lang</groupId>
- <artifactId>scalap</artifactId>
- <packaging>jar</packaging>
- <version>@VERSION@</version>
- <name>Scalap</name>
- <description>bytecode analysis tool</description>
- <url>http://www.scala-lang.org/</url>
- <inceptionYear>2002</inceptionYear>
- <organization>
- <name>LAMP/EPFL</name>
- <url>http://lamp.epfl.ch/</url>
- </organization>
- <licenses>
- <license>
- <name>BSD 3-Clause</name>
- <url>http://www.scala-lang.org/license.html</url>
- <distribution>repo</distribution>
- </license>
- </licenses>
- <scm>
- <connection>scm:git:git://github.com/scala/scala.git</connection>
- <url>https://github.com/scala/scala.git</url>
- </scm>
- <issueManagement>
- <system>JIRA</system>
- <url>https://issues.scala-lang.org/</url>
- </issueManagement>
- <dependencies>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-compiler</artifactId>
- <version>@VERSION@</version>
- </dependency>
- </dependencies>
- <developers>
- <developer>
- <id>lamp</id>
- <name>EPFL LAMP</name>
- </developer>
- <developer>
- <id>Lightbend</id>
- <name>Lightbend, Inc.</name>
- </developer>
- </developers>
-</project>
diff --git a/src/compiler/scala/reflect/reify/phases/Reshape.scala b/src/compiler/scala/reflect/reify/phases/Reshape.scala
index 091d42bb6d..581ce8256a 100644
--- a/src/compiler/scala/reflect/reify/phases/Reshape.scala
+++ b/src/compiler/scala/reflect/reify/phases/Reshape.scala
@@ -49,13 +49,13 @@ trait Reshape {
if (discard) hk else ta
case classDef @ ClassDef(mods, name, params, impl) =>
val Template(parents, self, body) = impl
- var body1 = trimAccessors(classDef, reshapeLazyVals(body))
+ var body1 = trimAccessors(classDef, body)
body1 = trimSyntheticCaseClassMembers(classDef, body1)
val impl1 = Template(parents, self, body1).copyAttrs(impl)
ClassDef(mods, name, params, impl1).copyAttrs(classDef)
case moduledef @ ModuleDef(mods, name, impl) =>
val Template(parents, self, body) = impl
- var body1 = trimAccessors(moduledef, reshapeLazyVals(body))
+ var body1 = trimAccessors(moduledef, body)
body1 = trimSyntheticCaseClassMembers(moduledef, body1)
val impl1 = Template(parents, self, body1).copyAttrs(impl)
ModuleDef(mods, name, impl1).copyAttrs(moduledef)
@@ -63,10 +63,10 @@ trait Reshape {
val discardedParents = parents collect { case tt: TypeTree => tt } filter isDiscarded
if (reifyDebug && discardedParents.length > 0) println("discarding parents in Template: " + discardedParents.mkString(", "))
val parents1 = parents diff discardedParents
- val body1 = reshapeLazyVals(trimSyntheticCaseClassCompanions(body))
+ val body1 = trimSyntheticCaseClassCompanions(body)
Template(parents1, self, body1).copyAttrs(template)
case block @ Block(stats, expr) =>
- val stats1 = reshapeLazyVals(trimSyntheticCaseClassCompanions(stats))
+ val stats1 = trimSyntheticCaseClassCompanions(stats)
Block(stats1, expr).copyAttrs(block)
case unapply @ UnApply(Unapplied(Select(fun, nme.unapply | nme.unapplySeq)), args) =>
if (reifyDebug) println("unapplying unapply: " + tree)
@@ -306,34 +306,6 @@ trait Reshape {
stats1
}
- private def reshapeLazyVals(stats: List[Tree]): List[Tree] = {
- val lazyvaldefs:Map[Symbol, DefDef] = stats.collect({ case ddef: DefDef if ddef.mods.isLazy => ddef }).
- map((ddef: DefDef) => ddef.symbol -> ddef).toMap
- // lazy valdef and defdef are in the same block.
- // only that valdef needs to have its rhs rebuilt from defdef
- stats flatMap (stat => stat match {
- case vdef: ValDef if vdef.symbol.isLazy =>
- if (reifyDebug) println(s"reconstructing original lazy value for $vdef")
- val ddefSym = vdef.symbol.lazyAccessor
- val vdef1 = lazyvaldefs.get(ddefSym) match {
- case Some(ddef) =>
- toPreTyperLazyVal(ddef)
- case None =>
- if (reifyDebug) println("couldn't find corresponding lazy val accessor")
- vdef
- }
- if (reifyDebug) println(s"reconstructed lazy val is $vdef1")
- vdef1::Nil
- case ddef: DefDef if ddef.symbol.isLazy =>
- if (isUnitType(ddef.symbol.info)) {
- // since lazy values of type Unit don't have val's
- // we need to create them from scratch
- toPreTyperLazyVal(ddef) :: Nil
- } else Nil
- case _ => stat::Nil
- })
- }
-
private def trimSyntheticCaseClassMembers(deff: Tree, stats: List[Tree]): List[Tree] =
stats filterNot (memberDef => memberDef.isDef && {
val isSynthetic = memberDef.symbol.isSynthetic
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index e9d1dfe4d2..511572f6f3 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -88,7 +88,7 @@ class Scalac extends ScalaMatchingTask with ScalacShared {
object CompilerPhase extends PermissibleValue {
val values = List("namer", "typer", "pickler", "refchecks",
"uncurry", "tailcalls", "specialize", "explicitouter",
- "erasure", "lazyvals", "lambdalift", "constructors",
+ "erasure", "fields", "lambdalift", "constructors",
"flatten", "mixin", "delambdafy", "cleanup",
"jvm", "terminal")
}
diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala
index 9b8e9fa330..3879d7b425 100644
--- a/src/compiler/scala/tools/nsc/CompilerCommand.scala
+++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala
@@ -107,7 +107,7 @@ class CompilerCommand(arguments: List[String], val settings: Settings) {
else {
val sb = new StringBuilder
allSettings foreach {
- case s: MultiChoiceSetting[_] if s.isHelping => sb append s.help
+ case s if s.isHelping => sb append s.help
case _ =>
}
sb.toString
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index af866e1a6f..32c446e16a 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -516,17 +516,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
val runsRightAfter = Some("erasure")
} with PostErasure
- // phaseName = "lazyvals"
- object lazyVals extends {
- val global: Global.this.type = Global.this
- val runsAfter = List("erasure")
- val runsRightAfter = None
- } with LazyVals
// phaseName = "lambdalift"
object lambdaLift extends {
val global: Global.this.type = Global.this
- val runsAfter = List("lazyvals")
+ val runsAfter = List("erasure")
val runsRightAfter = None
} with LambdaLift
@@ -620,13 +614,12 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
pickler -> "serialize symbol tables",
refChecks -> "reference/override checking, translate nested objects",
uncurry -> "uncurry, translate function values to anonymous classes",
- fields -> "synthesize accessors and fields",
+ fields -> "synthesize accessors and fields, including bitmaps for lazy vals",
tailCalls -> "replace tail calls by jumps",
specializeTypes -> "@specialized-driven class and method specialization",
explicitOuter -> "this refs to outer pointers",
erasure -> "erase types, add interfaces for traits",
postErasure -> "clean up erased inline classes",
- lazyVals -> "allocate bitmaps, translate lazy vals into lazified defs",
lambdaLift -> "move nested functions to top level",
constructors -> "move field definitions into constructors",
mixer -> "mixin composition",
@@ -1258,7 +1251,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
val explicitouterPhase = phaseNamed("explicitouter")
val erasurePhase = phaseNamed("erasure")
val posterasurePhase = phaseNamed("posterasure")
- // val lazyvalsPhase = phaseNamed("lazyvals")
val lambdaliftPhase = phaseNamed("lambdalift")
// val constructorsPhase = phaseNamed("constructors")
val flattenPhase = phaseNamed("flatten")
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 5dddf30c96..762456c9c9 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -91,7 +91,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
)
/** Make a synchronized block on 'monitor'. */
- def mkSynchronized(monitor: Tree, body: Tree): Tree =
+ def mkSynchronized(monitor: Tree)(body: Tree): Tree =
Apply(Select(monitor, Object_synchronized), List(body))
def mkAppliedTypeForCase(clazz: Symbol): Tree = {
@@ -233,26 +233,6 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
else Block(prefix, containing) setPos (prefix.head.pos union containing.pos)
}
- /** Return the synchronized part of the double-checked locking idiom around the syncBody tree. It guards with `cond` and
- * synchronizes on `clazz.this`. Additional statements can be included after initialization,
- * (outside the synchronized block).
- *
- * The idiom works only if the condition is using a volatile field.
- *
- * @see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
- */
- def mkSynchronizedCheck(clazz: Symbol, cond: Tree, syncBody: List[Tree], stats: List[Tree]): Tree =
- mkSynchronizedCheck(mkAttributedThis(clazz), cond, syncBody, stats)
-
- def mkSynchronizedCheck(attrThis: Tree, cond: Tree, syncBody: List[Tree], stats: List[Tree]): Tree = {
- def blockOrStat(stats: List[Tree]): Tree = stats match {
- case head :: Nil => head
- case _ => Block(stats : _*)
- }
- val sync = mkSynchronized(attrThis, If(cond, blockOrStat(syncBody), EmptyTree))
- blockOrStat(sync :: stats)
- }
-
/** Creates a tree representing new Object { stats }.
* To make sure an anonymous subclass of Object is created,
* if there are no stats, a () is added.
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
index 630b2b6c7f..1982c7f643 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
@@ -5,11 +5,15 @@
package scala.tools.nsc.backend.jvm
-import scala.tools.asm.tree.{InsnList, AbstractInsnNode, ClassNode, MethodNode}
-import java.io.{StringWriter, PrintWriter}
-import scala.tools.asm.util.{CheckClassAdapter, TraceClassVisitor, TraceMethodVisitor, Textifier}
-import scala.tools.asm.{ClassReader, ClassWriter, Attribute}
+import scala.tools.asm.tree.{AbstractInsnNode, ClassNode, FieldNode, InsnList, MethodNode}
+import java.io.{PrintWriter, StringWriter}
+import java.util
+
+import scala.tools.asm.util.{CheckClassAdapter, Textifier, TraceClassVisitor, TraceMethodVisitor}
+import scala.tools.asm.{Attribute, ClassReader, ClassWriter}
import scala.collection.JavaConverters._
+import scala.concurrent.duration.Duration
+import scala.concurrent.{Await, Future}
import scala.tools.nsc.backend.jvm.analysis.InitialProducer
import scala.tools.nsc.backend.jvm.opt.InlineInfoAttributePrototype
@@ -64,21 +68,37 @@ object AsmUtils {
bytes
}
- def textifyClassStably(bytes: Array[Byte]): Unit = {
+ def classFromBytes(bytes: Array[Byte]): ClassNode = {
val node = new ClassNode()
new ClassReader(bytes).accept(node, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES)
- node.fields = node.fields.asScala.sortBy(_.name).asJava
- node.methods = node.methods.asScala.sortBy(_.name).asJava
- node.visibleAnnotations = null
- node.attrs = null
- node.invisibleAnnotations = null
+ node
+ }
+
+// def main(args: Array[String]): Unit = println(textify(sortedClassRead(classBytes(args.head))))
+
+ def sortClassMembers(node: ClassNode): node.type = {
+ node.fields.sort(_.name compareTo _.name)
+ node.methods.sort(_.name compareTo _.name)
+ node
+ }
+
+ // drop ScalaSig annotation and class attributes
+ def zapScalaClassAttrs(node: ClassNode): node.type = {
+ if (node.visibleAnnotations != null)
+ node.visibleAnnotations = node.visibleAnnotations.asScala.filterNot(a => a == null || a.desc.contains("Lscala/reflect/ScalaSignature")).asJava
- println(textify(node))
+ node.attrs = null
+ node
}
- def main(args: Array[String]): Unit = {
- textifyClassStably(classBytes(args.head))
+ def main(args: Array[String]): Unit = args.par.foreach { classFileName =>
+ val node = zapScalaClassAttrs(sortClassMembers(classFromBytes(classBytes(classFileName))))
+
+ val pw = new PrintWriter(classFileName + ".asm")
+ val trace = new TraceClassVisitor(pw)
+ node.accept(trace)
+ pw.close()
}
/**
diff --git a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
index 8386722b63..9d643825f6 100644
--- a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
@@ -30,8 +30,8 @@ trait AbsScalaSettings {
type OutputSetting <: Setting
def BooleanSetting(name: String, descr: String): BooleanSetting
- def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String): ChoiceSetting
- def ChoiceSettingForcedDefault(name: String, helpArg: String, descr: String, choices: List[String], default: String): ChoiceSetting
+ def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String, choicesHelp: List[String] = Nil): ChoiceSetting
+ def ChoiceSettingForcedDefault(name: String, helpArg: String, descr: String, choices: List[String], default: String, choicesHelp: List[String] = Nil): ChoiceSetting
def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]): IntSetting
def MultiStringSetting(name: String, helpArg: String, descr: String): MultiStringSetting
def MultiChoiceSetting[E <: MultiChoiceEnumeration](name: String, helpArg: String, descr: String, domain: E, default: Option[List[String]]): MultiChoiceSetting[E]
diff --git a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala
index 060a24d8d4..08fa56d8e9 100644
--- a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala
@@ -88,6 +88,12 @@ trait AbsSettings extends scala.reflect.internal.settings.AbsSettings {
/** Issue error and return */
def errorAndValue[T](msg: String, x: T): T = { errorFn(msg) ; x }
+ /** If this method returns true, print the [[help]] message and exit. */
+ def isHelping: Boolean = false
+
+ /** The help message to be printed if [[isHelping]]. */
+ def help: String = ""
+
/** After correct Setting has been selected, tryToSet is called with the
* remainder of the command line. It consumes any applicable arguments and
* returns the unconsumed ones.
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
index 9cc8faf8c2..7b4c55c2af 100644
--- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
@@ -219,10 +219,10 @@ class MutableSettings(val errorFn: String => Unit)
}
def BooleanSetting(name: String, descr: String) = add(new BooleanSetting(name, descr))
- def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String) =
- add(new ChoiceSetting(name, helpArg, descr, choices, default))
- def ChoiceSettingForcedDefault(name: String, helpArg: String, descr: String, choices: List[String], default: String) =
- ChoiceSetting(name, helpArg, descr, choices, default).withPostSetHook(sett =>
+ def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String, choicesHelp: List[String]) =
+ add(new ChoiceSetting(name, helpArg, descr, choices, default, choicesHelp))
+ def ChoiceSettingForcedDefault(name: String, helpArg: String, descr: String, choices: List[String], default: String, choicesHelp: List[String]) =
+ ChoiceSetting(name, helpArg, descr, choices, default, choicesHelp).withPostSetHook(sett =>
if (sett.value != default) {
sett.withDeprecationMessage(s"${name}:${sett.value} is deprecated, forcing use of $default")
sett.value = default
@@ -627,7 +627,7 @@ class MutableSettings(val errorFn: String => Unit)
descr: String,
val domain: E,
val default: Option[List[String]]
- ) extends Setting(name, s"$descr: `_' for all, `$name:help' to list") with Clearable {
+ ) extends Setting(name, s"$descr: `_' for all, `$name:help' to list choices.") with Clearable {
withHelpSyntax(s"$name:<_,$helpArg,-$helpArg>")
@@ -748,9 +748,9 @@ class MutableSettings(val errorFn: String => Unit)
def contains(choice: domain.Value): Boolean = value contains choice
- def isHelping: Boolean = sawHelp
+ override def isHelping: Boolean = sawHelp
- def help: String = {
+ override def help: String = {
val choiceLength = choices.map(_.length).max + 1
val formatStr = s" %-${choiceLength}s %s"
choices.zipAll(descriptions, "", "").map {
@@ -808,18 +808,33 @@ class MutableSettings(val errorFn: String => Unit)
helpArg: String,
descr: String,
override val choices: List[String],
- val default: String)
- extends Setting(name, descr + choices.mkString(" (", ",", ") default:" + default)) {
+ val default: String,
+ val choicesHelp: List[String])
+ extends Setting(name,
+ if (choicesHelp.isEmpty) s"$descr Choices: ${choices.mkString("(", ",", ")")}, default: $default."
+ else s"$descr Default: `$default', `help' to list choices.") {
type T = String
protected var v: T = default
def indexOfChoice: Int = choices indexOf value
- private def usageErrorMessage = f"Usage: $name:<$helpArg>%n where <$helpArg> choices are ${choices mkString ", "} (default: $default)%n"
+ private def choicesHelpMessage = if (choicesHelp.isEmpty) "" else {
+ val choiceLength = choices.map(_.length).max + 1
+ val formatStr = s" %-${choiceLength}s %s%n"
+ choices.zipAll(choicesHelp, "", "").map({
+ case (choice, desc) => formatStr.format(choice, desc)
+ }).mkString("")
+ }
+ private def usageErrorMessage = f"Usage: $name:<$helpArg> where <$helpArg> choices are ${choices mkString ", "} (default: $default).%n$choicesHelpMessage"
+
+ private var sawHelp = false
+ override def isHelping = sawHelp
+ override def help = usageErrorMessage
def tryToSet(args: List[String]) = errorAndValue(usageErrorMessage, None)
override def tryToSetColon(args: List[String]) = args match {
case Nil => errorAndValue(usageErrorMessage, None)
+ case List("help") => sawHelp = true; Some(Nil)
case List(x) if choices contains x => value = x ; Some(Nil)
case List(x) => errorAndValue("'" + x + "' is not a valid choice for '" + name + "'", None)
case xs => errorAndValue("'" + name + "' does not accept multiple arguments.", None)
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index dae8539c66..e10fa3a114 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -38,8 +38,8 @@ trait ScalaSettings extends AbsScalaSettings
/** If any of these settings is enabled, the compiler should print a message and exit. */
def infoSettings = List[Setting](version, help, Xhelp, Yhelp, showPlugins, showPhases, genPhaseGraph)
- /** Any -multichoice:help? Nicer if any option could report that it had help to offer. */
- private def multihelp = allSettings exists { case s: MultiChoiceSetting[_] => s.isHelping case _ => false }
+ /** Any -option:help? */
+ private def multihelp = allSettings exists { case s => s.isHelping case _ => false }
/** Is an info setting set? */
def isInfo = (infoSettings exists (_.isSetByUser)) || multihelp
@@ -133,7 +133,22 @@ trait ScalaSettings extends AbsScalaSettings
val XnoPatmatAnalysis = BooleanSetting ("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.")
val XfullLubs = BooleanSetting ("-Xfull-lubs", "Retains pre 2.10 behavior of less aggressive truncation of least upper bounds.")
- val XgenMixinForwarders = BooleanSetting("-Xgen-mixin-forwarders", "Generate forwarder methods in classes inhering concrete methods from traits.")
+
+ val XmixinForceForwarders = ChoiceSetting(
+ name = "-Xmixin-force-forwarders",
+ helpArg = "mode",
+ descr = "Generate forwarder methods in classes inhering concrete methods from traits.",
+ choices = List("true", "junit", "false"),
+ default = "junit",
+ choicesHelp = List(
+ "Always generate mixin forwarders.",
+ "Generate mixin forwarders for JUnit-annotated methods (JUnit 4 does not support default methods).",
+ "Only generate mixin forwarders required for program correctness."))
+
+ object mixinForwarderChoices {
+ def isTruthy = XmixinForceForwarders.value == "true"
+ def isJunit = isTruthy || XmixinForceForwarders.value == "junit"
+ }
// XML parsing options
object XxmlSettings extends MultiChoiceEnumeration {
@@ -143,7 +158,7 @@ trait ScalaSettings extends AbsScalaSettings
val Xxml = MultiChoiceSetting(
name = "-Xxml",
helpArg = "property",
- descr = "Configure XML parsing",
+ descr = "Configure XML parsing.",
domain = XxmlSettings
)
@@ -169,7 +184,7 @@ trait ScalaSettings extends AbsScalaSettings
val Ycompacttrees = BooleanSetting ("-Ycompact-trees", "Use compact tree printer when displaying trees.")
val noCompletion = BooleanSetting ("-Yno-completion", "Disable tab-completion in the REPL.")
val debug = BooleanSetting ("-Ydebug", "Increase the quantity of debugging output.")
- val termConflict = ChoiceSetting ("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error")
+ val termConflict = ChoiceSetting ("-Yresolve-term-conflict", "strategy", "Resolve term conflicts.", List("package", "object", "error"), "error")
val log = PhasesSetting ("-Ylog", "Log operations during")
val Ylogcp = BooleanSetting ("-Ylog-classpath", "Output information about what classpath is being applied.")
val Ynogenericsig = BooleanSetting ("-Yno-generic-signatures", "Suppress generation of generic signatures for Java.")
@@ -193,7 +208,7 @@ trait ScalaSettings extends AbsScalaSettings
val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.")
val Ymemberpos = StringSetting ("-Yshow-member-pos", "output style", "Show start and end positions of members", "") withPostSetHook (_ => Yrangepos.value = true)
val Yreifycopypaste = BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.")
- val Ymacroexpand = ChoiceSetting ("-Ymacro-expand", "policy", "Control expansion of macros, useful for scaladoc and presentation compiler", List(MacroExpand.Normal, MacroExpand.None, MacroExpand.Discard), MacroExpand.Normal)
+ val Ymacroexpand = ChoiceSetting ("-Ymacro-expand", "policy", "Control expansion of macros, useful for scaladoc and presentation compiler.", List(MacroExpand.Normal, MacroExpand.None, MacroExpand.Discard), MacroExpand.Normal)
val Ymacronoexpand = BooleanSetting ("-Ymacro-no-expand", "Don't expand macros. Might be useful for scaladoc and presentation compiler, but will crash anything which uses macros and gets past typer.") withDeprecationMessage(s"Use ${Ymacroexpand.name}:${MacroExpand.None}") withPostSetHook(_ => Ymacroexpand.value = MacroExpand.None)
val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup")
val Yreplclassbased = BooleanSetting ("-Yrepl-class-based", "Use classes to wrap REPL snippets instead of objects")
diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala
index 7ef606b6ef..839e734abc 100644
--- a/src/compiler/scala/tools/nsc/settings/Warnings.scala
+++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala
@@ -25,8 +25,6 @@ trait Warnings {
// currently considered too noisy for general use
val warnUnusedImport = BooleanSetting("-Ywarn-unused-import", "Warn when imports are unused.")
- val nowarnDefaultJunitMethods = BooleanSetting("-Ynowarn-default-junit-methods", "Don't warn when a JUnit @Test method is generated as a default method (not supported in JUnit 4).")
-
// Experimental lint warnings that are turned off, but which could be turned on programmatically.
// They are not activated by -Xlint and can't be enabled on the command line because they are not
// created using the standard factory methods.
diff --git a/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala b/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala
new file mode 100644
index 0000000000..120ee5c26e
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala
@@ -0,0 +1,465 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL and Lightbend, Inc
+ */
+
+package scala.tools.nsc
+package transform
+
+import symtab._
+import Flags._
+import scala.collection.mutable
+
+trait AccessorSynthesis extends Transform with ast.TreeDSL {
+ import global._
+ import definitions._
+ import CODE._
+
+ val EmptyThicket = EmptyTree
+ def Thicket(trees: List[Tree]) = if (trees.isEmpty) EmptyTree else Block(trees, EmptyTree)
+ def mustExplodeThicket(tree: Tree): Boolean =
+ tree match {
+ case EmptyTree => true
+ case Block(_, EmptyTree) => true
+ case _ => false
+ }
+ def explodeThicket(tree: Tree): List[Tree] = tree match {
+ case EmptyTree => Nil
+ case Block(thicket, EmptyTree) => thicket
+ case stat => stat :: Nil
+ }
+
+
+ trait AccessorTreeSynthesis {
+ protected def typedPos(pos: Position)(tree: Tree): Tree
+
+ // used while we still need to synthesize some accessors in mixins: paramaccessors and presupers
+ class UncheckedAccessorSynth(protected val clazz: Symbol){
+ protected val _newDefs = mutable.ListBuffer[Tree]()
+
+ def newDefs = _newDefs.toList
+
+ /** Add tree at given position as new definition */
+ protected def addDef(tree: ValOrDefDef): Unit = _newDefs += typedPos(position(tree.symbol))(tree)
+
+ /** The position of given symbol, or, if this is undefined,
+ * the position of the current class.
+ */
+ private def position(sym: Symbol) = if (sym.pos == NoPosition) clazz.pos else sym.pos
+
+ /** Add new method definition.
+ *
+ * @param sym The method symbol.
+ * @param rhs The method body.
+ */
+ def addDefDef(sym: Symbol, rhs: Tree = EmptyTree) = addDef(DefDef(sym, rhs))
+ def addValDef(sym: Symbol, rhs: Tree = EmptyTree) = addDef(ValDef(sym, rhs))
+
+ /** Complete `stats` with init checks and bitmaps,
+ * removing any abstract method definitions in `stats` that are
+ * matched by some symbol defined by a tree previously passed to `addDef`.
+ */
+ def implementWithNewDefs(stats: List[Tree]): List[Tree] = {
+ val newDefs = _newDefs.toList
+ val newSyms = newDefs map (_.symbol)
+ def isNotDuplicate(tree: Tree) = tree match {
+ case DefDef(_, _, _, _, _, _) =>
+ val sym = tree.symbol
+ !(sym.isDeferred &&
+ (newSyms exists (nsym => nsym.name == sym.name && (nsym.tpe matches sym.tpe))))
+ case _ => true
+ }
+ if (newDefs.isEmpty) stats
+ else newDefs ::: (stats filter isNotDuplicate)
+ }
+
+ def accessorBody(sym: Symbol) =
+ if (sym.isSetter) setterBody(sym, sym.getterIn(clazz)) else getterBody(sym)
+
+ protected def getterBody(getter: Symbol): Tree = {
+ assert(getter.isGetter)
+ assert(getter.hasFlag(PARAMACCESSOR))
+
+ fieldAccess(getter)
+ }
+
+ protected def setterBody(setter: Symbol, getter: Symbol): Tree = {
+ assert(getter.hasFlag(PARAMACCESSOR), s"missing implementation for non-paramaccessor $setter in $clazz")
+
+ Assign(fieldAccess(setter), Ident(setter.firstParam))
+ }
+
+ private def fieldAccess(accessor: Symbol) =
+ Select(This(clazz), accessor.accessed)
+
+ }
+ }
+
+ case class BitmapInfo(symbol: Symbol, mask: Literal) {
+ def storageClass: ClassSymbol = symbol.info.typeSymbol.asClass
+ }
+
+
+ // TODO: better way to communicate from info transform to tree transfor?
+ private[this] val _bitmapInfo = perRunCaches.newMap[Symbol, BitmapInfo]
+ private[this] val _slowPathFor = perRunCaches.newMap[Symbol, Symbol]()
+
+ def checkedAccessorSymbolSynth(clz: Symbol) =
+ if (settings.checkInit) new CheckInitAccessorSymbolSynth { val clazz = clz }
+ else new CheckedAccessorSymbolSynth { val clazz = clz }
+
+ // base trait, with enough functionality for lazy vals -- CheckInitAccessorSymbolSynth adds logic for -Xcheckinit
+ trait CheckedAccessorSymbolSynth {
+ protected val clazz: Symbol
+
+ protected def defaultPos = clazz.pos.focus
+ protected def isTrait = clazz.isTrait
+ protected def hasTransientAnnot(field: Symbol) = field.accessedOrSelf hasAnnotation TransientAttr
+
+ def needsBitmap(sym: Symbol): Boolean = !(isTrait || sym.isDeferred) && sym.isMethod && sym.isLazy && !sym.isSpecialized
+
+
+ /** Examines the symbol and returns a name indicating what brand of
+ * bitmap it requires. The possibilities are the BITMAP_* vals
+ * defined in StdNames. If it needs no bitmap, nme.NO_NAME.
+ *
+ * bitmaps for checkinit fields are not inherited
+ */
+ protected def bitmapCategory(sym: Symbol): Name = {
+ // ensure that nested objects are transformed TODO: still needed?
+ sym.initialize
+
+ import nme._
+
+ if (needsBitmap(sym) && sym.isLazy)
+ if (hasTransientAnnot(sym)) BITMAP_TRANSIENT else BITMAP_NORMAL
+ else NO_NAME
+ }
+
+
+ def bitmapFor(sym: Symbol): BitmapInfo = _bitmapInfo(sym)
+ protected def hasBitmap(sym: Symbol): Boolean = _bitmapInfo isDefinedAt sym
+
+
+ /** Fill the map from fields to bitmap infos.
+ *
+ * Instead of field symbols, the map keeps their getter symbols. This makes code generation easier later.
+ */
+ def computeBitmapInfos(decls: List[Symbol]): List[Symbol] = {
+ def doCategory(fields: List[Symbol], category: Name) = {
+ val nbFields = fields.length // we know it's > 0
+ val (bitmapClass, bitmapCapacity) =
+ if (nbFields == 1) (BooleanClass, 1)
+ else if (nbFields <= 8) (ByteClass, 8)
+ else if (nbFields <= 32) (IntClass, 32)
+ else (LongClass, 64)
+
+ // 0-based index of highest bit, divided by bits per bitmap
+ // note that this is only ever > 0 when bitmapClass == LongClass
+ val maxBitmapNumber = (nbFields - 1) / bitmapCapacity
+
+ // transient fields get their own category
+ val isTransientCategory = fields.head hasAnnotation TransientAttr
+
+ val bitmapSyms =
+ (0 to maxBitmapNumber).toArray map { bitmapNumber =>
+ val bitmapSym = (
+ clazz.newVariable(nme.newBitmapName(category, bitmapNumber).toTermName, defaultPos)
+ setInfo bitmapClass.tpe
+ setFlag PrivateLocal | NEEDS_TREES
+ )
+
+ bitmapSym addAnnotation VolatileAttr
+
+ if (isTransientCategory) bitmapSym addAnnotation TransientAttr
+
+ bitmapSym
+ }
+
+ fields.zipWithIndex foreach { case (f, idx) =>
+ val bitmapIdx = idx / bitmapCapacity
+ val offsetInBitmap = idx % bitmapCapacity
+ val mask =
+ if (bitmapClass == LongClass) Constant(1L << offsetInBitmap)
+ else Constant(1 << offsetInBitmap)
+
+ _bitmapInfo(f) = BitmapInfo(bitmapSyms(bitmapIdx), Literal(mask))
+ }
+
+ bitmapSyms
+ }
+
+ decls groupBy bitmapCategory flatMap {
+ case (category, fields) if category != nme.NO_NAME && fields.nonEmpty => doCategory(fields, category)
+ case _ => Nil
+ } toList
+ }
+
+ def slowPathFor(lzyVal: Symbol): Symbol = _slowPathFor(lzyVal)
+
+ def newSlowPathSymbol(lzyVal: Symbol): Symbol = {
+ val pos = if (lzyVal.pos != NoPosition) lzyVal.pos else defaultPos // TODO: is the else branch ever taken?
+ val sym = clazz.newMethod(nme.newLazyValSlowComputeName(lzyVal.name.toTermName), pos, PRIVATE) setInfo MethodType(Nil, lzyVal.tpe.resultType)
+ _slowPathFor(lzyVal) = sym
+ sym
+ }
+
+ }
+
+ trait CheckInitAccessorSymbolSynth extends CheckedAccessorSymbolSynth {
+ /** Does this field require an initialized bit?
+ * Note: fields of classes inheriting DelayedInit are not checked.
+ * This is because they are neither initialized in the constructor
+ * nor do they have a setter (not if they are vals anyway). The usual
+ * logic for setting bitmaps does therefore not work for such fields.
+ * That's why they are excluded.
+ * Note: The `checkinit` option does not check if transient fields are initialized.
+ */
+ protected def needsInitFlag(sym: Symbol): Boolean =
+ sym.isGetter &&
+ !( sym.isInitializedToDefault
+ || isConstantType(sym.info.finalResultType) // SI-4742
+ || sym.hasFlag(PARAMACCESSOR | SPECIALIZED | LAZY)
+ || sym.accessed.hasFlag(PRESUPER)
+ || sym.isOuterAccessor
+ || (sym.owner isSubClass DelayedInitClass)
+ || (sym.accessed hasAnnotation TransientAttr))
+
+ /** Examines the symbol and returns a name indicating what brand of
+ * bitmap it requires. The possibilities are the BITMAP_* vals
+ * defined in StdNames. If it needs no bitmap, nme.NO_NAME.
+ *
+ * bitmaps for checkinit fields are not inherited
+ */
+ override protected def bitmapCategory(sym: Symbol): Name = {
+ import nme._
+
+ super.bitmapCategory(sym) match {
+ case NO_NAME if needsInitFlag(sym) && !sym.isDeferred =>
+ if (hasTransientAnnot(sym)) BITMAP_CHECKINIT_TRANSIENT else BITMAP_CHECKINIT
+ case category => category
+ }
+ }
+
+ override def needsBitmap(sym: Symbol): Boolean = super.needsBitmap(sym) || !(isTrait || sym.isDeferred) && needsInitFlag(sym)
+ }
+
+
+ // synthesize trees based on info gathered during info transform
+ // (which are known to have been run because the tree transform runs afterOwnPhase)
+ // since we can't easily share all info via symbols and flags, we have two maps above
+ // (they are persisted even between phases because the -Xcheckinit logic runs during constructors)
+ // TODO: can we use attachments instead of _bitmapInfo and _slowPathFor?
+ trait CheckedAccessorTreeSynthesis extends AccessorTreeSynthesis {
+
+ // note: we deal in getters here, not field symbols
+ trait SynthCheckedAccessorsTreesInClass extends CheckedAccessorSymbolSynth {
+ def isUnitGetter(sym: Symbol) = sym.tpe.resultType.typeSymbol == UnitClass
+ def thisRef = gen.mkAttributedThis(clazz)
+
+ /** Return an (untyped) tree of the form 'clazz.this.bitmapSym & mask (==|!=) 0', the
+ * precise comparison operator depending on the value of 'equalToZero'.
+ */
+ def mkTest(field: Symbol, equalToZero: Boolean = true): Tree = {
+ val bitmap = bitmapFor(field)
+ val bitmapTree = thisRef DOT bitmap.symbol
+
+ if (bitmap.storageClass == BooleanClass) {
+ if (equalToZero) NOT(bitmapTree) else bitmapTree
+ } else {
+ val lhs = bitmapTree GEN_&(bitmap.mask, bitmap.storageClass)
+ if (equalToZero) lhs GEN_==(ZERO, bitmap.storageClass)
+ else lhs GEN_!=(ZERO, bitmap.storageClass)
+ }
+ }
+
+ /** Return an (untyped) tree of the form 'Clazz.this.bmp = Clazz.this.bmp | mask'. */
+ def mkSetFlag(valSym: Symbol): Tree = {
+ val bitmap = bitmapFor(valSym)
+ def x = thisRef DOT bitmap.symbol
+
+ Assign(x,
+ if (bitmap.storageClass == BooleanClass) TRUE
+ else {
+ val or = Apply(Select(x, getMember(bitmap.storageClass, nme.OR)), List(bitmap.mask))
+ // NOTE: bitwise or (`|`) on two bytes yields and Int (TODO: why was this not a problem when this ran during mixins?)
+ // TODO: need this to make it type check -- is there another way??
+ if (bitmap.storageClass != LongClass) Apply(Select(or, newTermName("to" + bitmap.storageClass.name)), Nil)
+ else or
+ }
+ )
+ }
+ }
+
+ class SynthLazyAccessorsIn(protected val clazz: Symbol) extends SynthCheckedAccessorsTreesInClass {
+ /**
+ * The compute method (slow path) looks like:
+ *
+ * ```
+ * def l$compute() = {
+ * synchronized(this) {
+ * if ((bitmap$n & MASK) == 0) {
+ * init // l$ = <rhs>
+ * bitmap$n = bimap$n | MASK
+ * }
+ * }
+ * ...
+ * this.f1 = null
+ * ...
+ * this.fn = null
+ * l$
+ * }
+ * ```
+ *
+ * `bitmap$n` is a byte, int or long value acting as a bitmap of initialized values.
+ * The kind of the bitmap determines how many bit indicators for lazy vals are stored in it.
+ * For Int bitmap it is 32 and then 'n' in the above code is: (offset / 32),
+ * the MASK is (1 << (offset % 32)).
+ *
+ * If the class contains only a single lazy val then the bitmap is
+ * represented as a Boolean and the condition checking is a simple bool test.
+ *
+ * Private fields used only in this initializer are subsequently set to null.
+ *
+ * For performance reasons the double-checked locking is split into two parts,
+ * the first (fast) path checks the bitmap without synchronizing, and if that
+ * fails it initializes the lazy val within the synchronization block (slow path).
+ *
+ * This way the inliner should optimize the fast path because the method body is small enough.
+ */
+ def expandLazyClassMember(lazyVar: Symbol, lazyAccessor: Symbol, transformedRhs: Tree, nullables: Map[Symbol, List[Symbol]]): Tree = {
+ // use cast so that specialization can turn null.asInstanceOf[T] into null.asInstanceOf[Long]
+ def nullify(sym: Symbol) =
+ Select(thisRef, sym.accessedOrSelf) === gen.mkAsInstanceOf(NULL, sym.info.resultType)
+
+ val nulls = nullables.getOrElse(lazyAccessor, Nil) map nullify
+
+ if (nulls.nonEmpty)
+ log("nulling fields inside " + lazyAccessor + ": " + nulls)
+
+ val slowPathSym = slowPathFor(lazyAccessor)
+ val rhsAtSlowDef = transformedRhs.changeOwner(lazyAccessor -> slowPathSym)
+
+ val isUnit = isUnitGetter(lazyAccessor)
+ val selectVar = if (isUnit) UNIT else Select(thisRef, lazyVar)
+ val storeRes = if (isUnit) rhsAtSlowDef else Assign(selectVar, rhsAtSlowDef)
+
+ def needsInit = mkTest(lazyAccessor)
+ val doInit = Block(List(storeRes), mkSetFlag(lazyAccessor))
+ // the slow part of double-checked locking (TODO: is this the most efficient pattern? https://github.come/scala/scala-dev/issues/204)
+ val slowPathRhs = Block(gen.mkSynchronized(thisRef)(If(needsInit, doInit, EmptyTree)) :: nulls, selectVar)
+
+ // The lazy accessor delegates to the compute method if needed, otherwise just accesses the var (it was initialized previously)
+ // `if ((bitmap&n & MASK) == 0) this.l$compute() else l$`
+ val accessorRhs = If(needsInit, Apply(Select(thisRef, slowPathSym), Nil), selectVar)
+
+ afterOwnPhase { // so that we can assign to vals
+ Thicket(List((DefDef(slowPathSym, slowPathRhs)), DefDef(lazyAccessor, accessorRhs)) map typedPos(lazyAccessor.pos.focus))
+ }
+ }
+ }
+
+ /** Map lazy values to the fields they should null after initialization. */
+ // TODO: fix
+ def lazyValNullables(clazz: Symbol, templStats: List[Tree]): Map[Symbol, List[Symbol]] = {
+ // if there are no lazy fields, take the fast path and save a traversal of the whole AST
+ if (!clazz.info.decls.exists(_.isLazy)) Map()
+ else {
+ // A map of single-use fields to the lazy value that uses them during initialization.
+ // Each field has to be private and defined in the enclosing class, and there must
+ // be exactly one lazy value using it.
+ //
+ // Such fields will be nulled after the initializer has memoized the lazy value.
+ val singleUseFields: Map[Symbol, List[Symbol]] = {
+ val usedIn = mutable.HashMap[Symbol, List[Symbol]]() withDefaultValue Nil
+
+ object SingleUseTraverser extends Traverser {
+ override def traverse(tree: Tree) {
+ tree match {
+ // assignment targets don't count as a dereference -- only check the rhs
+ case Assign(_, rhs) => traverse(rhs)
+ case tree: RefTree if tree.symbol != NoSymbol =>
+ val sym = tree.symbol
+ // println(s"$sym in ${sym.owner} from $currentOwner ($tree)")
+ if ((sym.hasAccessorFlag || (sym.isTerm && !sym.isMethod)) && sym.isPrivate && !sym.isLazy // non-lazy private field or its accessor
+ && !definitions.isPrimitiveValueClass(sym.tpe.resultType.typeSymbol) // primitives don't hang on to significant amounts of heap
+ && sym.owner == currentOwner.enclClass && !(currentOwner.isGetter && currentOwner.accessed == sym)) {
+
+ // println("added use in: " + currentOwner + " -- " + tree)
+ usedIn(sym) ::= currentOwner
+ }
+ super.traverse(tree)
+ case _ => super.traverse(tree)
+ }
+ }
+ }
+ templStats foreach SingleUseTraverser.apply
+ // println("usedIn: " + usedIn)
+
+ // only consider usages from non-transient lazy vals (SI-9365)
+ val singlyUsedIn = usedIn filter { case (_, member :: Nil) => member.isLazy && !member.accessed.hasAnnotation(TransientAttr) case _ => false } toMap
+
+ // println("singlyUsedIn: " + singlyUsedIn)
+ singlyUsedIn
+ }
+
+ val map = mutable.Map[Symbol, Set[Symbol]]() withDefaultValue Set()
+ // invert the map to see which fields can be nulled for each non-transient lazy val
+ for ((field, users) <- singleUseFields; lazyFld <- users) map(lazyFld) += field
+
+ map.mapValues(_.toList sortBy (_.id)).toMap
+ }
+ }
+
+
+ class SynthInitCheckedAccessorsIn(protected val clazz: Symbol) extends SynthCheckedAccessorsTreesInClass with CheckInitAccessorSymbolSynth {
+ private object addInitBitsTransformer extends Transformer {
+ private def checkedGetter(lhs: Tree)(pos: Position) = {
+ val getter = clazz.info decl lhs.symbol.getterName suchThat (_.isGetter)
+ if (hasBitmap(getter) && needsInitFlag(getter)) {
+ debuglog("adding checked getter for: " + getter + " " + lhs.symbol.flagString)
+ List(typedPos(pos)(mkSetFlag(getter)))
+ }
+ else Nil
+ }
+ override def transformStats(stats: List[Tree], exprOwner: Symbol) = {
+ // !!! Ident(self) is never referenced, is it supposed to be confirming
+ // that self is anything in particular?
+ super.transformStats(
+ stats flatMap {
+ case stat@Assign(lhs@Select(This(_), _), rhs) => stat :: checkedGetter(lhs)(stat.pos.focus)
+ // remove initialization for default values -- TODO is this case ever hit? constructors does not generate Assigns with EmptyTree for the rhs AFAICT
+ case Apply(lhs@Select(Ident(self), _), EmptyTree.asList) if lhs.symbol.isSetter => Nil
+ case stat => List(stat)
+ },
+ exprOwner
+ )
+ }
+ }
+
+ /** Make getters check the initialized bit, and the class constructor & setters are changed to set the initialized bits. */
+ def wrapRhsWithInitChecks(sym: Symbol)(rhs: Tree): Tree = {
+ // Add statements to the body of a constructor to set the 'init' bit for each field initialized in the constructor
+ if (sym.isConstructor) addInitBitsTransformer transform rhs
+ else if (isTrait || rhs == EmptyTree) rhs
+ else if (needsInitFlag(sym)) // getter
+ mkCheckedAccessorRhs(if (isUnitGetter(sym)) UNIT else rhs, rhs.pos, sym)
+ else if (sym.isSetter) {
+ val getter = sym.getterIn(clazz)
+ if (needsInitFlag(getter)) Block(List(rhs, typedPos(rhs.pos.focus)(mkSetFlag(getter))), UNIT)
+ else rhs
+ }
+ else rhs
+ }
+
+ private def mkCheckedAccessorRhs(retVal: Tree, pos: Position, getter: Symbol): Tree = {
+ val msg = s"Uninitialized field: ${clazz.sourceFile}: ${pos.line}"
+ val result =
+ IF(mkTest(getter, equalToZero = false)).
+ THEN(retVal).
+ ELSE(Throw(NewFromConstructor(UninitializedFieldConstructor, LIT(msg))))
+
+ typedPos(pos)(BLOCK(result, retVal))
+ }
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index 0fb6213d36..81df28bc87 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -456,6 +456,11 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
super.transform(treeCopy.ApplyDynamic(tree, atPos(fn.pos)(Ident(SymbolLiteral_dummy).setType(SymbolLiteral_dummy.info)), LIT(SymbolLiteral_bootstrap) :: arg :: Nil))
+ // Drop the TypeApply, which was used in Erasure to make `synchronized { ... } ` erase like `...`
+ // (and to avoid boxing the argument to the polymorphic `synchronized` method).
+ case app@Apply(TypeApply(fun, _), args) if fun.symbol == Object_synchronized =>
+ super.transform(treeCopy.Apply(app, fun, args))
+
// Replaces `Array(Predef.wrapArray(ArrayValue(...).$asInstanceOf[...]), <tag>)`
// with just `ArrayValue(...).$asInstanceOf[...]`
//
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 0a87e358b4..8d362f13dd 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -450,7 +450,9 @@ abstract class Constructors extends Statics with Transform with TypingTransforme
with DelayedInitHelper
with OmittablesHelper
with GuardianOfCtorStmts
- {
+ with fields.CheckedAccessorTreeSynthesis
+ {
+ protected def typedPos(pos: Position)(tree: Tree): Tree = localTyper.typedPos(pos)(tree)
val clazz = impl.symbol.owner // the transformed class
@@ -770,11 +772,20 @@ abstract class Constructors extends Statics with Transform with TypingTransforme
// We never eliminate delayed hooks or the constructors, so, only filter `defs`.
val prunedStats = (defs filterNot omittableStat) ::: delayedHookDefs ::: constructors
+ val statsWithInitChecks =
+ if (settings.checkInit) {
+ val addChecks = new SynthInitCheckedAccessorsIn(currentOwner)
+ prunedStats mapConserve {
+ case dd: DefDef => deriveDefDef(dd)(addChecks.wrapRhsWithInitChecks(dd.symbol))
+ case stat => stat
+ }
+ } else prunedStats
+
// Add the static initializers
- if (classInitStats.isEmpty) deriveTemplate(impl)(_ => prunedStats)
+ if (classInitStats.isEmpty) deriveTemplate(impl)(_ => statsWithInitChecks)
else {
- val staticCtor = staticConstructor(prunedStats, localTyper, impl.pos)(classInitStats)
- deriveTemplate(impl)(_ => staticCtor :: prunedStats)
+ val staticCtor = staticConstructor(statsWithInitChecks, localTyper, impl.pos)(classInitStats)
+ deriveTemplate(impl)(_ => staticCtor :: statsWithInitChecks)
}
}
} // TemplateTransformer
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index eecd52546c..69240b07a1 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -1117,7 +1117,8 @@ abstract class Erasure extends InfoTransform
case TypeApply(fun, args) if (fun.symbol.owner != AnyClass &&
fun.symbol != Object_asInstanceOf &&
- fun.symbol != Object_isInstanceOf) =>
+ fun.symbol != Object_isInstanceOf &&
+ fun.symbol != Object_synchronized) =>
// leave all other type tests/type casts, remove all other type applications
preErase(fun)
@@ -1194,7 +1195,7 @@ abstract class Erasure extends InfoTransform
else {
val tree1 = preErase(tree)
tree1 match {
- case TypeApply(fun, targs @ List(targ)) if fun.symbol == Any_asInstanceOf && targ.tpe == UnitTpe =>
+ case TypeApply(fun, targs @ List(targ)) if (fun.symbol == Any_asInstanceOf || fun.symbol == Object_synchronized) && targ.tpe == UnitTpe =>
// SI-9066 prevent transforming `o.asInstanceOf[Unit]` to `o.asInstanceOf[BoxedUnit]`.
// adaptMember will then replace the call by a reference to BoxedUnit.UNIT.
treeCopy.TypeApply(tree1, transform(fun), targs).clearType()
diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala
index 26e517743a..a383b65192 100644
--- a/src/compiler/scala/tools/nsc/transform/Fields.scala
+++ b/src/compiler/scala/tools/nsc/transform/Fields.scala
@@ -10,26 +10,38 @@ import scala.annotation.tailrec
import symtab.Flags._
-/** Synthesize accessors and field for each (strict) val owned by a trait.
+/** Synthesize accessors, fields (and bitmaps) for (lazy) vals and modules.
*
- * For traits:
+ * During Namers, a `ValDef` that is `lazy`, deferred and/or defined in a trait carries its getter's symbol.
+ * The underlying field symbol does not exist until this phase.
*
- * - Namers translates a definition `val x = rhs` into a getter `def x = rhs` -- no underlying field is created.
- * - This phase synthesizes accessors and fields for any vals mixed into a non-trait class.
- * - Constructors will move the rhs to an assignment in the template body.
- * Those statements then move to the template into the constructor,
- * which means it will initialize the fields defined in this template (and execute the corresponding side effects).
- * We need to maintain the connection between getter and rhs until after specialization so that it can duplicate vals.
- * - A ModuleDef is desugared to a ClassDef, an accessor (which reuses the module's term symbol)
- * and a module var (unless the module is static and does not implement a member of a supertype, or we're in a trait).
- * For subclasses of traits that define modules, a module var is mixed in, as well as the required module accessors.
+ * For `val`s defined in classes, we still emit a field immediately.
+ * TODO: uniformly assign getter symbol to all `ValDef`s, stop using `accessed`.
*
- * Runs after uncurry to deal with classes that implement SAM traits with ValDefs.
- * Runs before erasure (to get bridges), and thus before lambdalift/flatten, so that nested functions/definitions must be considered.
+ * This phase synthesizes accessors, fields and bitmaps (for lazy or init-checked vals under -Xcheckinit)
+ * in the first (closest in the subclassing lattice) subclass (not a trait) of a trait.
*
- * We run after uncurry because it can introduce subclasses of traits with fields (SAMs with vals).
- * Lambdalift also introduces new fields (paramaccessors for captured vals), but runs too late in the pipeline
- * (mixins still synthesizes implementations for accessors that need to be mixed into subclasses of local traits that capture).
+ * 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.
+ *
+ * Local lazy vals do not receive bitmaps, but use a Lazy*Holder that has the volatile init bit and the computed value.
+ * See `mkLazyLocalDef`.
+ *
+ * Constructors will move the rhs to an assignment in the template body.
+ * Those statements then move to the template into the constructor,
+ * which means it will initialize the fields defined in this template (and execute the corresponding side effects).
+ * We need to maintain the connection between getter and rhs until after specialization so that it can duplicate vals.
+ *
+ * A ModuleDef is desugared to a ClassDef, an accessor (which reuses the module's term symbol)
+ * and a module var (unless the module is static and does not implement a member of a supertype, or we're in a trait).
+ *
+ * For subclasses of traits that define modules, a module var is mixed in, as well as the required module accessors.
+ *
+ * Phase ordering:
+ * - Runs after uncurry to deal with classes that implement SAM traits with ValDefs.
+ * - Runs before erasure (to get bridges), and thus before lambdalift/flatten, so that nested functions/definitions must be considered.
+ * - Lambdalift introduces new paramaccessors for captured vals, but runs too late in the pipeline, so
+ * mixins still synthesizes implementations for these accessors when a local trait that captures is subclassed.
*
*
* In the future, would like to get closer to dotty, which lifts a val's RHS (a similar thing is done for template-level statements)
@@ -54,10 +66,12 @@ import symtab.Flags._
* The only change due to overriding is that its value is never written to the field
* (the overridden val's value is, of course, stored in the field in addition to its side-effect being performed).
*
- * TODO: check init support (or drop the -Xcheck-init flag??)
+ * TODO: Java 9 support for vals defined in traits. They are currently emitted as final,
+ * but the write (putfield) to the val does not occur syntactically within the <init> method
+ * (it's done by the trait setter, which is called from the trait's mixin constructor,
+ * which is called from the subclass's constructor...)
*/
-abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransformers {
-
+abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransformers with AccessorSynthesis {
import global._
import definitions._
@@ -69,8 +83,8 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
if (sym.isJavaDefined || sym.isPackageClass || !sym.isClass) tp
else synthFieldsAndAccessors(tp)
- // we leave lazy vars/accessors and early-init vals alone for now
- private def excludedAccessorOrFieldByFlags(statSym: Symbol): Boolean = statSym hasFlag LAZY | PRESUPER
+ // TODO: drop PRESUPER support when we implement trait parameters in 2.13
+ private def excludedAccessorOrFieldByFlags(statSym: Symbol): Boolean = statSym hasFlag PRESUPER
// used for internal communication between info and tree transform of this phase -- not pickled, not in initialflags
// TODO: reuse MIXEDIN for NEEDS_TREES?
@@ -139,13 +153,12 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
class FieldMemoization(accessorOrField: Symbol, site: Symbol) {
val tp = fieldTypeOfAccessorIn(accessorOrField, site.thisType)
- // not stored, no side-effect
- val pureConstant = tp.isInstanceOf[ConstantType]
-
- // if !stored, may still have a side-effect
- // (currently not distinguished -- used to think we could drop unit-typed vals,
- // but the memory model cares about writes to unit-typed fields)
- val stored = !pureConstant // || isUnitType(tp))
+ // We can only omit strict vals of ConstantType. Lazy vals do not receive constant types (anymore).
+ // (See note at widenIfNecessary -- for example, the REPL breaks when we omit constant lazy vals)
+ // Note that a strict unit-typed val does receive a field, because we cannot omit the write to the field
+ // (well, we could emit it for non-@volatile ones, if I understand the memory model correctly,
+ // but that seems pretty edge-casey)
+ val constantTyped = tp.isInstanceOf[ConstantType]
}
private def fieldTypeForGetterIn(getter: Symbol, pre: Type): Type = getter.info.finalResultType.asSeenFrom(pre, getter.owner)
@@ -174,22 +187,71 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
// can't use the referenced field since it already tracks the module's moduleClass
- private[this] val moduleVarOf = perRunCaches.newMap[Symbol, Symbol]
+ private[this] val moduleOrLazyVarOf = perRunCaches.newMap[Symbol, Symbol]
+
+ // TODO: can we drop FINAL? In any case, since these variables are MUTABLE, they cannot and will
+ // 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(site: Symbol, module: Symbol, tp: Type, extraFlags: Long): TermSymbol = {
+ private def newModuleVarSymbol(owner: Symbol, module: Symbol, tp: Type): TermSymbol = {
// println(s"new module var in $site for $module of type $tp")
- val moduleVar = site.newVariable(nme.moduleVarName(module.name.toTermName), module.pos.focus, MODULEVAR | extraFlags) setInfo tp addAnnotation VolatileAttr
- moduleVarOf(module) = moduleVar
+ 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) = {
// println(s"moduleInit for $module in ${module.ownerChain} --> ${moduleVarOf.get(module)}")
- val moduleVar = moduleVarOf(module)
- gen.mkAssignAndReturn(moduleVar, gen.newModule(module, moduleVar.info))
+ val moduleVar = moduleOrLazyVarOf(module)
+ def moduleVarRef = gen.mkAttributedRef(moduleVar)
+
+ // for local modules, we synchronize on the owner of the method that owns the module
+ val monitorHolder = This(moduleVar.owner.enclClass)
+ def needsInit = Apply(Select(moduleVarRef, Object_eq), List(CODE.NULL))
+ val init = Assign(moduleVarRef, gen.newModule(module, moduleVar.info))
+
+ /** double-checked locking following https://shipilev.net/blog/2014/safe-public-construction/#_safe_publication
+ *
+ * public class SafeDCLFactory {
+ * private volatile Singleton instance;
+ *
+ * public Singleton get() {
+ * if (instance == null) { // check 1
+ * synchronized(this) {
+ * if (instance == null) { // check 2
+ * instance = new Singleton();
+ * }
+ * }
+ * }
+ * return instance;
+ * }
+ * }
+ *
+ * TODO: optimize using local variable?
+ */
+ Block(If(needsInit, gen.mkSynchronized(monitorHolder)(If(needsInit, init, EmptyTree)), EmptyTree) :: Nil, moduleVarRef)
}
+ // NoSymbol for lazy accessor sym with unit result type
+ def lazyVarOf(sym: Symbol) = moduleOrLazyVarOf.getOrElse(sym, NoSymbol)
+
+ private def newLazyVarMember(clazz: Symbol, member: Symbol, tp: Type): TermSymbol = {
+ val flags = LAZY | (member.flags & FieldFlags) | ModuleOrLazyFieldFlags
+ val name = member.name.toTermName.append(reflect.NameTransformer.LOCAL_SUFFIX_STRING)
+
+ // Set the MUTABLE flag because the field cannot be ACC_FINAL since we write to it outside of a constructor.
+ val sym = clazz.newVariable(name, member.pos.focus, flags) setInfo tp
+
+ moduleOrLazyVarOf(member) = sym
+ sym
+ }
private object synthFieldsAndAccessors extends TypeMap {
private def newTraitSetter(getter: Symbol, clazz: Symbol) = {
@@ -210,7 +272,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
private def newModuleAccessor(module: Symbol, site: Symbol, moduleVar: Symbol) = {
val accessor = site.newMethod(module.name.toTermName, site.pos, STABLE | MODULE | NEEDS_TREES)
- moduleVarOf(accessor) = moduleVar
+ moduleOrLazyVarOf(accessor) = moduleVar
// we're in the same prefix as module, so no need for site.thisType.memberType(module)
accessor setInfo MethodType(Nil, moduleVar.info)
@@ -221,7 +283,6 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
accessor
}
-
// needed for the following scenario (T could be trait or class)
// trait T { def f: Object }; object O extends T { object f }. Need to generate method f in O.
// marking it as an ACCESSOR so that it will get to `getterBody` when synthesizing trees below
@@ -233,6 +294,15 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
}
+ private def newSuperLazy(lazyCallingSuper: Symbol, site: Type, lazyVar: Symbol) = {
+ lazyCallingSuper.asTerm.referenced = lazyVar
+
+ val tp = site.memberInfo(lazyCallingSuper)
+
+ lazyVar setInfo tp.resultType
+ lazyCallingSuper setInfo tp
+ }
+
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)
@@ -246,11 +316,16 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
if (member hasFlag ACCESSOR) {
val fieldMemoization = fieldMemoizationIn(member, clazz)
// check flags before calling makeNotPrivate
- val accessorUnderConsideration = !(member hasFlag (DEFERRED | LAZY))
+ val accessorUnderConsideration = !(member hasFlag DEFERRED)
// destructively mangle accessor's name (which may cause rehashing of decls), also sets flags
// this accessor has to be implemented in a subclass -- can't be private
- if ((member hasFlag PRIVATE) && fieldMemoization.stored) member makeNotPrivate clazz
+ if ((member hasFlag PRIVATE) && !fieldMemoization.constantTyped) member makeNotPrivate clazz
+ // Since we need to refer to `member` using a super call in a subclass, we must ensure that access is allowed.
+ // If `member` has an access boundary, make sure the `PROTECTED` flag is set,
+ // to widen from `private[foo]` to `protected[foo]`
+ // (note that `member.hasAccessBoundary` implies `!member.hasFlag(PRIVATE)`, so we don't have to `resetFlag PRIVATE`)
+ else if (member.isLazy && member.hasAccessBoundary) member setFlag PROTECTED
// This must remain in synch with publicizeTraitMethod in Mixins, so that the
// synthesized member in a subclass and the trait member remain in synch regarding access.
@@ -262,10 +337,10 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
// (not sure why this only problem only arose when we started setting the notPROTECTED flag)
// derive trait setter after calling makeNotPrivate (so that names are mangled consistently)
- if (accessorUnderConsideration && fieldMemoization.stored) {
+ if (accessorUnderConsideration && !fieldMemoization.constantTyped) {
synthesizeImplInSubclasses(member)
- if (member hasFlag STABLE) // TODO: check isGetter?
+ if ((member hasFlag STABLE) && !(member hasFlag LAZY))
newDecls += newTraitSetter(member, clazz)
}
} else if (member hasFlag MODULE) {
@@ -296,29 +371,37 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
(existingGetter ne NoSymbol) && (tp matches (site memberInfo existingGetter).resultType) // !existingGetter.isDeferred && -- see (3)
}
- def newModuleVar(member: Symbol): TermSymbol =
- newModuleVarSymbol(clazz, member, site.memberType(member).resultType, PrivateLocal | SYNTHETIC | NEEDS_TREES)
+ def newModuleVarMember(member: Symbol): TermSymbol =
+ newModuleVarSymbol(clazz, member, site.memberType(member).resultType)
+
+ def newLazyVarMember(member: Symbol): TermSymbol =
+ Fields.this.newLazyVarMember(clazz, member, site.memberType(member).resultType)
// a module does not need treatment here if it's static, unless it has a matching member in a superclass
// a non-static method needs a module var
- val modulesNeedingExpansion =
- oldDecls.toList.filter(m => m.isModule && (!m.isStatic || m.isOverridingSymbol))
+ val modulesAndLazyValsNeedingExpansion =
+ oldDecls.toList.filter(m => (m.isModule && (!m.isStatic || m.isOverridingSymbol)) || m.isLazy)
+
+ val accessorSymbolSynth = checkedAccessorSymbolSynth(tp.typeSymbol)
// expand module def in class/object (if they need it -- see modulesNeedingExpansion above)
- val expandedModules =
- modulesNeedingExpansion map { module =>
+ val expandedModulesAndLazyVals = (
+ modulesAndLazyValsNeedingExpansion flatMap { member =>
+ if (member.isLazy) {
+ List(newLazyVarMember(member), accessorSymbolSynth.newSlowPathSymbol(member))
+ }
// expanding module def (top-level or nested in static module)
- if (module.isStatic) { // implies m.isOverridingSymbol as per above filter
+ else List(if (member.isStatic) { // implies m.isOverridingSymbol as per above filter
// Need a module accessor, to implement/override a matching member in a superclass.
// Never a need for a module var if the module is static.
- newMatchingModuleAccessor(clazz, module)
+ newMatchingModuleAccessor(clazz, member)
} else {
- nonStaticModuleToMethod(module)
+ nonStaticModuleToMethod(member)
// must reuse symbol instead of creating an accessor
- module setFlag NEEDS_TREES
- newModuleVar(module)
- }
- }
+ member setFlag NEEDS_TREES
+ newModuleVarMember(member)
+ })
+ })
// println(s"expanded modules for $clazz: $expandedModules")
@@ -344,16 +427,12 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
clonedAccessor
}
- if (member hasFlag MODULE) {
- val moduleVar = newModuleVar(member)
- List(moduleVar, newModuleAccessor(member, clazz, moduleVar))
- }
// when considering whether to mix in the trait setter, forget about conflicts -- they are reported for the getter
// a trait setter for an overridden val will receive a unit body in the tree transform
- else if (nme.isTraitSetterName(member.name)) {
+ if (nme.isTraitSetterName(member.name)) {
val getter = member.getterIn(member.owner)
val clone = cloneAccessor()
-
+
setClonedTraitSetterFlags(clazz, getter, clone)
// println(s"mixed in trait setter ${clone.defString}")
@@ -362,7 +441,17 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
// don't cause conflicts, skip overridden accessors contributed by supertraits (only act on the last overriding one)
// see pos/trait_fields_dependent_conflict.scala and neg/t1960.scala
else if (accessorConflictsExistingVal(member) || isOverriddenAccessor(member, clazz)) Nil
- else if (member.isGetter && fieldMemoizationIn(member, clazz).stored) {
+ else if (member hasFlag MODULE) {
+ val moduleVar = newModuleVarMember(member)
+ List(moduleVar, newModuleAccessor(member, clazz, moduleVar))
+ }
+ else if (member hasFlag LAZY) {
+ val mixedinLazy = cloneAccessor()
+ val lazyVar = newLazyVarMember(mixedinLazy)
+ // println(s"mixing in lazy var: $lazyVar for $member")
+ List(lazyVar, accessorSymbolSynth.newSlowPathSymbol(mixedinLazy), newSuperLazy(mixedinLazy, site, lazyVar))
+ }
+ else if (member.isGetter && !fieldMemoizationIn(member, clazz).constantTyped) {
// add field if needed
val field = clazz.newValue(member.localName, member.pos) setInfo fieldTypeForGetterIn(member, clazz.thisType)
@@ -376,27 +465,34 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
} else List(cloneAccessor()) // no field needed (constant-typed getter has constant as its RHS)
}
-// println(s"mixedInAccessorAndFields for $clazz: $mixedInAccessorAndFields")
+ // println(s"mixedInAccessorAndFields for $clazz: $mixedInAccessorAndFields")
// omit fields that are not memoized, retain all other members
- def omittableField(sym: Symbol) = sym.isValue && !sym.isMethod && !fieldMemoizationIn(sym, clazz).stored
+ def omittableField(sym: Symbol) = sym.isValue && !sym.isMethod && fieldMemoizationIn(sym, clazz).constantTyped
val newDecls =
- if (expandedModules.isEmpty && mixedInAccessorAndFields.isEmpty) oldDecls.filterNot(omittableField)
+ // under -Xcheckinit we generate all kinds of bitmaps, even when there are no lazy vals
+ if (expandedModulesAndLazyVals.isEmpty && mixedInAccessorAndFields.isEmpty && !settings.checkInit)
+ oldDecls.filterNot(omittableField)
else {
// must not alter `decls` directly
val newDecls = newScope
val enter = newDecls enter (_: Symbol)
val enterAll = (_: List[Symbol]) foreach enter
+ expandedModulesAndLazyVals foreach enter
oldDecls foreach { d => if (!omittableField(d)) enter(d) }
- expandedModules foreach enter
mixedInAccessorAndFields foreach enterAll
+ // both oldDecls and mixedInAccessorAndFields (a list of lists) contribute
+ val bitmapSyms = accessorSymbolSynth.computeBitmapInfos(newDecls.toList)
+
+ bitmapSyms foreach enter
+
newDecls
}
-// println(s"new decls for $clazz: $expandedModules ++ $mixedInAccessorAndFields")
+ // println(s"new decls for $clazz: $expandedModules ++ $mixedInAccessorAndFields")
if (newDecls eq oldDecls) tp
else ClassInfoType(parents, newDecls, clazz)
@@ -408,53 +504,123 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
// done by uncurry's info transformer
// instead of forcing every member's info to run said transformer, duplicate the flag update logic...
- def nonStaticModuleToMethod(module: Symbol): Unit = {
+ def nonStaticModuleToMethod(module: Symbol): Unit =
if (!module.isStatic) module setFlag METHOD | STABLE
- }
- class FieldsTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
- def mkTypedUnit(pos: Position) = localTyper.typedPos(pos)(CODE.UNIT)
- def deriveUnitDef(stat: Tree) = deriveDefDef(stat)(_ => mkTypedUnit(stat.pos))
-
- def mkAccessor(accessor: Symbol)(body: Tree) = localTyper.typedPos(accessor.pos)(DefDef(accessor, body)).asInstanceOf[DefDef]
+ class FieldsTransformer(unit: CompilationUnit) extends TypingTransformer(unit) with CheckedAccessorTreeSynthesis {
+ protected def typedPos(pos: Position)(tree: Tree): Tree = localTyper.typedPos(pos)(tree)
- def mkField(sym: Symbol) = localTyper.typedPos(sym.pos)(ValDef(sym)).asInstanceOf[ValDef]
+ def mkTypedUnit(pos: Position) = typedPos(pos)(CODE.UNIT)
+ // TODO: clean up. this method is not used
+ def deriveUnitDef(stat: Tree) = deriveDefDef(stat)(_ => mkTypedUnit(stat.pos))
+ def mkAccessor(accessor: Symbol)(body: Tree) = typedPos(accessor.pos)(DefDef(accessor, body)).asInstanceOf[DefDef]
+
+ // this makes trees for mixed in fields, as well as for bitmap fields (their RHS will be EmptyTree because they are initialized implicitly)
+ // if we decide to explicitly initialize, use this RHS: if (symbol.info.typeSymbol.asClass == BooleanClass) FALSE else ZERO)
+ // could detect it's a bitmap field with something like `sym.name.startsWith(nme.BITMAP_PREFIX)` (or perhaps something more robust...)
+ def mkTypedValDef(sym: Symbol, rhs: Tree = EmptyTree) = typedPos(sym.pos)(ValDef(sym, rhs)).asInstanceOf[ValDef]
+
+ /**
+ * Desugar a local `lazy val x: Int = rhs` into
+ * ```
+ * val x$lzy = new scala.runtime.LazyInt()
+ * def x$lzycompute(): Int =
+ * x$lzy.synchronized {
+ * if (x$lzy.initialized()) x$lzy.value()
+ * else x$lzy.initialize(rhs) // for a Unit-typed lazy val, this becomes `{ rhs ; x$lzy.initialize() }` to avoid passing around BoxedUnit
+ * }
+ * def x(): Int = if (x$lzy.initialized()) x$lzy.value() else x$lzycompute()
+ * ```
+ */
+ private def mkLazyLocalDef(lazyVal: Symbol, rhs: Tree): Tree = {
+ import CODE._
+ import scala.reflect.NameTransformer.LAZY_LOCAL_SUFFIX_STRING
+ val owner = lazyVal.owner
+
+ val lazyValType = lazyVal.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
+
+ // 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
+
+ // 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
+ // Must be marked LAZY to allow forward references, as in `def test2 { println(s.length) ; lazy val s = "abc" }
+ val holderSym = owner.newValue(localLazyName, pos, LAZY | ARTIFACT) setInfo refTpe
+
+ val initializedSym = refTpe.member(nme.initialized)
+ val initializeSym = refTpe.member(nme.initialize)
+
+ // LazyUnit does not have a `value` member
+ val valueSym = if (isUnit) NoSymbol else refTpe.member(nme.value)
+
+ def initialized = Select(Ident(holderSym), initializedSym)
+ def initialize = Select(Ident(holderSym), initializeSym)
+ def getValue = if (isUnit) UNIT else Apply(Select(Ident(holderSym), valueSym), Nil)
+
+ val computerSym =
+ owner.newMethod(lazyName append nme.LAZY_SLOW_SUFFIX, pos, ARTIFACT | PRIVATE) setInfo MethodType(Nil, lazyValType)
+
+ val rhsAtComputer = rhs.changeOwner(lazyVal -> 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)(
+ If(initialized, getValue,
+ Apply(Ident(computerSym), Nil)))
+
+ // do last!
+ // 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)
+
+ Thicket(mkTypedValDef(holderSym, New(refTpe)) :: computer :: accessor :: Nil)
+ }
// 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): Option[Tree] = {
+ 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) Some(Select(This(clazz), field))
- else None
+ if (field.exists) List(Select(This(clazz), field))
+ else Nil
}
- def getterBody(getter: Symbol): Option[Tree] = {
+ def getterBody(getter: Symbol): List[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) {
- Some(gen.mkAttributedRef(clazz.thisType, getter.asTerm.referenced))
+ List(gen.mkAttributedRef(clazz.thisType, getter.asTerm.referenced))
} else {
val fieldMemoization = fieldMemoizationIn(getter, clazz)
- if (fieldMemoization.pureConstant) Some(gen.mkAttributedQualifier(fieldMemoization.tp)) // TODO: drop when we no longer care about producing identical bytecode
+ if (fieldMemoization.constantTyped) List(gen.mkAttributedQualifier(fieldMemoization.tp)) // TODO: drop when we no longer care about producing identical bytecode
else fieldAccess(getter)
}
}
// println(s"accessorsAndFieldsNeedingTrees for $templateSym: $accessorsAndFieldsNeedingTrees")
- def setterBody(setter: Symbol): Option[Tree] = {
+ def setterBody(setter: Symbol): List[Tree] = {
// trait setter in trait
- if (clazz.isTrait) Some(EmptyTree)
+ if (clazz.isTrait) List(EmptyTree)
// trait setter for overridden val in class
- else if (checkAndClearOverriddenTraitSetter(setter)) Some(mkTypedUnit(setter.pos))
+ else if (checkAndClearOverriddenTraitSetter(setter)) List(mkTypedUnit(setter.pos))
// trait val/var setter mixed into class
else fieldAccess(setter) map (fieldSel => Assign(fieldSel, Ident(setter.firstParam)))
}
- def moduleAccessorBody(module: Symbol): Some[Tree] = Some(
+ def moduleAccessorBody(module: Symbol): List[Tree] = List(
// 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
@@ -462,11 +628,20 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
else moduleInit(module)
)
+ 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)
+ explodeThicket(synthAccessorInClass.expandLazyClassMember(lazyVarOf(getter), getter, rhs, Map.empty)).asInstanceOf[List[ValOrDefDef]]
+ }
+
clazz.info.decls.toList.filter(checkAndClearNeedsTrees) flatMap {
case module if module hasAllFlags (MODULE | METHOD) => moduleAccessorBody(module) map mkAccessor(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(mkField(field)) // vals/vars and module vars (cannot have flags PACKAGE | JAVA since those never receive NEEDS_TREES)
+ 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
}
}
@@ -474,10 +649,8 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
def rhsAtOwner(stat: ValOrDefDef, newOwner: Symbol): Tree =
atOwner(newOwner)(super.transform(stat.rhs.changeOwner(stat.symbol -> newOwner)))
-
- private def Thicket(trees: List[Tree]) = Block(trees, EmptyTree)
override def transform(stat: Tree): Tree = {
- val clazz = currentOwner
+ val currOwner = currentOwner // often a class, but not necessarily
val statSym = stat.symbol
/*
@@ -500,22 +673,37 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
// also remove ACCESSOR flag since there won't be an underlying field to access?
case DefDef(_, _, _, _, _, rhs) if (statSym hasFlag ACCESSOR)
&& (rhs ne EmptyTree) && !excludedAccessorOrFieldByFlags(statSym)
- && !clazz.isTrait // we've already done this for traits.. the asymmetry will be solved by the above todo
- && fieldMemoizationIn(statSym, clazz).pureConstant =>
- deriveDefDef(stat)(_ => gen.mkAttributedQualifier(rhs.tpe)) // TODO: recurse?
+ && !currOwner.isTrait // we've already done this for traits.. the asymmetry will be solved by the above todo
+ && fieldMemoizationIn(statSym, currOwner).constantTyped =>
+ deriveDefDef(stat)(_ => gen.mkAttributedQualifier(rhs.tpe))
+
+ // deferred val, trait val, lazy val (local or in class)
+ case vd@ValDef(mods, name, tpt, rhs) if vd.symbol.hasFlag(ACCESSOR) && treeInfo.noFieldFor(vd, currOwner) =>
+ val transformedRhs = atOwner(statSym)(transform(rhs))
+
+ if (rhs == EmptyTree) mkAccessor(statSym)(EmptyTree)
+ else if (currOwner.isTrait) mkAccessor(statSym)(transformedRhs)
+ else if (!currOwner.isClass) mkLazyLocalDef(vd.symbol, transformedRhs)
+ else {
+ // TODO: make `synthAccessorInClass` a field and update it in atOwner?
+ // note that `LazyAccessorTreeSynth` is pretty lightweight
+ // (it's just a bunch of methods that all take a `clazz` parameter, which is thus stored as a field)
+ val synthAccessorInClass = new SynthLazyAccessorsIn(currOwner)
+ synthAccessorInClass.expandLazyClassMember(lazyVarOf(statSym), statSym, transformedRhs, nullables.getOrElse(currOwner, Map.empty))
+ }
// 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, clazz).pureConstant =>
- EmptyTree
+ && fieldMemoizationIn(statSym, currOwner).constantTyped =>
+ EmptyThicket
case ModuleDef(_, _, impl) =>
// ??? The typer doesn't take kindly to seeing this ClassDef; we have to set NoType so it will be ignored.
val cd = super.transform(ClassDef(statSym.moduleClass, impl) setType NoType)
- if (clazz.isClass) cd
+ if (currOwner.isClass) cd
else { // local module -- symbols cannot be generated by info transformer, so do it all here
- val moduleVar = newModuleVarSymbol(currentOwner, statSym, statSym.info.resultType, 0)
- Thicket(cd :: mkField(moduleVar) :: mkAccessor(statSym)(moduleInit(statSym)) :: Nil)
+ val moduleVar = newModuleVarSymbol(currOwner, statSym, statSym.info.resultType)
+ Thicket(cd :: mkTypedValDef(moduleVar) :: mkAccessor(statSym)(moduleInit(statSym)) :: Nil)
}
case tree =>
@@ -524,26 +712,29 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
}
}
+
def transformTermsAtExprOwner(exprOwner: Symbol)(stat: Tree) =
if (stat.isTerm) atOwner(exprOwner)(transform(stat))
else transform(stat)
+ private val nullables = perRunCaches.newMap[Symbol, Map[Symbol, List[Symbol]]]
+
override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = {
val addedStats =
- if (!currentOwner.isClass) Nil
+ if (!currentOwner.isClass) Nil // TODO: || currentOwner.isPackageClass
else afterOwnPhase { fieldsAndAccessors(currentOwner) }
+ val inRealClass = currentOwner.isClass && !(currentOwner.isPackageClass || currentOwner.isTrait)
+ if (inRealClass)
+ nullables(currentOwner) = lazyValNullables(currentOwner, stats)
+
val newStats =
stats mapConserve (if (exprOwner != currentOwner) transformTermsAtExprOwner(exprOwner) else transform)
addedStats ::: (if (newStats eq stats) stats else {
// check whether we need to flatten thickets and drop empty ones
- if (newStats exists { case EmptyTree => true case Block(_, EmptyTree) => true case _ => false })
- newStats flatMap {
- case EmptyTree => Nil
- case Block(thicket, EmptyTree) => thicket
- case stat => stat :: Nil
- }
+ if (newStats exists mustExplodeThicket)
+ newStats flatMap explodeThicket
else newStats
})
}
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
deleted file mode 100644
index fc7999bf3b..0000000000
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ /dev/null
@@ -1,318 +0,0 @@
-package scala.tools.nsc
-package transform
-
-import scala.collection.mutable
-
-abstract class LazyVals extends Transform with TypingTransformers with ast.TreeDSL {
- // inherits abstract value `global` and class `Phase` from Transform
-
- import global._ // the global environment
- import definitions._ // standard classes and methods
- import typer.typed // methods to type trees
- import CODE._
-
- val phaseName: String = "lazyvals"
- private val FLAGS_PER_BYTE: Int = 8 // Byte
- private def bitmapKind = ByteClass
-
- def newTransformer(unit: CompilationUnit): Transformer =
- new LazyValues(unit)
-
- private def lazyUnit(sym: Symbol) = sym.tpe.resultType.typeSymbol == UnitClass
-
- object LocalLazyValFinder extends Traverser {
- var result: Boolean = _
-
- def find(t: Tree) = {result = false; traverse(t); result}
- def find(ts: List[Tree]) = {result = false; traverseTrees(ts); result}
-
- override def traverse(t: Tree) {
- if (!result)
- t match {
- case v@ValDef(_, _, _, _) if v.symbol.isLazy =>
- result = true
-
- case d@DefDef(_, _, _, _, _, _) if d.symbol.isLazy && lazyUnit(d.symbol) =>
- d.symbol.resetFlag(symtab.Flags.LAZY)
- result = true
-
- case ClassDef(_, _, _, _) | DefDef(_, _, _, _, _, _) | ModuleDef(_, _, _) =>
-
- // Avoid adding bitmaps when they are fully overshadowed by those that are added inside loops
- case LabelDef(name, _, _) if nme.isLoopHeaderLabel(name) =>
-
- case _ =>
- super.traverse(t)
- }
- }
- }
-
- /**
- * Transform local lazy accessors to check for the initialized bit.
- */
- class LazyValues(unit: CompilationUnit) extends TypingTransformer(unit) {
- /** map from method symbols to the number of lazy values it defines. */
- private val lazyVals = perRunCaches.newMap[Symbol, Int]() withDefaultValue 0
-
- import symtab.Flags._
- private def flattenThickets(stats: List[Tree]): List[Tree] = stats.flatMap(_ match {
- case b @ Block(List(d1@DefDef(_, n1, _, _, _, _)), d2@DefDef(_, n2, _, _, _, _)) if b.tpe == null && n1.endsWith(nme.LAZY_SLOW_SUFFIX) =>
- List(d1, d2)
- case stat =>
- List(stat)
- })
-
- /** Perform the following transformations:
- * - for a lazy accessor inside a method, make it check the initialization bitmap
- * - implement double checked locking of member modules for non-trait owners (trait just have the abstract accessor)
- * ```
- * // typer
- * class C { object x }
- * // fields
- * class C { var x$module; def x() = { x$module = new x; x$module }
- * // lazyvals
- * class C {
- * var x$module // module var
- * def x() = { if (x$module == null) x$lzycompute() else x$module // fast path
- * def x$lzycompute() = { synchronized { if (x$module == null) x$module = new x }; x$module } // slow path
- * }
- * ```
- * - for all methods, add enough int vars to allow one flag per lazy local value
- * - blocks in template bodies behave almost like methods. A single bitmaps section is
- * added in the first block, for all lazy values defined in such blocks.
- * - remove ACCESSOR flags: accessors in traits are not statically implemented,
- * but moved to the host class. local lazy values should be statically implemented.
- */
- override def transform(tree: Tree): Tree = {
- val sym = tree.symbol
- curTree = tree
-
- tree match {
-
- case Block(_, _) =>
- val block1 = super.transform(tree)
- val Block(stats, expr) = block1
- treeCopy.Block(block1, flattenThickets(stats), expr)
-
- case DefDef(_, _, _, _, _, rhs) => atOwner(tree.symbol) {
- val (res, slowPathDef) = if (!sym.owner.isClass && sym.isLazy) {
- val enclosingClassOrDummyOrMethod = {
- val enclMethod = sym.enclMethod
-
- if (enclMethod != NoSymbol) {
- val enclClass = sym.enclClass
- if (enclClass != NoSymbol && enclMethod == enclClass.enclMethod)
- enclClass
- else
- enclMethod
- } else
- sym.owner
- }
- debuglog(s"determined enclosing class/dummy/method for lazy val as $enclosingClassOrDummyOrMethod given symbol $sym")
- val idx = lazyVals(enclosingClassOrDummyOrMethod)
- lazyVals(enclosingClassOrDummyOrMethod) = idx + 1
- val (rhs1, sDef) = mkLazyDef(enclosingClassOrDummyOrMethod, transform(rhs), idx, sym)
- sym.resetFlag((if (lazyUnit(sym)) 0 else LAZY) | ACCESSOR)
- (rhs1, sDef)
- } else if (sym.hasAllFlags(MODULE | METHOD) && !sym.owner.isTrait) {
- rhs match {
- case b @ Block((assign @ Assign(moduleRef, _)) :: Nil, expr) =>
- def cond = Apply(Select(moduleRef, Object_eq), List(Literal(Constant(null))))
- val (fastPath, slowPath) = mkFastPathBody(sym.owner.enclClass, moduleRef.symbol, cond, transform(assign) :: Nil, Nil, transform(expr))
- (localTyper.typedPos(tree.pos)(fastPath), localTyper.typedPos(tree.pos)(slowPath))
- case rhs =>
- global.reporter.error(tree.pos, "Unexpected tree on the RHS of a module accessor: " + rhs)
- (rhs, EmptyTree)
- }
- } else {
- (transform(rhs), EmptyTree)
- }
-
- val ddef1 = deriveDefDef(tree)(_ => if (LocalLazyValFinder.find(res)) typed(addBitmapDefs(sym, res)) else res)
- if (slowPathDef != EmptyTree) {
- // The contents of this block are flattened into the enclosing statement sequence, see flattenThickets
- // This is a poor man's version of dotty's Thicket: https://github.com/lampepfl/dotty/blob/d5280358d1/src/dotty/tools/dotc/ast/Trees.scala#L707
- Block(slowPathDef, ddef1)
- } else ddef1
- }
-
- case Template(_, _, body) => atOwner(currentOwner) {
- // TODO: shady business... can this logic be encapsulated in LocalLazyValFinder?
- var added = false
- val stats = super.transformTrees(body) mapConserve {
- case stat: ValDef => typed(deriveValDef(stat)(addBitmapDefs(stat.symbol, _)))
- case stat: TermTree if !added && (LocalLazyValFinder find stat) =>
- added = true
- typed(addBitmapDefs(sym, stat))
- case stat => stat
- }
-
- val innerClassBitmaps = if (!added && currentOwner.isClass && bitmaps.contains(currentOwner)) {
- // add bitmap to inner class if necessary
- val toAdd0 = bitmaps(currentOwner).map(s => typed(ValDef(s, ZERO)))
- toAdd0.foreach(t => {
- if (currentOwner.info.decl(t.symbol.name) == NoSymbol) {
- t.symbol.setFlag(PROTECTED)
- currentOwner.info.decls.enter(t.symbol)
- }
- })
- toAdd0
- } else List()
- deriveTemplate(tree)(_ => innerClassBitmaps ++ flattenThickets(stats))
- }
-
- case ValDef(_, _, _, _) if !sym.owner.isModule && !sym.owner.isClass =>
- deriveValDef(tree) { rhs0 =>
- val rhs = transform(rhs0)
- if (LocalLazyValFinder.find(rhs)) typed(addBitmapDefs(sym, rhs)) else rhs
- }
-
- case l@LabelDef(name0, params0, ifp0@If(_, _, _)) if name0.startsWith(nme.WHILE_PREFIX) =>
- val ifp1 = super.transform(ifp0)
- val If(cond0, thenp0, elsep0) = ifp1
-
- if (LocalLazyValFinder.find(thenp0))
- deriveLabelDef(l)(_ => treeCopy.If(ifp1, cond0, typed(addBitmapDefs(sym.owner, thenp0)), elsep0))
- else
- l
-
- case l@LabelDef(name0, params0, block@Block(stats0, expr))
- if name0.startsWith(nme.WHILE_PREFIX) || name0.startsWith(nme.DO_WHILE_PREFIX) =>
- val stats1 = super.transformTrees(stats0)
- if (LocalLazyValFinder.find(stats1))
- deriveLabelDef(l)(_ => treeCopy.Block(block, typed(addBitmapDefs(sym.owner, stats1.head))::stats1.tail, expr))
- else
- l
-
- case _ => super.transform(tree)
- }
- }
-
- /** Add the bitmap definitions to the rhs of a method definition.
- * If the rhs has been tail-call transformed, insert the bitmap
- * definitions inside the top-level label definition, so that each
- * iteration has the lazy values uninitialized. Otherwise add them
- * at the very beginning of the method.
- */
- private def addBitmapDefs(methSym: Symbol, rhs: Tree): Tree = {
- def prependStats(stats: List[Tree], tree: Tree): Block = tree match {
- case Block(stats1, res) => Block(stats ::: stats1, res)
- case _ => Block(stats, tree)
- }
-
- val bmps = bitmaps(methSym) map (ValDef(_, ZERO))
-
- def isMatch(params: List[Ident]) = (params.tail corresponds methSym.tpe.params)(_.tpe == _.tpe)
-
- if (bmps.isEmpty) rhs else rhs match {
- case Block(assign, l @ LabelDef(name, params, _))
- if (name string_== "_" + methSym.name) && isMatch(params) =>
- Block(assign, deriveLabelDef(l)(rhs => typed(prependStats(bmps, rhs))))
-
- case _ => prependStats(bmps, rhs)
- }
- }
-
- def mkSlowPathDef(clazz: Symbol, lzyVal: Symbol, cond: Tree, syncBody: List[Tree],
- stats: List[Tree], retVal: Tree): Tree = {
- val owner = lzyVal.owner
- val defSym = owner.newMethod(nme.newLazyValSlowComputeName(lzyVal.name.toTermName), lzyVal.pos, STABLE | PRIVATE)
- defSym setInfo MethodType(List(), lzyVal.tpe.resultType)
- if (owner.isClass) owner.info.decls.enter(defSym)
- debuglog(s"crete slow compute path $defSym with owner ${defSym.owner} for lazy val $lzyVal")
- // this is a hack i don't understand for lazy vals nested in a lazy val, introduced in 3769f4d,
- // tested in pos/t3670 (add9be64). class A { val n = { lazy val b = { lazy val dd = 3; dd }; b } }
- // bitmaps has an entry bMethodSym -> List(bitmap$0), where bitmap$0.owner == bMethodSym.
- // now we set bitmap$0.owner = b$lzycomputeMethodSym.
- for (bitmap <- bitmaps(lzyVal)) bitmap.owner = defSym
- val rhs: Tree = gen.mkSynchronizedCheck(clazz, cond, syncBody, stats).changeOwner(currentOwner -> defSym)
-
- DefDef(defSym, addBitmapDefs(lzyVal, BLOCK(rhs, retVal)))
- }
-
-
- def mkFastPathBody(clazz: Symbol, lzyVal: Symbol, cond: => Tree, syncBody: List[Tree],
- stats: List[Tree], retVal: Tree): (Tree, Tree) = {
- val slowPathDef: Tree = mkSlowPathDef(clazz, lzyVal, cond, syncBody, stats, retVal)
- (If(cond, Apply(Ident(slowPathDef.symbol), Nil), retVal), slowPathDef)
- }
-
- /** return a 'lazified' version of rhs. Rhs should conform to the
- * following schema:
- * {
- * l$ = <rhs>
- * l$
- * } or
- * <rhs> when the lazy value has type Unit (for which there is no field
- * to cache its value.
- *
- * Similarly as for normal lazy val members (see Mixin), the result will be a tree of the form
- * { if ((bitmap&n & MASK) == 0) this.l$compute()
- * else l$
- *
- * def l$compute() = { synchronized(enclosing_class_or_dummy) {
- * if ((bitmap$n & MASK) == 0) {
- * l$ = <rhs>
- * bitmap$n = bimap$n | MASK
- * }}
- * l$
- * }
- * }
- * where bitmap$n is a byte value acting as a bitmap of initialized values. It is
- * the 'n' is (offset / 8), the MASK is (1 << (offset % 8)). If the value has type
- * unit, no field is used to cache the value, so the l$compute will now look as following:
- * {
- * def l$compute() = { synchronized(enclosing_class_or_dummy) {
- * if ((bitmap$n & MASK) == 0) {
- * <rhs>;
- * bitmap$n = bimap$n | MASK
- * }}
- * ()
- * }
- * }
- */
- private def mkLazyDef(methOrClass: Symbol, tree: Tree, offset: Int, lazyVal: Symbol): (Tree, Tree) = {
- val bitmapSym = getBitmapFor(methOrClass, offset)
- val mask = LIT(1 << (offset % FLAGS_PER_BYTE))
- val bitmapRef = if (methOrClass.isClass) Select(This(methOrClass), bitmapSym) else Ident(bitmapSym)
-
- def mkBlock(stmt: Tree) = BLOCK(stmt, mkSetFlag(bitmapSym, mask, bitmapRef), UNIT)
-
- debuglog(s"create complete lazy def in $methOrClass for $lazyVal")
- val (block, res) = tree match {
- case Block(List(assignment), res) if !lazyUnit(lazyVal) =>
- (mkBlock(assignment), res)
- case rhs =>
- (mkBlock(rhs), UNIT)
- }
-
- def cond = (bitmapRef GEN_& (mask, bitmapKind)) GEN_== (ZERO, bitmapKind)
- val lazyDefs = mkFastPathBody(methOrClass.enclClass, lazyVal, cond, List(block), Nil, res)
- (atPos(tree.pos)(localTyper.typed {lazyDefs._1 }), atPos(tree.pos)(localTyper.typed {lazyDefs._2 }))
- }
-
- private def mkSetFlag(bmp: Symbol, mask: Tree, bmpRef: Tree): Tree =
- bmpRef === (bmpRef GEN_| (mask, bitmapKind))
-
- val bitmaps = mutable.Map[Symbol, List[Symbol]]() withDefaultValue Nil
-
- /** Return the symbol corresponding of the right bitmap int inside meth,
- * given offset.
- */
- private def getBitmapFor(meth: Symbol, offset: Int): Symbol = {
- val n = offset / FLAGS_PER_BYTE
- val bmps = bitmaps(meth)
- if (bmps.length > n)
- bmps(n)
- else {
- val sym = meth.newVariable(nme.newBitmapName(nme.BITMAP_NORMAL, n), meth.pos).setInfo(ByteTpe)
- enteringTyper {
- sym addAnnotation VolatileAttr
- }
-
- bitmaps(meth) = (sym :: bmps).reverse
- sym
- }
- }
- }
-}
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index f781426f1a..582c51b90d 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -1,5 +1,6 @@
/* NSC -- new Scala compiler
- * Copyright 2005-2013 LAMP/EPFL
+ * Copyright 2005-2016 LAMP/EPFL and Lightbend, Inc
+ *
* @author Martin Odersky
*/
@@ -9,13 +10,14 @@ package transform
import symtab._
import Flags._
import scala.annotation.tailrec
-import scala.collection.mutable
-abstract class Mixin extends InfoTransform with ast.TreeDSL {
+
+abstract class Mixin extends InfoTransform with ast.TreeDSL with AccessorSynthesis {
import global._
import definitions._
import CODE._
+
/** The name of the phase: */
val phaseName: String = "mixin"
@@ -57,8 +59,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
*/
private val treatedClassInfos = perRunCaches.newMap[Symbol, Type]() withDefaultValue NoType
- /** Map a lazy, mixedin field accessor to its trait member accessor */
- private val initializer = perRunCaches.newMap[Symbol, Symbol]()
// --------- helper functions -----------------------------------------------
@@ -71,47 +71,22 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* (private modules, on the other hand, are implemented statically, but their
* module variable is not. all such private modules are lifted, because
* non-lifted private modules have been eliminated in ExplicitOuter)
- * - field accessors and superaccessors, except for lazy value accessors which become initializer
- * methods in the impl class (because they can have arbitrary initializers)
+ * - field accessors and superaccessors
*/
private def isImplementedStatically(sym: Symbol) = (
(sym.isMethod || ((sym hasFlag MODULE) && !sym.isStatic))
+ // TODO: ^^^ non-static modules should have been turned into methods by fields by now, no? maybe the info transformer hasn't run???
&& notDeferred(sym)
&& sym.owner.isTrait
&& (!sym.isModule || sym.hasFlag(PRIVATE | LIFTED))
- && (!(sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.isLazy)
+ && (!(sym hasFlag (ACCESSOR | SUPERACCESSOR)) || (sym hasFlag LAZY))
&& !sym.isPrivate
&& !sym.hasAllFlags(LIFTED | MODULE | METHOD)
&& !sym.isConstructor
&& (!sym.hasFlag(notPRIVATE | LIFTED) || sym.hasFlag(ACCESSOR | SUPERACCESSOR | MODULE))
)
- private def isFieldWithBitmap(field: Symbol) = {
- field.info // ensure that nested objects are transformed
- // For checkinit consider normal value getters
- // but for lazy values only take into account lazy getters
- field.isLazy && field.isMethod && !field.isDeferred
- }
- /** Does this field require an initialized bit?
- * Note: fields of classes inheriting DelayedInit are not checked.
- * This is because they are neither initialized in the constructor
- * nor do they have a setter (not if they are vals anyway). The usual
- * logic for setting bitmaps does therefore not work for such fields.
- * That's why they are excluded.
- * Note: The `checkinit` option does not check if transient fields are initialized.
- */
- private def needsInitFlag(sym: Symbol) = (
- settings.checkInit
- && sym.isGetter
- && !sym.isInitializedToDefault
- && !isConstantType(sym.info.finalResultType) // SI-4742
- && !sym.hasFlag(PARAMACCESSOR | SPECIALIZED | LAZY)
- && !sym.accessed.hasFlag(PRESUPER)
- && !sym.isOuterAccessor
- && !(sym.owner isSubClass DelayedInitClass)
- && !(sym.accessed hasAnnotation TransientAttr)
- )
/** Returns the symbol that is accessed by a super-accessor in a mixin composition.
*
@@ -156,7 +131,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
)
}
- private def isUnitGetter(sym: Symbol) = sym.tpe.resultType.typeSymbol == UnitClass
/** Add given member to given class, and mark member as mixed-in.
*/
@@ -207,9 +181,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
else {
assert(member.isTerm && !member.isDeferred, member)
// disable assert to support compiling against code compiled by an older compiler (until we re-starr)
- // assert(member hasFlag LAZY | PRESUPER, s"unexpected $member in $clazz ${member.debugFlagString}")
- // lazy vals still leave field symbols lying around in traits -- TODO: never emit them to begin with
- // ditto for early init vals
+ // assert(member hasFlag PRESUPER, s"unexpected $member in $clazz ${member.debugFlagString}")
clazz.info.decls.unlink(member)
}
@@ -243,51 +215,59 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
case NoSymbol =>
val isMemberOfClazz = clazz.info.findMember(member.name, 0, 0L, stableOnly = false).alternatives.contains(member)
if (isMemberOfClazz) {
- def genForwarder(): Unit = {
- cloneAndAddMixinMember(mixinClass, member).asInstanceOf[TermSymbol] setAlias member
+ def genForwarder(required: Boolean): Unit = {
+ val owner = member.owner
+ if (owner.isJavaDefined && owner.isInterface && !clazz.parentSymbols.contains(owner)) {
+ val text = s"Unable to implement a mixin forwarder for $member in $clazz unless interface ${owner.name} is directly extended by $clazz."
+ if (required) reporter.error(clazz.pos, text)
+ else warning(clazz.pos, text)
+ } else
+ cloneAndAddMixinMember(mixinClass, member).asInstanceOf[TermSymbol] setAlias member
+ }
+
+ // `member` is a concrete method defined in `mixinClass`, which is a base class of
+ // `clazz`, and the method is not overridden in `clazz`. A forwarder is needed if:
+ //
+ // - A non-trait base class of `clazz` defines a matching method. Example:
+ // class C {def f: Int}; trait T extends C {def f = 1}; class D extends T
+ // Even if C.f is abstract, the forwarder in D is needed, otherwise the JVM would
+ // resolve `D.f` to `C.f`, see jvms-6.5.invokevirtual.
+ //
+ // - There exists another concrete, matching method in a parent interface `p` of
+ // `clazz`, and the `mixinClass` does not itself extend `p`. In this case the
+ // forwarder is needed to disambiguate. Example:
+ // trait T1 {def f = 1}; trait T2 extends T1 {override def f = 2}; class C extends T2
+ // In C we don't need a forwarder for f because T2 extends T1, so the JVM resolves
+ // C.f to T2.f non-ambiguously. See jvms-5.4.3.3, "maximally-specific method".
+ // trait U1 {def f = 1}; trait U2 {self:U1 => override def f = 2}; class D extends U2
+ // In D the forwarder is needed, the interfaces U1 and U2 are unrelated at the JVM
+ // level.
+
+ @tailrec
+ def existsCompetingMethod(baseClasses: List[Symbol]): Boolean = baseClasses match {
+ case baseClass :: rest =>
+ if (baseClass ne mixinClass) {
+ val m = member.overriddenSymbol(baseClass)
+ val isCompeting = m.exists && {
+ !m.owner.isTraitOrInterface ||
+ (!m.isDeferred && !mixinClass.isNonBottomSubClass(m.owner))
+ }
+ isCompeting || existsCompetingMethod(rest)
+ } else existsCompetingMethod(rest)
+
+ case _ => false
}
- if (settings.XgenMixinForwarders) genForwarder()
- else {
-
- // `member` is a concrete method defined in `mixinClass`, which is a base class of
- // `clazz`, and the method is not overridden in `clazz`. A forwarder is needed if:
- //
- // - A non-trait base class of `clazz` defines a matching method. Example:
- // class C {def f: Int}; trait T extends C {def f = 1}; class D extends T
- // Even if C.f is abstract, the forwarder in D is needed, otherwise the JVM would
- // resolve `D.f` to `C.f`, see jvms-6.5.invokevirtual.
- //
- // - There exists another concrete, matching method in a parent interface `p` of
- // `clazz`, and the `mixinClass` does not itself extend `p`. In this case the
- // forwarder is needed to disambiguate. Example:
- // trait T1 {def f = 1}; trait T2 extends T1 {override def f = 2}; class C extends T2
- // In C we don't need a forwarder for f because T2 extends T1, so the JVM resolves
- // C.f to T2.f non-ambiguously. See jvms-5.4.3.3, "maximally-specific method".
- // trait U1 {def f = 1}; trait U2 {self:U1 => override def f = 2}; class D extends U2
- // In D the forwarder is needed, the interfaces U1 and U2 are unrelated at the JVM
- // level.
-
- @tailrec
- def existsCompetingMethod(baseClasses: List[Symbol]): Boolean = baseClasses match {
- case baseClass :: rest =>
- if (baseClass ne mixinClass) {
- val m = member.overriddenSymbol(baseClass)
- val isCompeting = m.exists && {
- !m.owner.isTraitOrInterface ||
- (!m.isDeferred && !mixinClass.isNonBottomSubClass(m.owner))
- }
- isCompeting || existsCompetingMethod(rest)
- } else existsCompetingMethod(rest)
-
- case _ => false
- }
-
- if (existsCompetingMethod(clazz.baseClasses))
- genForwarder()
- else if (!settings.nowarnDefaultJunitMethods && JUnitTestClass.exists && member.hasAnnotation(JUnitTestClass))
- warning(member.pos, "JUnit tests in traits that are compiled as default methods are not executed by JUnit 4. JUnit 5 will fix this issue.")
+ def generateJUnitForwarder: Boolean = {
+ settings.mixinForwarderChoices.isJunit &&
+ member.annotations.nonEmpty &&
+ JUnitAnnotations.exists(annot => annot.exists && member.hasAnnotation(annot))
}
+
+ if (existsCompetingMethod(clazz.baseClasses) || generateJUnitForwarder)
+ genForwarder(required = true)
+ else if (settings.mixinForwarderChoices.isTruthy)
+ genForwarder(required = false)
}
case _ =>
@@ -295,9 +275,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
}
- /* Mix in members of trait mixinClass into class clazz. Also,
- * for each lazy field in mixinClass, add a link from its mixed in member to its
- * initializer method inside the implclass.
+ /* Mix in members of trait mixinClass into class clazz.
*/
def mixinTraitMembers(mixinClass: Symbol) {
// For all members of a trait's interface do:
@@ -319,28 +297,15 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
}
else if (mixinMember.hasFlag(ACCESSOR) && notDeferred(mixinMember)
- && (mixinMember hasFlag (LAZY | PARAMACCESSOR))
+ && (mixinMember hasFlag PARAMACCESSOR)
&& !isOverriddenAccessor(mixinMember, clazz.info.baseClasses)) {
- // pick up where `fields` left off -- it already mixed in fields and accessors for regular vals.
- // but has ignored lazy vals and constructor parameter accessors
- // TODO: captures added by lambdalift for local traits?
- //
- // mixin accessor for lazy val or constructor parameter
+ // mixin accessor for constructor parameter
// (note that a paramaccessor cannot have a constant type as it must have a user-defined type)
- val mixedInAccessor = cloneAndAddMixinMember(mixinClass, mixinMember)
+ cloneAndAddMixinMember(mixinClass, mixinMember)
+
val name = mixinMember.name
- if (mixinMember.isLazy)
- initializer(mixedInAccessor) =
- (mixinClass.info.decl(name) orElse abort(s"Could not find initializer for lazy val $name!"))
-
- // Add field while we're mixing in the getter (unless it's a Unit-typed lazy val)
- //
- // lazy val of type Unit doesn't need a field -- the bitmap is enough.
- // TODO: constant-typed lazy vals... it's an extreme corner case, but we could also suppress the field in:
- // `trait T { final lazy val a = "a" }; class C extends T`, but who writes code like that!? :)
- // we'd also have to change the lazyvals logic if we do this
- if (!nme.isSetterName(name) && !(mixinMember.isLazy && isUnitGetter(mixinMember))) {
+ if (!nme.isSetterName(name)) {
// enteringPhase: the private field is moved to the implementation class by erasure,
// so it can no longer be found in the mixinMember's owner (the trait)
val accessed = enteringPickler(mixinMember.accessed)
@@ -354,7 +319,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val newFlags = (
(PrivateLocal)
- | (mixinMember getFlag MUTABLE | LAZY)
+ | (mixinMember getFlag MUTABLE)
| (if (mixinMember.hasStableFlag) 0 else MUTABLE)
)
@@ -384,82 +349,20 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
override def transformInfo(sym: Symbol, tp: Type): Type = tp
- /** Return a map of single-use fields to the lazy value that uses them during initialization.
- * Each field has to be private and defined in the enclosing class, and there must
- * be exactly one lazy value using it.
- *
- * Such fields will be nulled after the initializer has memoized the lazy value.
- */
- def singleUseFields(templ: Template): scala.collection.Map[Symbol, List[Symbol]] = {
- val usedIn = mutable.HashMap[Symbol, List[Symbol]]() withDefaultValue Nil
-
- object SingleUseTraverser extends Traverser {
- override def traverse(tree: Tree) {
- tree match {
- case Assign(lhs, rhs) => traverse(rhs) // assignments don't count
- case _ =>
- if (tree.hasSymbolField && tree.symbol != NoSymbol) {
- val sym = tree.symbol
- if ((sym.hasAccessorFlag || (sym.isTerm && !sym.isMethod))
- && sym.isPrivate
- && !(currentOwner.isGetter && currentOwner.accessed == sym) // getter
- && !definitions.isPrimitiveValueClass(sym.tpe.resultType.typeSymbol)
- && sym.owner == templ.symbol.owner
- && !sym.isLazy
- && !tree.isDef) {
- debuglog("added use in: " + currentOwner + " -- " + tree)
- usedIn(sym) ::= currentOwner
-
- }
- }
- super.traverse(tree)
- }
- }
- }
- SingleUseTraverser(templ)
- debuglog("usedIn: " + usedIn)
- usedIn filter {
- case (_, member :: Nil) => member.isValue && member.isLazy
- case _ => false
- }
- }
-
// --------- term transformation -----------------------------------------------
protected def newTransformer(unit: CompilationUnit): Transformer =
new MixinTransformer(unit)
- class MixinTransformer(unit : CompilationUnit) extends Transformer {
+ class MixinTransformer(unit : CompilationUnit) extends Transformer with AccessorTreeSynthesis {
+ /** The typer */
+ private var localTyper: erasure.Typer = _
+ protected def typedPos(pos: Position)(tree: Tree): Tree = localTyper.typedPos(pos)(tree)
/** The rootContext used for typing */
private val rootContext =
erasure.NoContext.make(EmptyTree, rootMirror.RootClass, newScope)
- /** The typer */
- private var localTyper: erasure.Typer = _
- private def typedPos(pos: Position)(tree: Tree): Tree = localTyper.typedPos(pos)(tree)
-
- /** Map lazy values to the fields they should null after initialization. */
- private var lazyValNullables: Map[Symbol, Set[Symbol]] = _
-
- /** Map a field symbol to a unique integer denoting its position in the class layout.
- * For each class, fields defined by the class come after inherited fields. Mixed-in
- * fields count as fields defined by the class itself.
- */
- private val fieldOffset = perRunCaches.newMap[Symbol, Int]()
-
- private val bitmapKindForCategory = perRunCaches.newMap[Name, ClassSymbol]()
-
- // ByteClass, IntClass, LongClass
- private def bitmapKind(field: Symbol): ClassSymbol = bitmapKindForCategory(bitmapCategory(field))
-
- private def flagsPerBitmap(field: Symbol): Int = bitmapKind(field) match {
- case BooleanClass => 1
- case ByteClass => 8
- case IntClass => 32
- case LongClass => 64
- }
-
/** The first transform; called in a pre-order traversal at phase mixin
* (that is, every node is processed before its children).
@@ -484,416 +387,24 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
}
- def needsInitAndHasOffset(sym: Symbol) =
- needsInitFlag(sym) && (fieldOffset contains sym)
-
- /** Examines the symbol and returns a name indicating what brand of
- * bitmap it requires. The possibilities are the BITMAP_* vals
- * defined in StdNames. If it needs no bitmap, nme.NO_NAME.
- */
- def bitmapCategory(field: Symbol): Name = {
- import nme._
- val isNormal = (
- if (isFieldWithBitmap(field)) true
- // bitmaps for checkinit fields are not inherited
- else if (needsInitFlag(field) && !field.isDeferred) false
- else return NO_NAME
- )
- if (field.accessed hasAnnotation TransientAttr) {
- if (isNormal) BITMAP_TRANSIENT
- else BITMAP_CHECKINIT_TRANSIENT
- } else {
- if (isNormal) BITMAP_NORMAL
- else BITMAP_CHECKINIT
- }
- }
/** Add all new definitions to a non-trait class
- * These fall into the following categories:
- * - for a trait interface:
- * - abstract accessors for all fields in the implementation class
- * - for a non-trait class:
- * - A field for every in a mixin class
- * - Setters and getters for such fields
- * - getters for mixed in lazy fields are completed
- * - module variables and module creators for every module in a mixin class
- * (except if module is lifted -- in this case the module variable
- * is local to some function, and the creator method is static.)
- * - A super accessor for every super accessor in a mixin class
- * - Forwarders for all methods that are implemented statically
- * All superaccessors are completed with right-hand sides (@see completeSuperAccessor)
- *
- * @param clazz The class to which definitions are added
- */
+ *
+ * These fall into the following categories:
+ * - for a trait interface:
+ * - abstract accessors for all paramaccessor or early initialized fields
+ * - for a non-trait class:
+ * - field and accessor implementations for each inherited paramaccessor or early initialized field
+ * - A super accessor for every super accessor in a mixin class
+ * - Forwarders for all methods that are implemented statically
+ *
+ * All superaccessors are completed with right-hand sides (@see completeSuperAccessor)
+ *
+ * @param clazz The class to which definitions are added
+ */
private def addNewDefs(clazz: Symbol, stats: List[Tree]): List[Tree] = {
- val newDefs = mutable.ListBuffer[Tree]()
-
- /* Attribute given tree and anchor at given position */
- def attributedDef(pos: Position, tree: Tree): Tree = {
- debuglog("add new def to " + clazz + ": " + tree)
- typedPos(pos)(tree)
- }
-
- /* The position of given symbol, or, if this is undefined,
- * the position of the current class.
- */
- def position(sym: Symbol) =
- if (sym.pos == NoPosition) clazz.pos else sym.pos
-
- /* Add tree at given position as new definition */
- def addDef(pos: Position, tree: Tree) {
- newDefs += attributedDef(pos, tree)
- }
-
- /* Add new method definition.
- *
- * @param sym The method symbol.
- * @param rhs The method body.
- */
- def addDefDef(sym: Symbol, rhs: Tree = EmptyTree) = addDef(position(sym), DefDef(sym, rhs))
- def addValDef(sym: Symbol, rhs: Tree = EmptyTree) = addDef(position(sym), ValDef(sym, rhs))
-
- /* Add `newdefs` to `stats`, removing any abstract method definitions
- * in `stats` that are matched by some symbol defined in
- * `newDefs`.
- */
- def add(stats: List[Tree], newDefs: List[Tree]) = {
- val newSyms = newDefs map (_.symbol)
- def isNotDuplicate(tree: Tree) = tree match {
- case DefDef(_, _, _, _, _, _) =>
- val sym = tree.symbol
- !(sym.isDeferred &&
- (newSyms exists (nsym => nsym.name == sym.name && (nsym.tpe matches sym.tpe))))
- case _ =>
- true
- }
- if (newDefs.isEmpty) stats
- else newDefs ::: (stats filter isNotDuplicate)
- }
-
- /* If `stat` is a superaccessor, complete it by adding a right-hand side.
- * Note: superaccessors are always abstract until this point.
- * The method to call in a superaccessor is stored in the accessor symbol's alias field.
- * The rhs is:
- * super.A(xs) where A is the super accessor's alias and xs are its formal parameters.
- * This rhs is typed and then mixin transformed.
- */
- def completeSuperAccessor(stat: Tree) = stat match {
- case DefDef(_, _, _, vparams :: Nil, _, EmptyTree) if stat.symbol.isSuperAccessor =>
- val body = atPos(stat.pos)(Apply(SuperSelect(clazz, stat.symbol.alias), vparams map (v => Ident(v.symbol))))
- val pt = stat.symbol.tpe.resultType
-
- copyDefDef(stat)(rhs = enteringMixin(transform(localTyper.typed(body, pt))))
- case _ =>
- stat
- }
-
- /*
- * Return the bitmap field for 'offset'. Depending on the hierarchy it is possible to reuse
- * the bitmap of its parents. If that does not exist yet we create one.
- */
- def bitmapFor(clazz0: Symbol, offset: Int, field: Symbol): Symbol = {
- val category = bitmapCategory(field)
- val bitmapName = nme.newBitmapName(category, offset / flagsPerBitmap(field)).toTermName
- val sym = clazz0.info.decl(bitmapName)
-
- assert(!sym.isOverloaded, sym)
-
- def createBitmap: Symbol = {
- val bitmapKind = bitmapKindForCategory(category)
- val sym = clazz0.newVariable(bitmapName, clazz0.pos) setInfo bitmapKind.tpe
- enteringTyper(sym addAnnotation VolatileAttr)
-
- category match {
- case nme.BITMAP_TRANSIENT | nme.BITMAP_CHECKINIT_TRANSIENT => sym addAnnotation TransientAttr
- case _ =>
- }
- val init = bitmapKind match {
- case BooleanClass => ValDef(sym, FALSE)
- case _ => ValDef(sym, ZERO)
- }
-
- sym setFlag PrivateLocal
- clazz0.info.decls.enter(sym)
- addDef(clazz0.pos, init)
- sym
- }
-
- sym orElse createBitmap
- }
-
- def maskForOffset(offset: Int, sym: Symbol, kind: ClassSymbol): Tree = {
- def realOffset = offset % flagsPerBitmap(sym)
- if (kind == LongClass ) LIT(1L << realOffset) else LIT(1 << realOffset)
- }
-
- /* Return an (untyped) tree of the form 'Clazz.this.bmp = Clazz.this.bmp | mask'. */
- def mkSetFlag(clazz: Symbol, offset: Int, valSym: Symbol, kind: ClassSymbol): Tree = {
- val bmp = bitmapFor(clazz, offset, valSym)
- def mask = maskForOffset(offset, valSym, kind)
- def x = This(clazz) DOT bmp
- def newValue = if (kind == BooleanClass) TRUE else (x GEN_| (mask, kind))
-
- x === newValue
- }
-
- /* Return an (untyped) tree of the form 'clazz.this.bitmapSym & mask (==|!=) 0', the
- * precise comparison operator depending on the value of 'equalToZero'.
- */
- def mkTest(clazz: Symbol, mask: Tree, bitmapSym: Symbol, equalToZero: Boolean, kind: ClassSymbol): Tree = {
- val bitmapTree = (This(clazz) DOT bitmapSym)
- def lhs = bitmapTree GEN_& (mask, kind)
- kind match {
- case BooleanClass =>
- if (equalToZero) NOT(bitmapTree)
- else bitmapTree
- case _ =>
- if (equalToZero) lhs GEN_== (ZERO, kind)
- else lhs GEN_!= (ZERO, kind)
- }
- }
-
- def mkSlowPathDef(clazz: Symbol, lzyVal: Symbol, cond: Tree, syncBody: List[Tree],
- stats: List[Tree], retVal: Tree, attrThis: Tree, args: List[Tree]): Symbol = {
- val defSym = clazz.newMethod(nme.newLazyValSlowComputeName(lzyVal.name.toTermName), lzyVal.pos, PRIVATE)
- val params = defSym newSyntheticValueParams args.map(_.symbol.tpe)
- defSym setInfoAndEnter MethodType(params, lzyVal.tpe.resultType)
- val rhs: Tree = gen.mkSynchronizedCheck(attrThis, cond, syncBody, stats).changeOwner(currentOwner -> defSym)
- val strictSubst = new TreeSymSubstituterWithCopying(args.map(_.symbol), params)
- addDef(position(defSym), DefDef(defSym, strictSubst(BLOCK(rhs, retVal))))
- defSym
- }
-
- def mkFastPathLazyBody(clazz: Symbol, lzyVal: Symbol, cond: => Tree, syncBody: List[Tree],
- stats: List[Tree], retVal: Tree): Tree = {
- mkFastPathBody(clazz, lzyVal, cond, syncBody, stats, retVal, gen.mkAttributedThis(clazz), List())
- }
-
- def mkFastPathBody(clazz: Symbol, lzyVal: Symbol, cond: => Tree, syncBody: List[Tree],
- stats: List[Tree], retVal: Tree, attrThis: Tree, args: List[Tree]): Tree = {
- val slowPathSym: Symbol = mkSlowPathDef(clazz, lzyVal, cond, syncBody, stats, retVal, attrThis, args)
- If(cond, fn (This(clazz), slowPathSym, args.map(arg => Ident(arg.symbol)): _*), retVal)
- }
-
-
- /* Always copy the tree if we are going to perform sym substitution,
- * otherwise we will side-effect on the tree that is used in the fast path
- */
- class TreeSymSubstituterWithCopying(from: List[Symbol], to: List[Symbol]) extends TreeSymSubstituter(from, to) {
- override def transform(tree: Tree): Tree =
- if (tree.hasSymbolField && from.contains(tree.symbol))
- super.transform(tree.duplicate)
- else super.transform(tree.duplicate)
-
- override def apply[T <: Tree](tree: T): T = if (from.isEmpty) tree else super.apply(tree)
- }
-
- /* return a 'lazified' version of rhs. It uses double-checked locking to ensure
- * initialization is performed at most once. For performance reasons the double-checked
- * locking is split into two parts, the first (fast) path checks the bitmap without
- * synchronizing, and if that fails it initializes the lazy val within the
- * synchronization block (slow path). This way the inliner should optimize
- * the fast path because the method body is small enough.
- * Private fields used only in this initializer are subsequently set to null.
- *
- * @param clazz The class symbol
- * @param lzyVal The symbol of this lazy field
- * @param init The tree which initializes the field ( f = <rhs> )
- * @param offset The offset of this field in the flags bitmap
- *
- * The result will be a tree of the form
- * { if ((bitmap&n & MASK) == 0) this.l$compute()
- * else l$
- *
- * ...
- * def l$compute() = { synchronized(this) {
- * if ((bitmap$n & MASK) == 0) {
- * init // l$ = <rhs>
- * bitmap$n = bimap$n | MASK
- * }}
- * l$
- * }
- *
- * ...
- * this.f1 = null
- * ... this.fn = null
- * }
- * where bitmap$n is a byte, int or long value acting as a bitmap of initialized values.
- * The kind of the bitmap determines how many bit indicators for lazy vals are stored in it.
- * For Int bitmap it is 32 and then 'n' in the above code is: (offset / 32),
- * the MASK is (1 << (offset % 32)).
- * If the class contains only a single lazy val then the bitmap is represented
- * as a Boolean and the condition checking is a simple bool test.
- */
- def mkLazyDef(clazz: Symbol, lzyVal: Symbol, init: List[Tree], retVal: Tree, offset: Int): Tree = {
- def nullify(sym: Symbol) = Select(This(clazz), sym.accessedOrSelf) === LIT(null)
-
- val bitmapSym = bitmapFor(clazz, offset, lzyVal)
- val kind = bitmapKind(lzyVal)
- val mask = maskForOffset(offset, lzyVal, kind)
- def cond = mkTest(clazz, mask, bitmapSym, equalToZero = true, kind)
- val nulls = lazyValNullables(lzyVal).toList sortBy (_.id) map nullify
- def syncBody = init ::: List(mkSetFlag(clazz, offset, lzyVal, kind), UNIT)
-
- if (nulls.nonEmpty)
- log("nulling fields inside " + lzyVal + ": " + nulls)
-
- typedPos(init.head.pos)(mkFastPathLazyBody(clazz, lzyVal, cond, syncBody, nulls, retVal))
- }
-
- def mkCheckedAccessor(clazz: Symbol, retVal: Tree, offset: Int, pos: Position, fieldSym: Symbol): Tree = {
- val sym = fieldSym.getterIn(fieldSym.owner)
- val bitmapSym = bitmapFor(clazz, offset, sym)
- val kind = bitmapKind(sym)
- val mask = maskForOffset(offset, sym, kind)
- val msg = s"Uninitialized field: ${unit.source}: ${pos.line}"
- val result =
- IF (mkTest(clazz, mask, bitmapSym, equalToZero = false, kind)) .
- THEN (retVal) .
- ELSE (Throw(NewFromConstructor(UninitializedFieldConstructor, LIT(msg))))
-
- typedPos(pos)(BLOCK(result, retVal))
- }
-
- /* Complete lazy field accessors. Applies only to classes,
- * for its own (non inherited) lazy fields. If 'checkinit'
- * is enabled, getters that check for the initialized bit are
- * generated, and the class constructor is changed to set the
- * initialized bits.
- */
- def addCheckedGetters(clazz: Symbol, stats: List[Tree]): List[Tree] = {
- def dd(stat: DefDef) = {
- val sym = stat.symbol
- def isEmpty = stat.rhs == EmptyTree
-
- if (!clazz.isTrait && sym.isLazy && !isEmpty) {
- assert(fieldOffset contains sym, sym)
- deriveDefDef(stat) {
- case t if isUnitGetter(sym) => mkLazyDef(clazz, sym, List(t), UNIT, fieldOffset(sym))
-
- case Block(stats, res) =>
- mkLazyDef(clazz, sym, stats, Select(This(clazz), res.symbol), fieldOffset(sym))
-
- case t => t // pass specialized lazy vals through
- }
- }
- else if (needsInitFlag(sym) && !isEmpty && !clazz.hasFlag(TRAIT)) {
- assert(fieldOffset contains sym, sym)
- deriveDefDef(stat)(rhs =>
- (mkCheckedAccessor(clazz, _: Tree, fieldOffset(sym), stat.pos, sym))(
- if (isUnitGetter(sym)) UNIT else rhs
- )
- )
- }
- else if (sym.isConstructor) {
- deriveDefDef(stat)(addInitBits(clazz, _))
- }
- else if (settings.checkInit && !clazz.isTrait && sym.isSetter) {
- val getter = sym.getterIn(clazz)
- if (needsInitFlag(getter) && fieldOffset.isDefinedAt(getter))
- deriveDefDef(stat)(rhs => Block(List(rhs, localTyper.typed(mkSetFlag(clazz, fieldOffset(getter), getter, bitmapKind(getter)))), UNIT))
- else stat
- }
- else stat
- }
- stats map {
- case defn: DefDef => dd(defn)
- case stat => stat
- }
- }
-
- class AddInitBitsTransformer(clazz: Symbol) extends Transformer {
- private def checkedGetter(lhs: Tree) = {
- val sym = clazz.info decl lhs.symbol.getterName suchThat (_.isGetter)
- if (needsInitAndHasOffset(sym)) {
- debuglog("adding checked getter for: " + sym + " " + lhs.symbol.flagString)
- List(localTyper typed mkSetFlag(clazz, fieldOffset(sym), sym, bitmapKind(sym)))
- }
- else Nil
- }
- override def transformStats(stats: List[Tree], exprOwner: Symbol) = {
- // !!! Ident(self) is never referenced, is it supposed to be confirming
- // that self is anything in particular?
- super.transformStats(
- stats flatMap {
- case stat @ Assign(lhs @ Select(This(_), _), rhs) => stat :: checkedGetter(lhs)
- // remove initialization for default values
- case Apply(lhs @ Select(Ident(self), _), EmptyTree.asList) if lhs.symbol.isSetter => Nil
- case stat => List(stat)
- },
- exprOwner
- )
- }
- }
-
- /* Adds statements to set the 'init' bit for each field initialized
- * in the body of a constructor.
- */
- def addInitBits(clazz: Symbol, rhs: Tree): Tree =
- new AddInitBitsTransformer(clazz) transform rhs
-
- // begin addNewDefs
-
- /* Fill the map from fields to offset numbers.
- * Instead of field symbols, the map keeps their getter symbols. This makes
- * code generation easier later.
- */
- def buildBitmapOffsets() {
- def fold(fields: List[Symbol], category: Name) = {
- var idx = 0
- fields foreach { f =>
- fieldOffset(f) = idx
- idx += 1
- }
-
- if (idx == 0) ()
- else if (idx == 1) bitmapKindForCategory(category) = BooleanClass
- else if (idx < 9) bitmapKindForCategory(category) = ByteClass
- else if (idx < 33) bitmapKindForCategory(category) = IntClass
- else bitmapKindForCategory(category) = LongClass
- }
- clazz.info.decls.toList groupBy bitmapCategory foreach {
- case (nme.NO_NAME, _) => ()
- case (category, fields) => fold(fields, category)
- }
- }
- buildBitmapOffsets()
- var stats1 = addCheckedGetters(clazz, stats)
-
- def getterBody(getter: Symbol) = {
- assert(getter.isGetter)
- val readValue =
- if (getter.isLazy) {
- getter.tpe.resultType match {
- case ConstantType(c) => Literal(c)
- case _ =>
- val initCall = Apply(SuperSelect(clazz, initializer(getter)), Nil)
- val offset = fieldOffset(getter)
- if (isUnitGetter(getter)) mkLazyDef(clazz, getter, List(initCall), UNIT, offset)
- else mkLazyDef(clazz, getter, List(atPos(getter.pos)(Assign(fieldAccess(getter), initCall))), fieldAccess(getter), offset)
- }
- } else {
- assert(getter.hasFlag(PARAMACCESSOR))
- fieldAccess(getter)
- }
-
- if (!needsInitFlag(getter)) readValue
- else mkCheckedAccessor(clazz, readValue, fieldOffset(getter), getter.pos, getter)
- }
-
- def setterBody(setter: Symbol) = {
- val getter = setter.getterIn(clazz)
- assert(getter.hasFlag(PARAMACCESSOR), s"missing implementation for non-paramaccessor $setter in $clazz")
-
- val setInitFlag =
- if (!needsInitFlag(getter)) Nil
- else List(mkSetFlag(clazz, fieldOffset(getter), getter, bitmapKind(getter)))
-
- Block(Assign(fieldAccess(setter), Ident(setter.firstParam)) :: setInitFlag : _*)
- }
-
- def fieldAccess(accessor: Symbol) = Select(This(clazz), accessor.accessed)
-
+ val accessorSynth = new UncheckedAccessorSynth(clazz)
+ import accessorSynth._
// for all symbols `sym` in the class definition, which are mixed in by mixinTraitMembers
for (sym <- clazz.info.decls ; if sym hasFlag MIXEDIN) {
@@ -902,10 +413,10 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
if (clazz.isTrait || sym.isSuperAccessor) addDefDef(sym)
// implement methods mixed in from a supertrait (the symbols were created by mixinTraitMembers)
else if (sym.hasFlag(ACCESSOR) && !sym.hasFlag(DEFERRED)) {
- assert(sym hasFlag (LAZY | PARAMACCESSOR), s"mixed in $sym from $clazz is not lazy/param?!?")
+ assert(sym hasFlag (PARAMACCESSOR), s"mixed in $sym from $clazz is not param?!?")
// add accessor definitions
- addDefDef(sym, if (sym.isSetter) setterBody(sym) else getterBody(sym))
+ addDefDef(sym, accessorBody(sym))
}
else if (!sym.isMethod) addValDef(sym) // field
else if (!sym.isMacro) { // forwarder
@@ -915,32 +426,33 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
}
}
- stats1 = add(stats1, newDefs.toList)
+ val implementedAccessors = implementWithNewDefs(stats)
- if (clazz.isTrait) stats1 = stats1.filter {
- case vd: ValDef =>
- assert(vd.symbol.hasFlag(PRESUPER | PARAMACCESSOR | LAZY), s"unexpected valdef $vd in trait $clazz")
- false
+ if (clazz.isTrait)
+ implementedAccessors filter {
+ case vd: ValDef => assert(vd.symbol.hasFlag(PRESUPER | PARAMACCESSOR), s"unexpected valdef $vd in trait $clazz"); false
case _ => true
}
+ else {
+ /* If `stat` is a superaccessor, complete it by adding a right-hand side.
+ * Note: superaccessors are always abstract until this point.
+ * The method to call in a superaccessor is stored in the accessor symbol's alias field.
+ * The rhs is:
+ * super.A(xs) where A is the super accessor's alias and xs are its formal parameters.
+ * This rhs is typed and then mixin transformed.
+ */
+ def completeSuperAccessor(stat: Tree) = stat match {
+ case DefDef(_, _, _, vparams :: Nil, _, EmptyTree) if stat.symbol.isSuperAccessor =>
+ val body = atPos(stat.pos)(Apply(SuperSelect(clazz, stat.symbol.alias), vparams map (v => Ident(v.symbol))))
+ val pt = stat.symbol.tpe.resultType
+
+ copyDefDef(stat)(rhs = enteringMixin(transform(localTyper.typed(body, pt))))
+ case _ =>
+ stat
+ }
- if (!clazz.isTrait) stats1 = stats1 map completeSuperAccessor
-
- stats1
- }
-
- private def nullableFields(templ: Template): Map[Symbol, Set[Symbol]] = {
- val scope = templ.symbol.owner.info.decls
- // if there are no lazy fields, take the fast path and save a traversal of the whole AST
- if (scope exists (_.isLazy)) {
- val map = mutable.Map[Symbol, Set[Symbol]]() withDefaultValue Set()
- // check what fields can be nulled for
- for ((field, users) <- singleUseFields(templ); lazyFld <- users if !lazyFld.accessed.hasAnnotation(TransientAttr))
- map(lazyFld) += field
-
- map.toMap
+ implementedAccessors map completeSuperAccessor
}
- else Map()
}
/** The transform that gets applied to a tree after it has been completely
@@ -961,8 +473,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
case templ @ Template(parents, self, body) =>
// change parents of templates to conform to parents in the symbol info
val parents1 = currentOwner.info.parents map (t => TypeTree(t) setPos tree.pos)
- // mark fields which can be nulled afterward
- lazyValNullables = nullableFields(templ) withDefaultValue Set()
+
// add all new definitions to current class or interface
val statsWithNewDefs = addNewDefs(currentOwner, body)
statsWithNewDefs foreach {
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 87c14eb3a1..c171050bbd 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -723,7 +723,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
} else if (!sClass.isTrait && m.isMethod && m.hasFlag(LAZY)) {
forwardToOverload(m)
- } else if (m.isValue && !m.isMethod && !m.hasFlag(LAZY)) { // concrete value definition
+ } else if (m.isValue && !m.isMethod) { // concrete value definition
def mkAccessor(field: Symbol, name: Name) = {
val newFlags = (SPECIALIZED | m.getterIn(clazz).flags) & ~(LOCAL | CASEACCESSOR | PARAMACCESSOR)
// we rely on the super class to initialize param accessors
@@ -744,7 +744,14 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
enterMember(specVal)
// create accessors
- if (nme.isLocalName(m.name)) {
+ if (m.isLazy) {
+ // no getters needed (we'll specialize the compute method and accessor separately), can stay private
+ // m.setFlag(PRIVATE) -- TODO: figure out how to leave the non-specialized lazy var private
+ // (the implementation needs it to be visible while duplicating and retypechecking,
+ // but it really could be private in bytecode)
+ specVal.setFlag(PRIVATE)
+ }
+ else if (nme.isLocalName(m.name)) {
val specGetter = mkAccessor(specVal, specVal.getterName) setInfo MethodType(Nil, specVal.info)
val origGetter = overrideIn(sClass, m.getterIn(clazz))
info(origGetter) = Forward(specGetter)
diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
index fa7c503213..744b9c8a8e 100644
--- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala
+++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala
@@ -274,10 +274,8 @@ abstract class TailCalls extends Transform {
import runDefinitions.{Boolean_or, Boolean_and}
tree match {
- case ValDef(_, _, _, _) =>
- if (tree.symbol.isLazy && tree.symbol.hasAnnotation(TailrecClass))
- reporter.error(tree.pos, "lazy vals are not tailcall transformed")
-
+ case dd: DefDef if tree.symbol.isLazy && tree.symbol.hasAnnotation(TailrecClass) =>
+ reporter.error(tree.pos, "lazy vals are not tailcall transformed")
super.transform(tree)
case dd @ DefDef(_, name, _, vparamss0, _, rhs0) if isEligible(dd) =>
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 6ade45c41c..f6c667353f 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -439,9 +439,9 @@ abstract class UnCurry extends InfoTransform
super.transform(treeCopy.DefDef(dd, mods, name, tparams, vparamssNoRhs, tpt, rhs))
}
}
- case ValDef(_, _, _, rhs) =>
+ case ValDef(mods, _, _, rhs) =>
if (sym eq NoSymbol) throw new IllegalStateException("Encountered Valdef without symbol: "+ tree + " in "+ unit)
- if (!sym.owner.isSourceMethod)
+ if (!sym.owner.isSourceMethod || mods.isLazy)
withNeedLift(needLift = true) { super.transform(tree) }
else
super.transform(tree)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
index 78e72cf771..df014b5161 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
@@ -151,8 +151,12 @@ abstract class Duplicators extends Analyzer {
ldef.symbol = newsym
debuglog("newsym: " + newsym + " info: " + newsym.info)
- case vdef @ ValDef(mods, name, _, rhs) if mods.hasFlag(Flags.LAZY) =>
- debuglog("ValDef " + name + " sym.info: " + vdef.symbol.info)
+ // don't retypecheck val members or local lazy vals -- you'll end up with duplicate symbols because
+ // entering a valdef results in synthesizing getters etc
+ // TODO: why retype check any valdefs?? I checked and the rhs is specialized just fine this way
+ // (and there are no args/type params/... to warrant full type checking?)
+ case vdef @ ValDef(mods, name, _, rhs) if mods.hasFlag(Flags.LAZY) || owner.isClass =>
+ debuglog(s"ValDef $name in $owner sym.info: ${vdef.symbol.info}")
invalidSyms(vdef.symbol) = vdef
val newowner = owner orElse context.owner
val newsym = vdef.symbol.cloneSymbol(newowner)
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index e0b64a7600..d11417192d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -5,6 +5,7 @@
package scala.tools.nsc
package typechecker
+import scala.reflect.NameTransformer
import symtab.Flags._
import scala.reflect.internal.util.StringOps.ojoin
import scala.reflect.internal.util.ListOfNil
@@ -116,38 +117,53 @@ trait MethodSynthesis {
import NamerErrorGen._
- def enterImplicitWrapper(tree: ClassDef): Unit = {
- enterSyntheticSym(ImplicitClassWrapper(tree).derivedTree)
- }
- // trees are later created by addDerivedTrees (common logic is encapsulated in field/standardAccessors/beanAccessors)
+ import treeInfo.noFieldFor
+
+ // populate synthetics for this unit with trees that will later be added by the typer
+ // we get here when entering the symbol for the valdef, so its rhs has not yet been type checked
def enterGetterSetter(tree: ValDef): Unit = {
+ val fieldSym =
+ if (noFieldFor(tree, owner)) NoSymbol
+ else owner.newValue(tree.name append NameTransformer.LOCAL_SUFFIX_STRING, tree.pos, tree.mods.flags & FieldFlags | PrivateLocal)
+
val getter = Getter(tree)
val getterSym = getter.createSym
- val setterSym = if (getter.needsSetter) Setter(tree).createSym else NoSymbol
-
- // a lazy field is linked to its lazy accessor (TODO: can we do the same for field -> getter -> setter)
- val fieldSym = if (Field.noFieldFor(tree)) NoSymbol else Field(tree).createSym(getterSym)
// only one symbol can have `tree.pos`, the others must focus their position
// normally the field gets the range position, but if there is none, give it to the getter
tree.symbol = fieldSym orElse (getterSym setPos tree.pos)
+ val namer = namerOf(tree.symbol)
+
+ // the valdef gets the accessor symbol for a lazy val (too much going on in its RHS)
+ // the fields phase creates the field symbol
+ if (!tree.mods.isLazy) {
+ // if there's a field symbol, the getter is considered a synthetic that must be added later
+ // if there's no field symbol, the ValDef tree receives the getter symbol and thus is not a synthetic
+ if (fieldSym != NoSymbol) {
+ context.unit.synthetics(getterSym) = getter.derivedTree(getterSym)
+ getterSym setInfo namer.accessorTypeCompleter(tree, tree.tpt.isEmpty, isBean = false, isSetter = false)
+ } else getterSym setInfo namer.valTypeCompleter(tree)
+
+ enterInScope(getterSym)
+
+ if (getter.needsSetter) {
+ val setter = Setter(tree)
+ val setterSym = setter.createSym
+ context.unit.synthetics(setterSym) = setter.derivedTree(setterSym)
+ setterSym setInfo namer.accessorTypeCompleter(tree, tree.tpt.isEmpty, isBean = false, isSetter = true)
+ enterInScope(setterSym)
+ }
- val namer = if (fieldSym != NoSymbol) namerOf(fieldSym) else namerOf(getterSym)
-
- // There's no reliable way to detect all kinds of setters from flags or name!!!
- // A BeanSetter's name does not end in `_=` -- it does begin with "set", but so could the getter
- // for a regular Scala field... TODO: can we add a flag to distinguish getter/setter accessors?
- val getterCompleter = namer.accessorTypeCompleter(tree, isSetter = false)
- val setterCompleter = namer.accessorTypeCompleter(tree, isSetter = true)
-
- getterSym setInfo getterCompleter
- setterSym andAlso (_ setInfo setterCompleter)
- fieldSym andAlso (_ setInfo namer.valTypeCompleter(tree))
-
- enterInScope(getterSym)
- setterSym andAlso (enterInScope(_))
- fieldSym andAlso (enterInScope(_))
+ // TODO: delay emitting the field to the fields phase (except for private[this] vals, which only get a field and no accessors)
+ if (fieldSym != NoSymbol) {
+ fieldSym setInfo namer.valTypeCompleter(tree)
+ enterInScope(fieldSym)
+ }
+ } else {
+ getterSym setInfo namer.valTypeCompleter(tree)
+ enterInScope(getterSym)
+ }
deriveBeanAccessors(tree, namer)
}
@@ -188,242 +204,82 @@ trait MethodSynthesis {
sym
}
- val getterCompleter = namer.beanAccessorTypeCompleter(tree, missingTpt, isSetter = false)
+ val getterCompleter = namer.accessorTypeCompleter(tree, missingTpt, isBean = true, isSetter = false)
enterInScope(deriveBeanAccessor(if (hasBeanProperty) "get" else "is") setInfo getterCompleter)
if (tree.mods.isMutable) {
- val setterCompleter = namer.beanAccessorTypeCompleter(tree, missingTpt, isSetter = true)
+ val setterCompleter = namer.accessorTypeCompleter(tree, missingTpt, isBean = true, isSetter = true)
enterInScope(deriveBeanAccessor("set") setInfo setterCompleter)
}
}
}
- import AnnotationInfo.{mkFilter => annotationFilter}
- def addDerivedTrees(typer: Typer, stat: Tree): List[Tree] = stat match {
- case vd @ ValDef(mods, name, tpt, rhs) if deriveAccessors(vd) && !vd.symbol.isModuleVar && !vd.symbol.isJava =>
- stat.symbol.initialize // needed!
-
- val getter = Getter(vd)
- getter.validate()
- val accessors = getter :: (if (getter.needsSetter) Setter(vd) :: Nil else Nil)
- (Field(vd) :: accessors).map(_.derivedTree).filter(_ ne EmptyTree)
-
- case cd @ ClassDef(mods, _, _, _) if mods.isImplicit =>
- val annotations = stat.symbol.initialize.annotations
- // TODO: need to shuffle annotations between wrapper and class.
- val wrapper = ImplicitClassWrapper(cd)
- val meth = wrapper.derivedSym
- context.unit.synthetics get meth match {
- case Some(mdef) =>
- context.unit.synthetics -= meth
- meth setAnnotations (annotations filter annotationFilter(MethodTargetClass, defaultRetention = false))
- cd.symbol setAnnotations (annotations filter annotationFilter(ClassTargetClass, defaultRetention = true))
- List(cd, mdef)
- case _ =>
- // Shouldn't happen, but let's give ourselves a reasonable error when it does
- context.error(cd.pos, s"Internal error: Symbol for synthetic factory method not found among ${context.unit.synthetics.keys.mkString(", ")}")
- // Soldier on for the sake of the presentation compiler
- List(cd)
- }
- case _ =>
- stat :: Nil
- }
-
-
- sealed trait Derived {
- /** The derived symbol. It is assumed that this symbol already exists and has been
- * entered in the parent scope when derivedSym is called
- */
- def derivedSym: Symbol
-
- /** The definition tree of the derived symbol. */
- def derivedTree: Tree
+ def enterImplicitWrapper(classDef: ClassDef): Unit = {
+ val methDef = factoryMeth(classDef.mods & AccessFlags | METHOD | IMPLICIT | SYNTHETIC, classDef.name.toTermName, classDef)
+ val methSym = assignAndEnterSymbol(methDef)
+ context.unit.synthetics(methSym) = methDef
+ methSym setInfo implicitFactoryMethodCompleter(methDef, classDef.symbol, completerOf(methDef).asInstanceOf[LockingTypeCompleter])
}
- /** A synthetic method which performs the implicit conversion implied by
- * the declaration of an implicit class.
- */
- case class ImplicitClassWrapper(tree: ClassDef) extends Derived {
- def derivedSym = {
- val enclClass = tree.symbol.owner.enclClass
- // Only methods will do! Don't want to pick up any stray
- // companion objects of the same name.
- val result = enclClass.info decl derivedName filter (x => x.isMethod && x.isSynthetic)
- if (result == NoSymbol || result.isOverloaded)
- context.error(tree.pos, s"Internal error: Unable to find the synthetic factory method corresponding to implicit class $derivedName in $enclClass / ${enclClass.info.decls}")
- result
- }
-
- def derivedTree = factoryMeth(derivedMods, derivedName, tree)
-
- def derivedName = tree.name.toTermName
- def derivedMods = tree.mods & AccessFlags | METHOD | IMPLICIT | SYNTHETIC
- }
-
- trait DerivedAccessor extends Derived {
+ trait DerivedAccessor {
def tree: ValDef
def derivedName: TermName
def derivedFlags: Long
+ def derivedTree(sym: Symbol): Tree
def derivedPos = tree.pos.focus
def createSym = createMethod(tree, derivedName, derivedPos, derivedFlags)
}
case class Getter(tree: ValDef) extends DerivedAccessor {
- def derivedName = tree.name
-
- def derivedSym =
- if (tree.mods.isLazy) tree.symbol.lazyAccessor
- else if (Field.noFieldFor(tree)) tree.symbol
- else tree.symbol.getterIn(tree.symbol.enclClass)
-
+ def derivedName = tree.name
def derivedFlags = tree.mods.flags & GetterFlags | ACCESSOR.toLong | ( if (needsSetter) 0 else STABLE )
+ def needsSetter = tree.mods.isMutable // implies !lazy
- def needsSetter = tree.mods.isMutable // implies !lazy
-
- override def derivedTree =
- if (tree.mods.isLazy) deriveLazyAccessor
- else newDefDef(derivedSym, if (Field.noFieldFor(tree)) tree.rhs else Select(This(tree.symbol.enclClass), tree.symbol))(tpt = derivedTpt)
-
- /** Implements lazy value accessors:
- * - for lazy values of type Unit and all lazy fields inside traits,
- * the rhs is the initializer itself, because we'll just "compute" the result on every access
- * ("computing" unit / constant type is free -- the side-effect is still only run once, using the init bitmap)
- * - for all other lazy values z the accessor is a block of this form:
- * { z = <rhs>; z } where z can be an identifier or a field.
- */
- private def deriveLazyAccessor: DefDef = {
- val ValDef(_, _, tpt0, rhs0) = tree
- val rhs1 = context.unit.transformed.getOrElse(rhs0, rhs0)
- val body =
- if (tree.symbol.owner.isTrait || Field.noFieldFor(tree)) rhs1 // TODO move tree.symbol.owner.isTrait into noFieldFor
- else gen.mkAssignAndReturn(tree.symbol, rhs1)
-
- derivedSym setPos tree.pos // TODO: can we propagate `tree.pos` to `derivedSym` when the symbol is created?
- val ddefRes = DefDef(derivedSym, new ChangeOwnerTraverser(tree.symbol, derivedSym)(body))
- // ValDef will have its position focused whereas DefDef will have original correct rangepos
- // ideally positions would be correct at the creation time but lazy vals are really a special case
- // here so for the sake of keeping api clean we fix positions manually in LazyValGetter
- ddefRes.tpt.setPos(tpt0.pos)
- tpt0.setPos(tpt0.pos.focus)
- ddefRes
- }
+ override def derivedTree(derivedSym: Symbol) = {
+ val missingTpt = tree.tpt.isEmpty
+ val tpt = if (missingTpt) TypeTree() else tree.tpt.duplicate
- // TODO: more principled approach -- this is a bit bizarre
- private def derivedTpt = {
- // For existentials, don't specify a type for the getter, even one derived
- // from the symbol! This leads to incompatible existentials for the field and
- // the getter. Let the typer do all the work. You might think "why only for
- // existentials, why not always," and you would be right, except: a single test
- // fails, but it looked like some work to deal with it. Test neg/t0606.scala
- // starts compiling (instead of failing like it's supposed to) because the typer
- // expects to be able to identify escaping locals in typedDefDef, and fails to
- // spot that brand of them. In other words it's an artifact of the implementation.
- //
- // JZ: ... or we could go back to uniformly using explicit result types in all cases
- // if we fix `dropExistential`. More details https://github.com/scala/scala-dev/issues/165
- val getterTp = derivedSym.tpe_*.finalResultType
- // Range position errors ensue if we don't duplicate this in some
- // circumstances (at least: concrete vals with existential types.)
- def inferredTpt = TypeTree() setOriginal (tree.tpt.duplicate setPos tree.tpt.pos.focus)
- val tpt = getterTp match {
- case _: ExistentialType => inferredTpt
- case _ => getterTp.widen match {
- case _: ExistentialType => inferredTpt
- case _ if tree.mods.isDeferred => TypeTree() setOriginal tree.tpt // keep type tree of original abstract field
- case _ => TypeTree(getterTp)
- }
- }
- tpt setPos tree.tpt.pos.focus
- }
+ val rhs =
+ if (noFieldFor(tree, owner)) tree.rhs // context.unit.transformed.getOrElse(tree.rhs, tree.rhs)
+ else Select(This(tree.symbol.enclClass), tree.symbol)
- def validate() = {
- assert(derivedSym != NoSymbol, tree)
- if (derivedSym.isOverloaded)
- GetterDefinedTwiceError(derivedSym)
+ newDefDef(derivedSym, rhs)(tparams = Nil, vparamss = Nil, tpt = tpt)
}
+// derivedSym setPos tree.pos
+// // ValDef will have its position focused whereas DefDef will have original correct rangepos
+// // ideally positions would be correct at the creation time but lazy vals are really a special case
+// // here so for the sake of keeping api clean we fix positions manually in LazyValGetter
+// tpt.setPos(tree.tpt.pos)
+// tree.tpt.setPos(tree.tpt.pos.focus)
+
}
case class Setter(tree: ValDef) extends DerivedAccessor {
def derivedName = tree.setterName
- def derivedSym = tree.symbol.setterIn(tree.symbol.enclClass)
def derivedFlags = tree.mods.flags & SetterFlags | ACCESSOR
- def derivedTree =
- derivedSym.paramss match {
- case (setterParam :: Nil) :: _ =>
- // assert(!derivedSym.isOverloaded, s"Unexpected overloaded setter $derivedSym for ${tree.symbol} in ${tree.symbol.enclClass}")
- val rhs =
- if (Field.noFieldFor(tree) || derivedSym.isOverloaded) EmptyTree
- else Assign(Select(This(tree.symbol.enclClass), tree.symbol), Ident(setterParam))
-
- DefDef(derivedSym, rhs)
- case _ => EmptyTree
- }
- }
-
- object Field {
- // No field for these vals (either never emitted or eliminated later on):
- // - abstract vals have no value we could store (until they become concrete, potentially)
- // - lazy vals of type Unit
- // - concrete vals in traits don't yield a field here either (their getter's RHS has the initial value)
- // Constructors will move the assignment to the constructor, abstracting over the field using the field setter,
- // and Fields will add a field to the class that mixes in the trait, implementing the accessors in terms of it
- // - [Emitted, later removed during Constructors] a concrete val with a statically known value (ConstantType)
- // performs its side effect according to lazy/strict semantics, but doesn't need to store its value
- // each access will "evaluate" the RHS (a literal) again
- // We would like to avoid emitting unnecessary fields, but the required knowledge isn't available until after typer.
- // The only way to avoid emitting & suppressing, is to not emit at all until we are sure to need the field, as dotty does.
- // NOTE: do not look at `vd.symbol` when called from `enterGetterSetter` (luckily, that call-site implies `!mods.isLazy`),
- // similarly, the `def field` call-site breaks when you add `|| vd.symbol.owner.isTrait` (detected in test suite)
- // as the symbol info is in the process of being created then.
- // TODO: harmonize tree & symbol creation
- // the middle `&& !owner.isTrait` is needed after `isLazy` because non-unit-typed lazy vals in traits still get a field -- see neg/t5455.scala
- def noFieldFor(vd: ValDef) = (vd.mods.isDeferred
- || (vd.mods.isLazy && !owner.isTrait && isUnitType(vd.symbol.info))
- || (owner.isTrait && !traitFieldFor(vd)))
-
- // TODO: never emit any fields in traits -- only use getter for lazy/presuper ones as well
- private def traitFieldFor(vd: ValDef): Boolean = vd.mods.hasFlag(PRESUPER | LAZY)
- }
+ def derivedTree(derivedSym: Symbol) = {
+ val setterParam = nme.syntheticParamName(1)
- case class Field(tree: ValDef) extends Derived {
- private val isLazy = tree.mods.isLazy
-
- // If the owner is not a class, this is a lazy val from a method,
- // with no associated field. It has an accessor with $lzy appended to its name and
- // its flags are set differently. The implicit flag is reset because otherwise
- // a local implicit "lazy val x" will create an ambiguity with itself
- // via "x$lzy" as can be seen in test #3927.
- private val localLazyVal = isLazy && !owner.isClass
- private val nameSuffix =
- if (!localLazyVal) reflect.NameTransformer.LOCAL_SUFFIX_STRING
- else reflect.NameTransformer.LAZY_LOCAL_SUFFIX_STRING
-
- def derivedName = tree.name.append(nameSuffix)
-
- def createSym(getter: MethodSymbol) = {
- val sym = owner.newValue(derivedName, tree.pos, derivedMods.flags)
- if (isLazy) sym setLazyAccessor getter
- sym
- }
+ // note: tree.tpt may be EmptyTree, which will be a problem when use as the tpt of a parameter
+ // the completer will patch this up (we can't do this now without completing the field)
+ val missingTpt = tree.tpt.isEmpty
+ val tptToPatch = if (missingTpt) TypeTree() else tree.tpt.duplicate
- def derivedSym = tree.symbol
+ val vparams = List(ValDef(Modifiers(PARAM | SYNTHETIC), setterParam, tptToPatch, EmptyTree))
- def derivedMods =
- if (!localLazyVal) tree.mods & FieldFlags | PrivateLocal | (if (isLazy) MUTABLE else 0)
- else (tree.mods | ARTIFACT | MUTABLE) & ~IMPLICIT
+ val tpt = TypeTree(UnitTpe)
- // TODO: why is this different from the symbol!?
- private def derivedModsForTree = tree.mods | PrivateLocal
+ val rhs =
+ if (noFieldFor(tree, owner)) EmptyTree
+ else Assign(Select(This(tree.symbol.enclClass), tree.symbol), Ident(setterParam))
- def derivedTree =
- if (Field.noFieldFor(tree)) EmptyTree
- else if (isLazy) copyValDef(tree)(mods = derivedModsForTree, name = derivedName, rhs = EmptyTree).setPos(tree.pos.focus)
- else copyValDef(tree)(mods = derivedModsForTree, name = derivedName)
+ newDefDef(derivedSym, rhs)(tparams = Nil, vparamss = List(vparams), tpt = tpt)
+ }
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 6b11dec967..0cd547c1eb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -129,6 +129,7 @@ trait Namers extends MethodSynthesis {
!(vd.name startsWith nme.OUTER) && // outer accessors are added later, in explicitouter
!isEnumConstant(vd) // enums can only occur in classes, so only check here
+
/** Determines whether this field holds an enum constant.
* To qualify, the following conditions must be met:
* - The field's class has the ENUM flag set
@@ -685,6 +686,8 @@ trait Namers extends MethodSynthesis {
if (name == nme.copy && sym.isSynthetic)
enterCopyMethod(tree)
+ else if (name == nme.apply && sym.hasAllFlags(SYNTHETIC | CASE))
+ sym setInfo caseApplyMethodCompleter(tree, completerOf(tree).asInstanceOf[LockingTypeCompleter])
else
sym setInfo completerOf(tree)
}
@@ -803,86 +806,98 @@ trait Namers extends MethodSynthesis {
import AnnotationInfo.{mkFilter => annotationFilter}
- def valTypeCompleter(tree: ValDef) = mkTypeCompleter(tree) { sym =>
- val annots =
- if (tree.mods.annotations.isEmpty) Nil
- else annotSig(tree.mods.annotations) filter annotationFilter(FieldTargetClass, !tree.mods.isParamAccessor)
+ def implicitFactoryMethodCompleter(tree: DefDef, classSym: Symbol, sigCompleter: LockingTypeCompleter) = mkTypeCompleter(tree) { methSym =>
+ sigCompleter.completeImpl(methSym)
- sym setInfo typeSig(tree, annots)
+ val annotations = classSym.initialize.annotations
- validate(sym)
+ methSym setAnnotations (annotations filter annotationFilter(MethodTargetClass, defaultRetention = false))
+ classSym setAnnotations (annotations filter annotationFilter(ClassTargetClass, defaultRetention = true))
}
- /* Explicit isSetter required for bean setters (beanSetterSym.isSetter is false) */
- def accessorTypeCompleter(tree: ValDef, isSetter: Boolean) = mkTypeCompleter(tree) { sym =>
- // println(s"triaging for ${sym.debugFlagString} $sym from $valAnnots to $annots")
-
- // typeSig calls valDefSig (because tree: ValDef)
- // sym is an accessor, while tree is the field (which may have the same symbol as the getter, or maybe it's the field)
- // TODO: can we make this work? typeSig is called on same tree (valdef) to complete info for field and all its accessors
- // reuse work done in valTypeCompleter if we already computed the type signature of the val
- // (assuming the field and accessor symbols are distinct -- i.e., we're not in a trait)
-// val valSig =
-// if ((sym ne tree.symbol) && tree.symbol.isInitialized) tree.symbol.info
-// else typeSig(tree, Nil) // don't set annotations for the valdef -- we just want to compute the type sig
+ def caseApplyMethodCompleter(tree: DefDef, sigCompleter: LockingTypeCompleter) = mkTypeCompleter(tree) { methSym =>
+ sigCompleter.completeImpl(methSym)
- val valSig = typeSig(tree, Nil) // don't set annotations for the valdef -- we just want to compute the type sig
+ // don't propagate e.g. @volatile annot to apply's argument
+ def retainOnlyParamAnnots(param: Symbol) =
+ param setAnnotations (param.annotations filter AnnotationInfo.mkFilter(ParamTargetClass, defaultRetention = false))
- val sig = accessorSigFromFieldTp(sym, isSetter, valSig)
+ methSym.info.paramss.foreach(_.foreach(retainOnlyParamAnnots))
+ }
+ // complete the type of a value definition (may have a method symbol, for those valdefs that never receive a field,
+ // as specified by Field.noFieldFor)
+ def valTypeCompleter(tree: ValDef) = mkTypeCompleter(tree) { fieldOrGetterSym =>
val mods = tree.mods
- if (mods.annotations.nonEmpty) {
- val annotSigs = annotSig(mods.annotations)
-
- // neg/t3403: check that we didn't get a sneaky type alias/renamed import that we couldn't detect because we only look at names during synthesis
- // (TODO: can we look at symbols earlier?)
- if (!((mods hasAnnotationNamed tpnme.BeanPropertyAnnot) || (mods hasAnnotationNamed tpnme.BooleanBeanPropertyAnnot))
- && annotSigs.exists(ann => (ann.matches(BeanPropertyAttr)) || ann.matches(BooleanBeanPropertyAttr)))
- BeanPropertyAnnotationLimitationError(tree)
+ val isGetter = fieldOrGetterSym.isMethod
+ val annots =
+ if (mods.annotations.isEmpty) Nil
+ else {
+ val annotSigs = annotSig(mods.annotations)
+ if (isGetter) filterAccessorAnnots(annotSigs, tree) // if this is really a getter, retain annots targeting either field/getter
+ else annotSigs filter annotationFilter(FieldTargetClass, !mods.isParamAccessor)
+ }
- sym setAnnotations (annotSigs filter filterAccessorAnnotations(isSetter))
- }
+ // must use typeSig, not memberSig (TODO: when do we need to switch namers?)
+ val sig = typeSig(tree, annots)
- sym setInfo pluginsTypeSigAccessor(sig, typer, tree, sym)
+ fieldOrGetterSym setInfo (if (isGetter) NullaryMethodType(sig) else sig)
- validate(sym)
+ validate(fieldOrGetterSym)
}
- /* Explicit isSetter required for bean setters (beanSetterSym.isSetter is false) */
- def beanAccessorTypeCompleter(tree: ValDef, missingTpt: Boolean, isSetter: Boolean) = mkTypeCompleter(tree) { sym =>
- context.unit.synthetics get sym match {
+ // knowing `isBean`, we could derive `isSetter` from `valDef.name`
+ def accessorTypeCompleter(valDef: ValDef, missingTpt: Boolean, isBean: Boolean, isSetter: Boolean) = mkTypeCompleter(valDef) { accessorSym =>
+ context.unit.synthetics get accessorSym match {
case Some(ddef: DefDef) =>
- // sym is an accessor, while tree is the field (for traits it's actually the getter, and we're completing the setter)
+ // `accessorSym` is the accessor for which we're completing the info (tree == ddef),
+ // while `valDef` is the field definition that spawned the accessor
+ // NOTE: `valTypeCompleter` handles abstract vals, trait vals and lazy vals, where the ValDef carries the getter's symbol
+
// reuse work done in valTypeCompleter if we already computed the type signature of the val
// (assuming the field and accessor symbols are distinct -- i.e., we're not in a trait)
val valSig =
- if ((sym ne tree.symbol) && tree.symbol.isInitialized) tree.symbol.info
- else typeSig(tree, Nil) // don't set annotations for the valdef -- we just want to compute the type sig
+ if ((accessorSym ne valDef.symbol) && valDef.symbol.isInitialized) valDef.symbol.info
+ else typeSig(valDef, Nil) // don't set annotations for the valdef -- we just want to compute the type sig (TODO: dig deeper and see if we can use memberSig)
// patch up the accessor's tree if the valdef's tpt was not known back when the tree was synthesized
- if (missingTpt) { // can't look at tree.tpt here because it may have been completed by now
+ // can't look at `valDef.tpt` here because it may have been completed by now (this is why we pass in `missingTpt`)
+ // HACK: a param accessor `ddef.tpt.tpe` somehow gets out of whack with `accessorSym.info`, so always patch it back...
+ // (the tpt is typed in the wrong namer, using the class as owner instead of the outer context, which is where param accessors should be typed)
+ if (missingTpt || accessorSym.isParamAccessor) {
if (!isSetter) ddef.tpt setType valSig
else if (ddef.vparamss.nonEmpty && ddef.vparamss.head.nonEmpty) ddef.vparamss.head.head.tpt setType valSig
- else throw new TypeError(tree.pos, s"Internal error: could not complete parameter/return type for $ddef from $sym")
+ else throw new TypeError(valDef.pos, s"Internal error: could not complete parameter/return type for $ddef from $accessorSym")
}
+ val mods = valDef.mods
val annots =
- if (tree.mods.annotations.isEmpty) Nil
- else annotSig(tree.mods.annotations) filter filterBeanAccessorAnnotations(isSetter)
+ if (mods.annotations.isEmpty) Nil
+ else filterAccessorAnnots(annotSig(mods.annotations), valDef, isSetter, isBean)
+
+ // for a setter, call memberSig to attribute the parameter (for a bean, we always use the regular method sig completer since they receive method types)
+ // for a regular getter, make sure it gets a NullaryMethodType (also, no need to recompute it: we already have the valSig)
+ val sig =
+ if (isSetter || isBean) typeSig(ddef, annots)
+ else {
+ if (annots.nonEmpty) annotate(accessorSym, annots)
+
+ NullaryMethodType(valSig)
+ }
- val sig = typeSig(ddef, annots)
+ accessorSym setInfo pluginsTypeSigAccessor(sig, typer, valDef, accessorSym)
- sym setInfo pluginsTypeSigAccessor(sig, typer, tree, sym)
+ if (!isBean && accessorSym.isOverloaded)
+ if (isSetter) ddef.rhs.setType(ErrorType)
+ else GetterDefinedTwiceError(accessorSym)
- validate(sym)
+ validate(accessorSym)
case _ =>
- throw new TypeError(tree.pos, s"Internal error: no synthetic tree found for bean accessor $sym")
+ throw new TypeError(valDef.pos, s"Internal error: no synthetic tree found for bean accessor $accessorSym")
}
-
}
-
// see scala.annotation.meta's package class for more info
// Annotations on ValDefs can be targeted towards the following: field, getter, setter, beanGetter, beanSetter, param.
// The defaults are:
@@ -893,24 +908,33 @@ trait Namers extends MethodSynthesis {
//
// TODO: these defaults can be surprising for annotations not meant for accessors/fields -- should we revisit?
// (In order to have `@foo val X` result in the X getter being annotated with `@foo`, foo needs to be meta-annotated with @getter)
- private def filterAccessorAnnotations(isSetter: Boolean): AnnotationInfo => Boolean =
- if (isSetter || !owner.isTrait)
- annotationFilter(if (isSetter) SetterTargetClass else GetterTargetClass, defaultRetention = false)
- else (ann =>
- annotationFilter(FieldTargetClass, defaultRetention = true)(ann) ||
- annotationFilter(GetterTargetClass, defaultRetention = true)(ann))
+ private def filterAccessorAnnots(annotSigs: List[global.AnnotationInfo], tree: global.ValDef, isSetter: Boolean = false, isBean: Boolean = false): List[AnnotationInfo] = {
+ val mods = tree.mods
+ if (!isBean) {
+ // neg/t3403: check that we didn't get a sneaky type alias/renamed import that we couldn't detect because we only look at names during synthesis
+ // (TODO: can we look at symbols earlier?)
+ if (!((mods hasAnnotationNamed tpnme.BeanPropertyAnnot) || (mods hasAnnotationNamed tpnme.BooleanBeanPropertyAnnot))
+ && annotSigs.exists(ann => (ann.matches(BeanPropertyAttr)) || ann.matches(BooleanBeanPropertyAttr)))
+ BeanPropertyAnnotationLimitationError(tree)
+ }
+
+ def filterAccessorAnnotations: AnnotationInfo => Boolean =
+ if (isSetter || !owner.isTrait)
+ annotationFilter(if (isSetter) SetterTargetClass else GetterTargetClass, defaultRetention = false)
+ else (ann =>
+ annotationFilter(FieldTargetClass, defaultRetention = true)(ann) ||
+ annotationFilter(GetterTargetClass, defaultRetention = true)(ann))
- private def filterBeanAccessorAnnotations(isSetter: Boolean): AnnotationInfo => Boolean =
- if (isSetter || !owner.isTrait)
- annotationFilter(if (isSetter) BeanSetterTargetClass else BeanGetterTargetClass, defaultRetention = false)
- else (ann =>
- annotationFilter(FieldTargetClass, defaultRetention = true)(ann) ||
- annotationFilter(BeanGetterTargetClass, defaultRetention = true)(ann))
+ def filterBeanAccessorAnnotations: AnnotationInfo => Boolean =
+ if (isSetter || !owner.isTrait)
+ annotationFilter(if (isSetter) BeanSetterTargetClass else BeanGetterTargetClass, defaultRetention = false)
+ else (ann =>
+ annotationFilter(FieldTargetClass, defaultRetention = true)(ann) ||
+ annotationFilter(BeanGetterTargetClass, defaultRetention = true)(ann))
+ annotSigs filter (if (isBean) filterBeanAccessorAnnotations else filterAccessorAnnotations)
+ }
- private def accessorSigFromFieldTp(sym: Symbol, isSetter: Boolean, tp: Type): Type =
- if (isSetter) MethodType(List(sym.newSyntheticValueParam(tp)), UnitTpe)
- else NullaryMethodType(tp)
def selfTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
val selftpe = typer.typedType(tree).tpe
@@ -959,7 +983,7 @@ trait Namers extends MethodSynthesis {
)
dropIllegalStarTypes(
if (shouldWiden) tpe.widen
- else if (sym.isFinal) tpe // "final val" allowed to retain constant type
+ else if (sym.isFinal && !sym.isLazy) tpe // "final val" allowed to retain constant type
else tpe.deconst
)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 8449260fe6..8034d056d7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -450,9 +450,9 @@ abstract class RefChecks extends Transform {
} else if (other.isStable && !member.isStable) { // (1.4)
overrideError("needs to be a stable, immutable value")
} else if (member.isValue && member.isLazy &&
- other.isValue && !other.isSourceMethod && !other.isDeferred && !other.isLazy) {
+ other.isValue && other.hasFlag(STABLE) && !(other.isDeferred || other.isLazy)) {
overrideError("cannot override a concrete non-lazy value")
- } else if (other.isValue && other.isLazy && !other.isSourceMethod && !other.isDeferred && // !(other.hasFlag(MODULE) && other.hasFlag(PACKAGE | JAVA)) && other.hasFlag(LAZY) && (!other.isMethod || other.hasFlag(STABLE)) && !other.hasFlag(DEFERRED)
+ } else if (other.isValue && other.isLazy &&
member.isValue && !member.isLazy) {
overrideError("must be declared lazy to override a concrete lazy value")
} else if (other.isDeferred && member.isTermMacro && member.extendedOverriddenSymbols.forall(_.isDeferred)) { // (1.9)
@@ -609,7 +609,7 @@ abstract class RefChecks extends Transform {
val (missing, rest) = memberList partition (m => m.isDeferred && !ignoreDeferred(m))
// Group missing members by the name of the underlying symbol,
// to consolidate getters and setters.
- val grouped = missing groupBy (sym => analyzer.underlyingSymbol(sym).name)
+ val grouped = missing groupBy (_.name.getterName)
val missingMethods = grouped.toList flatMap {
case (name, syms) =>
if (syms exists (_.isSetter)) syms filterNot (_.isGetter)
@@ -651,15 +651,16 @@ abstract class RefChecks extends Transform {
// Give a specific error message for abstract vars based on why it fails:
// It could be unimplemented, have only one accessor, or be uninitialized.
- if (underlying.isVariable) {
- val isMultiple = grouped.getOrElse(underlying.name, Nil).size > 1
+ val groupedAccessors = grouped.getOrElse(member.name.getterName, Nil)
+ val isMultiple = groupedAccessors.size > 1
+ if (groupedAccessors.exists(_.isSetter) || (member.isGetter && !isMultiple && member.setterIn(member.owner).exists)) {
// If both getter and setter are missing, squelch the setter error.
if (member.isSetter && isMultiple) ()
else undefined(
if (member.isSetter) "\n(Note that an abstract var requires a setter in addition to the getter)"
else if (member.isGetter && !isMultiple) "\n(Note that an abstract var requires a getter in addition to the setter)"
- else analyzer.abstractVarMessage(member)
+ else "\n(Note that variables need to be initialized to be defined)"
)
}
else if (underlying.isMethod) {
@@ -919,17 +920,11 @@ abstract class RefChecks extends Transform {
var index = -1
for (stat <- stats) {
index = index + 1
- def enterSym(sym: Symbol) = if (sym.isLocalToBlock) {
- currentLevel.scope.enter(sym)
- symIndex(sym) = index
- }
stat match {
- case DefDef(_, _, _, _, _, _) if stat.symbol.isLazy =>
- enterSym(stat.symbol)
- case ClassDef(_, _, _, _) | DefDef(_, _, _, _, _, _) | ModuleDef(_, _, _) | ValDef(_, _, _, _) =>
- //assert(stat.symbol != NoSymbol, stat);//debug
- enterSym(stat.symbol.lazyAccessorOrSelf)
+ case _ : MemberDef if stat.symbol.isLocalToBlock =>
+ currentLevel.scope.enter(stat.symbol)
+ symIndex(stat.symbol) = index
case _ =>
}
}
@@ -1180,10 +1175,10 @@ abstract class RefChecks extends Transform {
val tree1 = transform(tree) // important to do before forward reference check
if (tree1.symbol.isLazy) tree1 :: Nil
else {
- val lazySym = tree.symbol.lazyAccessorOrSelf
- if (lazySym.isLocalToBlock && index <= currentLevel.maxindex) {
+ val sym = tree.symbol
+ if (sym.isLocalToBlock && index <= currentLevel.maxindex) {
debuglog("refsym = " + currentLevel.refsym)
- reporter.error(currentLevel.refpos, "forward reference extends over definition of " + lazySym)
+ reporter.error(currentLevel.refpos, "forward reference extends over definition of " + sym)
}
tree1 :: Nil
}
@@ -1451,9 +1446,9 @@ abstract class RefChecks extends Transform {
)
}
- sym.isSourceMethod &&
+ sym.name == nme.apply &&
+ !(sym hasFlag STABLE) && // ???
sym.isCase &&
- sym.name == nme.apply &&
isClassTypeAccessible(tree) &&
!tree.tpe.finalResultType.typeSymbol.primaryConstructor.isLessAccessibleThan(tree.symbol)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 49d892e04f..963a9dea02 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -146,7 +146,28 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
val intermediateClasses = clazz.info.baseClasses.tail.takeWhile(_ != sym.owner)
intermediateClasses.map(sym.overridingSymbol).find(s => s.isDeferred && !s.isAbstractOverride && !s.owner.isTrait).foreach {
absSym =>
- reporter.error(sel.pos, s"${sym.fullLocationString} cannot be directly accessed from ${clazz} because ${absSym.owner} redeclares it as abstract")
+ reporter.error(sel.pos, s"${sym.fullLocationString} cannot be directly accessed from $clazz because ${absSym.owner} redeclares it as abstract")
+ }
+ } else if (mix != tpnme.EMPTY) {
+ // SD-143: a call super[T].m that resolves to A.m cannot be translated to correct bytecode if
+ // - A is a class (not a trait / interface), but not the direct superclass. Invokespecial
+ // would select an overriding method in the direct superclass, rather than A.m.
+ // We allow this if there are statically no intervening overrides.
+ // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokespecial
+ // - A is a java-defined interface and not listed as direct parent of the class. In this
+ // case, `invokespecial A.m` would be invalid.
+ def hasClassOverride(member: Symbol, subclass: Symbol): Boolean = {
+ if (subclass == ObjectClass || subclass == member.owner) false
+ else if (member.overridingSymbol(subclass) != NoSymbol) true
+ else hasClassOverride(member, subclass.superClass)
+ }
+ val owner = sym.owner
+ if (!owner.isTrait && owner != clazz.superClass && hasClassOverride(sym, clazz.superClass)) {
+ reporter.error(sel.pos,
+ s"cannot emit super call: the selected $sym is declared in $owner, which is not the direct superclass of $clazz.\n" +
+ s"An unqualified super call (super.${sym.name}) would be allowed.")
+ } else if (owner.isInterface && owner.isJavaDefined && !clazz.parentSymbols.contains(owner)) {
+ reporter.error(sel.pos, s"unable to emit super call unless interface ${owner.name} (which declares $sym) is directly extended by $clazz.")
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index bee327c760..b66dbf21c0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -97,7 +97,7 @@ trait TypeDiagnostics {
/** An explanatory note to be added to error messages
* when there's a problem with abstract var defs */
def abstractVarMessage(sym: Symbol): String =
- if (underlyingSymbol(sym).isVariable)
+ if (sym.isSetter || sym.isGetter && sym.setterIn(sym.owner).exists)
"\n(Note that variables need to be initialized to be defined)"
else ""
@@ -140,7 +140,7 @@ trait TypeDiagnostics {
* TODO: is it wise to create new symbols simply to generate error message? is this safe in interactive/resident mode?
*/
def underlyingSymbol(member: Symbol): Symbol =
- if (!member.hasAccessorFlag || member.owner.isTrait) member
+ if (!member.hasAccessorFlag || member.accessed == NoSymbol) member
else if (!member.isDeferred) member.accessed
else {
val getter = if (member.isSetter) member.getterIn(member.owner) else member
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index a95ecd360c..d8183ea8df 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -128,6 +128,15 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def canTranslateEmptyListToNil = true
def missingSelectErrorTree(tree: Tree, qual: Tree, name: Name): Tree = tree
+ // used to exempt synthetic accessors (i.e. those that are synthesized by the compiler to access a field)
+ // from skolemization because there's a weird bug that causes spurious type mismatches
+ // (it seems to have something to do with existential abstraction over values
+ // https://github.com/scala/scala-dev/issues/165
+ // when we're past typer, lazy accessors are synthetic, but before they are user-defined
+ // to make this hack less hacky, we could rework our flag assignment to allow for
+ // requiring both the ACCESSOR and the SYNTHETIC bits to trigger the exemption
+ private def isSyntheticAccessor(sym: Symbol) = sym.isAccessor && (!sym.isLazy || isPastTyper)
+
// when type checking during erasure, generate erased types in spots that aren't transformed by erasure
// (it erases in TypeTrees, but not in, e.g., the type a Function node)
def phasedAppliedType(sym: Symbol, args: List[Type]) = {
@@ -1159,7 +1168,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
adapt(tree setType restpe, mode, pt, original)
case TypeRef(_, ByNameParamClass, arg :: Nil) if mode.inExprMode => // (2)
adapt(tree setType arg, mode, pt, original)
- case tp if mode.typingExprNotLhs && isExistentialType(tp) =>
+ case tp if mode.typingExprNotLhs && isExistentialType(tp) && !isSyntheticAccessor(context.owner) =>
adapt(tree setType tp.dealias.skolemizeExistential(context.owner, tree), mode, pt, original)
case PolyType(tparams, restpe) if mode.inNone(TAPPmode | PATTERNmode) && !context.inTypeConstructorAllowed => // (3)
// assert((mode & HKmode) == 0) //@M a PolyType in HKmode represents an anonymous type function,
@@ -1373,13 +1382,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
notAllowed(s"redefinition of $name method. See SIP-15, criterion 4.")
else if (stat.symbol != null && stat.symbol.isParamAccessor)
notAllowed("additional parameter")
- // concrete accessor (getter) in trait corresponds to a field definition (neg/anytrait.scala)
- // TODO: only reject accessors that actually give rise to field (e.g., a constant-type val is fine)
- else if (!isValueClass && stat.symbol.isAccessor && !stat.symbol.isDeferred)
- notAllowed("field definition")
checkEphemeralDeep.traverse(rhs)
- // for value class or "exotic" vals in traits
- // (traits don't receive ValDefs for regular vals until fields phase -- well, except for early initialized/lazy vals)
case _: ValDef =>
notAllowed("field definition")
case _: ModuleDef =>
@@ -1956,11 +1959,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members
checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType])
- val body2 = {
- val body2 =
- if (isPastTyper || reporter.hasErrors) body1
- else body1 flatMap rewrappingWrapperTrees(namer.addDerivedTrees(Typer.this, _))
- val primaryCtor = treeInfo.firstConstructor(body2)
+ val bodyWithPrimaryCtor = {
+ val primaryCtor = treeInfo.firstConstructor(body1)
val primaryCtor1 = primaryCtor match {
case DefDef(_, _, _, _, _, Block(earlyVals :+ global.pendingSuperCall, unit)) =>
val argss = superArgs(parents1.head) getOrElse Nil
@@ -1969,10 +1969,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
deriveDefDef(primaryCtor)(block => Block(earlyVals :+ superCall, unit) setPos pos) setPos pos
case _ => primaryCtor
}
- body2 mapConserve { case `primaryCtor` => primaryCtor1; case stat => stat }
+ body1 mapConserve { case `primaryCtor` => primaryCtor1; case stat => stat }
}
- val body3 = typedStats(body2, templ.symbol)
+ val body3 = typedStats(bodyWithPrimaryCtor, templ.symbol)
if (clazz.info.firstParent.typeSymbol == AnyValClass)
validateDerivedValueClass(clazz, body3)
@@ -2040,7 +2040,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
override def matches(sym: Symbol, sym1: Symbol) =
if (sym.isSkolem) matches(sym.deSkolemize, sym1)
else if (sym1.isSkolem) matches(sym, sym1.deSkolemize)
- else super[SubstTypeMap].matches(sym, sym1)
+ else super.matches(sym, sym1)
}
// allow defaults on by-name parameters
if (sym hasFlag BYNAMEPARAM)
@@ -2436,13 +2436,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case _ =>
}
}
- val stats1 = if (isPastTyper) block.stats else
- block.stats.flatMap {
- case vd@ValDef(_, _, _, _) if vd.symbol.isLazy =>
- namer.addDerivedTrees(Typer.this, vd)
- case stat => stat::Nil
- }
- val stats2 = typedStats(stats1, context.owner, warnPure = false)
+ val statsTyped = typedStats(block.stats, context.owner, warnPure = false)
val expr1 = typed(block.expr, mode &~ (FUNmode | QUALmode), pt)
// sanity check block for unintended expr placement
@@ -2456,18 +2450,18 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def checkPure(t: Tree, supple: Boolean): Unit =
if (treeInfo.isPureExprForWarningPurposes(t)) {
val msg = "a pure expression does nothing in statement position"
- val parens = if (stats2.length + count > 1) "multiline expressions might require enclosing parentheses" else ""
+ val parens = if (statsTyped.length + count > 1) "multiline expressions might require enclosing parentheses" else ""
val discard = if (adapted) "; a value can be silently discarded when Unit is expected" else ""
val text =
if (supple) s"${parens}${discard}"
else if (!parens.isEmpty) s"${msg}; ${parens}" else msg
context.warning(t.pos, text)
}
- stats2.foreach(checkPure(_, supple = false))
+ statsTyped.foreach(checkPure(_, supple = false))
if (result0.nonEmpty) checkPure(result0, supple = true)
}
- treeCopy.Block(block, stats2, expr1)
+ treeCopy.Block(block, statsTyped, expr1)
.setType(if (treeInfo.isExprSafeToInline(block)) expr1.tpe else expr1.tpe.deconst)
} finally {
// enable escaping privates checking from the outside and recycle
@@ -3171,6 +3165,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case (ClassDef(cmods, cname, _, _), DefDef(dmods, dname, _, _, _, _)) =>
cmods.isImplicit && dmods.isImplicit && cname.toTermName == dname
+ // ValDef and Accessor
+ case (ValDef(_, cname, _, _), DefDef(_, dname, _, _, _, _)) =>
+ cname.getterName == dname.getterName
+
case _ => false
}
@@ -4455,8 +4453,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def narrowRhs(tp: Type) = { val sym = context.tree.symbol
context.tree match {
case ValDef(mods, _, _, Apply(Select(`tree`, _), _)) if !mods.isMutable && sym != null && sym != NoSymbol =>
- val sym1 = if (sym.owner.isClass && sym.getterIn(sym.owner) != NoSymbol) sym.getterIn(sym.owner)
- else sym.lazyAccessorOrSelf
+ val sym1 =
+ if (sym.owner.isClass && sym.getterIn(sym.owner) != NoSymbol) sym.getterIn(sym.owner)
+ else sym
val pre = if (sym1.owner.isClass) sym1.owner.thisType else NoPrefix
intersectionType(List(tp, singleType(pre, sym1)))
case _ => tp
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index 22fb0728e6..f2e9b260b0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -128,6 +128,7 @@ trait Unapplies extends ast.TreeDSL {
*/
def factoryMeth(mods: Modifiers, name: TermName, cdef: ClassDef): DefDef = {
val tparams = constrTparamsInvariant(cdef)
+
val cparamss = constrParamss(cdef)
def classtpe = classType(cdef, tparams)
atPos(cdef.pos.focus)(
diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala
index 64535a749f..715ba0d4f3 100644
--- a/src/interactive/scala/tools/nsc/interactive/Global.scala
+++ b/src/interactive/scala/tools/nsc/interactive/Global.scala
@@ -72,8 +72,6 @@ trait InteractiveAnalyzer extends Analyzer {
override def enterExistingSym(sym: Symbol, tree: Tree): Context = {
if (sym != null && sym.owner.isTerm) {
enterIfNotThere(sym)
- if (sym.isLazy)
- sym.lazyAccessor andAlso enterIfNotThere
for (defAtt <- sym.attachments.get[DefaultsOfLocalMethodAttachment])
defAtt.defaultGetters foreach enterIfNotThere
diff --git a/src/library/scala/runtime/LazyRef.scala b/src/library/scala/runtime/LazyRef.scala
new file mode 100644
index 0000000000..5a0bd5442c
--- /dev/null
+++ b/src/library/scala/runtime/LazyRef.scala
@@ -0,0 +1,157 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2016, LAMP/EPFL and Lightbend, Inc **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.runtime
+
+/** Classes used as holders for lazy vals defined in methods. */
+
+class LazyRef[T] {
+ @volatile private[this] var _initialized: Boolean = _
+ def initialized = _initialized
+
+ private[this] var _value: T = _
+ def value: T = _value
+ def initialize(value: T): T = {
+ _value = value
+ _initialized = true
+ value
+ }
+
+ override def toString = s"LazyRef ${if (_initialized) s"of: ${_value}" else "thunk"}"
+}
+
+class LazyBoolean {
+ @volatile private[this] var _initialized: Boolean = _
+ def initialized = _initialized
+
+ private[this] var _value: Boolean = _
+ def value: Boolean = _value
+ def initialize(value: Boolean): Boolean = {
+ _value = value
+ _initialized = true
+ value
+ }
+
+ override def toString = s"LazyBoolean ${if (_initialized) s"of: ${_value}" else "thunk"}"
+}
+
+class LazyByte {
+ @volatile private[this] var _initialized: Boolean = _
+ def initialized = _initialized
+
+ private[this] var _value: Byte = _
+
+ def value: Byte = _value
+
+ def initialize(value: Byte): Byte = {
+ _value = value
+ _initialized = true
+ value
+ }
+
+ override def toString = s"LazyByte ${if (_initialized) s"of: ${_value}" else "thunk"}"
+}
+
+class LazyChar {
+ @volatile private[this] var _initialized: Boolean = _
+ def initialized = _initialized
+
+ private[this] var _value: Char = _
+ def value: Char = _value
+ def initialize(value: Char): Char = {
+ _value = value
+ _initialized = true
+ value
+ }
+
+ override def toString = s"LazyChar ${if (_initialized) s"of: ${_value}" else "thunk"}"
+}
+
+class LazyShort {
+ @volatile private[this] var _initialized: Boolean = _
+ def initialized = _initialized
+
+ private[this] var _value: Short = _
+ def value: Short = _value
+ def initialize(value: Short): Short = {
+ _value = value
+ _initialized = true
+ value
+ }
+
+ override def toString = s"LazyShort ${if (_initialized) s"of: ${_value}" else "thunk"}"
+}
+
+class LazyInt {
+ @volatile private[this] var _initialized: Boolean = _
+ def initialized = _initialized
+
+ private[this] var _value: Int = _
+ def value: Int = _value
+ def initialize(value: Int): Int = {
+ _value = value
+ _initialized = true
+ value
+ }
+
+ override def toString = s"LazyInt ${if (_initialized) s"of: ${_value}" else "thunk"}"
+}
+
+class LazyLong {
+ @volatile private[this] var _initialized: Boolean = _
+ def initialized = _initialized
+
+ private[this] var _value: Long = _
+ def value: Long = _value
+ def initialize(value: Long): Long = {
+ _value = value
+ _initialized = true
+ value
+ }
+
+ override def toString = s"LazyLong ${if (_initialized) s"of: ${_value}" else "thunk"}"
+}
+
+class LazyFloat {
+ @volatile private[this] var _initialized: Boolean = _
+ def initialized = _initialized
+
+ private[this] var _value: Float = _
+ def value: Float = _value
+ def initialize(value: Float): Float = {
+ _value = value
+ _initialized = true
+ value
+ }
+
+ override def toString = s"LazyFloat ${if (_initialized) s"of: ${_value}" else "thunk"}"
+}
+
+class LazyDouble {
+ @volatile private[this] var _initialized: Boolean = _
+ def initialized = _initialized
+
+ private[this] var _value: Double = _
+ def value: Double = _value
+ def initialize(value: Double): Double = {
+ _value = value
+ _initialized = true
+ value
+ }
+
+ override def toString = s"LazyDouble ${if (_initialized) s"of: ${_value}" else "thunk"}"
+}
+
+class LazyUnit {
+ @volatile private[this] var _initialized: Boolean = _
+ def initialized = _initialized
+
+ def initialize(): Unit = _initialized = true
+
+ override def toString = s"LazyUnit${if (_initialized) "" else " thunk"}"
+}
diff --git a/src/manual/scala/man1/scalac.scala b/src/manual/scala/man1/scalac.scala
index 6ffcccea25..79c175e0f0 100644
--- a/src/manual/scala/man1/scalac.scala
+++ b/src/manual/scala/man1/scalac.scala
@@ -379,8 +379,8 @@ object scalac extends Command {
MItalic("posterasure"),
"clean up erased inline classes"),
Definition(
- MItalic("lazyvals"),
- "allocate bitmaps, translate lazy vals into lazified defs"),
+ MItalic("fields"),
+ "synthesize accessors and fields, including bitmaps for lazy vals"),
Definition(
MItalic("lambdalift"),
"move nested functions to top level"),
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index d0539dfd42..0f7cf07f08 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -81,7 +81,7 @@ trait Definitions extends api.StandardDefinitions {
}
}
- private[Definitions] def classesMap[T](f: Name => T) = symbolsMap(ScalaValueClassesNoUnit, f)
+ private[Definitions] def classesMap[T](f: Name => T): Map[Symbol, T] = symbolsMap(ScalaValueClassesNoUnit, f)
private def symbolsMap[T](syms: List[Symbol], f: Name => T): Map[Symbol, T] = mapFrom(syms)(x => f(x.name))
private def symbolsMapFilt[T](syms: List[Symbol], p: Name => Boolean, f: Name => T) = symbolsMap(syms filter (x => p(x.name)), f)
@@ -93,6 +93,9 @@ trait Definitions extends api.StandardDefinitions {
lazy val boxedClass = classesMap(x => getClassByName(boxedName(x)))
lazy val refClass = classesMap(x => getRequiredClass("scala.runtime." + x + "Ref"))
lazy val volatileRefClass = classesMap(x => getRequiredClass("scala.runtime.Volatile" + x + "Ref"))
+ lazy val lazyHolders = symbolsMap(ScalaValueClasses, x => getClassIfDefined("scala.runtime.Lazy" + x))
+ lazy val LazyRefClass = getClassIfDefined("scala.runtime.LazyRef")
+ lazy val LazyUnitClass = getClassIfDefined("scala.runtime.LazyUnit")
lazy val allRefClasses: Set[Symbol] = {
refClass.values.toSet ++ volatileRefClass.values.toSet ++ Set(VolatileObjectRefClass, ObjectRefClass)
@@ -1151,7 +1154,6 @@ trait Definitions extends api.StandardDefinitions {
lazy val ElidableMethodClass = requiredClass[scala.annotation.elidable]
lazy val ImplicitNotFoundClass = requiredClass[scala.annotation.implicitNotFound]
lazy val ImplicitAmbiguousClass = getClassIfDefined("scala.annotation.implicitAmbiguous")
- lazy val JUnitTestClass = getClassIfDefined("org.junit.Test")
lazy val MigrationAnnotationClass = requiredClass[scala.annotation.migration]
lazy val ScalaStrictFPAttr = requiredClass[scala.annotation.strictfp]
lazy val SwitchClass = requiredClass[scala.annotation.switch]
@@ -1193,6 +1195,8 @@ trait Definitions extends api.StandardDefinitions {
lazy val MethodTargetClass = requiredClass[meta.companionMethod] // TODO: module, moduleClass? package, packageObject?
lazy val LanguageFeatureAnnot = requiredClass[meta.languageFeature]
+ lazy val JUnitAnnotations = List("Test", "Ignore", "Before", "After", "BeforeClass", "AfterClass").map(n => getClassIfDefined("org.junit." + n))
+
// Language features
lazy val languageFeatureModule = getRequiredModule("scala.languageFeature")
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 925018d3a6..1a6c84b19e 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -704,6 +704,8 @@ trait StdNames {
val immutable: NameType = "immutable"
val implicitly: NameType = "implicitly"
val in: NameType = "in"
+ val initialize : NameType = "initialize"
+ val initialized : NameType = "initialized"
val internal: NameType = "internal"
val inlinedEquals: NameType = "inlinedEquals"
val isArray: NameType = "isArray"
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 487aadf5e5..ac025e50ae 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -655,7 +655,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
isClass && isFinal && loop(typeParams)
}
- final def isLazyAccessor = isLazy && lazyAccessor != NoSymbol
final def isOverridableMember = !(isClass || isEffectivelyFinal) && safeOwner.isClass
/** Does this symbol denote a wrapper created by the repl? */
@@ -1683,7 +1682,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*
* - packageobjects (follows namer)
* - superaccessors (follows typer)
- * - lazyvals (follows erasure)
+ * - lambdaLift (follows erasure)
* - null
*/
private def unsafeTypeParamPhase = {
@@ -2075,11 +2074,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def alias: Symbol = NoSymbol
- /** For a lazy value, its lazy accessor. NoSymbol for all others. */
+ @deprecated("No longer applicable, as lazy vals are not desugared until the fields phase", "2.12.0") // used by scala-refactoring
def lazyAccessor: Symbol = NoSymbol
- /** If this is a lazy value, the lazy accessor; otherwise this symbol. */
- def lazyAccessorOrSelf: Symbol = if (isLazy) lazyAccessor else this
+ @deprecated("No longer applicable, as lazy vals are not desugared until the fields phase", "2.12.0")
+ def lazyAccessorOrSelf: Symbol = NoSymbol
/** `accessed`, if this is an accessor that should have an underlying field. Otherwise, `this`.
* Note that a "regular" accessor in a trait does not have a field, as an interface cannot define a field.
@@ -2088,7 +2087,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* as they are an implementation detail that's irrelevant to type checking.
*/
def accessedOrSelf: Symbol =
- if (hasAccessorFlag && (!owner.isTrait || hasFlag(PRESUPER | LAZY))) accessed
+ if (hasAccessorFlag && (!owner.isTrait || hasFlag(PRESUPER))) accessed
else this
/** For an outer accessor: The class from which the outer originates.
@@ -2834,17 +2833,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
this
}
- def setLazyAccessor(sym: Symbol): TermSymbol = {
- assert(isLazy && (referenced == NoSymbol || referenced == sym), (this, debugFlagString, referenced, sym))
- referenced = sym
- this
- }
-
- override def lazyAccessor: Symbol = {
- assert(isLazy, this)
- referenced
- }
-
/** change name by appending $$<fully-qualified-name-of-class `base`>
* Do the same for any accessed symbols or setters/getters
*/
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index b9f3e987ee..61937958dd 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -293,6 +293,26 @@ abstract class TreeInfo {
}
}
+
+ // No field for these vals, which means the ValDef carries the symbol of the getter (and not the field symbol)
+ // - abstract vals have no value we could store (until they become concrete, potentially)
+ // - lazy vals: the ValDef carries the symbol of the lazy accessor.
+ // The sausage factory will spew out the inner workings during the fields phase (actual bitmaps won't follow
+ // until lazyvals & mixins, though we should move this stuff from mixins to lazyvals now that fields takes care of mixing in lazy vals)
+ // - concrete vals in traits don't yield a field here either (their getter's RHS has the initial value)
+ // Constructors will move the assignment to the constructor, abstracting over the field using the field setter,
+ // and Fields will add a field to the class that mixes in the trait, implementing the accessors in terms of it
+ //
+ // The following case does receive a field symbol (until it's eliminated during the fields phase):
+ // - a concrete val with a statically known value (ConstantType)
+ // performs its side effect according to lazy/strict semantics, but doesn't need to store its value
+ // each access will "evaluate" the RHS (a literal) again
+ //
+ // We would like to avoid emitting unnecessary fields, but the required knowledge isn't available until after typer.
+ // The only way to avoid emitting & suppressing, is to not emit at all until we are sure to need the field, as dotty does.
+ def noFieldFor(vd: ValDef, owner: Symbol) = vd.mods.isDeferred || vd.mods.isLazy || (owner.isTrait && !vd.mods.hasFlag(PRESUPER))
+
+
def isDefaultGetter(tree: Tree) = {
tree.symbol != null && tree.symbol.isDefaultGetter
}
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index 4bc804445c..c6cb0d0223 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -227,9 +227,7 @@ abstract class UnPickler {
return NoSymbol
if (tag == EXTMODCLASSref) {
- val moduleVar = owner.info.decl(nme.moduleVarName(name.toTermName))
- if (moduleVar.isLazyAccessor)
- return moduleVar.lazyAccessor.lazyAccessor
+ owner.info.decl(nme.moduleVarName(name.toTermName))
}
NoSymbol
}
diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala
index 62ca50d035..e2f1e74740 100644
--- a/src/reflect/scala/reflect/internal/transform/Erasure.scala
+++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala
@@ -147,21 +147,20 @@ trait Erasure {
case AnnotatedType(_, atp) =>
apply(atp)
case ClassInfoType(parents, decls, clazz) =>
- ClassInfoType(
- if (clazz == ObjectClass || isPrimitiveValueClass(clazz) || parents.isEmpty) Nil
+ val newParents =
+ if (parents.isEmpty || clazz == ObjectClass || isPrimitiveValueClass(clazz)) Nil
else if (clazz == ArrayClass) ObjectTpe :: Nil
else {
- val erasedParents = parents map this
+ val erasedParents = parents mapConserve this
// drop first parent for traits -- it has been normalized to a class by now,
// but we should drop that in bytecode
- val firstParent =
- if (clazz.hasFlag(Flags.TRAIT) && !clazz.hasFlag(Flags.JAVA)) ObjectTpe
- else erasedParents.head
-
- firstParent :: erasedParents.tail.filter(_.typeSymbol != ObjectClass)
- },
- decls, clazz)
+ if (clazz.hasFlag(Flags.TRAIT) && !clazz.hasFlag(Flags.JAVA))
+ ObjectTpe :: erasedParents.tail.filter(_.typeSymbol != ObjectClass)
+ else erasedParents
+ }
+ if (newParents eq parents) tp
+ else ClassInfoType(newParents, decls, clazz)
case _ =>
mapOver(tp)
}
@@ -343,23 +342,30 @@ trait Erasure {
}
}
- /** The symbol's erased info. This is the type's erasure, except for the following symbols:
- *
- * - For $asInstanceOf : [T]T
- * - For $isInstanceOf : [T]scala#Boolean
- * - For class Array : [T]C where C is the erased classinfo of the Array class.
- * - For Array[T].<init> : {scala#Int)Array[T]
- * - For a type parameter : A type bounds type consisting of the erasures of its bounds.
- */
+ /** The symbol's erased info. This is the type's erasure, except for the following primitive symbols:
+ *
+ * - $asInstanceOf --> [T]T
+ * - $isInstanceOf --> [T]scala#Boolean
+ * - synchronized --> [T](x: T)T
+ * - class Array --> [T]C where C is the erased classinfo of the Array class.
+ * - Array[T].<init> --> {scala#Int)Array[T]
+ *
+ * An abstract type's info erases to a TypeBounds type consisting of the erasures of the abstract type's bounds.
+ */
def transformInfo(sym: Symbol, tp: Type): Type = {
- if (sym == Object_asInstanceOf)
+ // Do not erase the primitive `synchronized` method's info or the info of its parameter.
+ // We do erase the info of its type param so that subtyping can relate its bounds after erasure.
+ def synchronizedPrimitive(sym: Symbol) =
+ sym == Object_synchronized || (sym.owner == Object_synchronized && sym.isTerm)
+
+ if (sym == Object_asInstanceOf || synchronizedPrimitive(sym))
sym.info
else if (sym == Object_isInstanceOf || sym == ArrayClass)
PolyType(sym.info.typeParams, specialErasure(sym)(sym.info.resultType))
else if (sym.isAbstractType)
- TypeBounds(WildcardType, WildcardType)
+ TypeBounds(WildcardType, WildcardType) // TODO why not use the erasure of the type's bounds, as stated in the doc?
else if (sym.isTerm && sym.owner == ArrayClass) {
- if (sym.isClassConstructor)
+ if (sym.isClassConstructor) // TODO: switch on name for all branches -- this one is sym.name == nme.CONSTRUCTOR
tp match {
case MethodType(params, TypeRef(pre, sym1, args)) =>
MethodType(cloneSymbolsAndModify(params, specialErasure(sym)),
@@ -376,12 +382,14 @@ trait Erasure {
} else if (
sym.owner != NoSymbol &&
sym.owner.owner == ArrayClass &&
- sym == Array_update.paramss.head(1)) {
+ sym == Array_update.paramss.head(1)) { // TODO: can we simplify the guard, perhaps cache the symbol to compare to?
// special case for Array.update: the non-erased type remains, i.e. (Int,A)Unit
// since the erasure type map gets applied to every symbol, we have to catch the
// symbol here
tp
} else {
+ // TODO OPT: altogether, there are 9 symbols that we special-case.
+ // Could we get to the common case more quickly by looking them up in a set?
specialErasure(sym)(tp)
}
}
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index f55b33959a..b74ccb9177 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -379,7 +379,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.ElidableMethodClass
definitions.ImplicitNotFoundClass
definitions.ImplicitAmbiguousClass
- definitions.JUnitTestClass
definitions.MigrationAnnotationClass
definitions.ScalaStrictFPAttr
definitions.SwitchClass
@@ -417,6 +416,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.ClassTargetClass
definitions.MethodTargetClass
definitions.LanguageFeatureAnnot
+ definitions.JUnitAnnotations
definitions.languageFeatureModule
definitions.metaAnnotations
definitions.AnnotationDefaultAttr
@@ -432,6 +432,9 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.boxedClass
definitions.refClass
definitions.volatileRefClass
+ definitions.lazyHolders
+ definitions.LazyRefClass
+ definitions.LazyUnitClass
definitions.allRefClasses
definitions.UnitClass
definitions.ByteClass
diff --git a/src/repl/scala/tools/nsc/interpreter/Phased.scala b/src/repl/scala/tools/nsc/interpreter/Phased.scala
index d1d422ce3e..dd327a13d4 100644
--- a/src/repl/scala/tools/nsc/interpreter/Phased.scala
+++ b/src/repl/scala/tools/nsc/interpreter/Phased.scala
@@ -88,7 +88,7 @@ trait Phased {
lazy val all = List(
Parser, Namer, Packageobjects, Typer, Superaccessors, Pickler, Refchecks,
- Uncurry, Tailcalls, Specialize, Explicitouter, Erasure, Lazyvals, Lambdalift,
+ Uncurry, Tailcalls, Specialize, Explicitouter, Erasure, Fields, Lambdalift,
Constructors, Flatten, Mixin, Cleanup, Delambdafy, Jvm, Terminal
)
lazy val nameMap = all.map(x => x.name -> x).toMap withDefaultValue NoPhaseName
@@ -114,12 +114,12 @@ trait Phased {
case object Pickler extends PhaseName
case object Refchecks extends PhaseName
case object Uncurry extends PhaseName
+ case object Fields extends PhaseName
case object Tailcalls extends PhaseName
case object Specialize extends PhaseName
case object Explicitouter extends PhaseName
case object Erasure extends PhaseName
case object PostErasure extends PhaseName
- case object Lazyvals extends PhaseName
case object Lambdalift extends PhaseName
case object Constructors extends PhaseName
case object Flatten extends PhaseName
diff --git a/src/scaladoc/scala/tools/nsc/doc/Settings.scala b/src/scaladoc/scala/tools/nsc/doc/Settings.scala
index 063a949323..fbb2dd9f87 100644
--- a/src/scaladoc/scala/tools/nsc/doc/Settings.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/Settings.scala
@@ -22,7 +22,7 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_))
val docformat = ChoiceSetting (
"-doc-format",
"format",
- "Selects in which format documentation is rendered",
+ "Selects in which format documentation is rendered.",
List("html"),
"html"
)
diff --git a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala
index 928cb34d30..fb9a5ce7eb 100644
--- a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala
@@ -106,10 +106,12 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
// in the doc comment of MyClass
def linkTarget: DocTemplateImpl = inTpl
- lazy val comment = {
- val documented = if (sym.hasAccessorFlag) sym.accessed else sym
- thisFactory.comment(documented, linkTarget, inTpl)
- }
+ // if there is a field symbol, the ValDef will use it, which means docs attached to it will be under the field symbol, not the getter's
+ protected[this] def commentCarryingSymbol(sym: Symbol) =
+ if (sym.hasAccessorFlag && sym.accessed.exists) sym.accessed else sym
+
+ lazy val comment = thisFactory.comment(commentCarryingSymbol(sym), linkTarget, inTpl)
+
def group = comment flatMap (_.group) getOrElse defaultGroup
override def inTemplate = inTpl
override def toRoot: List[MemberImpl] = this :: inTpl.toRoot
@@ -476,17 +478,18 @@ class ModelFactory(val global: Global, val settings: doc.Settings) {
override lazy val comment = {
def nonRootTemplate(sym: Symbol): Option[DocTemplateImpl] =
if (sym eq RootPackage) None else findTemplateMaybe(sym)
+
/* Variable precedence order for implicitly added members: Take the variable definitions from ...
* 1. the target of the implicit conversion
* 2. the definition template (owner)
* 3. the current template
*/
- val inRealTpl = conversion.flatMap { conv =>
- nonRootTemplate(conv.toType.typeSymbol)
- } orElse nonRootTemplate(sym.owner) orElse Option(inTpl)
- inRealTpl flatMap { tpl =>
- thisFactory.comment(sym, tpl, tpl)
- }
+ val inRealTpl = (
+ conversion.flatMap(conv => nonRootTemplate(conv.toType.typeSymbol))
+ orElse nonRootTemplate(sym.owner)
+ orElse Option(inTpl))
+
+ inRealTpl flatMap (tpl => thisFactory.comment(commentCarryingSymbol(sym), tpl, tpl))
}
override def inDefinitionTemplates = useCaseOf.fold(super.inDefinitionTemplates)(_.inDefinitionTemplates)
diff --git a/test/files/jvm/innerClassAttribute/Test.scala b/test/files/jvm/innerClassAttribute/Test.scala
index 5c666a615f..288c6ee30f 100644
--- a/test/files/jvm/innerClassAttribute/Test.scala
+++ b/test/files/jvm/innerClassAttribute/Test.scala
@@ -298,7 +298,7 @@ object Test extends BytecodeTest {
assertEnclosingMethod ("SI_9105$B$5" , "SI_9105", "m$1", "()Ljava/lang/Object;")
assertEnclosingMethod ("SI_9105$C$1" , "SI_9105", null , null)
assertEnclosingMethod ("SI_9105$D$1" , "SI_9105", "met", "()Lscala/Function1;")
- assertEnclosingMethod ("SI_9105$E$1" , "SI_9105", "m$3", "()Ljava/lang/Object;")
+ assertEnclosingMethod ("SI_9105$E$1" , "SI_9105", "m$2", "()Ljava/lang/Object;")
assertEnclosingMethod ("SI_9105$F$1" , "SI_9105", "met", "()Lscala/Function1;")
assertNoEnclosingMethod("SI_9105")
@@ -311,7 +311,7 @@ object Test extends BytecodeTest {
// by-name
assertEnclosingMethod("SI_9105$G$1", "SI_9105", null , null)
- assertEnclosingMethod("SI_9105$H$1", "SI_9105", "m$2", "()Ljava/lang/Object;")
+ assertEnclosingMethod("SI_9105$H$1", "SI_9105", "m$3", "()Ljava/lang/Object;")
assertEnclosingMethod("SI_9105$I$1", "SI_9105", null , null)
assertEnclosingMethod("SI_9105$J$1", "SI_9105", "bnM", "()I")
assertEnclosingMethod("SI_9105$K$2", "SI_9105", "m$4", "()Ljava/lang/Object;")
@@ -323,11 +323,11 @@ object Test extends BytecodeTest {
def testSI_9124() {
val classes: Map[String, String] = {
List("SI_9124$$anon$10",
- "SI_9124$$anon$11",
"SI_9124$$anon$12",
+ "SI_9124$$anon$13",
"SI_9124$$anon$8",
"SI_9124$$anon$9",
- "SI_9124$O$$anon$13").map({ name =>
+ "SI_9124$O$$anon$11").map({ name =>
val node = loadClassNode(name)
val fMethod = node.methods.asScala.find(_.name.startsWith("f")).get.name
(fMethod, node.name)
@@ -380,8 +380,8 @@ object Test extends BytecodeTest {
val b3 = assertLocal(_ : InnerClassNode, "ImplClassesAreTopLevel$B3$1", "B3$1", flags = publicAbstractInterface)
val b4 = assertLocal(_ : InnerClassNode, "ImplClassesAreTopLevel$B4$1", "B4$1", flags = publicAbstractInterface)
- testInner("ImplClassesAreTopLevel$$anon$14", an14, b3)
- testInner("ImplClassesAreTopLevel$$anon$15", an15, b2)
+ testInner("ImplClassesAreTopLevel$$anon$14", an14, b2)
+ testInner("ImplClassesAreTopLevel$$anon$15", an15, b3)
testInner("ImplClassesAreTopLevel$$anon$16", an16, b4)
testInner("ImplClassesAreTopLevel$B1", b1)
diff --git a/test/files/jvm/javaReflection.check b/test/files/jvm/javaReflection.check
index 9e9fe36d14..f3924940e9 100644
--- a/test/files/jvm/javaReflection.check
+++ b/test/files/jvm/javaReflection.check
@@ -2,13 +2,13 @@ A / A (canon) / A (simple)
- declared cls: List(class A$B, interface A$C, class A$D$)
- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
- properties : false (local) / false (member)
-A$$anon$1 / null (canon) / $anon$1 (simple)
+A$$anon$2 / null (canon) / $anon$2 (simple)
- declared cls: List()
- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
- properties : true (local) / false (member)
A$$anon$3 / null (canon) / $anon$3 (simple)
- declared cls: List()
-- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
- properties : true (local) / false (member)
A$$anon$4 / null (canon) / $anon$4 (simple)
- declared cls: List()
@@ -16,7 +16,7 @@ A$$anon$4 / null (canon) / $anon$4 (simple)
- properties : true (local) / false (member)
A$$anon$5 / null (canon) / $anon$5 (simple)
- declared cls: List()
-- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
- properties : true (local) / false (member)
A$$anon$6 / null (canon) / $anon$6 (simple)
- declared cls: List()
@@ -38,7 +38,7 @@ A$D$ / A.D$ (canon) / D$ (simple)
- declared cls: List(class A$D$B, interface A$D$C, class A$D$D$)
- enclosing : class A (declaring cls) / class A (cls) / null (constr) / null (meth)
- properties : false (local) / true (member)
-A$D$$anon$2 / null (canon) / anon$2 (simple)
+A$D$$anon$1 / null (canon) / anon$1 (simple)
- declared cls: List()
- enclosing : null (declaring cls) / class A$D$ (cls) / null (constr) / null (meth)
- properties : true (local) / false (member)
diff --git a/test/files/neg/anytrait.check b/test/files/neg/anytrait.check
index fabe74d379..6d9d681d60 100644
--- a/test/files/neg/anytrait.check
+++ b/test/files/neg/anytrait.check
@@ -4,4 +4,7 @@ anytrait.scala:3: error: field definition is not allowed in universal trait exte
anytrait.scala:5: error: this statement is not allowed in universal trait extending from class Any
{ x += 1 }
^
-two errors found
+anytrait.scala:9: error: field definition is not allowed in universal trait extending from class Any
+ val y: T
+ ^
+three errors found
diff --git a/test/files/neg/choices.check b/test/files/neg/choices.check
index df4f23461f..2449cadcd6 100644
--- a/test/files/neg/choices.check
+++ b/test/files/neg/choices.check
@@ -1,5 +1,4 @@
-error: Usage: -Yresolve-term-conflict:<strategy>
- where <strategy> choices are package, object, error (default: error)
+error: Usage: -Yresolve-term-conflict:<strategy> where <strategy> choices are package, object, error (default: error).
error: bad option: '-Yresolve-term-conflict'
error: bad options: -Yresolve-term-conflict
error: flags file may only contain compiler options, found: -Yresolve-term-conflict
diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check
index 0a7b1a7157..af164d90ea 100644
--- a/test/files/neg/names-defaults-neg.check
+++ b/test/files/neg/names-defaults-neg.check
@@ -1,7 +1,3 @@
-names-defaults-neg.scala:65: error: not enough arguments for method apply: (a: Int, b: String)(c: Int*)Fact in object Fact.
-Unspecified value parameter b.
- val fac = Fact(1)(2, 3)
- ^
names-defaults-neg.scala:5: error: type mismatch;
found : String("#")
required: Int
@@ -81,6 +77,10 @@ and method f in object t8 of type (a: Int, b: Object)String
match argument types (a: Int,b: String) and expected result type Any
println(t8.f(a = 0, b = "1")) // ambiguous reference
^
+names-defaults-neg.scala:65: error: not enough arguments for method apply: (a: Int, b: String)(c: Int*)Fact in object Fact.
+Unspecified value parameter b.
+ val fac = Fact(1)(2, 3)
+ ^
names-defaults-neg.scala:69: error: wrong number of arguments for pattern A1(x: Int,y: String)
A1() match { case A1(_) => () }
^
diff --git a/test/files/neg/nowarnDefaultJunitMethods.check b/test/files/neg/nowarnDefaultJunitMethods.check
deleted file mode 100644
index 7efdcc299a..0000000000
--- a/test/files/neg/nowarnDefaultJunitMethods.check
+++ /dev/null
@@ -1,6 +0,0 @@
-C_1.scala:2: warning: JUnit tests in traits that are compiled as default methods are not executed by JUnit 4. JUnit 5 will fix this issue.
- @org.junit.Test def foo = 0
- ^
-error: No warnings can be incurred under -Xfatal-warnings.
-one warning found
-one error found
diff --git a/test/files/neg/nowarnDefaultJunitMethods.flags b/test/files/neg/nowarnDefaultJunitMethods.flags
deleted file mode 100644
index 85d8eb2ba2..0000000000
--- a/test/files/neg/nowarnDefaultJunitMethods.flags
+++ /dev/null
@@ -1 +0,0 @@
--Xfatal-warnings
diff --git a/test/files/neg/nowarnDefaultJunitMethods/C_1.scala b/test/files/neg/nowarnDefaultJunitMethods/C_1.scala
deleted file mode 100644
index e2565a48bc..0000000000
--- a/test/files/neg/nowarnDefaultJunitMethods/C_1.scala
+++ /dev/null
@@ -1,5 +0,0 @@
-trait T {
- @org.junit.Test def foo = 0
-}
-
-class C extends T
diff --git a/test/files/neg/nowarnDefaultJunitMethods/Test.java b/test/files/neg/nowarnDefaultJunitMethods/Test.java
deleted file mode 100644
index e8d64c2cc8..0000000000
--- a/test/files/neg/nowarnDefaultJunitMethods/Test.java
+++ /dev/null
@@ -1,3 +0,0 @@
-package org.junit;
-
-public @interface Test { }
diff --git a/test/files/neg/protected-constructors.check b/test/files/neg/protected-constructors.check
index 0279f5815d..4f076ec993 100644
--- a/test/files/neg/protected-constructors.check
+++ b/test/files/neg/protected-constructors.check
@@ -1,3 +1,12 @@
+protected-constructors.scala:15: error: class Foo3 in object Ding cannot be accessed in object dingus.Ding
+ Access to protected class Foo3 not permitted because
+ enclosing object P in package hungus is not a subclass of
+ object Ding in package dingus where target is defined
+ class Bar3 extends Ding.Foo3("abc")
+ ^
+protected-constructors.scala:15: error: no arguments allowed for nullary constructor Object: ()Object
+ class Bar3 extends Ding.Foo3("abc")
+ ^
protected-constructors.scala:17: error: no arguments allowed for nullary constructor Foo1: ()dingus.Foo1
val foo1 = new Foo1("abc")
^
@@ -13,13 +22,4 @@ protected-constructors.scala:19: error: class Foo3 in object Ding cannot be acce
object Ding in package dingus where target is defined
val foo3 = new Ding.Foo3("abc")
^
-protected-constructors.scala:15: error: class Foo3 in object Ding cannot be accessed in object dingus.Ding
- Access to protected class Foo3 not permitted because
- enclosing object P in package hungus is not a subclass of
- object Ding in package dingus where target is defined
- class Bar3 extends Ding.Foo3("abc")
- ^
-protected-constructors.scala:15: error: no arguments allowed for nullary constructor Object: ()Object
- class Bar3 extends Ding.Foo3("abc")
- ^
5 errors found
diff --git a/test/files/neg/sabin2.check b/test/files/neg/sabin2.check
index 8a09361069..aa0e8f734c 100644
--- a/test/files/neg/sabin2.check
+++ b/test/files/neg/sabin2.check
@@ -1,6 +1,6 @@
sabin2.scala:22: error: type mismatch;
found : Test.Base#T
- required: _7.T where val _7: Test.Base
+ required: _5.T where val _5: Test.Base
a.set(b.get()) // Error
^
one error found
diff --git a/test/files/neg/t1838.check b/test/files/neg/t1838.check
index a476158c7b..af811a3810 100644
--- a/test/files/neg/t1838.check
+++ b/test/files/neg/t1838.check
@@ -1,7 +1,7 @@
-t1838.scala:6: error: `sealed' modifier can be used only for classes
- sealed val v = 0
- ^
t1838.scala:5: error: `sealed' modifier can be used only for classes
sealed def f = 0
^
+t1838.scala:6: error: `sealed' modifier can be used only for classes
+ sealed val v = 0
+ ^
two errors found
diff --git a/test/files/neg/t4158.check b/test/files/neg/t4158.check
index af281c52cd..7bac6558f7 100644
--- a/test/files/neg/t4158.check
+++ b/test/files/neg/t4158.check
@@ -1,7 +1,7 @@
-t4158.scala:3: error: an expression of type Null is ineligible for implicit conversion
- var y = null: Int
- ^
t4158.scala:2: error: an expression of type Null is ineligible for implicit conversion
var x: Int = null
^
+t4158.scala:3: error: an expression of type Null is ineligible for implicit conversion
+ var y = null: Int
+ ^
two errors found
diff --git a/test/files/neg/t6446-additional.check b/test/files/neg/t6446-additional.check
index 45db63317c..23df978cd9 100644
--- a/test/files/neg/t6446-additional.check
+++ b/test/files/neg/t6446-additional.check
@@ -10,19 +10,18 @@ superaccessors 6 add super accessors in traits and nested classes
pickler 8 serialize symbol tables
refchecks 9 reference/override checking, translate nested objects
uncurry 10 uncurry, translate function values to anonymous classes
- fields 11 synthesize accessors and fields
+ fields 11 synthesize accessors and fields, including bitmaps for la...
tailcalls 12 replace tail calls by jumps
specialize 13 @specialized-driven class and method specialization
explicitouter 14 this refs to outer pointers
erasure 15 erase types, add interfaces for traits
posterasure 16 clean up erased inline classes
- lazyvals 17 allocate bitmaps, translate lazy vals into lazified defs
- lambdalift 18 move nested functions to top level
- constructors 19 move field definitions into constructors
- flatten 20 eliminate inner classes
- mixin 21 mixin composition
- cleanup 22 platform-specific cleanups, generate reflective calls
- delambdafy 23 remove lambdas
- jvm 24 generate JVM bytecode
- ploogin 25 A sample phase that does so many things it's kind of hard...
- terminal 26 the last phase during a compilation run
+ lambdalift 17 move nested functions to top level
+ constructors 18 move field definitions into constructors
+ flatten 19 eliminate inner classes
+ mixin 20 mixin composition
+ cleanup 21 platform-specific cleanups, generate reflective calls
+ delambdafy 22 remove lambdas
+ jvm 23 generate JVM bytecode
+ ploogin 24 A sample phase that does so many things it's kind of hard...
+ terminal 25 the last phase during a compilation run
diff --git a/test/files/neg/t6446-missing.check b/test/files/neg/t6446-missing.check
index 04523d18e6..c0a8fea140 100644
--- a/test/files/neg/t6446-missing.check
+++ b/test/files/neg/t6446-missing.check
@@ -11,18 +11,17 @@ superaccessors 6 add super accessors in traits and nested classes
pickler 8 serialize symbol tables
refchecks 9 reference/override checking, translate nested objects
uncurry 10 uncurry, translate function values to anonymous classes
- fields 11 synthesize accessors and fields
+ fields 11 synthesize accessors and fields, including bitmaps for la...
tailcalls 12 replace tail calls by jumps
specialize 13 @specialized-driven class and method specialization
explicitouter 14 this refs to outer pointers
erasure 15 erase types, add interfaces for traits
posterasure 16 clean up erased inline classes
- lazyvals 17 allocate bitmaps, translate lazy vals into lazified defs
- lambdalift 18 move nested functions to top level
- constructors 19 move field definitions into constructors
- flatten 20 eliminate inner classes
- mixin 21 mixin composition
- cleanup 22 platform-specific cleanups, generate reflective calls
- delambdafy 23 remove lambdas
- jvm 24 generate JVM bytecode
- terminal 25 the last phase during a compilation run
+ lambdalift 17 move nested functions to top level
+ constructors 18 move field definitions into constructors
+ flatten 19 eliminate inner classes
+ mixin 20 mixin composition
+ cleanup 21 platform-specific cleanups, generate reflective calls
+ delambdafy 22 remove lambdas
+ jvm 23 generate JVM bytecode
+ terminal 24 the last phase during a compilation run
diff --git a/test/files/neg/t6446-show-phases.check b/test/files/neg/t6446-show-phases.check
index 03f8273c17..cf8595db5d 100644
--- a/test/files/neg/t6446-show-phases.check
+++ b/test/files/neg/t6446-show-phases.check
@@ -10,18 +10,17 @@ superaccessors 6 add super accessors in traits and nested classes
pickler 8 serialize symbol tables
refchecks 9 reference/override checking, translate nested objects
uncurry 10 uncurry, translate function values to anonymous classes
- fields 11 synthesize accessors and fields
+ fields 11 synthesize accessors and fields, including bitmaps for la...
tailcalls 12 replace tail calls by jumps
specialize 13 @specialized-driven class and method specialization
explicitouter 14 this refs to outer pointers
erasure 15 erase types, add interfaces for traits
posterasure 16 clean up erased inline classes
- lazyvals 17 allocate bitmaps, translate lazy vals into lazified defs
- lambdalift 18 move nested functions to top level
- constructors 19 move field definitions into constructors
- flatten 20 eliminate inner classes
- mixin 21 mixin composition
- cleanup 22 platform-specific cleanups, generate reflective calls
- delambdafy 23 remove lambdas
- jvm 24 generate JVM bytecode
- terminal 25 the last phase during a compilation run
+ lambdalift 17 move nested functions to top level
+ constructors 18 move field definitions into constructors
+ flatten 19 eliminate inner classes
+ mixin 20 mixin composition
+ cleanup 21 platform-specific cleanups, generate reflective calls
+ delambdafy 22 remove lambdas
+ jvm 23 generate JVM bytecode
+ terminal 24 the last phase during a compilation run
diff --git a/test/files/neg/t6666.check b/test/files/neg/t6666.check
index 090ef72770..bae948fe56 100644
--- a/test/files/neg/t6666.check
+++ b/test/files/neg/t6666.check
@@ -1,7 +1,7 @@
t6666.scala:23: error: Implementation restriction: access of method x$2 in object O1 from <$anon: Function0>, would require illegal premature access to object O1
F.byname(x)
^
-t6666.scala:30: error: Implementation restriction: access of method x$3 in object O2 from <$anon: Function0>, would require illegal premature access to object O2
+t6666.scala:30: error: Implementation restriction: access of lazy value x$3 in object O2 from <$anon: Function0>, would require illegal premature access to object O2
F.byname(x)
^
t6666.scala:37: error: Implementation restriction: access of method x$4 in object O3 from <$anon: Function0>, would require illegal premature access to object O3
@@ -10,7 +10,7 @@ t6666.scala:37: error: Implementation restriction: access of method x$4 in objec
t6666.scala:50: error: Implementation restriction: access of method x$6 in class C1 from <$anon: Function0>, would require illegal premature access to the unconstructed `this` of class C1
F.byname(x)
^
-t6666.scala:54: error: Implementation restriction: access of method x$7 in class C2 from <$anon: Function0>, would require illegal premature access to the unconstructed `this` of class C2
+t6666.scala:54: error: Implementation restriction: access of lazy value x$7 in class C2 from <$anon: Function0>, would require illegal premature access to the unconstructed `this` of class C2
F.byname(x)
^
t6666.scala:58: error: Implementation restriction: access of method x$8 in class C3 from <$anon: Function0>, would require illegal premature access to the unconstructed `this` of class C3
diff --git a/test/files/neg/t6829.check b/test/files/neg/t6829.check
index 914a1c9260..274094f791 100644
--- a/test/files/neg/t6829.check
+++ b/test/files/neg/t6829.check
@@ -17,32 +17,32 @@ t6829.scala:49: error: not found: value nextState
^
t6829.scala:50: error: type mismatch;
found : s.type (with underlying type Any)
- required: _53.State where val _53: G
+ required: _30.State where val _30: G
val r = rewards(agent).r(s,a,s2)
^
t6829.scala:50: error: type mismatch;
found : a.type (with underlying type Any)
- required: _53.Action where val _53: G
+ required: _30.Action where val _30: G
val r = rewards(agent).r(s,a,s2)
^
t6829.scala:50: error: type mismatch;
found : s2.type (with underlying type Any)
- required: _53.State where val _53: G
+ required: _30.State where val _30: G
val r = rewards(agent).r(s,a,s2)
^
t6829.scala:51: error: type mismatch;
found : s.type (with underlying type Any)
- required: _50.State
+ required: _25.State
agent.learn(s,a,s2,r): G#Agent
^
t6829.scala:51: error: type mismatch;
found : a.type (with underlying type Any)
- required: _50.Action
+ required: _25.Action
agent.learn(s,a,s2,r): G#Agent
^
t6829.scala:51: error: type mismatch;
found : s2.type (with underlying type Any)
- required: _50.State
+ required: _25.State
agent.learn(s,a,s2,r): G#Agent
^
t6829.scala:53: error: not found: value nextState
diff --git a/test/files/neg/t712.check b/test/files/neg/t712.check
index 831e943063..3f02b4b294 100644
--- a/test/files/neg/t712.check
+++ b/test/files/neg/t712.check
@@ -1,5 +1,4 @@
-t712.scala:10: error: value self is not a member of B.this.ParentImpl
- Note: implicit method coerce is not applicable here because it comes after the application point and it lacks an explicit result type
+t712.scala:10: error: overloaded method coerce needs result type
implicit def coerce(p : ParentImpl) = p.self;
^
one error found
diff --git a/test/files/neg/t7494-no-options.check b/test/files/neg/t7494-no-options.check
index bb143e8644..138d2fe9a3 100644
--- a/test/files/neg/t7494-no-options.check
+++ b/test/files/neg/t7494-no-options.check
@@ -11,19 +11,18 @@ superaccessors 6 add super accessors in traits and nested classes
pickler 8 serialize symbol tables
refchecks 9 reference/override checking, translate nested objects
uncurry 10 uncurry, translate function values to anonymous classes
- fields 11 synthesize accessors and fields
+ fields 11 synthesize accessors and fields, including bitmaps for la...
tailcalls 12 replace tail calls by jumps
specialize 13 @specialized-driven class and method specialization
explicitouter 14 this refs to outer pointers
erasure 15 erase types, add interfaces for traits
posterasure 16 clean up erased inline classes
- lazyvals 17 allocate bitmaps, translate lazy vals into lazified defs
- lambdalift 18 move nested functions to top level
- constructors 19 move field definitions into constructors
- flatten 20 eliminate inner classes
- mixin 21 mixin composition
- cleanup 22 platform-specific cleanups, generate reflective calls
- delambdafy 23 remove lambdas
- jvm 24 generate JVM bytecode
- ploogin 25 A sample phase that does so many things it's kind of hard...
- terminal 26 the last phase during a compilation run
+ lambdalift 17 move nested functions to top level
+ constructors 18 move field definitions into constructors
+ flatten 19 eliminate inner classes
+ mixin 20 mixin composition
+ cleanup 21 platform-specific cleanups, generate reflective calls
+ delambdafy 22 remove lambdas
+ jvm 23 generate JVM bytecode
+ ploogin 24 A sample phase that does so many things it's kind of hard...
+ terminal 25 the last phase during a compilation run
diff --git a/test/files/neg/t8217-local-alias-requires-rhs.check b/test/files/neg/t8217-local-alias-requires-rhs.check
index 0d4f0864ba..d970400ff6 100644
--- a/test/files/neg/t8217-local-alias-requires-rhs.check
+++ b/test/files/neg/t8217-local-alias-requires-rhs.check
@@ -1,9 +1,9 @@
-t8217-local-alias-requires-rhs.scala:6: error: only classes can have declared but undefined members
- type B
- ^
t8217-local-alias-requires-rhs.scala:3: error: only classes can have declared but undefined members
type A
^
+t8217-local-alias-requires-rhs.scala:6: error: only classes can have declared but undefined members
+ type B
+ ^
t8217-local-alias-requires-rhs.scala:14: error: only classes can have declared but undefined members
def this(a: Any) = { this(); type C }
^
diff --git a/test/files/neg/t963.check b/test/files/neg/t963.check
index 483e53c77d..85b64b0bb5 100644
--- a/test/files/neg/t963.check
+++ b/test/files/neg/t963.check
@@ -1,12 +1,12 @@
+t963.scala:10: error: type mismatch;
+ found : AnyRef{def x: Integer}
+ required: AnyRef{val x: Integer}
+ val y2 : { val x : java.lang.Integer } = new { def x = new java.lang.Integer(r.nextInt) }
+ ^
t963.scala:14: error: stable identifier required, but y3.x.type found.
val w3 : y3.x.type = y3.x
^
t963.scala:17: error: stable identifier required, but y4.x.type found.
val w4 : y4.x.type = y4.x
^
-t963.scala:10: error: type mismatch;
- found : AnyRef{def x: Integer}
- required: AnyRef{val x: Integer}
- val y2 : { val x : java.lang.Integer } = new { def x = new java.lang.Integer(r.nextInt) }
- ^
three errors found
diff --git a/test/files/pos/t5240.scala b/test/files/pos/t5240.scala
index 065d175f2f..ae52c6d69a 100644
--- a/test/files/pos/t5240.scala
+++ b/test/files/pos/t5240.scala
@@ -1,11 +1,3 @@
-
-
-
-
-
-
package object foo {
-
var labels: Array[_ <: String] = null
-
}
diff --git a/test/files/pos/t8873.scala b/test/files/pos/t8873.scala
new file mode 100644
index 0000000000..e2f0a5fad2
--- /dev/null
+++ b/test/files/pos/t8873.scala
@@ -0,0 +1 @@
+case class X(@volatile var x:Int)
diff --git a/test/files/pos/trait_lazy_accessboundary.scala b/test/files/pos/trait_lazy_accessboundary.scala
new file mode 100644
index 0000000000..6529816ffb
--- /dev/null
+++ b/test/files/pos/trait_lazy_accessboundary.scala
@@ -0,0 +1,2 @@
+package foo { trait HasLazy { private[foo] lazy val myLazy = "my lady" } }
+package bar { class MixInSuperLazy extends foo.HasLazy }
diff --git a/test/files/presentation/t5708.check b/test/files/presentation/t5708.check
index 4b33893e98..0f24d9626b 100644
--- a/test/files/presentation/t5708.check
+++ b/test/files/presentation/t5708.check
@@ -35,7 +35,7 @@ final def wait(): Unit
final def wait(x$1: Long): Unit
final def wait(x$1: Long,x$2: Int): Unit
final private[this] val CONST_STRING: String("constant")
-lazy private[this] var foo: Int
+lazy val foo: Int
private[package test] def pkgPrivateM: String
private[this] val pkgPrivateV: String
================================================================================
diff --git a/test/files/presentation/t8459.check b/test/files/presentation/t8459.check
index 336c147141..4c105d2a00 100644
--- a/test/files/presentation/t8459.check
+++ b/test/files/presentation/t8459.check
@@ -9,6 +9,7 @@ scala.AnyRef {
()
};
private[this] val bar: F = new F();
+ <stable> <accessor> def bar: F = Foo.this.bar;
Foo.this.bar.<selectDynamic: error>("<error>")
}
================================================================================
diff --git a/test/files/run/analyzerPlugins.check b/test/files/run/analyzerPlugins.check
index ca0005ea4d..64b68db242 100644
--- a/test/files/run/analyzerPlugins.check
+++ b/test/files/run/analyzerPlugins.check
@@ -1,4 +1,5 @@
adaptBoundsToAnnots(List( <: Int), List(type T), List(Int @testAnn)) [2]
+annotationsConform(Boolean @testAnn, Boolean @testAnn) [2]
annotationsConform(Boolean @testAnn, Boolean) [1]
annotationsConform(Boolean(false), Boolean @testAnn) [1]
annotationsConform(Int @testAnn, ?A) [1]
@@ -13,7 +14,7 @@ canAdaptAnnotations(Trees$Select, ?) [1]
canAdaptAnnotations(Trees$Select, Boolean @testAnn) [1]
canAdaptAnnotations(Trees$Select, Boolean) [1]
canAdaptAnnotations(Trees$Select, String @testAnn) [1]
-canAdaptAnnotations(Trees$TypeTree, ?) [10]
+canAdaptAnnotations(Trees$TypeTree, ?) [8]
canAdaptAnnotations(Trees$Typed, ?) [3]
canAdaptAnnotations(Trees$Typed, Any) [1]
canAdaptAnnotations(Trees$Typed, Int) [1]
@@ -24,21 +25,21 @@ pluginsPt(?, Trees$ApplyImplicitView) [2]
pluginsPt(?, Trees$Block) [4]
pluginsPt(?, Trees$ClassDef) [2]
pluginsPt(?, Trees$DefDef) [14]
-pluginsPt(?, Trees$Ident) [50]
+pluginsPt(?, Trees$Ident) [51]
pluginsPt(?, Trees$If) [2]
pluginsPt(?, Trees$Literal) [16]
-pluginsPt(?, Trees$New) [5]
+pluginsPt(?, Trees$New) [6]
pluginsPt(?, Trees$PackageDef) [1]
pluginsPt(?, Trees$Return) [1]
-pluginsPt(?, Trees$Select) [43]
+pluginsPt(?, Trees$Select) [45]
pluginsPt(?, Trees$Super) [2]
pluginsPt(?, Trees$This) [13]
pluginsPt(?, Trees$TypeApply) [3]
pluginsPt(?, Trees$TypeBoundsTree) [2]
pluginsPt(?, Trees$TypeDef) [1]
-pluginsPt(?, Trees$TypeTree) [38]
+pluginsPt(?, Trees$TypeTree) [32]
pluginsPt(?, Trees$Typed) [1]
-pluginsPt(?, Trees$ValDef) [21]
+pluginsPt(?, Trees$ValDef) [13]
pluginsPt(Any, Trees$Literal) [2]
pluginsPt(Any, Trees$Typed) [1]
pluginsPt(Array[Any], Trees$ArrayValue) [1]
@@ -60,7 +61,7 @@ pluginsPt(String, Trees$Ident) [3]
pluginsPt(String, Trees$Literal) [1]
pluginsPt(String, Trees$Select) [1]
pluginsPt(Unit, Trees$Assign) [1]
-pluginsPt(testAnn, Trees$Apply) [5]
+pluginsPt(testAnn, Trees$Apply) [6]
pluginsTypeSig(<none>, Trees$Template) [2]
pluginsTypeSig(class A, Trees$ClassDef) [1]
pluginsTypeSig(class testAnn, Trees$ClassDef) [1]
@@ -70,16 +71,18 @@ pluginsTypeSig(method foo, Trees$DefDef) [1]
pluginsTypeSig(method method, Trees$DefDef) [1]
pluginsTypeSig(method nested, Trees$DefDef) [1]
pluginsTypeSig(type T, Trees$TypeDef) [2]
-pluginsTypeSig(value annotField, Trees$ValDef) [2]
+pluginsTypeSig(value annotField, Trees$ValDef) [1]
+pluginsTypeSig(value count_=, Trees$ValDef) [1]
pluginsTypeSig(value f, Trees$ValDef) [1]
-pluginsTypeSig(value inferField, Trees$ValDef) [2]
-pluginsTypeSig(value lub1, Trees$ValDef) [2]
-pluginsTypeSig(value lub2, Trees$ValDef) [2]
+pluginsTypeSig(value inferField, Trees$ValDef) [1]
+pluginsTypeSig(value lub1, Trees$ValDef) [1]
+pluginsTypeSig(value lub2, Trees$ValDef) [1]
pluginsTypeSig(value param, Trees$ValDef) [2]
pluginsTypeSig(value str, Trees$ValDef) [1]
-pluginsTypeSig(value x, Trees$ValDef) [4]
-pluginsTypeSig(value y, Trees$ValDef) [4]
-pluginsTypeSig(variable count, Trees$ValDef) [3]
+pluginsTypeSig(value x, Trees$ValDef) [3]
+pluginsTypeSig(value y, Trees$ValDef) [3]
+pluginsTypeSig(variable count, Trees$DefDef) [1]
+pluginsTypeSig(variable count, Trees$ValDef) [1]
pluginsTypeSigAccessor(value annotField) [1]
pluginsTypeSigAccessor(value inferField) [1]
pluginsTypeSigAccessor(value lub1) [1]
@@ -93,7 +96,7 @@ pluginsTyped(()Object, Trees$Select) [1]
pluginsTyped(()String, Trees$Ident) [1]
pluginsTyped(()String, Trees$TypeApply) [1]
pluginsTyped(()scala.annotation.Annotation, Trees$Select) [1]
-pluginsTyped(()testAnn, Trees$Select) [10]
+pluginsTyped(()testAnn, Trees$Select) [12]
pluginsTyped((str: String)A <and> (param: Double)A, Trees$Select) [1]
pluginsTyped((x$1: Any)Boolean <and> (x: Double)Boolean <and> (x: Float)Boolean <and> (x: Long)Boolean <and> (x: Int)Boolean <and> (x: Char)Boolean <and> (x: Short)Boolean <and> (x: Byte)Boolean, Trees$Select) [1]
pluginsTyped((x$1: Int)Unit, Trees$Select) [1]
@@ -106,7 +109,7 @@ pluginsTyped(<notype>, Trees$ClassDef) [2]
pluginsTyped(<notype>, Trees$DefDef) [14]
pluginsTyped(<notype>, Trees$PackageDef) [1]
pluginsTyped(<notype>, Trees$TypeDef) [1]
-pluginsTyped(<notype>, Trees$ValDef) [21]
+pluginsTyped(<notype>, Trees$ValDef) [13]
pluginsTyped(=> Boolean @testAnn, Trees$Select) [1]
pluginsTyped(=> Double, Trees$Select) [1]
pluginsTyped(=> Int, Trees$Select) [5]
@@ -122,7 +125,7 @@ pluginsTyped(Any, Trees$TypeTree) [1]
pluginsTyped(AnyRef, Trees$Select) [4]
pluginsTyped(Array[Any], Trees$ArrayValue) [1]
pluginsTyped(Boolean @testAnn, Trees$Select) [1]
-pluginsTyped(Boolean @testAnn, Trees$TypeTree) [4]
+pluginsTyped(Boolean @testAnn, Trees$TypeTree) [3]
pluginsTyped(Boolean(false), Trees$Literal) [1]
pluginsTyped(Boolean, Trees$Apply) [1]
pluginsTyped(Boolean, Trees$Select) [3]
@@ -139,15 +142,15 @@ pluginsTyped(Int, Trees$Apply) [1]
pluginsTyped(Int, Trees$Ident) [1]
pluginsTyped(Int, Trees$If) [1]
pluginsTyped(Int, Trees$Select) [12]
-pluginsTyped(Int, Trees$TypeTree) [13]
+pluginsTyped(Int, Trees$TypeTree) [10]
pluginsTyped(List[Any], Trees$Apply) [1]
pluginsTyped(List[Any], Trees$Select) [1]
-pluginsTyped(List[Any], Trees$TypeTree) [3]
+pluginsTyped(List[Any], Trees$TypeTree) [2]
pluginsTyped(Nothing, Trees$Return) [1]
pluginsTyped(Object, Trees$Apply) [1]
pluginsTyped(String @testAnn, Trees$Ident) [1]
pluginsTyped(String @testAnn, Trees$Select) [1]
-pluginsTyped(String @testAnn, Trees$TypeTree) [4]
+pluginsTyped(String @testAnn, Trees$TypeTree) [3]
pluginsTyped(String(""), Trees$Literal) [2]
pluginsTyped(String("huhu"), Trees$Literal) [1]
pluginsTyped(String("str") @testAnn, Trees$Typed) [1]
@@ -156,13 +159,13 @@ pluginsTyped(String("two"), Trees$Literal) [2]
pluginsTyped(String, Trees$Apply) [2]
pluginsTyped(String, Trees$Block) [2]
pluginsTyped(String, Trees$Select) [7]
-pluginsTyped(String, Trees$TypeTree) [7]
+pluginsTyped(String, Trees$TypeTree) [6]
pluginsTyped(Unit, Trees$Apply) [2]
pluginsTyped(Unit, Trees$Assign) [1]
pluginsTyped(Unit, Trees$Block) [4]
pluginsTyped(Unit, Trees$If) [1]
pluginsTyped(Unit, Trees$Literal) [5]
-pluginsTyped(Unit, Trees$TypeTree) [1]
+pluginsTyped(Unit, Trees$TypeTree) [2]
pluginsTyped([A](xs: A*)List[A], Trees$Select) [1]
pluginsTyped([T <: Int]=> Int, Trees$Select) [1]
pluginsTyped([T0]()T0, Trees$Select) [1]
@@ -176,9 +179,9 @@ pluginsTyped(scala.collection.immutable.List.type, Trees$Select) [2]
pluginsTyped(scala.collection.immutable.StringOps, Trees$ApplyImplicitView) [2]
pluginsTyped(scala.collection.mutable.WrappedArray[Any], Trees$Apply) [1]
pluginsTyped(str.type, Trees$Ident) [3]
-pluginsTyped(testAnn, Trees$Apply) [5]
-pluginsTyped(testAnn, Trees$Ident) [5]
-pluginsTyped(testAnn, Trees$New) [5]
+pluginsTyped(testAnn, Trees$Apply) [6]
+pluginsTyped(testAnn, Trees$Ident) [6]
+pluginsTyped(testAnn, Trees$New) [6]
pluginsTyped(testAnn, Trees$This) [1]
pluginsTyped(testAnn, Trees$TypeTree) [2]
pluginsTyped(testAnn.super.type, Trees$Super) [1]
diff --git a/test/files/run/compiler-asSeenFrom.check b/test/files/run/compiler-asSeenFrom.check
index 7305504115..46ea4d3685 100644
--- a/test/files/run/compiler-asSeenFrom.check
+++ b/test/files/run/compiler-asSeenFrom.check
@@ -332,11 +332,6 @@ value dZ { // after parser
val cD: ll.C[List[T3]]
}
-value dZ { // after parser
- private[this] val cD: ll.C[List[T3]]
- val cD: ll.C[List[T3]]
-}
-
value dZ { // after uncurry
private[this] val cD: ll.C[List[T3]]
val cD(): ll.C[List[T3]]
@@ -347,11 +342,9 @@ value dZ { // after erasure
val cD(): ll.C
}
-value jZ { // after parser
- def thisI(): I.this.type
- def thisC(): C.this.type
- def t2(): T2
- def t1(): T1
+value dZ { // after parser
+ private[this] val cD: ll.C[List[T3]]
+ val cD: ll.C[List[T3]]
}
value jZ { // after parser
@@ -393,6 +386,13 @@ value jZ { // after flatten
def t1(): Object
}
+value jZ { // after parser
+ def thisI(): I.this.type
+ def thisC(): C.this.type
+ def t2(): T2
+ def t1(): T1
+}
+
method kz { // after parser
def thisI(): I.this.type
def thisC(): C.this.type
diff --git a/test/files/run/delambdafy_t6028.check b/test/files/run/delambdafy_t6028.check
index 8b0ae7e9b9..eaba70ee1a 100644
--- a/test/files/run/delambdafy_t6028.check
+++ b/test/files/run/delambdafy_t6028.check
@@ -42,18 +42,12 @@ package <empty> {
<synthetic> <stable> <artifact> def $outer(): T = MethodLocalObject$2.this.$outer;
<synthetic> <stable> <artifact> def $outer(): T = MethodLocalObject$2.this.$outer
};
- final <stable> private[this] def MethodLocalObject$lzycompute$1(barParam$1: String, MethodLocalObject$module$1: runtime.VolatileObjectRef): T#MethodLocalObject$2.type = {
- T.this.synchronized({
- 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);
- scala.runtime.BoxedUnit.UNIT
- });
+ final <stable> 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));
MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]()
};
- final <stable> 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)
- else
- MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]();
final <artifact> 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/existential-rangepos.check b/test/files/run/existential-rangepos.check
index 1212b60bae..984baeaaf8 100644
--- a/test/files/run/existential-rangepos.check
+++ b/test/files/run/existential-rangepos.check
@@ -7,7 +7,7 @@
};
[24:51]private[this] val foo: [28]Set[_ <: T] = [47:51]null;
[28]<stable> <accessor> def foo: [28]Set[_ <: T] = [28][28]A.this.foo;
- [54:74]<stable> <accessor> def bar: [58]Set[_ <: T]
+ [54:74]<stable> <accessor> val bar: [58]Set[_ <: T]
}
}
diff --git a/test/files/run/idempotency-lazy-vals.check b/test/files/run/idempotency-lazy-vals.check
index 15afa5303c..3a6f1a7ef0 100644
--- a/test/files/run/idempotency-lazy-vals.check
+++ b/test/files/run/idempotency-lazy-vals.check
@@ -5,19 +5,11 @@
C.super.<init>();
()
};
- lazy private[this] val x: Int = _;
- <stable> <accessor> lazy def x: Int = {
- C.this.x = 2;
- C.this.x
- };
- lazy private[this] val y: Int = _;
- implicit <stable> <accessor> lazy def y: Int = {
- C.this.y = 3;
- C.this.y
- }
+ <stable> <accessor> lazy val x: Int = 2;
+ implicit <stable> <accessor> lazy val y: Int = 3
};
val c: C = new C();
import c._;
c.x.*(Predef.implicitly[Int](c.y))
}
-error!
+6
diff --git a/test/files/run/junitForwarders/C_1.scala b/test/files/run/junitForwarders/C_1.scala
new file mode 100644
index 0000000000..2af2026a61
--- /dev/null
+++ b/test/files/run/junitForwarders/C_1.scala
@@ -0,0 +1,15 @@
+trait T {
+ @org.junit.Test def foo = 0
+}
+
+class C extends T
+
+object Test extends App {
+ def check(c: Class[_], e: String) = {
+ val s = c.getDeclaredMethods.sortBy(_.getName).map(m => s"${m.getName} - ${m.getDeclaredAnnotations.mkString(", ")}").mkString(";")
+ assert(s == e, s"found: $s\nexpected: $e")
+ }
+ check(classOf[C], "foo - @org.junit.Test()")
+ // TODO scala-dev#213: should `foo$` really carry the @Test annotation?
+ check(classOf[T], "$init$ - ;foo - @org.junit.Test();foo$ - @org.junit.Test()")
+}
diff --git a/test/files/run/junitForwarders/Test.java b/test/files/run/junitForwarders/Test.java
new file mode 100644
index 0000000000..57c4d5b544
--- /dev/null
+++ b/test/files/run/junitForwarders/Test.java
@@ -0,0 +1,10 @@
+package org.junit;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface Test { }
diff --git a/test/files/run/lazy-locals-2.scala b/test/files/run/lazy-locals-2.scala
new file mode 100644
index 0000000000..d6c33cffcb
--- /dev/null
+++ b/test/files/run/lazy-locals-2.scala
@@ -0,0 +1,322 @@
+object Logs {
+ val logBuf = new collection.mutable.StringBuilder()
+ def log(m: Any): Unit = { if (logBuf.nonEmpty) logBuf.append(":"); logBuf.append(m) }
+ def checkLog(expected: String): Unit = {
+ val res = logBuf.toString
+ assert(res == expected, s"expected:\n$expected\nfound:\n$res")
+ logBuf.clear()
+ }
+}
+
+import Logs._
+
+class C {
+ def getInt : Int = { log("getInt"); 1 }
+ def getString: String = { log("getString"); "s" }
+ def getUnit : Unit = { log("getUnit") }
+
+ lazy val t1 = getInt
+ lazy val t2 = getString
+ lazy val t3 = getUnit
+ checkLog("")
+
+ def m1 = {
+ lazy val t1 = getInt
+ t1 + t1
+ }
+ def m2 = {
+ lazy val t1 = getString
+ t1 + t1
+ }
+ def m3 = {
+ lazy val t1 = getUnit
+ log(t1); log(t1)
+ }
+ checkLog("")
+
+
+ val vl1 = {
+ lazy val t1 = getInt
+ t1 + t1
+ }
+ val vl2 = {
+ lazy val t1 = getString
+ t1 + t1
+ }
+ val vl3 = {
+ lazy val t1 = getUnit
+ log(t1); log(t1)
+ }
+ checkLog("getInt:getString:getUnit:():()")
+
+
+ var vr1 = {
+ lazy val t1 = getInt
+ t1 + t1
+ }
+ var vr2 = {
+ lazy val t1 = getString
+ t1 + t1
+ }
+ var vr3 = {
+ lazy val t1 = getUnit
+ log(t1); log(t1)
+ }
+ checkLog("getInt:getString:getUnit:():()")
+
+
+ lazy val lvl1 = {
+ lazy val t1 = getInt
+ t1 + t1
+ }
+ lazy val lvl2 = {
+ lazy val t1 = getString
+ t1 + t1
+ }
+ lazy val lvl3 = {
+ lazy val t1 = getUnit
+ log(t1); log(t1)
+ }
+ checkLog("")
+
+
+ {
+ lazy val t1 = getInt
+ lazy val t2 = getString
+ lazy val t3 = getUnit
+
+ log(t1 + t1)
+ log(t2 + t2)
+ log(t3); log(t3)
+ }
+ checkLog("getInt:2:getString:ss:getUnit:():()")
+
+
+ def run(): Unit = {
+ log(t1); log(t1);
+ log(t2); log(t2);
+ log(t3); log(t3);
+ checkLog("getInt:1:1:getString:s:s:getUnit:():()")
+
+ log(m1); log(m1)
+ log(m2); log(m2)
+ log(m3); log(m3)
+ checkLog("getInt:2:getInt:2:getString:ss:getString:ss:getUnit:():():():getUnit:():():()")
+
+ log(vl1); log(vl1)
+ log(vl2); log(vl2)
+ log(vl3); log(vl3)
+ checkLog("2:2:ss:ss:():()")
+
+ log(vr1); log(vr1); vr1 = 393; log(vr1)
+ log(vr2); log(vr2); vr2 = "h"; log(vr2)
+ log(vr3); log(vr3); vr3 = () ; log(vr3)
+ checkLog("2:2:393:ss:ss:h:():():()")
+
+ log(lvl1); log(lvl1)
+ log(lvl2); log(lvl2)
+ log(lvl3); log(lvl3)
+ checkLog("getInt:2:2:getString:ss:ss:getUnit:():():():()")
+ }
+}
+
+trait T {
+ def getInt : Int = { log("getInt"); 1 }
+ def getString: String = { log("getString"); "s" }
+ def getUnit : Unit = { log("getUnit") }
+
+ lazy val t1 = getInt
+ lazy val t2 = getString
+ lazy val t3 = getUnit
+ checkLog("")
+
+ def m1 = {
+ lazy val t1 = getInt
+ t1 + t1
+ }
+ def m2 = {
+ lazy val t1 = getString
+ t1 + t1
+ }
+ def m3 = {
+ lazy val t1 = getUnit
+ log(t1); log(t1)
+ }
+ checkLog("")
+
+
+ val vl1 = {
+ lazy val t1 = getInt
+ t1 + t1
+ }
+ val vl2 = {
+ lazy val t1 = getString
+ t1 + t1
+ }
+ val vl3 = {
+ lazy val t1 = getUnit
+ log(t1); log(t1)
+ }
+ checkLog("getInt:getString:getUnit:():()")
+
+
+ var vr1 = {
+ lazy val t1 = getInt
+ t1 + t1
+ }
+ var vr2 = {
+ lazy val t1 = getString
+ t1 + t1
+ }
+ var vr3 = {
+ lazy val t1 = getUnit
+ log(t1); log(t1)
+ }
+ checkLog("getInt:getString:getUnit:():()")
+
+
+ lazy val lvl1 = {
+ lazy val t1 = getInt
+ t1 + t1
+ }
+ lazy val lvl2 = {
+ lazy val t1 = getString
+ t1 + t1
+ }
+ lazy val lvl3 = {
+ lazy val t1 = getUnit
+ log(t1); log(t1)
+ }
+ checkLog("")
+
+
+ {
+ lazy val t1 = getInt
+ lazy val t2 = getString
+ lazy val t3 = getUnit
+
+ log(t1 + t1)
+ log(t2 + t2)
+ log(t3); log(t3)
+ }
+ checkLog("getInt:2:getString:ss:getUnit:():()")
+
+
+ def run(): Unit = {
+ log(t1); log(t1);
+ log(t2); log(t2);
+ log(t3); log(t3);
+ checkLog("getInt:1:1:getString:s:s:getUnit:():()")
+
+ log(m1); log(m1)
+ log(m2); log(m2)
+ log(m3); log(m3)
+ checkLog("getInt:2:getInt:2:getString:ss:getString:ss:getUnit:():():():getUnit:():():()")
+
+ log(vl1); log(vl1)
+ log(vl2); log(vl2)
+ log(vl3); log(vl3)
+ checkLog("2:2:ss:ss:():()")
+
+ log(vr1); log(vr1); vr1 = 393; log(vr1)
+ log(vr2); log(vr2); vr2 = "h"; log(vr2)
+ log(vr3); log(vr3); vr3 = () ; log(vr3)
+ checkLog("2:2:393:ss:ss:h:():():()")
+
+ log(lvl1); log(lvl1)
+ log(lvl2); log(lvl2)
+ log(lvl3); log(lvl3)
+ checkLog("getInt:2:2:getString:ss:ss:getUnit:():():():()")
+ }
+}
+
+class D extends T
+
+class D1 extends T {
+ override lazy val t1 = { log("o-t1"); -1 }
+ checkLog("")
+
+ override def m1 = { log("o-m1"); -2 }
+ override val m2 = { log("o-m2"); "n" }
+ override lazy val m3 = { log("o-m3") }
+ checkLog("o-m2")
+
+ override val vl1 = { log("o-vl1"); -3 }
+ checkLog("o-vl1")
+
+ override lazy val lvl1 = { log("o-lvl1"); -4 }
+ checkLog("")
+
+ override def run(): Unit = {
+ log(t1); log(t1)
+ checkLog("o-t1:-1:-1")
+
+ log(m1); log(m1)
+ log(m2); log(m2)
+ log(m3); log(m3)
+ checkLog("o-m1:-2:o-m1:-2:n:n:o-m3:():()")
+
+ log(vl1); log(vl1)
+ checkLog("-3:-3")
+
+ log(lvl1); log(lvl1)
+ checkLog("o-lvl1:-4:-4")
+ }
+}
+
+class E {
+ object T { log("init T"); override def toString = "T" }
+ def m = { object T { log("init T"); val x = 1 }; T.x }
+ checkLog("")
+}
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val c = new C
+ c.run()
+
+ val lzyComputeMethods = c.getClass.getDeclaredMethods.filter(_.getName contains "lzycompute").map(_.getName).toList.sorted
+ val expComputeMethods = List("lvl1$lzycompute", "lvl2$lzycompute", "lvl3$lzycompute", "t1$lzycompute", "t1$lzycompute$1", "t1$lzycompute$10", "t1$lzycompute$11", "t1$lzycompute$12", "t1$lzycompute$13", "t1$lzycompute$2", "t1$lzycompute$3", "t1$lzycompute$4", "t1$lzycompute$5", "t1$lzycompute$6", "t1$lzycompute$7", "t1$lzycompute$8", "t1$lzycompute$9", "t2$lzycompute", "t2$lzycompute$1", "t3$lzycompute", "t3$lzycompute$1")
+ assert(
+ lzyComputeMethods == expComputeMethods,
+ s"wrong lzycompute methods. expected:\n$expComputeMethods\nfound:\n$lzyComputeMethods")
+
+ val fields = c.getClass.getDeclaredFields.toList.sortBy(_.getName).map(_.toString)
+ val expFields = List(
+ "private volatile byte C.bitmap$0",
+ "private int C.lvl1",
+ "private java.lang.String C.lvl2",
+ "private scala.runtime.BoxedUnit C.lvl3",
+ "private int C.t1",
+ "private java.lang.String C.t2",
+ "private scala.runtime.BoxedUnit C.t3",
+ "private final int C.vl1",
+ "private final java.lang.String C.vl2",
+ "private final scala.runtime.BoxedUnit C.vl3",
+ "private int C.vr1",
+ "private java.lang.String C.vr2",
+ "private scala.runtime.BoxedUnit C.vr3")
+ assert(
+ fields == expFields,
+ s"wrong fields. expected:\n$expFields\nfound:\n$fields")
+
+
+ val d = new D
+ d.run()
+
+ val dFields = d.getClass.getDeclaredFields.toList.sortBy(_.getName).map(_.toString)
+ assert(
+ dFields == expFields.map(_.replaceAll(" C.", " D.")),
+ s"wrong fields. expected:\n$expFields\nfound:\n$fields")
+
+
+ val d1 = new D1
+ d1.run()
+
+ val e = new E
+ log(e.T); log(e.T)
+ checkLog("init T:T:T")
+ log(e.m); log(e.m)
+ checkLog("init T:1:init T:1")
+ }
+}
diff --git a/test/files/run/lazy-locals.check b/test/files/run/lazy-locals.check
index 4565326bea..0a3a85ead6 100644
--- a/test/files/run/lazy-locals.check
+++ b/test/files/run/lazy-locals.check
@@ -1,9 +1,6 @@
lazy-locals.scala:153: warning: a pure expression does nothing in statement position; multiline expressions may require enclosing parentheses
{
^
-lazy-locals.scala:159: warning: a pure expression does nothing in statement position; multiline expressions may require enclosing parentheses
- {
- ^
forced lazy val q
q = 10
forced lazy val t
diff --git a/test/files/run/lazy_local_labels.check b/test/files/run/lazy_local_labels.check
new file mode 100644
index 0000000000..e42c8fb8ce
--- /dev/null
+++ b/test/files/run/lazy_local_labels.check
@@ -0,0 +1,9 @@
+HI
+HI
+HI
+HI
+HI
+HI
+HI
+HI
+HI
diff --git a/test/files/run/lazy_local_labels.scala b/test/files/run/lazy_local_labels.scala
new file mode 100644
index 0000000000..f4a1cdf689
--- /dev/null
+++ b/test/files/run/lazy_local_labels.scala
@@ -0,0 +1,28 @@
+// should print HI nine times to indicate the lazy val has been re-initialized on every iteration
+object Test extends App {
+ def fooDo: Unit = {
+ var i = 3
+ do {
+ lazy val x = { println("HI"); 1 }
+ i -= x
+ } while(i > 0)
+ }
+
+ def fooWhile: Unit = {
+ var i = 3
+ while(i > 0) {
+ lazy val x = { println("HI"); 1 }
+ i -= x
+ }
+ }
+
+ @annotation.tailrec def fooTail(i: Int): Unit = {
+ lazy val x = { println("HI"); 1 }
+ if (i > 0) fooTail(i - x)
+ }
+
+
+ fooWhile
+ fooDo
+ fooTail(3)
+}
diff --git a/test/files/run/programmatic-main.check b/test/files/run/programmatic-main.check
index 03f8273c17..cf8595db5d 100644
--- a/test/files/run/programmatic-main.check
+++ b/test/files/run/programmatic-main.check
@@ -10,18 +10,17 @@ superaccessors 6 add super accessors in traits and nested classes
pickler 8 serialize symbol tables
refchecks 9 reference/override checking, translate nested objects
uncurry 10 uncurry, translate function values to anonymous classes
- fields 11 synthesize accessors and fields
+ fields 11 synthesize accessors and fields, including bitmaps for la...
tailcalls 12 replace tail calls by jumps
specialize 13 @specialized-driven class and method specialization
explicitouter 14 this refs to outer pointers
erasure 15 erase types, add interfaces for traits
posterasure 16 clean up erased inline classes
- lazyvals 17 allocate bitmaps, translate lazy vals into lazified defs
- lambdalift 18 move nested functions to top level
- constructors 19 move field definitions into constructors
- flatten 20 eliminate inner classes
- mixin 21 mixin composition
- cleanup 22 platform-specific cleanups, generate reflective calls
- delambdafy 23 remove lambdas
- jvm 24 generate JVM bytecode
- terminal 25 the last phase during a compilation run
+ lambdalift 17 move nested functions to top level
+ constructors 18 move field definitions into constructors
+ flatten 19 eliminate inner classes
+ mixin 20 mixin composition
+ cleanup 21 platform-specific cleanups, generate reflective calls
+ delambdafy 22 remove lambdas
+ jvm 23 generate JVM bytecode
+ terminal 24 the last phase during a compilation run
diff --git a/test/files/run/showraw_mods.check b/test/files/run/showraw_mods.check
index ff77d22adf..5afd7a438f 100644
--- a/test/files/run/showraw_mods.check
+++ b/test/files/run/showraw_mods.check
@@ -1 +1 @@
-Block(List(ClassDef(Modifiers(ABSTRACT | DEFAULTPARAM/TRAIT), TypeName("C"), List(), Template(List(Ident(TypeName("AnyRef"))), noSelfType, List(DefDef(Modifiers(), TermName("$init$"), List(), List(List()), TypeTree(), Block(List(), Literal(Constant(())))), DefDef(Modifiers(PRIVATE | METHOD | LOCAL | STABLE | ACCESSOR), TermName("x"), List(), List(), TypeTree(), Literal(Constant(2))), DefDef(Modifiers(METHOD | ACCESSOR), TermName("y"), List(), List(), TypeTree(), Select(This(TypeName("C")), TermName("x"))), DefDef(Modifiers(METHOD | ACCESSOR), TermName("y_$eq"), List(), List(List(ValDef(Modifiers(PARAM | SYNTHETIC), TermName("x$1"), TypeTree(), EmptyTree))), TypeTree(), EmptyTree), ValDef(Modifiers(LAZY), TermName("z"), TypeTree(), Select(This(TypeName("C")), TermName("y"))))))), Literal(Constant(())))
+Block(List(ClassDef(Modifiers(ABSTRACT | DEFAULTPARAM/TRAIT), TypeName("C"), List(), Template(List(Ident(TypeName("AnyRef"))), noSelfType, List(DefDef(Modifiers(), TermName("$init$"), List(), List(List()), TypeTree(), Block(List(), Literal(Constant(())))), ValDef(Modifiers(PRIVATE | LOCAL), TermName("x"), TypeTree(), Literal(Constant(2))), ValDef(Modifiers(MUTABLE), TermName("y"), TypeTree(), Select(This(TypeName("C")), TermName("x"))), DefDef(Modifiers(METHOD | ACCESSOR), TermName("y_$eq"), List(), List(List(ValDef(Modifiers(PARAM | SYNTHETIC), TermName("x$1"), TypeTree(), EmptyTree))), TypeTree(), EmptyTree), ValDef(Modifiers(LAZY), TermName("z"), TypeTree(), Select(This(TypeName("C")), TermName("y"))))))), Literal(Constant(())))
diff --git a/test/files/run/t3569.check b/test/files/run/t3569.check
index a9fb5ff32e..e0e1d6c405 100644
--- a/test/files/run/t3569.check
+++ b/test/files/run/t3569.check
@@ -2,6 +2,8 @@
private final int Test$X.val1
private final int Test$X.val2
private final int Test$X.val3
+private int Test$X.const1
+private int Test$X.const2
private int Test$X.lval1
private int Test$X.lval2
private int Test$X.lval3
diff --git a/test/files/run/t3569.scala b/test/files/run/t3569.scala
index eb3b424439..7da4de9e95 100644
--- a/test/files/run/t3569.scala
+++ b/test/files/run/t3569.scala
@@ -4,7 +4,13 @@ object Test {
lazy val lv = scala.util.Random.nextInt()
- class X(final var x: Int) {
+ trait T { final lazy val const1 = 1 } // no fields
+
+ class X(final var x: Int) extends T {
+ // a lazy val does not receive a constant type, for backwards compat (e.g. for the repl)
+ // besides, since you explicitly wanted something lazy, we'll give you something lazy! (a field and a bitmap)
+ final lazy val const2 = 2
+
final var var1: Int = 0
final private var var2: Int = 0
final private[this] var var3: Int = 0
diff --git a/test/files/run/t5552.check b/test/files/run/t5552.check
index a19a60840e..73ad9cf824 100644
--- a/test/files/run/t5552.check
+++ b/test/files/run/t5552.check
@@ -1,2 +1,6 @@
+lazy: 3
(3,3)
+(3,3)
+lazy: 3.0
+(3.0,3.0)
(3.0,3.0)
diff --git a/test/files/run/t5552.scala b/test/files/run/t5552.scala
index afb8a1f0be..5b717f9e13 100644
--- a/test/files/run/t5552.scala
+++ b/test/files/run/t5552.scala
@@ -1,10 +1,14 @@
class C[@specialized(Int) A](a:A) {
- lazy val b = (a, a)
+ lazy val b = {println(s"lazy: $a"); (a, a)} // there should only be two instances of "lazy" in the output
def c = b
}
object Test {
def main(args:Array[String]) {
- println(new C(3).c)
- println(new C(3.0).c)
+ val cInt = new C(3)
+ println(cInt.c)
+ println(cInt.c)
+ val cFloat = new C(3.0)
+ println(cFloat.c)
+ println(cFloat.c)
}
}
diff --git a/test/files/run/t6023.check b/test/files/run/t6023.check
index ee93565234..dd6d8f1f1c 100644
--- a/test/files/run/t6023.check
+++ b/test/files/run/t6023.check
@@ -1,12 +1,12 @@
{
abstract trait Foo extends AnyRef {
- <stable> <accessor> def a: Int
+ val a: Int
};
()
}
{
abstract trait Foo extends AnyRef {
- <stable> <accessor> def a: Int
+ <stable> <accessor> val a: Int
};
()
}
diff --git a/test/files/run/t6028.check b/test/files/run/t6028.check
index 532d177300..d6cc452bbf 100644
--- a/test/files/run/t6028.check
+++ b/test/files/run/t6028.check
@@ -54,18 +54,12 @@ package <empty> {
<synthetic> <stable> <artifact> def $outer(): T = MethodLocalObject$2.this.$outer;
<synthetic> <stable> <artifact> def $outer(): T = MethodLocalObject$2.this.$outer
};
- final <stable> private[this] def MethodLocalObject$lzycompute$1(barParam$1: Int, MethodLocalObject$module$1: runtime.VolatileObjectRef): T#MethodLocalObject$2.type = {
- T.this.synchronized({
- 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);
- scala.runtime.BoxedUnit.UNIT
- });
+ final <stable> 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));
MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]()
};
- final <stable> 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)
- else
- MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]();
@SerialVersionUID(value = 0) final <synthetic> class $anonfun$tryy$1 extends scala.runtime.AbstractFunction0$mcV$sp with Serializable {
def <init>($outer: T, tryyParam$1: Int, tryyLocal$1: runtime.IntRef): <$anon: Function0> = {
$anonfun$tryy$1.super.<init>();
diff --git a/test/files/run/t6733.check b/test/files/run/t6733.check
index 7062301c56..811a7d8f70 100644
--- a/test/files/run/t6733.check
+++ b/test/files/run/t6733.check
@@ -4,7 +4,6 @@ method pri2a: isPrivateThis = true, isProtectedThis = false
variable pri3a: isPrivateThis = true, isProtectedThis = false
variable pri3a: isPrivateThis = true, isProtectedThis = false
lazy value pri4a: isPrivateThis = true, isProtectedThis = false
-lazy value pri4a: isPrivateThis = true, isProtectedThis = false
type Pri5a: isPrivateThis = true, isProtectedThis = false
class Pri6: isPrivateThis = true, isProtectedThis = false
trait Pri7: isPrivateThis = true, isProtectedThis = false
@@ -18,7 +17,6 @@ variable pro3a: isPrivateThis = false, isProtectedThis = true
variable pro3b: isPrivateThis = false, isProtectedThis = true
variable pro3b: isPrivateThis = false, isProtectedThis = true
lazy value pro4a: isPrivateThis = false, isProtectedThis = true
-lazy value pro4a: isPrivateThis = true, isProtectedThis = false
type Pro5a: isPrivateThis = false, isProtectedThis = true
type Pro5b: isPrivateThis = false, isProtectedThis = true
class Pro6: isPrivateThis = false, isProtectedThis = true
diff --git a/test/files/run/trait-fields-override-lazy.check b/test/files/run/trait-fields-override-lazy.check
new file mode 100644
index 0000000000..9e4a9fe6c2
--- /dev/null
+++ b/test/files/run/trait-fields-override-lazy.check
@@ -0,0 +1,2 @@
+warning: there was one feature warning; re-run with -feature for details
+ok
diff --git a/test/files/run/trait-fields-override-lazy.scala b/test/files/run/trait-fields-override-lazy.scala
new file mode 100644
index 0000000000..2c1cf0e3b0
--- /dev/null
+++ b/test/files/run/trait-fields-override-lazy.scala
@@ -0,0 +1,13 @@
+trait T {
+ protected lazy val lv: Boolean = ???
+}
+
+object Test extends App {
+ val overrideLazy = new T {
+ override lazy val lv = true
+ def foo = lv
+ }
+
+ assert(overrideLazy.foo)
+ println("ok")
+}
diff --git a/test/files/scalacheck/quasiquotes/TypecheckedProps.scala b/test/files/scalacheck/quasiquotes/TypecheckedProps.scala
index fe07893a36..07bff40f13 100644
--- a/test/files/scalacheck/quasiquotes/TypecheckedProps.scala
+++ b/test/files/scalacheck/quasiquotes/TypecheckedProps.scala
@@ -103,7 +103,7 @@ object TypecheckedProps extends QuasiquoteProperties("typechecked")
val lazyName = TermName("x")
val lazyRhsVal = 42
val lazyRhs = Literal(Constant(lazyRhsVal))
- val q"{ $_ ; $mods val $pname: $_ = { $_ = $rhs ; $_ } }" = typecheck(q"{lazy val $lazyName = $lazyRhsVal}")
+ val q"{ $mods val $pname: $_ = $rhs }" = typecheck(q"{lazy val $lazyName = $lazyRhsVal}")
assert(pname == lazyName)
assert(rhs ≈ lazyRhs)
diff --git a/test/junit/scala/lang/traits/BytecodeTest.scala b/test/junit/scala/lang/traits/BytecodeTest.scala
index e6c74b86ab..cf658288c4 100644
--- a/test/junit/scala/lang/traits/BytecodeTest.scala
+++ b/test/junit/scala/lang/traits/BytecodeTest.scala
@@ -9,7 +9,6 @@ import scala.collection.JavaConverters._
import scala.tools.asm.Opcodes
import scala.tools.asm.Opcodes._
import scala.tools.asm.tree.ClassNode
-import scala.tools.nsc.backend.jvm.opt.BytecodeUtils
import scala.tools.partest.ASMConverters._
import scala.tools.testing.BytecodeTesting
import scala.tools.testing.BytecodeTesting._
@@ -237,7 +236,7 @@ class BytecodeTest extends BytecodeTesting {
|class C extends T
""".stripMargin
val List(c1, _) = compileClasses(code)
- val List(c2, _) = newCompiler(extraArgs = "-Xgen-mixin-forwarders").compileClasses(code)
+ val List(c2, _) = newCompiler(extraArgs = "-Xmixin-force-forwarders:true").compileClasses(code)
assert(getMethods(c1, "f").isEmpty)
assertSameCode(getMethod(c2, "f"),
List(VarOp(ALOAD, 0), Invoke(INVOKESTATIC, "T", "f$", "(LT;)I", true), Op(IRETURN)))
@@ -245,7 +244,6 @@ class BytecodeTest extends BytecodeTesting {
@Test
def sd143(): Unit = {
- // this tests the status quo, which is wrong.
val code =
"""class A { def m = 1 }
|class B extends A { override def m = 2 }
@@ -254,10 +252,119 @@ class BytecodeTest extends BytecodeTesting {
| override def m = super[T].m // should invoke A.m
|}
""".stripMargin
+
+ val err =
+ """cannot emit super call: the selected method m is declared in class A, which is not the direct superclass of class C.
+ |An unqualified super call (super.m) would be allowed.""".stripMargin
+ val cls = compileClasses(code, allowMessage = _.msg contains err)
+ assert(cls.isEmpty, cls.map(_.name))
+ }
+
+ @Test
+ def sd143b(): Unit = {
+ val jCode = List("interface A { default int m() { return 1; } }" -> "A.java")
+ val code =
+ """class B extends A { override def m = 2 }
+ |trait T extends A
+ |class C extends B with T {
+ | override def m = super[T].m
+ |}
+ """.stripMargin
+
+ val err = "unable to emit super call unless interface A (which declares method m) is directly extended by class C"
+ val cls = compileClasses(code, jCode, allowMessage = _.msg contains err)
+ assert(cls.isEmpty, cls.map(_.name))
+ }
+
+ @Test
+ def sd143c(): Unit = {
+ // Allow super calls to class methods of indirect super classes
+ val code =
+ """class A { def f = 1 }
+ |class B extends A
+ |trait T extends A { override def f = 2 }
+ |class C extends B with T {
+ | def t1 = super[B].f
+ | def t2 = super.f
+ | def t3 = super[T].f
+ |}
+ """.stripMargin
val List(_, _, c, _) = compileClasses(code)
- // even though the bytecode refers to A.m, invokespecial will resolve to B.m
- assertSameCode(getMethod(c, "m"),
- List(VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "A", "m", "()I", false), Op(IRETURN)))
+ val t1 = getInstructions(c, "t1")
+ assert(t1 contains Invoke(INVOKESPECIAL, "A", "f", "()I", false), t1.stringLines)
+ val t2 = getInstructions(c, "t2")
+ val invStat = Invoke(INVOKESTATIC, "T", "f$", "(LT;)I", true)
+ assert(t2 contains invStat, t2.stringLines)
+ val t3 = getInstructions(c, "t3")
+ assert(t3 contains invStat, t3.stringLines)
+ }
+
+ @Test
+ def sd210(): Unit = {
+ val forwardersCompiler = newCompiler(extraArgs = "-Xmixin-force-forwarders:true")
+ val jCode = List("interface A { default int m() { return 1; } }" -> "A.java")
+
+
+ // used to crash in the backend (SD-210) under `-Xmixin-force-forwarders:true`
+ val code1 =
+ """trait B1 extends A // called "B1" not "B" due to scala-dev#214
+ |class C extends B1
+ """.stripMargin
+
+ val List(_, c1a) = compileClasses(code1, jCode)
+ assert(getAsmMethods(c1a, "m").isEmpty) // ok, no forwarder
+
+ // here we test a warning. without `-Xmixin-force-forwarders:true`, the forwarder would not be
+ // generated, it is not necessary for correctness.
+ val warn = "Unable to implement a mixin forwarder for method m in class C unless interface A is directly extended by class C"
+ val List(_, c1b) = forwardersCompiler.compileClasses(code1, jCode, allowMessage = _.msg.contains(warn))
+ assert(getAsmMethods(c1a, "m").isEmpty) // no forwarder
+
+
+ val code2 =
+ """abstract class B { def m(): Int }
+ |trait T extends B with A
+ |class C extends T
+ """.stripMargin
+
+ // here we test a compilation error. the forwarder is required for correctness, but it cannot be generated.
+ val err = "Unable to implement a mixin forwarder for method m in class C unless interface A is directly extended by class C"
+ val cs = compileClasses(code2, jCode, allowMessage = _.msg contains err)
+ assert(cs.isEmpty, cs.map(_.name))
+
+
+ val code3 =
+ """abstract class B { def m: Int }
+ |class C extends B with A
+ """.stripMargin
+
+ val List(_, c3) = compileClasses(code3, jCode)
+ // invokespecial to A.m is correct here: A is an interface, so resolution starts at A.
+ // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokespecial
+ val ins3 = getMethod(c3, "m").instructions
+ assert(ins3 contains Invoke(INVOKESPECIAL, "A", "m", "()I", true), ins3.stringLines)
+
+
+ val code4 =
+ """trait B { self: A => override def m = 2 }
+ |class C extends A with B // forwarder, invokestatic B.m$
+ """.stripMargin
+
+ val List(_, c4) = compileClasses(code4, jCode)
+ val ins4 = getMethod(c4, "m").instructions
+ assert(ins4 contains Invoke(INVOKESTATIC, "B", "m$", "(LB;)I", true), ins4.stringLines)
+
+
+ // scala-only example
+ val code5 =
+ """trait AS { def m = 1 }
+ |abstract class B { def m: Int }
+ |class C extends B with AS // forwarder, invokestatic AS.m$
+ """.stripMargin
+
+ val List(_, _, c5) = compileClasses(code5)
+ val ins5 = getMethod(c5, "m").instructions
+ assert(ins5 contains Invoke(INVOKESTATIC, "AS", "m$", "(LAS;)I", true), ins5.stringLines)
}
}
diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala
index 234f22e9fb..722062ba21 100644
--- a/test/junit/scala/reflect/internal/PrintersTest.scala
+++ b/test/junit/scala/reflect/internal/PrintersTest.scala
@@ -151,7 +151,7 @@ class BasePrintTest {
|else
| ((a.toString): String)""",
typedCode=sm"""
- |val a: Int = 1;
+ |val a = 1;
|if (PrintersContext.this.a.>(1))
| ((PrintersContext.this.a): scala.Int)
|else
@@ -864,7 +864,7 @@ class TraitPrintTest {
@Test def testTraitWithSelf2 = assertPrintedCode(sm"""
|trait X { self: scala.Cloneable with scala.Serializable =>
- | val x: Int = 1
+ | val x: scala.Int = 1
|}""")
@Test def testTraitTypeParams = assertPrintedCode("trait X[A, B]")
@@ -903,7 +903,7 @@ class TraitPrintTest {
| type Foo;
| type XString = scala.Predef.String
|} with scala.Serializable {
- | val z: Int = 7
+ | val z: scala.Int = 7
|}""")
@Test def testTraitWithSingletonTypeTree = assertPrintedCode(sm"""
@@ -1008,27 +1008,16 @@ class ValAndDefPrintTest {
@Test def testDef9 = assertPrintedCode("def a(x: scala.Int)(implicit z: scala.Double, y: scala.Float): scala.Unit = ()")
- @Test def testDefWithLazyVal1 = assertResultCode(
- code = "def a = { lazy val test: Int = 42 }")(
- parsedCode = sm"""
+ @Test def testDefWithLazyVal1 = assertPrintedCode(sm"""
|def a = {
- | lazy val test: Int = 42;
+ | lazy val test: scala.Int = 42;
| ()
|}
- """,
- typedCode = sm"""
- |def a = {
- | lazy val test$$lzy: scala.Int = _;
- | lazy val test: Int = {
- | test$$lzy = 42;
- | test$$lzy
- | };
- | ()
- |}""")
+ """)
@Test def testDefWithLazyVal2 = assertPrintedCode(sm"""
|def a = {
- | lazy val test: Unit = {
+ | lazy val test: scala.Unit = {
| scala.Predef.println();
| scala.Predef.println()
| };
diff --git a/test/junit/scala/runtime/LambdaDeserializerTest.java b/test/junit/scala/runtime/LambdaDeserializerTest.java
index 3ed1ae1365..4e9c5c8954 100644
--- a/test/junit/scala/runtime/LambdaDeserializerTest.java
+++ b/test/junit/scala/runtime/LambdaDeserializerTest.java
@@ -136,6 +136,7 @@ public final class LambdaDeserializerTest {
}
}
+ @SuppressWarnings("unchecked")
private <A> A deserizalizeLambdaCreatingAllowedMap(A f1, HashMap<String, MethodHandle> cache, MethodHandles.Lookup lookup) {
SerializedLambda serialized = writeReplace(f1);
HashMap<String, MethodHandle> allowed = createAllowedMap(lookup, serialized);
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 5bd2ce68f1..85b44d9fa0 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
@@ -57,7 +57,7 @@ class InlineWarningTest extends BytecodeTesting {
assert(c == 1, c)
}
- @Test
+// @Test -- TODO
def mixedWarnings(): Unit = {
val javaCode =
"""public class A {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
index 29a23df784..9999cdb376 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -726,7 +726,7 @@ class InlinerTest extends BytecodeTesting {
"""sealed trait T {
| lazy val a = 0
| val b = 1
- | final lazy val c = 2
+ | final lazy val c: Int = 2 // make sure it doesn't get a constant type
| final val d = 3
| final val d1: Int = 3
|
@@ -740,7 +740,7 @@ class InlinerTest extends BytecodeTesting {
|trait U { // not sealed
| lazy val a = 0
| val b = 1
- | final lazy val c = 2
+ | final lazy val c: Int = 2 // make sure it doesn't get a constant type
| final val d = 3
| final val d1: Int = 3
|
@@ -766,7 +766,7 @@ class InlinerTest extends BytecodeTesting {
val m1 = getMethod(c, "m1")
assertInvoke(m1, "T", "a")
assertInvoke(m1, "T", "b")
- assertInvoke(m1, "T", "c")
+// assertInvoke(m1, "T", "c") -- this lazy val is implemented purely in the trait, as it's constant, so it *can* be inlined
assertNoInvoke(getMethod(c, "m2"))
@@ -779,7 +779,7 @@ class InlinerTest extends BytecodeTesting {
val m4 = getMethod(c, "m4")
assertInvoke(m4, "U", "a")
assertInvoke(m4, "U", "b")
- assertInvoke(m4, "U", "c")
+// assertInvoke(m4, "U", "c") -- this lazy val is implemented purely in the trait, as it's constant, so it *can* be inlined
assertNoInvoke(getMethod(c, "m5"))
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 56da0e2493..eae5385147 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/ScalaInlineInfoTest.scala
@@ -105,7 +105,6 @@ 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$lzycompute$1(Lscala/runtime/VolatileObjectRef;)LT$L$2$;", 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))),
@@ -118,7 +117,6 @@ class ScalaInlineInfoTest extends BytecodeTesting {
val infoC = inlineInfo(c)
val expectC = InlineInfo(false, None, Map(
"O()LT$O$;" -> MethodInlineInfo(true ,false,false),
- "O$lzycompute()LT$O$;" -> MethodInlineInfo(true, false,false),
"f6()I" -> MethodInlineInfo(false,false,false),
"x1()I" -> MethodInlineInfo(false,false,false),
"T$_setter_$x1_$eq(I)V" -> MethodInlineInfo(false,false,false),
@@ -181,7 +179,6 @@ class ScalaInlineInfoTest extends BytecodeTesting {
val infoC = inlineInfo(c)
val expected = Map(
"<init>()V" -> MethodInlineInfo(false,false,false),
- "O$lzycompute()LC$O$;" -> MethodInlineInfo(true,false,false),
"O()LC$O$;" -> MethodInlineInfo(true,false,false))
assert(infoC.methodInfos == expected, mapDiff(infoC.methodInfos, expected))
assertSameMethods(c, expected.keySet)
diff --git a/test/junit/scala/tools/testing/ClearAfterClass.java b/test/junit/scala/tools/testing/ClearAfterClass.java
index 95e170ec13..7f87f9a4d7 100644
--- a/test/junit/scala/tools/testing/ClearAfterClass.java
+++ b/test/junit/scala/tools/testing/ClearAfterClass.java
@@ -45,6 +45,7 @@ public class ClearAfterClass {
}
}
+ @SuppressWarnings("unchecked")
public <T> T cached(String key, scala.Function0<T> t) {
Map<String, Object> perClassCache = cache.get(getClass());
return (T) perClassCache.computeIfAbsent(key, s -> t.apply());
diff --git a/test/scaladoc/run/t7767.scala b/test/scaladoc/run/t7767.scala
index 6c9ceb511d..433fc5c0c4 100644
--- a/test/scaladoc/run/t7767.scala
+++ b/test/scaladoc/run/t7767.scala
@@ -4,15 +4,49 @@ import scala.tools.partest.ScaladocModelTest
object Test extends ScaladocModelTest {
override def code = """
- class Docable extends { /**Doc*/ val foo = 0 } with AnyRef
- """
+ class CEarly extends { /**CEarly_Doc_foo*/ val foo = 0 } with AnyRef
+ trait TEarly extends { /**TEarly_Doc_foo*/ val foo = 0 } with AnyRef
+ class C {
+ /**C_Doc_sigInferred*/ val sigInferred = 0
+ /**C_Doc_const*/ final val const = 0
+ /**C_Doc_varr*/ var varr: Any = null
+ /**C_Doc_abs*/ val abs: Int
+ /**C_Doc_absVar*/ var absVar: Any
+ /**C_Doc_lazyValInferred*/ lazy val lazyValInferred = 0
+ /**C_Doc_lazyValConst*/ final lazy val lazyValConst = 0
+ /**C_Doc_lazyValUnit*/ lazy val lazyValUnit: Unit = println()
+ /**C_Doc_lazyVal*/ lazy val lazyVal: Int = 0
+ }
+ trait T {
+ /**T_Doc_sigInferred*/ val sigInferred = 0
+ /**T_Doc_const*/ final val const = 0
+ /**T_Doc_varr*/ var varr: Any = null
+ /**T_Doc_abs*/ val abs: Int
+ /**T_Doc_absVar*/ var absVar: Any
+ /**T_Doc_lazyValInferred*/ lazy val lazyValInferred = 0
+ /**T_Doc_lazyValConst*/ final lazy val lazyValConst = 0
+ /**T_Doc_lazyValUnit*/ lazy val lazyValUnit: Unit = println()
+ /**T_Doc_lazyVal*/ lazy val lazyVal: Int = 0
+ }"""
// no need for special settings
def scaladocSettings = ""
+ def assertDoc(classEntity: DocTemplateEntity, valName: String) = {
+ import access._
+ val comment = classEntity._value(valName).comment.map(_.body.toString.trim).getOrElse("")
+ val className = classEntity.name
+ val marker = s"${className}_Doc_${valName}"
+ assert(comment.contains(marker), s"Expected $marker in comment for $valName in $className, found: $comment.")
+ }
+
def testModel(rootPackage: Package) = {
import access._
- val comment = rootPackage._class("Docable")._value("foo").comment.map(_.body.toString.trim).getOrElse("")
- assert(comment.contains("Doc"), comment)
+ assertDoc(rootPackage._class("CEarly"), "foo")
+ assertDoc(rootPackage._trait("TEarly"), "foo")
+
+ val valNames = List("sigInferred", "const", "varr", "abs", "absVar", "lazyValInferred", "lazyValConst", "lazyValUnit", "lazyVal")
+ val entities = List(rootPackage._class("C"), rootPackage._trait("T"))
+ for (e <- entities; vn <- valNames) assertDoc(e, vn)
}
}
diff --git a/tools/binary-repo-lib.sh b/tools/binary-repo-lib.sh
deleted file mode 100755
index 278804e30e..0000000000
--- a/tools/binary-repo-lib.sh
+++ /dev/null
@@ -1,234 +0,0 @@
-#!/usr/bin/env bash
-#
-# Library to push and pull binary artifacts from a remote repository using CURL.
-
-remote_urlget="https://dl.bintray.com/typesafe/scala-sha-bootstrap/org/scala-lang/bootstrap"
-remote_urlpush="https://dl.bintray.com/typesafe/scala-sha-bootstrap/org/scala-lang/bootstrap"
-libraryJar="$(pwd)/lib/scala-library.jar"
-desired_ext=".desired.sha1"
-push_jar="$(pwd)/tools/push.jar"
-
-if [[ "$OSTYPE" == *Cygwin* || "$OSTYPE" == *cygwin* ]]; then push_jar="$(cygpath -m "$push_jar")"; fi
-# Cache dir has .sbt in it to line up with SBT build.
-SCALA_BUILD_REPOS_HOME=${SCALA_BUILD_REPOS_HOME:=$HOME}
-cache_dir="${SCALA_BUILD_REPOS_HOME}/.sbt/cache/scala"
-
-# Checks whether or not curl is installed and issues a warning on failure.
-checkCurl() {
- if ! which curl >/dev/null; then
- cat <<EOM
-No means of downloading or uploading binary artifacts found.
-
-Please install curl for your OS. e.g.
-* sudo apt-get install curl
-* brew install curl
-EOM
- fi
-}
-
-# Executes the `curl` command to publish artifacts into a maven/ivy repository.
-# Arugment 1 - The location to publish the file.
-# Argument 2 - The file to publish.
-# Argument 3 - The user to publish as.
-# Argument 4 - The password for the user.
-curlUpload() {
- checkCurl
- local remote_location=$1
- local data=$2
- local user=$3
- local password=$4
- local url="${remote_urlpush}/${remote_location}"
- java -jar $push_jar "$data" "$url" "$user" "$password"
- if (( $? != 0 )); then
- echo "Error uploading $data to $url"
- echo "$url"
- exit 1
- fi
-}
-
-# Executes the `curl` command to download a file.
-# Argument 1 - The location to store the file.
-# Argument 2 - The URL to download.
-curlDownload() {
- checkCurl
- local jar=$1
- local url=$2
- if [[ "$OSTYPE" == *Cygwin* || "$OSTYPE" == *cygwin* ]]; then
- jar=$(cygpath -m $1)
- fi
- http_code=$(curl --write-out '%{http_code}' --silent --fail -L --output "$jar" "$url")
- if (( $? != 0 )); then
- echo "Error downloading $jar: response code: $http_code"
- echo "$url"
- exit 1
- fi
-}
-
-# Pushes a local JAR file to the remote repository and updates the .desired.sha1 file.
-# Argument 1 - The JAR file to update.
-# Argument 2 - The root directory of the project.
-# Argument 3 - The user to use when publishing artifacts.
-# Argument 4 - The password to use when publishing artifacts.
-pushJarFile() {
- local jar=$1
- local basedir=$2
- local user=$3
- local pw=$4
- local jar_dir=$(dirname $jar)
- local jar_name=${jar#$jar_dir/}
- pushd $jar_dir >/dev/null
- local version=$(makeJarSha $jar_name)
- local remote_uri=${version}${jar#$basedir}
- echo " Pushing to ${remote_urlpush}/${remote_uri} ..."
- echo " $curl"
- curlUpload $remote_uri $jar_name $user $pw
- echo " Making new sha1 file ...."
- echo "$version ?$jar_name" > "${jar_name}${desired_ext}"
- popd >/dev/null
- # TODO - Git remove jar and git add jar.desired.sha1
- # rm $jar
-}
-
-makeJarSha() {
- local jar=$1
- if which sha1sum 2>/dev/null >/dev/null; then
- shastring=$(sha1sum "$jar")
- echo "$shastring" | sed 's/ .*//'
- elif which shasum 2>/dev/null >/dev/null; then
- shastring=$(shasum "$jar")
- echo "$shastring" | sed 's/ .*//'
- else
- shastring=$(openssl sha1 "$jar")
- echo "$shastring" | sed 's/^.*= //'
- fi
-}
-
-getJarSha() {
- local jar=$1
- if [[ ! -f "$jar" ]]; then
- echo ""
- else
- echo $(makeJarSha $jar)
- fi
-}
-
-# Tests whether or not the .desired.sha1 hash matches a given file.
-# Arugment 1 - The jar file to test validity.
-# Returns: Empty string on failure, "OK" on success.
-isJarFileValid() {
- local jar=$1
- if [[ ! -f "$jar" ]]; then
- echo ""
- else
- local jar_dir=$(dirname $jar)
- local jar_name=${jar#$jar_dir/}
- pushd $jar_dir >/dev/null
- local valid=$(shasum -p --check ${jar_name}${desired_ext} 2>/dev/null)
- echo "${valid#$jar_name: }"
- popd >/dev/null
- fi
-}
-
-# Pushes any jar file in the local repository for which the corresponding SHA1 hash is invalid or nonexistent.
-# Argument 1 - The base directory of the project.
-# Argument 2 - The user to use when pushing artifacts.
-# Argument 3 - The password to use when pushing artifacts.
-pushJarFiles() {
- local basedir=$1
- local user=$2
- local password=$3
- # TODO - ignore target/ and build/
- local jarFiles="$(find ${basedir}/lib -name "*.jar") $(find ${basedir}/test/files -name "*.jar") $(find ${basedir}/tools -name "*.jar")"
- local changed="no"
- for jar in $jarFiles; do
- local valid=$(isJarFileValid $jar)
- if [[ "$valid" != "OK" ]]; then
- echo "$jar has changed, pushing changes...."
- changed="yes"
- pushJarFile $jar $basedir $user $password
- fi
- done
- if test "$changed" == "no"; then
- echo "No jars have been changed."
- else
- echo "Binary changes have been pushed. You may now submit the new *${desired_ext} files to git."
- fi
-}
-
-
-checkJarSha() {
- local jar=$1
- local sha=$2
- local testsha=$(getJarSha "$jar")
- if test "$sha" == "$testsha"; then
- echo "OK"
- fi
-}
-
-makeCacheLocation() {
- local uri=$1
- local sha=$2
- local cache_loc="$cache_dir/$uri"
- local cdir=$(dirname $cache_loc)
- if [[ ! -d "$cdir" ]]; then
- mkdir -p "$cdir"
- fi
- echo "$cache_loc"
-}
-
-# Pulls a single binary artifact from a remote repository.
-# Argument 1 - The uri to the file that should be downloaded.
-# Argument 2 - SHA of the file...
-# Returns: Cache location.
-pullJarFileToCache() {
- local uri=$1
- local sha=$2
- local cache_loc="$(makeCacheLocation $uri)"
- # TODO - Check SHA of local cache is accurate.
- if test -f "$cache_loc" && test "$(checkJarSha "$cache_loc" "$sha")" != "OK"; then
- echo "Found bad cached file: $cache_loc"
- rm -f "$cache_loc"
- fi
- if [[ ! -f "$cache_loc" ]]; then
- # Note: After we follow up with JFrog, we should check the more stable raw file server first
- # before hitting the more flaky artifactory.
- curlDownload $cache_loc ${remote_urlget}/${uri}
- if test "$(checkJarSha "$cache_loc" "$sha")" != "OK"; then
- echo "Trouble downloading $uri. Please try pull-binary-libs again when your internet connection is stable."
- exit 2
- fi
- fi
-}
-
-# Pulls a single binary artifact from a remote repository.
-# Argument 1 - The jar file that needs to be downloaded.
-# Argument 2 - The root directory of the project.
-pullJarFile() {
- local jar=$1
- local basedir=$2
- local sha1=$(cat ${jar}${desired_ext})
- local jar_dir=$(dirname $jar)
- local jar_name=${jar#$jar_dir/}
- local version=${sha1%% *}
- local remote_uri=${version}/${jar#$basedir/}
- echo "Resolving [${remote_uri}]"
- pullJarFileToCache $remote_uri $version
- local cached_file=$(makeCacheLocation $remote_uri)
- cp $cached_file $jar
-}
-
-# Pulls binary artifacts from the remote repository.
-# Argument 1 - The directory to search for *.desired.sha1 files that need to be retrieved.
-pullJarFiles() {
- local basedir=$1
- local desiredFiles="$(find ${basedir}/lib -name *${desired_ext}) $(find ${basedir}/test/files -name *${desired_ext}) $(find ${basedir}/tools -name *${desired_ext})"
- for sha in $desiredFiles; do
- jar=${sha%$desired_ext}
- local valid=$(isJarFileValid $jar)
- if [[ "$valid" != "OK" ]]; then
- pullJarFile $jar $basedir
- fi
- done
-}
-
-
diff --git a/tools/deploy-local-maven-snapshot b/tools/deploy-local-maven-snapshot
deleted file mode 100755
index 30f78cb110..0000000000
--- a/tools/deploy-local-maven-snapshot
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-#
-# Install the -SNAPSHOT artifacts in the local maven cache.
-
-set -e
-
-cd $(dirname $0)/..
-
-ant fastdist distpack
-cd dists/maven/latest
-ant deploy.snapshot.local
diff --git a/tools/new-starr b/tools/new-starr
deleted file mode 100755
index 5f00cc758e..0000000000
--- a/tools/new-starr
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-ant -Dscalac.args.optimise="-optimise" locker.done
-cp -R src/starr/* src/
-ant build-opt
-ant starr.done
diff --git a/tools/push.jar.desired.sha1 b/tools/push.jar.desired.sha1
deleted file mode 100644
index 63e6a47372..0000000000
--- a/tools/push.jar.desired.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a1883f4304d5aa65e1f6ee6aad5900c62dd81079 ?push.jar