diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2013-04-02 11:31:35 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2013-04-02 15:20:53 +0200 |
commit | 51d96a32f1726f5152b1b6ff9a469944c8a77e94 (patch) | |
tree | ecb17550e07c09acd5db362a3f7ee8b9d4eaacc4 | |
parent | 00e6c8b9e395cae3b761b848482bc91c7634ec13 (diff) | |
parent | a4785baf83f8655399bcfe865962fe4d1ef48e59 (diff) | |
download | scala-51d96a32f1726f5152b1b6ff9a469944c8a77e94.tar.gz scala-51d96a32f1726f5152b1b6ff9a469944c8a77e94.tar.bz2 scala-51d96a32f1726f5152b1b6ff9a469944c8a77e94.zip |
Merge remote tracking branch 'origin/2.10.x' into topic/merge-2.10.x-to-v2.11.0-M2-74-g00e6c8b
Conflicts:
bincompat-backward.whitelist.conf
bincompat-forward.whitelist.conf
build.xml
src/compiler/scala/reflect/reify/utils/Extractors.scala
src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
src/compiler/scala/tools/nsc/typechecker/Typers.scala
src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
src/reflect/scala/reflect/internal/Types.scala
src/reflect/scala/reflect/runtime/JavaUniverse.scala
test/files/run/inline-ex-handlers.check
test/files/run/t6223.check
test/files/run/t6223.scala
test/scaladoc/scalacheck/IndexTest.scala
76 files changed, 1862 insertions, 2495 deletions
@@ -44,8 +44,8 @@ targets exercised: <target name="distpack-maven" depends="dist.done, docs.done"> <ant antfile="${src.dir}/build/pack.xml" target="pack-maven.done" inheritall="yes" inheritrefs="yes"/></target> - <target name="distpack-opt" description="Builds an optimised distribution."> <optimize name="distpack"/></target> - <target name="distpack-maven-opt" description="Builds an optimised maven distribution."><optimize name="distpack-maven"/></target> + <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="all.done" depends="dist.done, test.done"/> @@ -57,8 +57,8 @@ targets exercised: <target name="nightly.checkall"> <antcall target="nightly-nopt"> <param name="partest.scalac_opts" value="-Ycheck:all"/></antcall></target> - <target name="clean" depends="locker.clean" description="Removes binaries of compiler and library. Distributions are untouched."/> - <target name="docsclean" depends="docs.clean" description="Removes generated documentation. Distributions are untouched."/> + <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."/> <target name="distclean" depends="dist.clean" description="Removes all distributions. Binaries and documentation are untouched."/> <macrodef name="optimized" > @@ -74,18 +74,18 @@ targets exercised: <property environment="env"/> <!-- Prevents system classpath from being used --> - <property name="build.sysclasspath" value="ignore"/> + <property name="build.sysclasspath" value="ignore"/> <!-- Defines the repository layout --> - <property name="docs.dir" value="${basedir}/docs"/> - <property name="lib.dir" value="${basedir}/lib"/> - <property name="src.dir" value="${basedir}/src"/> - <property name="partest.dir" value="${basedir}/test"/> + <property name="docs.dir" value="${basedir}/docs"/> + <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"/> + <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"/> + <property name="lib-extra.dir" value="${lib.dir}/extra"/> <!-- Loads custom properties definitions --> <property file="${basedir}/build.properties"/> @@ -93,44 +93,45 @@ targets exercised: <property file="${basedir}/build.number"/> <!-- Sets location of pre-compiled libraries --> - <property name="library.starr.jar" value="${lib.dir}/scala-library.jar"/> - <property name="reflect.starr.jar" value="${lib.dir}/scala-reflect.jar"/> - <property name="compiler.starr.jar" value="${lib.dir}/scala-compiler.jar"/> - <property name="jline.jar" value="${lib.dir}/jline.jar"/> - <property name="ant.jar" value="${ant.home}/lib/ant.jar"/> - <property name="scalacheck.jar" value="${lib.dir}/scalacheck.jar"/> + <property name="library.starr.jar" value="${lib.dir}/scala-library.jar"/> + <property name="reflect.starr.jar" value="${lib.dir}/scala-reflect.jar"/> + <property name="compiler.starr.jar" value="${lib.dir}/scala-compiler.jar"/> + <property name="jline.jar" value="${lib.dir}/jline.jar"/> + <property name="ant.jar" value="${ant.home}/lib/ant.jar"/> + <property name="scalacheck.jar" value="${lib.dir}/scalacheck.jar"/> <!-- Sets location of build folders --> - <property name="build.dir" value="${basedir}/build"/> - <property name="build-asm.dir" value="${build.dir}/asm"/> - <property name="build-locker.dir" value="${build.dir}/locker"/> - <property name="build-palo.dir" value="${build.dir}/palo"/> - <property name="build-quick.dir" value="${build.dir}/quick"/> - <property name="build-pack.dir" value="${build.dir}/pack"/> - <property name="build-osgi.dir" value="${build.dir}/osgi"/> - <property name="build-strap.dir" value="${build.dir}/strap"/> - <property name="build-docs.dir" value="${build.dir}/scaladoc"/> - <property name="build-libs.dir" value="${build.dir}/libs"/> - <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="dists.dir" value="${basedir}/dists"/> - - <property name="copyright.string" value="Copyright 2002-2013, LAMP/EPFL"/> - <property name="partest.version.number" value="0.9.2"/> + <property name="build.dir" value="${basedir}/build"/> + <property name="build-libs.dir" value="${build.dir}/libs"/> + <property name="build-asm.dir" value="${build.dir}/asm"/> + <property name="build-forkjoin.dir" value="${build-libs.dir}"/> + <property name="build-locker.dir" value="${build.dir}/locker"/> + <property name="build-palo.dir" value="${build.dir}/palo"/> + <property name="build-quick.dir" value="${build.dir}/quick"/> + <property name="build-pack.dir" value="${build.dir}/pack"/> + <property name="build-osgi.dir" value="${build.dir}/osgi"/> + <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="dists.dir" value="${basedir}/dists"/> + + <property name="copyright.string" value="Copyright 2002-2013, LAMP/EPFL"/> + <property name="partest.version.number" value="0.9.2"/> <!-- 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=""/> + <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:MaxPermSize=192M -XX:+UseParallelGC" /> + <property name="env.ANT_OPTS" value="-Xms1536M -Xmx1536M -Xss1M -XX:MaxPermSize=192M -XX:+UseParallelGC" /> - <property name="scalacfork.jvmargs" value="${env.ANT_OPTS} ${jvm.opts}"/> + <property name="scalacfork.jvmargs" value="${env.ANT_OPTS} ${jvm.opts}"/> <!-- =========================================================================== INITIALIZATION @@ -167,11 +168,15 @@ targets exercised: <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" artifactId="bnd" version="1.50.0"/> </artifact:dependencies> @@ -190,16 +195,15 @@ targets exercised: <dependency groupId="org.apache.felix" artifactId="org.apache.felix.framework" version="3.2.2"/> </artifact:dependencies> + <artifact:dependencies pathId="partest.extras.classpath" filesetId="partest.extras.fileset" versionsId="partest.extras.versions"> + <dependency groupId="com.googlecode.java-diff-utils" artifactId="diffutils" version="1.3.0"/> + </artifact:dependencies> + <!-- BND support --> <typedef resource="aQute/bnd/ant/taskdef.properties" classpathref="extra.tasks.classpath" /> - <!-- Resolve maven dependencies --> - <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="dependency.classpath" filesetId="dependency.fileset"> - <!--<dependency groupId="com.typesafe" artifactId="config" version="0.4.0"/>--> - </artifact:dependencies> - + <!-- Download STARR via maven if `starr.version` is specified. + Want to slow down STARR changes, using only released versions. --> <if><isset property="starr.version"/><then> <artifact:dependencies pathId="starr.core.path"> <dependency groupId="org.scala-lang" artifactId="scala-library" version="${starr.version}"/> @@ -208,7 +212,7 @@ targets exercised: </artifact:dependencies> </then></if> - <property name="maven-deps-done" value="yep!"/> + <property name="maven-deps-done" value="yep!"/> </then></if> @@ -226,30 +230,30 @@ targets exercised: - `version.suffix == maven.version.suffix == ""` --> <if><not><equals arg1="${version.bnum}" arg2="0"/></not><then> - <property name="version.suffix" value="-${version.bnum}"/> + <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}"/> + <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> + <property name="maven.version.suffix" value="${version.suffix}"/> + <property name="osgi.version.suffix" value="${version.suffix}"/></else></if> <!-- not building a release and no version.suffix specified --> - <property name="maven.version.suffix" value="-SNAPSHOT"/> + <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> + <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> + <property name="osgi.version.suffix" value="${maven.version.suffix}"/> + <property name="version.suffix" value="${maven.version.suffix}"/></else></if> <exec osfamily="unix" executable="tools/get-scala-commit-sha" outputproperty="git.commit.sha" failifexecutionfails="false" /> @@ -266,8 +270,8 @@ targets exercised: </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"/> + <property name="git.commit.sha" value="unknown"/> + <property name="git.commit.date" value="unknown"/> <!-- We use the git describe to determine the OSGi modifier for our build. --> <property name="maven.version.number" @@ -276,9 +280,9 @@ targets exercised: 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}"/> + <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}"/> + <property name="version.number" value="${version.major}.${version.minor}.${version.patch}${version.suffix}-${git.commit.date}-${git.commit.sha}"/> </else></if> <condition property="has.java6"> @@ -304,27 +308,27 @@ targets exercised: </then></if> <!-- Allow this to be overridden simply --> - <property name="sbt.latest.version" value="0.12.2"/> + <property name="sbt.latest.version" value="0.12.2"/> - <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.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://typesafe.artifactoryonline.com/typesafe/ivy-releases/org.scala-sbt/interface/${sbt.latest.version}/jars/interface.jar"/> + <property name="sbt.interface.jar" value="${sbt.lib.dir}/interface.jar"/> + <property name="sbt.interface.url" value="http://typesafe.artifactoryonline.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://typesafe.artifactoryonline.com/typesafe/ivy-releases/org.scala-sbt/compiler-interface/${sbt.latest.version}/jars/compiler-interface-src.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" value=""/> + <property name="javac.args" value=""/> - <property name="scalac.args.always" value="" /> - <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="scalac.args.always" value="" /> + <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}"/> <!-- This is the start time for the distribution --> <tstamp prefix="time"> @@ -333,8 +337,8 @@ targets exercised: </tstamp> <!-- some default in case something went wrong getting the revision --> - <property name="version.number" value="-unknown-"/> - <property name="init.avail" value="yes"/> + <property name="version.number" value="-unknown-"/> + <property name="init.avail" value="yes"/> <!-- Local libs (developer use.) --> <mkdir dir="${lib-extra.dir}"/> @@ -347,7 +351,6 @@ targets exercised: <fileset dir="${lib-extra.dir}"> <include name="**/*.jar"/> </fileset> - <path refid="dependency.classpath"/> </path> <!-- And print-out what we are building --> @@ -387,7 +390,9 @@ targets exercised: <fail unless="version.suffixes.consistent" message="Version suffixes inconsistent!"/> <path id="forkjoin.classpath" path="${build-libs.dir}/classes/forkjoin"/> - <path id="asm.classpath" path="${build-asm.dir}/classes/"/> + <path id="asm.classpath" path="${build-asm.dir}/classes"/> + <property name="forkjoin-classes" refid="forkjoin.classpath"/> + <property name="asm-classes" refid="asm.classpath"/> <!-- Compilers to use for the various stages. @@ -500,7 +505,8 @@ targets exercised: <path id="quick.partest.build.path"> <path refid="quick.scalap.build.path"/> - <pathelement location="${build-quick.dir}/classes/repl"/> + <path refid="partest.extras.classpath"/> + <pathelement location="${build-quick.dir}/classes/repl"/> <pathelement location="${scalacheck.jar}"/> </path> @@ -523,6 +529,7 @@ targets exercised: </path> <!-- PACK --> + <!-- also used for docs.* targets TODO: use separate paths for those --> <path id="pack.compiler.path"> <pathelement location="${build-pack.dir}/lib/scala-library.jar"/> <pathelement location="${build-pack.dir}/lib/scala-reflect.jar"/> @@ -531,6 +538,7 @@ targets exercised: <pathelement location="${build-pack.dir}/lib/scalap.jar"/> <pathelement location="${build-pack.dir}/lib/scala-actors.jar"/> <pathelement location="${ant.jar}"/> + <path refid="partest.extras.classpath"/> <path refid="aux.libs"/> </path> @@ -543,6 +551,47 @@ targets exercised: <path refid="aux.libs"/> </path> + <path id="pack.library.files"> + <fileset dir="${build-quick.dir}/classes/library"> + <!-- <exclude name="scala/swing/**"/> --> + <exclude name="scala/actors/**"/> + </fileset> + <fileset dir="${build-quick.dir}/classes/continuations-library"/> + <fileset dir="${forkjoin-classes}"/> + </path> + + <path id="pack.actors.files"> + <fileset dir="${build-quick.dir}/classes/library"> + <include name="scala/actors/**"/> + </fileset> + </path> + + <path id="pack.compiler.files"> + <fileset dir="${build-quick.dir}/classes/compiler"/> + <fileset dir="${build-quick.dir}/classes/repl"/> + <fileset dir="${build-quick.dir}/classes/scaladoc"/> + <fileset dir="${build-quick.dir}/classes/interactive"/> + <fileset dir="${asm-classes}"/> + </path> + + <path id="pack.swing.files"> <fileset dir="${build-quick.dir}/classes/swing"/> </path> + <path id="pack.reflect.files"> <fileset dir="${build-quick.dir}/classes/reflect"/> </path> + <path id="pack.plugins.files"> <fileset dir="${build-quick.dir}/classes/continuations-plugin"/> </path> + <path id="pack.scalacheck.files"> <fileset dir="${build-quick.dir}/classes/scalacheck"/> </path> + <path id="pack.scalap.files"> <fileset dir="${build-quick.dir}/classes/scalap"/> + <fileset file="${src.dir}/scalap/decoder.properties"/> </path> + + <path id="pack.partest.files"> + <fileset dir="${build-quick.dir}/classes/partest"> + <exclude name="scala/tools/partest/javaagent/**"/> + </fileset> + </path> + + <path id="pack.partest-javaagent.files"> + <fileset dir="${build-quick.dir}/classes/partest"> + <include name="scala/tools/partest/javaagent/**"/> + </fileset> + </path> <!-- STRAP --> <path id="strap.library.build.path"> @@ -579,6 +628,11 @@ targets exercised: <path id="partest.classpath"> <path refid="pack.compiler.path"/> + <path refid="partest.extras.classpath"/> + </path> + + <path id="partest.build.path"> + <path refid="pack.compiler.path"/> <fileset dir="${partest.dir}/files/lib" includes="*.jar" /> <pathelement location="${pack.dir}/lib/scala-swing.jar"/> <!-- TODO - segregate swing tests (there can't be many) --> </path> @@ -660,53 +714,39 @@ targets exercised: <delete dir="${build-@{build}.dir}" includeemptydirs="yes" quiet="yes" failonerror="no"/> </sequential> </macrodef> - <!-- =========================================================================== - LOCAL DEPENDENCY (Adapted ASM) + LOCAL DEPENDENCIES ============================================================================ --> - <target name="asm.done" depends="init"> - <available file="${build-asm.dir}/asm.complete" property="asm.available"/> - <if><not><isset property="asm.available"/></not><then> - <stopwatch name="asm.lib.timer"/> - <mkdir dir="${build-asm.dir}/classes/"/> - <javac - srcdir="${src.dir}/asm" - destdir="${build-asm.dir}/classes" - classpath="${build-asm.dir}/classes" - includes="**/*.java" - target="1.6" source="1.5"> - <compilerarg line="${javac.args} -XDignore.symbol.file"/> - </javac> - <stopwatch name="asm.lib.timer" action="total"/> - <touch file="${build-asm.dir}/asm.complete" verbose="no"/> - </then></if> - </target> - -<!-- =========================================================================== - LOCAL DEPENDENCY (FORKJOIN) -============================================================================ --> - <target name="forkjoin.done" depends="init"> - <uptodate property="forkjoin.available" targetfile="${build-libs.dir}/forkjoin.complete"> - <srcfiles dir="${src.dir}/forkjoin"/></uptodate> - <if><not><isset property="forkjoin.available"/></not><then> - <stopwatch name="forkjoin.lib.timer"/> - <mkdir dir="${build-libs.dir}/classes/forkjoin"/> - <javac - fork="yes" - compiler="javac1.6" - srcdir="${src.dir}/forkjoin" - destdir="${build-libs.dir}/classes/forkjoin" - classpath="${build-libs.dir}/classes/forkjoin" - includes="**/*.java" - debug="true" - target="1.6" source="1.5"> - <compilerarg line="${javac.args} -XDignore.symbol.file"/> - </javac> - <jar whenmanifestonly="fail" destfile="${build-libs.dir}/forkjoin.jar" basedir="${build-libs.dir}/classes/forkjoin"/> - <stopwatch name="forkjoin.lib.timer" action="total"/> - <touch file="${build-libs.dir}/forkjoin.complete" verbose="no"/> - </then></if> - </target> + <macrodef name="simple-javac" > + <attribute name="project"/> <!-- project: asm/forkjoin --> + <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 + srcdir="${src.dir}/@{project}" + destdir="${@{project}-classes}" + classpath="${@{project}-classes}" + includes="**/*.java" + target="1.6" source="1.5" + compiler="javac1.6"> + <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> + + <target name="asm.done" depends="init"> <simple-javac project="asm" jar="no"/> </target> + <target name="forkjoin.done" depends="init"> <simple-javac project="forkjoin" args="-XDignore.symbol.file"/></target> <!-- =========================================================================== STAGED COMPILATION MACROS @@ -871,15 +911,33 @@ targets exercised: <attribute name="project"/> <attribute name="targetdir" default="lib"/> <attribute name="targetjar" default="scala-@{project}.jar"/> - <element name="do" implicit="true"/> + <attribute name="destfile" default="${build-pack.dir}/@{targetdir}/@{targetjar}"/> + <attribute name="manifest" default=""/> + <element name="pre" optional="true"/> + <element name="jar-opts" optional="true"/> <sequential> - <uptodate property="pack.@{project}.available" - targetfile="${build-pack.dir}/@{targetdir}/@{targetjar}" - srcfile="${build-quick.dir}/@{project}.complete"/> + <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}/@{targetdir}"/> - <do/> + <pre/> + + <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"/> + </jar></then> + <else> + <jar whenmanifestonly="fail" destfile="@{destfile}"> + <jar-opts/> + <path refid="pack.@{project}.files"/> + </jar> + </else></if> </then></if> </sequential> </macrodef> @@ -897,7 +955,8 @@ targets exercised: <do> <stopwatch name="docs.@{project}.timer"/> <mkdir dir="${build-docs.dir}/@{project}"/> - <if><equals arg1="@{classpathref}" arg2="NOT SET"/><then> + <if><equals arg1="@{docroot}" arg2="NOT SET"/><then> + <!-- TODO: introduce docs.@{project}.build.path for classpathref --> <scaladoc destdir="${build-docs.dir}/@{project}" doctitle="@{title}" @@ -1057,113 +1116,64 @@ targets exercised: <!-- =========================================================================== PACKED QUICK BUILD (PACK) ============================================================================ --> - <target name="pack.lib" depends="quick.lib, quick.plugins, forkjoin.done"> - <staged-pack project="library"> - <!-- First copy maven dependencies --> - <copy todir="${build-pack.dir}/lib"> - <fileset refid="dependency.fileset" /> - <mapper type="flatten" /> - </copy> - <jar whenmanifestonly="fail" destfile="${build-pack.dir}/lib/scala-library.jar"> - <fileset dir="${build-quick.dir}/classes/library"> - <exclude name="scala/swing/**"/> - <exclude name="scala/actors/**"/> - </fileset> - <fileset dir="${build-quick.dir}/classes/continuations-library"/> - <fileset dir="${build-libs.dir}/classes/forkjoin"/> - </jar> - <jar whenmanifestonly="fail" destfile="${build-pack.dir}/lib/scala-actors.jar"> - <fileset dir="${build-quick.dir}/classes/library"> - <include name="scala/actors/**"/> - </fileset> - </jar> - </staged-pack> - </target> - - <target name="pack.swing" depends="quick.swing" if="has.java6"> - <staged-pack project="swing’"> - <jar whenmanifestonly="fail" destfile="${build-pack.dir}/lib/scala-swing.jar" basedir="${build-quick.dir}/classes/swing"/> - </staged-pack> - </target> - - <target name="pack.reflect" depends="quick.reflect"> - <staged-pack project="reflect’"> - <jar whenmanifestonly="fail" destfile="${build-pack.dir}/lib/scala-reflect.jar" basedir="${build-quick.dir}/classes/reflect"/> - </staged-pack> - </target> - - <target name="pack.comp" depends="quick.comp, quick.scaladoc, quick.interactive, quick.repl, asm.done"> - <staged-pack project="compiler"> - <mkdir dir="${build-pack.dir}/META-INF"/> - <copy file="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> - <jar whenmanifestonly="fail" destfile="${build-pack.dir}/lib/scala-compiler.jar" manifest="${build-pack.dir}/META-INF/MANIFEST.MF"> - <service type="javax.script.ScriptEngineFactory" provider="scala.tools.nsc.interpreter.IMain$Factory"/> - <fileset dir="${build-quick.dir}/classes/compiler"/> + <target name="pack.lib" depends="quick.lib, quick.plugins, forkjoin.done"> + <staged-pack project="library"/></target> + + <target name="pack.actors" depends="quick.lib"> <staged-pack project="actors"/> </target> + <target name="pack.swing" if="has.java6" depends="quick.swing"> <staged-pack project="swing"/> </target> + <target name="pack.reflect" depends="quick.reflect"> <staged-pack project="reflect"/> </target> + + <target name="pack.comp" depends="quick.comp, quick.scaladoc, quick.interactive, quick.repl, asm.done"> + <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 file="${jline.jar}" toDir="${build-pack.dir}/lib"/> + <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> + <jar-opts> <fileset dir="${build-quick.dir}/classes/scaladoc"/> <fileset dir="${build-quick.dir}/classes/interactive"/> <fileset dir="${build-quick.dir}/classes/repl"/> - <fileset dir="${build-asm.dir}/classes"/> - </jar> - <copy file="${jline.jar}" toDir="${build-pack.dir}/lib"/> - <copy todir="${build-pack.dir}/lib"> - <fileset dir="${lib-extra.dir}"> - <include name="**/*.jar"/> - </fileset> - </copy> - </staged-pack> - </target> - - <target name="pack.plugins" depends="quick.plugins"> - <staged-pack project="plugins" targetdir="misc/scala-devel/plugins" targetjar="continuations.jar"> - <jar whenmanifestonly="fail" destfile="${build-pack.dir}/misc/scala-devel/plugins/continuations.jar" basedir="${build-quick.dir}/classes/continuations-plugin"/> + <service type="javax.script.ScriptEngineFactory" provider="scala.tools.nsc.interpreter.IMain$Factory"/> + </jar-opts> </staged-pack> </target> - <target name="pack.scalacheck" depends="quick.scalacheck"> - <uptodate property="pack.scalacheck.available" - targetfile="${build-pack.dir}/lib/scalacheck.jar"> - <srcfiles dir="${build-quick.dir}/classes/scalacheck"/></uptodate> - <if><not><isset property="pack.scalacheck.available"/></not><then> - <jar whenmanifestonly="fail" destfile="${build-pack.dir}/lib/scalacheck.jar" basedir="${build-quick.dir}/classes/scalacheck"/> - </then></if> - </target> + <target name="pack.plugins" depends="quick.plugins"> <staged-pack project="plugins" targetdir="misc/scala-devel/plugins" targetjar="continuations.jar"/> </target> + <target name="pack.scalacheck" depends="quick.scalacheck"> <staged-pack project="scalacheck" targetjar="scalacheck.jar"/> </target> <target name="pack.partest" depends="quick.partest"> - <staged-pack project="partest"> - <jar whenmanifestonly="fail" destfile="${build-pack.dir}/lib/scala-partest.jar"> - <fileset dir="${build-quick.dir}/classes/partest"> - <exclude name="scala/tools/partest/javaagent/**"/> - </fileset> - </jar> - <jar whenmanifestonly="fail" destfile = "${build-pack.dir}/lib/scala-partest-javaagent.jar" - manifest = "${src.dir}/partest/scala/tools/partest/javaagent/MANIFEST.MF"> - <fileset dir = "${build-quick.dir}/classes/partest"> - <include name = "scala/tools/partest/javaagent/**"/> - </fileset> - </jar> - </staged-pack> + <staged-pack project="partest"/> + <!-- TODO the manifest should influence actuality of this target --> + <staged-pack project="partest-javaagent" manifest="${src.dir}/partest/scala/tools/partest/javaagent/MANIFEST.MF"/> </target> - <target name="pack.scalap" depends="quick.scalap"> - <staged-pack project="plugins" targetjar="scalap.jar"> - <jar whenmanifestonly="fail" destfile="${build-pack.dir}/lib/scalap.jar"> - <fileset dir="${build-quick.dir}/classes/scalap"/> - <fileset file="${src.dir}/scalap/decoder.properties"/> - </jar> - </staged-pack> - </target> + <target name="pack.scalap" depends="quick.scalap"> <staged-pack project="scalap" targetjar="scalap.jar"/> </target> - <target name="pack.bin" depends="pack.comp, pack.lib, pack.partest, pack.plugins, pack.reflect, pack.scalacheck, pack.scalap, pack.swing"> + <target name="pack.bin" depends="pack.comp, pack.lib, pack.actors, pack.partest, pack.plugins, pack.reflect, pack.scalacheck, pack.scalap, pack.swing"> <staged-bin stage="pack"/> </target> - <target name="pack.done" depends="pack.bin"> + <!-- depend on quick.done so quick.bin is run when pack.done is --> + <target name="pack.done" depends="quick.done, pack.bin"> + <!-- copy dependencies to build/pack/lib, it only takes a second so don't bother with uptodate checks --> + <copy todir="${build-pack.dir}/lib"> + <resources refid="partest.extras.fileset"/> + <mapper classpathref="maven-ant-tasks.classpath" classname="org.apache.maven.artifact.ant.VersionMapper" + from="${partest.extras.versions}" to="flatten"/> + </copy> + <taskdef resource="scala/tools/ant/antlib.xml" classpathref="pack.compiler.path"/> - <taskdef resource="scala/tools/partest/antlib.xml" classpathref="pack.compiler.path"/> + <taskdef resource="scala/tools/partest/antlib.xml" classpathref="partest.classpath"/> </target> @@ -1195,13 +1205,13 @@ targets exercised: <mkdir dir="${build-palo.dir}/lib"/> <jar whenmanifestonly="fail" destfile="${build-palo.dir}/lib/scala-library.jar"> <fileset dir="${build-locker.dir}/classes/library"/> - <fileset dir="${build-libs.dir}/classes/forkjoin"/> + <fileset dir="${forkjoin-classes}"/> </jar> <jar whenmanifestonly="fail" destfile="${build-palo.dir}/lib/scala-reflect.jar" manifest="${basedir}/META-INF/MANIFEST.MF" basedir="${build-locker.dir}/classes/reflect"/> <jar whenmanifestonly="fail" destfile="${build-palo.dir}/lib/scala-compiler.jar" manifest="${basedir}/META-INF/MANIFEST.MF"> <fileset dir="${build-locker.dir}/classes/compiler"/> - <fileset dir="${build-asm.dir}/classes/"/> + <fileset dir="${asm-classes}"/> </jar> <copy file="${jline.jar}" toDir="${build-palo.dir}/lib"/> </target> @@ -1369,7 +1379,7 @@ targets exercised: srcdir="${partest.srcdir}" scalacopts="${scalac.args.optimise}"> - <compilationpath refid="partest.classpath"/> + <compilationpath refid="partest.build.path"/> <runtests dir="${partest.dir}/${partest.srcdir}/run" includes="*.scala"/> <jvmtests dir="${partest.dir}/${partest.srcdir}/jvm" includes="*.scala"/> </partest> @@ -1380,7 +1390,7 @@ targets exercised: timeout="2400000" srcdir="${partest.srcdir}" scalacopts="${scalac.args.optimise}"> - <compilationpath refid="partest.classpath"/> + <compilationpath refid="partest.build.path"/> <postests dir="${partest.dir}/${partest.srcdir}/pos" includes="*.scala"/> <negtests dir="${partest.dir}/${partest.srcdir}/neg" includes="*.scala"/> <runtests dir="${partest.dir}/${partest.srcdir}/run" includes="*.scala"/> @@ -1406,7 +1416,7 @@ targets exercised: scalacopts="${scalac.args.optimise} -Xplugin-require:continuations -P:continuations:enable"> <compilerarg value="-Xpluginsdir"/> <compilerarg file="${build-quick.dir}/misc/scala-devel/plugins"/> - <compilationpath refid="partest.classpath"/> + <compilationpath refid="partest.build.path"/> <negtests dir="${partest.dir}/${partest.srcdir}/continuations-neg" includes="*.scala"/> <runtests dir="${partest.dir}/${partest.srcdir}/continuations-run" includes="*.scala"/> </partest> @@ -1414,7 +1424,7 @@ targets exercised: <target name="test.scaladoc" depends="pack.done"> <partest erroronfailed="yes" scalacopts="${scalac.args.optimise}" showlog="yes"> - <compilationpath refid="partest.classpath"/> + <compilationpath refid="partest.build.path"/> <runtests dir="${partest.dir}/scaladoc/run" includes="*.scala" /> <scalachecktests dir="${partest.dir}/scaladoc/scalacheck" includes="*.scala" /> </partest> @@ -1422,60 +1432,89 @@ targets exercised: <target name="test.interactive" depends="pack.done"> <partest erroronfailed="yes" scalacopts="${scalac.args.optimise}" showlog="yes"> - <compilationpath refid="partest.classpath"/> + <compilationpath refid="partest.build.path"/> <presentationtests dir="${partest.dir}/${partest.srcdir}/presentation"> <include name="*/*.scala"/> </presentationtests> </partest> </target> -<!-- currently disabled: test.ant, test.bc, test.positions, test.classload --> - <target name="test.done" depends="test.osgi, test.sbt, test.interactive, test.continuations.suite, test.suite, test.scaladoc, test.stability"/> + <!-- 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.interactive, test.continuations.suite, test.scaladoc, test.suite"/> + <target name="test.done" depends="test.core, test.stability"/> <!-- =========================================================================== BINARY COMPATIBILITY TESTING ============================================================================ --> <target name="bc.init" depends="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.9.2" version="0.1.4"/> + <dependency groupId="com.typesafe" artifactId="mima-reporter_2.9.2" version="0.1.5"/> </artifact:dependencies> <artifact:dependencies pathId="old.bc.classpath"> - <dependency groupId="org.scala-lang" artifactId="scala-library" version="2.10.0-RC2"/> - <dependency groupId="org.scala-lang" artifactId="scala-reflect" version="2.10.0-RC2"/> + <dependency groupId="org.scala-lang" artifactId="scala-swing" version="${bc-reference-version}"/> + <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" depends="bc.init, pack.lib"> - <java - fork="true" - failonerror="true" - classname="com.typesafe.tools.mima.cli.Main"> - <arg value="--prev"/> - <arg value="${org.scala-lang:scala-library:jar}"/> - <arg value="--curr"/> - <arg value="${build-pack.dir}/lib/scala-library.jar"/> - <classpath> - <path refid="mima.classpath"/> - </classpath> - </java> - <java - fork="true" - failonerror="true" - classname="com.typesafe.tools.mima.cli.Main"> - <arg value="--prev"/> - <arg value="${org.scala-lang:scala-reflect:jar}"/> - <arg value="--curr"/> - <arg value="${build-pack.dir}/lib/scala-reflect.jar"/> - <classpath> - <path refid="mima.classpath"/> - </classpath> - </java> + <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="jar-name"/> + <sequential> + <bc.run-mima + jar-name="@{jar-name}" + prev="${org.scala-lang:@{jar-name}:jar}" + curr="${build-pack.dir}/lib/@{jar-name}.jar" + direction="backward"/> + <bc.run-mima + jar-name="@{jar-name}" + prev="${build-pack.dir}/lib/@{jar-name}.jar" + curr="${org.scala-lang:@{jar-name}:jar}" + direction="forward"/> + </sequential> + </macrodef> + + <target name="test.bc-opt" description="Optimized version of test.bc."> <optimized name="test.bc"/></target> + + <!-- Enable after the release of the 2.11.0 or a prior RC that estabilishes the new baseline. --> + <target name="test.bc"></target> + <target name="test.bc.disabled" depends="bc.init, pack.lib, pack.reflect, pack.swing"> + <bc.check jar-name="scala-library"/> + <bc.check jar-name="scala-reflect"/> + <bc.check jar-name="scala-swing"/> </target> <!-- =========================================================================== @@ -1509,6 +1548,7 @@ targets exercised: <include name="swing/**"/> <include name="actors/**"/> <include name="reflect/**"/> + <include name="continuations/library/**"/> </srcfiles></check> <do> <stopwatch name="docs.lib.timer"/> @@ -1656,6 +1696,13 @@ targets exercised: <include name="scalap.jar"/> </fileset> </copy> + + <copy todir="${dist.dir}/lib"> + <resources refid="partest.extras.fileset"/> + <mapper classpathref="maven-ant-tasks.classpath" classname="org.apache.maven.artifact.ant.VersionMapper" + from="${partest.extras.versions}" to="flatten"/> + </copy> + <mkdir dir="${dist.dir}/bin"/> <!-- TODO - Stop being inefficient and don't copy OSGi bundles overtop other jars. --> <copy-bundle name="scala-library"/> @@ -1804,7 +1851,7 @@ targets exercised: </target> <target name="replacestarr-opt" description="Replaces the Starr compiler and library by fresh, optimised ones built from current sources and tests them."> - <optimize name="replacestarr"/></target> + <optimized name="replacestarr"/></target> <!-- Ant on Windows is not able to delete jar files that are referenced in any <path>. See ticket 1290 on trac. --> @@ -1821,13 +1868,13 @@ targets exercised: </target> <target name="replacestarrwin-opt" description="Creates a new Starr on Windows. Manually execute 'ant locker.clean build' first!"> - <optimize name="replacestarrwin"/></target> + <optimized name="replacestarrwin"/></target> <target name="replacelocker" description="Replaces the Locker compiler and library by fresh ones built from current sources." depends="palo.clean, locker.unlock, palo.done"/> <target name="replacelocker-opt" description="Replaces the Locker compiler and library by fresh, optimised ones built from current sources."> - <optimize name="replacelocker"/></target> + <optimized name="replacelocker"/></target> <target name="buildlocker" description="Does the same for locker as build does for quick." depends="locker.unlock, palo.bin"/> <target name="unlocklocker" description="Same as buildlocker." depends="buildlocker"/> <!-- REMOVE --> @@ -1846,105 +1893,6 @@ targets exercised: <target name="fastlocker" description="Buildlocker without extra fuss" depends="fastlocker.comp"/> - -<!-- =========================================================================== - TODO: FIX OR REMOVE -============================================================================ --> - - <!-- not called by test target --> - <target name="test.classload" depends="pack.done"> - <!-- TODO - Add actors + reflect to this --> - <classloadVerify classpath="${build-pack.dir}/lib/scala-library.jar" /> - </target> - - <!-- not called by test target --> - <target name="test.ant" depends="pack.done"> - <partest showlog="yes" erroronfailed="yes" javacmd="${java.home}/bin/java" - srcdir="${partest.srcdir}" - scalacopts="${scalac.args.optimise}"> - <compilationpath refid="partest.classpath"/> - <anttests dir="${partest.dir}/${partest.srcdir}/ant" includes="*build.xml"/> - </partest> - </target> - - <!-- not called by test target --> - <target name="test.positions" depends="quick.comp"> - <antcall target="test.positions.tests.sub" inheritRefs="true"> - <param name="test.tests.srcs" value="${partest.dir}/files/positions"/> - </antcall> - <antcall target="test.positions.sub" inheritRefs="true"> - <param name="test.srcs" value="${src.dir}/compiler"/> - </antcall> - <antcall target="test.positions.sub" inheritRefs="true"> - <param name="test.srcs" value="${src.dir}/library"/> - </antcall> - <antcall target="test.positions.sub" inheritRefs="true"> - <param name="test.srcs" value="${src.dir}/actors"/> - </antcall> - <antcall target="test.positions.sub" inheritRefs="true"> - <param name="test.srcs" value="${src.dir}/dbc"/> - </antcall> - <antcall target="test.positions.sub" inheritRefs="true"> - <param name="test.srcs" value="${src.dir}/swing"/> - </antcall> - <antcall target="test.positions.sub" inheritRefs="true"> - <param name="test.srcs" value="${src.dir}/partest"/> - </antcall> - <antcall target="test.positions.sub" inheritRefs="true"> - <param name="test.srcs" value="${src.dir}/scalap"/> - </antcall> - <antcall target="test.positions.tests.sub" inheritRefs="true"> - <param name="test.tests.srcs" value="${partest.dir}/files/pos"/> - </antcall> - <antcall target="test.positions.tests.sub" inheritRefs="true"> - <param name="test.tests.srcs" value="${partest.dir}/files/run"/> - </antcall> - <antcall target="test.positions.tests.sub" inheritRefs="true"> - <param name="test.tests.srcs" value="${partest.dir}/files/neg"/> - </antcall> - </target> - - <target name="test.positions.sub"> - <echo message="Validating positions for: ${test.srcs}"/> - <if> - <isfileselected file="${test.srcs}"> - <type type="dir"/> - </isfileselected> - <then> - <property name="srcdir" value="${test.srcs}"/> - <property name="srcs" value="**/*.scala"/> - </then> - <else> - <dirname property="srcdir" file="${test.srcs}"/> - <basename property="srcs" file="${test.srcs}"/> - </else> - </if> - <scalacfork - destdir="" - compilerpathref="locker.compiler.path" - srcpath="${srcdir}" - params="-Xprint-pos -Yide-debug" - srcdir="${srcdir}" - jvmargs="${scalacfork.jvmargs}"> - <include name="${srcs}"/> - <compilationpath refid="test.positions.sub.build.path"/> - </scalacfork> - </target> - - <target name="test.positions.tests.sub"> - <foreach target="test.positions.sub" - inheritAll="true" - inheritRefs="true" - param="test.srcs"> - <path> - <fileset dir="${test.tests.srcs}" includes="*.scala"/> - <dirset dir="${test.tests.srcs}"> - <include name="*"/> - </dirset> - </path> - </foreach> - </target> - <!-- =========================================================================== VISUALIZATION ============================================================================ --> diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala index d57188bf6e..7338df1f72 100644 --- a/src/compiler/scala/reflect/reify/utils/Extractors.scala +++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala @@ -164,51 +164,30 @@ trait Extractors { } } - object FreeDef { - def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match { - case FreeTermDef(uref, name, binding, flags, origin) => - Some((uref, name, binding, flags, origin)) - case FreeTypeDef(uref, name, binding, flags, origin) => - Some((uref, name, binding, flags, origin)) - case _ => - None - } - } - - object FreeTermDef { - def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match { - case - ValDef(_, name, _, Apply( - Select(Select(uref1 @ Ident(_), build1), newFreeTerm), - List( - _, - _, - Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))), - Literal(Constant(origin: String))))) - if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newFreeTerm == nme.newFreeTerm && - uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits => - Some((uref1, name, reifyBinding(tree), flags, origin)) - case _ => - None - } - } - - object FreeTypeDef { - def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match { - case - ValDef(_, name, _, Apply( - Select(Select(uref1 @ Ident(_), build1), newFreeType), - List( - _, - Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))), - Literal(Constant(origin: String))))) - if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newFreeType == nme.newFreeType && - uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits => - Some((uref1, name, reifyBinding(tree), flags, origin)) - case _ => - None + sealed abstract class FreeDefExtractor(acceptTerms: Boolean, acceptTypes: Boolean) { + def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = { + def acceptFreeTermFactory(name: Name) = { + (acceptTerms && name == nme.newFreeTerm) || + (acceptTypes && name == nme.newFreeType) + } + tree match { + case + ValDef(_, name, _, Apply( + Select(Select(uref1 @ Ident(_), build1), freeTermFactory), + _ :+ + Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))) :+ + Literal(Constant(origin: String)))) + if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && acceptFreeTermFactory(freeTermFactory) && + uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits => + Some((uref1, name, reifyBinding(tree), flags, origin)) + case _ => + None + } } } + object FreeDef extends FreeDefExtractor(acceptTerms = true, acceptTypes = true) + object FreeTermDef extends FreeDefExtractor(acceptTerms = true, acceptTypes = false) + object FreeTypeDef extends FreeDefExtractor(acceptTerms = false, acceptTypes = true) object FreeRef { def unapply(tree: Tree): Option[(Tree, TermName)] = tree match { diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index e471f4256b..0a18adcf4f 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -172,6 +172,7 @@ trait Members { var returnType: TypeKind = _ var recursive: Boolean = false var bytecodeHasEHs = false // set by ICodeReader only, used by Inliner to prevent inlining (SI-6188) + var bytecodeHasInvokeDynamic = false // set by ICodeReader only, used by Inliner to prevent inlining until we have proper invoke dynamic support /** local variables and method parameters */ var locals: List[Local] = Nil diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index d8aac8e9db..ff118be3c4 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -394,6 +394,25 @@ trait Opcodes { self: ICodes => override def category = mthdsCat } + + /** + * A place holder entry that allows us to parse class files with invoke dynamic + * instructions. Because the compiler doesn't yet really understand the + * behavior of invokeDynamic, this op acts as a poison pill. Any attempt to analyze + * this instruction will cause a failure. The only optimization that + * should ever look at non-Scala generated icode is the inliner, and it + * has been modified to not examine any method with invokeDynamic + * instructions. So if this poison pill ever causes problems then + * there's been a serious misunderstanding + */ + // TODO do the real thing + case class INVOKE_DYNAMIC(poolEntry: Char) extends Instruction { + private def error = sys.error("INVOKE_DYNAMIC is not fully implemented and should not be analyzed") + override def consumed = error + override def produced = error + override def producedTypes = error + override def category = error + } case class BOX(boxType: TypeKind) extends Instruction { assert(boxType.isValueType && (boxType ne UNIT)) // documentation diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 78fb109b42..0c098edf98 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -2251,16 +2251,16 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { // info calls so that types are up to date; erasure may add lateINTERFACE to traits hostSymbol.info ; methodOwner.info - def isInterfaceCall(sym: Symbol) = ( - sym.isInterface && methodOwner != ObjectClass + def needsInterfaceCall(sym: Symbol) = ( + sym.isInterface || sym.isJavaDefined && sym.isNonBottomSubClass(ClassfileAnnotationClass) ) // whether to reference the type of the receiver or - // the type of the method owner (if not an interface!) + // the type of the method owner val useMethodOwner = ( style != Dynamic - || !isInterfaceCall(hostSymbol) && isAccessibleFrom(methodOwner, siteSymbol) || hostSymbol.isBottomClass + || methodOwner == ObjectClass ) val receiver = if (useMethodOwner) methodOwner else hostSymbol val jowner = javaName(receiver) @@ -2283,11 +2283,11 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { } style match { - case Static(true) => dbg("invokespecial"); jcode.invokespecial (jowner, jname, jtype) - case Static(false) => dbg("invokestatic"); jcode.invokestatic (jowner, jname, jtype) - case Dynamic if isInterfaceCall(receiver) => dbg("invokinterface"); jcode.invokeinterface(jowner, jname, jtype) - case Dynamic => dbg("invokevirtual"); jcode.invokevirtual (jowner, jname, jtype) - case SuperCall(_) => + case Static(true) => dbg("invokespecial"); jcode.invokespecial (jowner, jname, jtype) + case Static(false) => dbg("invokestatic"); jcode.invokestatic (jowner, jname, jtype) + case Dynamic if needsInterfaceCall(receiver) => dbg("invokinterface"); jcode.invokeinterface(jowner, jname, jtype) + case Dynamic => dbg("invokevirtual"); jcode.invokevirtual (jowner, jname, jtype) + case SuperCall(_) => dbg("invokespecial") jcode.invokespecial(jowner, jname, jtype) initModule() diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 555c79e75e..557ef925a7 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -958,6 +958,7 @@ abstract class Inliners extends SubComponent { if(isInlineForbidden) { rs ::= "is annotated @noinline" } if(inc.isSynchronized) { rs ::= "is synchronized method" } if(inc.m.bytecodeHasEHs) { rs ::= "bytecode contains exception handlers / finally clause" } // SI-6188 + if(inc.m.bytecodeHasInvokeDynamic) { rs ::= "bytecode contains invoke dynamic" } if(rs.isEmpty) null else rs.mkString("", ", and ", "") } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index cf40fe90fa..f1b1d1a9a7 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -755,13 +755,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { val pos = in.currentPos val name = identForType() val (statics, body) = typeBody(AT, name) - def getValueMethodType(tree: Tree) = tree match { - case DefDef(_, nme.value, _, _, tpt, _) => Some(tpt.duplicate) - case _ => None - } - var templ = makeTemplate(annotationParents, body) - for (stat <- templ.body; tpt <- getValueMethodType(stat)) - templ = makeTemplate(annotationParents, makeConstructor(List(tpt)) :: templ.body) + val templ = makeTemplate(annotationParents, body) addCompanionObject(statics, atPos(pos) { ClassDef(mods, name, List(), templ) }) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 1206748b24..879320c016 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -136,10 +136,13 @@ abstract class ClassfileParser { (in.nextByte.toInt: @switch) match { case CONSTANT_UTF8 | CONSTANT_UNICODE => in.skip(in.nextChar) - case CONSTANT_CLASS | CONSTANT_STRING => + case CONSTANT_CLASS | CONSTANT_STRING | CONSTANT_METHODTYPE=> in.skip(2) + case CONSTANT_METHODHANDLE => + in.skip(3) case CONSTANT_FIELDREF | CONSTANT_METHODREF | CONSTANT_INTFMETHODREF - | CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT => + | CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT + | CONSTANT_INVOKEDYNAMIC => in.skip(4) case CONSTANT_LONG | CONSTANT_DOUBLE => in.skip(8) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index 599823b408..80a810703c 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -501,6 +501,13 @@ abstract class ICodeReader extends ClassfileParser { code.emit(UNBOX(toTypeKind(m.info.resultType))) else code.emit(CALL_METHOD(m, Static(onInstance = false))) + case JVM.invokedynamic => + // TODO, this is just a place holder. A real implementation must parse the class constant entry + debuglog("Found JVM invokedynamic instructionm, inserting place holder ICode INVOKE_DYNAMIC.") + containsInvokeDynamic = true + val poolEntry = in.nextChar + in.skip(2) + code.emit(INVOKE_DYNAMIC(poolEntry)) case JVM.new_ => code.emit(NEW(REFERENCE(pool.getClassSymbol(in.nextChar)))) @@ -639,6 +646,7 @@ abstract class ICodeReader extends ClassfileParser { var containsDUPX = false var containsNEW = false var containsEHs = false + var containsInvokeDynamic = false def emit(i: Instruction) { instrs += ((pc, i)) @@ -657,6 +665,7 @@ abstract class ICodeReader extends ClassfileParser { val code = new Code(method) method.setCode(code) method.bytecodeHasEHs = containsEHs + method.bytecodeHasInvokeDynamic = containsInvokeDynamic var bb = code.startBlock def makeBasicBlocks: mutable.Map[Int, BasicBlock] = diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 124dd6c995..367825c251 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -41,26 +41,24 @@ abstract class ExplicitOuter extends InfoTransform private def isInner(clazz: Symbol) = !clazz.isPackageClass && !clazz.outerClass.isStaticOwner - private def haveSameOuter(parent: Type, clazz: Symbol) = parent match { - case TypeRef(pre, sym, _) => - val owner = clazz.owner + private def haveSameOuter(parent: Type, clazz: Symbol) = { + val owner = clazz.owner + val parentSym = parent.typeSymbol - //println(s"have same outer $parent $clazz $sym ${sym.owner} $owner $pre") - - sym.isClass && owner.isClass && - (owner isSubClass sym.owner) && - owner.thisType =:= pre - - case _ => false + parentSym.isClass && owner.isClass && + (owner isSubClass parentSym.owner) && + owner.thisType =:= parent.prefix } /** Does given clazz define an outer field? */ def hasOuterField(clazz: Symbol) = { - val parents = clazz.info.parents + val parent = clazz.info.firstParent - isInner(clazz) && !clazz.isTrait && { - parents.isEmpty || !haveSameOuter(parents.head, clazz) - } + // space optimization: inherit the $outer pointer from the parent class if + // we know that it will point to the correct instance. + def canReuseParentOuterField = !parent.typeSymbol.isJavaDefined && haveSameOuter(parent, clazz) + + isInner(clazz) && !clazz.isTrait && !canReuseParentOuterField } private def outerField(clazz: Symbol): Symbol = { @@ -100,6 +98,29 @@ abstract class ExplicitOuter extends InfoTransform sym setInfo clazz.outerClass.thisType } + /** + * Will the outer accessor of the `clazz` subsume the outer accessor of + * `mixin`? + * + * This arises when an inner object mixes in its companion trait. + * + * {{{ + * class C { + * trait T { C.this } // C$T$$$outer$ : C + * object T extends T { C.this } // C$T$$$outer$ : C.this.type + * } + * }}} + * + * See SI-7242. + }} + */ + private def skipMixinOuterAccessor(clazz: Symbol, mixin: Symbol) = { + // Reliant on the current scheme for name expansion, the expanded name + // of the outer accessors in a trait and its companion object are the same. + // If the assumption is one day falsified, run/t7424.scala will let us know. + clazz.fullName == mixin.fullName + } + /** <p> * The type transformation method: * </p> @@ -162,10 +183,14 @@ abstract class ExplicitOuter extends InfoTransform for (mc <- clazz.mixinClasses) { val mixinOuterAcc: Symbol = exitingExplicitOuter(outerAccessor(mc)) if (mixinOuterAcc != NoSymbol) { - if (decls1 eq decls) decls1 = decls.cloneScope - val newAcc = mixinOuterAcc.cloneSymbol(clazz, mixinOuterAcc.flags & ~DEFERRED) - newAcc setInfo (clazz.thisType memberType mixinOuterAcc) - decls1 enter newAcc + if (skipMixinOuterAccessor(clazz, mc)) + debuglog(s"Reusing outer accessor symbol of $clazz for the mixin outer accessor of $mc") + else { + if (decls1 eq decls) decls1 = decls.cloneScope + val newAcc = mixinOuterAcc.cloneSymbol(clazz, mixinOuterAcc.flags & ~DEFERRED) + newAcc setInfo (clazz.thisType memberType mixinOuterAcc) + decls1 enter newAcc + } } } } @@ -370,6 +395,7 @@ abstract class ExplicitOuter extends InfoTransform val outerAcc = outerAccessor(mixinClass) overridingSymbol currentClass def mixinPrefix = (currentClass.thisType baseType mixinClass).prefix assert(outerAcc != NoSymbol, "No outer accessor for inner mixin " + mixinClass + " in " + currentClass) + assert(outerAcc.alternatives.size == 1, s"Multiple outer accessors match inner mixin $mixinClass in $currentClass : ${outerAcc.alternatives.map(_.defString)}") // I added the mixinPrefix.typeArgs.nonEmpty condition to address the // crash in SI-4970. I feel quite sure this can be improved. val path = ( @@ -404,7 +430,7 @@ abstract class ExplicitOuter extends InfoTransform } if (!currentClass.isTrait) for (mc <- currentClass.mixinClasses) - if (outerAccessor(mc) != NoSymbol) + if (outerAccessor(mc) != NoSymbol && !skipMixinOuterAccessor(currentClass, mc)) newDefs += mixinOuterAccessorDef(mc) } } diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 8fd1df7cea..11bd0665b1 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -347,10 +347,14 @@ abstract class UnCurry extends InfoTransform } else { log(s"Argument '$arg' at line ${arg.pos.safeLine} is $formal from ${fun.fullName}") + def canUseDirectly(recv: Tree) = ( + recv.tpe.typeSymbol.isSubClass(FunctionClass(0)) + && treeInfo.isExprSafeToInline(recv) + ) arg match { // don't add a thunk for by-name argument if argument already is an application of // a Function0. We can then remove the application and use the existing Function0. - case Apply(Select(recv, nme.apply), Nil) if recv.tpe.typeSymbol isSubClass FunctionClass(0) => + case Apply(Select(recv, nme.apply), Nil) if canUseDirectly(recv) => recv case _ => newFunction0(arg) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala index 0371df3b10..92b7700c04 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala @@ -573,6 +573,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { assert(tp.isInstanceOf[SingletonType]) val toString = tp match { case ConstantType(c) => c.escapedStringValue + case _ if tp.typeSymbol.isModuleClass => tp.typeSymbol.name.toString case _ => tp.toString } Const.unique(tp, new ValueConst(tp, tp.widen, toString)) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala index 125e9a3b65..31b04d0bd6 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala @@ -15,9 +15,9 @@ import scala.reflect.internal.util.Position /** Optimize and analyze matches based on their TreeMaker-representation. * * The patmat translation doesn't rely on this, so it could be disabled in principle. - * - * TODO: split out match analysis + * - well, not quite: the backend crashes if we emit duplicates in switches (e.g. SI-7290) */ +// TODO: split out match analysis trait MatchOptimization extends MatchTreeMaking with MatchAnalysis { import global._ import global.definitions._ @@ -435,7 +435,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis { case SwitchableTreeMaker(pattern) :: GuardAndBodyTreeMakers(guard, body) => Some(CaseDef(pattern, guard, body)) // alternatives - case AlternativesTreeMaker(_, altss, _) :: GuardAndBodyTreeMakers(guard, body) if alternativesSupported => + case AlternativesTreeMaker(_, altss, pos) :: GuardAndBodyTreeMakers(guard, body) if alternativesSupported => val switchableAlts = altss map { case SwitchableTreeMaker(pattern) :: Nil => Some(pattern) @@ -445,7 +445,17 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis { // succeed if they were all switchable sequence(switchableAlts) map { switchableAlts => - CaseDef(Alternative(switchableAlts), guard, body) + def extractConst(t: Tree) = t match { + case Literal(const) => const + case _ => t + } + // SI-7290 Discard duplicate alternatives that would crash the backend + val distinctAlts = distinctBy(switchableAlts)(extractConst) + if (distinctAlts.size < switchableAlts.size) { + val duplicated = switchableAlts.groupBy(extractConst).flatMap(_._2.drop(1).take(1)) // report the first duplicated + global.currentUnit.warning(pos, s"Pattern contains duplicate alternatives: ${duplicated.mkString(", ")}") + } + CaseDef(Alternative(distinctAlts), guard, body) } case _ => // debug.patmat("can't emit switch for "+ makers) diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index d5ecb687b0..6921f8ce27 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -499,7 +499,7 @@ trait NamesDefaults { self: Analyzer => // disable conforms as a view... val errsBefore = reporter.ERROR.count try typer.silent { tpr => - val res = tpr.typed(arg, subst(paramtpe)) + val res = tpr.typed(arg.duplicate, subst(paramtpe)) // better warning for SI-5044: if `silent` was not actually silent give a hint to the user // [H]: the reason why `silent` is not silent is because the cyclic reference exception is // thrown in a context completely different from `context` here. The exception happens while diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 1f03a80008..7436a244bd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1332,8 +1332,7 @@ trait Typers extends Adaptations with Tags { def adaptToMemberWithArgs(tree: Tree, qual: Tree, name: Name, mode: Mode, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = { def onError(reportError: => Tree): Tree = context.tree match { case Apply(tree1, args) if (tree1 eq tree) && args.nonEmpty => - ( silent (_.typedArgs(args, mode)) - map (_.asInstanceOf[List[Tree]]) + ( silent (_.typedArgs(args.map(_.duplicate), mode)) filter (xs => !(xs exists (_.isErrorTyped))) map (xs => adaptToArguments(qual, name, xs, WildcardType, reportAmbiguous, saveErrors)) orElse ( _ => reportError) @@ -4380,6 +4379,12 @@ trait Typers extends Adaptations with Tags { treeCopy.New(tree, tpt1).setType(tp) } + def functionTypeWildcard(tree: Tree, arity: Int): Type = { + val tp = functionType(List.fill(arity)(WildcardType), WildcardType) + if (tp == NoType) MaxFunctionArityError(tree) + tp + } + def typedEta(expr1: Tree): Tree = expr1.tpe match { case TypeRef(_, ByNameParamClass, _) => val expr2 = Function(List(), expr1) setPos expr1.pos @@ -4391,10 +4396,10 @@ trait Typers extends Adaptations with Tags { typed1(expr2, mode, pt) case PolyType(_, MethodType(formals, _)) => if (isFunctionType(pt)) expr1 - else adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType)) + else adapt(expr1, mode, functionTypeWildcard(expr1, formals.length)) case MethodType(formals, _) => if (isFunctionType(pt)) expr1 - else adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType)) + else adapt(expr1, mode, functionTypeWildcard(expr1, formals.length)) case ErrorType => expr1 case _ => @@ -4706,7 +4711,7 @@ trait Typers extends Adaptations with Tags { atPos(tree.pos)(gen.convertToSelectFromType(qual, name)) match { case EmptyTree => None case tree1 => Some(typed1(tree1, mode, pt)) - } + } } else None ) diff --git a/src/compiler/scala/tools/nsc/util/SimpleTracer.scala b/src/compiler/scala/tools/nsc/util/SimpleTracer.scala index 6997dbd402..4e1cf02a6e 100644 --- a/src/compiler/scala/tools/nsc/util/SimpleTracer.scala +++ b/src/compiler/scala/tools/nsc/util/SimpleTracer.scala @@ -10,7 +10,7 @@ import java.io.PrintStream * @param enabled: A condition that must be true for trace info to be produced. */ class SimpleTracer(out: PrintStream, enabled: Boolean = true) { - def apply[T](msg: String)(value: T): T = { + def apply[T](msg: => String)(value: T): T = { if (enabled) out.println(msg+value) value } diff --git a/src/library/scala/collection/parallel/package.scala b/src/library/scala/collection/parallel/package.scala index d91f70da75..85c620239a 100644 --- a/src/library/scala/collection/parallel/package.scala +++ b/src/library/scala/collection/parallel/package.scala @@ -42,11 +42,8 @@ package object parallel { private[parallel] def outofbounds(idx: Int) = throw new IndexOutOfBoundsException(idx.toString) private[parallel] def getTaskSupport: TaskSupport = - if (scala.util.Properties.isJavaAtLeast("1.6")) { - val vendor = scala.util.Properties.javaVmVendor - if ((vendor contains "Oracle") || (vendor contains "Sun") || (vendor contains "Apple")) new ForkJoinTaskSupport - else new ThreadPoolTaskSupport - } else new ThreadPoolTaskSupport + if (scala.util.Properties.isJavaAtLeast("1.6")) new ForkJoinTaskSupport + else new ThreadPoolTaskSupport val defaultTaskSupport: TaskSupport = getTaskSupport diff --git a/src/partest/scala/tools/partest/nest/Diff.java b/src/partest/scala/tools/partest/nest/Diff.java deleted file mode 100644 index f69fc6858b..0000000000 --- a/src/partest/scala/tools/partest/nest/Diff.java +++ /dev/null @@ -1,873 +0,0 @@ - -package scala.tools.partest.nest; - -import java.util.Hashtable; - -/** A class to compare IndexedSeqs of objects. The result of comparison - is a list of <code>change</code> objects which form an - edit script. The objects compared are traditionally lines - of text from two files. Comparison options such as "ignore - whitespace" are implemented by modifying the <code>equals</code> - and <code>hashcode</code> methods for the objects compared. -<p> - The basic algorithm is described in: </br> - "An O(ND) Difference Algorithm and its Variations", Eugene Myers, - Algorithmica Vol. 1 No. 2, 1986, p 251. -<p> - This class outputs different results from GNU diff 1.15 on some - inputs. Our results are actually better (smaller change list, smaller - total size of changes), but it would be nice to know why. Perhaps - there is a memory overwrite bug in GNU diff 1.15. - - @author Stuart D. Gathman, translated from GNU diff 1.15 - Copyright (C) 2000 Business Management Systems, Inc. -<p> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. -<p> - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -<p> - You should have received a copy of the <a href=COPYING.txt> - GNU General Public License</a> - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -public class Diff { - - /** Prepare to find differences between two arrays. Each element of - the arrays is translated to an "equivalence number" based on - the result of <code>equals</code>. The original Object arrays - are no longer needed for computing the differences. They will - be needed again later to print the results of the comparison as - an edit script, if desired. - */ - public Diff(Object[] a,Object[] b) { - Hashtable<Object, Integer> h = new Hashtable<Object, Integer>(a.length + b.length); - filevec[0] = new file_data(a,h); - filevec[1] = new file_data(b,h); - } - - /** 1 more than the maximum equivalence value used for this or its - sibling file. */ - private int equiv_max = 1; - - /** When set to true, the comparison uses a heuristic to speed it up. - With this heuristic, for files with a constant small density - of changes, the algorithm is linear in the file size. */ - public boolean heuristic = false; - - /** When set to true, the algorithm returns a guarranteed minimal - set of changes. This makes things slower, sometimes much slower. */ - public boolean no_discards = false; - - private int[] xvec, yvec; /* IndexedSeqs being compared. */ - private int[] fdiag; /* IndexedSeq, indexed by diagonal, containing - the X coordinate of the point furthest - along the given diagonal in the forward - search of the edit matrix. */ - private int[] bdiag; /* IndexedSeq, indexed by diagonal, containing - the X coordinate of the point furthest - along the given diagonal in the backward - search of the edit matrix. */ - private int fdiagoff, bdiagoff; - private final file_data[] filevec = new file_data[2]; - private int cost; - - /** Find the midpoint of the shortest edit script for a specified - portion of the two files. - - We scan from the beginnings of the files, and simultaneously from the ends, - doing a breadth-first search through the space of edit-sequence. - When the two searches meet, we have found the midpoint of the shortest - edit sequence. - - The value returned is the number of the diagonal on which the midpoint lies. - The diagonal number equals the number of inserted lines minus the number - of deleted lines (counting only lines before the midpoint). - The edit cost is stored into COST; this is the total number of - lines inserted or deleted (counting only lines before the midpoint). - - This function assumes that the first lines of the specified portions - of the two files do not match, and likewise that the last lines do not - match. The caller must trim matching lines from the beginning and end - of the portions it is going to specify. - - Note that if we return the "wrong" diagonal value, or if - the value of bdiag at that diagonal is "wrong", - the worst this can do is cause suboptimal diff output. - It cannot cause incorrect diff output. */ - - private int diag (int xoff, int xlim, int yoff, int ylim) { - final int[] fd = fdiag; // Give the compiler a chance. - final int[] bd = bdiag; // Additional help for the compiler. - final int[] xv = xvec; // Still more help for the compiler. - final int[] yv = yvec; // And more and more . . . - final int dmin = xoff - ylim; // Minimum valid diagonal. - final int dmax = xlim - yoff; // Maximum valid diagonal. - final int fmid = xoff - yoff; // Center diagonal of top-down search. - final int bmid = xlim - ylim; // Center diagonal of bottom-up search. - int fmin = fmid, fmax = fmid; // Limits of top-down search. - int bmin = bmid, bmax = bmid; // Limits of bottom-up search. - /* True if southeast corner is on an odd - diagonal with respect to the northwest. */ - final boolean odd = (fmid - bmid & 1) != 0; - - fd[fdiagoff + fmid] = xoff; - bd[bdiagoff + bmid] = xlim; - - for (int c = 1;; ++c) - { - int d; /* Active diagonal. */ - boolean big_snake = false; - - /* Extend the top-down search by an edit step in each diagonal. */ - if (fmin > dmin) - fd[fdiagoff + --fmin - 1] = -1; - else - ++fmin; - if (fmax < dmax) - fd[fdiagoff + ++fmax + 1] = -1; - else - --fmax; - for (d = fmax; d >= fmin; d -= 2) - { - int x, y, oldx, tlo = fd[fdiagoff + d - 1], thi = fd[fdiagoff + d + 1]; - - if (tlo >= thi) - x = tlo + 1; - else - x = thi; - oldx = x; - y = x - d; - while (x < xlim && y < ylim && xv[x] == yv[y]) { - ++x; ++y; - } - if (x - oldx > 20) - big_snake = true; - fd[fdiagoff + d] = x; - if (odd && bmin <= d && d <= bmax && bd[bdiagoff + d] <= fd[fdiagoff + d]) - { - cost = 2 * c - 1; - return d; - } - } - - /* Similar extend the bottom-up search. */ - if (bmin > dmin) - bd[bdiagoff + --bmin - 1] = Integer.MAX_VALUE; - else - ++bmin; - if (bmax < dmax) - bd[bdiagoff + ++bmax + 1] = Integer.MAX_VALUE; - else - --bmax; - for (d = bmax; d >= bmin; d -= 2) - { - int x, y, oldx, tlo = bd[bdiagoff + d - 1], thi = bd[bdiagoff + d + 1]; - - if (tlo < thi) - x = tlo; - else - x = thi - 1; - oldx = x; - y = x - d; - while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) { - --x; --y; - } - if (oldx - x > 20) - big_snake = true; - bd[bdiagoff + d] = x; - if (!odd && fmin <= d && d <= fmax && bd[bdiagoff + d] <= fd[fdiagoff + d]) - { - cost = 2 * c; - return d; - } - } - - /* Heuristic: check occasionally for a diagonal that has made - lots of progress compared with the edit distance. - If we have any such, find the one that has made the most - progress and return it as if it had succeeded. - - With this heuristic, for files with a constant small density - of changes, the algorithm is linear in the file size. */ - - if (c > 200 && big_snake && heuristic) - { - int best = 0; - int bestpos = -1; - - for (d = fmax; d >= fmin; d -= 2) - { - int dd = d - fmid; - if ((fd[fdiagoff + d] - xoff)*2 - dd > 12 * (c + (dd > 0 ? dd : -dd))) - { - if (fd[fdiagoff + d] * 2 - dd > best - && fd[fdiagoff + d] - xoff > 20 - && fd[fdiagoff + d] - d - yoff > 20) - { - int k; - int x = fd[fdiagoff + d]; - - /* We have a good enough best diagonal; - now insist that it end with a significant snake. */ - for (k = 1; k <= 20; k++) - if (xvec[x - k] != yvec[x - d - k]) - break; - - if (k == 21) - { - best = fd[fdiagoff + d] * 2 - dd; - bestpos = d; - } - } - } - } - if (best > 0) - { - cost = 2 * c - 1; - return bestpos; - } - - best = 0; - for (d = bmax; d >= bmin; d -= 2) - { - int dd = d - bmid; - if ((xlim - bd[bdiagoff + d])*2 + dd > 12 * (c + (dd > 0 ? dd : -dd))) - { - if ((xlim - bd[bdiagoff + d]) * 2 + dd > best - && xlim - bd[bdiagoff + d] > 20 - && ylim - (bd[bdiagoff + d] - d) > 20) - { - /* We have a good enough best diagonal; - now insist that it end with a significant snake. */ - int k; - int x = bd[bdiagoff + d]; - - for (k = 0; k < 20; k++) - if (xvec[x + k] != yvec[x - d + k]) - break; - if (k == 20) - { - best = (xlim - bd[bdiagoff + d]) * 2 + dd; - bestpos = d; - } - } - } - } - if (best > 0) - { - cost = 2 * c - 1; - return bestpos; - } - } - } - } - - /** Compare in detail contiguous subsequences of the two files - which are known, as a whole, to match each other. - - The results are recorded in the IndexedSeqs filevec[N].changed_flag, by - storing a 1 in the element for each line that is an insertion or deletion. - - The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1. - - Note that XLIM, YLIM are exclusive bounds. - All line numbers are origin-0 and discarded lines are not counted. */ - - private void compareseq (int xoff, int xlim, int yoff, int ylim) { - /* Slide down the bottom initial diagonal. */ - while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff]) { - ++xoff; ++yoff; - } - /* Slide up the top initial diagonal. */ - while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1]) { - --xlim; --ylim; - } - - /* Handle simple cases. */ - if (xoff == xlim) - while (yoff < ylim) - filevec[1].changed_flag[1+filevec[1].realindexes[yoff++]] = true; - else if (yoff == ylim) - while (xoff < xlim) - filevec[0].changed_flag[1+filevec[0].realindexes[xoff++]] = true; - else - { - /* Find a point of correspondence in the middle of the files. */ - - int d = diag (xoff, xlim, yoff, ylim); - int c = cost; - int f = fdiag[fdiagoff + d]; - int b = bdiag[bdiagoff + d]; - - if (c == 1) - { - /* This should be impossible, because it implies that - one of the two subsequences is empty, - and that case was handled above without calling `diag'. - Let's verify that this is true. */ - throw new IllegalArgumentException("Empty subsequence"); - } - else - { - /* Use that point to split this problem into two subproblems. */ - compareseq (xoff, b, yoff, b - d); - /* This used to use f instead of b, - but that is incorrect! - It is not necessarily the case that diagonal d - has a snake from b to f. */ - compareseq (b, xlim, b - d, ylim); - } - } - } - - /** Discard lines from one file that have no matches in the other file. - */ - - private void discard_confusing_lines() { - filevec[0].discard_confusing_lines(filevec[1]); - filevec[1].discard_confusing_lines(filevec[0]); - } - - private boolean inhibit = false; - - /** Adjust inserts/deletes of blank lines to join changes - as much as possible. - */ - - private void shift_boundaries() { - if (inhibit) - return; - filevec[0].shift_boundaries(filevec[1]); - filevec[1].shift_boundaries(filevec[0]); - } - - public interface ScriptBuilder { - /** Scan the tables of which lines are inserted and deleted, - producing an edit script. - @param changed0 true for lines in first file which do not match 2nd - @param len0 number of lines in first file - @param changed1 true for lines in 2nd file which do not match 1st - @param len1 number of lines in 2nd file - @return a linked list of changes - or null - */ - public change build_script( - boolean[] changed0,int len0, - boolean[] changed1,int len1 - ); - } - - /** Scan the tables of which lines are inserted and deleted, - producing an edit script in reverse order. */ - - static class ReverseScript implements ScriptBuilder { - public change build_script( - final boolean[] changed0,int len0, - final boolean[] changed1,int len1) - { - change script = null; - int i0 = 0, i1 = 0; - while (i0 < len0 || i1 < len1) { - if (changed0[1+i0] || changed1[1+i1]) { - int line0 = i0, line1 = i1; - - /* Find # lines changed here in each file. */ - while (changed0[1+i0]) ++i0; - while (changed1[1+i1]) ++i1; - - /* Record this change. */ - script = new change(line0, line1, i0 - line0, i1 - line1, script); - } - - /* We have reached lines in the two files that match each other. */ - i0++; i1++; - } - - return script; - } - } - - static class ForwardScript implements ScriptBuilder { - /** Scan the tables of which lines are inserted and deleted, - producing an edit script in forward order. */ - public change build_script( - final boolean[] changed0,int len0, - final boolean[] changed1,int len1) - { - change script = null; - int i0 = len0, i1 = len1; - - while (i0 >= 0 || i1 >= 0) - { - if (changed0[i0] || changed1[i1]) - { - int line0 = i0, line1 = i1; - - /* Find # lines changed here in each file. */ - while (changed0[i0]) --i0; - while (changed1[i1]) --i1; - - /* Record this change. */ - script = new change(i0, i1, line0 - i0, line1 - i1, script); - } - - /* We have reached lines in the two files that match each other. */ - i0--; i1--; - } - - return script; - } - } - - /** Standard ScriptBuilders. */ - public final static ScriptBuilder - forwardScript = new ForwardScript(), - reverseScript = new ReverseScript(); - - /* Report the differences of two files. DEPTH is the current directory - depth. */ - public final change diff_2(final boolean reverse) { - return diff(reverse ? reverseScript : forwardScript); - } - - /** Get the results of comparison as an edit script. The script - is described by a list of changes. The standard ScriptBuilder - implementations provide for forward and reverse edit scripts. - Alternate implementations could, for instance, list common elements - instead of differences. - @param bld an object to build the script from change flags - @return the head of a list of changes - */ - public change diff(final ScriptBuilder bld) { - - /* Some lines are obviously insertions or deletions - because they don't match anything. Detect them now, - and avoid even thinking about them in the main comparison algorithm. */ - - discard_confusing_lines (); - - /* Now do the main comparison algorithm, considering just the - undiscarded lines. */ - - xvec = filevec[0].undiscarded; - yvec = filevec[1].undiscarded; - - int diags = - filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3; - fdiag = new int[diags]; - fdiagoff = filevec[1].nondiscarded_lines + 1; - bdiag = new int[diags]; - bdiagoff = filevec[1].nondiscarded_lines + 1; - - compareseq (0, filevec[0].nondiscarded_lines, - 0, filevec[1].nondiscarded_lines); - fdiag = null; - bdiag = null; - - /* Modify the results slightly to make them prettier - in cases where that can validly be done. */ - - shift_boundaries (); - - /* Get the results of comparison in the form of a chain - of `struct change's -- an edit script. */ - return bld.build_script( - filevec[0].changed_flag, - filevec[0].buffered_lines, - filevec[1].changed_flag, - filevec[1].buffered_lines - ); - - } - - /** The result of comparison is an "edit script": a chain of change objects. - Each change represents one place where some lines are deleted - and some are inserted. - - LINE0 and LINE1 are the first affected lines in the two files (origin 0). - DELETED is the number of lines deleted here from file 0. - INSERTED is the number of lines inserted here in file 1. - - If DELETED is 0 then LINE0 is the number of the line before - which the insertion was done; vice versa for INSERTED and LINE1. */ - - public static class change { - /** Previous or next edit command. */ - public change link; - /** # lines of file 1 changed here. */ - public final int inserted; - /** # lines of file 0 changed here. */ - public final int deleted; - /** Line number of 1st deleted line. */ - public final int line0; - /** Line number of 1st inserted line. */ - public final int line1; - - /** Cons an additional entry onto the front of an edit script OLD. - LINE0 and LINE1 are the first affected lines in the two files (origin 0). - DELETED is the number of lines deleted here from file 0. - INSERTED is the number of lines inserted here in file 1. - - If DELETED is 0 then LINE0 is the number of the line before - which the insertion was done; vice versa for INSERTED and LINE1. */ - public change(int line0, int line1, int deleted, int inserted, change old) { - this.line0 = line0; - this.line1 = line1; - this.inserted = inserted; - this.deleted = deleted; - this.link = old; - //System.err.println(line0+","+line1+","+inserted+","+deleted); - } - } - - /** Data on one input file being compared. - */ - - class file_data { - - /** Allocate changed array for the results of comparison. */ - void clear() { - /* Allocate a flag for each line of each file, saying whether that line - is an insertion or deletion. - Allocate an extra element, always zero, at each end of each IndexedSeq. - */ - changed_flag = new boolean[buffered_lines + 2]; - } - - /** Return equiv_count[I] as the number of lines in this file - that fall in equivalence class I. - @return the array of equivalence class counts. - */ - int[] equivCount() { - int[] equiv_count = new int[equiv_max]; - for (int i = 0; i < buffered_lines; ++i) - ++equiv_count[equivs[i]]; - return equiv_count; - } - - /** Discard lines that have no matches in another file. - - A line which is discarded will not be considered by the actual - comparison algorithm; it will be as if that line were not in the file. - The file's `realindexes' table maps virtual line numbers - (which don't count the discarded lines) into real line numbers; - this is how the actual comparison algorithm produces results - that are comprehensible when the discarded lines are counted. -<p> - When we discard a line, we also mark it as a deletion or insertion - so that it will be printed in the output. - @param f the other file - */ - void discard_confusing_lines(file_data f) { - clear(); - /* Set up table of which lines are going to be discarded. */ - final byte[] discarded = discardable(f.equivCount()); - - /* Don't really discard the provisional lines except when they occur - in a run of discardables, with nonprovisionals at the beginning - and end. */ - filterDiscards(discarded); - - /* Actually discard the lines. */ - discard(discarded); - } - - /** Mark to be discarded each line that matches no line of another file. - If a line matches many lines, mark it as provisionally discardable. - @see equivCount() - @param counts The count of each equivalence number for the other file. - @return 0=nondiscardable, 1=discardable or 2=provisionally discardable - for each line - */ - - private byte[] discardable(final int[] counts) { - final int end = buffered_lines; - final byte[] discards = new byte[end]; - final int[] equivs = this.equivs; - int many = 5; - int tem = end / 64; - - /* Multiply MANY by approximate square root of number of lines. - That is the threshold for provisionally discardable lines. */ - while ((tem = tem >> 2) > 0) - many *= 2; - - for (int i = 0; i < end; i++) - { - int nmatch; - if (equivs[i] == 0) - continue; - nmatch = counts[equivs[i]]; - if (nmatch == 0) - discards[i] = 1; - else if (nmatch > many) - discards[i] = 2; - } - return discards; - } - - /** Don't really discard the provisional lines except when they occur - in a run of discardables, with nonprovisionals at the beginning - and end. */ - - private void filterDiscards(final byte[] discards) { - final int end = buffered_lines; - - for (int i = 0; i < end; i++) - { - /* Cancel provisional discards not in middle of run of discards. */ - if (discards[i] == 2) - discards[i] = 0; - else if (discards[i] != 0) - { - /* We have found a nonprovisional discard. */ - int j; - int length; - int provisional = 0; - - /* Find end of this run of discardable lines. - Count how many are provisionally discardable. */ - for (j = i; j < end; j++) - { - if (discards[j] == 0) - break; - if (discards[j] == 2) - ++provisional; - } - - /* Cancel provisional discards at end, and shrink the run. */ - while (j > i && discards[j - 1] == 2) { - discards[--j] = 0; --provisional; - } - - /* Now we have the length of a run of discardable lines - whose first and last are not provisional. */ - length = j - i; - - /* If 1/4 of the lines in the run are provisional, - cancel discarding of all provisional lines in the run. */ - if (provisional * 4 > length) - { - while (j > i) - if (discards[--j] == 2) - discards[j] = 0; - } - else - { - int consec; - int minimum = 1; - int tem = length / 4; - - /* MINIMUM is approximate square root of LENGTH/4. - A subrun of two or more provisionals can stand - when LENGTH is at least 16. - A subrun of 4 or more can stand when LENGTH >= 64. */ - while ((tem = tem >> 2) > 0) - minimum *= 2; - minimum++; - - /* Cancel any subrun of MINIMUM or more provisionals - within the larger run. */ - for (j = 0, consec = 0; j < length; j++) - if (discards[i + j] != 2) - consec = 0; - else if (minimum == ++consec) - /* Back up to start of subrun, to cancel it all. */ - j -= consec; - else if (minimum < consec) - discards[i + j] = 0; - - /* Scan from beginning of run - until we find 3 or more nonprovisionals in a row - or until the first nonprovisional at least 8 lines in. - Until that point, cancel any provisionals. */ - for (j = 0, consec = 0; j < length; j++) - { - if (j >= 8 && discards[i + j] == 1) - break; - if (discards[i + j] == 2) { - consec = 0; discards[i + j] = 0; - } - else if (discards[i + j] == 0) - consec = 0; - else - consec++; - if (consec == 3) - break; - } - - /* I advances to the last line of the run. */ - i += length - 1; - - /* Same thing, from end. */ - for (j = 0, consec = 0; j < length; j++) - { - if (j >= 8 && discards[i - j] == 1) - break; - if (discards[i - j] == 2) { - consec = 0; discards[i - j] = 0; - } - else if (discards[i - j] == 0) - consec = 0; - else - consec++; - if (consec == 3) - break; - } - } - } - } - } - - /** Actually discard the lines. - @param discards flags lines to be discarded - */ - private void discard(final byte[] discards) { - final int end = buffered_lines; - int j = 0; - for (int i = 0; i < end; ++i) - if (no_discards || discards[i] == 0) - { - undiscarded[j] = equivs[i]; - realindexes[j++] = i; - } - else - changed_flag[1+i] = true; - nondiscarded_lines = j; - } - - file_data(Object[] data, Hashtable<Object, Integer> h) { - buffered_lines = data.length; - - equivs = new int[buffered_lines]; - undiscarded = new int[buffered_lines]; - realindexes = new int[buffered_lines]; - - for (int i = 0; i < data.length; ++i) { - Integer ir = h.get(data[i]); - if (ir == null) - h.put(data[i], new Integer(equivs[i] = equiv_max++)); - else - equivs[i] = ir.intValue(); - } - } - - /** Adjust inserts/deletes of blank lines to join changes - as much as possible. - - We do something when a run of changed lines include a blank - line at one end and have an excluded blank line at the other. - We are free to choose which blank line is included. - `compareseq' always chooses the one at the beginning, - but usually it is cleaner to consider the following blank line - to be the "change". The only exception is if the preceding blank line - would join this change to other changes. - @param f the file being compared against - */ - - void shift_boundaries(file_data f) { - final boolean[] changed = changed_flag; - final boolean[] other_changed = f.changed_flag; - int i = 0; - int j = 0; - int i_end = buffered_lines; - int preceding = -1; - int other_preceding = -1; - - for (;;) - { - int start, end, other_start; - - /* Scan forwards to find beginning of another run of changes. - Also keep track of the corresponding point in the other file. */ - - while (i < i_end && !changed[1+i]) - { - while (other_changed[1+j++]) - /* Non-corresponding lines in the other file - will count as the preceding batch of changes. */ - other_preceding = j; - i++; - } - - if (i == i_end) - break; - - start = i; - other_start = j; - - for (;;) - { - /* Now find the end of this run of changes. */ - - while (i < i_end && changed[1+i]) i++; - end = i; - - /* If the first changed line matches the following unchanged one, - and this run does not follow right after a previous run, - and there are no lines deleted from the other file here, - then classify the first changed line as unchanged - and the following line as changed in its place. */ - - /* You might ask, how could this run follow right after another? - Only because the previous run was shifted here. */ - - if (end != i_end - && equivs[start] == equivs[end] - && !other_changed[1+j] - && end != i_end - && !((preceding >= 0 && start == preceding) - || (other_preceding >= 0 - && other_start == other_preceding))) - { - changed[1+end++] = true; - changed[1+start++] = false; - ++i; - /* Since one line-that-matches is now before this run - instead of after, we must advance in the other file - to keep in synch. */ - ++j; - } - else - break; - } - - preceding = i; - other_preceding = j; - } - } - - /** Number of elements (lines) in this file. */ - final int buffered_lines; - - /** IndexedSeq, indexed by line number, containing an equivalence code for - each line. It is this IndexedSeq that is actually compared with that - of another file to generate differences. */ - private final int[] equivs; - - /** IndexedSeq, like the previous one except that - the elements for discarded lines have been squeezed out. */ - final int[] undiscarded; - - /** IndexedSeq mapping virtual line numbers (not counting discarded lines) - to real ones (counting those lines). Both are origin-0. */ - final int[] realindexes; - - /** Total number of nondiscarded lines. */ - int nondiscarded_lines; - - /** Array, indexed by real origin-1 line number, - containing true for a line that is an insertion or a deletion. - The results of comparison are stored here. */ - boolean[] changed_flag; - - } -} diff --git a/src/partest/scala/tools/partest/nest/DiffPrint.java b/src/partest/scala/tools/partest/nest/DiffPrint.java deleted file mode 100644 index 31f9a1bc79..0000000000 --- a/src/partest/scala/tools/partest/nest/DiffPrint.java +++ /dev/null @@ -1,606 +0,0 @@ - -package scala.tools.partest.nest; - -import java.io.*; -import java.util.Vector; -import java.util.Date; -//import com.objectspace.jgl.predicates.UnaryPredicate; - -interface UnaryPredicate { - boolean execute(Object obj); -} - -/** A simple framework for printing change lists produced by <code>Diff</code>. - @see bmsi.util.Diff - @author Stuart D. Gathman - Copyright (C) 2000 Business Management Systems, Inc. -<p> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. -<p> - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -<p> - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -public class DiffPrint { - /** A Base class for printing edit scripts produced by Diff. - This class divides the change list into "hunks", and calls - <code>print_hunk</code> for each hunk. Various utility methods - are provided as well. - */ - public static abstract class Base { - protected Base(Object[] a,Object[] b, Writer w) { - outfile = new PrintWriter(w); - file0 = a; - file1 = b; - } - /** Set to ignore certain kinds of lines when printing - an edit script. For example, ignoring blank lines or comments. - */ - protected UnaryPredicate ignore = null; - - /** Set to the lines of the files being compared. - */ - protected Object[] file0, file1; - - /** Divide SCRIPT into pieces by calling HUNKFUN and - print each piece with PRINTFUN. - Both functions take one arg, an edit script. - - PRINTFUN takes a subscript which belongs together (with a null - link at the end) and prints it. */ - public void print_script(Diff.change script) { - Diff.change next = script; - - while (next != null) - { - Diff.change t, end; - - /* Find a set of changes that belong together. */ - t = next; - end = hunkfun(next); - - /* Disconnect them from the rest of the changes, - making them a hunk, and remember the rest for next iteration. */ - next = end.link; - end.link = null; - //if (DEBUG) - // debug_script(t); - - /* Print this hunk. */ - print_hunk(t); - - /* Reconnect the script so it will all be freed properly. */ - end.link = next; - } - outfile.flush(); - } - - /** Called with the tail of the script - and returns the last link that belongs together with the start - of the tail. */ - - protected Diff.change hunkfun(Diff.change hunk) { - return hunk; - } - - protected int first0, last0, first1, last1, deletes, inserts; - protected PrintWriter outfile; - - /** Look at a hunk of edit script and report the range of lines in each file - that it applies to. HUNK is the start of the hunk, which is a chain - of `struct change'. The first and last line numbers of file 0 are stored - in *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1. - Note that these are internal line numbers that count from 0. - - If no lines from file 0 are deleted, then FIRST0 is LAST0+1. - - Also set *DELETES nonzero if any lines of file 0 are deleted - and set *INSERTS nonzero if any lines of file 1 are inserted. - If only ignorable lines are inserted or deleted, both are - set to 0. */ - - protected void analyze_hunk(Diff.change hunk) { - int f0, l0 = 0, f1, l1 = 0, show_from = 0, show_to = 0; - int i; - Diff.change next; - boolean nontrivial = (ignore == null); - - show_from = show_to = 0; - - f0 = hunk.line0; - f1 = hunk.line1; - - for (next = hunk; next != null; next = next.link) - { - l0 = next.line0 + next.deleted - 1; - l1 = next.line1 + next.inserted - 1; - show_from += next.deleted; - show_to += next.inserted; - for (i = next.line0; i <= l0 && ! nontrivial; i++) - if (!ignore.execute(file0[i])) - nontrivial = true; - for (i = next.line1; i <= l1 && ! nontrivial; i++) - if (!ignore.execute(file1[i])) - nontrivial = true; - } - - first0 = f0; - last0 = l0; - first1 = f1; - last1 = l1; - - /* If all inserted or deleted lines are ignorable, - tell the caller to ignore this hunk. */ - - if (!nontrivial) - show_from = show_to = 0; - - deletes = show_from; - inserts = show_to; - } - - /** Print the script header which identifies the files compared. */ - protected void print_header(String filea, String fileb) { } - - protected abstract void print_hunk(Diff.change hunk); - - protected void print_1_line(String pre,Object linbuf) { - outfile.println(pre + linbuf.toString()); - } - - /** Print a pair of line numbers with SEPCHAR, translated for file FILE. - If the two numbers are identical, print just one number. - - Args A and B are internal line numbers. - We print the translated (real) line numbers. */ - - protected void print_number_range (char sepchar, int a, int b) { - /* Note: we can have B < A in the case of a range of no lines. - In this case, we should print the line number before the range, - which is B. */ - if (++b > ++a) - outfile.print("" + a + sepchar + b); - else - outfile.print(b); - } - - public static char change_letter(int inserts, int deletes) { - if (inserts == 0) - return 'd'; - else if (deletes == 0) - return 'a'; - else - return 'c'; - } - } - - /** Print a change list in the standard diff format. - */ - public static class NormalPrint extends Base { - - public NormalPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - /** Print a hunk of a normal diff. - This is a contiguous portion of a complete edit script, - describing changes in consecutive lines. */ - - protected void print_hunk (Diff.change hunk) { - - /* Determine range of line numbers involved in each file. */ - analyze_hunk(hunk); - if (deletes == 0 && inserts == 0) - return; - - /* Print out the line number header for this hunk */ - print_number_range (',', first0, last0); - outfile.print(change_letter(inserts, deletes)); - print_number_range (',', first1, last1); - outfile.println(); - - /* Print the lines that the first file has. */ - if (deletes != 0) - for (int i = first0; i <= last0; i++) - print_1_line ("< ", file0[i]); - - if (inserts != 0 && deletes != 0) - outfile.println("---"); - - /* Print the lines that the second file has. */ - if (inserts != 0) - for (int i = first1; i <= last1; i++) - print_1_line ("> ", file1[i]); - } - } - - /** Prints an edit script in a format suitable for input to <code>ed</code>. - The edit script must be generated with the reverse option to - be useful as actual <code>ed</code> input. - */ - public static class EdPrint extends Base { - - public EdPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - /** Print a hunk of an ed diff */ - protected void print_hunk(Diff.change hunk) { - - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk); - if (deletes == 0 && inserts == 0) - return; - - /* Print out the line number header for this hunk */ - print_number_range (',', first0, last0); - outfile.println(change_letter(inserts, deletes)); - - /* Print new/changed lines from second file, if needed */ - if (inserts != 0) - { - boolean inserting = true; - for (int i = first1; i <= last1; i++) - { - /* Resume the insert, if we stopped. */ - if (! inserting) - outfile.println(i - first1 + first0 + "a"); - inserting = true; - - /* If the file's line is just a dot, it would confuse `ed'. - So output it with a double dot, and set the flag LEADING_DOT - so that we will output another ed-command later - to change the double dot into a single dot. */ - - if (".".equals(file1[i])) - { - outfile.println(".."); - outfile.println("."); - /* Now change that double dot to the desired single dot. */ - outfile.println(i - first1 + first0 + 1 + "s/^\\.\\././"); - inserting = false; - } - else - /* Line is not `.', so output it unmodified. */ - print_1_line ("", file1[i]); - } - - /* End insert mode, if we are still in it. */ - if (inserting) - outfile.println("."); - } - } - } - - /** Prints an edit script in context diff format. This and its - 'unified' variation is used for source code patches. - */ - public static class ContextPrint extends Base { - - protected int context = 3; - - public ContextPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - protected void print_context_label (String mark, File inf, String label) { - if (label != null) - outfile.println(mark + ' ' + label); - else if (inf.lastModified() > 0) - // FIXME: use DateFormat to get precise format needed. - outfile.println( - mark + ' ' + inf.getPath() + '\t' + new Date(inf.lastModified()) - ); - else - /* Don't pretend that standard input is ancient. */ - outfile.println(mark + ' ' + inf.getPath()); - } - - public void print_header(String filea,String fileb) { - print_context_label ("***", new File(filea), filea); - print_context_label ("---", new File(fileb), fileb); - } - - /** If function_regexp defined, search for start of function. */ - private String find_function(Object[] lines, int start) { - return null; - } - - protected void print_function(Object[] file,int start) { - String function = find_function (file0, first0); - if (function != null) { - outfile.print(" "); - outfile.print( - (function.length() < 40) ? function : function.substring(0,40) - ); - } - } - - protected void print_hunk(Diff.change hunk) { - - /* Determine range of line numbers involved in each file. */ - - analyze_hunk (hunk); - - if (deletes == 0 && inserts == 0) - return; - - /* Include a context's width before and after. */ - - first0 = Math.max(first0 - context, 0); - first1 = Math.max(first1 - context, 0); - last0 = Math.min(last0 + context, file0.length - 1); - last1 = Math.min(last1 + context, file1.length - 1); - - - outfile.print("***************"); - - /* If we looked for and found a function this is part of, - include its name in the header of the diff section. */ - print_function (file0, first0); - - outfile.println(); - outfile.print("*** "); - print_number_range (',', first0, last0); - outfile.println(" ****"); - - if (deletes != 0) { - Diff.change next = hunk; - - for (int i = first0; i <= last0; i++) { - /* Skip past changes that apply (in file 0) - only to lines before line I. */ - - while (next != null && next.line0 + next.deleted <= i) - next = next.link; - - /* Compute the marking for line I. */ - - String prefix = " "; - if (next != null && next.line0 <= i) - /* The change NEXT covers this line. - If lines were inserted here in file 1, this is "changed". - Otherwise it is "deleted". */ - prefix = (next.inserted > 0) ? "!" : "-"; - - print_1_line (prefix, file0[i]); - } - } - - outfile.print("--- "); - print_number_range (',', first1, last1); - outfile.println(" ----"); - - if (inserts != 0) { - Diff.change next = hunk; - - for (int i = first1; i <= last1; i++) { - /* Skip past changes that apply (in file 1) - only to lines before line I. */ - - while (next != null && next.line1 + next.inserted <= i) - next = next.link; - - /* Compute the marking for line I. */ - - String prefix = " "; - if (next != null && next.line1 <= i) - /* The change NEXT covers this line. - If lines were deleted here in file 0, this is "changed". - Otherwise it is "inserted". */ - prefix = (next.deleted > 0) ? "!" : "+"; - - print_1_line (prefix, file1[i]); - } - } - } - } - - /** Prints an edit script in context diff format. This and its - 'unified' variation is used for source code patches. - */ - public static class UnifiedPrint extends ContextPrint { - - public UnifiedPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - public void print_header(String filea,String fileb) { - print_context_label ("---", new File(filea), filea); - print_context_label ("+++", new File(fileb), fileb); - } - - private void print_number_range (int a, int b) { - //translate_range (file, a, b, &trans_a, &trans_b); - - /* Note: we can have B < A in the case of a range of no lines. - In this case, we should print the line number before the range, - which is B. */ - if (b < a) - outfile.print(b + ",0"); - else - super.print_number_range(',',a,b); - } - - protected void print_hunk(Diff.change hunk) { - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk); - - if (deletes == 0 && inserts == 0) - return; - - /* Include a context's width before and after. */ - - first0 = Math.max(first0 - context, 0); - first1 = Math.max(first1 - context, 0); - last0 = Math.min(last0 + context, file0.length - 1); - last1 = Math.min(last1 + context, file1.length - 1); - - - - outfile.print("@@ -"); - print_number_range (first0, last0); - outfile.print(" +"); - print_number_range (first1, last1); - outfile.print(" @@"); - - /* If we looked for and found a function this is part of, - include its name in the header of the diff section. */ - print_function(file0,first0); - - outfile.println(); - - Diff.change next = hunk; - int i = first0; - int j = first1; - - while (i <= last0 || j <= last1) { - - /* If the line isn't a difference, output the context from file 0. */ - - if (next == null || i < next.line0) { - outfile.print(' '); - print_1_line ("", file0[i++]); - j++; - } - else { - /* For each difference, first output the deleted part. */ - - int k = next.deleted; - while (k-- > 0) { - outfile.print('-'); - print_1_line ("", file0[i++]); - } - - /* Then output the inserted part. */ - - k = next.inserted; - while (k-- > 0) { - outfile.print('+'); - print_1_line ("", file1[j++]); - } - - /* We're done with this hunk, so on to the next! */ - - next = next.link; - } - } - } - } - - - /** Read a text file into an array of String. This provides basic diff - functionality. A more advanced diff utility will use specialized - objects to represent the text lines, with options to, for example, - convert sequences of whitespace to a single space for comparison - purposes. - */ - static String[] slurp(String file) throws IOException { - BufferedReader rdr = new BufferedReader(new FileReader(file)); - Vector<String> s = new Vector<String>(); - for (;;) { - String line = rdr.readLine(); - if (line == null) break; - s.addElement(line); - } - String[] a = new String[s.size()]; - s.copyInto(a); - return a; - } - - public static void main(String[] argv) throws IOException { - String filea = argv[argv.length - 2]; - String fileb = argv[argv.length - 1]; - String[] a = slurp(filea); - String[] b = slurp(fileb); - Diff d = new Diff(a,b); - char style = 'n'; - for (int i = 0; i < argv.length - 2; ++i) { - String f = argv[i]; - if (f.startsWith("-")) { - for (int j = 1; j < f.length(); ++j) { - switch (f.charAt(j)) { - case 'e': // Ed style - style = 'e'; break; - case 'c': // Context diff - style = 'c'; break; - case 'u': - style = 'u'; break; - } - } - } - } - boolean reverse = style == 'e'; - Diff.change script = d.diff_2(reverse); - if (script == null) - System.err.println("No differences"); - else { - Base p; - Writer w = new OutputStreamWriter(System.out); - switch (style) { - case 'e': - p = new EdPrint(a,b,w); break; - case 'c': - p = new ContextPrint(a,b,w); break; - case 'u': - p = new UnifiedPrint(a,b,w); break; - default: - p = new NormalPrint(a,b,w); - } - p.print_header(filea,fileb); - p.print_script(script); - } - } - - public static void doDiff(String[] argv, Writer w) throws IOException { - String filea = argv[argv.length - 2]; - String fileb = argv[argv.length - 1]; - String[] a = slurp(filea); - String[] b = slurp(fileb); - Diff d = new Diff(a,b); - char style = 'n'; - for (int i = 0; i < argv.length - 2; ++i) { - String f = argv[i]; - if (f.startsWith("-")) { - for (int j = 1; j < f.length(); ++j) { - switch (f.charAt(j)) { - case 'e': // Ed style - style = 'e'; break; - case 'c': // Context diff - style = 'c'; break; - case 'u': - style = 'u'; break; - } - } - } - } - boolean reverse = style == 'e'; - Diff.change script = d.diff_2(reverse); - if (script == null) - w.write("No differences\n"); - else { - Base p; - switch (style) { - case 'e': - p = new EdPrint(a,b,w); break; - case 'c': - p = new ContextPrint(a,b,w); break; - case 'u': - p = new UnifiedPrint(a,b,w); break; - default: - p = new NormalPrint(a,b,w); - } - p.print_header(filea,fileb); - p.print_script(script); - } - } - -} diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala index a32c56e973..23546c6511 100644 --- a/src/partest/scala/tools/partest/nest/FileManager.scala +++ b/src/partest/scala/tools/partest/nest/FileManager.scala @@ -17,34 +17,31 @@ import scala.collection.mutable trait FileUtil { /** - * Compares two files using a Java implementation of the GNU diff - * available at http://www.bmsi.com/java/#diff. + * Compares two files using difflib to produce a unified diff. * * @param f1 the first file to be compared * @param f2 the second file to be compared - * @return the text difference between the compared files + * @return the unified diff of the compared files or the empty string if they're equal */ def compareFiles(f1: File, f2: File): String = { - val diffWriter = new StringWriter - val args = Array(f1.getAbsolutePath(), f2.getAbsolutePath()) - - DiffPrint.doDiff(args, diffWriter) - val res = diffWriter.toString - if (res startsWith "No") "" else res + compareContents(io.Source.fromFile(f1).getLines.toSeq, io.Source.fromFile(f2).getLines.toSeq, f1.getName, f2.getName) } - def compareContents(lines1: Seq[String], lines2: Seq[String]): String = { - val xs1 = lines1.toArray[AnyRef] - val xs2 = lines2.toArray[AnyRef] - - val diff = new Diff(xs1, xs2) - val change = diff.diff_2(false) - val writer = new StringWriter - val p = new DiffPrint.NormalPrint(xs1, xs2, writer) - - p.print_script(change) - val res = writer.toString - if (res startsWith "No ") "" - else res + + /** + * Compares two lists of lines using difflib to produce a unified diff. + * + * @param origLines the first seq of lines to be compared + * @param newLines the second seq of lines to be compared + * @param origName file name to be used in unified diff for `origLines` + * @param newName file name to be used in unified diff for `newLines` + * @return the unified diff of the `origLines` and `newLines` or the empty string if they're equal + */ + def compareContents(origLines: Seq[String], newLines: Seq[String], origName: String = "a", newName: String = "b"): String = { + import collection.JavaConverters._ + + val diff = difflib.DiffUtils.diff(origLines.asJava, newLines.asJava) + if (diff.getDeltas.isEmpty) "" + else difflib.DiffUtils.generateUnifiedDiff(origName, newName, origLines.asJava, diff, 1).asScala.mkString("\n") } } object FileUtil extends FileUtil { } diff --git a/src/partest/scala/tools/partest/nest/PathSettings.scala b/src/partest/scala/tools/partest/nest/PathSettings.scala index 02651c527b..7c005b4f61 100644 --- a/src/partest/scala/tools/partest/nest/PathSettings.scala +++ b/src/partest/scala/tools/partest/nest/PathSettings.scala @@ -71,6 +71,9 @@ object PathSettings { findJar(buildPackLibDir.files ++ srcLibDir.files, "scalacheck") getOrElse { sys.error("No scalacheck jar found in '%s' or '%s'".format(buildPackLibDir, srcLibDir)) } + + lazy val diffUtils: File = + findJar(buildPackLibDir.files, "diffutils") getOrElse sys.error(s"No diffutils.jar found in '$buildPackLibDir'.") } class PathSettings() { diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala index 05cae7b238..9780e82cd9 100644 --- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala +++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala @@ -51,10 +51,13 @@ class ReflectiveRunner { new ConsoleFileManager // this is a workaround for https://issues.scala-lang.org/browse/SI-5433 - // when that bug is fixed, the addition of PathSettings.srcCodeLib can be removed + // when that bug is fixed, the addition of PathSettings.srcCodeLib can be removed // we hack into the classloader that will become parent classloader for scalac // this way we ensure that reflective macro lookup will pick correct Code.lift - val sepUrls = PathSettings.srcCodeLib.toURI.toURL :: fileManager.latestUrls + // it's also used to inject diffutils into the classpath when running partest from the test/partest script + val srcCodeLibAndDiff = List(PathSettings.srcCodeLib, PathSettings.diffUtils) + val sepUrls = srcCodeLibAndDiff.map(_.toURI.toURL) ::: fileManager.latestUrls + // this seems to be the core classloader that determines which classes can be found when running partest from the test/partest script val sepLoader = new URLClassLoader(sepUrls.toArray, null) if (isPartestDebug) diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala index 8f28277a6c..a63a81c47b 100644 --- a/src/partest/scala/tools/partest/nest/RunnerManager.scala +++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala @@ -78,6 +78,7 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP val compileMgr = new CompileManager(fileManager) fileManager.CLASSPATH += File.pathSeparator + PathSettings.scalaCheck + fileManager.CLASSPATH += File.pathSeparator + PathSettings.diffUtils // needed to put diffutils on test/partest's classpath private def compareFiles(f1: File, f2: File): String = try fileManager.compareFiles(f1, f2) diff --git a/src/reflect/scala/reflect/internal/ClassfileConstants.scala b/src/reflect/scala/reflect/internal/ClassfileConstants.scala index 78f7438429..faf61e5205 100644 --- a/src/reflect/scala/reflect/internal/ClassfileConstants.scala +++ b/src/reflect/scala/reflect/internal/ClassfileConstants.scala @@ -72,6 +72,9 @@ object ClassfileConstants { final val CONSTANT_METHODREF = 10 final val CONSTANT_INTFMETHODREF = 11 final val CONSTANT_NAMEANDTYPE = 12 + final val CONSTANT_METHODHANDLE = 15 + final val CONSTANT_METHODTYPE = 16 + final val CONSTANT_INVOKEDYNAMIC = 18 // tags describing the type of a literal in attribute values final val BYTE_TAG = 'B' @@ -306,7 +309,7 @@ object ClassfileConstants { final val invokespecial = 0xb7 final val invokestatic = 0xb8 final val invokeinterface = 0xb9 - final val xxxunusedxxxx = 0xba + final val invokedynamic = 0xba final val new_ = 0xbb final val newarray = 0xbc diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 037d44c540..ad7a0d45eb 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -2621,20 +2621,32 @@ trait Symbols extends api.Symbols { self: SymbolTable => } /** change name by appending $$<fully-qualified-name-of-class `base`> - * Do the same for any accessed symbols or setters/getters + * Do the same for any accessed symbols or setters/getters. + * If the accessor to be renamed is overriding a base symbol, enter + * a cloned symbol with the original name but without ACCESSOR flag. */ override def expandName(base: Symbol) { - if (!hasFlag(EXPANDEDNAME)) { - setFlag(EXPANDEDNAME) - if (hasAccessorFlag && !isDeferred) { - accessed.expandName(base) - } - else if (hasGetter) { - getter(owner).expandName(base) - setter(owner).expandName(base) - } - name = nme.expandedName(name.toTermName, base) + def expand(sym: Symbol) { + if ((sym eq NoSymbol) || (sym hasFlag EXPANDEDNAME)) () // skip + else sym setFlag EXPANDEDNAME setName nme.expandedName(sym.name.toTermName, base) + } + def cloneAndExpand(accessor: Symbol) { + val clone = accessor.cloneSymbol(accessor.owner, (accessor.flags | ARTIFACT) & ~ACCESSOR) + expand(accessor) + log(s"Expanded overriding accessor to $accessor, but cloned $clone to preserve override") + accessor.owner.info.decls enter clone + } + def expandAccessor(accessor: Symbol) { + if (accessor.isOverridingSymbol) cloneAndExpand(accessor) else expand(accessor) + } + if (hasAccessorFlag && !isDeferred) { + expand(accessed) + } + else if (hasGetter) { + expandAccessor(getter(owner)) + expandAccessor(setter(owner)) } + expand(this) } } implicit val TermSymbolTag = ClassTag[TermSymbol](classOf[TermSymbol]) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index d6eeb68452..611873efc0 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3760,10 +3760,11 @@ trait Types if (tp.isTrivial) tp else if (tp.prefix.typeSymbol isNonBottomSubClass owner) { val widened = tp match { - case _: ConstantType => tp // Java enum constants: don't widen to the enum type! - case _ => tp.widen // C.X.type widens to C.this.X.type, otherwise `tp asSeenFrom (pre, C)` has no effect. + case _: ConstantType => tp // Java enum constants: don't widen to the enum type! + case _ => tp.widen // C.X.type widens to C.this.X.type, otherwise `tp asSeenFrom (pre, C)` has no effect. } - widened asSeenFrom (pre, tp.typeSymbol.owner) + val memType = widened asSeenFrom (pre, tp.typeSymbol.owner) + if (tp eq widened) memType else memType.narrow } else loop(tp.prefix) memberType tp.typeSymbol diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala index 63b7f73386..d6fca9d186 100644 --- a/src/reflect/scala/reflect/internal/util/Collections.scala +++ b/src/reflect/scala/reflect/internal/util/Collections.scala @@ -76,6 +76,19 @@ trait Collections { lb.toList } + final def distinctBy[A, B](xs: List[A])(f: A => B): List[A] = { + val buf = new ListBuffer[A] + val seen = mutable.Set[B]() + xs foreach { x => + val y = f(x) + if (!seen(y)) { + buf += x + seen += y + } + } + buf.toList + } + @tailrec final def flattensToEmpty(xss: Seq[Seq[_]]): Boolean = { xss.isEmpty || xss.head.isEmpty && flattensToEmpty(xss.tail) } diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index a130013398..4d90afcdc3 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -14,7 +14,7 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S lazy val settings = new Settings private val isLogging = sys.props contains "scala.debug.reflect" - def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg) + def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg) type TreeCopier = InternalTreeCopierOps def newStrictTreeCopier: TreeCopier = new StrictTreeCopier diff --git a/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala b/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala index 2a07547de2..ac5fec80b3 100755 --- a/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala +++ b/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala @@ -73,16 +73,20 @@ object EntityLink { def unapply(el: EntityLink): Option[(Inline, LinkTo)] = Some((el.title, el.link)) } final case class HtmlTag(data: String) extends Inline { - def canClose(open: HtmlTag) = { - open.data.stripPrefix("<") == data.stripPrefix("</") + private val Pattern = """(?ms)\A<(/?)(.*?)[\s>].*\z""".r + private val (isEnd, tagName) = data match { + case Pattern(s1, s2) => + (! s1.isEmpty, Some(s2.toLowerCase)) + case _ => + (false, None) } - def close = { - if (data.indexOf("</") == -1) - Some(HtmlTag("</" + data.stripPrefix("<"))) - else - None + def canClose(open: HtmlTag) = { + isEnd && tagName == open.tagName } + + private val TagsNotToClose = Set("br", "img") + def close = tagName collect { case name if !TagsNotToClose(name) => HtmlTag(s"</$name>") } } /** The summary of a comment, usually its first sentence. There must be exactly one summary per body. */ diff --git a/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala b/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala index 5781e680dd..348ea97c5b 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala @@ -6,6 +6,7 @@ package scala.tools.nsc.doc.html import scala.xml.NodeSeq +import scala.annotation.tailrec /** Highlight the syntax of Scala code appearing in a `{{{` wiki block * (see method `HtmlPage.blockToHtml`). @@ -209,9 +210,9 @@ private[html] object SyntaxHigh { out.toString } - def parse(pre: String, i: Int): Int = { + @tailrec def parse(pre: String, i: Int): Unit = { out append pre - if (i == buf.length) return i + if (i == buf.length) return buf(i) match { case '\n' => parse("\n", i+1) @@ -277,7 +278,6 @@ private[html] object SyntaxHigh { } else parse(buf(i).toChar.toString, i+1) } - i } parse("", 0) diff --git a/starr.number b/starr.number new file mode 100644 index 0000000000..7e6e869eaf --- /dev/null +++ b/starr.number @@ -0,0 +1 @@ +starr.version=2.10.1
\ No newline at end of file diff --git a/test/files/jvm/t7253.check b/test/files/jvm/t7253.check new file mode 100644 index 0000000000..43f53aba12 --- /dev/null +++ b/test/files/jvm/t7253.check @@ -0,0 +1 @@ +bytecode identical diff --git a/test/files/jvm/t7253/Base_1.scala b/test/files/jvm/t7253/Base_1.scala new file mode 100644 index 0000000000..a531ebb69d --- /dev/null +++ b/test/files/jvm/t7253/Base_1.scala @@ -0,0 +1,5 @@ +trait A { def f(): Int } +trait B1 extends A +abstract class B2 extends A +class B3 extends A { def f(): Int = 1 } +class B4 extends B3 diff --git a/test/files/jvm/t7253/JavaClient_1.java b/test/files/jvm/t7253/JavaClient_1.java new file mode 100644 index 0000000000..43475de2f5 --- /dev/null +++ b/test/files/jvm/t7253/JavaClient_1.java @@ -0,0 +1,9 @@ +public class JavaClient_1 { + int foo() { + ((A) null).f(); + ((B1) null).f(); + ((B2) null).f(); + ((B3) null).f(); + return ((B4) null).f(); + } +} diff --git a/test/files/jvm/t7253/ScalaClient_1.scala b/test/files/jvm/t7253/ScalaClient_1.scala new file mode 100644 index 0000000000..d244b326a8 --- /dev/null +++ b/test/files/jvm/t7253/ScalaClient_1.scala @@ -0,0 +1,9 @@ +class ScalaClient_1 { + def foo() = { + (null: A).f() + (null: B1).f() + (null: B2).f() + (null: B3).f() + (null: B4).f() + } +} diff --git a/test/files/jvm/t7253/test.scala b/test/files/jvm/t7253/test.scala new file mode 100644 index 0000000000..7fe08e8813 --- /dev/null +++ b/test/files/jvm/t7253/test.scala @@ -0,0 +1,28 @@ +import scala.tools.partest.BytecodeTest + +import scala.tools.nsc.util.JavaClassPath +import java.io.InputStream +import scala.tools.asm +import asm.ClassReader +import asm.tree.{ClassNode, InsnList} +import scala.collection.JavaConverters._ + +object Test extends BytecodeTest { + import instructions._ + + def show: Unit = { + val instrBaseSeqs = Seq("ScalaClient_1", "JavaClient_1") map (name => instructions.fromMethod(getMethod(loadClassNode(name), "foo"))) + val instrSeqs = instrBaseSeqs map (_ filter isInvoke) + cmpInstructions(instrSeqs(0), instrSeqs(1)) + } + + def cmpInstructions(isa: List[Instruction], isb: List[Instruction]) = { + if (isa == isb) println("bytecode identical") + else diffInstructions(isa, isb) + } + + def isInvoke(node: Instruction): Boolean = { + val opcode = node.opcode + (opcode == "INVOKEVIRTUAL") || (opcode == "INVOKEINTERFACE") + } +} diff --git a/test/files/neg/t7285.check b/test/files/neg/t7285.check new file mode 100644 index 0000000000..a38772bead --- /dev/null +++ b/test/files/neg/t7285.check @@ -0,0 +1,15 @@ +t7285.scala:15: warning: match may not be exhaustive. +It would fail on the following input: (Up, Down) + (d1, d2) match { + ^ +t7285.scala:33: warning: match may not be exhaustive. +It would fail on the following input: Down + (d1) match { + ^ +t7285.scala:51: warning: match may not be exhaustive. +It would fail on the following input: (Up, Down) + (d1, d2) match { + ^ +error: No warnings can be incurred under -Xfatal-warnings. +three warnings found +one error found diff --git a/test/files/neg/t7285.flags b/test/files/neg/t7285.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/t7285.flags @@ -0,0 +1 @@ +-Xfatal-warnings
\ No newline at end of file diff --git a/test/files/neg/t7285.scala b/test/files/neg/t7285.scala new file mode 100644 index 0000000000..14121d92b1 --- /dev/null +++ b/test/files/neg/t7285.scala @@ -0,0 +1,55 @@ +sealed abstract class Base + + +object Test1 { + sealed abstract class Base + + object Base { + case object Down extends Base { + } + + case object Up extends Base { + } + + (d1: Base, d2: Base) => + (d1, d2) match { + case (Up, Up) | (Down, Down) => false + case (Down, Up) => true + } + } +} + +object Test2 { + sealed abstract class Base + + object Base { + case object Down extends Base { + } + + case object Up extends Base { + } + + (d1: Base, d2: Base) => + (d1) match { + case Test2.Base.Up => false + } + } +} + + +object Test4 { + sealed abstract class Base + + object Base { + case object Down extends Base + + case object Up extends Base + } + + import Test4.Base._ + (d1: Base, d2: Base) => + (d1, d2) match { + case (Up, Up) | (Down, Down) => false + case (Down, Test4.Base.Up) => true + } +} diff --git a/test/files/neg/t7290.check b/test/files/neg/t7290.check new file mode 100644 index 0000000000..ad2d0e25b0 --- /dev/null +++ b/test/files/neg/t7290.check @@ -0,0 +1,12 @@ +t7290.scala:4: warning: Pattern contains duplicate alternatives: 0 + case 0 | 0 => 0 + ^ +t7290.scala:5: warning: Pattern contains duplicate alternatives: 2, 3 + case 2 | 2 | 2 | 3 | 2 | 3 => 0 + ^ +t7290.scala:6: warning: Pattern contains duplicate alternatives: 4 + case 4 | (_ @ 4) => 0 + ^ +error: No warnings can be incurred under -Xfatal-warnings. +three warnings found +one error found diff --git a/test/files/neg/t7290.flags b/test/files/neg/t7290.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/t7290.flags @@ -0,0 +1 @@ +-Xfatal-warnings
\ No newline at end of file diff --git a/test/files/neg/t7290.scala b/test/files/neg/t7290.scala new file mode 100644 index 0000000000..b9db7f7e8a --- /dev/null +++ b/test/files/neg/t7290.scala @@ -0,0 +1,10 @@ +object Test extends App { + val y = (0: Int) match { + case 1 => 1 + case 0 | 0 => 0 + case 2 | 2 | 2 | 3 | 2 | 3 => 0 + case 4 | (_ @ 4) => 0 + case _ => -1 + } + assert(y == 0, y) +} diff --git a/test/files/neg/t7299.check b/test/files/neg/t7299.check new file mode 100644 index 0000000000..74340c4841 --- /dev/null +++ b/test/files/neg/t7299.check @@ -0,0 +1,7 @@ +t7299.scala:4: error: implementation restricts functions to 22 parameters + val eta1 = f _ + ^ +t7299.scala:5: error: implementation restricts functions to 22 parameters + val eta2 = g[Any] _ + ^ +two errors found diff --git a/test/files/neg/t7299.scala b/test/files/neg/t7299.scala new file mode 100644 index 0000000000..f3aae5ce5d --- /dev/null +++ b/test/files/neg/t7299.scala @@ -0,0 +1,6 @@ +object Test { + def f(a1: Int, a2: Int, a3: Int, a4: Int, a5: Int, a6: Int, a7: Int, a8: Int, a9: Int, a10: Int, a11: Int, a12: Int, a13: Int, a14: Int, a15: Int, a16: Int, a17: Int, a18: Int, a19: Int, a20: Int, a21: Int, a22: Int, a23: Int) = 0 + def g[A](a1: Int, a2: Int, a3: Int, a4: Int, a5: Int, a6: Int, a7: Int, a8: Int, a9: Int, a10: Int, a11: Int, a12: Int, a13: Int, a14: Int, a15: Int, a16: Int, a17: Int, a18: Int, a19: Int, a20: Int, a21: Int, a22: Int, a23: Int) = 0 + val eta1 = f _ + val eta2 = g[Any] _ +} diff --git a/test/files/pos/t6210.flags b/test/files/pos/t6210.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/pos/t6210.flags @@ -0,0 +1 @@ +-Xfatal-warnings
\ No newline at end of file diff --git a/test/files/pos/t6210.scala b/test/files/pos/t6210.scala new file mode 100644 index 0000000000..1ce8493872 --- /dev/null +++ b/test/files/pos/t6210.scala @@ -0,0 +1,21 @@ +abstract sealed trait AST +abstract sealed trait AExpr extends AST +case class AAssign(name: String, v: AExpr) extends AExpr +case class AConstBool(v: Boolean) extends AExpr + +trait Ty {} +case class TInt() extends Ty +case class TBool() extends Ty + +object Foo { + def checkExpr(ast: AExpr): Ty = { + var astTy:Ty = ast match { + case AAssign(nm: String, v:AExpr) => TBool() + + case AConstBool(v: Boolean) => TBool() + + case _ => throw new Exception(s"Unhandled case check(ast: ${ast.getClass})") + } + astTy + } +} diff --git a/test/files/pos/t6921.scala b/test/files/pos/t6921.scala new file mode 100644 index 0000000000..36e70e5d2c --- /dev/null +++ b/test/files/pos/t6921.scala @@ -0,0 +1,11 @@ +class Message(messageType: String, reason: Option[String]) + +class ReproForSI6921 { + + private[this] var reason = "" + + def decideElection = { + val explanation = None + new Message("", reason = explanation) + } +} diff --git a/test/files/pos/t7239.scala b/test/files/pos/t7239.scala new file mode 100644 index 0000000000..16e9d00f17 --- /dev/null +++ b/test/files/pos/t7239.scala @@ -0,0 +1,38 @@ +object Test { + def BrokenMethod(): HasFilter[(Int, String)] = ??? + + trait HasFilter[B] { + def filter(p: B => Boolean) = ??? + } + + trait HasWithFilter { + def withFilter = ??? + } + + object addWithFilter { + trait NoImplicit + implicit def enrich(v: Any) + (implicit F0: NoImplicit): HasWithFilter = ??? + } + + BrokenMethod().withFilter(_ => true) // okay + BrokenMethod().filter(_ => true) // okay + + locally { + import addWithFilter._ + BrokenMethod().withFilter((_: (Int, String)) => true) // okay + } + + locally { + import addWithFilter._ + // adaptToMemberWithArgs sets the type of the tree `x` + // to ErrorType (while in silent mode, so the error is not + // reported. Later, when the fallback from `withFilter` + // to `filter` is attempted, the closure is taken to have + // have the type `<error> => Boolean`, which conforms to + // `(B => Boolean)`. Only later during pickling does the + // defensive check for erroneous types in the tree pick up + // the problem. + BrokenMethod().withFilter(x => true) // erroneous or inaccessible type. + } +} diff --git a/test/files/pos/t7285a.flags b/test/files/pos/t7285a.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/pos/t7285a.flags @@ -0,0 +1 @@ +-Xfatal-warnings
\ No newline at end of file diff --git a/test/files/pos/t7285a.scala b/test/files/pos/t7285a.scala new file mode 100644 index 0000000000..34e79c741b --- /dev/null +++ b/test/files/pos/t7285a.scala @@ -0,0 +1,83 @@ +sealed abstract class Base + +object Test { + case object Up extends Base + + def foo(d1: Base) = + d1 match { + case Up => + } + + // Sealed subtype: ModuleTypeRef <empty>.this.Test.Up.type + // Pattern: UniqueThisType Test.this.type +} + + +object Test1 { + sealed abstract class Base + + object Base { + case object Down extends Base { + } + + case object Up extends Base { + } + + (d1: Base, d2: Base) => + (d1, d2) match { + case (Up, Up) | (Down, Down) => false + case (Down, Up) => true + case (Up, Down) => false + } + } +} + +object Test2 { + sealed abstract class Base + + object Base { + case object Down extends Base { + } + + case object Up extends Base { + } + + (d1: Base, d2: Base) => + (d1) match { + case Up | Down => false + } + } +} + +object Test3 { + sealed abstract class Base + + object Base { + case object Down extends Base + + (d1: Base, d2: Base) => + (d1, d2) match { + case (Down, Down) => false + } + } +} + +object Test4 { + sealed abstract class Base + + object Base { + case object Down extends Base { + } + + case object Up extends Base { + } + + } + import Test4.Base._ + (d1: Base, d2: Base) => + (d1, d2) match { + case (Up, Up) | (Down, Down) => false + case (Down, Test4.Base.Up) => true + case (Up, Down) => false + } +} diff --git a/test/files/run/classfile-format-51.scala b/test/files/run/classfile-format-51.scala new file mode 100644 index 0000000000..9b1e612f4f --- /dev/null +++ b/test/files/run/classfile-format-51.scala @@ -0,0 +1,126 @@ +import java.io.{File, FileOutputStream} + +import scala.tools.nsc.settings.ScalaVersion +import scala.tools.partest._ +import scala.tools.asm +import asm.{AnnotationVisitor, ClassWriter, FieldVisitor, Handle, MethodVisitor, Opcodes} +import Opcodes._ + +// This test ensures that we can read JDK 7 (classfile format 51) files, including those +// with invokeDynamic instructions and associated constant pool entries +// to do that it first uses ASM to generate a class called DynamicInvoker. Then +// it runs a normal compile on the source in the 'code' field that refers to +// DynamicInvoker. Any failure will be dumped to std out. +// +// By it's nature the test can only work on JDK 7+ because under JDK 6 some of the +// classes referred to by DynamicInvoker won't be available and DynamicInvoker won't +// verify. So the test includes a version check that short-circuites the whole test +// on JDK 6 +object Test extends DirectTest { + override def extraSettings: String = "-optimise -usejavacp -d " + testOutput.path + " -cp " + testOutput.path + + def generateClass() { + val invokerClassName = "DynamicInvoker" + val bootstrapMethodName = "bootstrap" + val bootStrapMethodType = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;" + val targetMethodName = "target" + val targetMethodType = "()Ljava/lang/String;" + + val cw = new ClassWriter(0) + cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, invokerClassName, null, "java/lang/Object", null) + + val constructor = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null) + constructor.visitCode() + constructor.visitVarInsn(ALOAD, 0) + constructor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V") + constructor.visitInsn(RETURN) + constructor.visitMaxs(1, 1) + constructor.visitEnd() + + val target = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, targetMethodName, targetMethodType, null, null) + target.visitCode() + target.visitLdcInsn("hello") + target.visitInsn(ARETURN) + target.visitMaxs(1, 1) + target.visitEnd() + + val bootstrap = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, bootstrapMethodName, bootStrapMethodType, null, null) + bootstrap.visitCode() +// val lookup = MethodHandles.lookup(); + bootstrap.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;") + bootstrap.visitVarInsn(ASTORE, 3) // lookup + +// val clazz = lookup.lookupClass(); + bootstrap.visitVarInsn(ALOAD, 3) // lookup + bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;") + bootstrap.visitVarInsn(ASTORE, 4) // clazz + +// val methodType = MethodType.fromMethodDescriptorString("()Ljava/lang/String, clazz.getClassLoader()") + bootstrap.visitLdcInsn("()Ljava/lang/String;") + bootstrap.visitVarInsn(ALOAD, 4) // CLAZZ + bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;") + bootstrap.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;") + bootstrap.visitVarInsn(ASTORE, 5) // methodType + +// val methodHandle = lookup.findStatic(thisClass, "target", methodType) + bootstrap.visitVarInsn(ALOAD, 3) // lookup + bootstrap.visitVarInsn(ALOAD, 4) // clazz + bootstrap.visitLdcInsn("target") + bootstrap.visitVarInsn(ALOAD, 5) // methodType + bootstrap.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;") + bootstrap.visitVarInsn(ASTORE, 6) // methodHandle + +// new ConstantCallSite(methodHandle) + bootstrap.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite") + bootstrap.visitInsn(DUP) + bootstrap.visitVarInsn(ALOAD, 6) // methodHandle + bootstrap.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "<init>", "(Ljava/lang/invoke/MethodHandle;)V") + bootstrap.visitInsn(ARETURN) + bootstrap.visitMaxs(4,7) + bootstrap.visitEnd() + + val test = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "test", s"()Ljava/lang/String;", null, null) + test.visitCode() + val bootstrapHandle = new Handle(H_INVOKESTATIC, invokerClassName, bootstrapMethodName, bootStrapMethodType) + test.visitInvokeDynamicInsn("invoke", targetMethodType, bootstrapHandle) + test.visitInsn(ARETURN) + test.visitMaxs(1, 1) + test.visitEnd() + + cw.visitEnd() + val bytes = cw.toByteArray() + + val fos = new FileOutputStream(new File(s"${testOutput.path}/$invokerClassName.class")) + try + fos write bytes + finally + fos.close() + + } + + def code = +""" +object Driver { + val invoker = new DynamicInvoker() + println(invoker.test()) +} +""" + + override def show(): Unit = { + // redirect err to out, for logging + val prevErr = System.err + System.setErr(System.out) + try { + // this test is only valid under JDK 1.7+ + // cheat a little by using 'ScalaVersion' because it can parse java versions just as well + val requiredJavaVersion = ScalaVersion("1.7") + val executingJavaVersion = ScalaVersion(System.getProperty("java.specification.version")) + if (executingJavaVersion >= requiredJavaVersion) { + generateClass() + compile() + } + } + finally + System.setErr(prevErr) + } +} diff --git a/test/files/run/inline-ex-handlers.check b/test/files/run/inline-ex-handlers.check index abcc8bf42d..7c885d2cc9 100644 --- a/test/files/run/inline-ex-handlers.check +++ b/test/files/run/inline-ex-handlers.check @@ -1,427 +1,492 @@ -172c172 -< locals: value x$1, value x1 ---- -> locals: value x$1, value x1, variable boxed1 -174c174 -< blocks: [1,2,3,4] ---- -> blocks: [1,3,4] -186a187,188 -> 92 STORE_LOCAL(variable boxed1) -> 92 LOAD_LOCAL(variable boxed1) -195,197d196 -< 92 JUMP 2 -< -< 2: -247c246 -< blocks: [1,2,3,4,5,6,7,8,11,12,13,14,15,16,17,18] ---- -> blocks: [1,2,3,4,5,6,8,11,12,13,14,15,16,17,18] -258,260d256 -< 92 JUMP 7 -< -< 7: -391c387 -< locals: value args, variable result, value ex6, value x4, value x5, value message, value x ---- -> locals: value args, variable result, value ex6, value x4, value x5, value x -393c389 -< blocks: [1,2,3,4,5,8,10,11,13] ---- -> blocks: [1,2,3,5,8,10,11,13,14] -417c413,422 -< 103 THROW(MyException) ---- -> ? STORE_LOCAL(value ex6) -> ? JUMP 14 -> -> 14: -> 101 LOAD_LOCAL(value ex6) -> 101 STORE_LOCAL(value x4) -> 101 SCOPE_ENTER value x4 -> 106 LOAD_LOCAL(value x4) -> 106 IS_INSTANCE REF(class MyException) -> 106 CZJUMP (BOOL)NE ? 5 : 8 -430,432d434 -< 101 JUMP 4 -< -< 4: -442,445d443 -< 106 LOAD_LOCAL(value x5) -< 106 CALL_METHOD MyException.message (dynamic) -< 106 STORE_LOCAL(value message) -< 106 SCOPE_ENTER value message -447c445,446 -< 106 LOAD_LOCAL(value message) ---- -> ? LOAD_LOCAL(value x5) -> 106 CALL_METHOD MyException.message (dynamic) -519c518 -< blocks: [1,2,3,4,6,7,9,10] ---- -> blocks: [1,3,4,6,7,9,10,11,12,13] -548c547,552 -< 306 THROW(MyException) ---- -> ? JUMP 11 -> -> 11: -> ? LOAD_LOCAL(variable monitor4) -> 305 MONITOR_EXIT -> ? JUMP 12 -554c558 -< ? THROW(Throwable) ---- -> ? JUMP 12 -560c564,571 -< ? THROW(Throwable) ---- -> ? STORE_LOCAL(value t) -> ? JUMP 13 -> -> 12: -> ? LOAD_LOCAL(variable monitor3) -> 304 MONITOR_EXIT -> ? STORE_LOCAL(value t) -> ? JUMP 13 -574c585 -< 310 JUMP 2 ---- -> 300 RETURN(UNIT) -576c587,596 -< 2: ---- -> 13: -> 310 LOAD_MODULE object Predef -> 310 CALL_PRIMITIVE(StartConcat) -> 310 CONSTANT("Caught crash: ") -> 310 CALL_PRIMITIVE(StringConcat(REF(class String))) -> 310 LOAD_LOCAL(value t) -> 310 CALL_METHOD java.lang.Throwable.toString (dynamic) -> 310 CALL_PRIMITIVE(StringConcat(REF(class String))) -> 310 CALL_PRIMITIVE(EndConcat) -> 310 CALL_METHOD scala.Predef.println (dynamic) -584c604 -< catch (Throwable) in ArrayBuffer(7, 9, 10) starting at: 6 ---- -> catch (Throwable) in ArrayBuffer(7, 9, 10, 11) starting at: 6 -587c607 -< catch (Throwable) in ArrayBuffer(4, 6, 7, 9, 10) starting at: 3 ---- -> catch (Throwable) in ArrayBuffer(4, 6, 7, 9, 10, 11, 12) starting at: 3 -619c639 -< blocks: [1,3,4,5,6,8,9] ---- -> blocks: [1,3,4,5,6,8,9,10,11] -643c663,669 -< 78 THROW(IllegalArgumentException) ---- -> ? STORE_LOCAL(value e) -> ? JUMP 10 -> -> 10: -> 81 LOAD_LOCAL(value e) -> ? STORE_LOCAL(variable exc1) -> ? JUMP 11 -669c695,696 -< 81 THROW(Exception) ---- -> ? STORE_LOCAL(variable exc1) -> ? JUMP 11 -685a713,725 -> 11: -> 83 LOAD_MODULE object Predef -> 83 CONSTANT("finally") -> 83 CALL_METHOD scala.Predef.println (dynamic) -> 84 LOAD_LOCAL(variable result) -> 84 CONSTANT(1) -> 84 CALL_PRIMITIVE(Arithmetic(SUB,INT)) -> 84 CONSTANT(2) -> 84 CALL_PRIMITIVE(Arithmetic(DIV,INT)) -> 84 STORE_LOCAL(variable result) -> 84 LOAD_LOCAL(variable exc1) -> 84 THROW(Throwable) -> -691c731 -< catch (<none>) in ArrayBuffer(4, 5, 6, 8) starting at: 3 ---- -> catch (<none>) in ArrayBuffer(4, 5, 6, 8, 10) starting at: 3 -715c755 -< locals: value args, variable result, value ex6, variable exc2, value x4, value x5, value message, value x, value ex6, value x4, value x5, value message, value x ---- -> locals: value args, variable result, value ex6, variable exc2, value x4, value x5, value x, value ex6, value x4, value x5, value x -717c757 -< blocks: [1,3,4,5,6,9,13,14,15,18,20,21,23,24] ---- -> blocks: [1,3,4,5,6,9,13,14,15,18,20,21,23,24,25,26,27] -741c781,788 -< 172 THROW(MyException) ---- -> ? STORE_LOCAL(value ex6) -> ? JUMP 25 -> -> 25: -> 170 LOAD_LOCAL(value ex6) -> 170 STORE_LOCAL(value x4) -> 170 SCOPE_ENTER value x4 -> 170 JUMP 14 -781,784d827 -< 175 LOAD_LOCAL(value x5) -< 175 CALL_METHOD MyException.message (dynamic) -< 175 STORE_LOCAL(value message) -< 175 SCOPE_ENTER value message -786c829,830 -< 176 LOAD_LOCAL(value message) ---- -> ? LOAD_LOCAL(value x5) -> 176 CALL_METHOD MyException.message (dynamic) -790c834,835 -< 177 LOAD_LOCAL(value message) ---- -> ? LOAD_LOCAL(value x5) -> 177 CALL_METHOD MyException.message (dynamic) -792c837,838 -< 177 THROW(MyException) ---- -> ? STORE_LOCAL(value ex6) -> ? JUMP 26 -796c842,843 -< 170 THROW(Throwable) ---- -> ? STORE_LOCAL(value ex6) -> ? JUMP 26 -805a853,858 -> 26: -> 169 LOAD_LOCAL(value ex6) -> 169 STORE_LOCAL(value x4) -> 169 SCOPE_ENTER value x4 -> 169 JUMP 5 -> -816,819d868 -< 180 LOAD_LOCAL(value x5) -< 180 CALL_METHOD MyException.message (dynamic) -< 180 STORE_LOCAL(value message) -< 180 SCOPE_ENTER value message -821c870,871 -< 181 LOAD_LOCAL(value message) ---- -> ? LOAD_LOCAL(value x5) -> 181 CALL_METHOD MyException.message (dynamic) -825c875,876 -< 182 LOAD_LOCAL(value message) ---- -> ? LOAD_LOCAL(value x5) -> 182 CALL_METHOD MyException.message (dynamic) -827c878,879 -< 182 THROW(MyException) ---- -> ? STORE_LOCAL(variable exc2) -> ? JUMP 27 -831c883,884 -< 169 THROW(Throwable) ---- -> ? STORE_LOCAL(variable exc2) -> ? JUMP 27 -847a901,913 -> 27: -> 184 LOAD_MODULE object Predef -> 184 CONSTANT("finally") -> 184 CALL_METHOD scala.Predef.println (dynamic) -> 185 LOAD_LOCAL(variable result) -> 185 CONSTANT(1) -> 185 CALL_PRIMITIVE(Arithmetic(SUB,INT)) -> 185 CONSTANT(2) -> 185 CALL_PRIMITIVE(Arithmetic(DIV,INT)) -> 185 STORE_LOCAL(variable result) -> 185 LOAD_LOCAL(variable exc2) -> 185 THROW(Throwable) -> -853c919 -< catch (Throwable) in ArrayBuffer(13, 14, 15, 18, 20, 21, 23) starting at: 4 ---- -> catch (Throwable) in ArrayBuffer(13, 14, 15, 18, 20, 21, 23, 25) starting at: 4 -856c922 -< catch (<none>) in ArrayBuffer(4, 5, 6, 9, 13, 14, 15, 18, 20, 21, 23) starting at: 3 ---- -> catch (<none>) in ArrayBuffer(4, 5, 6, 9, 13, 14, 15, 18, 20, 21, 23, 25, 26) starting at: 3 -880c946 -< locals: value args, variable result, value e, value ex6, value x4, value x5, value message, value x ---- -> locals: value args, variable result, value e, value ex6, value x4, value x5, value x -882c948 -< blocks: [1,2,3,6,7,8,11,13,14,16] ---- -> blocks: [1,2,3,6,7,8,11,13,14,16,17] -906c972,979 -< 124 THROW(MyException) ---- -> ? STORE_LOCAL(value ex6) -> ? JUMP 17 -> -> 17: -> 122 LOAD_LOCAL(value ex6) -> 122 STORE_LOCAL(value x4) -> 122 SCOPE_ENTER value x4 -> 122 JUMP 7 -931,934d1003 -< 127 LOAD_LOCAL(value x5) -< 127 CALL_METHOD MyException.message (dynamic) -< 127 STORE_LOCAL(value message) -< 127 SCOPE_ENTER value message -936c1005,1006 -< 127 LOAD_LOCAL(value message) ---- -> ? LOAD_LOCAL(value x5) -> 127 CALL_METHOD MyException.message (dynamic) -965c1035 -< catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 11, 13, 14, 16) starting at: 3 ---- -> catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 11, 13, 14, 16, 17) starting at: 3 -989c1059 -< locals: value args, variable result, value ex6, value x4, value x5, value message, value x, value e ---- -> locals: value args, variable result, value ex6, value x4, value x5, value x, value e -991c1061 -< blocks: [1,2,3,4,5,8,12,13,14,16] ---- -> blocks: [1,2,3,5,8,12,13,14,16,17] -1015c1085,1094 -< 148 THROW(MyException) ---- -> ? STORE_LOCAL(value ex6) -> ? JUMP 17 -> -> 17: -> 145 LOAD_LOCAL(value ex6) -> 145 STORE_LOCAL(value x4) -> 145 SCOPE_ENTER value x4 -> 154 LOAD_LOCAL(value x4) -> 154 IS_INSTANCE REF(class MyException) -> 154 CZJUMP (BOOL)NE ? 5 : 8 -1036,1038d1114 -< 145 JUMP 4 -< -< 4: -1048,1051d1123 -< 154 LOAD_LOCAL(value x5) -< 154 CALL_METHOD MyException.message (dynamic) -< 154 STORE_LOCAL(value message) -< 154 SCOPE_ENTER value message -1053c1125,1126 -< 154 LOAD_LOCAL(value message) ---- -> ? LOAD_LOCAL(value x5) -> 154 CALL_METHOD MyException.message (dynamic) -1270c1343 -< blocks: [1,2,3,4,5,7] ---- -> blocks: [1,2,3,4,5,7,8] -1294c1367,1374 -< 38 THROW(IllegalArgumentException) ---- -> ? STORE_LOCAL(value e) -> ? JUMP 8 -> -> 8: -> 42 LOAD_MODULE object Predef -> 42 CONSTANT("IllegalArgumentException") -> 42 CALL_METHOD scala.Predef.println (dynamic) -> 42 JUMP 2 -1341c1421 -< locals: value args, variable result, value ex6, value x4, value x5, value message, value x ---- -> locals: value args, variable result, value ex6, value x4, value x5, value x -1343c1423 -< blocks: [1,2,3,4,5,8,10,11,13,14,16] ---- -> blocks: [1,2,3,5,8,10,11,13,14,16,17] -1367c1447,1448 -< 203 THROW(MyException) ---- -> ? STORE_LOCAL(value ex6) -> ? JUMP 17 -1387c1468,1477 -< 209 THROW(MyException) ---- -> ? STORE_LOCAL(value ex6) -> ? JUMP 17 -> -> 17: -> 200 LOAD_LOCAL(value ex6) -> 200 STORE_LOCAL(value x4) -> 200 SCOPE_ENTER value x4 -> 212 LOAD_LOCAL(value x4) -> 212 IS_INSTANCE REF(class MyException) -> 212 CZJUMP (BOOL)NE ? 5 : 8 -1400,1402d1489 -< 200 JUMP 4 -< -< 4: -1412,1415d1498 -< 212 LOAD_LOCAL(value x5) -< 212 CALL_METHOD MyException.message (dynamic) -< 212 STORE_LOCAL(value message) -< 212 SCOPE_ENTER value message -1417c1500,1501 -< 213 LOAD_LOCAL(value message) ---- -> ? LOAD_LOCAL(value x5) -> 213 CALL_METHOD MyException.message (dynamic) -1461c1545 -< blocks: [1,2,3,4,5,7] ---- -> blocks: [1,2,3,4,5,7,8] -1485c1569,1570 -< 58 THROW(IllegalArgumentException) ---- -> ? STORE_LOCAL(value e) -> ? JUMP 8 -1486a1572,1577 -> 8: -> 62 LOAD_MODULE object Predef -> 62 CONSTANT("RuntimeException") -> 62 CALL_METHOD scala.Predef.println (dynamic) -> 62 JUMP 2 -> -1534c1625 -< blocks: [1,3,4] ---- -> blocks: [1,3,4,5] -1554c1645,1650 -< 229 THROW(MyException) ---- -> ? JUMP 5 -> -> 5: -> ? LOAD_LOCAL(variable monitor1) -> 228 MONITOR_EXIT -> 228 THROW(Throwable) -1560c1656 -< ? THROW(Throwable) ---- -> 228 THROW(Throwable) -1588c1684 -< locals: value args, variable result, variable monitor2, variable monitorResult1 ---- -> locals: value exception$1, value args, variable result, variable monitor2, variable monitorResult1 -1590c1686 -< blocks: [1,3,4] ---- -> blocks: [1,3,4,5] -1613c1709,1717 -< 245 THROW(MyException) ---- -> ? STORE_LOCAL(value exception$1) -> ? DROP ConcatClass -> ? LOAD_LOCAL(value exception$1) -> ? JUMP 5 -> -> 5: -> ? LOAD_LOCAL(variable monitor2) -> 244 MONITOR_EXIT -> 244 THROW(Throwable) -1619c1723 -< ? THROW(Throwable) ---- -> 244 THROW(Throwable) - +--- a ++++ b +@@ -171,5 +171,5 @@ + def productElement(x$1: Int (INT)): Object { +- locals: value x$1, value x1 ++ locals: value x$1, value x1, variable boxed1 + startBlock: 1 +- blocks: [1,2,3,4] ++ blocks: [1,3,4] + +@@ -186,2 +186,4 @@ + 92 LOAD_LOCAL(value x$1) ++ 92 STORE_LOCAL(variable boxed1) ++ 92 LOAD_LOCAL(variable boxed1) + 92 BOX INT +@@ -194,5 +196,2 @@ + 92 CALL_METHOD MyException.message (dynamic) +- 92 JUMP 2 +- +- 2: + 92 RETURN(REF(class Object)) +@@ -246,3 +245,3 @@ + startBlock: 1 +- blocks: [1,2,3,4,5,6,7,8,11,12,13,14,15,16,17,18] ++ blocks: [1,2,3,4,5,6,8,11,12,13,14,15,16,17,18] + +@@ -257,5 +256,2 @@ + 92 SCOPE_ENTER value x1 +- 92 JUMP 7 +- +- 7: + 92 LOAD_LOCAL(value x1) +@@ -390,5 +386,5 @@ + def main(args: Array[String] (ARRAY[REF(class String)])): Unit { +- locals: value args, variable result, value ex6, value x4, value x5, value message, value x ++ locals: value args, variable result, value ex6, value x4, value x5, value x + startBlock: 1 +- blocks: [1,2,3,4,5,8,10,11,13] ++ blocks: [1,2,3,5,8,10,11,13,14] + +@@ -416,4 +412,13 @@ + 103 CALL_METHOD MyException.<init> (static-instance) +- 103 THROW(MyException) ++ ? STORE_LOCAL(value ex6) ++ ? JUMP 14 + ++ 14: ++ 101 LOAD_LOCAL(value ex6) ++ 101 STORE_LOCAL(value x4) ++ 101 SCOPE_ENTER value x4 ++ 106 LOAD_LOCAL(value x4) ++ 106 IS_INSTANCE REF(class MyException) ++ 106 CZJUMP (BOOL)NE ? 5 : 8 ++ + 13: +@@ -429,5 +434,2 @@ + 101 SCOPE_ENTER value x4 +- 101 JUMP 4 +- +- 4: + 106 LOAD_LOCAL(value x4) +@@ -441,8 +443,5 @@ + 106 SCOPE_ENTER value x5 +- 106 LOAD_LOCAL(value x5) +- 106 CALL_METHOD MyException.message (dynamic) +- 106 STORE_LOCAL(value message) +- 106 SCOPE_ENTER value message + 106 LOAD_MODULE object Predef +- 106 LOAD_LOCAL(value message) ++ ? LOAD_LOCAL(value x5) ++ 106 CALL_METHOD MyException.message (dynamic) + 106 CALL_METHOD scala.Predef.println (dynamic) +@@ -518,3 +517,3 @@ + startBlock: 1 +- blocks: [1,2,3,4,6,7,9,10] ++ blocks: [1,3,4,6,7,9,10,11,12,13] + +@@ -547,4 +546,9 @@ + 306 CALL_METHOD MyException.<init> (static-instance) +- 306 THROW(MyException) ++ ? JUMP 11 + ++ 11: ++ ? LOAD_LOCAL(variable monitor4) ++ 305 MONITOR_EXIT ++ ? JUMP 12 ++ + 9: +@@ -553,3 +557,3 @@ + 305 MONITOR_EXIT +- ? THROW(Throwable) ++ ? JUMP 12 + +@@ -559,4 +563,11 @@ + 304 MONITOR_EXIT +- ? THROW(Throwable) ++ ? STORE_LOCAL(value t) ++ ? JUMP 13 + ++ 12: ++ ? LOAD_LOCAL(variable monitor3) ++ 304 MONITOR_EXIT ++ ? STORE_LOCAL(value t) ++ ? JUMP 13 ++ + 3: +@@ -573,5 +584,14 @@ + 310 CALL_METHOD scala.Predef.println (dynamic) +- 310 JUMP 2 ++ 300 RETURN(UNIT) + +- 2: ++ 13: ++ 310 LOAD_MODULE object Predef ++ 310 CALL_PRIMITIVE(StartConcat) ++ 310 CONSTANT("Caught crash: ") ++ 310 CALL_PRIMITIVE(StringConcat(REF(class String))) ++ 310 LOAD_LOCAL(value t) ++ 310 CALL_METHOD java.lang.Throwable.toString (dynamic) ++ 310 CALL_PRIMITIVE(StringConcat(REF(class String))) ++ 310 CALL_PRIMITIVE(EndConcat) ++ 310 CALL_METHOD scala.Predef.println (dynamic) + 300 RETURN(UNIT) +@@ -583,6 +603,6 @@ + with finalizer: null +- catch (Throwable) in ArrayBuffer(7, 9, 10) starting at: 6 ++ catch (Throwable) in ArrayBuffer(7, 9, 10, 11) starting at: 6 + consisting of blocks: List(6) + with finalizer: null +- catch (Throwable) in ArrayBuffer(4, 6, 7, 9, 10) starting at: 3 ++ catch (Throwable) in ArrayBuffer(4, 6, 7, 9, 10, 11, 12) starting at: 3 + consisting of blocks: List(3) +@@ -618,3 +638,3 @@ + startBlock: 1 +- blocks: [1,3,4,5,6,8,9] ++ blocks: [1,3,4,5,6,8,9,10,11] + +@@ -642,4 +662,10 @@ + 78 CALL_METHOD java.lang.IllegalArgumentException.<init> (static-instance) +- 78 THROW(IllegalArgumentException) ++ ? STORE_LOCAL(value e) ++ ? JUMP 10 + ++ 10: ++ 81 LOAD_LOCAL(value e) ++ ? STORE_LOCAL(variable exc1) ++ ? JUMP 11 ++ + 8: +@@ -668,3 +694,4 @@ + 81 LOAD_LOCAL(value e) +- 81 THROW(Exception) ++ ? STORE_LOCAL(variable exc1) ++ ? JUMP 11 + +@@ -685,2 +712,15 @@ + ++ 11: ++ 83 LOAD_MODULE object Predef ++ 83 CONSTANT("finally") ++ 83 CALL_METHOD scala.Predef.println (dynamic) ++ 84 LOAD_LOCAL(variable result) ++ 84 CONSTANT(1) ++ 84 CALL_PRIMITIVE(Arithmetic(SUB,INT)) ++ 84 CONSTANT(2) ++ 84 CALL_PRIMITIVE(Arithmetic(DIV,INT)) ++ 84 STORE_LOCAL(variable result) ++ 84 LOAD_LOCAL(variable exc1) ++ 84 THROW(Throwable) ++ + } +@@ -690,3 +730,3 @@ + with finalizer: null +- catch (<none>) in ArrayBuffer(4, 5, 6, 8) starting at: 3 ++ catch (<none>) in ArrayBuffer(4, 5, 6, 8, 10) starting at: 3 + consisting of blocks: List(3) +@@ -714,5 +754,5 @@ + def main(args: Array[String] (ARRAY[REF(class String)])): Unit { +- locals: value args, variable result, value ex6, variable exc2, value x4, value x5, value message, value x, value ex6, value x4, value x5, value message, value x ++ locals: value args, variable result, value ex6, variable exc2, value x4, value x5, value x, value ex6, value x4, value x5, value x + startBlock: 1 +- blocks: [1,3,4,5,6,9,13,14,15,18,20,21,23,24] ++ blocks: [1,3,4,5,6,9,13,14,15,18,20,21,23,24,25,26,27] + +@@ -740,4 +780,11 @@ + 172 CALL_METHOD MyException.<init> (static-instance) +- 172 THROW(MyException) ++ ? STORE_LOCAL(value ex6) ++ ? JUMP 25 + ++ 25: ++ 170 LOAD_LOCAL(value ex6) ++ 170 STORE_LOCAL(value x4) ++ 170 SCOPE_ENTER value x4 ++ 170 JUMP 14 ++ + 23: +@@ -780,8 +827,5 @@ + 175 SCOPE_ENTER value x5 +- 175 LOAD_LOCAL(value x5) +- 175 CALL_METHOD MyException.message (dynamic) +- 175 STORE_LOCAL(value message) +- 175 SCOPE_ENTER value message + 176 LOAD_MODULE object Predef +- 176 LOAD_LOCAL(value message) ++ ? LOAD_LOCAL(value x5) ++ 176 CALL_METHOD MyException.message (dynamic) + 176 CALL_METHOD scala.Predef.println (dynamic) +@@ -789,5 +833,7 @@ + 177 DUP(REF(class MyException)) +- 177 LOAD_LOCAL(value message) ++ ? LOAD_LOCAL(value x5) ++ 177 CALL_METHOD MyException.message (dynamic) + 177 CALL_METHOD MyException.<init> (static-instance) +- 177 THROW(MyException) ++ ? STORE_LOCAL(value ex6) ++ ? JUMP 26 + +@@ -795,3 +841,4 @@ + 170 LOAD_LOCAL(value ex6) +- 170 THROW(Throwable) ++ ? STORE_LOCAL(value ex6) ++ ? JUMP 26 + +@@ -805,2 +852,8 @@ + ++ 26: ++ 169 LOAD_LOCAL(value ex6) ++ 169 STORE_LOCAL(value x4) ++ 169 SCOPE_ENTER value x4 ++ 169 JUMP 5 ++ + 5: +@@ -815,8 +868,5 @@ + 180 SCOPE_ENTER value x5 +- 180 LOAD_LOCAL(value x5) +- 180 CALL_METHOD MyException.message (dynamic) +- 180 STORE_LOCAL(value message) +- 180 SCOPE_ENTER value message + 181 LOAD_MODULE object Predef +- 181 LOAD_LOCAL(value message) ++ ? LOAD_LOCAL(value x5) ++ 181 CALL_METHOD MyException.message (dynamic) + 181 CALL_METHOD scala.Predef.println (dynamic) +@@ -824,5 +874,7 @@ + 182 DUP(REF(class MyException)) +- 182 LOAD_LOCAL(value message) ++ ? LOAD_LOCAL(value x5) ++ 182 CALL_METHOD MyException.message (dynamic) + 182 CALL_METHOD MyException.<init> (static-instance) +- 182 THROW(MyException) ++ ? STORE_LOCAL(variable exc2) ++ ? JUMP 27 + +@@ -830,3 +882,4 @@ + 169 LOAD_LOCAL(value ex6) +- 169 THROW(Throwable) ++ ? STORE_LOCAL(variable exc2) ++ ? JUMP 27 + +@@ -847,2 +900,15 @@ + ++ 27: ++ 184 LOAD_MODULE object Predef ++ 184 CONSTANT("finally") ++ 184 CALL_METHOD scala.Predef.println (dynamic) ++ 185 LOAD_LOCAL(variable result) ++ 185 CONSTANT(1) ++ 185 CALL_PRIMITIVE(Arithmetic(SUB,INT)) ++ 185 CONSTANT(2) ++ 185 CALL_PRIMITIVE(Arithmetic(DIV,INT)) ++ 185 STORE_LOCAL(variable result) ++ 185 LOAD_LOCAL(variable exc2) ++ 185 THROW(Throwable) ++ + } +@@ -852,6 +918,6 @@ + with finalizer: null +- catch (Throwable) in ArrayBuffer(13, 14, 15, 18, 20, 21, 23) starting at: 4 ++ catch (Throwable) in ArrayBuffer(13, 14, 15, 18, 20, 21, 23, 25) starting at: 4 + consisting of blocks: List(9, 8, 6, 5, 4) + with finalizer: null +- catch (<none>) in ArrayBuffer(4, 5, 6, 9, 13, 14, 15, 18, 20, 21, 23) starting at: 3 ++ catch (<none>) in ArrayBuffer(4, 5, 6, 9, 13, 14, 15, 18, 20, 21, 23, 25, 26) starting at: 3 + consisting of blocks: List(3) +@@ -879,5 +945,5 @@ + def main(args: Array[String] (ARRAY[REF(class String)])): Unit { +- locals: value args, variable result, value e, value ex6, value x4, value x5, value message, value x ++ locals: value args, variable result, value e, value ex6, value x4, value x5, value x + startBlock: 1 +- blocks: [1,2,3,6,7,8,11,13,14,16] ++ blocks: [1,2,3,6,7,8,11,13,14,16,17] + +@@ -905,4 +971,11 @@ + 124 CALL_METHOD MyException.<init> (static-instance) +- 124 THROW(MyException) ++ ? STORE_LOCAL(value ex6) ++ ? JUMP 17 + ++ 17: ++ 122 LOAD_LOCAL(value ex6) ++ 122 STORE_LOCAL(value x4) ++ 122 SCOPE_ENTER value x4 ++ 122 JUMP 7 ++ + 16: +@@ -930,8 +1003,5 @@ + 127 SCOPE_ENTER value x5 +- 127 LOAD_LOCAL(value x5) +- 127 CALL_METHOD MyException.message (dynamic) +- 127 STORE_LOCAL(value message) +- 127 SCOPE_ENTER value message + 127 LOAD_MODULE object Predef +- 127 LOAD_LOCAL(value message) ++ ? LOAD_LOCAL(value x5) ++ 127 CALL_METHOD MyException.message (dynamic) + 127 CALL_METHOD scala.Predef.println (dynamic) +@@ -964,3 +1034,3 @@ + with finalizer: null +- catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 11, 13, 14, 16) starting at: 3 ++ catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 11, 13, 14, 16, 17) starting at: 3 + consisting of blocks: List(3) +@@ -988,5 +1058,5 @@ + def main(args: Array[String] (ARRAY[REF(class String)])): Unit { +- locals: value args, variable result, value ex6, value x4, value x5, value message, value x, value e ++ locals: value args, variable result, value ex6, value x4, value x5, value x, value e + startBlock: 1 +- blocks: [1,2,3,4,5,8,12,13,14,16] ++ blocks: [1,2,3,5,8,12,13,14,16,17] + +@@ -1014,4 +1084,13 @@ + 148 CALL_METHOD MyException.<init> (static-instance) +- 148 THROW(MyException) ++ ? STORE_LOCAL(value ex6) ++ ? JUMP 17 + ++ 17: ++ 145 LOAD_LOCAL(value ex6) ++ 145 STORE_LOCAL(value x4) ++ 145 SCOPE_ENTER value x4 ++ 154 LOAD_LOCAL(value x4) ++ 154 IS_INSTANCE REF(class MyException) ++ 154 CZJUMP (BOOL)NE ? 5 : 8 ++ + 16: +@@ -1035,5 +1114,2 @@ + 145 SCOPE_ENTER value x4 +- 145 JUMP 4 +- +- 4: + 154 LOAD_LOCAL(value x4) +@@ -1047,8 +1123,5 @@ + 154 SCOPE_ENTER value x5 +- 154 LOAD_LOCAL(value x5) +- 154 CALL_METHOD MyException.message (dynamic) +- 154 STORE_LOCAL(value message) +- 154 SCOPE_ENTER value message + 154 LOAD_MODULE object Predef +- 154 LOAD_LOCAL(value message) ++ ? LOAD_LOCAL(value x5) ++ 154 CALL_METHOD MyException.message (dynamic) + 154 CALL_METHOD scala.Predef.println (dynamic) +@@ -1269,3 +1342,3 @@ + startBlock: 1 +- blocks: [1,2,3,4,5,7] ++ blocks: [1,2,3,4,5,7,8] + +@@ -1293,4 +1366,11 @@ + 38 CALL_METHOD java.lang.IllegalArgumentException.<init> (static-instance) +- 38 THROW(IllegalArgumentException) ++ ? STORE_LOCAL(value e) ++ ? JUMP 8 + ++ 8: ++ 42 LOAD_MODULE object Predef ++ 42 CONSTANT("IllegalArgumentException") ++ 42 CALL_METHOD scala.Predef.println (dynamic) ++ 42 JUMP 2 ++ + 7: +@@ -1340,5 +1420,5 @@ + def main(args: Array[String] (ARRAY[REF(class String)])): Unit { +- locals: value args, variable result, value ex6, value x4, value x5, value message, value x ++ locals: value args, variable result, value ex6, value x4, value x5, value x + startBlock: 1 +- blocks: [1,2,3,4,5,8,10,11,13,14,16] ++ blocks: [1,2,3,5,8,10,11,13,14,16,17] + +@@ -1366,3 +1446,4 @@ + 203 CALL_METHOD MyException.<init> (static-instance) +- 203 THROW(MyException) ++ ? STORE_LOCAL(value ex6) ++ ? JUMP 17 + +@@ -1386,4 +1467,13 @@ + 209 CALL_METHOD MyException.<init> (static-instance) +- 209 THROW(MyException) ++ ? STORE_LOCAL(value ex6) ++ ? JUMP 17 + ++ 17: ++ 200 LOAD_LOCAL(value ex6) ++ 200 STORE_LOCAL(value x4) ++ 200 SCOPE_ENTER value x4 ++ 212 LOAD_LOCAL(value x4) ++ 212 IS_INSTANCE REF(class MyException) ++ 212 CZJUMP (BOOL)NE ? 5 : 8 ++ + 16: +@@ -1399,5 +1489,2 @@ + 200 SCOPE_ENTER value x4 +- 200 JUMP 4 +- +- 4: + 212 LOAD_LOCAL(value x4) +@@ -1411,8 +1498,5 @@ + 212 SCOPE_ENTER value x5 +- 212 LOAD_LOCAL(value x5) +- 212 CALL_METHOD MyException.message (dynamic) +- 212 STORE_LOCAL(value message) +- 212 SCOPE_ENTER value message + 213 LOAD_MODULE object Predef +- 213 LOAD_LOCAL(value message) ++ ? LOAD_LOCAL(value x5) ++ 213 CALL_METHOD MyException.message (dynamic) + 213 CALL_METHOD scala.Predef.println (dynamic) +@@ -1460,3 +1544,3 @@ + startBlock: 1 +- blocks: [1,2,3,4,5,7] ++ blocks: [1,2,3,4,5,7,8] + +@@ -1484,4 +1568,11 @@ + 58 CALL_METHOD java.lang.IllegalArgumentException.<init> (static-instance) +- 58 THROW(IllegalArgumentException) ++ ? STORE_LOCAL(value e) ++ ? JUMP 8 + ++ 8: ++ 62 LOAD_MODULE object Predef ++ 62 CONSTANT("RuntimeException") ++ 62 CALL_METHOD scala.Predef.println (dynamic) ++ 62 JUMP 2 ++ + 7: +@@ -1533,3 +1624,3 @@ + startBlock: 1 +- blocks: [1,3,4] ++ blocks: [1,3,4,5] + +@@ -1553,4 +1644,9 @@ + 229 CALL_METHOD MyException.<init> (static-instance) +- 229 THROW(MyException) ++ ? JUMP 5 + ++ 5: ++ ? LOAD_LOCAL(variable monitor1) ++ 228 MONITOR_EXIT ++ 228 THROW(Throwable) ++ + 3: +@@ -1559,3 +1655,3 @@ + 228 MONITOR_EXIT +- ? THROW(Throwable) ++ 228 THROW(Throwable) + +@@ -1587,5 +1683,5 @@ + def main(args: Array[String] (ARRAY[REF(class String)])): Unit { +- locals: value args, variable result, variable monitor2, variable monitorResult1 ++ locals: value exception$1, value args, variable result, variable monitor2, variable monitorResult1 + startBlock: 1 +- blocks: [1,3,4] ++ blocks: [1,3,4,5] + +@@ -1612,4 +1708,12 @@ + 245 CALL_METHOD MyException.<init> (static-instance) +- 245 THROW(MyException) ++ ? STORE_LOCAL(value exception$1) ++ ? DROP ConcatClass ++ ? LOAD_LOCAL(value exception$1) ++ ? JUMP 5 + ++ 5: ++ ? LOAD_LOCAL(variable monitor2) ++ 244 MONITOR_EXIT ++ 244 THROW(Throwable) ++ + 3: +@@ -1618,3 +1722,3 @@ + 244 MONITOR_EXIT +- ? THROW(Throwable) ++ 244 THROW(Throwable) + diff --git a/test/files/run/outertest.scala b/test/files/run/outertest.scala index 3cc96afa5b..fa0443f669 100644 --- a/test/files/run/outertest.scala +++ b/test/files/run/outertest.scala @@ -1,26 +1,57 @@ // A test for the case where the outer field of class B#J should be eliminated. -// You can verify this by running a javap on B.J + +import reflect.ClassTag + abstract class A { + abstract class I - abstract class I { + val foo = this +} +class B extends A { + class J extends I { + val bar = foo } - val foo = "foo" + type II = I + class K extends II { + val bar = foo + } + class L extends (I @annotation.tailrec) { + val bar = foo + } } -class B extends A { - class J extends I { +class C extends A { + val c: C = this + + class M extends c.I { val bar = foo } - } -object Test extends App { +object Test extends App { val b = new B - assert((new b.J).bar == b.foo) + val c0 = new C + val c = new { override val c = c0 } with C + + assert((new b.J).bar eq b) + assert((new b.K).bar eq b) + assert((new b.L).bar eq b) + assert((new c.M).bar eq c) + + def checkOuterFields[C: ClassTag](expected: Int) { + val cls = implicitly[ClassTag[C]].runtimeClass + val outerFields = cls.getDeclaredFields().filter(_.getName.contains("$outer")) + assert(outerFields.size == expected, outerFields.map(_.getName)) + } + checkOuterFields[A#I](1) // the base class must have the $outer pointer + checkOuterFields[B#J](0) // reuse parent class' $outer pointer + checkOuterFields[B#K](0) // ... through an alias + checkOuterFields[B#L](0) // ... through the annotated type + checkOuterFields[C#M](1) // different prefix, can't share. } diff --git a/test/files/run/t3994.scala b/test/files/run/t3994.scala new file mode 100644 index 0000000000..0ee1d9d966 --- /dev/null +++ b/test/files/run/t3994.scala @@ -0,0 +1,20 @@ +trait T { + trait Default { def foo = this } + object Default extends Default +} + +class Crash { // if you change this to a `trait` it keeps failing, though if it is an `object` it compiles just fine! + class Element + + /* declare this as a class, and the crash goes away */ + trait ElementOrdering extends Ordering[Element] { + def compare(a: Element, b: Element): Int = 0 + } + + implicit object ElementOrdering extends ElementOrdering +} + +object Test extends App { + (new T {}).Default + (new Crash).ElementOrdering +} diff --git a/test/files/run/t5699.check b/test/files/run/t5699.check new file mode 100755 index 0000000000..df19644ae6 --- /dev/null +++ b/test/files/run/t5699.check @@ -0,0 +1,11 @@ +[[syntax trees at end of parser]] // annodef.java +package <empty> { + object MyAnnotation extends { + def <init>() = _ + }; + class MyAnnotation extends scala.annotation.Annotation with _root_.java.lang.annotation.Annotation with scala.annotation.ClassfileAnnotation { + def <init>() = _; + def value(): String + } +} + diff --git a/test/files/run/t5699.scala b/test/files/run/t5699.scala new file mode 100755 index 0000000000..5cef67e3b1 --- /dev/null +++ b/test/files/run/t5699.scala @@ -0,0 +1,24 @@ +import scala.tools.partest.DirectTest +import scala.tools.nsc.util.BatchSourceFile + +object Test extends DirectTest { + // Java code + override def code = """ + |public @interface MyAnnotation { String value(); } + """.stripMargin + + override def extraSettings: String = "-usejavacp -Ystop-after:typer -Xprint:parser" + + override def show(): Unit = { + // redirect err to out, for logging + val prevErr = System.err + System.setErr(System.out) + compile() + System.setErr(prevErr) + } + + override def newSources(sourceCodes: String*) = { + assert(sourceCodes.size == 1) + List(new BatchSourceFile("annodef.java", sourceCodes(0))) + } +} diff --git a/test/files/run/t6146b.check b/test/files/run/t6146b.check index b664d1152a..49ff70697e 100644 --- a/test/files/run/t6146b.check +++ b/test/files/run/t6146b.check @@ -37,8 +37,15 @@ memType: (sub: u.Type, scrut: u.Type)u.Type scala> -scala> memType(S1, fTpe) -res0: u.Type = O.X.S1.type +scala> val mt1 = memType(S1, fTpe) +mt1: u.Type = O.X.S1.type + +scala> global.typeDeconstruct.show(mt1) +res0: String = +TypeRef( + pre = SingleType(pre = ThisType(object O), object X) + TypeSymbol(class S1 extends C.this.F[T]) +) scala> memType(S2, fTpe) res1: u.Type = O.S2 diff --git a/test/files/run/t6146b.scala b/test/files/run/t6146b.scala index adcd40d2ee..e63709aa9d 100644 --- a/test/files/run/t6146b.scala +++ b/test/files/run/t6146b.scala @@ -31,7 +31,8 @@ val fTpe = typeOf[O.type].decl(newTermName("foo")).paramss.head.head.tpe def memType(sub: Type, scrut: Type): Type = nestedMemberType(sub.typeSymbol, scrut.prefix, scrut.typeSymbol.owner) -memType(S1, fTpe) +val mt1 = memType(S1, fTpe) +global.typeDeconstruct.show(mt1) memType(S2, fTpe) memType(S3, fTpe) memType(S4, fTpe) diff --git a/test/files/run/t6223.scala b/test/files/run/t6223.scala index fb176e32e6..0996ea1c45 100644 --- a/test/files/run/t6223.scala +++ b/test/files/run/t6223.scala @@ -5,7 +5,7 @@ class Foo[@specialized(Int) A](a:A) { object Test { def main(args:Array[String]) { val f = new Foo(333) - val ms = f.getClass().getDeclaredMethods().sortBy(_.getName) - ms.foreach(m => println(m.getName)) + val ms = f.getClass().getDeclaredMethods().map(_.getName).sorted + ms.foreach(println) } } diff --git a/test/files/run/t6387.check b/test/files/run/t6387.check new file mode 100644 index 0000000000..83b33d238d --- /dev/null +++ b/test/files/run/t6387.check @@ -0,0 +1 @@ +1000 diff --git a/test/files/run/t6387.scala b/test/files/run/t6387.scala new file mode 100644 index 0000000000..bbebb5f511 --- /dev/null +++ b/test/files/run/t6387.scala @@ -0,0 +1,16 @@ +trait A { + def foo: Long +} + +object Test { + def a(): A = new A { + var foo: Long = 1000L + + val test = () => { + foo = 28 + } + } + def main(args: Array[String]) { + println(a().foo) + } +} diff --git a/test/files/run/t7242.scala b/test/files/run/t7242.scala new file mode 100644 index 0000000000..c995336144 --- /dev/null +++ b/test/files/run/t7242.scala @@ -0,0 +1,71 @@ +class CrashTest { + def foo = () + trait CrashTestTable { + def cols = foo + } + // This was leading to a class between the mixed in + // outer accessor and the outer accessor of this object. + object CrashTestTable extends CrashTestTable { + foo + cols + } +} + +class CrashTest1 { + def foo = () + class CrashTestTable { + def cols = foo + } + object CrashTestTable extends CrashTestTable { + foo + cols + } +} + +class CrashTest2 { + def foo = () + trait CrashTestTable { + def cols = foo + } + object Obj extends CrashTestTable { + foo + cols + } +} + +class CrashTest3 { + def foo = () + + def meth() { + trait CrashTestTable { + def cols = foo + } + object Obj extends CrashTestTable { + foo + cols + } + Obj + } +} + +object Test extends App { + { + val c = new CrashTest + c.CrashTestTable + } + + { + val c = new CrashTest1 + c.CrashTestTable + } + + { + val c = new CrashTest2 + c.Obj + } + + { + val c = new CrashTest3 + c.meth() + } +} diff --git a/test/files/run/t7246.check b/test/files/run/t7246.check new file mode 100755 index 0000000000..ce01362503 --- /dev/null +++ b/test/files/run/t7246.check @@ -0,0 +1 @@ +hello diff --git a/test/files/run/t7246/Outer.java b/test/files/run/t7246/Outer.java new file mode 100755 index 0000000000..163276fb3b --- /dev/null +++ b/test/files/run/t7246/Outer.java @@ -0,0 +1,4 @@ +public class Outer { + public class Inner { + } +}
\ No newline at end of file diff --git a/test/files/run/t7246/Test.scala b/test/files/run/t7246/Test.scala new file mode 100755 index 0000000000..9f23ca8f3a --- /dev/null +++ b/test/files/run/t7246/Test.scala @@ -0,0 +1,16 @@ +object Test extends App { + + val so = new SubOuter + val si = new so.SubInner + println(si.bar) +} + +class SubOuter extends Outer { + + val foo = "hello" + + class SubInner extends Inner { + def bar = foo + } + +}
\ No newline at end of file diff --git a/test/files/run/t7246b.check b/test/files/run/t7246b.check new file mode 100755 index 0000000000..5073bd8617 --- /dev/null +++ b/test/files/run/t7246b.check @@ -0,0 +1,2 @@ +base +sub diff --git a/test/files/run/t7246b/Base.scala b/test/files/run/t7246b/Base.scala new file mode 100755 index 0000000000..4e71d3313d --- /dev/null +++ b/test/files/run/t7246b/Base.scala @@ -0,0 +1,7 @@ +class Base { + val baseOuter = "base" + + class BaseInner { + val baseInner = baseOuter + } +} diff --git a/test/files/run/t7246b/Outer.java b/test/files/run/t7246b/Outer.java new file mode 100755 index 0000000000..53a79316ef --- /dev/null +++ b/test/files/run/t7246b/Outer.java @@ -0,0 +1,4 @@ +public class Outer extends Base { + public class Inner extends BaseInner { + } +}
\ No newline at end of file diff --git a/test/files/run/t7246b/Test.scala b/test/files/run/t7246b/Test.scala new file mode 100755 index 0000000000..f0982ea8d0 --- /dev/null +++ b/test/files/run/t7246b/Test.scala @@ -0,0 +1,14 @@ +object Test extends App { + + val so = new SubOuter + val si = new so.SubInner + println(si.baseInner) + println(si.subInner) +} + +class SubOuter extends Outer { + val subOuter = "sub" + class SubInner extends Inner { + def subInner = subOuter + } +} diff --git a/test/files/run/t7249.check b/test/files/run/t7249.check new file mode 100644 index 0000000000..7777e0a5a2 --- /dev/null +++ b/test/files/run/t7249.check @@ -0,0 +1 @@ +Yup! diff --git a/test/files/run/t7249.scala b/test/files/run/t7249.scala new file mode 100644 index 0000000000..375df5c3ad --- /dev/null +++ b/test/files/run/t7249.scala @@ -0,0 +1,7 @@ +object Test extends App { + def bnToLambda(s: => String): () => String = () => s + var x: () => String = () => sys.error("Nope") + val y = bnToLambda { x() } + x = () => "Yup!" + println(y()) +} diff --git a/test/files/run/t7290.scala b/test/files/run/t7290.scala new file mode 100644 index 0000000000..01f7e8f68e --- /dev/null +++ b/test/files/run/t7290.scala @@ -0,0 +1,9 @@ +object Test extends App { + val y = (0: Int) match { + case 1 => 1 + case 0 | 0 => 0 + case 2 | 2 | 2 | 3 | 2 | 3 => 0 + case _ => -1 + } + assert(y == 0, y) +} diff --git a/test/files/run/test-cpp.check b/test/files/run/test-cpp.check index bfea438c60..13f4c64be3 100644 --- a/test/files/run/test-cpp.check +++ b/test/files/run/test-cpp.check @@ -1,65 +1,81 @@ -37c37 -< locals: value args, value x, value y ---- -> locals: value args -42,43d41 -< 52 CONSTANT(2) -< 52 STORE_LOCAL(value x) -45,46d42 -< 53 LOAD_LOCAL(value x) -< 53 STORE_LOCAL(value y) -49c45 -< 54 LOAD_LOCAL(value y) ---- -> 54 CONSTANT(2) -92c88 -< locals: value args, value x, value y ---- -> locals: value args, value x -101,102d96 -< 82 LOAD_LOCAL(value x) -< 82 STORE_LOCAL(value y) -105c99 -< 83 LOAD_LOCAL(value y) ---- -> 83 LOAD_LOCAL(value x) -135c129 -< locals: value args, value x, value y ---- -> locals: value args -140,141d133 -< 66 THIS(TestAliasChainDerefThis) -< 66 STORE_LOCAL(value x) -143,144d134 -< 67 LOAD_LOCAL(value x) -< 67 STORE_LOCAL(value y) -147c137 -< 68 LOAD_LOCAL(value y) ---- -> 68 THIS(Object) -176c166 -< locals: value x, value y ---- -> locals: value x -181,182d170 -< 29 LOAD_LOCAL(value x) -< 29 STORE_LOCAL(value y) -185c173 -< 30 LOAD_LOCAL(value y) ---- -> 30 LOAD_LOCAL(value x) -223,224d210 -< 97 LOAD_LOCAL(variable x) -< 97 STORE_LOCAL(variable y) -227c213 -< 98 LOAD_LOCAL(variable y) ---- -> 98 LOAD_LOCAL(variable x) -233,234d218 -< 101 LOAD_LOCAL(variable y) -< 101 STORE_LOCAL(variable x) -236c220 -< 102 LOAD_LOCAL(variable x) ---- -> 102 LOAD_LOCAL(variable y) - +--- a ++++ b +@@ -36,3 +36,3 @@ + def main(args: Array[String] (ARRAY[REF(class String)])): Unit { +- locals: value args, value x, value y ++ locals: value args + startBlock: 1 +@@ -41,10 +41,6 @@ + 1: +- 52 CONSTANT(2) +- 52 STORE_LOCAL(value x) + 52 SCOPE_ENTER value x +- 53 LOAD_LOCAL(value x) +- 53 STORE_LOCAL(value y) + 53 SCOPE_ENTER value y + 54 LOAD_MODULE object Predef +- 54 LOAD_LOCAL(value y) ++ 54 CONSTANT(2) + 54 BOX INT +@@ -91,3 +87,3 @@ + def main(args: Array[String] (ARRAY[REF(class String)])): Unit { +- locals: value args, value x, value y ++ locals: value args, value x + startBlock: 1 +@@ -100,7 +96,5 @@ + 81 SCOPE_ENTER value x +- 82 LOAD_LOCAL(value x) +- 82 STORE_LOCAL(value y) + 82 SCOPE_ENTER value y + 83 LOAD_MODULE object Predef +- 83 LOAD_LOCAL(value y) ++ 83 LOAD_LOCAL(value x) + 83 BOX INT +@@ -134,3 +128,3 @@ + def main(args: Array[String] (ARRAY[REF(class String)])): Unit { +- locals: value args, value x, value y ++ locals: value args + startBlock: 1 +@@ -139,10 +133,6 @@ + 1: +- 66 THIS(TestAliasChainDerefThis) +- 66 STORE_LOCAL(value x) + 66 SCOPE_ENTER value x +- 67 LOAD_LOCAL(value x) +- 67 STORE_LOCAL(value y) + 67 SCOPE_ENTER value y + 68 LOAD_MODULE object Predef +- 68 LOAD_LOCAL(value y) ++ 68 THIS(Object) + 68 CALL_METHOD scala.Predef.println (dynamic) +@@ -175,3 +165,3 @@ + def test(x: Int (INT)): Unit { +- locals: value x, value y ++ locals: value x + startBlock: 1 +@@ -180,7 +170,5 @@ + 1: +- 29 LOAD_LOCAL(value x) +- 29 STORE_LOCAL(value y) + 29 SCOPE_ENTER value y + 30 LOAD_MODULE object Predef +- 30 LOAD_LOCAL(value y) ++ 30 LOAD_LOCAL(value x) + 30 BOX INT +@@ -222,7 +210,5 @@ + 96 SCOPE_ENTER variable x +- 97 LOAD_LOCAL(variable x) +- 97 STORE_LOCAL(variable y) + 97 SCOPE_ENTER variable y + 98 LOAD_MODULE object Predef +- 98 LOAD_LOCAL(variable y) ++ 98 LOAD_LOCAL(variable x) + 98 BOX INT +@@ -232,6 +218,4 @@ + 100 STORE_LOCAL(variable y) +- 101 LOAD_LOCAL(variable y) +- 101 STORE_LOCAL(variable x) + 102 LOAD_MODULE object Predef +- 102 LOAD_LOCAL(variable x) ++ 102 LOAD_LOCAL(variable y) + 102 BOX INT diff --git a/test/partest b/test/partest index 9b0ab02fdc..ec66f5c048 100755 --- a/test/partest +++ b/test/partest @@ -53,8 +53,8 @@ if [ -z "$EXT_CLASSPATH" ] ; then fi done elif [ -f "$SCALA_HOME/build/pack/lib/scala-partest.jar" ] ; then - for lib in `echo "partest library reflect compiler"`; do - ext="$SCALA_HOME/build/pack/lib/scala-$lib.jar" + for lib in `echo "scala-partest scala-library scala-reflect scala-compiler diffutils"`; do + ext="$SCALA_HOME/build/pack/lib/$lib.jar" if [ -z "$EXT_CLASSPATH" ] ; then EXT_CLASSPATH="$ext" else diff --git a/test/scaladoc/run/SI-6580.check b/test/scaladoc/run/SI-6580.check new file mode 100644 index 0000000000..2fb6ec3258 --- /dev/null +++ b/test/scaladoc/run/SI-6580.check @@ -0,0 +1,11 @@ +Chain(List(Chain(List(Text(Here z(1) is defined as follows:), Text( +), HtmlTag(<br>), Text( +), Text( ), HtmlTag(<img src='http://example.com/fig1.png'>), Text( +), HtmlTag(<br>), Text( +), Text(plus z(1) times), Text( +), HtmlTag(<br>), Text( +), Text( ), HtmlTag(<img src='http://example.com/fig2.png'>), Text( +), HtmlTag(<br>), Text( +), Text(equals QL of something +))))) +Done. diff --git a/test/scaladoc/run/SI-6580.scala b/test/scaladoc/run/SI-6580.scala new file mode 100644 index 0000000000..c544138f44 --- /dev/null +++ b/test/scaladoc/run/SI-6580.scala @@ -0,0 +1,32 @@ +import scala.tools.nsc.doc +import scala.tools.nsc.doc.model._ +import scala.tools.nsc.doc.html.page.{Index, ReferenceIndex} +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + override def scaladocSettings = "" + override def code = """ + + object Test { + /** Here z(1) is defined as follows: + * <br> + * <img src='http://example.com/fig1.png'> + * <br> + * plus z(1) times + * <br> + * <img src='http://example.com/fig2.png'> + * <br> + * equals QL of something + */ + def f = 1 + } + + """ + + def testModel(rootPackage: Package) { + import access._ + + val f = rootPackage._object("Test")._method("f") + println(f.comment.get.short) + } +} |