diff options
861 files changed, 13723 insertions, 4844 deletions
@@ -10,6 +10,7 @@ Aleksandar Prokopec <aleksandar.prokopec@epfl.ch> <aleksandar@lampmac14.epfl.ch> Aleksandar Prokopec <aleksandar.prokopec@epfl.ch> <axel22@gmail.com> Alex Cruise <alex@cluonflux.com> Alex Cruise <alex@cluonflux.com> <alex@metaforsoftware.com> +A. P. Marki <som.snytt@gmail.com> Antonio Cunei <antonio.cunei@typesafe.com> Antonio Cunei <antonio.cunei@typesafe.com> <antonio.cunei@epfl.ch> Buraq Emir <buraq@epfl.ch> @@ -71,5 +72,6 @@ Unknown Committer <lost.soul@typesafe.com> <USER@epfl.ch> Unknown Committer <lost.soul@typesafe.com> <noreply@epfl.ch> Viktor Klang <viktor.klang@gmail.com> Vincent Cremet <cremet@epfl.ch> +Vladimir Nikolaev <vladimir.nikolaev9@gmail.com> Vojin Jovanovic <vojin.jovanovic@epfl.ch> Vojin Jovanovic <vojin.jovanovic@epfl.ch> <gvojin@gmail.com> diff --git a/build-ant-macros.xml b/build-ant-macros.xml index 593f93b784..458d1014c2 100644 --- a/build-ant-macros.xml +++ b/build-ant-macros.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<project name="build-support"> +<project name="build-support" xmlns:artifact="urn:maven-artifact-ant"> <description> Macros for Scala's ant build </description> <macrodef name="optimized"> @@ -23,15 +23,35 @@ </sequential> </macrodef> + <!-- Set a property @{name}.cross to the actual cross suffix that should be + used when resolving the module "@{name}". If the (user-supplied) + @{name}.cross.suffix property exists then use that value, otherwise use + "_${scala.binary.version}". --> + <macrodef name="prepareCross"> + <attribute name="name" /> + <sequential> + <if> + <isset property="@{name}.cross.suffix" /> + <then> + <property name="@{name}.cross" value="${@{name}.cross.suffix}" /> + </then> + <else> + <property name="@{name}.cross" value="_${scala.binary.version}" /> + </else> + </if> + </sequential> + </macrodef> + <!-- Set property named @{name} to the jar resolved as @{jar}_${scala.binary.version}:jar. @{jar}_${scala.binary.version} must be a maven dependency. --> <macrodef name="propertyForCrossedArtifact"> <attribute name="name"/> <attribute name="jar"/> + <attribute name="suffix" default="${@{name}.cross}"/> <sequential> - <readProperty name="@{name}" property="@{jar}_${scala.binary.version}:jar"/> - <readProperty name="@{name}-sources" property="@{jar}_${scala.binary.version}:java-source:sources"/> - <readProperty name="@{name}-javadoc" property="@{jar}_${scala.binary.version}:java-source:javadoc"/> + <readProperty name="@{name}" property="@{jar}@{suffix}:jar"/> + <readProperty name="@{name}-sources" property="@{jar}@{suffix}:java-source:sources"/> + <readProperty name="@{name}-javadoc" property="@{jar}@{suffix}:java-source:javadoc"/> </sequential> </macrodef> @@ -451,8 +471,8 @@ <attribute name="project"/> <sequential> <local name="artifact-base"/> - <property name="artifact-base" value="${maven-base}/${@{project}.dir}${@{project}.name}/${@{project}.name}"/> - <mkdir dir="${maven-base}/${@{project}.dir}${@{project}.name}"/> + <property name="artifact-base" value="${dist.maven}/${@{project}.dir}${@{project}.name}/${@{project}.name}"/> + <mkdir dir="${dist.maven}/${@{project}.dir}${@{project}.name}"/> <copy tofile="${artifact-base}.jar" file="${build-osgi.dir}/org.scala-lang.${@{project}.package}${@{project}.name}${@{project}.namesuffix}.jar" overwrite="true"/> <copy tofile="${artifact-base}-src.jar" file="${build-osgi.dir}/${@{project}.name}-src.jar" overwrite="true"/> <copy tofile="${artifact-base}-pom.xml" file="${src.dir}/build/maven/${@{project}.dir}/${@{project}.name}-pom.xml" overwrite="true"/> @@ -469,7 +489,8 @@ </sequential> </macrodef> - + <!-- TODO inline maven-deploy.xml's macrodefs, remove maven-deploy.xml --> + <include file="src/build/maven/maven-deploy.xml" as="deploy-macros"/> <macrodef name="testSuite"> <attribute name="dir" default="${partest.dir}"/> @@ -4,17 +4,14 @@ xmlns:artifact="urn:maven-artifact-ant" xmlns:rsel="antlib:org.apache.tools.ant.types.resources.selectors"> <include file="build-ant-macros.xml" as="macros"/> - <include file="src/build/maven/maven-deploy.xml" as="maven-deploy"/> <description> SuperSabbus for Scala core, builds the scala library and compiler. It can also package it as a simple distribution, tests it for stable bootstrapping and against the Scala test suite. </description> <!-- HINTS - - for faster builds, have a build.properties in the same directory as build.xml that says: locker.skip=1 - --> <!-- USAGE FROM JENKINS SCRIPTS IS (CURRENTLY) AS FOLLOWS: @@ -27,11 +24,14 @@ antArgs tend to be: scalacArgs examples: "-Dscalac.args=\"-Yrangepos\" -Dpartest.scalac_opts=\"-Yrangepos\"" -targets exercised: - deploy-core.snapshot publish-opt-nodocs distpack-maven-opt nightly locker.done build build-opt test.suite test.continuations.suite test.scaladoc +supported/exercised targets + to publish: nightly publish-opt-nodocs + to build: build build-opt locker.done + to run tests: test.suite test.scaladoc + +DO NOT RELY ON ANY OTHER TARGETS (ok, you're probably ok assuming the ones defined in the first 100 lines of this file) -NOTE: after distpack-maven-opt, it is expected there's a build file in dists/maven/latest that defines targets deploy and deploy.local -TODO: get rid of this separate step +NOTE: dists/maven/latest/build.xml will soon disappear; call `publish` in this build instead --> <!-- To use Zinc with the ant build: @@ -70,7 +70,6 @@ TODO: <!-- packaging --> <target name="distpack" depends="pack-archives.done, pack-maven.done"/> <target name="distpack-maven" depends="pack-maven.done"/> - <target name="distpack-opt" description="Builds an optimised distribution."> <optimized name="distpack"/></target> <target name="distpack-maven-opt" description="Builds an optimised maven distribution."><optimized name="distpack-maven"/></target> @@ -81,7 +80,6 @@ TODO: <param name="scalac.args.optimise" value="-optimise"/> </antcall> </target> - <target name="publish-core-opt-nodocs" description="Builds an untested, undocumented optimised core (library/reflect/compiler) and publishes to maven."> <antcall target="publish-core"> <param name="docs.skip" value="1"/> @@ -93,24 +91,22 @@ TODO: <param name="docs.skip" value="1"/> </antcall> </target> - <target name="all.done" depends="test.done, distpack"/> - <target name="nightly-nopt" depends="all.done"/> <target name="nightly"><optimized name="nightly-nopt"/></target> - <target name="nightly.checkall"> <antcall target="nightly-nopt"> <param name="partest.scalac_opts" value="-Ycheck:all"/></antcall></target> + <!-- prefer the sbt names, but the dotted names are used in jenkins; + rename there first before dropping the dotted ones --> + <target name="publish-local" depends="publish.local"/> + <target name="publish-signed" depends="publish.signed"/> + <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."/> - <target name="test.continuations.suite"> - <echo message="DEPRECATED: the continuations have moved to https://github.com/scala/scala-continuations"/> - </target> - <!-- =========================================================================== PROPERTIES ============================================================================ --> @@ -120,7 +116,7 @@ TODO: <property name="build.sysclasspath" value="ignore"/> <!-- Defines the repository layout --> - <property name="docs.dir" value="${basedir}/docs"/> + <property name="doc.dir" value="${basedir}/doc"/> <property name="lib.dir" value="${basedir}/lib"/> <property name="src.dir" value="${basedir}/src"/> <property name="partest.dir" value="${basedir}/test"/> @@ -151,6 +147,7 @@ TODO: <property name="build-locker.dir" value="${build.dir}/locker"/> <property name="build-quick.dir" value="${build.dir}/quick"/> <property name="build-pack.dir" value="${build.dir}/pack"/> + <property name="build-manual.dir" value="${build.dir}/manual"/> <property name="build-osgi.dir" value="${build.dir}/osgi"/> <property name="build-junit.dir" value="${build.dir}/junit"/> <property name="build-strap.dir" value="${build.dir}/strap"/> @@ -279,6 +276,16 @@ TODO: <artifact:remoteRepository id="extra-repo" url="${extra.repo.url}"/> + <!-- prepare, for each of the names below, the property "@{name}.cross", set to the + necessary cross suffix (usually something like "_2.11.0-M6". --> + <prepareCross name="scala-xml" /> + <prepareCross name="scala-parser-combinators" /> + <prepareCross name="scala-continuations-plugin" /> + <prepareCross name="scala-continuations-library"/> + <prepareCross name="scala-swing"/> + <prepareCross name="partest"/> + <prepareCross name="scalacheck"/> + <!-- TODO: delay until absolutely necessary to allow minimal build, also move out partest dependency from scaladoc --> <artifact:dependencies pathId="partest.classpath" filesetId="partest.fileset" versionsId="partest.versions"> <!-- uncomment the following if you're deploying your own partest locally --> @@ -287,13 +294,13 @@ TODO: (we don't distribute partest with Scala, so the risk of sonatype and maven being out of synch is irrelevant): --> <artifact:remoteRepository refid="extra-repo"/> - <dependency groupId="org.scala-lang.modules" artifactId="scala-partest_${scala.binary.version}" version="${partest.version.number}" /> + <dependency groupId="org.scala-lang.modules" artifactId="scala-partest${partest.cross}" version="${partest.version.number}" /> </artifact:dependencies> <copy-deps project="partest"/> <artifact:dependencies pathId="scalacheck.classpath" filesetId="scalacheck.fileset" versionsId="scalacheck.versions"> <artifact:remoteRepository refid="extra-repo"/> - <dependency groupId="org.scalacheck" artifactId="scalacheck_${scala.binary.version}" version="${scalacheck.version.number}" /> + <dependency groupId="org.scalacheck" artifactId="scalacheck${scalacheck.cross}" version="${scalacheck.version.number}" /> </artifact:dependencies> <artifact:dependencies pathId="repl.deps.classpath" filesetId="repl.fileset" versionsId="repl.deps.versions"> @@ -305,11 +312,11 @@ TODO: must specify sourcesFilesetId, javadocFilesetId to download these types of artifacts --> <artifact:dependencies pathId="external-modules.deps.classpath" sourcesFilesetId="external-modules.sources.fileset" javadocFilesetId="external-modules.javadoc.fileset"> <artifact:remoteRepository refid="extra-repo"/> - <dependency groupId="org.scala-lang.modules" artifactId="scala-xml_${scala.binary.version}" version="${scala-xml.version.number}"/> - <dependency groupId="org.scala-lang.modules" artifactId="scala-parser-combinators_${scala.binary.version}" version="${scala-parser-combinators.version.number}"/> - <dependency groupId="org.scala-lang.plugins" artifactId="scala-continuations-plugin_${scala.binary.version}" version="${scala-continuations-plugin.version.number}"/> - <dependency groupId="org.scala-lang.plugins" artifactId="scala-continuations-library_${scala.binary.version}" version="${scala-continuations-library.version.number}"/> - <dependency groupId="org.scala-lang.modules" artifactId="scala-swing_${scala.binary.version}" version="${scala-swing.version.number}"/> + <dependency groupId="org.scala-lang.modules" artifactId="scala-xml${scala-xml.cross}" version="${scala-xml.version.number}"/> + <dependency groupId="org.scala-lang.modules" artifactId="scala-parser-combinators${scala-parser-combinators.cross}" version="${scala-parser-combinators.version.number}"/> + <dependency groupId="org.scala-lang.plugins" artifactId="scala-continuations-plugin${scala-continuations-plugin.cross}" version="${scala-continuations-plugin.version.number}"/> + <dependency groupId="org.scala-lang.plugins" artifactId="scala-continuations-library${scala-continuations-library.cross}" version="${scala-continuations-library.version.number}"/> + <dependency groupId="org.scala-lang.modules" artifactId="scala-swing${scala-swing.cross}" version="${scala-swing.version.number}"/> </artifact:dependencies> <!-- External modules, excluding the core --> @@ -401,14 +408,25 @@ TODO: <property name="version.number" value="${version.major}.${version.minor}.${version.patch}${version.suffix}-${git.commit.date}-${git.commit.sha}"/> </else></if> + <!-- some default in case something went wrong getting the revision --> + <property name="version.number" value="-unknown-"/> + + <property name="dist.name" value="scala-${version.number}"/> + <property name="dist.dir" value="${dists.dir}/${dist.name}"/> + <property name="dist.maven" value="${dists.dir}/maven/${version.number}"/> + <condition property="has.java6"> <equals arg1="${ant.java.version}" arg2="1.6"/> </condition> <condition property="has.java7"> <equals arg1="${ant.java.version}" arg2="1.7"/> </condition> + <condition property="has.java8"> + <equals arg1="${ant.java.version}" arg2="1.8"/> + </condition> <condition property="has.unsupported.jdk"> <not><or> + <isset property="has.java8" /> <isset property="has.java7" /> <isset property="has.java6" /> </or></not> @@ -445,10 +463,6 @@ TODO: <format property="short" pattern="yyyyMMddHHmmss"/> </tstamp> - <!-- some default in case something went wrong getting the revision --> - <property name="version.number" value="-unknown-"/> - <property name="init.avail" value="yes"/> - <!-- Local libs (developer use.) --> <mkdir dir="${lib-extra.dir}"/> @@ -1559,8 +1573,36 @@ TODO: </staged-docs> </target> - <target name="docs.man" depends="docs.start"> - <staged-uptodate stage="docs" project="manual"> + <target name="docs.core" depends="docs.lib, docs.reflect, docs.comp" unless="docs.skip"/> + <!-- TODO modularize compiler: docs.scaladoc, docs.interactive, --> + <target name="docs.done" depends="docs.core, docs.actors, docs.scalap" unless="docs.skip"/> + +<!-- =========================================================================== + DISTRIBUTION +============================================================================ --> + <!-- bin/ --> + <target name="dist.bin" depends="pack.bin"> + <mkdir dir="${dist.dir}/bin"/> + <copy toDir="${dist.dir}/bin" overwrite="true"> + <fileset dir="${build-pack.dir}/bin"/> + </copy> + <chmod perm="ugo+rx" file="${dist.dir}/bin/scala"/> + <chmod perm="ugo+rx" file="${dist.dir}/bin/scalac"/> + <chmod perm="ugo+rx" file="${dist.dir}/bin/scaladoc"/> + <chmod perm="ugo+rx" file="${dist.dir}/bin/fsc"/> + <chmod perm="ugo+rx" file="${dist.dir}/bin/scalap"/> + </target> + + <!-- doc/ and man/ --> + <target name="dist.doc" depends="scaladoc.task" unless="docs.skip"> <!-- depends on scaladoc.task for scalac taskdef --> + <mkdir dir="${dist.dir}/doc"/> + <copy toDir="${dist.dir}/doc" overwrite="true"> + <fileset dir="${doc.dir}"/> + </copy> + + <mkdir dir="${dist.dir}/doc/tools"/> + <mkdir dir="${dist.dir}/man/man1"/> + <staged-uptodate stage="manual" project="manual"> <check><srcfiles dir="${src.dir}/manual"/></check> <do> <mkdir dir="${build.dir}/manmaker/classes"/> @@ -1570,44 +1612,33 @@ TODO: srcdir="${src.dir}/manual" includes="**/*.scala" addparams="${scalac.args.all} -language:implicitConversions"/> - <mkdir dir="${build-docs.dir}/manual/man/man1"/> - <mkdir dir="${build-docs.dir}/manual/html"/> - <mkdir dir="${build-docs.dir}/manual/genman/man1"/> + <mkdir dir="${build-manual.dir}/genman/man1"/> <taskdef name="genman" classname="scala.tools.docutil.ManMaker" classpathref="manual.build.path"/> <genman command="fsc, scala, scalac, scaladoc, scalap" - htmlout="${build-docs.dir}/manual/html" - manout="${build-docs.dir}/manual/genman"/> - <!-- On Windows source and target files can't be the same ! --> - <fixcrlf - srcdir="${build-docs.dir}/manual/genman" - destdir="${build-docs.dir}/manual/man" - eol="unix" includes="**/*.1"/> - <copy todir="${build-docs.dir}/manual/html" overwrite="true"> - <fileset dir="${src.dir}/manual/scala/tools/docutil/resources"> - <include name="**/*.html"/> - <include name="**/*.css"/> - <include name="**/*.gif"/> - <include name="**/*.png"/> - </fileset> - </copy> + htmlout="${dist.dir}/doc/tools" + manout="${build-manual.dir}/genman"/> </do> </staged-uptodate> - </target> - - <target name="docs.core" depends="docs.lib, docs.reflect, docs.comp" unless="docs.skip"/> - <!-- TODO modularize compiler: docs.scaladoc, docs.interactive, --> - <target name="docs.done" depends="docs.core, docs.actors, docs.scalap" unless="docs.skip"/> - -<!-- =========================================================================== - DISTRIBUTION -============================================================================ --> - <target name="dist.base" depends="osgi.done"> - <property name="dist.name" value="scala-${version.number}"/> - <property name="dist.dir" value="${dists.dir}/${dist.name}"/> + <!-- On Windows source and target files can't be the same ! --> + <fixcrlf + srcdir="${build-manual.dir}/genman" + destdir="${dist.dir}/man" + eol="unix" includes="**/*.1"/> + <copy todir="${dist.dir}/doc/tools" overwrite="true"> + <fileset dir="${src.dir}/manual/scala/tools/docutil/resources"> + <include name="**/*.html"/> + <include name="**/*.css"/> + <include name="**/*.gif"/> + <include name="**/*.png"/> + </fileset> + </copy> + </target> + <!-- lib/ and src/ (jars: classes and sources) --> + <target name="dist.lib" depends="osgi.done"> <mkdir dir="${dist.dir}/lib"/> <mkdir dir="${dist.dir}/src"/> @@ -1637,35 +1668,16 @@ TODO: </fileset> </copy> <jar whenmanifestonly="fail" destfile="${dist.dir}/src/scalap-src.jar" basedir="${src.dir}/scalap"/> - - <mkdir dir="${dist.dir}/bin"/> - <copy toDir="${dist.dir}/bin" overwrite="true"> - <fileset dir="${build-pack.dir}/bin"/> - </copy> - <chmod perm="ugo+rx" file="${dist.dir}/bin/scala"/> - <chmod perm="ugo+rx" file="${dist.dir}/bin/scalac"/> - <chmod perm="ugo+rx" file="${dist.dir}/bin/scaladoc"/> - <chmod perm="ugo+rx" file="${dist.dir}/bin/fsc"/> - <chmod perm="ugo+rx" file="${dist.dir}/bin/scalap"/> </target> - - <target name="dist.doc" depends="dist.base, docs.done"> - <mkdir dir="${dist.dir}/doc"/> - <mkdir dir="${dist.dir}/doc/licenses"/> - <mkdir dir="${dist.dir}/doc/tools"/> - <copy file="${docs.dir}/LICENSE" toDir="${dist.dir}/doc" overwrite="true"/> - <copy file="${docs.dir}/README" toDir="${dist.dir}/doc" overwrite="true"/> - <copy toDir="${dist.dir}/doc/licenses" overwrite="true"> - <fileset dir="${docs.dir}/licenses"/> - </copy> - + <!-- api/ (scaladoc) --> + <target name="dist.api" depends="docs.done" unless="docs.skip"> <mkdir dir="${dist.dir}/api"/> <copy toDir="${dist.dir}/api" overwrite="true"> <fileset dir="${build-docs.dir}/library"/> </copy> - <copy toDir="${dist.dir}/doc/api" overwrite="true" flatten="true"> + <copy toDir="${dist.dir}/api" overwrite="true" flatten="true"> <file file="${scala-xml-javadoc}"/> <file file="${scala-parser-combinators-javadoc}"/> <file file="${scala-continuations-plugin-javadoc}"/> @@ -1674,20 +1686,7 @@ TODO: </copy> </target> - - <target name="dist.man" depends="dist.base, docs.man"> - <mkdir dir="${dist.dir}/man"/> - <copy toDir="${dist.dir}/man" overwrite="true"> - <fileset dir="${build-docs.dir}/manual/man"/> - </copy> - <mkdir dir="${dist.dir}/doc/scala-devel-docs/tools"/> - <copy toDir="${dist.dir}/doc/scala-devel-docs/tools" overwrite="true"> - <fileset dir="${build-docs.dir}/manual/html"/> - </copy> - </target> - - - <target name="dist.partial" depends="dist.base"> + <target name="dist.partial" depends="dist.lib, dist.bin, dist.doc"> <if><not><os family="windows"/></not><then> <symlink link="${dists.dir}/latest" resource="${dist.name}" overwrite="true"/> </then><else> <!-- XXX THIS PROBABLY DOES NOT WORK: copying must happen last during dist.done! is this guaranteed? --> @@ -1695,12 +1694,13 @@ TODO: </else></if> </target> - <target name="dist.done" depends="dist.doc, dist.man, dist.partial"/> + <target name="dist.done" depends="dist.partial, dist.api"/> <!-- =========================================================================== MAIN DISTRIBUTION PACKAGING ============================================================================ --> + <!-- TODO: get rid of this, it's redundant between maven and github --> <target name="pack-archives.done" depends="dist.done, docs.done"> <mkdir dir="${dists.dir}/archives"/> <property name="archive-base" value="${dists.dir}/archives/${dist.name}"/> @@ -1716,7 +1716,7 @@ MAIN DISTRIBUTION PACKAGING <if><not><isset property="docs.skip"/></not><then> <tarz name="${archive-base}-devel-docs"> - <tarfileset dir="${dist.dir}/doc/scala-devel-docs" prefix="${dist.name}-devel-docs"/> + <tarfileset dir="${dist.dir}/api" prefix="${dist.name}-devel-docs"/> </tarz> </then></if> @@ -1761,13 +1761,13 @@ MAIN DISTRIBUTION PACKAGING </target> <target name="pack-maven.core" depends="osgi.core, docs.core"> - <property name="maven-base" value="${dists.dir}/maven/${version.number}"/> - <mkdir dir="${maven-base}"/> - <mvn-package project="library"/> <mvn-package project="reflect"/> <mvn-package project="compiler"/> + <copy tofile="${dist.maven}/scala-library-all/scala-library-all-pom.xml" + file="${src.dir}/build/maven/scala-library-all-pom.xml" overwrite="true"/> + <!-- for replacestarr --> <if><isset property="update.starr.version"/><then> <echo message="From now on, ${maven.version.number} will be used as STARR (`build.properties`'s `starr.version` was modified)."/> @@ -1777,7 +1777,16 @@ MAIN DISTRIBUTION PACKAGING </then></if> </target> - <target name="pack-maven.base" depends="pack-maven.core, osgi.done, docs.done"> + <target name="pack-maven.dist" depends="dist.bin, dist.doc"> + <copy tofile="${dist.maven}/scala-dist/scala-dist-pom.xml" file="${src.dir}/build/maven/scala-dist-pom.xml" overwrite="true"/> + <jar whenmanifestonly="fail" destfile="${dist.maven}/scala-dist/scala-dist.jar" basedir="${dist.dir}"> + <include name="bin/" /> + <include name="doc/" /> + <include name="man/" /> + </jar> + </target> + + <target name="pack-maven.base" depends="pack-maven.core, osgi.done, docs.done, pack-maven.dist"> <!-- TODO modularize compiler <mvn-package project="interactive"/> <mvn-package project="scaladoc"/> @@ -1786,19 +1795,21 @@ MAIN DISTRIBUTION PACKAGING <mvn-package project="actors"/> <!-- don't bother fitting scalap into the mould: it will move out soon --> - <copy tofile="${maven-base}/scalap/scalap-pom.xml" file="${src.dir}/build/maven/scalap-pom.xml" overwrite="true"/> - <copy tofile="${maven-base}/scalap/scalap.jar" file="${scalap.jar}" overwrite="true"/> - <jar destfile="${maven-base}/scalap/scalap-src.jar" basedir="${src.dir}/scalap" whenmanifestonly="fail"/> + <mkdir dir="${dist.maven}"/> + <copy tofile="${dist.maven}/scalap/scalap-pom.xml" file="${src.dir}/build/maven/scalap-pom.xml" overwrite="true"/> + <copy tofile="${dist.maven}/scalap/scalap.jar" file="${scalap.jar}" overwrite="true"/> + <jar destfile="${dist.maven}/scalap/scalap-src.jar" basedir="${src.dir}/scalap" whenmanifestonly="fail"/> <if><not><isset property="docs.skip"/></not><then> - <jar destfile="${maven-base}/scalap/scalap-docs.jar" basedir="${build-docs.dir}/scalap"/> + <jar destfile="${dist.maven}/scalap/scalap-docs.jar" basedir="${build-docs.dir}/scalap"/> </then></if> </target> + <!-- TODO: remove this target and delete src/build/maven-deploy.xml --> <target name="pack-maven.done" depends="pack-maven.base"> <!-- Create dists/maven/latest alias and copy maven-deploy ant build there. --> <if><isset property="os.win"/><then> <copy todir="${dists.dir}/maven/latest" overwrite="true"> - <fileset dir="${maven-base}"/> + <fileset dir="${dist.maven}"/> </copy> </then><else> <symlink link="${dists.dir}/maven/latest" @@ -1806,17 +1817,17 @@ MAIN DISTRIBUTION PACKAGING overwrite="true"/> </else></if> <!-- copy build file and its dependencies --> - <copy todir="${maven-base}" + <copy todir="${dist.maven}" file="${lib-ant.dir}/ant-contrib.jar" overwrite="true"/> - <copy todir="${maven-base}" + <copy todir="${dist.maven}" file="${lib-ant.dir}/maven-ant-tasks-2.1.1.jar" overwrite="true"/> - <copy tofile="${maven-base}/build.xml" + <copy tofile="${dist.maven}/build.xml" file="${src.dir}/build/maven/maven-deploy.xml"/> <!-- export properties for use when deploying --> - <echoproperties destfile="${maven-base}/build.properties"/> + <echoproperties destfile="${dist.maven}/build.properties"/> </target> - <!-- keep these properties out of ${maven-base}/build.properties, dumped in pack-maven.done --> + <!-- keep these properties out of ${dist.maven}/build.properties, dumped in pack-maven.done --> <target name="init.maven" depends="init"> <property name="remote.snapshot.repository" value="https://oss.sonatype.org/content/repositories/snapshots" /> <property name="remote.release.repository" value="https://oss.sonatype.org/service/local/staging/deploy/maven2" /> @@ -1840,20 +1851,34 @@ MAIN DISTRIBUTION PACKAGING <!-- =========================================================================== MAVEN PUBLISHING ============================================================================ --> - <!-- TODO: inline maven-deploy.xml here and remove it, once jenkins jobs no longer rely on it --> - <target name="publish" depends="pack-maven.base, init.maven" description="Publishes unsigned artifacts to the maven repo."> <deploy dir="${maven-base}/"/> </target> - <target name="publish.local" depends="pack-maven.base, init.maven" description="Publishes unsigned artifacts to the local maven repo."> <deploy dir="${maven-base}/" local="true"/> </target> - <target name="publish.signed" depends="pack-maven.base, init.maven" description="Publishes signed artifacts to the remote maven repo."> <deploy dir="${maven-base}/" signed="true"/> </target> + <target name="publish" depends="pack-maven.base, init.maven" description="Publishes unsigned artifacts to the maven repo."> + <deploy /> + <deploy-pom name="scala-library-all"/> + <deploy-jar name="scala-dist"/> + </target> + + <target name="publish.local" depends="pack-maven.base, init.maven" description="Publishes unsigned artifacts to the local maven repo."> + <deploy local="true"/> + <deploy-pom name="scala-library-all" local="true"/> + <deploy-jar name="scala-dist" local="true"/> + </target> + + <target name="publish.signed" depends="pack-maven.base, init.maven" description="Publishes signed artifacts to the remote maven repo."> + <deploy signed="true"/> + <deploy-pom name="scala-library-all" signed="true"/> + <deploy-jar name="scala-dist" signed="true"/> + </target> <target name="publish-core" depends="pack-maven.core, init.maven"> - <deploy-one dir="${maven-base}/" name="scala-compiler" /> - <deploy-one dir="${maven-base}/" name="scala-library" /> - <deploy-one dir="${maven-base}/" name="scala-reflect" /> + <deploy-one name="scala-compiler" /> + <deploy-one name="scala-library" /> + <deploy-one name="scala-reflect" /> </target> + <target name="publish-core-local" depends="pack-maven.core, init.maven"> - <deploy-one dir="${maven-base}/" name="scala-compiler" local="true"/> - <deploy-one dir="${maven-base}/" name="scala-library" local="true"/> - <deploy-one dir="${maven-base}/" name="scala-reflect" local="true"/> + <deploy-one name="scala-compiler" local="true"/> + <deploy-one name="scala-library" local="true"/> + <deploy-one name="scala-reflect" local="true"/> </target> <target name="publish-core-opt" description="Builds an untested optimised core (library/reflect/compiler) and publishes to maven."> diff --git a/docs/LICENSE b/doc/LICENSE.md index 4daedef581..6b039afd68 100644 --- a/docs/LICENSE +++ b/doc/LICENSE.md @@ -11,14 +11,14 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of the EPFL nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the EPFL nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -39,18 +39,22 @@ which are also included in the `licenses/` directory: ### [Apache License](http://www.apache.org/licenses/LICENSE-2.0.html) This license is used by the following third-party libraries: + * jansi ### [BSD License](http://www.opensource.org/licenses/bsd-license.php) This license is used by the following third-party libraries: + * jline ### [BSD 3-Clause License](http://opensource.org/licenses/BSD-3-Clause) This license is used by the following third-party libraries: + * asm ### [MIT License](http://www.opensource.org/licenses/MIT) This license is used by the following third-party libraries: + * jquery * jquery-ui * jquery-layout @@ -59,5 +63,6 @@ This license is used by the following third-party libraries: ### Public Domain The following libraries are freely available in the public domain: + * forkjoin diff --git a/doc/License.rtf b/doc/License.rtf new file mode 100644 index 0000000000..62ec2d023c --- /dev/null +++ b/doc/License.rtf @@ -0,0 +1,65 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\margl1440\margr1440\vieww25140\viewh18960\viewkind0 +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural + +\f0\fs26 \cf0 Scala is licensed under the {\field{\*\fldinst{HYPERLINK "http://opensource.org/licenses/BSD-3-Clause"}}{\fldrslt BSD 3-Clause License}}.\ +\ + +\fs48 Scala License +\fs40 \ + +\fs26 Copyright (c) 2002-2013 EPFL\ +Copyright (c) 2011-2013 Typesafe, Inc.\ +All rights reserved.\ +\ +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\ + \'95 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\ + \'95 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\ + \'95 Neither the name of the EPFL nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\ +\ +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \'93AS IS\'94 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\ + +\fs52 \ + +\fs48 Other Licenses +\fs52 \ + +\fs26 This software includes projects with the following licenses, which are also included in the +\fs24 licenses/ +\fs26 directory:\ + +\fs30 \ +{\field{\*\fldinst{HYPERLINK "http://www.apache.org/licenses/LICENSE-2.0.html"}}{\fldrslt Apache License}}\ + +\fs26 This license is used by the following third-party libraries:\ + \'95 jansi\ + +\fs30 \ +{\field{\*\fldinst{HYPERLINK "http://www.opensource.org/licenses/bsd-license.php"}}{\fldrslt BSD License}}\ + +\fs26 This license is used by the following third-party libraries:\ + \'95 jline\ + +\fs30 \ +{\field{\*\fldinst{HYPERLINK "http://opensource.org/licenses/BSD-3-Clause"}}{\fldrslt BSD 3-Clause License}}\ + +\fs26 This license is used by the following third-party libraries:\ + \'95 asm\ + +\fs30 \ +{\field{\*\fldinst{HYPERLINK "http://www.opensource.org/licenses/MIT"}}{\fldrslt MIT License}}\ + +\fs26 This license is used by the following third-party libraries:\ + \'95 jquery\ + \'95 jquery-ui\ + \'95 jquery-layout\ + \'95 sizzle\ + \'95 tools tooltip\ + +\fs30 \ +Public Domain\ + +\fs26 The following libraries are freely available in the public domain:\ + \'95 forkjoin}
\ No newline at end of file diff --git a/docs/README b/doc/README index 1d5f553d2e..29f64c9fef 100644 --- a/docs/README +++ b/doc/README @@ -13,7 +13,7 @@ Scala Tools - scalac Scala compiler - fsc Scala resident compiler - scaladoc Scala API documentation generator -- scalap Scala classfile decoder +- scalap Scala classfile decoder Run the command "scalac -help" to display the list of available compiler options. diff --git a/docs/licenses/apache_jansi.txt b/doc/licenses/apache_jansi.txt index 067a5a6a34..067a5a6a34 100644 --- a/docs/licenses/apache_jansi.txt +++ b/doc/licenses/apache_jansi.txt diff --git a/docs/licenses/bsd_asm.txt b/doc/licenses/bsd_asm.txt index 8613cd33a2..8613cd33a2 100644 --- a/docs/licenses/bsd_asm.txt +++ b/doc/licenses/bsd_asm.txt diff --git a/docs/licenses/bsd_jline.txt b/doc/licenses/bsd_jline.txt index 3e5dba75da..3e5dba75da 100644 --- a/docs/licenses/bsd_jline.txt +++ b/doc/licenses/bsd_jline.txt diff --git a/docs/licenses/mit_jquery-layout.txt b/doc/licenses/mit_jquery-layout.txt index 4af6a0a4b0..4af6a0a4b0 100644 --- a/docs/licenses/mit_jquery-layout.txt +++ b/doc/licenses/mit_jquery-layout.txt diff --git a/docs/licenses/mit_jquery-ui.txt b/doc/licenses/mit_jquery-ui.txt index be226805d3..be226805d3 100644 --- a/docs/licenses/mit_jquery-ui.txt +++ b/doc/licenses/mit_jquery-ui.txt diff --git a/docs/licenses/mit_jquery.txt b/doc/licenses/mit_jquery.txt index ef2c570469..ef2c570469 100644 --- a/docs/licenses/mit_jquery.txt +++ b/doc/licenses/mit_jquery.txt diff --git a/docs/licenses/mit_sizzle.txt b/doc/licenses/mit_sizzle.txt index d81d30aa0f..d81d30aa0f 100644 --- a/docs/licenses/mit_sizzle.txt +++ b/doc/licenses/mit_sizzle.txt diff --git a/docs/licenses/mit_tools.tooltip.txt b/doc/licenses/mit_tools.tooltip.txt index 27a4dbc788..27a4dbc788 100644 --- a/docs/licenses/mit_tools.tooltip.txt +++ b/doc/licenses/mit_tools.tooltip.txt diff --git a/src/asm/scala/tools/asm/MethodWriter.java b/src/asm/scala/tools/asm/MethodWriter.java index f5fbd1e74f..87acab17c9 100644 --- a/src/asm/scala/tools/asm/MethodWriter.java +++ b/src/asm/scala/tools/asm/MethodWriter.java @@ -1869,7 +1869,12 @@ class MethodWriter extends MethodVisitor { int size = 8; if (code.length > 0) { if (code.length > 65536) { - throw new RuntimeException("Method code too large!"); + String nameString = ""; + int i = 0; + // find item that corresponds to the index of our name + while (i < cw.items.length && (cw.items[i] == null || cw.items[i].index != name)) i++; + if (cw.items[i] != null) nameString = cw.items[i].strVal1 +"'s "; + throw new RuntimeException("Method "+ nameString +"code too large!"); } cw.newUTF8("Code"); size += 18 + code.length + 8 * handlerCount; diff --git a/src/build/maven/maven-deploy.xml b/src/build/maven/maven-deploy.xml index 412d7caab6..a2c3eefbca 100644 --- a/src/build/maven/maven-deploy.xml +++ b/src/build/maven/maven-deploy.xml @@ -1,21 +1,34 @@ <?xml version="1.0" encoding="UTF-8"?> +<!-- +THIS FILE WILL SOON SELF DESTRUCT; DO NOT USE +see publish.* targets in /build.xml +--> <project name="sabbus-maven-deploy" xmlns:artifact="urn:maven-artifact-ant"> <description> SuperSabbus extension for deploying a distribution to Maven. THIS FILE IS MEANT TO BE RUN STANDALONE IN THE MAVEN "distpack" DIRECTORY </description> + <macrodef name="deploy-remote"> <attribute name="jar" default=""/> <attribute name="pom"/> <element name="artifacts" implicit="true" optional="true"/> <sequential> - <artifact:deploy file="@{jar}" settingsFile="${settings.file}"> - <artifact:remoteRepository url="${remote.repository}" id="${repository.credentials.id}" /> - <artifact:pom refid="@{pom}" /> - <artifacts/> - </artifact:deploy> + <if><equals arg1="@{jar}" arg2="true"/><then> + <artifact:deploy settingsFile="${settings.file}"> + <artifact:remoteRepository url="${remote.repository}" id="${repository.credentials.id}" /> + <artifact:pom refid="@{pom}" /> + <artifacts/> + </artifact:deploy> + </then><else> + <artifact:deploy file="@{jar}" settingsFile="${settings.file}"> + <artifact:remoteRepository url="${remote.repository}" id="${repository.credentials.id}" /> + <artifact:pom refid="@{pom}" /> + <artifacts/> + </artifact:deploy> + </else></if> </sequential> </macrodef> @@ -24,11 +37,19 @@ <attribute name="pom"/> <element name="artifacts" implicit="true" optional="true"/> <sequential> - <artifact:install file="@{jar}"> - <artifact:localRepository path="${local.repository}" id="${repository.credentials.id}" /> - <artifact:pom refid="@{pom}" /> - <artifacts/> - </artifact:install> + <if><equals arg1="@{jar}" arg2="true"/><then> + <artifact:install> + <artifact:localRepository path="${local.repository}" id="${repository.credentials.id}" /> + <artifact:pom refid="@{pom}" /> + <artifacts/> + </artifact:install> + </then><else> + <artifact:install file="@{jar}"> + <artifact:localRepository path="${local.repository}" id="${repository.credentials.id}" /> + <artifact:pom refid="@{pom}" /> + <artifacts/> + </artifact:install> + </else></if> </sequential> </macrodef> @@ -46,26 +67,25 @@ </sequential> </macrodef> - <macrodef name="deploy-one"> - <attribute name="dir" default=""/> + <macrodef name="filter-pom"> + <attribute name="path" /> <attribute name="name" /> - <attribute name="local" default="false"/> - <attribute name="signed" default="false"/> <sequential> - <local name="path"/> <property name="path" value="@{dir}@{name}/@{name}"/> - - <echo>Deploying ${path}-[pom.xml|src.jar|docs.jar].</echo> - <copy file="${path}-pom.xml" tofile="${path}-pom-filtered.xml" overwrite="true"> <filterset> <filter token="VERSION" value="${maven.version.number}" /> <filter token="SCALA_BINARY_VERSION" value="${scala.binary.version}" /> <filter token="XML_VERSION" value="${scala-xml.version.number}" /> <filter token="PARSER_COMBINATORS_VERSION" value="${scala-parser-combinators.version.number}" /> + <filter token="CONTINUATIONS_PLUGIN_VERSION" value="${scala-continuations-plugin.version.number}" /> + <filter token="CONTINUATIONS_LIBRARY_VERSION" value="${scala-continuations-library.version.number}" /> + <filter token="SCALA_SWING_VERSION" value="${scala-swing.version.number}" /> <filter token="RELEASE_REPOSITORY" value="${remote.release.repository}" /> <filter token="SNAPSHOT_REPOSITORY" value="${remote.snapshot.repository}" /> <filter token="JLINE_VERSION" value="${jline.version}" /> + <filter token="AKKA_ACTOR_VERSION" value="${akka-actor.version.number}" /> + <filter token="ACTORS_MIGRATION_VERSION" value="${actors-migration.version.number}" /> <!-- TODO modularize compiler. <filter token="SCALA_COMPILER_DOC_VERSION" value="${scala-compiler-doc.version.number}" /> @@ -74,6 +94,20 @@ </filterset> </copy> <artifact:pom id="@{name}.pom" file="${path}-pom-filtered.xml" /> + </sequential> + </macrodef> + + <macrodef name="deploy-one"> + <attribute name="name" /> + <attribute name="local" default="false"/> + <attribute name="signed" default="false"/> + + <sequential> + <local name="path"/> <property name="path" value="${dist.maven}/@{name}/@{name}"/> + + <echo>Deploying ${path}-[pom.xml|src.jar|docs.jar].</echo> + + <filter-pom name="@{name}" path="@{path}"/> <if><equals arg1="@{signed}" arg2="false"/><then> <if><isset property="docs.skip"/><then> @@ -108,26 +142,94 @@ </sequential> </macrodef> + <macrodef name="deploy-jar"> + <attribute name="name" /> + <attribute name="local" default="false"/> + <attribute name="signed" default="false"/> + + <sequential> + <local name="path"/> <property name="path" value="${dist.maven}/@{name}/@{name}"/> + + <echo>Deploying ${path}.jar with ${path}-pom.xml.</echo> + + <filter-pom name="@{name}" path="@{path}"/> + + <if><equals arg1="@{signed}" arg2="false"/><then> + <deploy-to local="@{local}" jar="${path}.jar" pom="@{name}.pom"/> + </then><else> + <local name="repo"/> + <if><equals arg1="@{local}" arg2="false"/><then> + <property name="repo" value="${remote.repository}"/> + </then><else> + <property name="repo" value="${local.repository}"/> + </else></if> + <artifact:mvn failonerror="true"> + <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" /> + <arg value="-Durl=${repo}" /> + <arg value="-DrepositoryId=${repository.credentials.id}" /> + <arg value="-DpomFile=${path}-pom-filtered.xml" /> + <arg value= "-Dfile=${path}.jar" /> + <arg value="-Pgpg" /> + <arg value="-Dgpg.useagent=true" /> + </artifact:mvn> + </else></if> + </sequential> + </macrodef> + + <macrodef name="deploy-pom"> + <attribute name="name" /> + <attribute name="local" default="false"/> + <attribute name="signed" default="false"/> + + <sequential> + <local name="path"/> <property name="path" value="${dist.maven}/@{name}/@{name}"/> + + <echo>Deploying ${path}-pom.xml.</echo> + + <filter-pom name="@{name}" path="@{path}"/> + + <if><equals arg1="@{signed}" arg2="false"/><then> + <deploy-to local="@{local}" pom="@{name}.pom"/> + </then><else> + <local name="repo"/> + <if><equals arg1="@{local}" arg2="false"/><then> + <property name="repo" value="${remote.repository}"/> + </then><else> + <property name="repo" value="${local.repository}"/> + </else></if> + <artifact:mvn failonerror="true"> + <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" /> + <arg value="-Durl=${repo}" /> + <arg value="-DrepositoryId=${repository.credentials.id}" /> + <arg value="-DpomFile=${path}-pom-filtered.xml" /> + <arg value= "-Dfile=${path}-pom-filtered.xml" /> + <arg value="-Pgpg" /> + <arg value="-Dgpg.useagent=true" /> + </artifact:mvn> + </else></if> + </sequential> + </macrodef> + <macrodef name="deploy"> - <attribute name="dir" default=""/> <attribute name="local" default="false"/> <attribute name="signed" default="false"/> <sequential> - <deploy-one dir="@{dir}" name="scala-library" local="@{local}" signed="@{signed}"/> - <deploy-one dir="@{dir}" name="scala-reflect" local="@{local}" signed="@{signed}"/> - <deploy-one dir="@{dir}" name="scala-compiler" local="@{local}" signed="@{signed}"/> + <deploy-one name="scala-library" local="@{local}" signed="@{signed}"/> + <deploy-one name="scala-reflect" local="@{local}" signed="@{signed}"/> + <deploy-one name="scala-compiler" local="@{local}" signed="@{signed}"/> <!-- TODO modularize compiler. - <deploy-one dir="@{dir}" name="scala-compiler-doc" local="@{local}" signed="@{signed}"/> - <deploy-one dir="@{dir}" name="scala-compiler-interactive" local="@{local}" signed="@{signed}"/> + <deploy-one name="scala-compiler-doc" local="@{local}" signed="@{signed}"/> + <deploy-one name="scala-compiler-interactive" local="@{local}" signed="@{signed}"/> --> - <deploy-one dir="@{dir}" name="scala-actors" local="@{local}" signed="@{signed}"/> - <deploy-one dir="@{dir}" name="scalap" local="@{local}" signed="@{signed}"/> + <deploy-one name="scala-actors" local="@{local}" signed="@{signed}"/> + <deploy-one name="scalap" local="@{local}" signed="@{signed}"/> </sequential> </macrodef> + <target name="boot.maven"> <!-- Pull in properties from build --> <property file="build.properties" /> @@ -162,7 +264,18 @@ </echo> </target> - <target name="deploy" depends="init.maven" description="Deploys unsigned artifacts to the maven repo."> <deploy/> </target> - <target name="deploy.local" depends="init.maven" description="Deploys unsigned artifacts to the local maven repo."> <deploy local="true"/> </target> - <target name="deploy.signed" depends="init.maven" description="Deploys signed artifacts to the remote maven repo."> <deploy signed="true"/> </target> + <target name="deploy" depends="init.maven" description="Deploys unsigned artifacts to the maven repo."> + <echo message="WARNING!1! THIS TARGET HAS BEEN DEPRECATED -- CALL `ant publish` FROM /build.xml"/> + <deploy/> + </target> + + <target name="deploy.local" depends="init.maven" description="Deploys unsigned artifacts to the local maven repo."> + <echo message="WARNING!1! THIS TARGET HAS BEEN DEPRECATED -- CALL `ant publish.local` FROM /build.xml"/> + <deploy local="true"/> + </target> + + <target name="deploy.signed" depends="init.maven" description="Deploys signed artifacts to the remote maven repo."> + <echo message="WARNING!1! THIS TARGET HAS BEEN DEPRECATED -- CALL `ant publish.signed` FROM /build.xml"/> + <deploy signed="true"/> + </target> </project> diff --git a/src/build/maven/scala-actors-pom.xml b/src/build/maven/scala-actors-pom.xml index 424ac2898c..a0ebcecad1 100644 --- a/src/build/maven/scala-actors-pom.xml +++ b/src/build/maven/scala-actors-pom.xml @@ -38,17 +38,6 @@ <version>@VERSION@</version> </dependency> </dependencies> - <distributionManagement> - <repository> - <id>scala-tools.org</id> - <url>@RELEASE_REPOSITORY@</url> - </repository> - <snapshotRepository> - <id>scala-tools.org</id> - <url>@SNAPSHOT_REPOSITORY@</url> - <uniqueVersion>false</uniqueVersion> - </snapshotRepository> - </distributionManagement> <developers> <developer> <id>lamp</id> diff --git a/src/build/maven/scala-compiler-doc-pom.xml b/src/build/maven/scala-compiler-doc-pom.xml index 30161d2fea..8572e55b42 100644 --- a/src/build/maven/scala-compiler-doc-pom.xml +++ b/src/build/maven/scala-compiler-doc-pom.xml @@ -45,17 +45,6 @@ <version>@PARSER_COMBINATORS_VERSION@</version> </dependency> </dependencies> - <distributionManagement> - <repository> - <id>scala-tools.org</id> - <url>@RELEASE_REPOSITORY@</url> - </repository> - <snapshotRepository> - <id>scala-tools.org</id> - <url>@SNAPSHOT_REPOSITORY@</url> - <uniqueVersion>false</uniqueVersion> - </snapshotRepository> - </distributionManagement> <developers> <developer> <id>lamp</id> diff --git a/src/build/maven/scala-compiler-interactive-pom.xml b/src/build/maven/scala-compiler-interactive-pom.xml index d59f305a9f..ad8192b694 100644 --- a/src/build/maven/scala-compiler-interactive-pom.xml +++ b/src/build/maven/scala-compiler-interactive-pom.xml @@ -35,17 +35,6 @@ <version>@VERSION@</version> </dependency> </dependencies> - <distributionManagement> - <repository> - <id>scala-tools.org</id> - <url>@RELEASE_REPOSITORY@</url> - </repository> - <snapshotRepository> - <id>scala-tools.org</id> - <url>@SNAPSHOT_REPOSITORY@</url> - <uniqueVersion>false</uniqueVersion> - </snapshotRepository> - </distributionManagement> <developers> <developer> <id>lamp</id> diff --git a/src/build/maven/scala-compiler-pom.xml b/src/build/maven/scala-compiler-pom.xml index a16fe22343..8ca18f6f14 100644 --- a/src/build/maven/scala-compiler-pom.xml +++ b/src/build/maven/scala-compiler-pom.xml @@ -39,7 +39,7 @@ <artifactId>scala-reflect</artifactId> <version>@VERSION@</version> </dependency> - <!-- TODO modularize compiler: these dependencies will disappear then the compiler is modularized --> + <!-- TODO modularize compiler: these dependencies will disappear when the compiler is modularized --> <dependency> <!-- for scala-compiler-doc --> <groupId>org.scala-lang.modules</groupId> <artifactId>scala-xml_@SCALA_BINARY_VERSION@</artifactId> @@ -50,24 +50,13 @@ <artifactId>scala-parser-combinators_@SCALA_BINARY_VERSION@</artifactId> <version>@PARSER_COMBINATORS_VERSION@</version> </dependency> - <dependency> <!-- for scala-compiler-repl--> + <dependency> <!-- for scala-compiler-repl; once it moves there, make it required --> <groupId>jline</groupId> <artifactId>jline</artifactId> <version>@JLINE_VERSION@</version> <optional>true</optional> </dependency> </dependencies> - <distributionManagement> - <repository> - <id>scala-tools.org</id> - <url>@RELEASE_REPOSITORY@</url> - </repository> - <snapshotRepository> - <id>scala-tools.org</id> - <url>@SNAPSHOT_REPOSITORY@</url> - <uniqueVersion>false</uniqueVersion> - </snapshotRepository> - </distributionManagement> <developers> <developer> <id>lamp</id> diff --git a/src/build/maven/scala-dist-pom.xml b/src/build/maven/scala-dist-pom.xml new file mode 100644 index 0000000000..9a566d231b --- /dev/null +++ b/src/build/maven/scala-dist-pom.xml @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.scala-lang</groupId> + <artifactId>scala-dist</artifactId> + <packaging>jar</packaging> + <version>@VERSION@</version> + <name>Scala Distribution Artifacts</name> + <description>The Artifacts Distributed with Scala</description> + <url>http://www.scala-lang.org/</url> + <inceptionYear>2002</inceptionYear> + <organization> + <name>LAMP/EPFL</name> + <url>http://lamp.epfl.ch/</url> + </organization> + <licenses> + <license> + <name>BSD 3-Clause</name> + <url>http://www.scala-lang.org/license.html</url> + <distribution>repo</distribution> + </license> + </licenses> + <scm> + <connection>scm:git:git://github.com/scala/scala.git</connection> + <url>https://github.com/scala/scala.git</url> + </scm> + <issueManagement> + <system>JIRA</system> + <url>https://issues.scala-lang.org/</url> + </issueManagement> + <dependencies> + <dependency> + <groupId>org.scala-lang</groupId> + <artifactId>scala-library-all</artifactId> + <version>@VERSION@</version> + </dependency> + <dependency> + <groupId>org.scala-lang</groupId> + <artifactId>scala-compiler</artifactId> + <version>@VERSION@</version> + </dependency> + <!-- duplicated from scala-compiler, where it's optional, + so that resolving scala-dist's transitive dependencies does not include jline, + even though we need to include it in the dist, but macros depending on the compiler + shouldn't have to require jline... + another reason to modularize and move the dependency to scala-compiler-repl + TODO: remove duplication once we have the scala-compiler-repl module --> + <dependency> + <groupId>jline</groupId> + <artifactId>jline</artifactId> + <version>@JLINE_VERSION@</version> + </dependency> + </dependencies> + <developers> + <developer> + <id>lamp</id> + <name>EPFL LAMP</name> + </developer> + <developer> + <id>Typesafe</id> + <name>Typesafe, Inc.</name> + </developer> + </developers> +</project> diff --git a/src/build/maven/scala-library-all-pom.xml b/src/build/maven/scala-library-all-pom.xml new file mode 100644 index 0000000000..b649c8c525 --- /dev/null +++ b/src/build/maven/scala-library-all-pom.xml @@ -0,0 +1,88 @@ +<?xml version="1.0"?> +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.scala-lang</groupId> + <artifactId>scala-library-all</artifactId> + <packaging>pom</packaging> + <version>@VERSION@</version> + <name>Scala Library Powerpack</name> + <description>The Scala Standard Library and Official Modules</description> + <url>http://www.scala-lang.org/</url> + <inceptionYear>2002</inceptionYear> + <organization> + <name>LAMP/EPFL</name> + <url>http://lamp.epfl.ch/</url> + </organization> + <licenses> + <license> + <name>BSD 3-Clause</name> + <url>http://www.scala-lang.org/license.html</url> + <distribution>repo</distribution> + </license> + </licenses> + <scm> + <connection>scm:git:git://github.com/scala/scala.git</connection> + <url>https://github.com/scala/scala.git</url> + </scm> + <issueManagement> + <system>JIRA</system> + <url>https://issues.scala-lang.org/</url> + </issueManagement> + <dependencies> + <dependency> + <groupId>org.scala-lang</groupId> + <artifactId>scala-library</artifactId> + <version>@VERSION@</version> + </dependency> + <dependency> + <groupId>org.scala-lang</groupId> + <artifactId>scala-reflect</artifactId> + <version>@VERSION@</version> + </dependency> + <dependency> + <groupId>org.scala-lang.modules</groupId> + <artifactId>scala-xml_@SCALA_BINARY_VERSION@</artifactId> + <version>@XML_VERSION@</version> + </dependency> + <dependency> + <groupId>org.scala-lang.modules</groupId> + <artifactId>scala-parser-combinators_@SCALA_BINARY_VERSION@</artifactId> + <version>@PARSER_COMBINATORS_VERSION@</version> + </dependency> + <dependency> + <groupId>org.scala-lang.plugins</groupId> + <artifactId>scala-continuations-plugin_@SCALA_BINARY_VERSION@</artifactId> + <version>@CONTINUATIONS_PLUGIN_VERSION@</version> + </dependency> + <dependency> + <groupId>org.scala-lang.plugins</groupId> + <artifactId>scala-continuations-library_@SCALA_BINARY_VERSION@</artifactId> + <version>@CONTINUATIONS_LIBRARY_VERSION@</version> + </dependency> + <dependency> + <groupId>org.scala-lang.modules</groupId> + <artifactId>scala-swing_@SCALA_BINARY_VERSION@</artifactId> + <version>@SCALA_SWING_VERSION@</version> + </dependency> + <dependency> + <groupId>com.typesafe.akka</groupId> + <artifactId>akka-actor_@SCALA_BINARY_VERSION@</artifactId> + <version>@AKKA_ACTOR_VERSION@</version> + </dependency> + <dependency> + <groupId>org.scala-lang</groupId> + <artifactId>scala-actors-migration_@SCALA_BINARY_VERSION@</artifactId> + <version>@ACTORS_MIGRATION_VERSION@</version> + </dependency> + </dependencies> + <developers> + <developer> + <id>lamp</id> + <name>EPFL LAMP</name> + </developer> + <developer> + <id>Typesafe</id> + <name>Typesafe, Inc.</name> + </developer> + </developers> +</project> diff --git a/src/build/maven/scala-library-pom.xml b/src/build/maven/scala-library-pom.xml index d40cee2656..78fc05a7c3 100644 --- a/src/build/maven/scala-library-pom.xml +++ b/src/build/maven/scala-library-pom.xml @@ -33,17 +33,6 @@ </properties> <dependencies> </dependencies> - <distributionManagement> - <repository> - <id>scala-tools.org</id> - <url>@RELEASE_REPOSITORY@</url> - </repository> - <snapshotRepository> - <id>scala-tools.org</id> - <url>@SNAPSHOT_REPOSITORY@</url> - <uniqueVersion>false</uniqueVersion> - </snapshotRepository> - </distributionManagement> <developers> <developer> <id>lamp</id> diff --git a/src/build/maven/scala-reflect-pom.xml b/src/build/maven/scala-reflect-pom.xml index d0a9c0e274..c21caefcf2 100644 --- a/src/build/maven/scala-reflect-pom.xml +++ b/src/build/maven/scala-reflect-pom.xml @@ -38,17 +38,6 @@ <version>@VERSION@</version> </dependency> </dependencies> - <distributionManagement> - <repository> - <id>scala-tools.org</id> - <url>@RELEASE_REPOSITORY@</url> - </repository> - <snapshotRepository> - <id>scala-tools.org</id> - <url>@SNAPSHOT_REPOSITORY@</url> - <uniqueVersion>false</uniqueVersion> - </snapshotRepository> - </distributionManagement> <developers> <developer> <id>lamp</id> diff --git a/src/build/maven/scalap-pom.xml b/src/build/maven/scalap-pom.xml index 88cfce08d8..236ac999fc 100644 --- a/src/build/maven/scalap-pom.xml +++ b/src/build/maven/scalap-pom.xml @@ -35,17 +35,6 @@ <version>@VERSION@</version> </dependency> </dependencies> - <distributionManagement> - <repository> - <id>scala-tools.org</id> - <url>@RELEASE_REPOSITORY@</url> - </repository> - <snapshotRepository> - <id>scala-tools.org</id> - <url>@SNAPSHOT_REPOSITORY@</url> - <uniqueVersion>false</uniqueVersion> - </snapshotRepository> - </distributionManagement> <developers> <developer> <id>lamp</id> diff --git a/src/compiler/scala/reflect/macros/compiler/Errors.scala b/src/compiler/scala/reflect/macros/compiler/Errors.scala index 4c30a9a85c..280baa2a42 100644 --- a/src/compiler/scala/reflect/macros/compiler/Errors.scala +++ b/src/compiler/scala/reflect/macros/compiler/Errors.scala @@ -51,7 +51,7 @@ trait Errors extends Traces { def MacroBundleNonStaticError() = bundleRefError("macro bundles must be static") - def MacroBundleWrongShapeError() = bundleRefError("macro bundles must be monomorphic traits extending either BlackboxMacro or WhiteboxMacro and not implementing their `val c: BlackboxContext/WhiteboxContext` member") + def MacroBundleWrongShapeError() = bundleRefError("macro bundles must be concrete classes having a single constructor with a `val c: Context` parameter") // compatibility errors diff --git a/src/compiler/scala/reflect/macros/compiler/Resolvers.scala b/src/compiler/scala/reflect/macros/compiler/Resolvers.scala index e4851632a5..d35f1c32a9 100644 --- a/src/compiler/scala/reflect/macros/compiler/Resolvers.scala +++ b/src/compiler/scala/reflect/macros/compiler/Resolvers.scala @@ -40,36 +40,11 @@ trait Resolvers { } val untypedImplRef = typer.silent(_.typedTypeConstructor(maybeBundleRef)) match { - case SilentResultValue(result) if mightBeMacroBundleType(result.tpe) => - val bundleProto = result.tpe.typeSymbol - val bundlePkg = bundleProto.enclosingPackageClass - if (!isMacroBundleProtoType(bundleProto.tpe)) MacroBundleWrongShapeError() - if (!bundleProto.owner.isStaticOwner) MacroBundleNonStaticError() - - // synthesize the bundle, i.e. given a static `trait Foo extends Macro { def expand = ... } ` - // create a top-level definition `class Foo$Bundle(val c: BlackboxContext/WhiteboxContext) extends Foo` in a package next to `Foo` - val bundlePid = gen.mkUnattributedRef(bundlePkg) - val bundlePrefix = - if (bundlePkg == EmptyPackageClass) bundleProto.fullName('$') - else bundleProto.fullName('$').substring(bundlePkg.fullName('$').length + 1) - val bundleName = TypeName(bundlePrefix + tpnme.MACRO_BUNDLE_SUFFIX) - val existingBundle = bundleProto.enclosingPackageClass.info.decl(bundleName) - if (!currentRun.compiles(existingBundle)) { - val contextType = if (isBlackboxMacroBundleType(bundleProto.tpe)) BlackboxContextClass.tpe else WhiteboxContextClass.tpe - def mkContextValDef(flags: Long) = ValDef(Modifiers(flags), nme.c, TypeTree(contextType), EmptyTree) - val contextField = mkContextValDef(PARAMACCESSOR) - val contextParam = mkContextValDef(PARAM | PARAMACCESSOR) - val bundleCtor = DefDef(Modifiers(), nme.CONSTRUCTOR, Nil, List(List(contextParam)), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(())))) - val bundleParent = gen.mkAppliedTypeTree(Ident(bundleProto), bundleProto.typeParams.map(sym => Ident(sym.name))) - val bundleTemplate = Template(List(bundleParent), noSelfType, List(contextField, bundleCtor)) - val bundle = atPos(bundleProto.pos)(ClassDef(NoMods, bundleName, bundleProto.typeParams.map(TypeDef(_)), bundleTemplate)) - currentRun.compileLate(bundleName + ".scala", PackageDef(bundlePid, List(bundle))) - } - - // synthesize the macro impl reference, which is going to look like: - // `new FooBundle(???).macroName` plus the optional type arguments - val bundleInstance = New(Select(bundlePid, bundleName), List(List(Ident(Predef_???)))) - atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(bundleInstance, methName), targs)) + case SilentResultValue(result) if looksLikeMacroBundleType(result.tpe) => + val bundle = result.tpe.typeSymbol + if (!isMacroBundleType(bundle.tpe)) MacroBundleWrongShapeError() + if (!bundle.owner.isStaticOwner) MacroBundleNonStaticError() + atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(New(bundle, Ident(Predef_???)), methName), targs)) case _ => macroDdef.rhs } diff --git a/src/compiler/scala/reflect/macros/compiler/Validators.scala b/src/compiler/scala/reflect/macros/compiler/Validators.scala index 5936b52890..02c1f7c431 100644 --- a/src/compiler/scala/reflect/macros/compiler/Validators.scala +++ b/src/compiler/scala/reflect/macros/compiler/Validators.scala @@ -26,9 +26,9 @@ trait Validators { if (macroImpl.isOverloaded) MacroImplOverloadedError() val implicitParams = aparamss.flatten filter (_.isImplicit) if (implicitParams.nonEmpty) MacroImplNonTagImplicitParameters(implicitParams) - val declaredInStaticObject = isImplMethod && (macroImplOwner.isStaticOwner || macroImplOwner.moduleClass.isStaticOwner) - val declaredInTopLevelClass = isImplBundle && macroImplOwner.owner.isPackageClass - if (!declaredInStaticObject && !declaredInTopLevelClass) MacroImplReferenceWrongShapeError() + val effectiveOwner = if (isImplMethod) macroImplOwner else macroImplOwner.owner + val declaredInStaticObject = effectiveOwner.isStaticOwner || effectiveOwner.moduleClass.isStaticOwner + if (!declaredInStaticObject) MacroImplReferenceWrongShapeError() } private def checkMacroDefMacroImplCorrespondence() = { @@ -93,20 +93,20 @@ trait Validators { * * For the following macro impl: * def fooBar[T: c.WeakTypeTag] - * (c: scala.reflect.macros.BlackboxContext) + * (c: scala.reflect.macros.blackbox.Context) * (xs: c.Expr[List[T]]) * : c.Expr[T] = ... * * This function will return: - * (c: scala.reflect.macros.BlackboxContext)(xs: c.Expr[List[T]])c.Expr[T] + * (c: scala.reflect.macros.blackbox.Context)(xs: c.Expr[List[T]])c.Expr[T] * * Note that type tag evidence parameters are not included into the result. * Type tag context bounds for macro impl tparams are optional. * Therefore compatibility checks ignore such parameters, and we don't need to bother about them here. * * This method cannot be reduced to just macroImpl.info, because macro implementations might - * come in different shapes. If the implementation is an apply method of a BlackboxMacro/WhiteboxMacro-compatible object, - * then it won't have (c: BlackboxContext/WhiteboxContext) in its parameters, but will rather refer to BlackboxMacro/WhiteboxMacro.c. + * come in different shapes. If the implementation is an apply method of a *box.Macro-compatible object, + * then it won't have (c: *box.Context) in its parameters, but will rather refer to *boxMacro.c. * * @param macroImpl The macro implementation symbol */ @@ -123,8 +123,8 @@ trait Validators { * def foo[T](xs: List[T]): T = macro fooBar * * This function will return: - * (c: scala.reflect.macros.BlackboxContext)(xs: c.Expr[List[T]])c.Expr[T] or - * (c: scala.reflect.macros.WhiteboxContext)(xs: c.Expr[List[T]])c.Expr[T] + * (c: scala.reflect.macros.blackbox.Context)(xs: c.Expr[List[T]])c.Expr[T] or + * (c: scala.reflect.macros.whitebox.Context)(xs: c.Expr[List[T]])c.Expr[T] * * Note that type tag evidence parameters are not included into the result. * Type tag context bounds for macro impl tparams are optional. diff --git a/src/compiler/scala/reflect/macros/contexts/Context.scala b/src/compiler/scala/reflect/macros/contexts/Context.scala index 7b79b52a18..87dac18849 100644 --- a/src/compiler/scala/reflect/macros/contexts/Context.scala +++ b/src/compiler/scala/reflect/macros/contexts/Context.scala @@ -3,8 +3,8 @@ package contexts import scala.tools.nsc.Global -abstract class Context extends scala.reflect.macros.BlackboxContext - with scala.reflect.macros.WhiteboxContext +abstract class Context extends scala.reflect.macros.blackbox.Context + with scala.reflect.macros.whitebox.Context with Aliases with Enclosures with Names diff --git a/src/compiler/scala/reflect/macros/contexts/Evals.scala b/src/compiler/scala/reflect/macros/contexts/Evals.scala index 84928ddf86..180a998c39 100644 --- a/src/compiler/scala/reflect/macros/contexts/Evals.scala +++ b/src/compiler/scala/reflect/macros/contexts/Evals.scala @@ -12,7 +12,12 @@ trait Evals { private lazy val evalImporter = ru.mkImporter(universe).asInstanceOf[ru.Importer { val from: universe.type }] def eval[T](expr: Expr[T]): T = { - val imported = evalImporter.importTree(expr.tree) - evalToolBox.eval(imported).asInstanceOf[T] + expr.tree match { + case global.Literal(global.Constant(value)) => + value.asInstanceOf[T] + case _ => + val imported = evalImporter.importTree(expr.tree) + evalToolBox.eval(imported).asInstanceOf[T] + } } }
\ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/contexts/Names.scala b/src/compiler/scala/reflect/macros/contexts/Names.scala index c2f14cf0f1..299af40b94 100644 --- a/src/compiler/scala/reflect/macros/contexts/Names.scala +++ b/src/compiler/scala/reflect/macros/contexts/Names.scala @@ -4,7 +4,9 @@ package contexts trait Names { self: Context => - def freshNameCreator = callsiteTyper.context.unit.fresh + import global._ + + def freshNameCreator = globalFreshNameCreator def fresh(): String = freshName() @@ -16,11 +18,25 @@ trait Names { freshName[NameType](name) def freshName(): String = - freshName("fresh$") - - def freshName(name: String): String = - freshNameCreator.newName(name) + freshName(nme.FRESH_PREFIX) + + def freshName(name: String): String = { + // In comparison with the first version of freshName, current "fresh" names + // at least can't clash with legible user-written identifiers and are much less likely to clash with each other. + // It is still not good enough however, because the counter gets reset every time we create a new Global. + // + // This would most certainly cause problems if Scala featured something like introduceTopLevel, + // but even for def macros this can lead to unexpected troubles. Imagine that one Global + // creates a term of an anonymous type with a member featuring a "fresh" name, and then another Global + // imports that term with a wildcard and then generates a "fresh" name of its own. Given unlucky + // circumstances these "fresh" names might end up clashing. + // + // TODO: hopefully SI-7823 will provide an ultimate answer to this problem. + // In the meanwhile I will also keep open the original issue: SI-6879 "c.freshName is broken". + val sortOfUniqueSuffix = freshNameCreator.newName(nme.FRESH_SUFFIX) + name + "$" + sortOfUniqueSuffix + } def freshName[NameType <: Name](name: NameType): NameType = - name.mapName(freshNameCreator.newName(_)).asInstanceOf[NameType] + name.mapName(freshName(_)).asInstanceOf[NameType] }
\ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/contexts/Typers.scala b/src/compiler/scala/reflect/macros/contexts/Typers.scala index 85204d0f1b..c1ab17027f 100644 --- a/src/compiler/scala/reflect/macros/contexts/Typers.scala +++ b/src/compiler/scala/reflect/macros/contexts/Typers.scala @@ -46,7 +46,7 @@ trait Typers { universe.analyzer.inferImplicit(tree, viewTpe, true, callsiteTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw TypecheckException(pos, msg)) } - def resetAllAttrs(tree: Tree): Tree = universe.resetAllAttrs(universe.duplicateAndKeepPositions(tree)) + def resetLocalAttrs(tree: Tree): Tree = universe.resetAttrs(universe.duplicateAndKeepPositions(tree)) - def resetLocalAttrs(tree: Tree): Tree = universe.resetLocalAttrs(universe.duplicateAndKeepPositions(tree)) + def untypecheck(tree: Tree): Tree = resetLocalAttrs(tree) } diff --git a/src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala b/src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala index 450cb4d9ea..ecdd48db22 100644 --- a/src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala +++ b/src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala @@ -2,7 +2,9 @@ package scala.reflect.macros package runtime import scala.reflect.runtime.ReflectionUtils -import scala.reflect.macros.{Context => ApiContext} +import scala.reflect.macros.blackbox.{Context => BlackboxContext} +import scala.reflect.macros.whitebox.{Context => WhiteboxContext} +import java.lang.reflect.{Constructor => jConstructor} trait JavaReflectionRuntimes { self: scala.tools.nsc.typechecker.Analyzer => @@ -19,8 +21,15 @@ trait JavaReflectionRuntimes { macroLogVerbose(s"successfully loaded macro impl as ($implClass, $implMeth)") args => { val implObj = - if (isBundle) implClass.getConstructor(classOf[ApiContext]).newInstance(args.c) - else ReflectionUtils.staticSingletonInstance(implClass) + if (isBundle) { + def isMacroContext(clazz: Class[_]) = clazz == classOf[BlackboxContext] || clazz == classOf[WhiteboxContext] + def isBundleCtor(ctor: jConstructor[_]) = ctor.getParameterTypes match { + case Array(param) if isMacroContext(param) => true + case _ => false + } + val Array(bundleCtor) = implClass.getConstructors.filter(isBundleCtor) + bundleCtor.newInstance(args.c) + } else ReflectionUtils.staticSingletonInstance(implClass) val implArgs = if (isBundle) args.others else args.c +: args.others implMeth.invoke(implObj, implArgs.asInstanceOf[Seq[AnyRef]]: _*) } diff --git a/src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala b/src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala index 14b0c6baba..5fd9c0db34 100644 --- a/src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala +++ b/src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala @@ -4,7 +4,7 @@ package runtime import scala.reflect.internal.Flags._ import scala.reflect.runtime.ReflectionUtils -trait MacroRuntimes extends JavaReflectionRuntimes with ScalaReflectionRuntimes { +trait MacroRuntimes extends JavaReflectionRuntimes { self: scala.tools.nsc.typechecker.Analyzer => import global._ @@ -49,8 +49,7 @@ trait MacroRuntimes extends JavaReflectionRuntimes with ScalaReflectionRuntimes /** Abstracts away resolution of macro runtimes. */ type MacroRuntime = MacroArgs => Any - class MacroRuntimeResolver(val macroDef: Symbol) extends JavaReflectionResolvers - with ScalaReflectionResolvers { + class MacroRuntimeResolver(val macroDef: Symbol) extends JavaReflectionResolvers { val binding = loadMacroImplBinding(macroDef).get val isBundle = binding.isBundle val className = binding.className @@ -63,7 +62,6 @@ trait MacroRuntimes extends JavaReflectionRuntimes with ScalaReflectionRuntimes try { macroLogVerbose(s"resolving macro implementation as $className.$methName (isBundle = $isBundle)") macroLogVerbose(s"classloader is: ${ReflectionUtils.show(defaultMacroClassloader)}") - // resolveScalaReflectionRuntime(defaultMacroClassloader) resolveJavaReflectionRuntime(defaultMacroClassloader) } catch { case ex: Exception => diff --git a/src/compiler/scala/reflect/macros/runtime/ScalaReflectionRuntimes.scala b/src/compiler/scala/reflect/macros/runtime/ScalaReflectionRuntimes.scala deleted file mode 100644 index 50f64310f8..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/ScalaReflectionRuntimes.scala +++ /dev/null @@ -1,31 +0,0 @@ -package scala.reflect.macros -package runtime - -import scala.reflect.runtime.{universe => ru} - -trait ScalaReflectionRuntimes { - self: scala.tools.nsc.typechecker.Analyzer => - - trait ScalaReflectionResolvers { - self: MacroRuntimeResolver => - - def resolveScalaReflectionRuntime(classLoader: ClassLoader): MacroRuntime = { - val macroMirror: ru.JavaMirror = ru.runtimeMirror(classLoader) - val implContainerSym = macroMirror.classSymbol(Class.forName(className, true, classLoader)) - val implMethSym = implContainerSym.typeSignature.member(ru.TermName(methName)).asMethod - macroLogVerbose(s"successfully loaded macro impl as ($implContainerSym, $implMethSym)") - args => { - val implContainer = - if (isBundle) { - val implCtorSym = implContainerSym.typeSignature.member(ru.nme.CONSTRUCTOR).asMethod - macroMirror.reflectClass(implContainerSym).reflectConstructor(implCtorSym)(args.c) - } else { - macroMirror.reflectModule(implContainerSym.module.asModule).instance - } - val implMeth = macroMirror.reflect(implContainer).reflectMethod(implMethSym) - val implArgs = if (isBundle) args.others else args.c +: args.others - implMeth(implArgs: _*) - } - } - } -} diff --git a/src/compiler/scala/reflect/reify/Reifier.scala b/src/compiler/scala/reflect/reify/Reifier.scala index ad0632f93e..6b0a0ee8d7 100644 --- a/src/compiler/scala/reflect/reify/Reifier.scala +++ b/src/compiler/scala/reflect/reify/Reifier.scala @@ -86,7 +86,7 @@ abstract class Reifier extends States throw new Error("reifee %s of type %s is not supported".format(reifee, if (reifee == null) "null" else reifee.getClass.toString)) } - // todo. why do we resetAllAttrs? + // todo. why do we reset attrs? // // typically we do some preprocessing before reification and // the code emitted/moved around during preprocessing is very hard to typecheck, so we leave it as it is @@ -109,19 +109,11 @@ abstract class Reifier extends States // // todo. this is a common problem with non-trivial macros in our current macro system // needs to be solved some day - // maybe try `resetLocalAttrs` once the dust settles - var importantSymbols = Set[Symbol]( - NothingClass, AnyClass, SingletonClass, PredefModule, ScalaRunTimeModule, TypeCreatorClass, TreeCreatorClass, MirrorClass, - ApiUniverseClass, JavaUniverseClass, ReflectRuntimePackage, runDefinitions.ReflectRuntimeCurrentMirror) - importantSymbols ++= importantSymbols map (_.companionSymbol) - importantSymbols ++= importantSymbols map (_.moduleClass) - importantSymbols ++= importantSymbols map (_.linkedClassOfClass) - def isImportantSymbol(sym: Symbol): Boolean = sym != null && sym != NoSymbol && importantSymbols(sym) - val untyped = resetAllAttrs(result, leaveAlone = { + // upd. a new hope: https://groups.google.com/forum/#!topic/scala-internals/TtCTPlj_qcQ + val untyped = resetAttrs(result, leaveAlone = { case ValDef(_, u, _, _) if u == nme.UNIVERSE_SHORT => true case ValDef(_, m, _, _) if m == nme.MIRROR_SHORT => true case tree if symtab.syms contains tree.symbol => true - case tree if isImportantSymbol(tree.symbol) => true case _ => false }) diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index f6b3c42ca9..b082796757 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -140,7 +140,7 @@ trait GenTrees { if (sym == NoSymbol) { // this sometimes happens, e.g. for binds that don't have a body // or for untyped code generated during previous phases - // (see a comment in Reifiers about the latter, starting with "why do we resetAllAttrs?") + // (see a comment in Reifiers about the latter, starting with "why do we reset attrs?") mirrorCall(nme.Ident, reify(name)) } else if (!sym.isLocalToReifee) { diff --git a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala index 99b968be3b..a90a3a338b 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala @@ -60,7 +60,7 @@ trait GenTypes { reifyProduct(tpe) case tpe @ NullaryMethodType(restpe) => reifyProduct(tpe) - case tpe @ AnnotatedType(anns, underlying, selfsym) => + case tpe @ AnnotatedType(anns, underlying) => reifyAnnotatedType(tpe) case _ => reifyToughType(tpe) @@ -162,8 +162,8 @@ trait GenTypes { /** Reify an annotated type, i.e. the one that makes us deal with AnnotationInfos */ private def reifyAnnotatedType(tpe: AnnotatedType): Tree = { - val AnnotatedType(anns, underlying, selfsym) = tpe - mirrorFactoryCall(nme.AnnotatedType, mkList(anns map reifyAnnotationInfo), reify(underlying), reify(selfsym)) + val AnnotatedType(anns, underlying) = tpe + mirrorFactoryCall(nme.AnnotatedType, mkList(anns map reifyAnnotationInfo), reify(underlying)) } /** Reify a tough type, i.e. the one that leads to creation of auxiliary symbols */ diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index df5952a4cf..c2caed70a0 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -98,6 +98,11 @@ trait CompilationUnits { global: Global => override def toString = map.toString } + // namer calls typer.computeType(rhs) on DefDef / ValDef when tpt is empty. the result + // is cached here and re-used in typedDefDef / typedValDef + // Also used to cache imports type-checked by namer. + val transformed = new mutable.AnyRefMap[Tree, Tree] + /** things to check at end of compilation unit */ val toCheck = new ListBuffer[() => Unit] diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 5f079a428b..1617db7517 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -81,6 +81,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def picklerPhase: Phase = if (currentRun.isDefined) currentRun.picklerPhase else NoPhase + def erasurePhase: Phase = if (currentRun.isDefined) currentRun.erasurePhase else NoPhase + // platform specific elements protected class GlobalPlatform extends { @@ -527,7 +529,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } with Erasure // phaseName = "posterasure" - object postErasure extends { + override object postErasure extends { val global: Global.this.type = Global.this val runsAfter = List("erasure") val runsRightAfter = Some("erasure") @@ -1710,25 +1712,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } } - /** Create and compile a synthetic compilation unit from the provided tree. - * - * This needs to create a virtual file underlying the compilation unit in order to appease SBT. - * However this file cannot have a randomly generated name, because then SBT 0.13 goes into a vicious loop - * as described on the mailing list: https://groups.google.com/forum/#!msg/scala-user/r1SgSoVfs0U/Wv4av0LOKukJ - * Therefore I have introduced an additional parameter that makes everyone specify meaningful file names. - */ - def compileLate(virtualFileName: String, code: PackageDef) { - // compatibility with SBT - // on the one hand, we need to specify some jfile here, otherwise sbt crashes with an NPE (SI-6870) - // on the other hand, we can't specify the obvious enclosingUnit, because then sbt somehow fails to run tests using type macros - val fakeJfile = new java.io.File(virtualFileName) - val virtualFile = new VirtualFile(virtualFileName) { override def file = fakeJfile } - val sourceFile = new BatchSourceFile(virtualFile, code.toString) - val unit = new CompilationUnit(sourceFile) - unit.body = code - compileLate(unit) - } - /** Reset package class to state at typer (not sure what this * is needed for?) */ diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala index c68b248240..eafecf9462 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala @@ -619,7 +619,7 @@ abstract class TreeBrowsers { toDocument(result) :: ")") ) - case AnnotatedType(annots, tp, _) => + case AnnotatedType(annots, tp) => Document.group( Document.nest(4, "AnnotatedType(" :/: annots.mkString("[", ",", "]") :/: @@ -632,7 +632,7 @@ abstract class TreeBrowsers { Document.group("(" :/: symsToDocument(tparams) :/: "), ") :/: toDocument(result) :: ")")) - case global.analyzer.ImportType(expr) => + case ImportType(expr) => "ImportType(" + expr.toString + ")" diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 4ac6672727..a87a04472a 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -37,7 +37,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { NoSymbol newImport NoPosition setFlag SYNTHETIC - setInfo analyzer.ImportType(qual) + setInfo ImportType(qual) ) val importTree = ( Import(qual, selector) diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index cccae0c3a0..7a7d4ac0b2 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -176,13 +176,24 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => } } - /** resets symbol and tpe fields in a tree, @see ResetAttrs - */ -// def resetAllAttrs[A<:Tree](x:A): A = { new ResetAttrsTraverser().traverse(x); x } -// def resetLocalAttrs[A<:Tree](x:A): A = { new ResetLocalAttrsTraverser().traverse(x); x } - - def resetAllAttrs(x: Tree, leaveAlone: Tree => Boolean = null): Tree = new ResetAttrs(false, leaveAlone).transform(x) - def resetLocalAttrs(x: Tree, leaveAlone: Tree => Boolean = null): Tree = new ResetAttrs(true, leaveAlone).transform(x) + // Finally, noone resetAllAttrs it anymore, so I'm removing it from the compiler. + // Even though it's with great pleasure I'm doing that, I'll leave its body here to warn future generations about what happened in the past. + // + // So what actually happened in the past is that we used to have two flavors of resetAttrs: resetAllAttrs and resetLocalAttrs. + // resetAllAttrs destroyed all symbols and types in the tree in order to reset its state to something suitable for retypechecking + // and/or embedding into bigger trees / different lexical scopes. (Btw here's some background on why people would want to use + // reset attrs in the first place: https://groups.google.com/forum/#!topic/scala-internals/TtCTPlj_qcQ). + // + // However resetAllAttrs was more of a poison than of a treatment, because along with locally defined symbols that are the cause + // for almost every or maybe even every case of tree corruption, it erased external bindings that sometimes could not be restored. + // This is how we came up with resetLocalAttrs that left external bindings alone, and that was a big step forward. + // Then slowly but steadily we've evicted all usages of resetAllAttrs from our codebase in favor of resetLocalAttrs + // and have been living happily ever after. + // + // def resetAllAttrs(x: Tree, leaveAlone: Tree => Boolean = null): Tree = new ResetAttrs(localOnly = false, leaveAlone).transform(x) + + /** @see ResetAttrs */ + def resetAttrs(x: Tree, leaveAlone: Tree => Boolean = null): Tree = new ResetAttrs(leaveAlone).transform(x) /** A transformer which resets symbol and tpe fields of all nodes in a given tree, * with special treatment of: @@ -193,8 +204,10 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => * * (bq:) This transformer has mutable state and should be discarded after use */ - private class ResetAttrs(localOnly: Boolean, leaveAlone: Tree => Boolean = null, keepLabels: Boolean = false) { - val debug = settings.debug.value + private class ResetAttrs(leaveAlone: Tree => Boolean = null) { + // this used to be based on -Ydebug, but the need for logging in this code is so situational + // that I've reverted to a hard-coded constant here. + val debug = false val trace = scala.tools.nsc.util.trace when debug val locals = util.HashSet[Symbol](8) @@ -275,29 +288,18 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => // vetoXXX local variables declared below describe the conditions under which we cannot erase symbols. // // The first reason to not erase symbols is the threat of non-idempotency (SI-5464). - // Here we take care of labels (SI-5562) and references to package classes (SI-5705). + // Here we take care of references to package classes (SI-5705). // There are other non-idempotencies, but they are not worked around yet. // - // The second reason has to do with the fact that resetAttrs itself has limited usefulness. - // - // First of all, why do we need resetAttrs? Gor one, it's absolutely required to move trees around. - // One cannot just take a typed tree from one lexical context and transplant it somewhere else. - // Most likely symbols defined by those trees will become borked and the compiler will blow up (SI-5797). - // To work around we just erase all symbols and types and then hope that we'll be able to correctly retypecheck. - // For ones who're not affected by scalac Stockholm syndrome, this might seem to be an extremely naive fix, but well... - // - // Of course, sometimes erasing everything won't work, because if a given identifier got resolved to something - // in one lexical scope, it can get resolved to something else. - // - // What do we do in these cases? Enter the workaround for the workaround: resetLocalAttrs, which only destroys - // locally defined symbols, but doesn't touch references to stuff declared outside of a given tree. - // That's what localOnly and vetoScope are for. + // The second reason has to do with the fact that resetAttrs needs to be less destructive. + // Erasing locally-defined symbols is useful to prevent tree corruption, but erasing external bindings is not, + // therefore we want to retain those bindings, especially given that restoring them can be impossible + // if we move these trees into lexical contexts different from their original locations. if (dupl.hasSymbol) { val sym = dupl.symbol - val vetoScope = localOnly && !(locals contains sym) - val vetoLabel = keepLabels && sym.isLabel + val vetoScope = !(locals contains sym) val vetoThis = dupl.isInstanceOf[This] && sym.isPackageClass - if (!(vetoScope || vetoLabel || vetoThis)) dupl.symbol = NoSymbol + if (!(vetoScope || vetoThis)) dupl.symbol = NoSymbol } dupl.clearType() } @@ -306,10 +308,9 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => } def transform(x: Tree): Tree = { - if (localOnly) new MarkLocals().traverse(x) - if (localOnly && debug) { + if (debug) { assert(locals.size == orderedLocals.size) val msg = orderedLocals.toList filter {_ != NoSymbol} map {" " + _} mkString EOL trace("locals (%d total): %n".format(orderedLocals.size))(msg) diff --git a/src/compiler/scala/tools/nsc/ast/parser/CommonTokens.scala b/src/compiler/scala/tools/nsc/ast/parser/CommonTokens.scala new file mode 100644 index 0000000000..5fcb02814b --- /dev/null +++ b/src/compiler/scala/tools/nsc/ast/parser/CommonTokens.scala @@ -0,0 +1,112 @@ +package scala.tools.nsc +package ast.parser + +/** Common code between Scala's Tokens and JavaTokens. */ +abstract class CommonTokens { + + def isIdentifier(code: Int): Boolean + def isLiteral(code: Int): Boolean + + /** special tokens */ + final val EMPTY = -3 + final val UNDEF = -2 + final val ERROR = -1 + final val EOF = 0 + + /** literals */ + final val CHARLIT = 1 + final val INTLIT = 2 + final val LONGLIT = 3 + final val FLOATLIT = 4 + final val DOUBLELIT = 5 + final val STRINGLIT = 6 + + /** keywords */ + final val NEW = 20 + final val THIS = 21 + final val SUPER = 23 + + final val NULL = 24 + final val TRUE = 25 + final val FALSE = 26 + + // J: INSTANCEOF = 27 + // J: CONST = 28 + + /** modifiers */ + // S: IMPLICIT = 40 + // S: OVERRIDE = 41 + // J: PUBLIC = 42 + final val PROTECTED = 43 + final val PRIVATE = 44 + // S: SEALED = 45 + final val ABSTRACT = 46 + // J: DEFAULT = 47 + // J: STATIC = 48 + final val FINAL = 49 + // J: TRANSIENT = 50 + // J: VOLATILE = 51 + // J: SYNCHRONIZED = 52 + // J: NATIVE = 53 + // J: STRICTFP = 54 + // S: LAZY = 55 + // J: THROWS = 56 + // S: MACRO = 57 + + /** templates */ + final val PACKAGE = 60 + final val IMPORT = 61 + final val CLASS = 62 + // S: CASECLASS = 63 + // S: OBJECT = 64 + // S: CASEOBJECT = 65 + // S: TRAIT, J: INTERFACE = 66 + // J: ENUM = 67 + final val EXTENDS = 68 + // S: WITH, J: IMPLEMENTS = 69 + // S: TYPE = 70 + // S: FORSOME = 71 + // S: DEF = 72 + // S: VAL = 73 + // S: VAR = 74 + + /** control structures */ + final val IF = 80 + // S: THEN = 81 + final val ELSE = 82 + final val WHILE = 83 + final val DO = 84 + final val FOR = 85 + // S: YIELD = 86 + // J: BREAK = 87 + // J: CONTINUE = 88 + // J: GOTO = 89 + final val THROW = 90 + final val TRY = 91 + final val CATCH = 92 + final val FINALLY = 93 + // J: SWITCH = 94 + // S: MATCH = 95 + final val CASE = 96 + final val RETURN = 97 + // J: ASSERT = 98 + + /** parenthesis */ + final val LPAREN = 100 + final val RPAREN = 101 + final val LBRACKET = 102 + final val RBRACKET = 103 + final val LBRACE = 104 + final val RBRACE = 105 + + /** special symbols */ + final val COMMA = 120 + final val SEMI = 121 + final val DOT = 122 + final val COLON = 123 + final val EQUALS = 124 + final val AT = 125 + // S: <special symbols> = 130 - 139 + // J: <special symbols> = 140 - 179 + // J: <primitive types> = 180 - 189 +} diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index d122a1a207..e3d2bf14a0 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -33,7 +33,7 @@ trait ParsersCommon extends ScannersCommon { self => import global.{currentUnit => _, _} def newLiteral(const: Any) = Literal(Constant(const)) - def literalUnit = newLiteral(()) + def literalUnit = gen.mkSyntheticUnit() /** This is now an abstract class, only to work around the optimizer: * methods in traits are never inlined. @@ -133,7 +133,7 @@ self => val global: Global import global._ - case class OpInfo(lhs: Tree, operator: TermName, offset: Offset) { + case class OpInfo(lhs: Tree, operator: TermName, targs: List[Tree], offset: Offset) { def precedence = Precedence(operator.toString) } @@ -787,10 +787,13 @@ self => private def opHead = opstack.head private def headPrecedence = opHead.precedence private def popOpInfo(): OpInfo = try opHead finally opstack = opstack.tail - private def pushOpInfo(top: Tree) { - val opinfo = OpInfo(top, in.name, in.offset) - opstack ::= opinfo + private def pushOpInfo(top: Tree): Unit = { + val name = in.name + val offset = in.offset ident() + val targs = if (in.token == LBRACKET) exprTypeArgs() else Nil + val opinfo = OpInfo(top, name, targs, offset) + opstack ::= opinfo } def checkHeadAssoc(leftAssoc: Boolean) = checkAssoc(opHead.offset, opHead.operator, leftAssoc) @@ -800,6 +803,9 @@ self => ) def finishPostfixOp(start: Int, base: List[OpInfo], opinfo: OpInfo): Tree = { + if (opinfo.targs.nonEmpty) + syntaxError(opinfo.offset, "type application is not allowed for postfix operators") + val od = stripParens(reduceExprStack(base, opinfo.lhs)) makePostfixSelect(start, opinfo.offset, od, opinfo.operator) } @@ -809,7 +815,7 @@ self => val operatorPos: Position = Position.range(rhs.pos.source, offset, offset, offset + operator.length) val pos = lhs.pos union rhs.pos union operatorPos withPoint offset - atPos(pos)(makeBinop(isExpr, lhs, operator, rhs, operatorPos)) + atPos(pos)(makeBinop(isExpr, lhs, operator, rhs, operatorPos, opinfo.targs)) } def reduceExprStack(base: List[OpInfo], top: Tree): Tree = reduceStack(isExpr = true, base, top) @@ -831,8 +837,14 @@ self => if (samePrecedence) checkHeadAssoc(leftAssoc) - def loop(top: Tree): Tree = - if (canReduce) loop(finishBinaryOp(isExpr, popOpInfo(), top)) else top + def loop(top: Tree): Tree = if (canReduce) { + val info = popOpInfo() + if (!isExpr && info.targs.nonEmpty) { + syntaxError(info.offset, "type application is not allowed in pattern") + info.targs.foreach(_.setType(ErrorType)) + } + loop(finishBinaryOp(isExpr, info, top)) + } else top loop(top) } @@ -1024,7 +1036,11 @@ self => /** Assumed (provisionally) to be TermNames. */ def ident(skipIt: Boolean): Name = ( - if (isIdent) rawIdent().encode + if (isIdent) { + val name = in.name.encode + in.nextToken() + name + } else syntaxErrorOrIncompleteAnd(expectedMsg(IDENTIFIER), skipIt)(nme.ERROR) ) @@ -1209,7 +1225,7 @@ self => // Like Swiss cheese, with holes def stringCheese: Tree = atPos(in.offset) { val start = in.offset - val interpolator = in.name + val interpolator = in.name.encoded // ident() for INTERPOLATIONID val partsBuf = new ListBuffer[Tree] val exprBuf = new ListBuffer[Tree] @@ -1892,9 +1908,9 @@ self => def isDelimiter = in.token == RPAREN || in.token == RBRACE def isCommaOrDelimiter = isComma || isDelimiter val (isUnderscore, isStar) = opstack match { - case OpInfo(Ident(nme.WILDCARD), nme.STAR, _) :: _ => (true, true) - case OpInfo(_, nme.STAR, _) :: _ => (false, true) - case _ => (false, false) + case OpInfo(Ident(nme.WILDCARD), nme.STAR, _, _) :: _ => (true, true) + case OpInfo(_, nme.STAR, _, _) :: _ => (false, true) + case _ => (false, false) } def isSeqPatternClose = isUnderscore && isStar && isSequenceOK && isDelimiter val preamble = "bad simple pattern:" @@ -2121,8 +2137,6 @@ self => /* -------- PARAMETERS ------------------------------------------- */ - def allowTypelessParams = false - /** {{{ * ParamClauses ::= {ParamClause} [[nl] `(' implicit Params `)'] * ParamClause ::= [nl] `(' [Params] `)' @@ -2137,56 +2151,6 @@ self => def paramClauses(owner: Name, contextBounds: List[Tree], ofCaseClass: Boolean): List[List[ValDef]] = { var implicitmod = 0 var caseParam = ofCaseClass - def param(): ValDef = { - val start = in.offset - val annots = annotations(skipNewLines = false) - var mods = Modifiers(Flags.PARAM) - if (owner.isTypeName) { - mods = modifiers() | Flags.PARAMACCESSOR - if (mods.isLazy) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead", skipIt = false) - in.token match { - case v @ (VAL | VAR) => - mods = mods withPosition (in.token.toLong, tokenRange(in)) - if (v == VAR) mods |= Flags.MUTABLE - in.nextToken() - case _ => - if (mods.flags != Flags.PARAMACCESSOR) accept(VAL) - if (!caseParam) mods |= Flags.PrivateLocal - } - if (caseParam) mods |= Flags.CASEACCESSOR - } - val nameOffset = in.offset - val name = ident() - var bynamemod = 0 - val tpt = - if (((settings.YmethodInfer && !owner.isTypeName) || allowTypelessParams) && in.token != COLON) { - TypeTree() - } else { // XX-METHOD-INFER - accept(COLON) - if (in.token == ARROW) { - if (owner.isTypeName && !mods.hasLocalFlag) - syntaxError( - in.offset, - (if (mods.isMutable) "`var'" else "`val'") + - " parameters may not be call-by-name", skipIt = false) - else if (implicitmod != 0) - syntaxError( - in.offset, - "implicit parameters may not be call-by-name", skipIt = false) - else bynamemod = Flags.BYNAMEPARAM - } - paramType() - } - val default = - if (in.token == EQUALS) { - in.nextToken() - mods |= Flags.DEFAULTPARAM - expr() - } else EmptyTree - atPos(start, if (name == nme.ERROR) start else nameOffset) { - ValDef((mods | implicitmod.toLong | bynamemod) withAnnotations annots, name.toTermName, tpt, default) - } - } def paramClause(): List[ValDef] = { if (in.token == RPAREN) return Nil @@ -2195,7 +2159,7 @@ self => in.nextToken() implicitmod = Flags.IMPLICIT } - commaSeparated(param()) + commaSeparated(param(owner, implicitmod, caseParam )) } val vds = new ListBuffer[List[ValDef]] val start = in.offset @@ -2243,6 +2207,57 @@ self => } } + def param(owner: Name, implicitmod: Int, caseParam: Boolean): ValDef = { + val start = in.offset + val annots = annotations(skipNewLines = false) + var mods = Modifiers(Flags.PARAM) + if (owner.isTypeName) { + mods = modifiers() | Flags.PARAMACCESSOR + if (mods.isLazy) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead", skipIt = false) + in.token match { + case v @ (VAL | VAR) => + mods = mods withPosition (in.token.toLong, tokenRange(in)) + if (v == VAR) mods |= Flags.MUTABLE + in.nextToken() + case _ => + if (mods.flags != Flags.PARAMACCESSOR) accept(VAL) + if (!caseParam) mods |= Flags.PrivateLocal + } + if (caseParam) mods |= Flags.CASEACCESSOR + } + val nameOffset = in.offset + val name = ident() + var bynamemod = 0 + val tpt = + if ((settings.YmethodInfer && !owner.isTypeName) && in.token != COLON) { + TypeTree() + } else { // XX-METHOD-INFER + accept(COLON) + if (in.token == ARROW) { + if (owner.isTypeName && !mods.hasLocalFlag) + syntaxError( + in.offset, + (if (mods.isMutable) "`var'" else "`val'") + + " parameters may not be call-by-name", skipIt = false) + else if (implicitmod != 0) + syntaxError( + in.offset, + "implicit parameters may not be call-by-name", skipIt = false) + else bynamemod = Flags.BYNAMEPARAM + } + paramType() + } + val default = + if (in.token == EQUALS) { + in.nextToken() + mods |= Flags.DEFAULTPARAM + expr() + } else EmptyTree + atPos(start, if (name == nme.ERROR) start else nameOffset) { + ValDef((mods | implicitmod.toLong | bynamemod) withAnnotations annots, name.toTermName, tpt, default) + } + } + /** {{{ * TypeParamClauseOpt ::= [TypeParamClause] * TypeParamClause ::= `[' VariantTypeParam {`,' VariantTypeParam} `]'] diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 87bd498ea1..e8d46704c3 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -206,9 +206,9 @@ trait Scanners extends ScannersCommon { token = kwArray(idx) if (token == IDENTIFIER && allowIdent != name) { if (name == nme.MACROkw) - syntaxError(name+" is now a reserved word; usage as an identifier is disallowed") + syntaxError(s"$name is now a reserved word; usage as an identifier is disallowed") else if (emitIdentifierDeprecationWarnings) - deprecationWarning(name+" is now a reserved word; usage as an identifier is deprecated") + deprecationWarning(s"$name is now a reserved word; usage as an identifier is deprecated") } } } @@ -389,7 +389,7 @@ trait Scanners extends ScannersCommon { // println("blank line found at "+lastOffset+":"+(lastOffset to idx).map(buf(_)).toList) return true } - if (idx == end) return false + if (idx == end) return false } while (ch <= ' ') } idx += 1; ch = buf(idx) @@ -475,14 +475,17 @@ trait Scanners extends ScannersCommon { if (token == INTERPOLATIONID) { nextRawChar() if (ch == '\"') { - nextRawChar() - if (ch == '\"') { + val lookahead = lookaheadReader + lookahead.nextChar() + if (lookahead.ch == '\"') { + nextRawChar() // now eat it offset += 3 nextRawChar() getStringPart(multiLine = true) sepRegions = STRINGPART :: sepRegions // indicate string part sepRegions = STRINGLIT :: sepRegions // once more to indicate multi line string part } else { + nextChar() token = STRINGLIT strVal = "" } @@ -607,10 +610,7 @@ trait Scanners extends ScannersCommon { if (ch == '`') { nextChar() finishNamed(BACKQUOTED_IDENT) - if (name.length == 0) - syntaxError("empty quoted identifier") - else if (name == nme.WILDCARD) - syntaxError("wildcard invalid as backquoted identifier") + if (name.length == 0) syntaxError("empty quoted identifier") } else syntaxError("unclosed quoted identifier") } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala index 5a7dc4950d..e624aec88c 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala @@ -6,123 +6,57 @@ package scala.tools.nsc package ast.parser -/** Common code between JavaTokens and Tokens. Not as much (and not as concrete) - * as one might like because JavaTokens for no clear reason chose new numbers for - * identical token sets. - */ -abstract class Tokens { - /** special tokens */ - final val EMPTY = -3 - final val UNDEF = -2 - final val ERROR = -1 - final val EOF = 0 - - /** literals */ - final val CHARLIT = 1 - final val INTLIT = 2 - final val LONGLIT = 3 - final val FLOATLIT = 4 - final val DOUBLELIT = 5 - final val STRINGLIT = 6 - - def LPAREN: Int - def RBRACE: Int - - def isIdentifier(code: Int): Boolean - def isLiteral(code: Int): Boolean -} - -object Tokens extends Tokens { - final val STRINGPART = 7 // a part of an interpolated string +object Tokens extends CommonTokens { + final val STRINGPART = 7 // a part of an interpolated string final val SYMBOLLIT = 8 final val INTERPOLATIONID = 9 // the lead identifier of an interpolated string - def isLiteral(code: Int) = - code >= CHARLIT && code <= INTERPOLATIONID + def isLiteral(code: Int) = code >= CHARLIT && code <= INTERPOLATIONID /** identifiers */ final val IDENTIFIER = 10 final val BACKQUOTED_IDENT = 11 - def isIdentifier(code: Int) = code >= IDENTIFIER && code <= BACKQUOTED_IDENT // used by ide - - /** keywords */ - final val IF = 20 - final val FOR = 21 - final val ELSE = 22 - final val THIS = 23 - final val NULL = 24 - final val NEW = 25 - final val WITH = 26 - final val SUPER = 27 - final val CASE = 28 - final val CASECLASS = 29 - final val CASEOBJECT = 30 - final val VAL = 31 - final val ABSTRACT = 32 - final val FINAL = 33 - final val PRIVATE = 34 - final val PROTECTED = 35 - final val OVERRIDE = 36 - final val IMPLICIT = 37 - final val VAR = 38 - final val DEF = 39 - final val TYPE = 40 - final val EXTENDS = 41 - final val TRUE = 42 - final val FALSE = 43 - final val OBJECT = 44 - final val CLASS = 45 - - final val IMPORT = 46 - final val PACKAGE = 47 - final val YIELD = 48 - final val DO = 49 - final val TRAIT = 50 - final val SEALED = 51 - final val THROW = 52 - final val TRY = 53 - final val CATCH = 54 - final val FINALLY = 55 - final val WHILE = 56 - final val RETURN = 57 - final val MATCH = 58 - final val FORSOME = 59 - final val LAZY = 61 - final val MACRO = 62 // not yet used in 2.10 - final val THEN = 63 // not yet used in 2.10 + def isIdentifier(code: Int) = code == IDENTIFIER || code == BACKQUOTED_IDENT // used by ide + + /** modifiers */ + final val IMPLICIT = 40 + final val OVERRIDE = 41 + final val SEALED = 45 + final val LAZY = 55 + final val MACRO = 57 + + /** templates */ + final val CASECLASS = 63 + final val OBJECT = 64 + final val CASEOBJECT = 65 + final val TRAIT = 66 + final val WITH = 69 + final val TYPE = 70 + final val FORSOME = 71 + final val DEF = 72 + final val VAL = 73 + final val VAR = 74 + + /** control structures */ + final val THEN = 81 + final val YIELD = 86 + final val MATCH = 95 /** special symbols */ - final val COMMA = 70 - final val SEMI = 71 - final val DOT = 72 - final val USCORE = 73 - final val COLON = 74 - final val EQUALS = 75 - final val LARROW = 76 - final val ARROW = 77 - final val NEWLINE = 78 - final val NEWLINES = 79 - final val SUBTYPE = 80 - final val SUPERTYPE = 81 - final val HASH = 82 - final val AT = 83 - final val VIEWBOUND = 84 - - /** parenthesis */ - final val LPAREN = 90 - final val RPAREN = 91 - final val LBRACKET = 92 - final val RBRACKET = 93 - final val LBRACE = 94 - final val RBRACE = 95 - - /** XML mode */ - final val XMLSTART = 96 + final val HASH = 130 + final val USCORE = 131 + final val ARROW = 132 + final val LARROW = 133 + final val SUBTYPE = 134 + final val SUPERTYPE = 135 + final val VIEWBOUND = 136 + final val NEWLINE = 137 + final val NEWLINES = 138 + final val XMLSTART = 139 /** for IDE only */ - final val COMMENT = 97 - - final val WHITESPACE = 105 - final val IGNORE = 106 - final val ESCAPE = 109 + final val COMMENT = 200 + final val WHITESPACE = 201 + final val IGNORE = 202 + final val ESCAPE = 203 } diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index d88470bd5e..525dcffb0c 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -55,7 +55,13 @@ abstract class TreeBuilder { ValDef(Modifiers(PRIVATE), name, tpt, EmptyTree) /** Create tree representing (unencoded) binary operation expression or pattern. */ - def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position): Tree = { + def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position, targs: List[Tree] = Nil): Tree = { + require(isExpr || targs.isEmpty || targs.exists(_.isErroneous), s"Incompatible args to makeBinop: !isExpr but targs=$targs") + + def mkSelection(t: Tree) = { + def sel = atPos(opPos union t.pos)(Select(stripParens(t), op.encode)) + if (targs.isEmpty) sel else atPos(left.pos)(TypeApply(sel, targs)) + } def mkNamed(args: List[Tree]) = if (isExpr) args map treeInfo.assignmentToMaybeNamedArg else args val arguments = right match { case Parens(args) => mkNamed(args) @@ -63,12 +69,12 @@ abstract class TreeBuilder { } if (isExpr) { if (treeInfo.isLeftAssoc(op)) { - Apply(atPos(opPos union left.pos) { Select(stripParens(left), op.encode) }, arguments) + Apply(mkSelection(left), arguments) } else { val x = freshTermName() Block( List(ValDef(Modifiers(SYNTHETIC | ARTIFACT), x, TypeTree(), stripParens(left))), - Apply(atPos(opPos union right.pos) { Select(stripParens(right), op.encode) }, List(Ident(x)))) + Apply(mkSelection(right), List(Ident(x)))) } } else { Apply(Ident(op.encode), stripParens(left) :: arguments) diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index d44e7a9312..b650cdfa09 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -46,8 +46,10 @@ abstract class GenICode extends SubComponent { var unit: CompilationUnit = NoCompilationUnit override def run() { - scalaPrimitives.init() - classes.clear() + if (!settings.isBCodeActive) { + scalaPrimitives.init() + classes.clear() + } super.run() } @@ -793,10 +795,7 @@ abstract class GenICode extends SubComponent { case _ => } ctx1.bb.emit(cm, tree.pos) - - if (sym == ctx1.method.symbol) { - ctx1.method.recursive = true - } + ctx1.method.updateRecursive(sym) generatedType = if (sym.isClassConstructor) UNIT else toTypeKind(sym.info.resultType) @@ -1010,8 +1009,15 @@ abstract class GenICode extends SubComponent { } // emit conversion - if (generatedType != expectedType) - adapt(generatedType, expectedType, resCtx, tree.pos) + if (generatedType != expectedType) { + tree match { + case Literal(Constant(null)) if generatedType == NullReference => + // literal null on the stack (as opposed to a boxed null, see SI-8233), + // we can bypass `adapt` which would otherwise emitt a redundant [DROP, CONSTANT(null)] + case _ => + adapt(generatedType, expectedType, resCtx, tree.pos) + } + } resCtx } @@ -1061,6 +1067,9 @@ abstract class GenICode extends SubComponent { case (NothingReference, _) => ctx.bb.emit(THROW(ThrowableClass)) ctx.bb.enterIgnoreMode() + case (NullReference, REFERENCE(_)) => + // SI-8223 we can't assume that the stack contains a `null`, it might contain a Null$ + ctx.bb.emit(Seq(DROP(from), CONSTANT(Constant(null)))) case _ if from isAssignabledTo to => () case (_, UNIT) => diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 4d1d59cd12..64146585e5 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -21,7 +21,7 @@ trait Members { import global._ - object NoCode extends Code(null, "NoCode") { + object NoCode extends Code(null, TermName("NoCode")) { override def blocksList: List[BasicBlock] = Nil } @@ -29,8 +29,8 @@ trait Members { * This class represents the intermediate code of a method or * other multi-block piece of code, like exception handlers. */ - class Code(method: IMethod, name: String) { - def this(method: IMethod) = this(method, method.symbol.decodedName.toString.intern) + class Code(method: IMethod, name: Name) { + def this(method: IMethod) = this(method, method.symbol.name) /** The set of all blocks */ val blocks = mutable.ListBuffer[BasicBlock]() @@ -82,7 +82,7 @@ trait Members { } /** This methods returns a string representation of the ICode */ - override def toString = "ICode '" + name + "'" + override def toString = "ICode '" + name.decoded + "'" /* Compute a unique new label */ def nextLabel: Int = { @@ -195,6 +195,10 @@ trait Members { this } + final def updateRecursive(called: Symbol): Unit = { + recursive ||= (called == symbol) + } + def addLocal(l: Local): Local = findOrElse(locals)(_ == l) { locals ::= l ; l } def addParam(p: Local): Unit = diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index 633e71a756..a6d0d3b9fa 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -393,7 +393,7 @@ trait TypeKinds { self: ICodes => // if the first two cases exist because they do or as a defensive measure, but // at the time I added it, RefinedTypes were indeed reaching here. case ExistentialType(_, t) => toTypeKind(t) - case AnnotatedType(_, t, _) => toTypeKind(t) + case AnnotatedType(_, t) => toTypeKind(t) case RefinedType(parents, _) => parents map toTypeKind reduceLeft lub // For sure WildcardTypes shouldn't reach here either, but when // debugging such situations this may come in handy. diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 4f9f4c9e31..c8845344e9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -88,7 +88,9 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { def genThrow(expr: Tree): BType = { val thrownKind = tpeTK(expr) - assert(exemplars.get(thrownKind).isSubtypeOf(ThrowableReference)) + // `throw null` is valid although scala.Null (as defined in src/libray-aux) isn't a subtype of Throwable. + // Similarly for scala.Nothing (again, as defined in src/libray-aux). + assert(thrownKind.isNullType || thrownKind.isNothingType || exemplars.get(thrownKind).isSubtypeOf(ThrowableReference)) genLoad(expr, thrownKind) lineNumber(expr) emit(asm.Opcodes.ATHROW) // ICode enters here into enterIgnoreMode, we'll rely instead on DCE at ClassNode level. @@ -824,7 +826,6 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { /* Generate code that loads args into label parameters. */ def genLoadLabelArguments(args: List[Tree], lblDef: LabelDef, gotoPos: Position) { - assert(args forall { a => !a.hasSymbolField || a.hasSymbolWhich( s => !s.isLabel) }, s"SI-6089 at: $gotoPos") // SI-6089 val aps = { val params: List[Symbol] = lblDef.params.map(_.symbol) @@ -857,12 +858,11 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { } def genLoadModule(tree: Tree): BType = { - // Working around SI-5604. Rather than failing the compile when we see a package here, check if there's a package object. val module = ( if (!tree.symbol.isPackageClass) tree.symbol else tree.symbol.info.member(nme.PACKAGE) match { - case NoSymbol => abort(s"Cannot use package as value: $tree") ; NoSymbol - case s => devWarning("Bug: found package class where package object expected. Converting.") ; s.moduleClass + case NoSymbol => abort(s"SI-5604: Cannot use package as value: $tree") + case s => abort(s"SI-5604: found package class where package object expected: $tree") } ) lineNumber(tree) @@ -871,7 +871,8 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { } def genLoadModule(module: Symbol) { - if (claszSymbol == module.moduleClass && jMethodName != "readResolve") { + def inStaticMethod = methSymbol != null && methSymbol.isStaticMember + if (claszSymbol == module.moduleClass && jMethodName != "readResolve" && !inStaticMethod) { mnode.visitVarInsn(asm.Opcodes.ALOAD, 0) } else { val mbt = symInfoTK(module) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala index 9dcf263f4f..cc3265c5f9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeGlue.scala @@ -661,6 +661,14 @@ abstract class BCodeGlue extends SubComponent { val CT_NOTHING = brefType("scala/Nothing") // TODO needed? val CT_NULL = brefType("scala/Null") // TODO needed? + val srBooleanRef = brefType("scala/runtime/BooleanRef") + val srByteRef = brefType("scala/runtime/ByteRef") + val srCharRef = brefType("scala/runtime/CharRef") + val srIntRef = brefType("scala/runtime/IntRef") + val srLongRef = brefType("scala/runtime/LongRef") + val srFloatRef = brefType("scala/runtime/FloatRef") + val srDoubleRef = brefType("scala/runtime/DoubleRef") + /* Map from type kinds to the Java reference types. * Useful when pushing class literals onto the operand stack (ldc instruction taking a class literal). * @see Predef.classOf diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 64ed094a47..18ccced75e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -440,13 +440,11 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { if (sym0 == definitions.NullClass) return RT_NULL; if (sym0 == definitions.NothingClass) return RT_NOTHING; - // Working around SI-5604. Rather than failing the compile when we see - // a package here, check if there's a package object. val sym = ( if (!sym0.isPackageClass) sym0 else sym0.info.member(nme.PACKAGE) match { - case NoSymbol => abort(s"Cannot use package as value: ${sym0.fullName}") - case s => devWarning("Bug: found package class where package object expected. Converting.") ; s.moduleClass + case NoSymbol => abort(s"SI-5604: Cannot use package as value: ${sym0.fullName}") + case s => abort(s"SI-5604: found package class where package object expected: $s") } ) @@ -518,7 +516,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { // !!! Iulian says types which make no sense after erasure should not reach here, which includes the ExistentialType, AnnotatedType, RefinedType. case ExistentialType(_, t) => toTypeKind(t) // TODO shouldn't get here but the following does: akka-actor/src/main/scala/akka/util/WildcardTree.scala - case AnnotatedType(_, w, _) => toTypeKind(w) // TODO test/files/jvm/annotations.scala causes an AnnotatedType to reach here. + case AnnotatedType(_, w) => toTypeKind(w) // TODO test/files/jvm/annotations.scala causes an AnnotatedType to reach here. case RefinedType(parents, _) => parents map toTypeKind reduceLeft jvmWiseLUB // For sure WildcardTypes shouldn't reach here either, but when debugging such situations this may come in handy. @@ -561,7 +559,9 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { memberCTK } - exemplar(csym) // side effect city + + exemplar(csym).directMemberClasses = result + result } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala index 529295389c..c3492b79a9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala @@ -46,6 +46,7 @@ abstract class BCodeIdiomatic extends BCodeGlue { val ObjectReference = brefType("java/lang/Object") val AnyRefReference = ObjectReference + val objArrayReference = arrayOf(ObjectReference) val JAVA_LANG_OBJECT = ObjectReference val JAVA_LANG_STRING = brefType("java/lang/String") diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala index c921d11d00..360ce58ecc 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala @@ -460,7 +460,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { } def lineNumber(tree: Tree) { if (!emitLines || !tree.pos.isDefined) return; - val nr = tree.pos.line + val nr = tree.pos.finalPosition.line if (nr != lastEmittedLineNr) { lastEmittedLineNr = nr lastInsn match { diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala index 27bcbb82d4..9ddb7a3ce8 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala @@ -386,10 +386,6 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder { /* Does this tree have a try-catch block? */ def mayCleanStack(tree: Tree): Boolean = tree exists { t => t.isInstanceOf[Try] } - abstract class Cleanup(val value: AnyRef) { } - case class MonitorRelease(v: Symbol) extends Cleanup(v) { } - case class Finalizer(f: Tree) extends Cleanup (f) { } - trait EHClause case class NamelessEH(typeToDrop: BType, caseBody: Tree) extends EHClause case class BoundEH (patSymbol: Symbol, caseBody: Tree) extends EHClause diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala index 5be5abd895..1eca69936a 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala @@ -24,11 +24,15 @@ abstract class BCodeTypes extends BCodeIdiomatic { // when compiling the Scala library, some assertions don't hold (e.g., scala.Boolean has null superClass although it's not an interface) val isCompilingStdLib = !(settings.sourcepath.isDefault) + val srBoxedUnit = brefType("scala/runtime/BoxedUnit") + // special names var StringReference : BType = null var ThrowableReference : BType = null var jlCloneableReference : BType = null // java/lang/Cloneable + var jlNPEReference : BType = null // java/lang/NullPointerException var jioSerializableReference : BType = null // java/io/Serializable + var scalaSerializableReference : BType = null // scala/Serializable var classCastExceptionReference : BType = null // java/lang/ClassCastException /* A map from scala primitive type-symbols to BTypes */ @@ -52,6 +56,8 @@ abstract class BCodeTypes extends BCodeIdiomatic { /* The Object => String overload. */ var String_valueOf: Symbol = null + var ArrayInterfaces: Set[Tracked] = null + // scala.FunctionX and scala.runtim.AbstractFunctionX val FunctionReference = new Array[Tracked](definitions.MaxFunctionArity + 1) val AbstractFunctionReference = new Array[Tracked](definitions.MaxFunctionArity + 1) @@ -128,15 +134,17 @@ abstract class BCodeTypes extends BCodeIdiomatic { ) } - exemplar(JavaCloneableClass).c - exemplar(JavaSerializableClass).c - exemplar(SerializableClass).c + exemplar(JavaCloneableClass) + exemplar(JavaSerializableClass) + exemplar(SerializableClass) StringReference = exemplar(StringClass).c StringBuilderReference = exemplar(StringBuilderClass).c ThrowableReference = exemplar(ThrowableClass).c jlCloneableReference = exemplar(JavaCloneableClass).c + jlNPEReference = exemplar(NullPointerExceptionClass).c jioSerializableReference = exemplar(JavaSerializableClass).c + scalaSerializableReference = exemplar(SerializableClass).c classCastExceptionReference = exemplar(ClassCastExceptionClass).c /* @@ -203,6 +211,23 @@ abstract class BCodeTypes extends BCodeIdiomatic { * All methods of this class can-multi-thread */ case class Tracked(c: BType, flags: Int, sc: Tracked, ifaces: Array[Tracked], innersChain: Array[InnerClassEntry]) { + + // not a case-field because we initialize it only for JVM classes we emit. + private var _directMemberClasses: List[BType] = null + + def directMemberClasses: List[BType] = { + assert(_directMemberClasses != null, s"getter directMemberClasses() invoked too early for $c") + _directMemberClasses + } + + def directMemberClasses_=(bs: List[BType]) { + if (_directMemberClasses != null) { + // TODO we enter here when both mirror class and plain class are emitted for the same ModuleClassSymbol. + assert(_directMemberClasses == bs.sortBy(_.off)) + } + _directMemberClasses = bs.sortBy(_.off) + } + /* `isCompilingStdLib` saves the day when compiling: * (1) scala.Nothing (the test `c.isNonSpecial` fails for it) * (2) scala.Boolean (it has null superClass and is not an interface) @@ -835,6 +860,7 @@ abstract class BCodeTypes extends BCodeIdiomatic { if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0, if (sym.isArtifact) ACC_SYNTHETIC else 0, if (sym.isClass && !sym.isInterface) ACC_SUPER else 0, + if (sym.hasEnumFlag) ACC_ENUM else 0, if (sym.isVarargsMethod) ACC_VARARGS else 0, if (sym.hasFlag(symtab.Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0 ) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index e92f8c2541..b03519ce7d 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -171,10 +171,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { var pickledBytes = 0 // statistics - val javaNameCache = perRunCaches.newMap[Symbol, Name]() + val javaNameCache = perRunCaches.newAnyRefMap[Symbol, Name]() // unlike javaNameCache, reverseJavaName contains entries only for class symbols and their internal names. - val reverseJavaName = perRunCaches.newMap[String, Symbol]() + val reverseJavaName = perRunCaches.newAnyRefMap[String, Symbol]() private def mkFlags(args: Int*) = args.foldLeft(0)(_ | _) private def hasPublicBitSet(flags: Int) = (flags & asm.Opcodes.ACC_PUBLIC) != 0 @@ -244,6 +244,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0, if (sym.isArtifact) ACC_SYNTHETIC else 0, if (sym.isClass && !sym.isInterface) ACC_SUPER else 0, + if (sym.hasEnumFlag) ACC_ENUM else 0, if (sym.isVarargsMethod) ACC_VARARGS else 0, if (sym.hasFlag(Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0 ) @@ -468,9 +469,9 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { } bytecodeWriter.writeClass(label, jclassName, arr, outF) } catch { - case e: java.lang.RuntimeException if(e.getMessage() == "Class file too large!") => - // TODO check where ASM throws the equivalent of CodeSizeTooBigException - log("Skipped class "+jclassName+" because it exceeds JVM limits (it's too big or has methods that are too long).") + case e: java.lang.RuntimeException if e != null && (e.getMessage contains "too large!") => + reporter.error(sym.pos, + s"Could not write class $jclassName because it exceeds JVM code size limits. ${e.getMessage}") } } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 7932dd3459..a61ad392ee 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -190,7 +190,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { case GTGTGT => GTGT case GTGTEQ => GTEQ case GTGT => GT - case GTEQ => ASSIGN + case GTEQ => EQUALS } if (closers isDefinedAt in.token) in.token = closers(in.token) else accept(GT) @@ -538,7 +538,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { in.nextToken() if (in.token == IDENTIFIER) { // if there's an ident after the comma ... val name = ident() - if (in.token == ASSIGN || in.token == SEMI) { // ... followed by a `=` or `;`, we know it's a real variable definition + if (in.token == EQUALS || in.token == SEMI) { // ... followed by a `=` or `;`, we know it's a real variable definition buf ++= maybe buf += varDecl(in.currentPos, mods, tpt.duplicate, name.toTermName) maybe.clear() @@ -563,7 +563,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { def varDecl(pos: Position, mods: Modifiers, tpt: Tree, name: TermName): ValDef = { val tpt1 = optArrayBrackets(tpt) - if (in.token == ASSIGN && !mods.isParameter) skipTo(COMMA, SEMI) + if (in.token == EQUALS && !mods.isParameter) skipTo(COMMA, SEMI) val mods1 = if (mods.isFinal) mods &~ Flags.FINAL else mods | Flags.MUTABLE atPos(pos) { ValDef(mods1, name, tpt1, blankExpr) @@ -792,7 +792,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { val superclazz = AppliedTypeTree(javaLangDot(tpnme.Enum), List(enumType)) addCompanionObject(consts ::: statics ::: predefs, atPos(pos) { - ClassDef(mods, name, List(), + ClassDef(mods | Flags.ENUM, name, List(), makeTemplate(superclazz :: interfaces, body)) }) } @@ -811,10 +811,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { skipAhead() accept(RBRACE) } - // The STABLE flag is to signal to namer that this was read from a - // java enum, and so should be given a Constant type (thereby making - // it usable in annotations.) - ValDef(Modifiers(Flags.STABLE | Flags.JAVA | Flags.STATIC), name.toTermName, enumType, blankExpr) + ValDef(Modifiers(Flags.ENUM | Flags.STABLE | Flags.JAVA | Flags.STATIC), name.toTermName, enumType, blankExpr) } } diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala index b7ea70e2c7..c5401219dd 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala @@ -155,7 +155,6 @@ trait JavaScanners extends ast.parser.ScannersCommon { case AMP => "`&'" case AMPAMP => "`&&'" case AMPEQ => "`&='" - case ASSIGN => "`='" case ASTERISK => "`*'" case ASTERISKEQ => "`*='" case AT => "`@'" @@ -169,6 +168,7 @@ trait JavaScanners extends ast.parser.ScannersCommon { case DOT => "`.'" case DOTDOTDOT => "`...'" case EQEQ => "`=='" + case EQUALS => "`='" case GT => "`>'" case GTEQ => "`>='" case GTGT => "`>>'" @@ -337,7 +337,7 @@ trait JavaScanners extends ast.parser.ScannersCommon { return case '=' => - token = ASSIGN + token = EQUALS in.next() if (in.ch == '=') { token = EQEQ diff --git a/src/compiler/scala/tools/nsc/javac/JavaTokens.scala b/src/compiler/scala/tools/nsc/javac/JavaTokens.scala index 953a3c6d82..9b31e6e8a2 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaTokens.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaTokens.scala @@ -6,117 +6,89 @@ package scala.tools.nsc package javac -object JavaTokens extends ast.parser.Tokens { +object JavaTokens extends ast.parser.CommonTokens { - def isLiteral(code : Int) = + def isLiteral(code: Int) = code >= CHARLIT && code <= STRINGLIT /** identifiers */ final val IDENTIFIER = 10 - def isIdentifier(code : Int) = + def isIdentifier(code: Int) = code == IDENTIFIER /** keywords */ - final val ABSTRACT = 20 - final val ASSERT = 21 - final val BOOLEAN = 22 - final val BREAK = 23 - final val BYTE = 24 - final val CASE = 25 - final val CATCH = 26 - final val CHAR = 27 - final val CLASS = 28 - final val CONST = 29 - final val CONTINUE = 30 - final val DEFAULT = 31 - final val DO = 32 - final val DOUBLE = 33 - final val ELSE = 34 - final val ENUM = 35 - final val EXTENDS = 36 - final val FINAL = 37 - final val FINALLY = 38 - final val FLOAT = 39 - final val FOR = 40 - final val IF = 41 - final val GOTO = 42 - final val IMPLEMENTS = 43 - final val IMPORT = 44 - final val INSTANCEOF = 45 - final val INT = 46 - final val INTERFACE = 47 - final val LONG = 48 - final val NATIVE = 49 - final val NEW = 50 - final val PACKAGE = 51 - final val PRIVATE = 52 - final val PROTECTED = 53 - final val PUBLIC = 54 - final val RETURN = 55 - final val SHORT = 56 - final val STATIC = 57 - final val STRICTFP = 58 - final val SUPER = 59 - final val SWITCH = 60 - final val SYNCHRONIZED = 61 - final val THIS = 62 - final val THROW = 63 - final val THROWS = 64 - final val TRANSIENT = 65 - final val TRY = 66 - final val VOID = 67 - final val VOLATILE = 68 - final val WHILE = 69 + final val INSTANCEOF = 27 + final val CONST = 28 + + /** modifiers */ + final val PUBLIC = 42 + final val DEFAULT = 47 + final val STATIC = 48 + final val TRANSIENT = 50 + final val VOLATILE = 51 + final val SYNCHRONIZED = 52 + final val NATIVE = 53 + final val STRICTFP = 54 + final val THROWS = 56 + + /** templates */ + final val INTERFACE = 66 + final val ENUM = 67 + final val IMPLEMENTS = 69 + + /** control structures */ + final val BREAK = 87 + final val CONTINUE = 88 + final val GOTO = 89 + final val SWITCH = 94 + final val ASSERT = 98 /** special symbols */ - final val COMMA = 70 - final val SEMI = 71 - final val DOT = 72 - final val AT = 73 - final val COLON = 74 - final val ASSIGN = 75 - final val EQEQ = 76 - final val BANGEQ = 77 - final val LT = 78 - final val GT = 79 - final val LTEQ = 80 - final val GTEQ = 81 - final val BANG = 82 - final val QMARK = 83 - final val AMP = 84 - final val BAR = 85 - final val PLUS = 86 - final val MINUS = 87 - final val ASTERISK = 88 - final val SLASH = 89 - final val PERCENT = 90 - final val HAT = 91 - final val LTLT = 92 - final val GTGT = 93 - final val GTGTGT = 94 - final val AMPAMP = 95 - final val BARBAR = 96 - final val PLUSPLUS = 97 - final val MINUSMINUS = 98 - final val TILDE = 99 - final val DOTDOTDOT = 100 - final val AMPEQ = 104 - final val BAREQ = 105 - final val PLUSEQ = 106 - final val MINUSEQ = 107 - final val ASTERISKEQ = 1010 - final val SLASHEQ = 109 - final val PERCENTEQ = 110 - final val HATEQ = 111 - final val LTLTEQ = 112 - final val GTGTEQ = 113 - final val GTGTGTEQ = 114 + final val EQEQ = 140 + final val BANGEQ = 141 + final val LT = 142 + final val GT = 143 + final val LTEQ = 144 + final val GTEQ = 145 + final val BANG = 146 + final val QMARK = 147 + final val AMP = 148 + final val BAR = 149 + final val PLUS = 150 + final val MINUS = 151 + final val ASTERISK = 152 + final val SLASH = 153 + final val PERCENT = 154 + final val HAT = 155 + final val LTLT = 156 + final val GTGT = 157 + final val GTGTGT = 158 + final val AMPAMP = 159 + final val BARBAR = 160 + final val PLUSPLUS = 161 + final val MINUSMINUS = 162 + final val TILDE = 163 + final val DOTDOTDOT = 164 + final val AMPEQ = 165 + final val BAREQ = 166 + final val PLUSEQ = 167 + final val MINUSEQ = 168 + final val ASTERISKEQ = 169 + final val SLASHEQ = 170 + final val PERCENTEQ = 171 + final val HATEQ = 172 + final val LTLTEQ = 173 + final val GTGTEQ = 174 + final val GTGTGTEQ = 175 - /** parenthesis */ - final val LPAREN = 115 - final val RPAREN = 116 - final val LBRACKET = 117 - final val RBRACKET = 118 - final val LBRACE = 119 - final val RBRACE = 120 + /** primitive types */ + final val VOID = 180 + final val BOOLEAN = 181 + final val BYTE = 182 + final val SHORT = 183 + final val CHAR = 184 + final val INT = 185 + final val LONG = 186 + final val FLOAT = 187 + final val DOUBLE = 188 } diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala index 183752d4a2..7837f9a11a 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala @@ -126,10 +126,11 @@ object Plugin { } /** Load all plugins specified by the arguments. - * Each of `jars` must be a valid plugin archive or exploded archive. + * Each location of `paths` must be a valid plugin archive or exploded archive. + * Each of `paths` must define one plugin. * Each of `dirs` may be a directory containing arbitrary plugin archives. * Skips all plugins named in `ignoring`. - * A single classloader is created and used to load all of them. + * A classloader is created to load each plugin. */ def loadAllFrom( paths: List[List[Path]], diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 1f9987c83b..a3114a3d7b 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -73,48 +73,55 @@ trait ScalaSettings extends AbsScalaSettings val nospecialization = BooleanSetting ("-no-specialization", "Ignore @specialize annotations.") val language = MultiStringSetting("-language", "feature", "Enable one or more language features.") + /* + * The previous "-source" option is intended to be used mainly + * though this helper. + */ + lazy val isScala211: Boolean = (source.value >= ScalaVersion("2.11.0")) + /** * -X "Advanced" settings */ - val Xhelp = BooleanSetting ("-X", "Print a synopsis of advanced options.") - val checkInit = BooleanSetting ("-Xcheckinit", "Wrap field accessors to throw an exception on uninitialized access.") - val developer = BooleanSetting ("-Xdev", "Indicates user is a developer - issue warnings about anything which seems amiss") - val noassertions = BooleanSetting ("-Xdisable-assertions", "Generate no assertions or assumptions.") - val elidebelow = IntSetting ("-Xelide-below", "Calls to @elidable methods are omitted if method priority is lower than argument", + val Xhelp = BooleanSetting ("-X", "Print a synopsis of advanced options.") + val checkInit = BooleanSetting ("-Xcheckinit", "Wrap field accessors to throw an exception on uninitialized access.") + val developer = BooleanSetting ("-Xdev", "Indicates user is a developer - issue warnings about anything which seems amiss") + val noassertions = BooleanSetting ("-Xdisable-assertions", "Generate no assertions or assumptions.") + val elidebelow = IntSetting ("-Xelide-below", "Calls to @elidable methods are omitted if method priority is lower than argument", elidable.MINIMUM, None, elidable.byName get _) - val noForwarders = BooleanSetting ("-Xno-forwarders", "Do not generate static forwarders in mirror classes.") - val genPhaseGraph = StringSetting ("-Xgenerate-phase-graph", "file", "Generate the phase graphs (outputs .dot files) to fileX.dot.", "") - val XlogImplicits = BooleanSetting ("-Xlog-implicits", "Show more detail on why some implicits are not applicable.") - val logImplicitConv = BooleanSetting ("-Xlog-implicit-conversions", "Print a message whenever an implicit conversion is inserted.") - val logReflectiveCalls = BooleanSetting("-Xlog-reflective-calls", "Print a message when a reflective method call is generated") - val logFreeTerms = BooleanSetting ("-Xlog-free-terms", "Print a message when reification creates a free term.") - val logFreeTypes = BooleanSetting ("-Xlog-free-types", "Print a message when reification resorts to generating a free type.") - val maxClassfileName = IntSetting ("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, Some((72, 255)), _ => None) - val Xmigration = ScalaVersionSetting("-Xmigration", "version", "Warn about constructs whose behavior may have changed since version.", AnyScalaVersion) - val nouescape = BooleanSetting ("-Xno-uescape", "Disable handling of \\u unicode escapes.") - val Xnojline = BooleanSetting ("-Xnojline", "Do not use JLine for editing.") - val Xverify = BooleanSetting ("-Xverify", "Verify generic signatures in generated bytecode (asm backend only.)") - val plugin = MultiStringSetting("-Xplugin", "file", "Load one or more plugins from files.") - val disable = MultiStringSetting("-Xplugin-disable", "plugin", "Disable the given plugin(s).") - val showPlugins = BooleanSetting ("-Xplugin-list", "Print a synopsis of loaded plugins.") - val require = MultiStringSetting("-Xplugin-require", "plugin", "Abort unless the given plugin(s) are available.") - val pluginsDir = StringSetting ("-Xpluginsdir", "path", "Path to search compiler plugins.", Defaults.scalaPluginPath) - val Xprint = PhasesSetting ("-Xprint", "Print out program after") - val writeICode = PhasesSetting ("-Xprint-icode", "Log internal icode to *.icode files after", "icode") - val Xprintpos = BooleanSetting ("-Xprint-pos", "Print tree positions, as offsets.") - val printtypes = BooleanSetting ("-Xprint-types", "Print tree types (debugging option).") - val prompt = BooleanSetting ("-Xprompt", "Display a prompt after each error (debugging option).") - val resident = BooleanSetting ("-Xresident", "Compiler stays resident: read source filenames from standard input.") - val script = StringSetting ("-Xscript", "object", "Treat the source file as a script and wrap it in a main method.", "") - val mainClass = StringSetting ("-Xmain-class", "path", "Class for manifest's Main-Class entry (only useful with -d <jar>)", "") - val Xshowcls = StringSetting ("-Xshow-class", "class", "Show internal representation of class.", "") - val Xshowobj = StringSetting ("-Xshow-object", "object", "Show internal representation of object.", "") - val showPhases = BooleanSetting ("-Xshow-phases", "Print a synopsis of compiler phases.") - val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "") - val strictInference = BooleanSetting ("-Xstrict-inference", "Don't infer known-unsound types") + val noForwarders = BooleanSetting ("-Xno-forwarders", "Do not generate static forwarders in mirror classes.") + val genPhaseGraph = StringSetting ("-Xgenerate-phase-graph", "file", "Generate the phase graphs (outputs .dot files) to fileX.dot.", "") + val XlogImplicits = BooleanSetting ("-Xlog-implicits", "Show more detail on why some implicits are not applicable.") + val logImplicitConv = BooleanSetting ("-Xlog-implicit-conversions", "Print a message whenever an implicit conversion is inserted.") + val logReflectiveCalls = BooleanSetting ("-Xlog-reflective-calls", "Print a message when a reflective method call is generated") + val logFreeTerms = BooleanSetting ("-Xlog-free-terms", "Print a message when reification creates a free term.") + val logFreeTypes = BooleanSetting ("-Xlog-free-types", "Print a message when reification resorts to generating a free type.") + val maxClassfileName = IntSetting ("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, Some((72, 255)), _ => None) + val Xmigration = ScalaVersionSetting ("-Xmigration", "version", "Warn about constructs whose behavior may have changed since version.", AnyScalaVersion) + val nouescape = BooleanSetting ("-Xno-uescape", "Disable handling of \\u unicode escapes.") + val Xnojline = BooleanSetting ("-Xnojline", "Do not use JLine for editing.") + val Xverify = BooleanSetting ("-Xverify", "Verify generic signatures in generated bytecode (asm backend only.)") + val plugin = MultiStringSetting ("-Xplugin", "paths", "Load a plugin from each classpath.") + val disable = MultiStringSetting ("-Xplugin-disable", "plugin", "Disable plugins by name.") + val showPlugins = BooleanSetting ("-Xplugin-list", "Print a synopsis of loaded plugins.") + val require = MultiStringSetting ("-Xplugin-require", "plugin", "Abort if a named plugin is not loaded.") + val pluginsDir = StringSetting ("-Xpluginsdir", "path", "Path to search for plugin archives.", Defaults.scalaPluginPath) + val Xprint = PhasesSetting ("-Xprint", "Print out program after") + val writeICode = PhasesSetting ("-Xprint-icode", "Log internal icode to *.icode files after", "icode") + val Xprintpos = BooleanSetting ("-Xprint-pos", "Print tree positions, as offsets.") + val printtypes = BooleanSetting ("-Xprint-types", "Print tree types (debugging option).") + val prompt = BooleanSetting ("-Xprompt", "Display a prompt after each error (debugging option).") + val resident = BooleanSetting ("-Xresident", "Compiler stays resident: read source filenames from standard input.") + val script = StringSetting ("-Xscript", "object", "Treat the source file as a script and wrap it in a main method.", "") + val mainClass = StringSetting ("-Xmain-class", "path", "Class for manifest's Main-Class entry (only useful with -d <jar>)", "") + val Xshowcls = StringSetting ("-Xshow-class", "class", "Show internal representation of class.", "") + val Xshowobj = StringSetting ("-Xshow-object", "object", "Show internal representation of object.", "") + val showPhases = BooleanSetting ("-Xshow-phases", "Print a synopsis of compiler phases.") + val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "") + val strictInference = BooleanSetting ("-Xstrict-inference", "Don't infer known-unsound types") + val source = ScalaVersionSetting ("-Xsource", "version", "Treat compiler input as Scala source for the specified version, see SI-8126.", ScalaVersion("2.11")) withPostSetHook ( _ => isScala211) val XnoPatmatAnalysis = BooleanSetting ("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.") - val XfullLubs = BooleanSetting ("-Xfull-lubs", "Retains pre 2.10 behavior of less aggressive truncation of least upper bounds.") + val XfullLubs = BooleanSetting ("-Xfull-lubs", "Retains pre 2.10 behavior of less aggressive truncation of least upper bounds.") /** Compatibility stubs for options whose value name did * not previously match the option name. @@ -154,7 +161,6 @@ trait ScalaSettings extends AbsScalaSettings val nopredef = BooleanSetting ("-Yno-predef", "Compile without importing Predef.") val noAdaptedArgs = BooleanSetting ("-Yno-adapted-args", "Do not adapt an argument list (either by inserting () or creating a tuple) to match the receiver.") val Yrecursion = IntSetting ("-Yrecursion", "Set recursion depth used when locking symbols.", 0, Some((0, Int.MaxValue)), (_: String) => None) - val selfInAnnots = BooleanSetting ("-Yself-in-annots", "Include a \"self\" identifier inside of annotations.") val Xshowtrees = BooleanSetting ("-Yshow-trees", "(Requires -Xprint:) Print detailed ASTs in formatted form.") val XshowtreesCompact = BooleanSetting ("-Yshow-trees-compact", "(Requires -Xprint:) Print detailed ASTs in compact form.") diff --git a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala index 4b9e056df3..c2d0f5ccec 100644 --- a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala @@ -64,8 +64,10 @@ abstract class BrowsingLoaders extends GlobalSymbolLoaders { addPackagePrefix(pre) packagePrefix += ("." + name) case Ident(name) => - if (packagePrefix.length != 0) packagePrefix += "." - packagePrefix += name + if (name != nme.EMPTY_PACKAGE_NAME) { // mirrors logic in Namers, see createPackageSymbol + if (packagePrefix.length != 0) packagePrefix += "." + packagePrefix += name + } case _ => throw new MalformedInput(pkg.pos.point, "illegal tree node in package prefix: "+pkg) } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 2b96961291..2f9cc01c0b 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -515,7 +515,7 @@ abstract class ClassfileParser { val info = readType() val sym = ownerForFlags(jflags).newValue(name.toTermName, NoPosition, sflags) - // Note: the info may be overrwritten later with a generic signature + // Note: the info may be overwritten later with a generic signature // parsed from SignatureATTR sym setInfo { if (jflags.isEnum) ConstantType(Constant(sym)) @@ -665,8 +665,11 @@ abstract class ClassfileParser { // so have to check unsafeTypeParams.isEmpty before worrying about raw type case below, // or we'll create a boatload of needless existentials. else if (classSym.isMonomorphicType || classSym.unsafeTypeParams.isEmpty) tp - // raw type - existentially quantify all type parameters - else debuglogResult(s"raw type from $classSym")(unsafeClassExistentialType(classSym)) + else debuglogResult(s"raw type from $classSym"){ + // raw type - existentially quantify all type parameters + val eparams = typeParamsToExistentials(classSym, classSym.unsafeTypeParams) + newExistentialType(eparams, typeRef(pre, classSym, eparams.map(_.tpeHK))) + } case tp => assert(sig.charAt(index) != '<', s"sig=$sig, index=$index, tp=$tp") tp diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index f704d8ac89..6ca2205881 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -575,23 +575,28 @@ abstract class ICodeReader extends ClassfileParser { case JVM.invokevirtual => val m = pool.getMemberSymbol(u2, static = false); size += 2 code.emit(CALL_METHOD(m, Dynamic)) + method.updateRecursive(m) case JVM.invokeinterface => val m = pool.getMemberSymbol(u2, static = false); size += 4 in.skip(2) code.emit(CALL_METHOD(m, Dynamic)) + // invokeinterface can't be recursive case JVM.invokespecial => val m = pool.getMemberSymbol(u2, static = false); size += 2 val style = if (m.name == nme.CONSTRUCTOR || m.isPrivate) Static(onInstance = true) else SuperCall(m.owner.name) code.emit(CALL_METHOD(m, style)) + method.updateRecursive(m) case JVM.invokestatic => val m = pool.getMemberSymbol(u2, static = true); size += 2 if (isBox(m)) code.emit(BOX(toTypeKind(m.info.paramTypes.head))) else if (isUnbox(m)) code.emit(UNBOX(toTypeKind(m.info.resultType))) - else + else { code.emit(CALL_METHOD(m, Static(onInstance = false))) + method.updateRecursive(m) + } 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.") diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index ce3e7b1bb5..55f45257dc 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -55,23 +55,26 @@ abstract class Pickler extends SubComponent { case _ => } } - // If there are any erroneous types in the tree, then we will crash - // when we pickle it: so let's report an error instead. We know next - // to nothing about what happened, but our supposition is a lot better - // than "bad type: <error>" in terms of explanatory power. - for (t <- unit.body) { - if (t.isErroneous) { - unit.error(t.pos, "erroneous or inaccessible type") - return - } - if (!t.isDef && t.hasSymbolField && t.symbol.isTermMacro) { - unit.error(t.pos, "macro has not been expanded") - return - } + try { + pickle(unit.body) + } catch { + case e: FatalError => + for (t <- unit.body) { + // If there are any erroneous types in the tree, then we will crash + // when we pickle it: so let's report an error instead. We know next + // to nothing about what happened, but our supposition is a lot better + // than "bad type: <error>" in terms of explanatory power. + // + // OPT: do this only as a recovery after fatal error. Checking in advance was expensive. + if (t.isErroneous) { + if (settings.debug) e.printStackTrace() + unit.error(t.pos, "erroneous or inaccessible type") + return + } + } + throw e } - - pickle(unit.body) } } @@ -238,9 +241,8 @@ abstract class Pickler extends SubComponent { case ExistentialType(tparams, restpe) => putType(restpe) putSymbols(tparams) - case AnnotatedType(_, underlying, selfsym) => + case AnnotatedType(_, underlying) => putType(underlying) - if (settings.selfInAnnots) putSymbol(selfsym) tp.staticAnnotations foreach putAnnotation case _ => throw new FatalError("bad type: " + tp + "(" + tp.getClass + ")") @@ -450,7 +452,7 @@ abstract class Pickler extends SubComponent { case PolyType(tparams, restpe) => writeRef(restpe); writeRefs(tparams) case ExistentialType(tparams, restpe) => writeRef(restpe); writeRefs(tparams) case StaticallyAnnotatedType(annots, tp) => writeRef(tp) ; writeRefs(annots) - case AnnotatedType(_, tp, _) => writeTypeBody(tp) // write the underlying type if there are no static annotations + case AnnotatedType(_, tp) => writeTypeBody(tp) // write the underlying type if there are no static annotations case CompoundType(parents, _, clazz) => writeRef(clazz); writeRefs(parents) } diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala index 933a2f70a1..d81a5d5755 100644 --- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala +++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala @@ -232,6 +232,10 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre val parents = addSerializable(abstractFunctionErasedType) val funOwner = originalFunction.symbol.owner + // TODO harmonize the naming of delamdafy anon-fun classes with those spun up by Uncurry + // - make `anonClass.isAnonymousClass` true. + // - use `newAnonymousClassSymbol` or push the required variations into a similar factory method + // - reinstate the assertion in `Erasure.resolveAnonymousBridgeClash` val suffix = "$lambda$" + ( if (funOwner.isPrimaryConstructor) "" else "$" + funOwner.name @@ -282,18 +286,11 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre if (sym == NoSymbol) sym.toString else s"$sym: ${sym.tpe} in ${sym.owner}" - def clashError(bm: Symbol) = { - unit.error( - applyMethodDef.symbol.pos, - sm"""bridge generated for member ${fulldef(applyMethodDef.symbol)} - |which overrides ${fulldef(getMember(abstractFunctionErasedType.typeSymbol, nme.apply))} - |clashes with definition of the member itself; - |both have erased type ${exitingPostErasure(bm.tpe)}""") - } - bridgeMethod foreach (bm => + // TODO SI-6260 maybe just create the apply method with the signature (Object => Object) in all cases + // rather than the method+bridge pair. if (bm.symbol.tpe =:= applyMethodDef.symbol.tpe) - clashError(bm.symbol) + erasure.resolveAnonymousBridgeClash(applyMethodDef.symbol, bm.symbol) ) val body = members ++ List(constr, applyMethodDef) ++ bridgeMethod diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 6732900ef2..60c1553ef3 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -61,7 +61,7 @@ abstract class Erasure extends AddInterfaces parents foreach traverse case ClassInfoType(parents, _, _) => parents foreach traverse - case AnnotatedType(_, atp, _) => + case AnnotatedType(_, atp) => traverse(atp) case _ => mapOver(tp) @@ -92,11 +92,22 @@ abstract class Erasure extends AddInterfaces // more rigorous way up front rather than catching it after the fact, // but that will be more involved. private def dotCleanup(sig: String): String = { + // OPT 50% of time in generic signatures (~1% of compile time) was in this method, hence the imperative rewrite. var last: Char = '\u0000' - sig map { - case '.' if last != '>' => last = '.' ; '$' - case ch => last = ch ; ch + var i = 0 + val len = sig.length + val copy: Array[Char] = sig.toCharArray + var changed = false + while (i < sig.length) { + val ch = copy(i) + if (ch == '.' && last != '>') { + copy(i) = '$' + changed = true + } + last = ch + i += 1 } + if (changed) new String(copy) else sig } /** This object is only used for sanity testing when -check:genjvm is set. @@ -302,7 +313,7 @@ abstract class Erasure extends AddInterfaces boxedSig(parent) case ClassInfoType(parents, _, _) => superSig(parents) - case AnnotatedType(_, atp, _) => + case AnnotatedType(_, atp) => jsig(atp, existentiallyBound, toplevel, primitiveOK) case BoundedWildcardType(bounds) => println("something's wrong: "+sym0+":"+sym0.tpe+" has a bounded wildcard type") @@ -392,19 +403,19 @@ abstract class Erasure extends AddInterfaces * @param other The overidden symbol for which the bridge was generated * @param bridge The bridge */ - def checkBridgeOverrides(member: Symbol, other: Symbol, bridge: Symbol): Boolean = { + def checkBridgeOverrides(member: Symbol, other: Symbol, bridge: Symbol): Seq[(Position, String)] = { def fulldef(sym: Symbol) = if (sym == NoSymbol) sym.toString else s"$sym: ${sym.tpe} in ${sym.owner}" var noclash = true + val clashErrors = mutable.Buffer[(Position, String)]() def clashError(what: String) = { - noclash = false - unit.error( - if (member.owner == root) member.pos else root.pos, - sm"""bridge generated for member ${fulldef(member)} - |which overrides ${fulldef(other)} - |clashes with definition of $what; - |both have erased type ${exitingPostErasure(bridge.tpe)}""") + val pos = if (member.owner == root) member.pos else root.pos + val msg = sm"""bridge generated for member ${fulldef(member)} + |which overrides ${fulldef(other)} + |clashes with definition of $what; + |both have erased type ${exitingPostErasure(bridge.tpe)}""" + clashErrors += Tuple2(pos, msg) } for (bc <- root.baseClasses) { if (settings.debug) @@ -429,7 +440,7 @@ abstract class Erasure extends AddInterfaces } } } - noclash + clashErrors } /** TODO - work through this logic with a fine-toothed comb, incorporating @@ -467,8 +478,18 @@ abstract class Erasure extends AddInterfaces bridge setInfo (otpe cloneInfo bridge) bridgeTarget(bridge) = member - if (!(member.tpe exists (_.typeSymbol.isDerivedValueClass)) || - checkBridgeOverrides(member, other, bridge)) { + def sigContainsValueClass = (member.tpe exists (_.typeSymbol.isDerivedValueClass)) + + val shouldAdd = ( + !sigContainsValueClass + || (checkBridgeOverrides(member, other, bridge) match { + case Nil => true + case es if member.owner.isAnonymousClass => resolveAnonymousBridgeClash(member, bridge); true + case es => for ((pos, msg) <- es) unit.error(pos, msg); false + }) + ) + + if (shouldAdd) { exitingErasure(root.info.decls enter bridge) if (other.owner == root) { exitingErasure(root.info.decls.unlink(other)) @@ -522,6 +543,8 @@ abstract class Erasure extends AddInterfaces class Eraser(_context: Context) extends Typer(_context) with TypeAdapter { val typer = this.asInstanceOf[analyzer.Typer] + override protected def stabilize(tree: Tree, pre: Type, mode: Mode, pt: Type): Tree = tree + /** Replace member references as follows: * * - `x == y` for == in class Any becomes `x equals y` with equals in class Object. @@ -760,7 +783,7 @@ abstract class Erasure extends AddInterfaces || super.exclude(sym) || !sym.hasTypeAt(currentRun.refchecksPhase.id) ) - override def matches(sym1: Symbol, sym2: Symbol) = true + override def matches(lo: Symbol, high: Symbol) = true } def isErasureDoubleDef(pair: SymbolPair) = { import pair._ @@ -1114,5 +1137,13 @@ abstract class Erasure extends AddInterfaces } } + final def resolveAnonymousBridgeClash(sym: Symbol, bridge: Symbol) { + // TODO reinstate this after Delambdafy generates anonymous classes that meet this requirement. + // require(sym.owner.isAnonymousClass, sym.owner) + log(s"Expanding name of ${sym.debugLocationString} as it clashes with bridge. Renaming deemed safe because the owner is anonymous.") + sym.expandName(sym.owner) + bridge.resetFlag(BRIDGE) + } + private class TypeRefAttachment(val tpe: TypeRef) } diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala index 4222c4d8c8..bbd11efa7e 100644 --- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala +++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala @@ -24,15 +24,21 @@ abstract class OverridingPairs extends SymbolPairs { /** Symbols to exclude: Here these are constructors and private/artifact symbols, * including bridges. But it may be refined in subclasses. */ - override protected def exclude(sym: Symbol) = (sym hasFlag PRIVATE | ARTIFACT) || sym.isConstructor + override protected def exclude(sym: Symbol) = ( + sym.isPrivateLocal + || sym.isArtifact + || sym.isConstructor + || (sym.isPrivate && sym.owner != base) // Privates aren't inherited. Needed for pos/t7475a.scala + ) /** Types always match. Term symbols match if their member types * relative to `self` match. */ - override protected def matches(sym1: Symbol, sym2: Symbol) = sym1.isType || ( - (sym1.owner != sym2.owner) - && !exclude(sym2) - && relatively.matches(sym1, sym2) - ) + override protected def matches(lo: Symbol, high: Symbol) = lo.isType || ( + (lo.owner != high.owner) // don't try to form pairs from overloaded members + && !high.isPrivate // private or private[this] members never are overriden + && !exclude(lo) // this admits private, as one can't have a private member that matches a less-private member. + && relatively.matches(lo, high) + ) // TODO we don't call exclude(high), should we? } } diff --git a/src/compiler/scala/tools/nsc/transform/PostErasure.scala b/src/compiler/scala/tools/nsc/transform/PostErasure.scala index cc78e27282..32987fed8c 100644 --- a/src/compiler/scala/tools/nsc/transform/PostErasure.scala +++ b/src/compiler/scala/tools/nsc/transform/PostErasure.scala @@ -8,7 +8,7 @@ package transform /** This phase maps ErasedValueTypes to the underlying unboxed representation and * performs peephole optimizations. */ -trait PostErasure extends InfoTransform with TypingTransformers { +trait PostErasure extends InfoTransform with TypingTransformers with scala.reflect.internal.transform.PostErasure { val global: Global import global._ @@ -19,16 +19,6 @@ trait PostErasure extends InfoTransform with TypingTransformers { def newTransformer(unit: CompilationUnit): Transformer = new PostErasureTransformer(unit) override def changesBaseClasses = false - object elimErasedValueType extends TypeMap { - def apply(tp: Type) = tp match { - case ConstantType(Constant(tp: Type)) => ConstantType(Constant(apply(tp))) - case ErasedValueType(_, underlying) => underlying - case _ => mapOver(tp) - } - } - - def transformInfo(sym: Symbol, tp: Type) = elimErasedValueType(tp) - class PostErasureTransformer(unit: CompilationUnit) extends TypingTransformer(unit) { override def transform(tree: Tree) = { def finish(res: Tree) = logResult(s"Posterasure reduction\n Old: $tree\n New")(res) diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index c505d9dc5f..c59b726076 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -306,6 +306,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { /** Return the specialized name of 'sym' in the given environment. It * guarantees the same result regardless of the map order by sorting * type variables alphabetically. + * + * !!! Is this safe in the face of the following? + * scala> trait T { def foo[A] = 0}; object O extends T { override def foo[B] = 0 } */ private def specializedName(sym: Symbol, env: TypeEnv): TermName = { val tvars = ( @@ -391,13 +394,16 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * enclosing member with the annotation. */ private def needsSpecialization(env: TypeEnv, sym: Symbol): Boolean = ( - !sym.ownerChain.exists(_ hasAnnotation UnspecializedClass) && ( + !hasUnspecializableAnnotation(sym) && ( specializedTypeVars(sym).intersect(env.keySet).diff(wasSpecializedForTypeVars(sym)).nonEmpty || sym.isClassConstructor && (sym.enclClass.typeParams exists (_.isSpecialized)) || isNormalizedMember(sym) && info(sym).typeBoundsIn(env) ) ) + private def hasUnspecializableAnnotation(sym: Symbol): Boolean = + sym.ownerChain.exists(_ hasAnnotation UnspecializedClass) + def isNormalizedMember(m: Symbol) = m.isSpecialized && (info get m exists { case NormalizedMember(_) => true case _ => false @@ -433,12 +439,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { else specializedTypeVars(sym.typeParams zip args collect { case (tp, arg) if tp.isSpecialized => arg }) - case PolyType(tparams, resTpe) => specializedTypeVars(resTpe :: tparams.map(_.info)) + case PolyType(tparams, resTpe) => specializedTypeVars(resTpe :: mapList(tparams)(symInfo)) // OPT // since this method may be run at phase typer (before uncurry, where NMTs are eliminated) case NullaryMethodType(resTpe) => specializedTypeVars(resTpe) - case MethodType(argSyms, resTpe) => specializedTypeVars(resTpe :: argSyms.map(_.tpe)) + case MethodType(argSyms, resTpe) => specializedTypeVars(resTpe :: mapList(argSyms)(symTpe)) // OPT case ExistentialType(_, res) => specializedTypeVars(res) - case AnnotatedType(_, tp, _) => specializedTypeVars(tp) + case AnnotatedType(_, tp) => specializedTypeVars(tp) case TypeBounds(lo, hi) => specializedTypeVars(lo :: hi :: Nil) case RefinedType(parents, _) => parents flatMap specializedTypeVars toSet case _ => immutable.Set.empty @@ -907,16 +913,20 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } if (sym.isMethod) { - val stvars = specializedTypeVars(sym) - if (stvars.nonEmpty) - debuglog("specialized %s on %s".format(sym.fullLocationString, stvars.map(_.name).mkString(", "))) + if (hasUnspecializableAnnotation(sym)) { + List() + } else { + val stvars = specializedTypeVars(sym) + if (stvars.nonEmpty) + debuglog("specialized %s on %s".format(sym.fullLocationString, stvars.map(_.name).mkString(", "))) - val tps1 = if (sym.isConstructor) tps filter (sym.info.paramTypes contains _) else tps - val tps2 = tps1 filter stvars - if (!sym.isDeferred) - addConcreteSpecMethod(sym) + val tps1 = if (sym.isConstructor) tps filter (sym.info.paramTypes contains _) else tps + val tps2 = tps1 filter stvars + if (!sym.isDeferred) + addConcreteSpecMethod(sym) - specializeOn(tps2) + specializeOn(tps2) + } } else Nil } @@ -1098,7 +1108,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case (ThisType(_), _) => unify(tp1.widen, tp2, env, strict) case (_, ThisType(_)) => unify(tp1, tp2.widen, env, strict) case (RefinedType(_, _), RefinedType(_, _)) => env - case (AnnotatedType(_, tp1, _), tp2) => unify(tp2, tp1, env, strict) + case (AnnotatedType(_, tp1), tp2) => unify(tp2, tp1, env, strict) case (ExistentialType(_, res1), _) => unify(tp2, res1, env, strict) case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => unify(List(lo1, hi1), List(lo2, hi2), env, strict) case _ => diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index b471d16ddd..5973c70583 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -128,6 +128,7 @@ abstract class TailCalls extends Transform { logResult(msg)(method.newValue(nme.THIS, pos, SYNTHETIC) setInfo currentClass.typeOfThis) } override def toString = s"${method.name} tparams=$tparams tailPos=$tailPos label=$label label info=${label.info}" + } object EmptyTailContext extends TailContext { @@ -185,6 +186,18 @@ abstract class TailCalls extends Transform { private def noTailContext() = new ClonedTailContext(ctx, tailPos = false) private def yesTailContext() = new ClonedTailContext(ctx, tailPos = true) + + override def transformUnit(unit: CompilationUnit): Unit = { + try { + super.transformUnit(unit) + } finally { + // OPT clear these after each compilation unit + failPositions.clear() + failReasons.clear() + accessed.clear() + } + } + /** Rewrite this tree to contain no tail recursive calls */ def transform(tree: Tree, nctx: TailContext): Tree = { val saved = ctx @@ -218,12 +231,12 @@ abstract class TailCalls extends Transform { */ def fail(reason: String) = { debuglog("Cannot rewrite recursive call at: " + fun.pos + " because: " + reason) - failReasons(ctx) = reason + if (ctx.isMandatory) failReasons(ctx) = reason treeCopy.Apply(tree, noTailTransform(target), transformArgs) } /* Position of failure is that of the tree being considered. */ def failHere(reason: String) = { - failPositions(ctx) = fun.pos + if (ctx.isMandatory) failPositions(ctx) = fun.pos fail(reason) } def rewriteTailCall(recv: Tree): Tree = { @@ -237,7 +250,8 @@ abstract class TailCalls extends Transform { if (!ctx.isEligible) fail("it is neither private nor final so can be overridden") else if (!isRecursiveCall) { - if (receiverIsSuper) failHere("it contains a recursive call targeting a supertype") + if (ctx.isMandatory && receiverIsSuper) // OPT expensive check, avoid unless we will actually report the error + failHere("it contains a recursive call targeting a supertype") else failHere(defaultReason) } else if (!matchesTypeArgs) failHere("it is called recursively with different type arguments") @@ -245,6 +259,11 @@ abstract class TailCalls extends Transform { else if (!receiverIsSame) failHere("it changes type of 'this' on a polymorphic recursive call") else rewriteTailCall(receiver) } + + def isEligible(tree: DefDef) = { + val sym = tree.symbol + !(sym.hasAccessorFlag || sym.isConstructor) + } tree match { case ValDef(_, _, _, _) => @@ -253,7 +272,7 @@ abstract class TailCalls extends Transform { super.transform(tree) - case dd @ DefDef(_, name, _, vparamss0, _, rhs0) if !dd.symbol.hasAccessorFlag => + case dd @ DefDef(_, name, _, vparamss0, _, rhs0) if isEligible(dd) => val newCtx = new DefDefTailContext(dd) if (newCtx.isMandatory && !(newCtx containsRecursiveCall rhs0)) unit.error(tree.pos, "@tailrec annotated method contains no recursive calls") diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 844774e75f..e7ea686bc8 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -105,12 +105,11 @@ abstract class UnCurry extends InfoTransform */ def isByNameRef(tree: Tree) = ( tree.isTerm - && !byNameArgs(tree) && (tree.symbol ne null) && (isByName(tree.symbol)) + && !byNameArgs(tree) ) - // ------- Handling non-local returns ------------------------------------------------- /** The type of a non-local return expression with given argument type */ @@ -457,12 +456,11 @@ abstract class UnCurry extends InfoTransform else super.transform(tree) case UnApply(fn, args) => - val fn1 = transform(fn) - val args1 = transformTrees(fn.symbol.name match { - case nme.unapply => args - case nme.unapplySeq => transformArgs(tree.pos, fn.symbol, args, localTyper.expectedPatternTypes(fn, args)) - case _ => sys.error("internal error: UnApply node has wrong symbol") - }) + val fn1 = transform(fn) + val args1 = fn.symbol.name match { + case nme.unapplySeq => transformArgs(tree.pos, fn.symbol, args, patmat.alignPatterns(tree).expectedTypes) + case _ => args + } treeCopy.UnApply(tree, fn1, args1) case Apply(fn, args) => @@ -686,11 +684,13 @@ abstract class UnCurry extends InfoTransform case Packed(param, tempVal) => (param, tempVal) }.unzip - val rhs1 = localTyper.typedPos(rhs.pos) { - // Patch the method body to refer to the temp vals - val rhsSubstituted = rhs.substituteSymbols(packedParams map (_.symbol), tempVals map (_.symbol)) - // The new method body: { val p$1 = p.asInstanceOf[<dependent type>]; ...; <rhsSubstituted> } - Block(tempVals, rhsSubstituted) + val rhs1 = if (tempVals.isEmpty) rhs else { + localTyper.typedPos(rhs.pos) { + // Patch the method body to refer to the temp vals + val rhsSubstituted = rhs.substituteSymbols(packedParams map (_.symbol), tempVals map (_.symbol)) + // The new method body: { val p$1 = p.asInstanceOf[<dependent type>]; ...; <rhsSubstituted> } + Block(tempVals, rhsSubstituted) + } } (allParams :: Nil, rhs1) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala index 63f4a4bf25..699e98f963 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala @@ -31,6 +31,30 @@ trait MatchTranslation { trait MatchTranslator extends TreeMakers with TreeMakerWarnings { import typer.context + /** A conservative approximation of which patterns do not discern anything. + * They are discarded during the translation. + */ + object WildcardPattern { + def unapply(pat: Tree): Boolean = pat match { + case Bind(nme.WILDCARD, WildcardPattern()) => true // don't skip when binding an interesting symbol! + case Star(WildcardPattern()) => true + case x: Ident => treeInfo.isVarPattern(x) + case Alternative(ps) => ps forall unapply + case EmptyTree => true + case _ => false + } + } + + object PatternBoundToUnderscore { + def unapply(pat: Tree): Boolean = pat match { + case Bind(nme.WILDCARD, _) => true // don't skip when binding an interesting symbol! + case Ident(nme.WILDCARD) => true + case Alternative(ps) => ps forall unapply + case Typed(PatternBoundToUnderscore(), _) => true + case _ => false + } + } + object SymbolBound { def unapply(tree: Tree): Option[(Symbol, Tree)] = tree match { case Bind(_, expr) if hasSym(tree) => Some(tree.symbol -> expr) @@ -86,10 +110,8 @@ trait MatchTranslation { // example check: List[Int] <:< ::[Int] private def extractorStep(): TranslationStep = { - import extractor.{ paramType, treeMaker } - if (!extractor.isTyped) - ErrorUtils.issueNormalTypeError(tree, "Could not typecheck extractor call: "+ extractor)(context) - + def paramType = extractor.aligner.wholeType + import extractor.treeMaker // chain a type-testing extractor before the actual extractor call // it tests the type, checks the outer pointer and casts to the expected type // TODO: the outer check is mandated by the spec for case classes, but we do it for user-defined unapplies as well [SPEC] @@ -355,36 +377,20 @@ trait MatchTranslation { object ExtractorCall { // TODO: check unargs == args def apply(tree: Tree): ExtractorCall = tree match { - case UnApply(unfun, args) => new ExtractorCallRegular(unfun, args) // extractor - case Apply(fun, args) => new ExtractorCallProd(fun, args) // case class + case UnApply(unfun, args) => new ExtractorCallRegular(alignPatterns(tree), unfun, args) // extractor + case Apply(fun, args) => new ExtractorCallProd(alignPatterns(tree), fun, args) // case class } } - abstract class ExtractorCall { + abstract class ExtractorCall(val aligner: PatternAligned) { + import aligner._ def fun: Tree def args: List[Tree] - val nbSubPats = args.length - val starLength = if (hasStar) 1 else 0 - val nonStarLength = args.length - starLength - - // everything okay, captain? - def isTyped: Boolean - def isSeq: Boolean - - private def hasStar = nbSubPats > 0 && isStar(args.last) - private def isNonEmptySeq = nbSubPats > 0 && isSeq - - /** This is special cased so that a single pattern will accept any extractor - * result, even if it's a tuple (SI-6675) - */ - def isSingle = nbSubPats == 1 && !isSeq - - // to which type should the previous binder be casted? - def paramType : Type - - protected def rawSubPatTypes: List[Type] - protected def resultType: Type + // don't go looking for selectors if we only expect one pattern + def rawSubPatTypes = aligner.extractedTypes + def resultInMonad = if (isBool) UnitTpe else typeOfMemberNamedGet(resultType) + def resultType = fun.tpe.finalResultType /** Create the TreeMaker that embodies this extractor call * @@ -407,24 +413,14 @@ trait MatchTranslation { lazy val ignoredSubPatBinders: Set[Symbol] = subPatBinders zip args collect { case (b, PatternBoundToUnderscore()) => b } toSet // do repeated-parameter expansion to match up with the expected number of arguments (in casu, subpatterns) - private def nonStarSubPatTypes = formalTypes(rawInit :+ repeatedType, nonStarLength) + private def nonStarSubPatTypes = aligner.typedNonStarPatterns map (_.tpe) - def subPatTypes: List[Type] = ( - if (rawSubPatTypes.isEmpty || !isSeq) rawSubPatTypes - else if (hasStar) nonStarSubPatTypes :+ sequenceType - else nonStarSubPatTypes - ) - - private def rawGet = typeOfMemberNamedGetOrSelf(resultType) - private def rawInit = rawSubPatTypes dropRight 1 - protected def sequenceType = typeOfLastSelectorOrSelf(rawGet) - protected def elementType = elementTypeOfLastSelectorOrSelf(rawGet) - protected def repeatedType = scalaRepeatedType(elementType) + def subPatTypes: List[Type] = typedPatterns map (_.tpe) - // rawSubPatTypes.last is the Seq, thus there are `rawSubPatTypes.length - 1` non-seq elements in the tuple - protected def firstIndexingBinder = rawSubPatTypes.length - 1 - protected def lastIndexingBinder = nbSubPats - 1 - starLength - protected def expectedLength = lastIndexingBinder - firstIndexingBinder + 1 + // there are `productArity` non-seq elements in the tuple. + protected def firstIndexingBinder = productArity + protected def expectedLength = elementArity + protected def lastIndexingBinder = totalArity - starArity - 1 private def productElemsToN(binder: Symbol, n: Int): List[Tree] = 1 to n map tupleSel(binder) toList private def genTake(binder: Symbol, n: Int): List[Tree] = (0 until n).toList map (codegen index seqTree(binder)) @@ -438,12 +434,12 @@ trait MatchTranslation { // referenced by `binder` protected def subPatRefsSeq(binder: Symbol): List[Tree] = { def lastTrees: List[Tree] = ( - if (!hasStar) Nil + if (!aligner.isStar) Nil else if (expectedLength == 0) seqTree(binder) :: Nil else genDrop(binder, expectedLength) ) // this error-condition has already been checked by checkStarPatOK: - // if(isSeq) assert(firstIndexingBinder + nbIndexingIndices + (if(lastIsStar) 1 else 0) == nbSubPats, "(resultInMonad, ts, subPatTypes, subPats)= "+(resultInMonad, ts, subPatTypes, subPats)) + // if(isSeq) assert(firstIndexingBinder + nbIndexingIndices + (if(lastIsStar) 1 else 0) == totalArity, "(resultInMonad, ts, subPatTypes, subPats)= "+(resultInMonad, ts, subPatTypes, subPats)) // [1] there are `firstIndexingBinder` non-seq tuple elements preceding the Seq // [2] then we have to index the binder that represents the sequence for the remaining subpatterns, except for... @@ -457,8 +453,10 @@ trait MatchTranslation { // the trees that select the subpatterns on the extractor's result, referenced by `binder` // require (nbSubPats > 0 && (!lastIsStar || isSeq)) - protected def subPatRefs(binder: Symbol): List[Tree] = - if (isNonEmptySeq) subPatRefsSeq(binder) else productElemsToN(binder, nbSubPats) + protected def subPatRefs(binder: Symbol): List[Tree] = ( + if (totalArity > 0 && isSeq) subPatRefsSeq(binder) + else productElemsToN(binder, totalArity) + ) private def compareInts(t1: Tree, t2: Tree) = gen.mkMethodCall(termMember(ScalaPackage, "math"), TermName("signum"), Nil, (t1 INT_- t2) :: Nil) @@ -478,7 +476,7 @@ trait MatchTranslation { // when the last subpattern is a wildcard-star the expectedLength is but a lower bound // (otherwise equality is required) def compareOp: (Tree, Tree) => Tree = - if (hasStar) _ INT_>= _ + if (aligner.isStar) _ INT_>= _ else _ INT_== _ // `if (binder != null && $checkExpectedLength [== | >=] 0) then else zero` @@ -487,26 +485,14 @@ trait MatchTranslation { def checkedLength: Option[Int] = // no need to check unless it's an unapplySeq and the minimal length is non-trivially satisfied - if (!isSeq || expectedLength < starLength) None + if (!isSeq || expectedLength < starArity) None else Some(expectedLength) } // TODO: to be called when there's a def unapplyProd(x: T): U // U must have N members _1,..., _N -- the _i are type checked, call their type Ti, // for now only used for case classes -- pretending there's an unapplyProd that's the identity (and don't call it) - class ExtractorCallProd(val fun: Tree, val args: List[Tree]) extends ExtractorCall { - private def constructorTp = fun.tpe - - def isTyped = fun.isTyped - - // to which type should the previous binder be casted? - def paramType = constructorTp.finalResultType - def resultType = fun.tpe.finalResultType - - def isSeq = isVarArgTypes(rawSubPatTypes) - - protected def rawSubPatTypes = constructorTp.paramTypes - + class ExtractorCallProd(aligner: PatternAligned, val fun: Tree, val args: List[Tree]) extends ExtractorCall(aligner) { /** Create the TreeMaker that embodies this extractor call * * `binder` has been casted to `paramType` if necessary @@ -535,20 +521,11 @@ trait MatchTranslation { if (accessors isDefinedAt (i-1)) REF(binder) DOT accessors(i-1) else codegen.tupleSel(binder)(i) // this won't type check for case classes, as they do not inherit ProductN } - - override def toString() = s"ExtractorCallProd($fun:${fun.tpe} / ${fun.symbol} / args=$args)" } - class ExtractorCallRegular(extractorCallIncludingDummy: Tree, val args: List[Tree]) extends ExtractorCall { + class ExtractorCallRegular(aligner: PatternAligned, extractorCallIncludingDummy: Tree, val args: List[Tree]) extends ExtractorCall(aligner) { val Unapplied(fun) = extractorCallIncludingDummy - def tpe = fun.tpe - def paramType = firstParamType(tpe) - def resultType = tpe.finalResultType - def isTyped = (tpe ne NoType) && fun.isTyped && (resultInMonad ne ErrorType) - def isSeq = fun.symbol.name == nme.unapplySeq - def isBool = resultType =:= BooleanTpe - /** Create the TreeMaker that embodies this extractor call * * `binder` has been casted to `paramType` if necessary @@ -571,7 +548,7 @@ trait MatchTranslation { ExtractorTreeMaker(extractorApply, lengthGuard(binder), binder)( subPatBinders, subPatRefs(binder), - isBool, + aligner.isBool, checkedLength, patBinderOrCasted, ignoredSubPatBinders @@ -583,9 +560,9 @@ trait MatchTranslation { else super.seqTree(binder) // the trees that select the subpatterns on the extractor's result, referenced by `binder` - // require (nbSubPats > 0 && (!lastIsStar || isSeq)) + // require (totalArity > 0 && (!lastIsStar || isSeq)) override protected def subPatRefs(binder: Symbol): List[Tree] = - if (isSingle) REF(binder) :: Nil // special case for extractors + if (aligner.isSingle) REF(binder) :: Nil // special case for extractors else super.subPatRefs(binder) protected def spliceApply(binder: Symbol): Tree = { @@ -606,40 +583,7 @@ trait MatchTranslation { splice transform extractorCallIncludingDummy } - // what's the extractor's result type in the monad? It is the type of its nullary member `get`. - protected lazy val resultInMonad: Type = if (isBool) UnitTpe else typeOfMemberNamedGet(resultType) - - protected lazy val rawSubPatTypes = ( - if (isBool) Nil - else if (isSingle) resultInMonad :: Nil // don't go looking for selectors if we only expect one pattern - else typesOfSelectorsOrSelf(resultInMonad) - ) - - override def toString() = s"ExtractorCallRegular($fun: $tpe / ${fun.symbol})" - } - - /** A conservative approximation of which patterns do not discern anything. - * They are discarded during the translation. - */ - object WildcardPattern { - def unapply(pat: Tree): Boolean = pat match { - case Bind(nme.WILDCARD, WildcardPattern()) => true // don't skip when binding an interesting symbol! - case Star(WildcardPattern()) => true - case x: Ident => treeInfo.isVarPattern(x) - case Alternative(ps) => ps forall unapply - case EmptyTree => true - case _ => false - } - } - - object PatternBoundToUnderscore { - def unapply(pat: Tree): Boolean = pat match { - case Bind(nme.WILDCARD, _) => true // don't skip when binding an interesting symbol! - case Ident(nme.WILDCARD) => true - case Alternative(ps) => ps forall unapply - case Typed(PatternBoundToUnderscore(), _) => true - case _ => false - } + override def rawSubPatTypes = aligner.extractor.varargsTypes } } } diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala index 7df03044aa..a80f158949 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala @@ -395,8 +395,10 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { debug.patmat("TTTM"+((prevBinder, extractorArgTypeTest, testedBinder, expectedTp, nextBinderTp))) lazy val outerTestNeeded = ( - !((expectedTp.prefix eq NoPrefix) || expectedTp.prefix.typeSymbol.isPackageClass) - && needsOuterTest(expectedTp, testedBinder.info, matchOwner)) + (expectedTp.prefix ne NoPrefix) + && !expectedTp.prefix.typeSymbol.isPackageClass + && needsOuterTest(expectedTp, testedBinder.info, matchOwner) + ) // the logic to generate the run-time test that follows from the fact that // a `prevBinder` is expected to have type `expectedTp` @@ -406,44 +408,52 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { def renderCondition(cs: TypeTestCondStrategy): cs.Result = { import cs._ - def default = - // do type test first to ensure we won't select outer on null - if (outerTestNeeded) and(typeTest(testedBinder, expectedTp), outerTest(testedBinder, expectedTp)) - else typeTest(testedBinder, expectedTp) - // propagate expected type def expTp(t: Tree): t.type = t setType expectedTp + def testedWide = testedBinder.info.widen + def expectedWide = expectedTp.widen + def isAnyRef = testedWide <:< AnyRefTpe + def isAsExpected = testedWide <:< expectedTp + def isExpectedPrimitiveType = isAsExpected && isPrimitiveValueType(expectedTp) + def isExpectedReferenceType = isAsExpected && (expectedTp <:< AnyRefTpe) + def mkNullTest = nonNullTest(testedBinder) + def mkOuterTest = outerTest(testedBinder, expectedTp) + def mkTypeTest = typeTest(testedBinder, expectedWide) + + def mkEqualsTest(lhs: Tree): cs.Result = equalsTest(lhs, testedBinder) + def mkEqTest(lhs: Tree): cs.Result = eqTest(lhs, testedBinder) + def addOuterTest(res: cs.Result): cs.Result = if (outerTestNeeded) and(res, mkOuterTest) else res + + // If we conform to expected primitive type: + // it cannot be null and cannot have an outer pointer. No further checking. + // If we conform to expected reference type: + // have to test outer and non-null + // If we do not conform to expected type: + // have to test type and outer (non-null is implied by successful type test) + def mkDefault = ( + if (isExpectedPrimitiveType) tru + else addOuterTest( + if (isExpectedReferenceType) mkNullTest + else mkTypeTest + ) + ) + // true when called to type-test the argument to an extractor // don't do any fancy equality checking, just test the type - if (extractorArgTypeTest) default + // TODO: verify that we don't need to special-case Array + // I think it's okay: + // - the isInstanceOf test includes a test for the element type + // - Scala's arrays are invariant (so we don't drop type tests unsoundly) + if (extractorArgTypeTest) mkDefault else expectedTp match { - // TODO: [SPEC] the spec requires `eq` instead of `==` for singleton types - // this implies sym.isStable - case SingleType(_, sym) => and(equalsTest(gen.mkAttributedQualifier(expectedTp), testedBinder), typeTest(testedBinder, expectedTp.widen)) - // must use == to support e.g. List() == Nil - case ThisType(sym) if sym.isModule => and(equalsTest(CODE.REF(sym), testedBinder), typeTest(testedBinder, expectedTp.widen)) - case ConstantType(Constant(null)) if testedBinder.info.widen <:< AnyRefTpe - => eqTest(expTp(CODE.NULL), testedBinder) - case ConstantType(const) => equalsTest(expTp(Literal(const)), testedBinder) - case ThisType(sym) => eqTest(expTp(This(sym)), testedBinder) - - // TODO: verify that we don't need to special-case Array - // I think it's okay: - // - the isInstanceOf test includes a test for the element type - // - Scala's arrays are invariant (so we don't drop type tests unsoundly) - case _ if testedBinder.info.widen <:< expectedTp => - // if the expected type is a primitive value type, it cannot be null and it cannot have an outer pointer - // since the types conform, no further checking is required - if (isPrimitiveValueType(expectedTp)) tru - // have to test outer and non-null only when it's a reference type - else if (expectedTp <:< AnyRefTpe) { - // do non-null check first to ensure we won't select outer on null - if (outerTestNeeded) and(nonNullTest(testedBinder), outerTest(testedBinder, expectedTp)) - else nonNullTest(testedBinder) - } else default - - case _ => default + // TODO: [SPEC] the spec requires `eq` instead of `==` for singleton types - this implies sym.isStable + case SingleType(_, sym) => and(mkEqualsTest(gen.mkAttributedQualifier(expectedTp)), mkTypeTest) + case ThisType(sym) if sym.isModule => and(mkEqualsTest(CODE.REF(sym)), mkTypeTest) // must use == to support e.g. List() == Nil + case ConstantType(Constant(null)) if isAnyRef => mkEqTest(expTp(CODE.NULL)) + case ConstantType(const) => mkEqualsTest(expTp(Literal(const))) + case ThisType(sym) => mkEqTest(expTp(This(sym))) + case _ => mkDefault } } diff --git a/src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala b/src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala new file mode 100644 index 0000000000..e84ccbf754 --- /dev/null +++ b/src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala @@ -0,0 +1,155 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Paul Phillips + */ + +package scala +package tools +package nsc +package transform +package patmat + +/** An extractor returns: F1, F2, ..., Fi, opt[Seq[E] or E*] + * A case matches: P1, P2, ..., Pj, opt[Seq[E]] + * Put together: P1/F1, P2/F2, ... Pi/Fi, Pi+1/E, Pi+2/E, ... Pj/E, opt[Seq[E]] + * + * Here Pm/Fi is the last pattern to match the fixed arity section. + * + * productArity: the value of i, i.e. the number of non-sequence types in the extractor + * nonStarArity: the value of j, i.e. the number of non-star patterns in the case definition + * elementArity: j - i, i.e. the number of non-star patterns which must match sequence elements + * starArity: 1 or 0 based on whether there is a star (sequence-absorbing) pattern + * totalArity: nonStarArity + starArity, i.e. the number of patterns in the case definition + * + * Note that productArity is a function only of the extractor, and + * nonStar/star/totalArity are all functions of the patterns. The key + * value for aligning and typing the patterns is elementArity, as it + * is derived from both sets of information. + */ +trait PatternExpander[Pattern, Type] { + /** You'll note we're not inside the cake. "Pattern" and "Type" are + * arbitrary types here, and NoPattern and NoType arbitrary values. + */ + def NoPattern: Pattern + def NoType: Type + + /** It's not optimal that we're carrying both sequence and repeated + * type here, but the implementation requires more unraveling before + * it can be avoided. + * + * sequenceType is Seq[T], elementType is T, repeatedType is T*. + */ + sealed case class Repeated(sequenceType: Type, elementType: Type, repeatedType: Type) { + def exists = elementType != NoType + + def elementList = if (exists) elementType :: Nil else Nil + def sequenceList = if (exists) sequenceType :: Nil else Nil + def repeatedList = if (exists) repeatedType :: Nil else Nil + + override def toString = s"${elementType}*" + } + object NoRepeated extends Repeated(NoType, NoType, NoType) { + override def toString = "<none>" + } + + final case class Patterns(fixed: List[Pattern], star: Pattern) { + def hasStar = star != NoPattern + def starArity = if (hasStar) 1 else 0 + def nonStarArity = fixed.length + def totalArity = nonStarArity + starArity + def starPatterns = if (hasStar) star :: Nil else Nil + def all = fixed ::: starPatterns + + override def toString = all mkString ", " + } + + /** An 'extractor' can be a case class or an unapply or unapplySeq method. + * Decoding what it is that they extract takes place before we arrive here, + * so that this class can concentrate only on the relationship between + * patterns and types. + * + * In a case class, the class is the unextracted type and the fixed and + * repeated types are derived from its constructor parameters. + * + * In an unapply, this is reversed: the parameter to the unapply is the + * unextracted type, and the other types are derived based on the return + * type of the unapply method. + * + * In other words, this case class and unapply are encoded the same: + * + * case class Foo(x: Int, y: Int, zs: Char*) + * def unapplySeq(x: Foo): Option[(Int, Int, Seq[Char])] + * + * Both are Extractor(Foo, Int :: Int :: Nil, Repeated(Seq[Char], Char, Char*)) + * + * @param whole The type in its unextracted form + * @param fixed The non-sequence types which are extracted + * @param repeated The sequence type which is extracted + */ + final case class Extractor(whole: Type, fixed: List[Type], repeated: Repeated) { + require(whole != NoType, s"expandTypes($whole, $fixed, $repeated)") + + def productArity = fixed.length + def hasSeq = repeated.exists + def elementType = repeated.elementType + def sequenceType = repeated.sequenceType + def allTypes = fixed ::: repeated.sequenceList + def varargsTypes = fixed ::: repeated.repeatedList + def isErroneous = allTypes contains NoType + + private def typeStrings = fixed.map("" + _) ::: ( if (hasSeq) List("" + repeated) else Nil ) + + def offeringString = if (isErroneous) "<error>" else typeStrings match { + case Nil => "Boolean" + case tp :: Nil => tp + case tps => tps.mkString("(", ", ", ")") + } + override def toString = "%s => %s".format(whole, offeringString) + } + + final case class TypedPat(pat: Pattern, tpe: Type) { + override def toString = s"$pat: $tpe" + } + + /** If elementArity is... + * 0: A perfect match between extractor and the fixed patterns. + * If there is a star pattern it will match any sequence. + * > 0: There are more patterns than products. There will have to be a + * sequence which can populate at least <elementArity> patterns. + * < 0: There are more products than patterns: compile time error. + */ + final case class Aligned(patterns: Patterns, extractor: Extractor) { + def elementArity = patterns.nonStarArity - productArity + def productArity = extractor.productArity + def starArity = patterns.starArity + def totalArity = patterns.totalArity + + def wholeType = extractor.whole + def sequenceType = extractor.sequenceType + def productTypes = extractor.fixed + def extractedTypes = extractor.allTypes + def typedNonStarPatterns = products ::: elements + def typedPatterns = typedNonStarPatterns ::: stars + + def isBool = !isSeq && productArity == 0 + def isSingle = !isSeq && totalArity == 1 + def isStar = patterns.hasStar + def isSeq = extractor.hasSeq + + private def typedAsElement(pat: Pattern) = TypedPat(pat, extractor.elementType) + private def typedAsSequence(pat: Pattern) = TypedPat(pat, extractor.sequenceType) + private def productPats = patterns.fixed take productArity + private def elementPats = patterns.fixed drop productArity + private def products = (productPats, productTypes).zipped map TypedPat + private def elements = elementPats map typedAsElement + private def stars = patterns.starPatterns map typedAsSequence + + override def toString = s""" + |Aligned { + | patterns $patterns + | extractor $extractor + | arities $productArity/$elementArity/$starArity // product/element/star + | typed ${typedPatterns mkString ", "} + |}""".stripMargin.trim + } +} diff --git a/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala b/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala index 394ba98f17..f6c960d089 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala @@ -34,7 +34,8 @@ import scala.reflect.internal.util.Position * - recover GADT typing by locally inserting implicit witnesses to type equalities derived from the current case, and considering these witnesses during subtyping (?) * - recover exhaustivity/unreachability of user-defined extractors by partitioning the types they match on using an HList or similar type-level structure */ -trait PatternMatching extends Transform with TypingTransformers +trait PatternMatching extends Transform + with TypingTransformers with Debugging with Interface with MatchTranslation @@ -45,7 +46,8 @@ trait PatternMatching extends Transform with TypingTransformers with Solving with MatchAnalysis with MatchOptimization - with MatchWarnings { + with MatchWarnings + with ScalacPatternExpanders { import global._ val phaseName: String = "patmat" diff --git a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala new file mode 100644 index 0000000000..7858cb5586 --- /dev/null +++ b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala @@ -0,0 +1,154 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Paul Phillips + */ + +package scala +package tools +package nsc +package transform +package patmat + +/** This is scalac-specific logic layered on top of the scalac-agnostic + * "matching products to patterns" logic defined in PatternExpander. + */ +trait ScalacPatternExpanders { + val global: Global + + import global._ + import definitions._ + import treeInfo._ + + type PatternAligned = ScalacPatternExpander#Aligned + + implicit class AlignedOps(val aligned: PatternAligned) { + import aligned._ + def expectedTypes = typedPatterns map (_.tpe) + def unexpandedFormals = extractor.varargsTypes + } + trait ScalacPatternExpander extends PatternExpander[Tree, Type] { + def NoPattern = EmptyTree + def NoType = global.NoType + + def newPatterns(patterns: List[Tree]): Patterns = patterns match { + case init :+ last if isStar(last) => Patterns(init, last) + case _ => Patterns(patterns, NoPattern) + } + def elementTypeOf(tpe: Type) = { + val seq = repeatedToSeq(tpe) + + ( typeOfMemberNamedHead(seq) + orElse typeOfMemberNamedApply(seq) + orElse definitions.elementType(ArrayClass, seq) + ) + } + def newExtractor(whole: Type, fixed: List[Type], repeated: Repeated): Extractor = + logResult(s"newExtractor($whole, $fixed, $repeated")(Extractor(whole, fixed, repeated)) + + // Turn Seq[A] into Repeated(Seq[A], A, A*) + def repeatedFromSeq(seqType: Type): Repeated = { + val elem = elementTypeOf(seqType) + val repeated = scalaRepeatedType(elem) + + Repeated(seqType, elem, repeated) + } + // Turn A* into Repeated(Seq[A], A, A*) + def repeatedFromVarargs(repeated: Type): Repeated = + Repeated(repeatedToSeq(repeated), repeatedToSingle(repeated), repeated) + + /** In this case we are basing the pattern expansion on a case class constructor. + * The argument is the MethodType carried by the primary constructor. + */ + def applyMethodTypes(method: Type): Extractor = { + val whole = method.finalResultType + + method.paramTypes match { + case init :+ last if isScalaRepeatedParamType(last) => newExtractor(whole, init, repeatedFromVarargs(last)) + case tps => newExtractor(whole, tps, NoRepeated) + } + } + + /** In this case, expansion is based on an unapply or unapplySeq method. + * Unfortunately the MethodType does not carry the information of whether + * it was unapplySeq, so we have to funnel that information in separately. + */ + def unapplyMethodTypes(method: Type, isSeq: Boolean): Extractor = { + val whole = firstParamType(method) + val result = method.finalResultType + val expanded = ( + if (result =:= BooleanTpe) Nil + else typeOfMemberNamedGet(result) match { + case rawGet if !hasSelectors(rawGet) => rawGet :: Nil + case rawGet => typesOfSelectors(rawGet) + } + ) + expanded match { + case init :+ last if isSeq => newExtractor(whole, init, repeatedFromSeq(last)) + case tps => newExtractor(whole, tps, NoRepeated) + } + } + } + object alignPatterns extends ScalacPatternExpander { + /** Converts a T => (A, B, C) extractor to a T => ((A, B, CC)) extractor. + */ + def tupleExtractor(extractor: Extractor): Extractor = + extractor.copy(fixed = tupleType(extractor.fixed) :: Nil) + + private def validateAligned(tree: Tree, aligned: Aligned): Aligned = { + import aligned._ + + def owner = tree.symbol.owner + def offering = extractor.offeringString + def symString = tree.symbol.fullLocationString + def offerString = if (extractor.isErroneous) "" else s" offering $offering" + def arityExpected = ( if (extractor.hasSeq) "at least " else "" ) + productArity + + def err(msg: String) = currentUnit.error(tree.pos, msg) + def warn(msg: String) = currentUnit.warning(tree.pos, msg) + def arityError(what: String) = err(s"$what patterns for $owner$offerString: expected $arityExpected, found $totalArity") + + if (isStar && !isSeq) + err("Star pattern must correspond with varargs or unapplySeq") + else if (elementArity < 0) + arityError("not enough") + else if (elementArity > 0 && !extractor.hasSeq) + arityError("too many") + + aligned + } + + def apply(sel: Tree, args: List[Tree]): Aligned = { + val fn = sel match { + case Unapplied(fn) => fn + case _ => sel + } + val patterns = newPatterns(args) + val isSeq = sel.symbol.name == nme.unapplySeq + val isUnapply = sel.symbol.name == nme.unapply + val extractor = sel.symbol.name match { + case nme.unapply => unapplyMethodTypes(fn.tpe, isSeq = false) + case nme.unapplySeq => unapplyMethodTypes(fn.tpe, isSeq = true) + case _ => applyMethodTypes(fn.tpe) + } + + /** Rather than let the error that is SI-6675 pollute the entire matching + * process, we will tuple the extractor before creation Aligned so that + * it contains known good values. + */ + def productArity = extractor.productArity + def acceptMessage = if (extractor.isErroneous) "" else s" to hold ${extractor.offeringString}" + val requiresTupling = isUnapply && patterns.totalArity == 1 && productArity > 1 + + if (settings.lint && requiresTupling && effectivePatternArity(args) == 1) + currentUnit.warning(sel.pos, s"${sel.symbol.owner} expects $productArity patterns$acceptMessage but crushing into $productArity-tuple to fit single pattern (SI-6675)") + + val normalizedExtractor = if (requiresTupling) tupleExtractor(extractor) else extractor + validateAligned(fn, Aligned(patterns, normalizedExtractor)) + } + + def apply(tree: Tree): Aligned = tree match { + case Apply(fn, args) => apply(fn, args) + case UnApply(fn, args) => apply(fn, args) + } + } +} diff --git a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala index 0b5b0759b2..1e544e54f6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala @@ -43,11 +43,11 @@ trait Adaptations { def givenString = if (args.isEmpty) "<none>" else args.mkString(", ") def adaptedArgs = if (args.isEmpty) "(): Unit" else args.mkString("(", ", ", "): " + applyArg.tpe) - def adaptWarning(msg: String) = context.warning(t.pos, msg + + def adaptWarningMessage(msg: String, showAdaptation: Boolean = true) = msg + "\n signature: " + sigString + "\n given arguments: " + givenString + - "\n after adaptation: " + callString + "(" + adaptedArgs + ")" - ) + (if (showAdaptation) "\n after adaptation: " + callString + "(" + adaptedArgs + ")" else "") + // A one-argument method accepting Object (which may look like "Any" // at this point if the class is java defined) is a "leaky target" for // which we should be especially reluctant to insert () or auto-tuple. @@ -69,17 +69,20 @@ trait Adaptations { } if (settings.noAdaptedArgs) - adaptWarning("No automatic adaptation here: use explicit parentheses.") - else if (settings.warnAdaptedArgs) - adaptWarning( - if (args.isEmpty) "Adapting argument list by inserting (): " + ( - if (isLeakyTarget) "leaky (Object-receiving) target makes this especially dangerous." - else "this is unlikely to be what you want." - ) - else "Adapting argument list by creating a " + args.size + "-tuple: this may not be what you want." - ) + context.warning(t.pos, adaptWarningMessage("No automatic adaptation here: use explicit parentheses.")) + else if (args.isEmpty) { + if (settings.future) + context.error(t.pos, adaptWarningMessage("Adaptation of argument list by inserting () has been removed.", showAdaptation = false)) + else { + val msg = "Adaptation of argument list by inserting () has been deprecated: " + ( + if (isLeakyTarget) "leaky (Object-receiving) target makes this especially dangerous." + else "this is unlikely to be what you want.") + context.unit.deprecationWarning(t.pos, adaptWarningMessage(msg)) + } + } else if (settings.warnAdaptedArgs) + context.warning(t.pos, adaptWarningMessage(s"Adapting argument list by creating a ${args.size}-tuple: this may not be what you want.")) - !settings.noAdaptedArgs + !settings.noAdaptedArgs || !(args.isEmpty && settings.future) } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala index 94f8f509fc..b899cd8994 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala @@ -186,7 +186,7 @@ trait Checkable { * additional conditions holds: * - either A or B is effectively final * - neither A nor B is a trait (i.e. both are actual classes, not eligible for mixin) - * - both A and B are sealed, and every possible pairing of their children is irreconcilable + * - both A and B are sealed/final, and every possible pairing of their children is irreconcilable * * TODO: the last two conditions of the last possibility (that the symbols are not of * classes being compiled in the current run) are because this currently runs too early, @@ -198,8 +198,9 @@ trait Checkable { isEffectivelyFinal(sym1) // initialization important || isEffectivelyFinal(sym2) || !sym1.isTrait && !sym2.isTrait - || sym1.isSealed && sym2.isSealed && allChildrenAreIrreconcilable(sym1, sym2) && !currentRun.compiles(sym1) && !currentRun.compiles(sym2) + || isSealedOrFinal(sym1) && isSealedOrFinal(sym2) && allChildrenAreIrreconcilable(sym1, sym2) && !currentRun.compiles(sym1) && !currentRun.compiles(sym2) ) + private def isSealedOrFinal(sym: Symbol) = sym.isSealed || sym.isFinal private def isEffectivelyFinal(sym: Symbol): Boolean = ( // initialization important sym.initialize.isEffectivelyFinal || ( diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index cd6b77404d..2043eb5d5d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -418,7 +418,7 @@ trait ContextErrors { case TypeRef(_, _, arg :: _) if arg.typeSymbol == TupleClass(funArity) && funArity > 1 => sm"""| |Note: The expected type requires a one-argument function accepting a $funArity-Tuple. - | Consider a pattern matching anoynmous function, `{ case $example => ... }`""" + | Consider a pattern matching anonymous function, `{ case $example => ... }`""" case _ => "" } case _ => "" @@ -625,8 +625,7 @@ trait ContextErrors { setError(tree) } - def CaseClassConstructorError(tree: Tree) = { - val baseMessage = tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method" + def CaseClassConstructorError(tree: Tree, baseMessage: String) = { val addendum = directUnapplyMember(tree.symbol.info) match { case sym if hasMultipleNonImplicitParamLists(sym) => s"\nNote: ${sym.defString} exists in ${tree.symbol}, but it cannot be used as an extractor due to its second non-implicit parameter list" case _ => "" diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 53bc9a2772..c065fb54b7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -89,6 +89,8 @@ trait Contexts { self: Analyzer => if (settings.noimports) Nil else if (unit.isJava) RootImports.javaList else if (settings.nopredef || treeInfo.noPredefImportForUnit(unit.body)) { + // SI-8258 Needed for the presentation compiler using -sourcepath, otherwise cycles can occur. See the commit + // message for this ticket for an example. debuglog("Omitted import of Predef._ for " + unit) RootImports.javaAndScalaList } @@ -457,7 +459,9 @@ trait Contexts { self: Analyzer => c.prefix = prefixInChild c.enclClass = if (isTemplateOrPackage) c else enclClass c(ConstructorSuffix) = !isTemplateOrPackage && c(ConstructorSuffix) - c.enclMethod = if (isDefDef) c else enclMethod + + // SI-8245 `isLazy` need to skip lazy getters to ensure `return` binds to the right place + c.enclMethod = if (isDefDef && !owner.isLazy) c else enclMethod registerContext(c.asInstanceOf[analyzer.Context]) debuglog("[context] ++ " + c.unit + " / " + tree.summaryString) @@ -1303,7 +1307,7 @@ trait Contexts { self: Analyzer => var renamed = false var selectors = tree.selectors def current = selectors.head - while (selectors.nonEmpty && result == NoSymbol) { + while ((selectors ne Nil) && result == NoSymbol) { if (current.rename == name.toTermName) result = qual.tpe.nonLocalMember( // new to address #2733: consider only non-local members for imports if (name.isTypeName) current.name.toTypeName else current.name) @@ -1353,9 +1357,8 @@ trait Contexts { self: Analyzer => override def toString = tree.toString } - case class ImportType(expr: Tree) extends Type { - override def safeToString = "ImportType("+expr+")" - } + type ImportType = global.ImportType + val ImportType = global.ImportType } object ContextMode { diff --git a/src/compiler/scala/tools/nsc/typechecker/DestructureTypes.scala b/src/compiler/scala/tools/nsc/typechecker/DestructureTypes.scala index 73572bcae9..1f1ccbe359 100644 --- a/src/compiler/scala/tools/nsc/typechecker/DestructureTypes.scala +++ b/src/compiler/scala/tools/nsc/typechecker/DestructureTypes.scala @@ -180,7 +180,7 @@ trait DestructureTypes { case SuperType(thistp, supertp) => product(tp, this("this", thistp), this("super", supertp)) case ThisType(clazz) => product(tp, wrapAtom(clazz)) case TypeVar(inst, constr) => product(tp, this("inst", inst), typeConstraint(constr)) - case AnnotatedType(annotations, underlying, _) => annotatedType(annotations, underlying) + case AnnotatedType(annotations, underlying) => annotatedType(annotations, underlying) case ExistentialType(tparams, underlying) => polyFunction(tparams, underlying) case PolyType(tparams, restpe) => polyFunction(tparams, restpe) case MethodType(params, restpe) => monoFunction(params, restpe) diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index fdec1edcc0..776920ed42 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -137,10 +137,6 @@ trait Implicits { private val improvesCache = perRunCaches.newMap[(ImplicitInfo, ImplicitInfo), Boolean]() private val implicitSearchId = { var id = 1 ; () => try id finally id += 1 } - private def isInvalidConversionTarget(tpe: Type): Boolean = tpe match { - case Function1(_, out) => AnyRefClass.tpe <:< out - case _ => false - } private def isInvalidConversionSource(tpe: Type): Boolean = tpe match { case Function1(in, _) => in <:< NullClass.tpe case _ => false @@ -389,7 +385,7 @@ trait Implicits { private def dominates(dtor: Type, dted: Type): Boolean = { def core(tp: Type): Type = tp.dealiasWiden match { case RefinedType(parents, defs) => intersectionType(parents map core, tp.typeSymbol.owner) - case AnnotatedType(annots, tp, selfsym) => core(tp) + case AnnotatedType(annots, tp) => core(tp) case ExistentialType(tparams, result) => core(result).subst(tparams, tparams map (t => core(t.info.bounds.hi))) case PolyType(tparams, result) => core(result).subst(tparams, tparams map (t => core(t.info.bounds.hi))) case _ => tp @@ -629,7 +625,8 @@ trait Implicits { // for instance, if we have `class C[T]` and `implicit def conv[T: Numeric](c: C[T]) = ???` // then Scaladoc will give us something of type `C[T]`, and it would like to know // that `conv` is potentially available under such and such conditions - case tree if isImplicitMethodType(tree.tpe) && !isScalaDoc => applyImplicitArgs(tree) + case tree if isImplicitMethodType(tree.tpe) && !isScalaDoc => + applyImplicitArgs(tree) case tree => tree } case _ => fallback @@ -791,7 +788,7 @@ trait Implicits { final class LocalShadower extends Shadower { val shadowed = util.HashSet[Name](512) def addInfos(infos: Infos) { - shadowed addEntries infos.map(_.name) + infos.foreach(i => shadowed.addEntry(i.name)) } def isShadowed(name: Name) = shadowed(name) } @@ -808,7 +805,6 @@ trait Implicits { private def isIneligible(info: ImplicitInfo) = ( info.isCyclicOrErroneous || isView && (info.sym eq Predef_conforms) - || shadower.isShadowed(info.name) || (!context.macrosEnabled && info.sym.isTermMacro) ) @@ -817,6 +813,7 @@ trait Implicits { def survives(info: ImplicitInfo) = ( !isIneligible(info) // cyclic, erroneous, shadowed, or specially excluded && isPlausiblyCompatible(info.tpe, wildPt) // optimization to avoid matchesPt + && !shadower.isShadowed(info.name) // OPT rare, only check for plausible candidates && matchesPt(info) // stable and matches expected type ) /** The implicits that are not valid because they come later in the source and @@ -1060,7 +1057,7 @@ trait Implicits { getParts(restpe) case RefinedType(ps, _) => for (p <- ps) getParts(p) - case AnnotatedType(_, t, _) => + case AnnotatedType(_, t) => getParts(t) case ExistentialType(_, t) => getParts(t) @@ -1145,7 +1142,7 @@ trait Implicits { gen.mkAttributedThis(thisSym) case _ => // if `pre` is not a PDT, e.g. if someone wrote - // implicitly[scala.reflect.macros.BlackboxContext#TypeTag[Int]] + // implicitly[scala.reflect.macros.blackbox.Context#TypeTag[Int]] // then we need to fail, because we don't know the prefix to use during type reification // upd. we also need to fail silently, because this is a very common situation // e.g. quite often we're searching for BaseUniverse#TypeTag, e.g. for a type tag in any universe @@ -1361,11 +1358,17 @@ trait Implicits { if (context.ambiguousErrors) context.issueAmbiguousError(AmbiguousImplicitTypeError(tree, msg)) } - if (isInvalidConversionTarget(pt)) { - maybeInvalidConversionError("the result type of an implicit conversion must be more specific than AnyRef") - result = SearchFailure + pt match { + case Function1(_, out) => + def prohibit(sym: Symbol) = if (sym.tpe <:< out) { + maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than ${sym.name}") + result = SearchFailure + } + prohibit(AnyRefClass) + if (settings.isScala211) prohibit(AnyValClass) + case _ => false } - else if (isInvalidConversionSource(pt)) { + if (settings.isScala211 && isInvalidConversionSource(pt)) { maybeInvalidConversionError("an expression of type Null is ineligible for implicit conversion") result = SearchFailure } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index dd0923a696..2d6c94349b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -174,7 +174,8 @@ trait Infer extends Checkable { private lazy val stdErrorValue = stdErrorClass.newErrorValue(nme.ERROR) /** The context-dependent inferencer part */ - class Inferencer(context: Context) extends InferencerContextErrors with InferCheckable { + abstract class Inferencer extends InferencerContextErrors with InferCheckable { + def context: Context import InferErrorGen._ /* -- Error Messages --------------------------------------------------- */ @@ -595,6 +596,7 @@ trait Infer extends Checkable { } private[typechecker] def followApply(tp: Type): Type = tp match { + case _ if tp.isError => tp // SI-8228, `ErrorType nonPrivateMember nme.apply` returns an member with an erroneous type! case NullaryMethodType(restp) => val restp1 = followApply(restp) if (restp1 eq restp) tp else restp1 diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index a1e77515a8..677c94e063 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -29,7 +29,7 @@ import Fingerprint._ * Then fooBar needs to point to a static method of the following form: * * def fooBar[T: c.WeakTypeTag] // type tag annotation is optional - * (c: scala.reflect.macros.BlackboxContext) + * (c: scala.reflect.macros.blackbox.Context) * (xs: c.Expr[List[T]]) * : c.Expr[T] = { * ... @@ -67,7 +67,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { * * This solution is very simple, but unfortunately it's also lacking. If we use it, then * signatures of macro defs become transitively dependent on scala-reflect.jar - * (because they refer to macro impls, and macro impls refer to scala.reflect.macros.BlackboxContext/WhiteboxContext defined in scala-reflect.jar). + * (because they refer to macro impls, and macro impls refer to *box.Context defined in scala-reflect.jar). * More details can be found in comments to https://issues.scala-lang.org/browse/SI-5940. * * Therefore we have to avoid putting macro impls into binding pickles and come up with our own serialization format. @@ -81,9 +81,9 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { * and various accounting information necessary when composing an argument list for the reflective invocation. */ case class MacroImplBinding( - // Is this macro impl a bundle (a trait extending BlackboxMacro or WhiteboxMacro) or a vanilla def? + // Is this macro impl a bundle (a trait extending *box.Macro) or a vanilla def? val isBundle: Boolean, - // Is this macro impl blackbox (i.e. having BlackboxContext in its signature)? + // Is this macro impl blackbox (i.e. having blackbox.Context in its signature)? val isBlackbox: Boolean, // Java class name of the class that contains the macro implementation // is used to load the corresponding object with Java reflection @@ -97,8 +97,8 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { // * c.Expr[T] => LiftedTyped // * c.Tree => LiftedUntyped // * c.WeakTypeTag[T] => Tagged(index of the type parameter corresponding to that type tag) - // * everything else (e.g. scala.reflect.macros.BlackboxContext/WhiteboxContext) => Other - // f.ex. for: def impl[T: WeakTypeTag, U, V: WeakTypeTag](c: BlackboxContext)(x: c.Expr[T], y: c.Tree): (U, V) = ??? + // * everything else (e.g. *box.Context) => Other + // f.ex. for: def impl[T: WeakTypeTag, U, V: WeakTypeTag](c: blackbox.Context)(x: c.Expr[T], y: c.Tree): (U, V) = ??? // `signature` will be equal to List(List(Other), List(LiftedTyped, LiftedUntyped), List(Tagged(0), Tagged(2))) signature: List[List[Fingerprint]], // type arguments part of a macro impl ref (the right-hand side of a macro definition) @@ -116,7 +116,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { * with synthetic content that carries the payload described in `MacroImplBinding`. * * For example, for a pair of macro definition and macro implementation: - * def impl(c: scala.reflect.macros.BlackboxContext): c.Expr[Unit] = ??? + * def impl(c: scala.reflect.macros.blackbox.Context): c.Expr[Unit] = ??? * def foo: Unit = macro impl * * We will have the following annotation added on the macro definition `foo`: @@ -478,7 +478,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { } /** Keeps track of macros in-flight. - * See more informations in comments to `openMacros` in `scala.reflect.macros.WhiteboxContext`. + * See more informations in comments to `openMacros` in `scala.reflect.macros.whitebox.Context`. */ var _openMacros = List[MacroContext]() def openMacros = _openMacros @@ -620,9 +620,11 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { val expanded1 = atPos(enclosingMacroPosition.makeTransparent)(Typed(expanded0, TypeTree(innerPt))) typecheck("blackbox typecheck", expanded1, outerPt) } else { - val expanded1 = expanded0 - val expanded2 = typecheck("whitebox typecheck #1", expanded1, outerPt) - typecheck("whitebox typecheck #2", expanded2, innerPt) + // whitebox expansions need to be typechecked against WildcardType first in order to avoid SI-6992 and SI-8048 + // then we typecheck against innerPt, not against outerPt in order to prevent SI-8209 + val expanded1 = typecheck("whitebox typecheck #0", expanded0, WildcardType) + val expanded2 = typecheck("whitebox typecheck #1", expanded1, innerPt) + typecheck("whitebox typecheck #2", expanded2, outerPt) } } override def onDelayed(delayed: Tree) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index ec2b7d49f5..ba183fe3e6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -427,7 +427,7 @@ trait MethodSynthesis { override def derivedSym = basisSym.lazyAccessor override def derivedTree: DefDef = { val ValDef(_, _, tpt0, rhs0) = tree - val rhs1 = transformed.getOrElse(rhs0, rhs0) + val rhs1 = context.unit.transformed.getOrElse(rhs0, rhs0) val body = ( if (tree.symbol.owner.isTrait || hasUnitType(basisSym)) rhs1 else gen.mkAssignAndReturn(basisSym, rhs1) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 51fbb390ed..9b5b0e1f37 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -122,10 +122,31 @@ trait Namers extends MethodSynthesis { || (vd.mods.isPrivateLocal && !vd.mods.isCaseAccessor) || (vd.name startsWith nme.OUTER) || (context.unit.isJava) + || isEnumConstant(vd) ) + def noFinishGetterSetter(vd: ValDef) = ( (vd.mods.isPrivateLocal && !vd.mods.isLazy) // all lazy vals need accessors, even private[this] - || vd.symbol.isModuleVar) + || vd.symbol.isModuleVar + || isEnumConstant(vd)) + + /** Determines whether this field holds an enum constant. + * To qualify, the following conditions must be met: + * - The field's class has the ENUM flag set + * - The field's class extends java.lang.Enum + * - The field has the ENUM flag set + * - The field is static + * - The field is stable + */ + def isEnumConstant(vd: ValDef) = { + val ownerHasEnumFlag = + // Necessary to check because scalac puts Java's static members into the companion object + // while Scala's enum constants live directly in the class. + // We don't check for clazz.superClass == JavaEnumClass, because this causes a illegal + // cyclic reference error. See the commit message for details. + if (context.unit.isJava) owner.companionClass.hasEnumFlag else owner.hasEnumFlag + vd.mods.hasAllFlags(ENUM | STABLE | STATIC) && ownerHasEnumFlag + } def setPrivateWithin[T <: Symbol](tree: Tree, sym: T, mods: Modifiers): T = if (sym.isPrivateLocal || !mods.hasAccessBoundary) sym @@ -638,11 +659,7 @@ trait Namers extends MethodSynthesis { else enterGetterSetter(tree) - // When java enums are read from bytecode, they are known to have - // constant types by the jvm flag and assigned accordingly. When - // they are read from source, the java parser marks them with the - // STABLE flag, and now we receive that signal. - if (tree.symbol hasAllFlags STABLE | JAVA) + if (isEnumConstant(tree)) tree.symbol setInfo ConstantType(Constant(tree.symbol)) } @@ -1070,8 +1087,9 @@ trait Namers extends MethodSynthesis { } def overriddenSymbol(resTp: Type) = { + lazy val schema: Type = methodTypeSchema(resTp) // OPT create once. Must be lazy to avoid cycles in neg/t5093.scala intersectionType(methOwner.info.parents).nonPrivateMember(meth.name).filter { sym => - sym != NoSymbol && (site.memberType(sym) matches methodTypeSchema(resTp)) + sym != NoSymbol && (site.memberType(sym) matches schema) } } // TODO: see whether this or something similar would work instead: @@ -1205,7 +1223,7 @@ trait Namers extends MethodSynthesis { * flag. */ private def addDefaultGetters(meth: Symbol, ddef: DefDef, vparamss: List[List[ValDef]], tparams: List[TypeDef], overriddenSymbol: => Symbol) { - val DefDef(_, _, rtparams0, rvparamss0, _, _) = resetLocalAttrs(ddef.duplicate) + val DefDef(_, _, rtparams0, rvparamss0, _, _) = resetAttrs(ddef.duplicate) // having defs here is important to make sure that there's no sneaky tree sharing // in methods with multiple default parameters def rtparams = rtparams0.map(_.duplicate) @@ -1292,7 +1310,7 @@ trait Namers extends MethodSynthesis { return // fix #3649 (prevent crash in erroneous source code) } } - val ClassDef(_, _, rtparams, _) = resetLocalAttrs(cdef.duplicate) + val ClassDef(_, _, rtparams, _) = resetAttrs(cdef.duplicate) defTparams = rtparams.map(rt => copyTypeDef(rt)(mods = rt.mods &~ (COVARIANT | CONTRAVARIANT))) nmr } @@ -1408,12 +1426,18 @@ trait Namers extends MethodSynthesis { if (expr1.isErrorTyped) ErrorType else { - if (!treeInfo.isStableIdentifierPattern(expr1)) - typer.TyperErrorGen.UnstableTreeError(expr1) + expr1 match { + case This(_) => + // SI-8207 okay, typedIdent expands Ident(self) to C.this which doesn't satisfy the next case + // TODO should we change `typedIdent` not to expand to the `Ident` to a `This`? + case _ if treeInfo.isStableIdentifierPattern(expr1) => + case _ => + typer.TyperErrorGen.UnstableTreeError(expr1) + } val newImport = treeCopy.Import(imp, expr1, selectors).asInstanceOf[Import] checkSelectors(newImport) - transformed(imp) = newImport + context.unit.transformed(imp) = newImport // copy symbol and type attributes back into old expression // so that the structure builder will find it. expr setSymbol expr1.symbol setType expr1.tpe diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 46ff98875f..6a4df415ae 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -173,7 +173,7 @@ trait NamesDefaults { self: Analyzer => // setSymbol below is important because the 'selected' function might be overloaded. by // assigning the correct method symbol, typedSelect will just assign the type. the reason // to still call 'typed' is to correctly infer singleton types, SI-5259. - val selectPos = + val selectPos = if(qual.pos.isRange && baseFun.pos.isRange) qual.pos.union(baseFun.pos).withStart(Math.min(qual.pos.end, baseFun.pos.end)) else baseFun.pos val f = blockTyper.typedOperator(Select(newQual, selected).setSymbol(baseFun1.symbol).setPos(selectPos)) @@ -287,7 +287,7 @@ trait NamesDefaults { self: Analyzer => } else { // TODO In 83c9c764b, we tried to a stable type here to fix SI-7234. But the resulting TypeTree over a - // singleton type without an original TypeTree fails to retypecheck after a resetLocalAttrs (SI-7516), + // singleton type without an original TypeTree fails to retypecheck after a resetAttrs (SI-7516), // which is important for (at least) macros. arg.tpe } @@ -310,7 +310,7 @@ trait NamesDefaults { self: Analyzer => new ChangeOwnerTraverser(context.owner, sym) traverse arg // fixes #4502 if (repeated) arg match { case WildcardStarArg(expr) => expr - case _ => blockTyper typed gen.mkSeqApply(resetLocalAttrs(arg)) + case _ => blockTyper typed gen.mkSeqApply(resetAttrs(arg)) } else arg } Some(atPos(body.pos)(ValDef(sym, body).setType(NoType))) diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala index 069d6d5fb2..cf3f265f0c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala @@ -78,26 +78,34 @@ trait PatternTypers { // Do some ad-hoc overloading resolution and update the tree's symbol and type // do not update the symbol if the tree's symbol's type does not define an unapply member // (e.g. since it's some method that returns an object with an unapply member) - val fun = inPlaceAdHocOverloadingResolution(fun0)(hasUnapplyMember) - def caseClass = fun.tpe.typeSymbol.linkedClassOfClass + val fun = inPlaceAdHocOverloadingResolution(fun0)(hasUnapplyMember) + val caseClass = fun.tpe.typeSymbol.linkedClassOfClass + val member = unapplyMember(fun.tpe) + def resultType = (fun.tpe memberType member).finalResultType + def isEmptyType = resultOfMatchingMethod(resultType, nme.isEmpty)() + def isOkay = ( + resultType.isErroneous + || (resultType <:< BooleanTpe) + || (isEmptyType <:< BooleanTpe) + || member.isMacro + || member.isOverloaded // the whole overloading situation is over the rails + ) // Dueling test cases: pos/overloaded-unapply.scala, run/case-class-23.scala, pos/t5022.scala // A case class with 23+ params has no unapply method. - // A case class constructor be overloaded with unapply methods in the companion. - if (caseClass.isCase && !unapplyMember(fun.tpe).isOverloaded) + // A case class constructor may be overloaded with unapply methods in the companion. + if (caseClass.isCase && !member.isOverloaded) logResult(s"convertToCaseConstructor($fun, $caseClass, pt=$pt)")(convertToCaseConstructor(fun, caseClass, pt)) - else if (hasUnapplyMember(fun)) + else if (!reallyExists(member)) + CaseClassConstructorError(fun, s"${fun.symbol} is not a case class, nor does it have an unapply/unapplySeq member") + else if (isOkay) fun + else if (isEmptyType == NoType) + CaseClassConstructorError(fun, s"an unapply result must have a member `def isEmpty: Boolean") else - CaseClassConstructorError(fun) + CaseClassConstructorError(fun, s"an unapply result must have a member `def isEmpty: Boolean (found: def isEmpty: $isEmptyType)") } - def expectedPatternTypes(fun: Tree, args: List[Tree]): List[Type] = - newExtractorShape(fun, args).expectedPatternTypes - - def typedPatternArgs(fun: Tree, args: List[Tree], mode: Mode): List[Tree] = - typedArgsForFormals(args, newExtractorShape(fun, args).formals, mode) - def typedArgsForFormals(args: List[Tree], formals: List[Type], mode: Mode): List[Tree] = { def typedArgWithFormal(arg: Tree, pt: Type) = { val newMode = if (isByNameParamType(pt)) mode.onlySticky else mode.onlySticky | BYVALmode @@ -158,109 +166,6 @@ trait PatternTypers { case _ => wrapClassTagUnapply(treeTyped, extractor, tpe) } } - - def newExtractorShape(fun: Tree, args: List[Tree]): ExtractorShape = ExtractorShape(fun, args) - - case class CaseClassInfo(clazz: Symbol, classType: Type) { - def constructor = clazz.primaryConstructor - def constructorType = classType.prefix memberType clazz memberType constructor - def accessors = clazz.caseFieldAccessors - } - object NoCaseClassInfo extends CaseClassInfo(NoSymbol, NoType) { - override def toString = "NoCaseClassInfo" - } - - case class UnapplyMethodInfo(unapply: Symbol, tpe: Type) { - def name = unapply.name - def isUnapplySeq = name == nme.unapplySeq - def unapplyType = tpe memberType method - def resultType = tpe.finalResultType - def method = unapplyMember(tpe) - def paramType = firstParamType(unapplyType) - def rawGet = if (isBool) UnitTpe else typeOfMemberNamedGetOrSelf(resultType) - def rawTypes = if (isBool) Nil else typesOfSelectorsOrSelf(rawGet) - def isBool = resultType =:= BooleanTpe // aka "Tuple0" or "Option[Unit]" - } - - object NoUnapplyMethodInfo extends UnapplyMethodInfo(NoSymbol, NoType) { - override def toString = "NoUnapplyMethodInfo" - } - - case class ExtractorShape(fun: Tree, args: List[Tree]) { - def pos = fun.pos - private def symbol = fun.symbol - private def tpe = fun.tpe - - val ccInfo = tpe.typeSymbol.linkedClassOfClass match { - case clazz if clazz.isCase => CaseClassInfo(clazz, tpe) - case _ => NoCaseClassInfo - } - val exInfo = UnapplyMethodInfo(symbol, tpe) - import exInfo.{ rawGet, rawTypes, isUnapplySeq } - - override def toString = s"ExtractorShape($fun, $args)" - - def unapplyMethod = exInfo.method - def unapplyType = exInfo.unapplyType - def unapplyParamType = exInfo.paramType - def enclClass = symbol.enclClass - - // TODO - merge these. The difference between these two methods is that expectedPatternTypes - // expands the list of types so it is the same length as the number of patterns, whereas formals - // leaves the varargs type unexpanded. - def formals = ( - if (isUnapplySeq) productTypes :+ varargsType - else if (elementArity == 0) productTypes - else if (isSingle) squishIntoOne() - else wrongArity(patternFixedArity) - ) - def expectedPatternTypes = elementArity match { - case 0 => productTypes - case _ if elementArity > 0 && isUnapplySeq => productTypes ::: elementTypes - case _ if productArity > 1 && patternFixedArity == 1 => squishIntoOne() - case _ => wrongArity(patternFixedArity) - } - - def elementType = elementTypeOfLastSelectorOrSelf(rawGet) - - private def hasBogusExtractor = directUnapplyMember(tpe).exists && !unapplyMethod.exists - private def expectedArity = "" + productArity + ( if (isUnapplySeq) "+" else "") - private def wrongArityMsg(n: Int) = ( - if (hasBogusExtractor) s"$enclClass does not define a valid extractor method" - else s"wrong number of patterns for $enclClass offering $rawTypes_s: expected $expectedArity, found $n" - ) - private def rawTypes_s = rawTypes match { - case Nil => "()" - case tp :: Nil => "" + tp - case tps => tps.mkString("(", ", ", ")") - } - - private def err(msg: String) = { unit.error(pos, msg) ; throw new TypeError(msg) } - private def wrongArity(n: Int) = err(wrongArityMsg(n)) - - def squishIntoOne() = { - if (settings.lint) - unit.warning(pos, s"$enclClass expects $expectedArity patterns to hold $rawGet but crushing into $productArity-tuple to fit single pattern (SI-6675)") - - rawGet :: Nil - } - // elementArity is the number of non-sequence patterns minus the - // the number of non-sequence product elements returned by the extractor. - // If it is zero, there is a perfect match between those parts, and - // if there is a wildcard star it will match any sequence. - // If it is positive, there are more patterns than products, - // so a sequence will have to fill in the elements. If it is negative, - // there are more products than patterns, which is a compile time error. - def elementArity = patternFixedArity - productArity - def patternFixedArity = treeInfo effectivePatternArity args - def productArity = productTypes.size - def isSingle = !isUnapplySeq && (patternFixedArity == 1) - - def productTypes = if (isUnapplySeq) rawTypes dropRight 1 else rawTypes - def elementTypes = List.fill(elementArity)(elementType) - def varargsType = scalaRepeatedType(elementType) - } - private class VariantToSkolemMap extends TypeMap(trackVariance = true) { private val skolemBuffer = mutable.ListBuffer[TypeSymbol]() @@ -316,10 +221,12 @@ trait PatternTypers { * see test/files/../t5189*.scala */ private def convertToCaseConstructor(tree: Tree, caseClass: Symbol, ptIn: Type): Tree = { - def untrustworthyPt = ( + // TODO SI-7886 / SI-5900 This is well intentioned but doesn't quite hit the nail on the head. + // For now, I've put it completely behind -Xstrict-inference. + val untrustworthyPt = settings.strictInference && ( ptIn =:= AnyTpe || ptIn =:= NothingTpe - || settings.strictInference && ptIn.typeSymbol != caseClass + || ptIn.typeSymbol != caseClass ) val variantToSkolem = new VariantToSkolemMap val caseClassType = tree.tpe.prefix memberType caseClass @@ -365,10 +272,12 @@ trait PatternTypers { case OverloadedType(_, _) => OverloadedUnapplyError(fun) ; ErrorType case _ => UnapplyWithSingleArgError(fun) ; ErrorType } - val shape = newExtractorShape(fun, args) - import shape.{ unapplyParamType, unapplyType, unapplyMethod } + val unapplyMethod = unapplyMember(fun.tpe) + val unapplyType = fun.tpe memberType unapplyMethod + val unapplyParamType = firstParamType(unapplyType) + def isSeq = unapplyMethod.name == nme.unapplySeq - def extractor = extractorForUncheckedType(shape.pos, unapplyParamType) + def extractor = extractorForUncheckedType(fun.pos, unapplyParamType) def canRemedy = unapplyParamType match { case RefinedType(_, decls) if !decls.isEmpty => false case RefinedType(parents, _) if parents exists isUncheckable => false @@ -400,7 +309,8 @@ trait PatternTypers { // the union of the expected type and the inferred type of the argument to unapply val glbType = glb(ensureFullyDefined(pt) :: unapplyArg.tpe_* :: Nil) val wrapInTypeTest = canRemedy && !(fun1.symbol.owner isNonBottomSubClass ClassTagClass) - val args1 = typedPatternArgs(fun1, args, mode) + val formals = patmat.alignPatterns(fun1, args).unexpandedFormals + val args1 = typedArgsForFormals(args, formals, mode) val result = UnApply(fun1, args1) setPos tree.pos setType glbType if (wrapInTypeTest) @@ -463,4 +373,4 @@ trait PatternTypers { } } } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index f5893172e8..916b8a3e0c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -132,11 +132,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans defaultMethodNames.toList.distinct foreach { name => val methods = clazz.info.findMember(name, 0L, requiredFlags = METHOD, stableOnly = false).alternatives - def hasDefaultParam(tpe: Type): Boolean = tpe match { - case MethodType(params, restpe) => (params exists (_.hasDefault)) || hasDefaultParam(restpe) - case _ => false - } - val haveDefaults = methods filter (sym => hasDefaultParam(sym.info) && !nme.isProtectedAccessorName(sym.name)) + val haveDefaults = methods filter (sym => mexists(sym.info.paramss)(_.hasDefault) && !nme.isProtectedAccessorName(sym.name)) if (haveDefaults.lengthCompare(1) > 0) { val owners = haveDefaults map (_.owner) @@ -471,6 +467,11 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // overrideError("may not override parameterized type"); // @M: substSym def checkOverrideAlias() { + // Important: first check the pair has the same kind, since the substitution + // carries high's type parameter's bounds over to low, so that + // type equality doesn't consider potentially different bounds on low/high's type params. + // In b781e25afe this went from using memberInfo to memberType (now lowType/highType), tested by neg/override.scala. + // TODO: was that the right fix? it seems type alias's RHS should be checked by looking at the symbol's info if (pair.sameKind && lowType.substSym(low.typeParams, high.typeParams) =:= highType) () else overrideTypeError() // (1.6) } @@ -1418,7 +1419,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case TypeRef(pre, sym, args) => tree match { case tt: TypeTree if tt.original == null => // SI-7783 don't warn about inferred types - // FIXME: reconcile this check with one in resetAllAttrs + // FIXME: reconcile this check with one in resetAttrs case _ => checkUndesiredProperties(sym, tree.pos) } if(sym.isJavaDefined) @@ -1431,7 +1432,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans private def checkTypeRefBounds(tp: Type, tree: Tree) = { var skipBounds = false tp match { - case AnnotatedType(ann :: Nil, underlying, selfSym) if ann.symbol == UncheckedBoundsClass => + case AnnotatedType(ann :: Nil, underlying) if ann.symbol == UncheckedBoundsClass => skipBounds = true underlying case TypeRef(pre, sym, args) => @@ -1474,7 +1475,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } doTypeTraversal(tree) { - case tp @ AnnotatedType(annots, _, _) => + case tp @ AnnotatedType(annots, _) => applyChecks(annots) case tp => } @@ -1600,6 +1601,10 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } } + private def checkUnexpandedMacro(t: Tree) = + if (!t.isDef && t.hasSymbolField && t.symbol.isTermMacro) + unit.error(t.pos, "macro has not been expanded") + override def transform(tree: Tree): Tree = { val savedLocalTyper = localTyper val savedCurrentApplication = currentApplication @@ -1759,6 +1764,9 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans varianceValidator.traverse(tt.original) // See SI-7872 case _ => } + + checkUnexpandedMacro(result) + result } catch { case ex: TypeError => diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala index 995f98cc2c..57f27a05fd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala +++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala @@ -46,7 +46,7 @@ trait StdAttachments { * The parameter is of type `Any`, because macros can expand both into trees and into annotations. */ def hasMacroExpansionAttachment(any: Any): Boolean = any match { - case tree: Tree => tree.attachments.get[MacroExpansionAttachment].isDefined + case tree: Tree => tree.hasAttachment[MacroExpansionAttachment] case _ => false } @@ -96,7 +96,7 @@ trait StdAttachments { */ def isMacroExpansionSuppressed(tree: Tree): Boolean = ( settings.Ymacroexpand.value == settings.MacroExpand.None // SI-6812 - || tree.attachments.get[SuppressMacroExpansionAttachment.type].isDefined + || tree.hasAttachment[SuppressMacroExpansionAttachment.type] || (tree match { // we have to account for the fact that during typechecking an expandee might become wrapped, // i.e. surrounded by an inferred implicit argument application or by an inferred type argument application. @@ -150,7 +150,7 @@ trait StdAttachments { /** Determines whether a tree should or should not be adapted, * because someone has put MacroImplRefAttachment on it. */ - def isMacroImplRef(tree: Tree): Boolean = tree.attachments.get[MacroImplRefAttachment.type].isDefined + def isMacroImplRef(tree: Tree): Boolean = tree.hasAttachment[MacroImplRefAttachment.type] /** Since mkInvoke, the applyDynamic/selectDynamic/etc desugarer, is disconnected * from typedNamedApply, the applyDynamicNamed argument rewriter, the latter diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index b706e1af6b..06796eca8e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -542,7 +542,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT case TypeRef(pre, _, _) => isThisType(pre) case SingleType(pre, _) => isThisType(pre) case RefinedType(parents, _) => parents exists isThisType - case AnnotatedType(_, tp, _) => isThisType(tp) + case AnnotatedType(_, tp) => isThisType(tp) case _ => false } } diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index f0252251f7..9516f94135 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -380,7 +380,7 @@ trait SyntheticMethods extends ast.TreeDSL { val original = ddef.symbol val newAcc = deriveMethod(ddef.symbol, name => context.unit.freshTermName(name + "$")) { newAcc => newAcc.makePublic - newAcc resetFlag (ACCESSOR | PARAMACCESSOR) + newAcc resetFlag (ACCESSOR | PARAMACCESSOR | OVERRIDE) ddef.rhs.duplicate } // TODO: shouldn't the next line be: `original resetFlag CASEACCESSOR`? diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 58b7c330d9..5971782e37 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -13,7 +13,7 @@ package scala package tools.nsc package typechecker -import scala.collection.{ mutable, immutable } +import scala.collection.{mutable, immutable} import scala.reflect.internal.util.{ BatchSourceFile, Statistics, shortClassOfInstance } import mutable.ListBuffer import symtab.Flags._ @@ -39,7 +39,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // namer calls typer.computeType(rhs) on DefDef / ValDef when tpt is empty. the result // is cached here and re-used in typedDefDef / typedValDef // Also used to cache imports type-checked by namer. - val transformed = new mutable.HashMap[Tree, Tree] + val transformed = new mutable.AnyRefMap[Tree, Tree] final val shortenImports = false @@ -52,7 +52,6 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper //println("resetTyper called") resetContexts() resetImplicits() - transformed.clear() resetDocComments() } @@ -108,7 +107,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val runDefinitions = currentRun.runDefinitions import runDefinitions._ - val infer = new Inferencer(context0) { + private val transformed: mutable.Map[Tree, Tree] = unit.transformed + + val infer = new Inferencer { + def context = Typer.this.context // See SI-3281 re undoLog override def isCoercible(tp: Type, pt: Type) = undoLog undo viewExists(tp, pt) } @@ -555,7 +557,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } val qual = typedQualifier { atPos(tree.pos.makeTransparent) { tree match { - case Ident(_) => Ident(nme.PACKAGEkw) + case Ident(_) => Ident(rootMirror.getPackageObjectWithMember(pre, sym)) case Select(qual, _) => Select(qual, nme.PACKAGEkw) case SelectFromTypeTree(qual, _) => Select(qual, nme.PACKAGEkw) } @@ -579,7 +581,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper * 3. Turn tree type into stable type if possible and required by context. * 4. Give getClass calls a more precise type based on the type of the target of the call. */ - private def stabilize(tree: Tree, pre: Type, mode: Mode, pt: Type): Tree = { + protected def stabilize(tree: Tree, pre: Type, mode: Mode, pt: Type): Tree = { + // Side effect time! Don't be an idiot like me and think you // can move "val sym = tree.symbol" before this line, because // inferExprAlternative side-effects the tree's symbol. @@ -831,7 +834,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper else tpr.typed(withImplicitArgs, mode, pt) } orElse { _ => - val resetTree = resetLocalAttrs(original) + val resetTree = resetAttrs(original) debuglog(s"fallback on implicits: ${tree}/$resetTree") val tree1 = typed(resetTree, mode) // Q: `typed` already calls `pluginsTyped` and `adapt`. the only difference here is that @@ -992,7 +995,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def adaptMismatchedSkolems() = { def canIgnoreMismatch = ( !context.reportErrors && isPastTyper - || tree.attachments.get[MacroExpansionAttachment].isDefined + || tree.hasAttachment[MacroExpansionAttachment] ) def bound = pt match { case ExistentialType(qs, _) => qs @@ -1122,7 +1125,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (treeInfo.isMacroApplication(tree)) adapt(unmarkMacroImplRef(tree), mode, pt, original) else tree } else tree.tpe match { - case atp @ AnnotatedType(_, _, _) if canAdaptAnnotations(tree, this, mode, pt) => // (-1) + case atp @ AnnotatedType(_, _) if canAdaptAnnotations(tree, this, mode, pt) => // (-1) adaptAnnotations(tree, this, mode, pt) case ct @ ConstantType(value) if mode.inNone(TYPEmode | FUNmode) && (ct <:< pt) && canAdaptConstantTypeToLiteral => // (0) adaptConstant(value) @@ -1793,7 +1796,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val impl2 = finishMethodSynthesis(impl1, clazz, context) - if (mdef.symbol == PredefModule) + if (settings.isScala211 && mdef.symbol == PredefModule) ensurePredefParentsAreInSameSourceFile(impl2) treeCopy.ModuleDef(mdef, typedMods, mdef.name, impl2) setType NoType @@ -2206,14 +2209,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper DeprecatedParamNameError(p, n) } } - } - if (meth.isStructuralRefinementMember) - checkMethodStructuralCompatible(ddef) + if (meth.isStructuralRefinementMember) + checkMethodStructuralCompatible(ddef) - if (meth.isImplicit && !meth.isSynthetic) meth.info.paramss match { - case List(param) :: _ if !param.isImplicit => - checkFeature(ddef.pos, ImplicitConversionsFeature, meth.toString) - case _ => + if (meth.isImplicit && !meth.isSynthetic) meth.info.paramss match { + case List(param) :: _ if !param.isImplicit => + checkFeature(ddef.pos, ImplicitConversionsFeature, meth.toString) + case _ => + } } treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType @@ -2280,7 +2283,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper context.scope.unlink(ldef.symbol) val sym2 = namer.enterInScope( context.owner.newLabel(ldef.name, ldef.pos) setInfo MethodType(List(), restpe)) - val rhs2 = typed(resetAllAttrs(ldef.rhs), restpe) + val LabelDef(_, _, rhs1) = resetAttrs(ldef) + val rhs2 = typed(rhs1, restpe) ldef.params foreach (param => param setType param.symbol.tpe) deriveLabelDef(ldef)(_ => rhs2) setSymbol sym2 setType restpe } @@ -2562,7 +2566,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // // Well behaved trees satisfy the property: // - // typed(tree) == typed(resetLocalAttrs(typed(tree)) + // typed(tree) == typed(resetAttrs(typed(tree)) // // Trees constructed without low-level symbol manipulation get this for free; // references to local symbols are cleared by `ResetAttrs`, but bind to the @@ -3300,6 +3304,28 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // calls to the default getters. Example: // foo[Int](a)() ==> foo[Int](a)(b = foo$qual.foo$default$2[Int](a)) checkNotMacro() + + // SI-8111 transformNamedApplication eagerly shuffles around the application to preserve + // evaluation order. During this process, it calls `changeOwner` on symbols that + // are transplanted underneath synthetic temporary vals. + // + // Here, we keep track of the symbols owned by `context.owner` to enable us to + // rollback, so that we don't end up with "orphaned" symbols. + // + // TODO: Find a better way! + // + // Note that duplicating trees would not be enough to fix this problem, we would also need to + // clone local symbols in the duplicated tree to truly isolate things (in the spirit of BodyDuplicator), + // or, better yet, disentangle the logic in `transformNamedApplication` so that we could + // determine whether names/defaults is viable *before* transforming trees. + def ownerOf(sym: Symbol) = if (sym == null || sym == NoSymbol) NoSymbol else sym.owner + val symsOwnedByContextOwner = tree.collect { + case t @ (_: DefTree | _: Function) if ownerOf(t.symbol) == context.owner => t.symbol + } + def rollbackNamesDefaultsOwnerChanges() { + symsOwnedByContextOwner foreach (_.owner = context.owner) + } + val fun1 = transformNamedApplication(Typer.this, mode, pt)(fun, x => x) if (fun1.isErroneous) duplErrTree else { @@ -3328,6 +3354,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (!(context.diagnostic contains note)) context.diagnostic = note :: context.diagnostic doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt) } else { + rollbackNamesDefaultsOwnerChanges() tryTupleApply orElse duplErrorTree(NotEnoughArgsError(tree, fun, missing)) } } @@ -3362,7 +3389,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // instantiate dependent method types, must preserve singleton types where possible (stableTypeFor) -- example use case: // val foo = "foo"; def precise(x: String)(y: x.type): x.type = {...}; val bar : foo.type = precise(foo)(foo) // precise(foo) : foo.type => foo.type - val restpe = mt.resultType(args1 map (arg => gen stableTypeFor arg orElse arg.tpe)) + val restpe = mt.resultType(mapList(args1)(arg => gen stableTypeFor arg orElse arg.tpe)) def ifPatternSkipFormals(tp: Type) = tp match { case MethodType(_, rtp) if (mode.inPatternMode) => rtp case _ => tp @@ -3444,7 +3471,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper /** * Convert an annotation constructor call into an AnnotationInfo. */ - def typedAnnotation(ann: Tree, mode: Mode = EXPRmode, selfsym: Symbol = NoSymbol): AnnotationInfo = { + def typedAnnotation(ann: Tree, mode: Mode = EXPRmode): AnnotationInfo = { var hasError: Boolean = false val pending = ListBuffer[AbsTypeError]() @@ -3493,7 +3520,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper reportAnnotationError(ArrayConstantsError(tree)); None case ann @ Apply(Select(New(tpt), nme.CONSTRUCTOR), args) => - val annInfo = typedAnnotation(ann, mode, NoSymbol) + val annInfo = typedAnnotation(ann, mode) val annType = annInfo.tpe if (!annType.typeSymbol.isSubClass(pt.typeSymbol)) @@ -3605,28 +3632,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } } else { - val typedAnn = if (selfsym == NoSymbol) { + val typedAnn: Tree = { // local dummy fixes SI-5544 val localTyper = newTyper(context.make(ann, context.owner.newLocalDummy(ann.pos))) localTyper.typed(ann, mode, annType) } - else { - // Since a selfsym is supplied, the annotation should have an extra - // "self" identifier in scope for type checking. This is implemented - // by wrapping the rhs in a function like "self => rhs" during type - // checking, and then stripping the "self =>" and substituting in - // the supplied selfsym. - val funcparm = ValDef(NoMods, nme.self, TypeTree(selfsym.info), EmptyTree) - // The .duplicate of annot.constr deals with problems that accur - // if this annotation is later typed again, which the compiler - // sometimes does. The problem is that "self" ident's within - // annot.constr will retain the old symbol from the previous typing. - val func = Function(funcparm :: Nil, ann.duplicate) - val funcType = appliedType(FunctionClass(1), selfsym.info, annType) - val Function(arg :: Nil, rhs) = typed(func, mode, funcType) - - rhs.substituteSymbols(arg.symbol :: Nil, selfsym :: Nil) - } def annInfo(t: Tree): AnnotationInfo = t match { case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) => AnnotationInfo(annType, args, List()).setOriginal(typedAnn).setPos(t.pos) @@ -3744,7 +3754,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper t match { case ExistentialType(tparams, _) => boundSyms ++= tparams - case AnnotatedType(annots, _, _) => + case AnnotatedType(annots, _) => for (annot <- annots; arg <- annot.args) { arg match { case Ident(_) => @@ -3799,7 +3809,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // lifted out of typed1 because it's needed in typedImplicit0 protected def typedTypeApply(tree: Tree, mode: Mode, fun: Tree, args: List[Tree]): Tree = fun.tpe match { case OverloadedType(pre, alts) => - inferPolyAlternatives(fun, args map (_.tpe)) + inferPolyAlternatives(fun, mapList(args)(treeTpe)) val tparams = fun.symbol.typeParams //@M TODO: fun.symbol.info.typeParams ? (as in typedAppliedTypeTree) val args1 = if (sameLength(args, tparams)) { //@M: in case TypeApply we can't check the kind-arities of the type arguments, @@ -3819,7 +3829,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper typedTypeApply(tree, mode, fun setType fun.tpe.widen, args) case PolyType(tparams, restpe) if tparams.nonEmpty => if (sameLength(tparams, args)) { - val targs = args map (_.tpe) + val targs = mapList(args)(treeTpe) checkBounds(tree, NoPrefix, NoSymbol, tparams, targs, "") if (isPredefClassOf(fun.symbol)) typedClassOf(tree, args.head, noGen = true) @@ -4009,39 +4019,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (arg1.isType) { // make sure the annotation is only typechecked once if (ann.tpe == null) { - // an annotated type - val selfsym = - if (!settings.selfInAnnots) - NoSymbol - else - arg1.tpe.selfsym orElse { - /* Implementation limitation: Currently this - * can cause cyclical reference errors even - * when the self symbol is not referenced at all. - * Surely at least some of these cases can be - * fixed by proper use of LazyType's. Lex tinkered - * on this but did not succeed, so is leaving - * it alone for now. Example code with the problem: - * class peer extends Annotation - * class NPE[T <: NPE[T] @peer] - * - * (Note: -Yself-in-annots must be on to see the problem) - * */ - ( context.owner - newLocalDummy (ann.pos) - newValue (nme.self, ann.pos) - setInfo (arg1.tpe.withoutAnnotations) - ) - } - - val ainfo = typedAnnotation(ann, annotMode, selfsym) - val atype0 = arg1.tpe.withAnnotation(ainfo) - val atype = - if ((selfsym != NoSymbol) && (ainfo.refsSymbol(selfsym))) - atype0.withSelfsym(selfsym) - else - atype0 // do not record selfsym if - // this annotation did not need it + val ainfo = typedAnnotation(ann, annotMode) + val atype = arg1.tpe.withAnnotation(ainfo) if (ainfo.isErroneous) // Erroneous annotations were already reported in typedAnnotation @@ -4870,7 +4849,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper typedHigherKindedType(arg, mode, pt) } - val argtypes = args1 map (_.tpe) + val argtypes = mapList(args1)(treeTpe) foreach2(args, tparams) { (arg, tparam) => // note: can't use args1 in selector, because Binds got replaced @@ -4886,20 +4865,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper asym setInfo logResult(s"Updating bounds of ${asym.fullLocationString} in $tree from '$abounds' to")(TypeBounds(lo, hi)) } if (asym != null && asym.isAbstractType) { - // See pos/t1786 to follow what's happening here. - def canEnhanceIdent = ( - asym.hasCompleteInfo - && tparam.exists /* sometimes it is NoSymbol */ - && tparam.hasCompleteInfo /* SI-2940 */ - && !tparam.isFBounded /* SI-2251 */ - && !tparam.isHigherOrderTypeParameter - && !(abounds.hi <:< tbounds.hi) - && asym.isSynthetic /* this limits us to placeholder tparams, excluding named ones */ - ) arg match { - case Bind(_, _) => enhanceBounds() - case Ident(name) if canEnhanceIdent => enhanceBounds() - case _ => + // I removed the Ident() case that partially fixed SI-1786, + // because the stricter bounds being inferred broke e.g., slick + // worse, the fix was compilation order-dependent + // sharpenQuantifierBounds (used in skolemizeExistential) has an alternative fix (SI-6169) that's less invasive + case Bind(_, _) => enhanceBounds() + case _ => } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index ffac29b4b8..cc2d9141ce 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -52,13 +52,13 @@ trait Unapplies extends ast.TreeDSL { } private def constrParamss(cdef: ClassDef): List[List[ValDef]] = { - val ClassDef(_, _, _, Template(_, _, body)) = resetLocalAttrs(cdef.duplicate) + val ClassDef(_, _, _, Template(_, _, body)) = resetAttrs(cdef.duplicate) val DefDef(_, _, _, vparamss, _, _) = treeInfo firstConstructor body vparamss } private def constrTparamsInvariant(cdef: ClassDef): List[TypeDef] = { - val ClassDef(_, _, tparams, _) = resetLocalAttrs(cdef.duplicate) + val ClassDef(_, _, tparams, _) = resetAttrs(cdef.duplicate) val tparamsInvariant = tparams.map(tparam => copyTypeDef(tparam)(mods = tparam.mods &~ (COVARIANT | CONTRAVARIANT))) tparamsInvariant } diff --git a/src/compiler/scala/tools/nsc/util/CharArrayReader.scala b/src/compiler/scala/tools/nsc/util/CharArrayReader.scala index f116e4af34..e6f95eb0d6 100644 --- a/src/compiler/scala/tools/nsc/util/CharArrayReader.scala +++ b/src/compiler/scala/tools/nsc/util/CharArrayReader.scala @@ -46,7 +46,7 @@ abstract class CharArrayReader extends CharArrayReaderData { self => def isUnicodeEscape = charOffset == lastUnicodeOffset /** Advance one character; reducing CR;LF pairs to just LF */ - final def nextChar() { + final def nextChar(): Unit = { if (charOffset >= buf.length) { ch = SU } else { @@ -54,7 +54,10 @@ abstract class CharArrayReader extends CharArrayReaderData { self => ch = c charOffset += 1 if (c == '\\') potentialUnicode() - else if (c < ' ') { skipCR(); potentialLineEnd() } + if (ch < ' ') { + skipCR() + potentialLineEnd() + } } } @@ -74,7 +77,7 @@ abstract class CharArrayReader extends CharArrayReaderData { self => } /** Interpret \\uxxxx escapes */ - private def potentialUnicode() { + private def potentialUnicode() = { def evenSlashPrefix: Boolean = { var p = charOffset - 2 while (p >= 0 && buf(p) == '\\') p -= 1 @@ -105,13 +108,17 @@ abstract class CharArrayReader extends CharArrayReaderData { self => } /** replace CR;LF by LF */ - private def skipCR() { - if (ch == CR) - if (charOffset < buf.length && buf(charOffset) == LF) { - charOffset += 1 - ch = LF + private def skipCR() = + if (ch == CR && charOffset < buf.length) + buf(charOffset) match { + case LF => + charOffset += 1 + ch = LF + case '\\' => + if (lookaheadReader.getu == LF) + potentialUnicode() + case _ => } - } /** Handle line ends */ private def potentialLineEnd() { @@ -132,5 +139,6 @@ abstract class CharArrayReader extends CharArrayReaderData { self => def error(offset: Int, msg: String) = self.error(offset, msg) /** A mystery why CharArrayReader.nextChar() returns Unit */ def getc() = { nextChar() ; ch } + def getu() = { require(buf(charOffset) == '\\') ; ch = '\\' ; charOffset += 1 ; potentialUnicode() ; ch } } } diff --git a/src/compiler/scala/tools/nsc/util/package.scala b/src/compiler/scala/tools/nsc/util/package.scala index 4237f36ade..bd95fdbb50 100644 --- a/src/compiler/scala/tools/nsc/util/package.scala +++ b/src/compiler/scala/tools/nsc/util/package.scala @@ -7,7 +7,7 @@ package scala package tools package nsc -import java.io.{ OutputStream, PrintStream, ByteArrayOutputStream, PrintWriter, StringWriter } +import java.io.{ OutputStream, PrintStream, ByteArrayOutputStream, PrintWriter, StringWriter, Reader } package object util { // forwarder for old code that builds against 2.9 and 2.10 @@ -46,6 +46,17 @@ package object util { (result, ts2 filterNot (ts1 contains _)) } + def stringFromReader(reader: Reader) = { + val writer = new StringWriter() + var c = reader.read() + while(c != -1) { + writer.write(c) + c = reader.read() + } + reader.close() + writer.toString() + } + /** Generate a string using a routine that wants to write on a stream. */ def stringFromWriter(writer: PrintWriter => Unit): String = { val stringWriter = new StringWriter() diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala index bb0bbd79a3..8630ecf69e 100644 --- a/src/compiler/scala/tools/reflect/FastTrack.scala +++ b/src/compiler/scala/tools/reflect/FastTrack.scala @@ -20,8 +20,8 @@ trait FastTrack { private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers - private implicit def context2macroimplementations(c0: MacroContext): MacroImplementations { val c: c0.type } = - new { val c: c0.type = c0 } with MacroImplementations + private implicit def context2macroimplementations(c0: MacroContext): FormatInterpolator { val c: c0.type } = + new { val c: c0.type = c0 } with FormatInterpolator private implicit def context2quasiquote(c0: MacroContext): QuasiquoteImpls { val c: c0.type } = new { val c: c0.type = c0 } with QuasiquoteImpls private def makeBlackbox(sym: Symbol)(pf: PartialFunction[Applied, MacroContext => Tree]) = @@ -48,7 +48,7 @@ trait FastTrack { makeBlackbox( materializeWeakTypeTag) { case Applied(_, ttag :: Nil, (u :: _) :: _) => _.materializeTypeTag(u, EmptyTree, ttag.tpe, concrete = false) }, makeBlackbox( materializeTypeTag) { case Applied(_, ttag :: Nil, (u :: _) :: _) => _.materializeTypeTag(u, EmptyTree, ttag.tpe, concrete = true) }, makeBlackbox( ApiUniverseReify) { case Applied(_, ttag :: Nil, (expr :: _) :: _) => c => c.materializeExpr(c.prefix.tree, EmptyTree, expr) }, - makeBlackbox( StringContext_f) { case Applied(Select(Apply(_, ps), _), _, args) => c => c.macro_StringInterpolation_f(ps, args.flatten, c.expandee.pos) }, + makeBlackbox( StringContext_f) { case _ => _.interpolate }, makeBlackbox(ReflectRuntimeCurrentMirror) { case _ => c => currentMirror(c).tree }, makeWhitebox( QuasiquoteClass_api_apply) { case _ => _.expandQuasiquote }, makeWhitebox(QuasiquoteClass_api_unapply) { case _ => _.expandQuasiquote } diff --git a/src/compiler/scala/tools/reflect/FormatInterpolator.scala b/src/compiler/scala/tools/reflect/FormatInterpolator.scala new file mode 100644 index 0000000000..d5e674ebae --- /dev/null +++ b/src/compiler/scala/tools/reflect/FormatInterpolator.scala @@ -0,0 +1,329 @@ +package scala.tools.reflect + +import scala.reflect.macros.runtime.Context +import scala.collection.mutable.{ ListBuffer, Stack } +import scala.reflect.internal.util.Position +import scala.PartialFunction.cond +import scala.util.matching.Regex.Match + +import java.util.{ Formatter, Formattable, IllegalFormatException } + +abstract class FormatInterpolator { + val c: Context + val global: c.universe.type = c.universe + + import c.universe.{ Match => _, _ } + import definitions._ + import treeInfo.Applied + + @inline private def truly(body: => Unit): Boolean = { body ; true } + @inline private def falsely(body: => Unit): Boolean = { body ; false } + + private def fail(msg: String) = c.abort(c.enclosingPosition, msg) + private def bail(msg: String) = global.abort(msg) + + def interpolate: Tree = c.macroApplication match { + //case q"$_(..$parts).f(..$args)" => + case Applied(Select(Apply(_, parts), _), _, argss) => + val args = argss.flatten + def badlyInvoked = (parts.length != args.length + 1) && truly { + def because(s: String) = s"too $s arguments for interpolated string" + val (p, msg) = + if (parts.length == 0) (c.prefix.tree.pos, "there are no parts") + else if (args.length + 1 < parts.length) + (if (args.isEmpty) c.enclosingPosition else args.last.pos, because("few")) + else (args(parts.length-1).pos, because("many")) + c.abort(p, msg) + } + if (badlyInvoked) c.macroApplication else interpolated(parts, args) + case other => + bail(s"Unexpected application ${showRaw(other)}") + other + } + + /** Every part except the first must begin with a conversion for + * the arg that preceded it. If the conversion is missing, "%s" + * is inserted. + * + * In any other position, the only permissible conversions are + * the literals (%% and %n) or an index reference (%1$ or %<). + * + * A conversion specifier has the form: + * + * [index$][flags][width][.precision]conversion + * + * 1) "...${smth}" => okay, equivalent to "...${smth}%s" + * 2) "...${smth}blahblah" => okay, equivalent to "...${smth}%sblahblah" + * 3) "...${smth}%" => error + * 4) "...${smth}%n" => okay, equivalent to "...${smth}%s%n" + * 5) "...${smth}%%" => okay, equivalent to "...${smth}%s%%" + * 6) "...${smth}[%legalJavaConversion]" => okay* + * 7) "...${smth}[%illegalJavaConversion]" => error + * *Legal according to [[http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html]] + */ + def interpolated(parts: List[Tree], args: List[Tree]) = { + val fstring = new StringBuilder + val evals = ListBuffer[ValDef]() + val ids = ListBuffer[Ident]() + val argStack = Stack(args: _*) + + // create a tmp val and add it to the ids passed to format + def defval(value: Tree, tpe: Type): Unit = { + val freshName = TermName(c.freshName("arg$")) + evals += ValDef(Modifiers(), freshName, TypeTree(tpe) setPos value.pos.focus, value) setPos value.pos + ids += Ident(freshName) + } + // Append the nth part to the string builder, possibly prepending an omitted %s first. + // Sanity-check the % fields in this part. + def copyPart(part: Tree, n: Int): Unit = { + import SpecifierGroups.{ Spec, Index } + val s0 = part match { + case Literal(Constant(x: String)) => x + case _ => throw new IllegalArgumentException("internal error: argument parts must be a list of string literals") + } + val s = StringContext.treatEscapes(s0) + val ms = fpat findAllMatchIn s + + def errorLeading(op: Conversion) = op.errorAt(Spec, s"conversions must follow a splice; ${Conversion.literalHelp}") + + def first = n == 0 + // a conversion for the arg is required + if (!first) { + val arg = argStack.pop() + def s_%() = { + fstring append "%s" + defval(arg, AnyTpe) + } + def accept(op: Conversion) = { + if (!op.isLeading) errorLeading(op) + op.accepts(arg) match { + case Some(tpe) => defval(arg, tpe) + case None => + } + } + if (ms.hasNext) { + Conversion(ms.next, part.pos, args.size) match { + case Some(op) if op.isLiteral => s_%() + case Some(op) if op.indexed => + if (op.index map (_ == n) getOrElse true) accept(op) + else { + // either some other arg num, or '<' + c.warning(op.groupPos(Index), "Index is not this arg") + s_%() + } + case Some(op) => accept(op) + case None => + } + } else s_%() + } + // any remaining conversions must be either literals or indexed + while (ms.hasNext) { + Conversion(ms.next, part.pos, args.size) match { + case Some(op) if first && op.hasFlag('<') => op.badFlag('<', "No last arg") + case Some(op) if op.isLiteral || op.indexed => // OK + case Some(op) => errorLeading(op) + case None => + } + } + fstring append s + } + + parts.zipWithIndex foreach { + case (part, n) => copyPart(part, n) + } + + //q"{..$evals; ${fstring.toString}.format(..$ids)}" + locally { + val expr = + Apply( + Select( + Literal(Constant(fstring.toString)), + newTermName("format")), + ids.toList + ) + val p = c.macroApplication.pos + Block(evals.toList, atPos(p.focus)(expr)) setPos p.makeTransparent + } + } + + val fpat = """%(?:(\d+)\$)?([-#+ 0,(\<]+)?(\d+)?(\.\d+)?([tT]?[%a-zA-Z])?""".r + object SpecifierGroups extends Enumeration { val Spec, Index, Flags, Width, Precision, CC = Value } + + val stdContextTags = new { val tc: c.type = c } with StdContextTags + import stdContextTags._ + val tagOfFormattable = typeTag[Formattable] + + /** A conversion specifier matched by `m` in the string part at `pos`, + * with `argc` arguments to interpolate. + */ + sealed trait Conversion { + def m: Match + def pos: Position + def argc: Int + + import SpecifierGroups.{ Value => SpecGroup, _ } + private def maybeStr(g: SpecGroup) = Option(m group g.id) + private def maybeInt(g: SpecGroup) = maybeStr(g) map (_.toInt) + val index: Option[Int] = maybeInt(Index) + val flags: Option[String] = maybeStr(Flags) + val width: Option[Int] = maybeInt(Width) + val precision: Option[Int] = maybeStr(Precision) map (_.drop(1).toInt) + val op: String = maybeStr(CC) getOrElse "" + + def cc: Char = if ("tT" contains op(0)) op(1) else op(0) + + def indexed: Boolean = index.nonEmpty || hasFlag('<') + def isLiteral: Boolean = false + def isLeading: Boolean = m.start(0) == 0 + def verify: Boolean = goodFlags && goodIndex + def accepts(arg: Tree): Option[Type] + + val allFlags = "-#+ 0,(<" + def hasFlag(f: Char) = (flags getOrElse "") contains f + def hasAnyFlag(fs: String) = fs exists (hasFlag) + + def badFlag(f: Char, msg: String) = { + val i = flags map (_.indexOf(f)) filter (_ >= 0) getOrElse 0 + errorAtOffset(Flags, i, msg) + } + def groupPos(g: SpecGroup) = groupPosAt(g, 0) + def groupPosAt(g: SpecGroup, i: Int) = pos withPoint (pos.point + m.start(g.id) + i) + def errorAt(g: SpecGroup, msg: String) = c.error(groupPos(g), msg) + def errorAtOffset(g: SpecGroup, i: Int, msg: String) = c.error(groupPosAt(g, i), msg) + + def noFlags = flags.isEmpty || falsely { errorAt(Flags, "flags not allowed") } + def noWidth = width.isEmpty || falsely { errorAt(Width, "width not allowed") } + def noPrecision = precision.isEmpty || falsely { errorAt(Precision, "precision not allowed") } + def only_-(msg: String) = { + val badFlags = (flags getOrElse "") filterNot { case '-' | '<' => true case _ => false } + badFlags.isEmpty || falsely { badFlag(badFlags(0), s"Only '-' allowed for $msg") } + } + protected def okFlags: String = allFlags + def goodFlags = { + val badFlags = flags map (_ filterNot (okFlags contains _)) + for (bf <- badFlags; f <- bf) badFlag(f, s"Illegal flag '$f'") + badFlags.getOrElse("").isEmpty + } + def goodIndex = { + if (index.nonEmpty && hasFlag('<')) + c.warning(groupPos(Index), "Argument index ignored if '<' flag is present") + val okRange = index map (i => i > 0 && i <= argc) getOrElse true + okRange || hasFlag('<') || falsely { errorAt(Index, "Argument index out of range") } + } + /** Pick the type of an arg to format from among the variants + * supported by a conversion. This is the type of the temporary, + * so failure results in an erroneous assignment to the first variant. + * A more complete message would be nice. + */ + def pickAcceptable(arg: Tree, variants: Type*): Option[Type] = + variants find (arg.tpe <:< _) orElse ( + variants find (c.inferImplicitView(arg, arg.tpe, _) != EmptyTree) + ) orElse Some(variants(0)) + } + object Conversion { + import SpecifierGroups.{ Spec, CC, Width } + def apply(m: Match, p: Position, n: Int): Option[Conversion] = { + def badCC(msg: String) = { + val dk = new ErrorXn(m, p) + val at = if (dk.op.isEmpty) Spec else CC + dk.errorAt(at, msg) + } + def cv(cc: Char) = cc match { + case 'b' | 'B' | 'h' | 'H' | 's' | 'S' => + new GeneralXn(m, p, n) + case 'c' | 'C' => + new CharacterXn(m, p, n) + case 'd' | 'o' | 'x' | 'X' => + new IntegralXn(m, p, n) + case 'e' | 'E' | 'f' | 'g' | 'G' | 'a' | 'A' => + new FloatingPointXn(m, p, n) + case 't' | 'T' => + new DateTimeXn(m, p, n) + case '%' | 'n' => + new LiteralXn(m, p, n) + case _ => + badCC(s"illegal conversion character '$cc'") + null + } + Option(m group CC.id) map (cc => cv(cc(0))) match { + case Some(x) => Option(x) filter (_.verify) + case None => + badCC(s"Missing conversion operator in '${m.matched}'; $literalHelp") + None + } + } + val literalHelp = "use %% for literal %, %n for newline" + } + class GeneralXn(val m: Match, val pos: Position, val argc: Int) extends Conversion { + def accepts(arg: Tree) = cc match { + case 's' | 'S' if hasFlag('#') => pickAcceptable(arg, tagOfFormattable.tpe) + case 'b' | 'B' => if (arg.tpe <:< NullTpe) Some(NullTpe) else Some(BooleanTpe) + case _ => Some(AnyTpe) + } + override protected def okFlags = cc match { + case 's' | 'S' => "-#<" + case _ => "-<" + } + } + class LiteralXn(val m: Match, val pos: Position, val argc: Int) extends Conversion { + import SpecifierGroups.Width + override val isLiteral = true + override def verify = op match { + case "%" => super.verify && noPrecision && truly(width foreach (_ => c.warning(groupPos(Width), "width ignored on literal"))) + case "n" => noFlags && noWidth && noPrecision + } + override protected val okFlags = "-" + def accepts(arg: Tree) = None + } + class CharacterXn(val m: Match, val pos: Position, val argc: Int) extends Conversion { + override def verify = super.verify && noPrecision && only_-("c conversion") + def accepts(arg: Tree) = pickAcceptable(arg, CharTpe, ByteTpe, ShortTpe, IntTpe) + } + class IntegralXn(val m: Match, val pos: Position, val argc: Int) extends Conversion { + override def verify = { + def d_# = (cc == 'd' && hasFlag('#') && + truly { badFlag('#', "# not allowed for d conversion") } + ) + def x_comma = (cc != 'd' && hasFlag(',') && + truly { badFlag(',', "',' only allowed for d conversion of integral types") } + ) + super.verify && noPrecision && !d_# && !x_comma + } + override def accepts(arg: Tree) = { + def isBigInt = arg.tpe <:< tagOfBigInt.tpe + val maybeOK = "+ (" + def bad_+ = cond(cc) { + case 'o' | 'x' | 'X' if hasAnyFlag(maybeOK) && !isBigInt => + maybeOK filter hasFlag foreach (badf => + badFlag(badf, s"only use '$badf' for BigInt conversions to o, x, X")) + true + } + if (bad_+) None else pickAcceptable(arg, IntTpe, LongTpe, ByteTpe, ShortTpe, tagOfBigInt.tpe) + } + } + class FloatingPointXn(val m: Match, val pos: Position, val argc: Int) extends Conversion { + override def verify = super.verify && (cc match { + case 'a' | 'A' => + val badFlags = ",(" filter hasFlag + noPrecision && badFlags.isEmpty || falsely { + badFlags foreach (badf => badFlag(badf, s"'$badf' not allowed for a, A")) + } + case _ => true + }) + def accepts(arg: Tree) = pickAcceptable(arg, DoubleTpe, FloatTpe, tagOfBigDecimal.tpe) + } + class DateTimeXn(val m: Match, val pos: Position, val argc: Int) extends Conversion { + import SpecifierGroups.CC + def hasCC = (op.length == 2 || + falsely { errorAt(CC, "Date/time conversion must have two characters") }) + def goodCC = ("HIklMSLNpzZsQBbhAaCYyjmdeRTrDFc" contains cc) || + falsely { errorAtOffset(CC, 1, s"'$cc' doesn't seem to be a date or time conversion") } + override def verify = super.verify && hasCC && goodCC && noPrecision && only_-("date/time conversions") + def accepts(arg: Tree) = pickAcceptable(arg, LongTpe, tagOfCalendar.tpe, tagOfDate.tpe) + } + class ErrorXn(val m: Match, val pos: Position) extends Conversion { + val argc = 0 + override def verify = false + def accepts(arg: Tree) = None + } +} diff --git a/src/compiler/scala/tools/reflect/MacroImplementations.scala b/src/compiler/scala/tools/reflect/MacroImplementations.scala deleted file mode 100644 index a9ed419b1e..0000000000 --- a/src/compiler/scala/tools/reflect/MacroImplementations.scala +++ /dev/null @@ -1,171 +0,0 @@ -package scala.tools.reflect - -import scala.reflect.macros.contexts.Context -import scala.collection.mutable.ListBuffer -import scala.collection.mutable.Stack -import scala.reflect.internal.util.Position - -abstract class MacroImplementations { - val c: Context - - import c.universe._ - import definitions._ - - def macro_StringInterpolation_f(parts: List[Tree], args: List[Tree], origApplyPos: c.universe.Position): Tree = { - // the parts all have the same position information (as the expression is generated by the compiler) - // the args have correct position information - - // the following conditions can only be violated if invoked directly - if (parts.length != args.length + 1) { - if(parts.length == 0) - c.abort(c.prefix.tree.pos, "too few parts") - else if(args.length + 1 < parts.length) - c.abort(if(args.length==0) c.enclosingPosition else args.last.pos, - "too few arguments for interpolated string") - else - c.abort(args(parts.length-1).pos, - "too many arguments for interpolated string") - } - - val pi = parts.iterator - val bldr = new java.lang.StringBuilder - val evals = ListBuffer[ValDef]() - val ids = ListBuffer[Ident]() - val argStack = Stack(args : _*) - - def defval(value: Tree, tpe: Type): Unit = { - val freshName = newTermName(c.freshName("arg$")) - evals += ValDef(Modifiers(), freshName, TypeTree(tpe) setPos value.pos.focus, value) setPos value.pos - ids += Ident(freshName) - } - - def isFlag(ch: Char): Boolean = { - ch match { - case '-' | '#' | '+' | ' ' | '0' | ',' | '(' => true - case _ => false - } - } - - def checkType(arg: Tree, variants: Type*): Option[Type] = { - variants.find(arg.tpe <:< _).orElse( - variants.find(c.inferImplicitView(arg, arg.tpe, _) != EmptyTree).orElse( - Some(variants(0)) - ) - ) - } - - val stdContextTags = new { val tc: c.type = c } with StdContextTags - import stdContextTags._ - - def conversionType(ch: Char, arg: Tree): Option[Type] = { - ch match { - case 'b' | 'B' => - if(arg.tpe <:< NullTpe) Some(NullTpe) else Some(BooleanTpe) - case 'h' | 'H' => - Some(AnyTpe) - case 's' | 'S' => - Some(AnyTpe) - case 'c' | 'C' => - checkType(arg, CharTpe, ByteTpe, ShortTpe, IntTpe) - case 'd' | 'o' | 'x' | 'X' => - checkType(arg, IntTpe, LongTpe, ByteTpe, ShortTpe, tagOfBigInt.tpe) - case 'e' | 'E' | 'g' | 'G' | 'f' | 'a' | 'A' => - checkType(arg, DoubleTpe, FloatTpe, tagOfBigDecimal.tpe) - case 't' | 'T' => - checkType(arg, LongTpe, tagOfCalendar.tpe, tagOfDate.tpe) - case _ => None - } - } - - def copyString(first: Boolean): Unit = { - val strTree = pi.next() - val rawStr = strTree match { - case Literal(Constant(str: String)) => str - case _ => throw new IllegalArgumentException("internal error: argument parts must be a list of string literals") - } - val str = StringContext.treatEscapes(rawStr) - val strLen = str.length - val strIsEmpty = strLen == 0 - def charAtIndexIs(idx: Int, ch: Char) = idx < strLen && str(idx) == ch - def isPercent(idx: Int) = charAtIndexIs(idx, '%') - def isConversion(idx: Int) = isPercent(idx) && !charAtIndexIs(idx + 1, 'n') && !charAtIndexIs(idx + 1, '%') - var idx = 0 - - def errorAtIndex(idx: Int, msg: String) = c.error(Position.offset(strTree.pos.source, strTree.pos.point + idx), msg) - def wrongConversionString(idx: Int) = errorAtIndex(idx, "wrong conversion string") - def illegalConversionCharacter(idx: Int) = errorAtIndex(idx, "illegal conversion character") - def nonEscapedPercent(idx: Int) = errorAtIndex(idx, - "conversions must follow a splice; use %% for literal %, %n for newline") - - // STEP 1: handle argument conversion - // 1) "...${smth}" => okay, equivalent to "...${smth}%s" - // 2) "...${smth}blahblah" => okay, equivalent to "...${smth}%sblahblah" - // 3) "...${smth}%" => error - // 4) "...${smth}%n" => okay, equivalent to "...${smth}%s%n" - // 5) "...${smth}%%" => okay, equivalent to "...${smth}%s%%" - // 6) "...${smth}[%legalJavaConversion]" => okay, according to http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html - // 7) "...${smth}[%illegalJavaConversion]" => error - if (!first) { - val arg = argStack.pop() - if (isConversion(0)) { - // PRE str is not empty and str(0) == '%' - // argument index parameter is not allowed, thus parse - // [flags][width][.precision]conversion - var pos = 1 - while (pos < strLen && isFlag(str charAt pos)) pos += 1 - while (pos < strLen && Character.isDigit(str charAt pos)) pos += 1 - if (pos < strLen && str.charAt(pos) == '.') { - pos += 1 - while (pos < strLen && Character.isDigit(str charAt pos)) pos += 1 - } - if (pos < strLen) { - conversionType(str charAt pos, arg) match { - case Some(tpe) => defval(arg, tpe) - case None => illegalConversionCharacter(pos) - } - } else { - wrongConversionString(pos - 1) - } - idx = 1 - } else { - bldr append "%s" - defval(arg, AnyTpe) - } - } - - // STEP 2: handle the rest of the text - // 1) %n tokens are left as is - // 2) %% tokens are left as is - // 3) other usages of percents are reported as errors - if (!strIsEmpty) { - while (idx < strLen) { - if (isPercent(idx)) { - if (isConversion(idx)) nonEscapedPercent(idx) - else idx += 1 // skip n and % in %n and %% - } - idx += 1 - } - bldr append (str take idx) - } - } - - copyString(first = true) - while (pi.hasNext) { - copyString(first = false) - } - - val fstring = bldr.toString -// val expr = c.reify(fstring.format((ids.map(id => Expr(id).eval)) : _*)) -// https://issues.scala-lang.org/browse/SI-5824, therefore - val expr = - Apply( - Select( - Literal(Constant(fstring)), - newTermName("format")), - List(ids: _* ) - ) - - Block(evals.toList, atPos(origApplyPos.focus)(expr)) setPos origApplyPos.makeTransparent - } - -} diff --git a/src/compiler/scala/tools/reflect/ReflectGlobal.scala b/src/compiler/scala/tools/reflect/ReflectGlobal.scala index f8ded56ec6..6f369212ad 100644 --- a/src/compiler/scala/tools/reflect/ReflectGlobal.scala +++ b/src/compiler/scala/tools/reflect/ReflectGlobal.scala @@ -12,9 +12,10 @@ class ReflectGlobal(currentSettings: Settings, reporter: Reporter, override val extends Global(currentSettings, reporter) with scala.tools.reflect.ReflectSetup with scala.reflect.runtime.SymbolTable { override def transformedType(sym: Symbol) = - erasure.transformInfo(sym, - uncurry.transformInfo(sym, - refChecks.transformInfo(sym, sym.info))) + postErasure.transformInfo(sym, + erasure.transformInfo(sym, + uncurry.transformInfo(sym, + refChecks.transformInfo(sym, sym.info)))) override def isCompilerUniverse = true diff --git a/src/compiler/scala/tools/reflect/ToolBox.scala b/src/compiler/scala/tools/reflect/ToolBox.scala index 236b868842..4a3db09909 100644 --- a/src/compiler/scala/tools/reflect/ToolBox.scala +++ b/src/compiler/scala/tools/reflect/ToolBox.scala @@ -71,20 +71,17 @@ trait ToolBox[U <: scala.reflect.api.Universe] { */ def inferImplicitView(tree: u.Tree, from: u.Type, to: u.Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: u.Position = u.NoPosition): u.Tree - /** Recursively resets symbols and types in a given tree. - * - * Note that this does not revert the tree to its pre-typer shape. - * For more info, read up https://issues.scala-lang.org/browse/SI-5464. - */ - def resetAllAttrs(tree: u.Tree): u.Tree - /** Recursively resets locally defined symbols and types in a given tree. - * - * Note that this does not revert the tree to its pre-typer shape. - * For more info, read up https://issues.scala-lang.org/browse/SI-5464. + * WARNING: Don't use this API, go for [[untypecheck]] instead. */ + @deprecated("Use `tb.untypecheck` instead", "2.11.0") def resetLocalAttrs(tree: u.Tree): u.Tree + /** + * @see [[scala.reflect.macros.Typers.untypecheck]] + */ + def untypecheck(tree: u.Tree): u.Tree + /** .. */ def parse(code: String): u.Tree @@ -99,6 +96,15 @@ trait ToolBox[U <: scala.reflect.api.Universe] { */ def compile(tree: u.Tree): () => Any + /** Defines a top-level class, trait or module in this ToolBox, + * putting it into a uniquely-named package and returning a symbol that references the defined entity. + * For a ClassDef, a ClassSymbol is returned, and for a ModuleDef, a ModuleSymbol is returned (not a module class, but a module itself). + * + * This method can be used to generate definitions that will later be re-used by subsequent calls to + * `compile`, `define` or `eval`. To refer to the generated definition in a tree, use q"$sym". + */ + def define(tree: u.ImplDef): u.Symbol + /** Compiles and runs a tree using this ToolBox. * Is equivalent to `compile(tree)()`. */ diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index af13b7d0ba..7bae3203c2 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -193,6 +193,19 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => analyzer.inferImplicit(tree, pt, isView, currentTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw ToolBoxError(msg)) }) + private def wrapInPackageAndCompile(packageName: TermName, tree: ImplDef): Symbol = { + val pdef = PackageDef(Ident(packageName), List(tree)) + val unit = new CompilationUnit(NoSourceFile) + unit.body = pdef + + val run = new Run + reporter.reset() + run.compileUnits(List(unit), run.namerPhase) + throwIfErrors() + + tree.symbol + } + def compile(expr0: Tree): () => Any = { val expr = wrapIntoTerm(expr0) @@ -200,7 +213,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order verify(expr) - def wrap(expr0: Tree): ModuleDef = { + def wrapInModule(expr0: Tree): ModuleDef = { val (expr, freeTerms) = extractFreeTerms(expr0, wrapFreeTermRefs = true) val (obj, _) = rootMirror.EmptyPackageClass.newModuleAndClassSymbol( @@ -236,22 +249,15 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => NoPosition)) trace("wrapped: ")(showAttributed(moduledef, true, true, settings.Yshowsymkinds.value)) - val cleanedUp = resetLocalAttrs(moduledef) + val cleanedUp = resetAttrs(moduledef) trace("cleaned up: ")(showAttributed(cleanedUp, true, true, settings.Yshowsymkinds.value)) cleanedUp.asInstanceOf[ModuleDef] } - val mdef = wrap(expr) - val pdef = PackageDef(Ident(mdef.name), List(mdef)) - val unit = new CompilationUnit(NoSourceFile) - unit.body = pdef - - val run = new Run - reporter.reset() - run.compileUnits(List(unit), run.namerPhase) - throwIfErrors() + val mdef = wrapInModule(expr) + val msym = wrapInPackageAndCompile(mdef.name, mdef) - val className = mdef.symbol.fullName + val className = msym.fullName if (settings.debug) println("generated: "+className) def moduleFileName(className: String) = className + "$" val jclazz = jClass.forName(moduleFileName(className), true, classLoader) @@ -278,6 +284,13 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } } + def define(tree: ImplDef): Symbol = { + val freeTerms = tree.freeTerms + if (freeTerms.nonEmpty) throw ToolBoxError(s"reflective toolbox has failed: cannot have free terms in a top-level definition") + verify(tree) + wrapInPackageAndCompile(nextWrapperModuleName(), tree) + } + def parse(code: String): Tree = { reporter.reset() val tree = gen.mkTreeOrBlock(newUnitParser(code, "<toolbox>").parseStatsOrPackages()) @@ -385,22 +398,16 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => uitree } - def resetAllAttrs(tree: u.Tree): u.Tree = withCompilerApi { compilerApi => - import compilerApi._ - val ctree: compiler.Tree = importer.importTree(tree) - val ttree: compiler.Tree = compiler.resetAllAttrs(ctree) - val uttree = exporter.importTree(ttree) - uttree - } - def resetLocalAttrs(tree: u.Tree): u.Tree = withCompilerApi { compilerApi => import compilerApi._ val ctree: compiler.Tree = importer.importTree(tree) - val ttree: compiler.Tree = compiler.resetLocalAttrs(ctree) + val ttree: compiler.Tree = compiler.resetAttrs(ctree) val uttree = exporter.importTree(ttree) uttree } + def untypecheck(tree: u.Tree): u.Tree = resetLocalAttrs(tree) + def parse(code: String): u.Tree = withCompilerApi { compilerApi => import compilerApi._ if (compiler.settings.verbose) println("parsing "+code) @@ -419,6 +426,18 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => compiler.compile(ctree) } + def define(tree: u.ImplDef): u.Symbol = withCompilerApi { compilerApi => + import compilerApi._ + + if (compiler.settings.verbose) println("importing "+tree) + val ctree: compiler.ImplDef = importer.importTree(tree).asInstanceOf[compiler.ImplDef] + + if (compiler.settings.verbose) println("defining "+ctree) + val csym: compiler.Symbol = compiler.define(ctree) + val usym = exporter.importSymbol(csym) + usym + } + def eval(tree: u.Tree): Any = compile(tree)() } } diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala index f5bcaf68e0..2027d43264 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala @@ -31,26 +31,28 @@ trait Holes { self: Quasiquotes => import definitions._ import universeTypes._ - protected lazy val IterableTParam = IterableClass.typeParams(0).asType.toType - protected def inferParamImplicit(tfun: Type, targ: Type) = c.inferImplicitValue(appliedType(tfun, List(targ)), silent = true) - protected def inferLiftable(tpe: Type): Tree = inferParamImplicit(liftableType, tpe) - protected def inferUnliftable(tpe: Type): Tree = inferParamImplicit(unliftableType, tpe) - protected def isLiftableType(tpe: Type) = inferLiftable(tpe) != EmptyTree - protected def isNativeType(tpe: Type) = + private lazy val IterableTParam = IterableClass.typeParams(0).asType.toType + private def inferParamImplicit(tfun: Type, targ: Type) = c.inferImplicitValue(appliedType(tfun, List(targ)), silent = true) + private def inferLiftable(tpe: Type): Tree = inferParamImplicit(liftableType, tpe) + private def inferUnliftable(tpe: Type): Tree = inferParamImplicit(unliftableType, tpe) + private def isLiftableType(tpe: Type) = inferLiftable(tpe) != EmptyTree + private def isNativeType(tpe: Type) = (tpe <:< treeType) || (tpe <:< nameType) || (tpe <:< modsType) || (tpe <:< flagsType) || (tpe <:< symbolType) - protected def isBottomType(tpe: Type) = + private def isBottomType(tpe: Type) = tpe <:< NothingClass.tpe || tpe <:< NullClass.tpe - protected def stripIterable(tpe: Type, limit: Option[Cardinality] = None): (Cardinality, Type) = + private def extractIterableTParam(tpe: Type) = + IterableTParam.asSeenFrom(tpe, IterableClass) + private def stripIterable(tpe: Type, limit: Option[Cardinality] = None): (Cardinality, Type) = if (limit.map { _ == NoDot }.getOrElse { false }) (NoDot, tpe) else if (tpe != null && !isIterableType(tpe)) (NoDot, tpe) else if (isBottomType(tpe)) (NoDot, tpe) else { - val targ = IterableTParam.asSeenFrom(tpe, IterableClass) + val targ = extractIterableTParam(tpe) val (card, innerTpe) = stripIterable(targ, limit.map { _.pred }) (card.succ, innerTpe) } - protected def iterableTypeFromCard(n: Cardinality, tpe: Type): Type = { + private def iterableTypeFromCard(n: Cardinality, tpe: Type): Type = { if (n == NoDot) tpe else appliedType(IterableClass.toType, List(iterableTypeFromCard(n.pred, tpe))) } @@ -74,8 +76,7 @@ trait Holes { self: Quasiquotes => class ApplyHole(card: Cardinality, splicee: Tree) extends Hole { val (strippedTpe, tpe): (Type, Type) = { - if (stripIterable(splicee.tpe)._1.value < card.value) cantSplice() - val (_, strippedTpe) = stripIterable(splicee.tpe, limit = Some(card)) + val (strippedCard, strippedTpe) = stripIterable(splicee.tpe, limit = Some(card)) if (isBottomType(strippedTpe)) cantSplice() else if (isNativeType(strippedTpe)) (strippedTpe, iterableTypeFromCard(card, strippedTpe)) else if (isLiftableType(strippedTpe)) (strippedTpe, iterableTypeFromCard(card, treeType)) @@ -88,14 +89,14 @@ trait Holes { self: Quasiquotes => else if (isLiftableType(itpe)) lifted(itpe)(tree) else global.abort("unreachable") if (card == NoDot) inner(strippedTpe)(splicee) - else iterated(card, strippedTpe, inner(strippedTpe))(splicee) + else iterated(card, splicee, splicee.tpe) } val pos = splicee.pos val cardinality = stripIterable(tpe)._1 - protected def cantSplice(): Nothing = { + private def cantSplice(): Nothing = { val (iterableCard, iterableType) = stripIterable(splicee.tpe) val holeCardMsg = if (card != NoDot) s" with $card" else "" val action = "splice " + splicee.tpe + holeCardMsg @@ -111,29 +112,66 @@ trait Holes { self: Quasiquotes => c.abort(splicee.pos, s"Can't $action, $advice") } - protected def lifted(tpe: Type)(tree: Tree): Tree = { + private def lifted(tpe: Type)(tree: Tree): Tree = { val lifter = inferLiftable(tpe) assert(lifter != EmptyTree, s"couldnt find a liftable for $tpe") val lifted = Apply(lifter, List(tree)) - val targetType = Select(u, tpnme.Tree) - atPos(tree.pos)(TypeApply(Select(lifted, nme.asInstanceOf_), List(targetType))) + atPos(tree.pos)(lifted) } - protected def iterated(card: Cardinality, tpe: Type, elementTransform: Tree => Tree = identity)(tree: Tree): Tree = { - assert(card != NoDot) - def reifyIterable(tree: Tree, n: Cardinality): Tree = { - def loop(tree: Tree, n: Cardinality): Tree = - if (n == NoDot) elementTransform(tree) - else { - val x: TermName = c.freshName() - val wrapped = reifyIterable(Ident(x), n.pred) - val xToWrapped = Function(List(ValDef(Modifiers(PARAM), x, TypeTree(), EmptyTree)), wrapped) - Select(Apply(Select(tree, nme.map), List(xToWrapped)), nme.toList) - } - if (tree.tpe != null && (tree.tpe <:< listTreeType || tree.tpe <:< listListTreeType)) tree - else atPos(tree.pos)(loop(tree, n)) + private def toStats(tree: Tree): Tree = + // q"$u.build.toStats($tree)" + Apply(Select(Select(u, nme.build), nme.toStats), tree :: Nil) + + private def toList(tree: Tree, tpe: Type): Tree = + if (isListType(tpe)) tree + else Select(tree, nme.toList) + + private def mapF(tree: Tree, f: Tree => Tree): Tree = + if (f(Ident(TermName("x"))) equalsStructure Ident(TermName("x"))) tree + else { + val x: TermName = c.freshName() + // q"$tree.map { $x => ${f(Ident(x))} }" + Apply(Select(tree, nme.map), + Function(ValDef(Modifiers(PARAM), x, TypeTree(), EmptyTree) :: Nil, + f(Ident(x))) :: Nil) } - reifyIterable(tree, card) + + private object IterableType { + def unapply(tpe: Type): Option[Type] = + if (isIterableType(tpe)) Some(extractIterableTParam(tpe)) else None + } + + private object LiftedType { + def unapply(tpe: Type): Option[Tree => Tree] = + if (tpe <:< treeType) Some(t => t) + else if (isLiftableType(tpe)) Some(lifted(tpe)(_)) + else None + } + + /** Map high-cardinality splice onto an expression that eveluates as a list of given cardinality. + * + * All possible combinations of representations are given in the table below: + * + * input output for T <: Tree output for T: Liftable + * + * ..${x: Iterable[T]} x.toList x.toList.map(lift) + * ..${x: T} toStats(x) toStats(lift(x)) + * + * ...${x: Iterable[Iterable[T]]} x.toList { _.toList } x.toList.map { _.toList.map(lift) } + * ...${x: Iterable[T]} x.toList.map { toStats(_) } x.toList.map { toStats(lift(_)) } + * ...${x: T} toStats(x).map { toStats(_) } toStats(lift(x)).map { toStats(_) } + * + * For optimization purposes `x.toList` is represented as just `x` if it is statically known that + * x is not just an Iterable[T] but a List[T]. Similarly no mapping is performed if mapping function is + * known to be an identity. + */ + private def iterated(card: Cardinality, tree: Tree, tpe: Type): Tree = (card, tpe) match { + case (DotDot, tpe @ IterableType(LiftedType(lift))) => mapF(toList(tree, tpe), lift) + case (DotDot, LiftedType(lift)) => toStats(lift(tree)) + case (DotDotDot, tpe @ IterableType(inner)) => mapF(toList(tree, tpe), t => iterated(DotDot, t, inner)) + case (DotDotDot, LiftedType(lift)) => mapF(toStats(lift(tree)), toStats) + case _ => global.abort("unreachable") } } @@ -167,16 +205,15 @@ trait Holes { self: Quasiquotes => /** Full support for unliftable implies that it's possible to interleave * deconstruction with higher cardinality and unlifting of the values. * In particular extraction of List[Tree] as List[T: Unliftable] requires - * helper extractors that would do the job: UnliftHelper1[T]. Similarly - * List[List[Tree]] needs UnliftHelper2[T]. + * helper extractors that would do the job: UnliftListElementwise[T]. Similarly + * List[List[Tree]] needs UnliftListOfListsElementwise[T]. * * See also "unlift list" tests in UnapplyProps.scala */ object unlifters { private var records = List.empty[(Type, Cardinality)] - // Request an UnliftHelperN[T] where n == card and T == tpe. - // If card == 0 then helper is not needed and plain instance - // of unliftable is returned. + // Materialize unlift helper that does elementwise + // unlifting for corresponding cardinality and type. def spawn(tpe: Type, card: Cardinality): Option[Tree] = { val unlifter = inferUnliftable(tpe) if (unlifter == EmptyTree) None @@ -191,7 +228,10 @@ trait Holes { self: Quasiquotes => def preamble(): List[Tree] = records.zipWithIndex.map { case ((tpe, card), idx) => val name = TermName(nme.QUASIQUOTE_UNLIFT_HELPER + idx) - val helperName = card match { case DotDot => nme.UnliftHelper1 case DotDotDot => nme.UnliftHelper2 } + val helperName = card match { + case DotDot => nme.UnliftListElementwise + case DotDotDot => nme.UnliftListOfListsElementwise + } val lifter = inferUnliftable(tpe) assert(helperName.isTermName) // q"val $name: $u.build.${helperName.toTypeName} = $u.build.$helperName($lifter)" diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index 6e6b617e5c..9f6807fe17 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -55,7 +55,7 @@ trait Parsers { self: Quasiquotes => def isHole(name: Name): Boolean = holeMap.contains(name) - override implicit def fresh: FreshNameCreator = new FreshNameCreator(nme.QUASIQUOTE_PREFIX) + override implicit lazy val fresh: FreshNameCreator = new FreshNameCreator(nme.QUASIQUOTE_PREFIX) override val treeBuilder = new ParserTreeBuilder { override implicit def fresh: FreshNameCreator = parser.fresh @@ -80,8 +80,20 @@ trait Parsers { self: Quasiquotes => } import treeBuilder.{global => _, unit => _, _} + def quasiquoteParam(name: Name, flags: FlagSet = NoFlags) = + ValDef(Modifiers(flags), name.toTermName, Ident(tpnme.QUASIQUOTE_PARAM), EmptyTree) + // q"def foo($x)" - override def allowTypelessParams = true + override def param(owner: Name, implicitmod: Int, caseParam: Boolean): ValDef = + if (isHole && lookingAhead { in.token == COMMA || in.token == RPAREN }) { + quasiquoteParam(ident(), implicitmod) + } else super.param(owner, implicitmod, caseParam) + + // q"($x) => ..." && q"class X { selfie => } + override def convertToParam(tree: Tree): ValDef = tree match { + case Ident(name) if isHole(name) => quasiquoteParam(name) + case _ => super.convertToParam(tree) + } // q"foo match { case $x }" override def caseClause(): CaseDef = @@ -160,17 +172,26 @@ trait Parsers { self: Quasiquotes => } } - object TermParser extends Parser { - def entryPoint = { parser => - parser.templateOrTopStatSeq() match { - case head :: Nil => Block(Nil, head) - case lst => gen.mkTreeOrBlock(lst) - } + /** Wrapper around tree parsed in q"..." quote. Needed to support ..$ splicing on top-level. */ + object Q { + def apply(tree: Tree): Block = Block(Nil, tree).updateAttachment(Q) + def unapply(tree: Tree): Option[Tree] = tree match { + case Block(Nil, contents) if tree.hasAttachment[Q.type] => Some(contents) + case _ => None } } + object TermParser extends Parser { + def entryPoint = parser => Q(gen.mkTreeOrBlock(parser.templateOrTopStatSeq())) + } + object TypeParser extends Parser { - def entryPoint = _.typ() + def entryPoint = { parser => + if (parser.in.token == EOF) + TypeTree() + else + parser.typ() + } } object CaseParser extends Parser { @@ -179,7 +200,7 @@ trait Parsers { self: Quasiquotes => object PatternParser extends Parser { def entryPoint = { parser => - val pat = parser.noSeq.pattern1() + val pat = parser.noSeq.pattern() gen.patvarTransformer.transform(pat) } } @@ -193,4 +214,4 @@ trait Parsers { self: Quasiquotes => } object FreshName extends FreshNameExtractor(nme.QUASIQUOTE_PREFIX) -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala index bdb44ad9a2..825d0c04f3 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala @@ -17,7 +17,6 @@ trait Placeholders { self: Quasiquotes => // Step 1: Transform Scala source with holes into vanilla Scala source - lazy val holeMap = new HoleMap() lazy val posMap = mutable.ListMap[Position, (Int, Int)]() lazy val code = { val sb = new StringBuilder() @@ -58,25 +57,27 @@ trait Placeholders { self: Quasiquotes => sb.toString } - class HoleMap { - private var underlying = immutable.SortedMap[String, Hole]() - private val accessed = mutable.Set[String]() + object holeMap { + private val underlying = mutable.LinkedHashMap.empty[String, Hole] + private val accessed = mutable.Set.empty[String] def unused: Set[Name] = (underlying.keys.toSet -- accessed).map(TermName(_)) - def contains(key: Name) = underlying.contains(key.toString) - def apply(key: Name) = { - val s = key.toString - accessed += s - underlying(s) - } - def update(key: Name, hole: Hole) = { + def contains(key: Name): Boolean = underlying.contains(key.toString) + def apply(key: Name): Hole = { + val skey = key.toString + val value = underlying(skey) + accessed += skey + value + } + def update(key: Name, hole: Hole) = underlying += key.toString -> hole - } - def get(key: Name) = { - val s = key.toString - accessed += s - underlying.get(s) - } - def toList = underlying.toList + def get(key: Name): Option[Hole] = { + val skey = key.toString + underlying.get(skey).map { v => + accessed += skey + v + } + } + def keysIterator: Iterator[TermName] = underlying.keysIterator.map(TermName(_)) } // Step 2: Transform vanilla Scala AST into an AST with holes @@ -95,7 +96,6 @@ trait Placeholders { self: Quasiquotes => case Ident(name) => name case Bind(name, Ident(nme.WILDCARD)) => name case TypeDef(_, name, List(), TypeBoundsTree(EmptyTree, EmptyTree)) => name - case ValDef(_, name, TypeTree(), EmptyTree) => name } } @@ -111,6 +111,12 @@ trait Placeholders { self: Quasiquotes => } } + object ParamPlaceholder extends HolePlaceholder { + def matching = { + case ValDef(_, name, Ident(tpnme.QUASIQUOTE_PARAM), EmptyTree) => name + } + } + object TuplePlaceholder { def unapply(tree: Tree): Option[List[Tree]] = tree match { case Apply(Ident(nme.QUASIQUOTE_TUPLE), args) => Some(args) @@ -174,4 +180,4 @@ trait Placeholders { self: Quasiquotes => case _ => None } } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala index 7d777ef7d5..396688c437 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala @@ -11,12 +11,12 @@ abstract class Quasiquotes extends Parsers val global: c.universe.type = c.universe import c.universe._ - def debug(msg: String): Unit = + def debug(msg: => String): Unit = if (settings.Yquasiquotedebug.value) println(msg) lazy val (universe: Tree, args, parts, parse, reify, method) = c.macroApplication match { case Apply(build.SyntacticTypeApplied(Select(Select(Apply(Select(universe0, _), List(Apply(_, parts0))), interpolator0), method0), _), args0) => - debug(s"\nparse prefix:\nuniverse=$universe0\nparts=$parts0\ninterpolator=$interpolator0\nmethod=$method0\nargs=$args0\n") + debug(s"parse prefix:\nuniverse=$universe0\nparts=$parts0\ninterpolator=$interpolator0\nmethod=$method0\nargs=$args0\n") val parts1 = parts0.map { case lit @ Literal(Constant(s: String)) => s -> lit.pos case part => c.abort(part.pos, "Quasiquotes can only be used with literal strings") @@ -43,12 +43,12 @@ abstract class Quasiquotes extends Parsers lazy val universeTypes = new definitions.UniverseDependentTypes(universe) def expandQuasiquote = { - debug(s"\nmacro application:\n${c.macroApplication}\n") - debug(s"\ncode to parse:\n$code\n") + debug(s"macro application:\n${c.macroApplication}\n") + debug(s"code to parse:\n$code\n") val tree = parse(code) debug(s"parsed:\n${showRaw(tree)}\n$tree\n") val reified = reify(tree) - val sreified = + def sreified = reified .toString .replace("scala.reflect.runtime.`package`.universe.build.", "") diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index 87ab52414c..017e966f63 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -29,7 +29,7 @@ trait Reifiers { self: Quasiquotes => /** Map that stores freshly generated names linked to the corresponding names in the reified tree. * This information is used to reify names created by calls to freshTermName and freshTypeName. */ - var nameMap = collection.mutable.HashMap.empty[Name, Set[TermName]].withDefault { _ => Set() } + val nameMap = collection.mutable.HashMap.empty[Name, Set[TermName]].withDefault { _ => Set() } /** Wraps expressions into: * a block which starts with a sequence of vals that correspond @@ -71,7 +71,7 @@ trait Reifiers { self: Quasiquotes => // q"..$freshdefs; $tree" SyntacticBlock(freshdefs :+ tree) } else { - val freevars = holeMap.toList.map { case (name, _) => Ident(name) } + val freevars = holeMap.keysIterator.map(Ident(_)).toList val isVarPattern = tree match { case Bind(name, Ident(nme.WILDCARD)) => true case _ => false } val cases = if(isVarPattern) { @@ -137,6 +137,7 @@ trait Reifiers { self: Quasiquotes => case RefineStatPlaceholder(hole) => reifyRefineStat(hole) case EarlyDefPlaceholder(hole) => reifyEarlyDef(hole) case PackageStatPlaceholder(hole) => reifyPackageStat(hole) + case ParamPlaceholder(hole) => hole.tree // for enumerators are checked not during splicing but during // desugaring of the for loop in SyntacticFor & SyntacticForYield case ForEnumPlaceholder(hole) => hole.tree @@ -159,8 +160,12 @@ trait Reifiers { self: Quasiquotes => reifyBuildCall(nme.SyntacticObjectDef, mods, name, earlyDefs, parents, selfdef, body) case SyntacticNew(earlyDefs, parents, selfdef, body) => reifyBuildCall(nme.SyntacticNew, earlyDefs, parents, selfdef, body) - case SyntacticDefDef(mods, name, tparams, vparamss, tpt, rhs) => - reifyBuildCall(nme.SyntacticDefDef, mods, name, tparams, vparamss, tpt, rhs) + case SyntacticDefDef(mods, name, tparams, build.ImplicitParams(vparamss, implparams), tpt, rhs) => + if (implparams.nonEmpty) + mirrorBuildCall(nme.SyntacticDefDef, reify(mods), reify(name), reify(tparams), + reifyBuildCall(nme.ImplicitParams, vparamss, implparams), reify(tpt), reify(rhs)) + else + reifyBuildCall(nme.SyntacticDefDef, mods, name, tparams, vparamss, tpt, rhs) case SyntacticValDef(mods, name, tpt, rhs) if tree != noSelfType => reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs) case SyntacticVarDef(mods, name, tpt, rhs) => @@ -185,12 +190,18 @@ trait Reifiers { self: Quasiquotes => reifyBuildCall(nme.SyntacticFunction, args, body) case SyntacticIdent(name, isBackquoted) => reifyBuildCall(nme.SyntacticIdent, name, isBackquoted) - case Block(Nil, Placeholder(Hole(tree, DotDot))) => + case SyntacticEmptyTypeTree() => + reifyBuildCall(nme.SyntacticEmptyTypeTree) + case SyntacticImport(expr, selectors) => + reifyBuildCall(nme.SyntacticImport, expr, selectors) + case Q(Placeholder(Hole(tree, DotDot))) => mirrorBuildCall(nme.SyntacticBlock, tree) - case Block(Nil, other) => + case Q(other) => reifyTree(other) - case Block(stats, last) => - reifyBuildCall(nme.SyntacticBlock, stats :+ last) + // Syntactic block always matches so we have to be careful + // not to cause infinite recursion. + case block @ SyntacticBlock(stats) if block.isInstanceOf[Block] => + reifyBuildCall(nme.SyntacticBlock, stats) case Try(block, catches, finalizer) => reifyBuildCall(nme.SyntacticTry, block, catches, finalizer) case Match(selector, cases) => @@ -298,7 +309,7 @@ trait Reifiers { self: Quasiquotes => * > reifyMultiCardinalityList(lst) { ... } { ... } * q"List($foo, $bar) ++ ${holeMap(qq$f3948f9s$1).tree}" */ - def reifyMultiCardinalityList[T](xs: List[T])(fill: PartialFunction[T, Tree])(fallback: T => Tree): Tree + def reifyMultiCardinalityList(xs: List[Any])(fill: PartialFunction[Any, Tree])(fallback: Any => Tree): Tree /** Reifies arbitrary list filling ..$x and ...$y holeMap when they are put * in the correct position. Fallbacks to regular reification for non-high cardinality @@ -311,6 +322,8 @@ trait Reifiers { self: Quasiquotes => case EarlyDefPlaceholder(h @ Hole(_, DotDot)) => reifyEarlyDef(h) case PackageStatPlaceholder(h @ Hole(_, DotDot)) => reifyPackageStat(h) case ForEnumPlaceholder(Hole(tree, DotDot)) => tree + case ParamPlaceholder(Hole(tree, DotDot)) => tree + case List(ParamPlaceholder(Hole(tree, DotDotDot))) => tree case List(Placeholder(Hole(tree, DotDotDot))) => tree } { reify(_) @@ -352,10 +365,10 @@ trait Reifiers { self: Quasiquotes => } class ApplyReifier extends Reifier(isReifyingExpressions = true) { - def reifyMultiCardinalityList[T](xs: List[T])(fill: PartialFunction[T, Tree])(fallback: T => Tree): Tree = + def reifyMultiCardinalityList(xs: List[Any])(fill: PartialFunction[Any, Tree])(fallback: Any => Tree): Tree = if (xs.isEmpty) mkList(Nil) else { - def reifyGroup(group: List[T]): Tree = group match { + def reifyGroup(group: List[Any]): Tree = group match { case List(elem) if fill.isDefinedAt(elem) => fill(elem) case elems => mkList(elems.map(fallback)) } @@ -394,14 +407,26 @@ trait Reifiers { self: Quasiquotes => } class UnapplyReifier extends Reifier(isReifyingExpressions = false) { - def reifyMultiCardinalityList[T](xs: List[T])(fill: PartialFunction[T, Tree])(fallback: T => Tree): Tree = xs match { - case init :+ last if fill.isDefinedAt(last) => - init.foldRight[Tree](fill(last)) { (el, rest) => - val cons = Select(Select(Select(Ident(nme.scala_), nme.collection), nme.immutable), nme.CONS) - Apply(cons, List(fallback(el), rest)) - } - case _ => - mkList(xs.map(fallback)) + private def collection = ScalaDot(nme.collection) + private def collectionColonPlus = Select(collection, nme.COLONPLUS) + private def collectionCons = Select(Select(collection, nme.immutable), nme.CONS) + private def collectionNil = Select(Select(collection, nme.immutable), nme.Nil) + // pq"$lhs :+ $rhs" + private def append(lhs: Tree, rhs: Tree) = Apply(collectionColonPlus, lhs :: rhs :: Nil) + // pq"$lhs :: $rhs" + private def cons(lhs: Tree, rhs: Tree) = Apply(collectionCons, lhs :: rhs :: Nil) + + def reifyMultiCardinalityList(xs: List[Any])(fill: PartialFunction[Any, Tree])(fallback: Any => Tree): Tree = { + val grouped = group(xs) { (a, b) => !fill.isDefinedAt(a) && !fill.isDefinedAt(b) } + def appended(lst: List[Any], init: Tree) = lst.foldLeft(init) { (l, r) => append(l, fallback(r)) } + def prepended(lst: List[Any], init: Tree) = lst.foldRight(init) { (l, r) => cons(fallback(l), r) } + grouped match { + case init :: List(hole) :: last :: Nil if fill.isDefinedAt(hole) => appended(last, prepended(init, fill(hole))) + case init :: List(hole) :: Nil if fill.isDefinedAt(hole) => prepended(init, fill(hole)) + case List(hole) :: last :: Nil if fill.isDefinedAt(hole) => appended(last, fill(hole)) + case List(hole) :: Nil if fill.isDefinedAt(hole) => fill(hole) + case _ => prepended(xs, collectionNil) + } } override def reifyModifiers(m: Modifiers) = diff --git a/src/eclipse/partest/.classpath b/src/eclipse/partest/.classpath index 35528a276d..c2aab19f18 100644 --- a/src/eclipse/partest/.classpath +++ b/src/eclipse/partest/.classpath @@ -4,7 +4,7 @@ <classpathentry combineaccessrules="false" kind="src" path="/asm"/> <classpathentry combineaccessrules="false" kind="src" path="/repl"/> <classpathentry kind="var" path="M2_REPO/com/googlecode/java-diff-utils/diffutils/1.3.0/diffutils-1.3.0.jar"/> - <classpathentry kind="var" path="M2_REPO/org/scala-tools/testing/test-interface/0.5/test-interface-0.5.jar"/> + <classpathentry kind="var" path="M2_REPO/org/scala-sbt/test-interface/1.0/test-interface-1.0.jar"/> <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-partest_2.11.0-M7/1.0.0-RC8/scala-partest_2.11.0-M7-1.0.0-RC8.jar"/> <classpathentry kind="var" path="SCALA_BASEDIR/lib/ant/ant.jar"/> <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/> diff --git a/src/eclipse/test-junit/.classpath b/src/eclipse/test-junit/.classpath index d028dcc21e..8a599bd8c7 100644 --- a/src/eclipse/test-junit/.classpath +++ b/src/eclipse/test-junit/.classpath @@ -7,5 +7,6 @@ <classpathentry combineaccessrules="false" kind="src" path="/scala-library"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/> + <classpathentry combineaccessrules="false" kind="src" path="/repl"/> <classpathentry kind="output" path="build-test-junit"/> </classpath> diff --git a/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala b/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala index 4f67a22b8f..bf718c27cc 100644 --- a/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala +++ b/src/interactive/scala/tools/nsc/interactive/ContextTrees.scala @@ -64,9 +64,12 @@ trait ContextTrees { self: Global => def locateContextTree(contexts: Contexts, pos: Position): Option[ContextTree] = { if (contexts.isEmpty) None else { + // binary search on contexts, loop invar: lo <= hi, recursion metric: `hi - lo` @tailrec def loop(lo: Int, hi: Int, previousSibling: Option[ContextTree]): Option[ContextTree] = { - if (pos properlyPrecedes contexts(lo).pos) + // [SI-8239] enforce loop invariant & ensure recursion metric decreases monotonically on every recursion + if (lo > hi) previousSibling + else if (pos properlyPrecedes contexts(lo).pos) previousSibling else if (contexts(hi).pos properlyPrecedes pos) Some(contexts(hi)) @@ -76,9 +79,18 @@ trait ContextTrees { self: Global => if (midpos includes pos) Some(contexts(mid)) else if (midpos properlyPrecedes pos) + // recursion metric: (hi - ((lo + hi)/2 + 1)) < (hi - lo) + // since (hi - ((lo + hi)/2 + 1)) - (hi - lo) = lo - ((lo + hi)/2 + 1) < 0 + // since 2*lo - lo - hi - 2 = lo - hi - 2 < 0 + // since lo < hi + 2 + // can violate lo <= hi, hence the lo > hi check at the top [SI-8239] loop(mid + 1, hi, Some(contexts(mid))) - else + else if (lo != hi) // avoid looping forever (lo == hi violates the recursion metric) [SI-8239] + // recursion metric: ((lo + hi)/2) - lo < (hi - lo) + // since ((lo + hi)/2) - lo - (hi - lo) = ((lo + hi)/2) - hi < 0 + // since 2 * (((lo + hi)/2) - hi) = lo - hi < 0 since lo < hi loop(lo, mid, previousSibling) + else previousSibling } } loop(0, contexts.length - 1, None) diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index b55a573029..95027a26b1 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -534,7 +534,6 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") threadId += 1 compileRunner = new PresentationCompilerThread(this, projectName) compileRunner.setDaemon(true) - compileRunner.start() compileRunner } @@ -638,6 +637,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") unit.problems.clear() unit.body = EmptyTree unit.status = NotLoaded + unit.transformed.clear() } /** Parse unit and create a name index, unless this has already been done before */ @@ -956,7 +956,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") singleType(qual.tpe, tree.symbol) case Import(expr, selectors) => tree.symbol.info match { - case analyzer.ImportType(expr) => expr match { + case ImportType(expr) => expr match { case s@Select(qual, name) if treeInfo.admitsTypeSelection(expr) => singleType(qual.tpe, s.symbol) case i : Ident => i.tpe case _ => tree.tpe @@ -1021,7 +1021,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") def addScopeMember(sym: Symbol, pre: Type, viaImport: Tree) = locals.add(sym, pre, implicitlyAdded = false) { (s, st) => // imported val and var are always marked as inaccessible, but they could be accessed through their getters. SI-7995 - if (s.hasGetter) + if (s.hasGetter) new ScopeMember(s, st, context.isAccessible(s.getter, pre, superAccess = false), viaImport) else new ScopeMember(s, st, context.isAccessible(s, pre, superAccess = false), viaImport) @@ -1111,7 +1111,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") val pre = stabilizedType(tree) val ownerTpe = tree.tpe match { - case analyzer.ImportType(expr) => expr.tpe + case ImportType(expr) => expr.tpe case null => pre case MethodType(List(), rtpe) => rtpe case _ => tree.tpe @@ -1252,11 +1252,21 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") forceSymbolsUsedByParser() + /** Start the compiler background thread and turn on thread confinement checks */ + private def finishInitialization(): Unit = { + // this flag turns on `assertCorrectThread checks` + initializing = false + + // Only start the thread if initialization was successful. A crash while forcing symbols (for example + // if the Scala library is not on the classpath) can leave running threads behind. See Scala IDE #1002016 + compileRunner.start() + } + /** The compiler has been initialized. Constructors are evaluated in textual order, - * so this is set to true only after all super constructors and the primary constructor + * if we reached here, all super constructors and the primary constructor * have been executed. */ - initializing = false + finishInitialization() } object CancelException extends Exception diff --git a/src/library-aux/scala/AnyRef.scala b/src/library-aux/scala/AnyRef.scala index 362fbcf0f5..8c1862e729 100644 --- a/src/library-aux/scala/AnyRef.scala +++ b/src/library-aux/scala/AnyRef.scala @@ -76,8 +76,8 @@ trait AnyRef extends Any { * @param arg0 the object to compare against this object for equality. * @return `true` if the receiver object is equivalent to the argument; `false` otherwise. */ - final def ==(that: AnyRef): Boolean = - if (this eq null) that eq null + final def ==(that: Any): Boolean = + if (this eq null) that.asInstanceOf[AnyRef] eq null else this equals that /** Create a copy of the receiver object. diff --git a/src/library/rootdoc.txt b/src/library/rootdoc.txt index 0722d808bf..4795a47efe 100644 --- a/src/library/rootdoc.txt +++ b/src/library/rootdoc.txt @@ -2,21 +2,54 @@ This is the documentation for the Scala standard library. == Package structure == -The [[scala]] package contains core types. - -[[scala.collection `scala.collection`]] and its subpackages contain a collections framework with higher-order functions for manipulation. Both [[scala.collection.immutable `scala.collection.immutable`]] and [[scala.collection.mutable `scala.collection.mutable`]] data structures are available, with immutable as the default. The [[scala.collection.parallel `scala.collection.parallel`]] collections provide automatic parallel operation. - -Other important packages include: - - - [[scala.actors `scala.actors`]] - Concurrency framework inspired by Erlang. - - [[scala.io `scala.io`]] - Input and output. - - [[scala.math `scala.math`]] - Basic math functions and additional numeric types. - - [[scala.sys `scala.sys`]] - Interaction with other processes and the operating system. - - [[scala.util.matching `scala.util.matching`]] - Pattern matching in text using regular expressions. - - [[scala.util.parsing.combinator `scala.util.parsing.combinator`]] - Composable combinators for parsing. - - [[scala.xml `scala.xml`]] - XML parsing, manipulation, and serialization. - -Many other packages exist. See the complete list on the left. +The [[scala]] package contains core types like [[scala.Int `Int`]], [[scala.Float `Float`]], [[scala.Array `Array`]] +or [[scala.Option `Option`]] which are accessible in all Scala compilation units without explicit qualification or +imports. + +Notable packages include: + + - [[scala.collection `scala.collection`]] and its sub-packages contain Scala's collections framework + - [[scala.collection.immutable `scala.collection.immutable`]] - Immutable, sequential data-structures such as + [[scala.collection.immutable.Vector `Vector`]], [[scala.collection.immutable.List `List`]], + [[scala.collection.immutable.Range `Range`]], [[scala.collection.immutable.HashMap `HashMap`]] or + [[scala.collection.immutable.HashSet `HasSet`]] + - [[scala.collection.mutable `scala.collection.mutable`]] - Mutable, sequential data-structures such as + [[scala.collection.mutable.ArrayBuffer `ArrayBuffer`]], + [[scala.collection.mutable.StringBuilder `StringBuilder`]], + [[scala.collection.mutable.HashMap `HashMap`]] or [[scala.collection.mutable.HashSet `HashSet`]] + - [[scala.collection.concurrent `scala.collection.concurrent`]] - Mutable, concurrent data-structures such as + [[scala.collection.concurrent.TrieMap `TrieMap`]] + - [[scala.collection.parallel.immutable `scala.collection.parallel.immutable`]] - Immutable, parallel + data-structures such as [[scala.collection.parallel.immutable.ParVector `ParVector`]], + [[scala.collection.parallel.immutable.ParRange `ParRange`]], + [[scala.collection.parallel.immutable.ParHashMap `ParHashMap`]] or + [[scala.collection.parallel.immutable.ParHashSet `ParHashSet`]] + - [[scala.collection.parallel.mutable `scala.collection.parallel.mutable`]] - Mutable, parallel + data-structures such as [[scala.collection.parallel.mutable.ParArray `ParArray`]], + [[scala.collection.parallel.mutable.ParHashMap `ParHashMap`]], + [[scala.collection.parallel.mutable.ParTrieMap `ParTrieMap`]] or + [[scala.collection.parallel.mutable.ParHashSet `ParHashSet`]] + - [[scala.concurrent `scala.concurrent`]] - Primitives for concurrent programming such as + [[scala.concurrent.Future `Futures`]] and [[scala.concurrent.Promise `Promises`]] + - [[scala.io `scala.io`]] - Input and output operations + - [[scala.math `scala.math`]] - Basic math functions and additional numeric types like + [[scala.math.BigInt `BigInt`]] and [[scala.math.BigDecimal `BigDecimal`]] + - [[scala.sys `scala.sys`]] - Interaction with other processes and the operating system + - [[scala.util.matching `scala.util.matching`]] - [[scala.util.matching.Regex Regular expressions]] + +Other packages exist. See the complete list on the left. + +Additional parts of the standard library are shipped as separate libraries. These include: + + - [[scala.reflect `scala.reflect`]] - Scala's reflection API (scala-reflect.jar) + - [[scala.xml `scala.xml`]] - XML parsing, manipulation, and serialization (scala-xml.jar) + - [[scala.swing `scala.swing`]] - A convenient wrapper around Java's GUI framework called Swing (scala-swing.jar) + - [[scala.util.continuations `scala.util.continuations`]] - Delimited continuations using continuation-passing-style + (scala-continuations-library.jar, scala-continuations-plugin.jar) + - [[scala.util.parsing `scala.util.parsing`]] - [[scala.util.parsing.combinator Parser combinators]], including an + example implementation of a [[scala.util.parsing.json JSON parser]] (scala-parser-combinators.jar) + - [[scala.actors `scala.actors`]] - Actor-based concurrency (deprecated and replaced by Akka actors, + scala-actors.jar) == Automatic imports == diff --git a/src/library/scala/Console.scala b/src/library/scala/Console.scala index 275d7629ee..37127a93d5 100644 --- a/src/library/scala/Console.scala +++ b/src/library/scala/Console.scala @@ -9,7 +9,7 @@ package scala import java.io.{ BufferedReader, InputStream, InputStreamReader, OutputStream, PrintStream, Reader } -import scala.io.{ AnsiColor, ReadStdin } +import scala.io.{ AnsiColor, StdIn } import scala.util.DynamicVariable /** Implements functionality for @@ -169,20 +169,20 @@ private[scala] abstract class DeprecatedConsole { protected def setErrDirect(err: PrintStream): Unit protected def setInDirect(in: BufferedReader): Unit - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readBoolean(): Boolean = ReadStdin.readBoolean() - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readByte(): Byte = ReadStdin.readByte() - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readChar(): Char = ReadStdin.readChar() - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readDouble(): Double = ReadStdin.readDouble() - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readFloat(): Float = ReadStdin.readFloat() - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readInt(): Int = ReadStdin.readInt() - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readLine(): String = ReadStdin.readLine() - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readLine(text: String, args: Any*): String = ReadStdin.readLine(text, args: _*) - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readLong(): Long = ReadStdin.readLong() - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readShort(): Short = ReadStdin.readShort() - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readf(format: String): List[Any] = ReadStdin.readf(format) - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readf1(format: String): Any = ReadStdin.readf1(format) - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readf2(format: String): (Any, Any) = ReadStdin.readf2(format) - @deprecated("Use the method in scala.io.ReadStdin", "2.11.0") def readf3(format: String): (Any, Any, Any) = ReadStdin.readf3(format) + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readBoolean(): Boolean = StdIn.readBoolean() + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readByte(): Byte = StdIn.readByte() + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readChar(): Char = StdIn.readChar() + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readDouble(): Double = StdIn.readDouble() + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readFloat(): Float = StdIn.readFloat() + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readInt(): Int = StdIn.readInt() + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readLine(): String = StdIn.readLine() + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readLine(text: String, args: Any*): String = StdIn.readLine(text, args: _*) + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readLong(): Long = StdIn.readLong() + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readShort(): Short = StdIn.readShort() + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readf(format: String): List[Any] = StdIn.readf(format) + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readf1(format: String): Any = StdIn.readf1(format) + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readf2(format: String): (Any, Any) = StdIn.readf2(format) + @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readf3(format: String): (Any, Any, Any) = StdIn.readf3(format) /** Sets the default output stream. * diff --git a/src/library/scala/Enumeration.scala b/src/library/scala/Enumeration.scala index 59be0cdfa3..d4b9c17eab 100644 --- a/src/library/scala/Enumeration.scala +++ b/src/library/scala/Enumeration.scala @@ -11,7 +11,7 @@ package scala import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet } import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField } import scala.reflect.NameTransformer._ -import java.util.regex.Pattern +import scala.util.matching.Regex /** Defines a finite set of values specific to the enumeration. Typically * these values enumerate all possible forms something can take and provide @@ -64,7 +64,7 @@ abstract class Enumeration (initial: Int) extends Serializable { */ override def toString = ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split - Pattern.quote(NAME_JOIN_STRING)).last + Regex.quote(NAME_JOIN_STRING)).last /** The mapping from the integer used to identify values to the actual * values. */ diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 8900450fa3..50577e710e 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -15,7 +15,7 @@ import generic.CanBuildFrom import scala.annotation.{ elidable, implicitNotFound } import scala.annotation.elidable.ASSERTION import scala.language.{implicitConversions, existentials} -import scala.io.ReadStdin +import scala.io.StdIn /** The `Predef` object provides definitions that are accessible in all Scala * compilation units without explicit qualification. @@ -95,8 +95,6 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { type Set[A] = immutable.Set[A] val Map = immutable.Map val Set = immutable.Set - // @deprecated("Use scala.AnyRef instead", "2.10.0") - // def AnyRef = scala.AnyRef // Manifest types, companions, and incantations for summoning @annotation.implicitNotFound(msg = "No ClassManifest available for ${T}.") @@ -417,20 +415,20 @@ private[scala] trait DeprecatedPredef { @deprecated("Use `SeqCharSequence`", "2.11.0") def seqToCharSequence(xs: scala.collection.IndexedSeq[Char]): CharSequence = new SeqCharSequence(xs) @deprecated("Use `ArrayCharSequence`", "2.11.0") def arrayToCharSequence(xs: Array[Char]): CharSequence = new ArrayCharSequence(xs) - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readLine(): String = ReadStdin.readLine() - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readLine(text: String, args: Any*) = ReadStdin.readLine(text, args: _*) - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readBoolean() = ReadStdin.readBoolean() - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readByte() = ReadStdin.readByte() - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readShort() = ReadStdin.readShort() - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readChar() = ReadStdin.readChar() - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readInt() = ReadStdin.readInt() - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readLong() = ReadStdin.readLong() - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readFloat() = ReadStdin.readFloat() - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readDouble() = ReadStdin.readDouble() - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readf(format: String) = ReadStdin.readf(format) - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readf1(format: String) = ReadStdin.readf1(format) - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readf2(format: String) = ReadStdin.readf2(format) - @deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readf3(format: String) = ReadStdin.readf3(format) + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLine(): String = StdIn.readLine() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLine(text: String, args: Any*) = StdIn.readLine(text, args: _*) + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readBoolean() = StdIn.readBoolean() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readByte() = StdIn.readByte() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readShort() = StdIn.readShort() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readChar() = StdIn.readChar() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readInt() = StdIn.readInt() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLong() = StdIn.readLong() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readFloat() = StdIn.readFloat() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readDouble() = StdIn.readDouble() + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf(format: String) = StdIn.readf(format) + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf1(format: String) = StdIn.readf1(format) + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf2(format: String) = StdIn.readf2(format) + @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf3(format: String) = StdIn.readf3(format) } /** The `LowPriorityImplicits` class provides implicit values that diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala index 70f95750da..2d79452c5d 100644 --- a/src/library/scala/StringContext.scala +++ b/src/library/scala/StringContext.scala @@ -157,9 +157,8 @@ case class StringContext(parts: String*) { * If a formatting position does not refer to a `%` character (which is assumed to * start a format specifier), then the string format specifier `%s` is inserted. * - * 2. Any `%` characters not in formatting positions are left in the resulting - * string literally. This is achieved by replacing each such occurrence by the - * format specifier `%%`. + * 2. Any `%` characters not in formatting positions must begin one of the conversions + * `%%` (the literal percent) or `%n` (the platform-specific line separator). */ // The implementation is hardwired to `scala.tools.reflect.MacroImplementations.macro_StringInterpolation_f` // Using the mechanism implemented in `scala.tools.reflect.FastTrack` diff --git a/src/library/scala/collection/GenSeqLike.scala b/src/library/scala/collection/GenSeqLike.scala index e265beca1b..c3bad60072 100644 --- a/src/library/scala/collection/GenSeqLike.scala +++ b/src/library/scala/collection/GenSeqLike.scala @@ -38,8 +38,8 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal * Example: * * {{{ - * scala> val x = LinkedList(1, 2, 3, 4, 5) - * x: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4, 5) + * scala> val x = List(1, 2, 3, 4, 5) + * x: List[Int] = List(1, 2, 3, 4, 5) * * scala> x(3) * res1: Int = 4 @@ -302,14 +302,14 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal * * Example: * {{{ - * scala> val x = LinkedList(1) - * x: scala.collection.mutable.LinkedList[Int] = LinkedList(1) + * scala> val x = List(1) + * x: List[Int] = List(1) * * scala> val y = 2 +: x - * y: scala.collection.mutable.LinkedList[Int] = LinkedList(2, 1) + * y: List[Int] = List(2, 1) * * scala> println(x) - * LinkedList(1) + * List(1) * }}} * * @return a new $coll consisting of `elem` followed @@ -335,17 +335,14 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal * * Example: * {{{ - * scala> import scala.collection.mutable.LinkedList - * import scala.collection.mutable.LinkedList - * - * scala> val a = LinkedList(1) - * a: scala.collection.mutable.LinkedList[Int] = LinkedList(1) - * + * scala> val a = List(1) + * a: List[Int] = List(1) + * * scala> val b = a :+ 2 - * b: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2) - * + * b: List[Int] = List(1, 2) + * * scala> println(a) - * LinkedList(1) + * List(1) * }}} * * @return a new $coll consisting of diff --git a/src/library/scala/collection/GenTraversableLike.scala b/src/library/scala/collection/GenTraversableLike.scala index a0c519884c..ca098e57b9 100644 --- a/src/library/scala/collection/GenTraversableLike.scala +++ b/src/library/scala/collection/GenTraversableLike.scala @@ -267,20 +267,20 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with * * Example: * {{{ - * scala> val a = LinkedList(1) - * a: scala.collection.mutable.LinkedList[Int] = LinkedList(1) - * - * scala> val b = LinkedList(2) - * b: scala.collection.mutable.LinkedList[Int] = LinkedList(2) - * + * scala> val a = List(1) + * a: List[Int] = List(1) + * + * scala> val b = List(2) + * b: List[Int] = List(2) + * * scala> val c = a ++ b - * c: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2) - * - * scala> val d = LinkedList('a') - * d: scala.collection.mutable.LinkedList[Char] = LinkedList(a) - * + * c: List[Int] = List(1, 2) + * + * scala> val d = List('a') + * d: List[Char] = List(a) + * * scala> val e = c ++ d - * e: scala.collection.mutable.LinkedList[AnyVal] = LinkedList(1, 2, a) + * e: List[AnyVal] = List(1, 2, a) * }}} * * @return a new $coll which contains all elements of this $coll diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala index a9fe279599..01d179aeb6 100644 --- a/src/library/scala/collection/GenTraversableOnce.scala +++ b/src/library/scala/collection/GenTraversableOnce.scala @@ -130,8 +130,8 @@ trait GenTraversableOnce[+A] extends Any { * * Note that the folding function used to compute b is equivalent to that used to compute c. * {{{ - * scala> val a = LinkedList(1,2,3,4) - * a: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4) + * scala> val a = List(1,2,3,4) + * a: List[Int] = List(1, 2, 3, 4) * * scala> val b = (5 /: a)(_+_) * b: Int = 15 @@ -167,8 +167,8 @@ trait GenTraversableOnce[+A] extends Any { * * Note that the folding function used to compute b is equivalent to that used to compute c. * {{{ - * scala> val a = LinkedList(1,2,3,4) - * a: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4) + * scala> val a = List(1,2,3,4) + * a: List[Int] = List(1, 2, 3, 4) * * scala> val b = (a :\ 5)(_+_) * b: Int = 15 diff --git a/src/library/scala/collection/Iterable.scala b/src/library/scala/collection/Iterable.scala index 973efc447e..a5ab8efd5c 100644 --- a/src/library/scala/collection/Iterable.scala +++ b/src/library/scala/collection/Iterable.scala @@ -51,4 +51,4 @@ object Iterable extends TraversableFactory[Iterable] { } /** Explicit instantiation of the `Iterable` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractIterable[+A] extends AbstractTraversable[A] with Iterable[A] +abstract class AbstractIterable[+A] extends AbstractTraversable[A] with Iterable[A] diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index 72a23a0dd0..01a0aa3b51 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -1171,4 +1171,4 @@ trait Iterator[+A] extends TraversableOnce[A] { } /** Explicit instantiation of the `Iterator` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractIterator[+A] extends Iterator[A] +abstract class AbstractIterator[+A] extends Iterator[A] diff --git a/src/library/scala/collection/Map.scala b/src/library/scala/collection/Map.scala index 761b65723c..1e40fd8c24 100644 --- a/src/library/scala/collection/Map.scala +++ b/src/library/scala/collection/Map.scala @@ -56,4 +56,4 @@ object Map extends MapFactory[Map] { } /** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractMap[A, +B] extends AbstractIterable[(A, B)] with Map[A, B] +abstract class AbstractMap[A, +B] extends AbstractIterable[(A, B)] with Map[A, B] diff --git a/src/library/scala/collection/Seq.scala b/src/library/scala/collection/Seq.scala index b21acdd9b7..2f4b3e5f8a 100644 --- a/src/library/scala/collection/Seq.scala +++ b/src/library/scala/collection/Seq.scala @@ -38,4 +38,4 @@ object Seq extends SeqFactory[Seq] { } /** Explicit instantiation of the `Seq` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractSeq[+A] extends AbstractIterable[A] with Seq[A] +abstract class AbstractSeq[+A] extends AbstractIterable[A] with Seq[A] diff --git a/src/library/scala/collection/Set.scala b/src/library/scala/collection/Set.scala index 46d5dfa056..f74c26571a 100644 --- a/src/library/scala/collection/Set.scala +++ b/src/library/scala/collection/Set.scala @@ -44,4 +44,4 @@ object Set extends SetFactory[Set] { } /** Explicit instantiation of the `Set` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractSet[A] extends AbstractIterable[A] with Set[A] +abstract class AbstractSet[A] extends AbstractIterable[A] with Set[A] diff --git a/src/library/scala/collection/Traversable.scala b/src/library/scala/collection/Traversable.scala index 61d9a42f04..b53724c568 100644 --- a/src/library/scala/collection/Traversable.scala +++ b/src/library/scala/collection/Traversable.scala @@ -101,4 +101,4 @@ object Traversable extends TraversableFactory[Traversable] { self => } /** Explicit instantiation of the `Traversable` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractTraversable[+A] extends Traversable[A] +abstract class AbstractTraversable[+A] extends Traversable[A] diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala index 26af32046c..072fd3da44 100644 --- a/src/library/scala/collection/TraversableOnce.scala +++ b/src/library/scala/collection/TraversableOnce.scala @@ -320,14 +320,14 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] { * Example: * * {{{ - * scala> val a = LinkedList(1,2,3,4) - * a: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4) - * + * scala> val a = List(1,2,3,4) + * a: List[Int] = List(1, 2, 3, 4) + * * scala> val b = new StringBuilder() - * b: StringBuilder = - * - * scala> a.addString(b, "LinkedList(", ", ", ")") - * res1: StringBuilder = LinkedList(1, 2, 3, 4) + * b: StringBuilder = + * + * scala> a.addString(b , "List(" , ", " , ")") + * res5: StringBuilder = List(1, 2, 3, 4) * }}} * * @param b the string builder to which elements are appended. @@ -362,9 +362,9 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] { * Example: * * {{{ - * scala> val a = LinkedList(1,2,3,4) - * a: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4) - * + * scala> val a = List(1,2,3,4) + * a: List[Int] = List(1, 2, 3, 4) + * * scala> val b = new StringBuilder() * b: StringBuilder = * @@ -385,14 +385,14 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] { * Example: * * {{{ - * scala> val a = LinkedList(1,2,3,4) - * a: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4) - * + * scala> val a = List(1,2,3,4) + * a: List[Int] = List(1, 2, 3, 4) + * * scala> val b = new StringBuilder() * b: StringBuilder = * * scala> val h = a.addString(b) - * b: StringBuilder = 1234 + * h: StringBuilder = 1234 * }}} * @param b the string builder to which elements are appended. diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala index 56f1802509..14ae57c43a 100644 --- a/src/library/scala/collection/convert/Wrappers.scala +++ b/src/library/scala/collection/convert/Wrappers.scala @@ -102,8 +102,14 @@ private[collection] trait Wrappers { override def clone(): JListWrapper[A] = JListWrapper(new ju.ArrayList[A](underlying)) } + // Note various overrides to avoid performance gotchas. class SetWrapper[A](underlying: Set[A]) extends ju.AbstractSet[A] { self => + override def contains(o: Object): Boolean = { + try { underlying.contains(o.asInstanceOf[A]) } + catch { case cce: ClassCastException => false } + } + override def isEmpty = underlying.isEmpty def size = underlying.size def iterator = new ju.Iterator[A] { val ui = underlying.iterator diff --git a/src/library/scala/collection/generic/ImmutableSetFactory.scala b/src/library/scala/collection/generic/ImmutableSetFactory.scala index f4d4e061bb..a72caf2633 100644 --- a/src/library/scala/collection/generic/ImmutableSetFactory.scala +++ b/src/library/scala/collection/generic/ImmutableSetFactory.scala @@ -15,6 +15,7 @@ import scala.language.higherKinds abstract class ImmutableSetFactory[CC[X] <: immutable.Set[X] with SetLike[X, CC[X]]] extends SetFactory[CC] { - + private[collection] def emptyInstance: CC[Any] + override def empty[A] = emptyInstance.asInstanceOf[CC[A]] def newBuilder[A]: Builder[A, CC[A]] = new SetBuilder[A, CC[A]](empty[A]) } diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index fb0a34e64d..8a24f721d7 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -40,6 +40,8 @@ class HashMap[A, +B] extends AbstractMap[A, B] with Serializable with CustomParallelizable[(A, B), ParHashMap[A, B]] { + import HashMap.{nullToEmpty, bufferSize} + override def size: Int = 0 override def empty = HashMap.empty[A, B] @@ -59,11 +61,22 @@ class HashMap[A, +B] extends AbstractMap[A, B] override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): HashMap[A, B1] = this + elem1 + elem2 ++ elems - // TODO: optimize (might be able to use mutable updates) def - (key: A): HashMap[A, B] = removed0(key, computeHash(key), 0) + override def filter(p: ((A, B)) => Boolean) = { + val buffer = new Array[HashMap[A, B]](bufferSize(size)) + nullToEmpty(filter0(p, false, 0, buffer, 0)) + } + + override def filterNot(p: ((A, B)) => Boolean) = { + val buffer = new Array[HashMap[A, B]](bufferSize(size)) + nullToEmpty(filter0(p, true, 0, buffer, 0)) + } + + protected def filter0(p: ((A, B)) => Boolean, negate: Boolean, level: Int, buffer: Array[HashMap[A, B @uV]], offset0: Int): HashMap[A, B] = null + protected def elemHashCode(key: A) = key.## protected final def improve(hcode: Int) = { @@ -168,8 +181,6 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } } - // TODO: add HashMap2, HashMap3, ... - class HashMap1[A,+B](private[collection] val key: A, private[collection] val hash: Int, private[collection] val value: (B @uV), private[collection] var kv: (A,B @uV)) extends HashMap[A,B] { override def size = 1 @@ -203,6 +214,9 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = if (hash == this.hash && key == this.key) HashMap.empty[A,B] else this + override protected def filter0(p: ((A, B)) => Boolean, negate: Boolean, level: Int, buffer: Array[HashMap[A, B @uV]], offset0: Int): HashMap[A, B] = + if (negate ^ p(ensurePair)) this else null + override def iterator: Iterator[(A,B)] = Iterator(ensurePair) override def foreach[U](f: ((A, B)) => U): Unit = f(ensurePair) // this method may be called multiple times in a multithreaded environment, but that's ok @@ -233,16 +247,33 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = if (hash == this.hash) { val kvs1 = kvs - key - if (kvs1 eq kvs) + kvs1.size match { + case 0 => + HashMap.empty[A,B] + case 1 => + val kv = kvs1.head + new HashMap1(kv._1,hash,kv._2,kv) + case x if x == kvs.size => + this + case _ => + new HashMapCollision1(hash, kvs1) + } + } else this + + override protected def filter0(p: ((A, B)) => Boolean, negate: Boolean, level: Int, buffer: Array[HashMap[A, B @uV]], offset0: Int): HashMap[A, B] = { + val kvs1 = if(negate) kvs.filterNot(p) else kvs.filter(p) + kvs1.size match { + case 0 => + null + case 1 => + val kv@(k,v) = kvs1.head + new HashMap1(k, hash, v, kv) + case x if x == kvs.size => this - else if (kvs1.isEmpty) - HashMap.empty[A,B] - else if(kvs1.tail.isEmpty) { - val kv = kvs1.head - new HashMap1[A,B](kv._1,hash,kv._2,kv) - } else + case _ => new HashMapCollision1(hash, kvs1) - } else this + } + } override def iterator: Iterator[(A,B)] = kvs.iterator override def foreach[U](f: ((A, B)) => U): Unit = kvs.foreach(f) @@ -277,7 +308,6 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { elems(index & 0x1f).get0(key, hash, level + 5) } else if ((bitmap & mask) != 0) { val offset = Integer.bitCount(bitmap & (mask-1)) - // TODO: might be worth checking if sub is HashTrieMap (-> monomorphic call site) elems(offset).get0(key, hash, level + 5) } else None @@ -289,7 +319,6 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { val offset = Integer.bitCount(bitmap & (mask-1)) if ((bitmap & mask) != 0) { val sub = elems(offset) - // TODO: might be worth checking if sub is HashTrieMap (-> monomorphic call site) val subNew = sub.updated0(key, hash, level + 5, value, kv, merger) if(subNew eq sub) this else { val elemsNew = new Array[HashMap[A,B1]](elems.length) @@ -312,7 +341,6 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { val offset = Integer.bitCount(bitmap & (mask-1)) if ((bitmap & mask) != 0) { val sub = elems(offset) - // TODO: might be worth checking if sub is HashTrieMap (-> monomorphic call site) val subNew = sub.removed0(key, hash, level + 5) if (subNew eq sub) this else if (subNew.isEmpty) { @@ -342,6 +370,52 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } } + override protected def filter0(p: ((A, B)) => Boolean, negate: Boolean, level: Int, buffer: Array[HashMap[A, B @uV]], offset0: Int): HashMap[A, B] = { + // current offset + var offset = offset0 + // result size + var rs = 0 + // bitmap for kept elems + var kept = 0 + // loop over all elements + var i = 0 + while (i < elems.length) { + val result = elems(i).filter0(p, negate, level + 5, buffer, offset) + if (result ne null) { + buffer(offset) = result + offset += 1 + // add the result size + rs += result.size + // mark the bit i as kept + kept |= (1 << i) + } + i += 1 + } + if (offset == offset0) { + // empty + null + } else if (rs == size0) { + // unchanged + this + } else if (offset == offset0 + 1 && !buffer(offset0).isInstanceOf[HashTrieMap[A, B]]) { + // leaf + buffer(offset0) + } else { + // we have to return a HashTrieMap + val length = offset - offset0 + val elems1 = new Array[HashMap[A, B]](length) + System.arraycopy(buffer, offset0, elems1, 0, length) + val bitmap1 = if (length == elems.length) { + // we can reuse the original bitmap + bitmap + } else { + // calculate new bitmap by keeping just bits in the kept bitmask + keepBits(bitmap, kept) + } + new HashTrieMap(bitmap1, elems1, rs) + } + } + override def iterator: Iterator[(A, B)] = new TrieIterator[(A, B)](elems.asInstanceOf[Array[Iterable[(A, B)]]]) { final override def getElem(cc: AnyRef): (A, B) = cc.asInstanceOf[HashMap1[A, B]].ensurePair } @@ -445,6 +519,50 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } } + /** + * Calculates the maximum buffer size given the maximum possible total size of the trie-based collection + * @param size the maximum size of the collection to be generated + * @return the maximum buffer size + */ + @inline private def bufferSize(size: Int): Int = (size + 6) min (32 * 7) + + /** + * In many internal operations the empty map is represented as null for performance reasons. This method converts + * null to the empty map for use in public methods + */ + @inline private def nullToEmpty[A, B](m: HashMap[A, B]): HashMap[A, B] = if (m eq null) empty[A, B] else m + + /** + * Utility method to keep a subset of all bits in a given bitmap + * + * Example + * bitmap (binary): 00000001000000010000000100000001 + * keep (binary): 1010 + * result (binary): 00000001000000000000000100000000 + * + * @param bitmap the bitmap + * @param keep a bitmask containing which bits to keep + * @return the original bitmap with all bits where keep is not 1 set to 0 + */ + private def keepBits(bitmap: Int, keep: Int): Int = { + var result = 0 + var current = bitmap + var kept = keep + while (kept != 0) { + // lowest remaining bit in current + val lsb = current ^ (current & (current - 1)) + if ((kept & 1) != 0) { + // mark bit in result bitmap + result |= lsb + } + // clear lowest remaining one bit in abm + current &= ~lsb + // look at the next kept bit + kept >>>= 1 + } + result + } + @SerialVersionUID(2L) private class SerializationProxy[A,B](@transient private var orig: HashMap[A, B]) extends Serializable { private def writeObject(out: java.io.ObjectOutputStream) { diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index 9eaceccd9f..67e9d18da7 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -12,9 +12,10 @@ package scala package collection package immutable -import scala.annotation.unchecked.{ uncheckedVariance => uV } import generic._ import scala.collection.parallel.immutable.ParHashSet +import scala.collection.GenSet +import scala.annotation.tailrec /** This class implements immutable sets using a hash trie. * @@ -38,6 +39,8 @@ class HashSet[A] extends AbstractSet[A] with CustomParallelizable[A, ParHashSet[A]] with Serializable { + import HashSet.{nullToEmpty, bufferSize, LeafHashSet} + override def companion: GenericCompanion[HashSet] = HashSet //class HashSet[A] extends Set[A] with SetLike[A, HashSet[A]] { @@ -54,14 +57,122 @@ class HashSet[A] extends AbstractSet[A] def contains(e: A): Boolean = get0(e, computeHash(e), 0) + override def subsetOf(that: GenSet[A]) = that match { + case that:HashSet[A] => + // call the specialized implementation with a level of 0 since both this and that are top-level hash sets + subsetOf0(that, 0) + case _ => + // call the generic implementation + super.subsetOf(that) + } + + /** + * A specialized implementation of subsetOf for when both this and that are HashSet[A] and we can take advantage + * of the tree structure of both operands and the precalculated hashcodes of the HashSet1 instances. + * @param that the other set + * @param level the level of this and that hashset + * The purpose of level is to keep track of how deep we are in the tree. + * We need this information for when we arrive at a leaf and have to call get0 on that + * The value of level is 0 for a top-level HashSet and grows in increments of 5 + * @return true if all elements of this set are contained in that set + */ + protected def subsetOf0(that: HashSet[A], level: Int) = { + // The default implementation is for the empty set and returns true because the empty set is a subset of all sets + true + } + override def + (e: A): HashSet[A] = updated0(e, computeHash(e), 0) override def + (elem1: A, elem2: A, elems: A*): HashSet[A] = this + elem1 + elem2 ++ elems - // TODO: optimize (might be able to use mutable updates) + + override def union(that: GenSet[A]): HashSet[A] = that match { + case that: HashSet[A] => + val buffer = new Array[HashSet[A]](bufferSize(this.size + that.size)) + nullToEmpty(union0(that, 0, buffer, 0)) + case _ => super.union(that) + } + + override def intersect(that: GenSet[A]): HashSet[A] = that match { + case that: HashSet[A] => + val buffer = new Array[HashSet[A]](bufferSize(this.size min that.size)) + nullToEmpty(intersect0(that, 0, buffer, 0)) + case _ => super.intersect(that) + } + + override def diff(that: GenSet[A]): HashSet[A] = that match { + case that: HashSet[A] => + val buffer = new Array[HashSet[A]](bufferSize(this.size)) + nullToEmpty(diff0(that, 0, buffer, 0)) + case _ => super.diff(that) + } + + /** + * Union with a leaf HashSet at a given level. + * @param that a leaf HashSet + * @param level the depth in the tree. We need this when we have to create a branch node on top of this and that + * @return The union of this and that at the given level. Unless level is zero, the result is not a self-contained + * HashSet but needs to be stored at the correct depth + */ + private[immutable] def union0(that: LeafHashSet[A], level: Int): HashSet[A] = { + // the default implementation is for the empty set, so we just return that + that + } + + /** + * Union with a HashSet at a given level + * @param that a HashSet + * @param level the depth in the tree. We need to keep track of the level to know how deep we are in the tree + * @param buffer a temporary buffer that is used for temporarily storing elements when creating new branch nodes + * @param offset0 the first offset into the buffer in which we are allowed to write + * @return The union of this and that at the given level. Unless level is zero, the result is not a self-contained + * HashSet but needs to be stored at the correct depth + */ + private[immutable] def union0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = { + // the default implementation is for the empty set, so we just return that + that + } + + /** + * Intersection with another hash set at a given level + * @param level the depth in the tree. We need to keep track of the level to know how deep we are in the tree + * @param buffer a temporary buffer that is used for temporarily storing elements when creating new branch nodes + * @param offset0 the first offset into the buffer in which we are allowed to write + * @return The intersection of this and that at the given level. Unless level is zero, the result is not a + * self-contained HashSet but needs to be stored at the correct depth + */ + private[immutable] def intersect0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = { + // the default implementation is for the empty set, so we just return the empty set + null + } + + /** + * Diff with another hash set at a given level + * @param level the depth in the tree. We need to keep track of the level to know how deep we are in the tree + * @param buffer a temporary buffer that is used for temporarily storing elements when creating new branch nodes + * @param offset0 the first offset into the buffer in which we are allowed to write + * @return The diff of this and that at the given level. Unless level is zero, the result is not a + * self-contained HashSet but needs to be stored at the correct depth + */ + private[immutable] def diff0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = { + // the default implementation is for the empty set, so we just return the empty set + null + } def - (e: A): HashSet[A] = - removed0(e, computeHash(e), 0) + nullToEmpty(removed0(e, computeHash(e), 0)) + + override def filter(p: A => Boolean) = { + val buffer = new Array[HashSet[A]](bufferSize(size)) + nullToEmpty(filter0(p, false, 0, buffer, 0)) + } + + override def filterNot(p: A => Boolean) = { + val buffer = new Array[HashSet[A]](bufferSize(size)) + nullToEmpty(filter0(p, true, 0, buffer, 0)) + } + + protected def filter0(p: A => Boolean, negate: Boolean, level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = null protected def elemHashCode(key: A) = key.## @@ -100,10 +211,10 @@ object HashSet extends ImmutableSetFactory[HashSet] { /** $setCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HashSet[A]] = setCanBuildFrom[A] - override def empty[A]: HashSet[A] = EmptyHashSet.asInstanceOf[HashSet[A]] private object EmptyHashSet extends HashSet[Any] { } - + private[collection] def emptyInstance: HashSet[Any] = EmptyHashSet + // utility method to create a HashTrieSet from two leaf HashSets (HashSet1 or HashSetCollision1) with non-colliding hash code) private def makeHashTrieSet[A](hash0:Int, elem0:HashSet[A], hash1:Int, elem1:HashSet[A], level:Int) : HashTrieSet[A] = { val index0 = (hash0 >>> level) & 0x1f @@ -128,14 +239,27 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } - // TODO: add HashSet2, HashSet3, ... + /** + * Common superclass of HashSet1 and HashSetCollision1, which are the two possible leaves of the Trie + */ + private[HashSet] sealed abstract class LeafHashSet[A] extends HashSet[A] { + private[HashSet] def hash:Int + } - class HashSet1[A](private[HashSet] val key: A, private[HashSet] val hash: Int) extends HashSet[A] { + class HashSet1[A](private[HashSet] val key: A, private[HashSet] val hash: Int) extends LeafHashSet[A] { override def size = 1 override def get0(key: A, hash: Int, level: Int): Boolean = (hash == this.hash && key == this.key) + override def subsetOf0(that: HashSet[A], level: Int) = { + // check if that contains this.key + // we use get0 with our key and hash at the correct level instead of calling contains, + // which would not work since that might not be a top-level HashSet + // and in any case would be inefficient because it would require recalculating the hash code + that.get0(key, hash, level) + } + override def updated0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash && key == this.key) this else { @@ -147,35 +271,194 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } + override private[immutable] def union0(that: LeafHashSet[A], level: Int): HashSet[A] = that match { + case that if that.hash != this.hash => + // different hash code, so there is no need to investigate further. + // Just create a branch node containing the two. + makeHashTrieSet(this.hash, this, that.hash, that, level) + case that: HashSet1[A] => + if (this.key == that.key) { + this + } else { + // 32-bit hash collision (rare, but not impossible) + new HashSetCollision1[A](hash, ListSet.empty + this.key + that.key) + } + case that: HashSetCollision1[A] => + val ks1 = that.ks + key + // Could use eq check (faster) if ListSet was guaranteed to return itself + if (ks1.size == that.ks.size) { + that + } else { + new HashSetCollision1[A](hash, ks1) + } + } + + override private[immutable] def union0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int) = { + // switch to the Leaf version of union + // we can exchange the arguments because union is symmetrical + that.union0(this, level) + } + + override private[immutable] def intersect0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = + if (that.get0(key, hash, level)) this else null + + override private[immutable] def diff0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = + if (that.get0(key, hash, level)) null else this + override def removed0(key: A, hash: Int, level: Int): HashSet[A] = - if (hash == this.hash && key == this.key) HashSet.empty[A] else this + if (hash == this.hash && key == this.key) null else this + + override protected def filter0(p: A => Boolean, negate: Boolean, level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = + if (negate ^ p(key)) this else null override def iterator: Iterator[A] = Iterator(key) override def foreach[U](f: A => U): Unit = f(key) } - private[immutable] class HashSetCollision1[A](private[HashSet] val hash: Int, val ks: ListSet[A]) - extends HashSet[A] { + private[immutable] class HashSetCollision1[A](private[HashSet] val hash: Int, val ks: ListSet[A]) extends LeafHashSet[A] { override def size = ks.size override def get0(key: A, hash: Int, level: Int): Boolean = if (hash == this.hash) ks.contains(key) else false + override def subsetOf0(that: HashSet[A], level: Int) = { + // we have to check each element + // we use get0 with our hash at the correct level instead of calling contains, + // which would not work since that might not be a top-level HashSet + // and in any case would be inefficient because it would require recalculating the hash code + ks.forall(key => that.get0(key, hash, level)) + } + override def updated0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash) new HashSetCollision1(hash, ks + key) else makeHashTrieSet(this.hash, this, hash, new HashSet1(key, hash), level) + override def union0(that: LeafHashSet[A], level: Int): HashSet[A] = that match { + case that if that.hash != this.hash => + // different hash code, so there is no need to investigate further. + // Just create a branch node containing the two. + makeHashTrieSet(this.hash, this, that.hash, that, level) + case that: HashSet1[A] => + val ks1 = ks + that.key + // Could use eq check (faster) if ListSet was guaranteed to return itself + if (ks1.size == ks.size) { + this + } else { + // create a new HashSetCollision with the existing hash + // we don't have to check for size=1 because union is never going to remove elements + new HashSetCollision1[A](hash, ks1) + } + case that: HashSetCollision1[A] => + val ks1 = this.ks ++ that.ks + ks1.size match { + case size if size == this.ks.size => + // could this check be made faster by doing an eq check? + // I am not sure we can rely on ListSet returning itself when all elements are already in the set, + // so it seems unwise to rely on it. + this + case size if size == that.ks.size => + // we have to check this as well, since we don't want to create a new instance if this is a subset of that + that + case _ => + // create a new HashSetCollision with the existing hash + // we don't have to check for size=1 because union is never going to remove elements + new HashSetCollision1[A](hash, ks1) + } + } + + override def union0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = that match { + case that: LeafHashSet[A] => + // switch to the simpler Tree/Leaf implementation + this.union0(that, level) + case that: HashTrieSet[A] => + // switch to the simpler Tree/Leaf implementation + // we can swap this and that because union is symmetrical + that.union0(this, level) + case _ => this + } + + override private[immutable] def intersect0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = { + // filter the keys, taking advantage of the fact that we know their hash code + val ks1 = ks.filter(that.get0(_, hash, level)) + ks1.size match { + case 0 => + // the empty set + null + case size if size == this.size => + // unchanged + // We do this check first since even if the result is of size 1 since + // it is preferable to return the existing set for better structural sharing + this + case size if size == that.size => + // the other set + // We do this check first since even if the result is of size 1 since + // it is preferable to return the existing set for better structural sharing + that + case 1 => + // create a new HashSet1 with the hash we already know + new HashSet1(ks1.head, hash) + case _ => + // create a new HashSetCollison with the hash we already know and the new keys + new HashSetCollision1(hash, ks1) + } + } + + override private[immutable] def diff0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = { + val ks1 = ks.filterNot(that.get0(_, hash, level)) + ks1.size match { + case 0 => + // the empty set + null + case size if size == this.size => + // unchanged + // We do this check first since even if the result is of size 1 since + // it is preferable to return the existing set for better structural sharing + this + case 1 => + // create a new HashSet1 with the hash we already know + new HashSet1(ks1.head, hash) + case _ => + // create a new HashSetCollison with the hash we already know and the new keys + new HashSetCollision1(hash, ks1) + } + } + override def removed0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash) { val ks1 = ks - key - if(ks1.isEmpty) - HashSet.empty[A] - else if(ks1.tail.isEmpty) + ks1.size match { + case 0 => + // the empty set + null + case size if size == ks.size => + // We do this check first since even if the result is of size 1 since + // it is preferable to return the existing set for better structural sharing + // we can not rely on ks.- returning the same instance if we subtract an element that is not in it + // so we need to do the size check + this + case 1 => + // create a new HashSet1 with the hash we already know + new HashSet1(ks1.head, hash) + case _ => + // create a new HashSetCollison with the hash we already know and the new keys + new HashSetCollision1(hash, ks1) + } + } else this + + override protected def filter0(p: A => Boolean, negate: Boolean, level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = { + val ks1 = if(negate) ks.filterNot(p) else ks.filter(p) + ks1.size match { + case 0 => + null + case 1 => new HashSet1(ks1.head, hash) - else + case x if x == ks.size => + this + case _ => new HashSetCollision1(hash, ks1) - } else this + } + } override def iterator: Iterator[A] = ks.iterator override def foreach[U](f: A => U): Unit = ks.foreach(f) @@ -197,6 +480,42 @@ object HashSet extends ImmutableSetFactory[HashSet] { } + /** + * A branch node of the HashTrieSet with at least one and up to 32 children. + * + * @param bitmap encodes which element corresponds to which child + * @param elems the up to 32 children of this node. + * the number of children must be identical to the number of 1 bits in bitmap + * @param size0 the total number of elements. This is stored just for performance reasons. + * @tparam A the type of the elements contained in this hash set. + * + * How levels work: + * + * When looking up or adding elements, the part of the hashcode that is used to address the children array depends + * on how deep we are in the tree. This is accomplished by having a level parameter in all internal methods + * that starts at 0 and increases by 5 (32 = 2^5) every time we go deeper into the tree. + * + * hashcode (binary): 00000000000000000000000000000000 + * level=0 (depth=0) ^^^^^ + * level=5 (depth=1) ^^^^^ + * level=10 (depth=2) ^^^^^ + * ... + * + * Be careful: a non-toplevel HashTrieSet is not a self-contained set, so e.g. calling contains on it will not work! + * It relies on its depth in the Trie for which part of a hash to use to address the children, but this information + * (the level) is not stored due to storage efficiency reasons but has to be passed explicitly! + * + * How bitmap and elems correspond: + * + * A naive implementation of a HashTrieSet would always have an array of size 32 for children and leave the unused + * children empty (null). But that would be very wasteful regarding memory. Instead, only non-empty children are + * stored in elems, and the bitmap is used to encode which elem corresponds to which child bucket. The lowest 1 bit + * corresponds to the first element, the second-lowest to the second, etc. + * + * bitmap (binary): 00010000000000000000100000000000 + * elems: [a,b] + * children: ---b----------------a----------- + */ class HashTrieSet[A](private val bitmap: Int, private[collection] val elems: Array[HashSet[A]], private val size0: Int) extends HashSet[A] { assert(Integer.bitCount(bitmap) == elems.length) @@ -212,7 +531,6 @@ object HashSet extends ImmutableSetFactory[HashSet] { elems(index & 0x1f).get0(key, hash, level + 5) } else if ((bitmap & mask) != 0) { val offset = Integer.bitCount(bitmap & (mask-1)) - // TODO: might be worth checking if sub is HashTrieSet (-> monomorphic call site) elems(offset).get0(key, hash, level + 5) } else false @@ -223,7 +541,6 @@ object HashSet extends ImmutableSetFactory[HashSet] { val mask = (1 << index) val offset = Integer.bitCount(bitmap & (mask-1)) if ((bitmap & mask) != 0) { - // TODO: might be worth checking if sub is HashTrieSet (-> monomorphic call site) val sub = elems(offset) val subNew = sub.updated0(key, hash, level + 5) if (sub eq subNew) this @@ -243,16 +560,293 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } + override private[immutable] def union0(that: LeafHashSet[A], level: Int): HashSet[A] = { + val index = (that.hash >>> level) & 0x1f + val mask = (1 << index) + val offset = Integer.bitCount(bitmap & (mask - 1)) + if ((bitmap & mask) != 0) { + val sub = elems(offset) + val sub1 = sub.union0(that, level + 5) + if (sub eq sub1) this + else { + val elems1 = new Array[HashSet[A]](elems.length) + Array.copy(elems, 0, elems1, 0, elems.length) + elems1(offset) = sub1 + new HashTrieSet(bitmap, elems1, size + (sub1.size - sub.size)) + } + } else { + val elems1 = new Array[HashSet[A]](elems.length + 1) + Array.copy(elems, 0, elems1, 0, offset) + elems1(offset) = that + Array.copy(elems, offset, elems1, offset + 1, elems.length - offset) + val bitmap1 = bitmap | mask + new HashTrieSet(bitmap1, elems1, size + that.size) + } + } + + override private[immutable] def union0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = that match { + case that if that eq this => + // shortcut for when that is this + // this happens often for nodes deeper in the tree, especially when that and this share a common "heritage" + // e.g. you have a large set A and do some small operations (adding and removing elements) to it to create B + // then A and B will have the vast majority of nodes in common, and this eq check will allow not even looking + // at these nodes. + this + case that: LeafHashSet[A] => + // when that is a leaf, we can switch to the simpler Tree/Leaf implementation + this.union0(that, level) + case that: HashTrieSet[A] => + val a = this.elems + var abm = this.bitmap + var ai = 0 + + val b = that.elems + var bbm = that.bitmap + var bi = 0 + + // fetch a new temporary array that is guaranteed to be big enough (32 elements) + var offset = offset0 + var rs = 0 + + // loop as long as there are bits left in either abm or bbm + while ((abm | bbm) != 0) { + // lowest remaining bit in abm + val alsb = abm ^ (abm & (abm - 1)) + // lowest remaining bit in bbm + val blsb = bbm ^ (bbm & (bbm - 1)) + if (alsb == blsb) { + val sub1 = a(ai).union0(b(bi), level + 5, buffer, offset) + rs += sub1.size + buffer(offset) = sub1 + offset += 1 + // clear lowest remaining one bit in abm and increase the a index + abm &= ~alsb + ai += 1 + // clear lowest remaining one bit in bbm and increase the b index + bbm &= ~blsb + bi += 1 + } else if (unsignedCompare(alsb - 1, blsb - 1)) { + // alsb is smaller than blsb, or alsb is set and blsb is 0 + // in any case, alsb is guaranteed to be set here! + val sub1 = a(ai) + rs += sub1.size + buffer(offset) = sub1 + offset += 1 + // clear lowest remaining one bit in abm and increase the a index + abm &= ~alsb + ai += 1 + } else { + // blsb is smaller than alsb, or blsb is set and alsb is 0 + // in any case, blsb is guaranteed to be set here! + val sub1 = b(bi) + rs += sub1.size + buffer(offset) = sub1 + offset += 1 + // clear lowest remaining one bit in bbm and increase the b index + bbm &= ~blsb + bi += 1 + } + } + if (rs == this.size) { + // if the result would be identical to this, we might as well return this + this + } else if (rs == that.size) { + // if the result would be identical to that, we might as well return that + that + } else { + // we don't have to check whether the result is a leaf, since union will only make the set larger + // and this is not a leaf to begin with. + val length = offset - offset0 + val elems = new Array[HashSet[A]](length) + System.arraycopy(buffer, offset0, elems, 0, length) + new HashTrieSet(this.bitmap | that.bitmap, elems, rs) + } + case _ => this + } + + override private[immutable] def intersect0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = that match { + case that if that eq this => + // shortcut for when that is this + // this happens often for nodes deeper in the tree, especially when that and this share a common "heritage" + // e.g. you have a large set A and do some small operations (adding and removing elements) to it to create B + // then A and B will have the vast majority of nodes in common, and this eq check will allow not even looking + // at these nodes! + this + case that: LeafHashSet[A] => + // when that is a leaf, we can switch to the simpler Tree/Leaf implementation + // it is OK to swap the arguments because intersect is symmetric + // (we can't do this in case of diff, which is not symmetric) + that.intersect0(this, level, buffer, offset0) + case that: HashTrieSet[A] => + val a = this.elems + var abm = this.bitmap + var ai = 0 + + val b = that.elems + var bbm = that.bitmap + var bi = 0 + + // if the bitmasks do not overlap, the result is definitely empty so we can abort here + if ((abm & bbm) == 0) + return null + + // fetch a new temporary array that is guaranteed to be big enough (32 elements) + var offset = offset0 + var rs = 0 + var rbm = 0 + + // loop as long as there are bits left that are set in both abm and bbm + while ((abm & bbm) != 0) { + // highest remaining bit in abm + val alsb = abm ^ (abm & (abm - 1)) + // highest remaining bit in bbm + val blsb = bbm ^ (bbm & (bbm - 1)) + if (alsb == blsb) { + val sub1 = a(ai).intersect0(b(bi), level + 5, buffer, offset) + if (sub1 ne null) { + rs += sub1.size + rbm |= alsb + buffer(offset) = sub1 + offset += 1 + } + // clear lowest remaining one bit in abm and increase the a index + abm &= ~alsb; + ai += 1 + // clear lowest remaining one bit in bbm and increase the b index + bbm &= ~blsb; + bi += 1 + } else if (unsignedCompare(alsb - 1, blsb - 1)) { + // alsb is smaller than blsb, or alsb is set and blsb is 0 + // in any case, alsb is guaranteed to be set here! + // clear lowest remaining one bit in abm and increase the a index + abm &= ~alsb; + ai += 1 + } else { + // blsb is smaller than alsb, or blsb is set and alsb is 0 + // in any case, blsb is guaranteed to be set here! + // clear lowest remaining one bit in bbm and increase the b index + bbm &= ~blsb; + bi += 1 + } + } + + if (rbm == 0) { + // if the result bitmap is empty, the result is the empty set + null + } else if (rs == size0) { + // if the result has the same number of elements as this, it must be identical to this, + // so we might as well return this + this + } else if (rs == that.size0) { + // if the result has the same number of elements as that, it must be identical to that, + // so we might as well return that + that + } else { + val length = offset - offset0 + if (length == 1 && !buffer(offset0).isInstanceOf[HashTrieSet[A]]) + buffer(offset0) + else { + val elems = new Array[HashSet[A]](length) + System.arraycopy(buffer, offset0, elems, 0, length) + new HashTrieSet[A](rbm, elems, rs) + } + } + case _ => null + } + + override private[immutable] def diff0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = that match { + case that if that eq this => + // shortcut for when that is this + // this happens often for nodes deeper in the tree, especially when that and this share a common "heritage" + // e.g. you have a large set A and do some small operations (adding and removing elements) to it to create B + // then A and B will have the vast majority of nodes in common, and this eq check will allow not even looking + // at these nodes! + null + case that: HashSet1[A] => + removed0(that.key, that.hash, level) + case that: HashTrieSet[A] => + val a = this.elems + var abm = this.bitmap + var ai = 0 + + val b = that.elems + var bbm = that.bitmap + var bi = 0 + + // fetch a new temporary array that is guaranteed to be big enough (32 elements) + var offset = offset0 + var rs = 0 + var rbm = 0 + + // loop until there are no more bits in abm + while(abm!=0) { + // highest remaining bit in abm + val alsb = abm ^ (abm & (abm - 1)) + // highest remaining bit in bbm + val blsb = bbm ^ (bbm & (bbm - 1)) + if (alsb == blsb) { + val sub1 = a(ai).diff0(b(bi), level + 5, buffer, offset) + if (sub1 ne null) { + rs += sub1.size + rbm |= alsb + buffer(offset) = sub1 + offset += 1 + } + // clear lowest remaining one bit in abm and increase the a index + abm &= ~alsb; ai += 1 + // clear lowest remaining one bit in bbm and increase the b index + bbm &= ~blsb; bi += 1 + } else if (unsignedCompare(alsb - 1, blsb - 1)) { + // alsb is smaller than blsb, or alsb is set and blsb is 0 + // in any case, alsb is guaranteed to be set here! + val sub1 = a(ai) + rs += sub1.size + rbm |= alsb + buffer(offset) = sub1; offset += 1 + // clear lowest remaining one bit in abm and increase the a index + abm &= ~alsb; ai += 1 + } else { + // blsb is smaller than alsb, or blsb is set and alsb is 0 + // in any case, blsb is guaranteed to be set here! + // clear lowest remaining one bit in bbm and increase the b index + bbm &= ~blsb; bi += 1 + } + } + if (rbm == 0) { + null + } else if (rs == this.size0) { + // if the result has the same number of elements as this, it must be identical to this, + // so we might as well return this + this + } else { + val length = offset - offset0 + if (length == 1 && !buffer(offset0).isInstanceOf[HashTrieSet[A]]) + buffer(offset0) + else { + val elems = new Array[HashSet[A]](length) + System.arraycopy(buffer, offset0, elems, 0, length) + new HashTrieSet[A](rbm, elems, rs) + } + } + case that: HashSetCollision1[A] => + // we remove the elements using removed0 so we can use the fact that we know the hash of all elements + // to be removed + @tailrec def removeAll(s:HashSet[A], r:ListSet[A]) : HashSet[A] = + if(r.isEmpty || (s eq null)) s + else removeAll(s.removed0(r.head, that.hash, level), r.tail) + removeAll(this, that.ks) + case _ => this + } + override def removed0(key: A, hash: Int, level: Int): HashSet[A] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) val offset = Integer.bitCount(bitmap & (mask-1)) if ((bitmap & mask) != 0) { val sub = elems(offset) - // TODO: might be worth checking if sub is HashTrieMap (-> monomorphic call site) val subNew = sub.removed0(key, hash, level + 5) if (sub eq subNew) this - else if (subNew.isEmpty) { + else if (subNew eq null) { val bitmapNew = bitmap ^ mask if (bitmapNew != 0) { val elemsNew = new Array[HashSet[A]](elems.length - 1) @@ -266,7 +860,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { else new HashTrieSet(bitmapNew, elemsNew, sizeNew) } else - HashSet.empty[A] + null } else { val elemsNew = new Array[HashSet[A]](elems.length) Array.copy(elems, 0, elemsNew, 0, elems.length) @@ -279,6 +873,95 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } + override def subsetOf0(that: HashSet[A], level: Int): Boolean = if (that eq this) true else that match { + case that: HashTrieSet[A] if this.size0 <= that.size0 => + // create local mutable copies of members + var abm = this.bitmap + val a = this.elems + var ai = 0 + val b = that.elems + var bbm = that.bitmap + var bi = 0 + if ((abm & bbm) == abm) { + // I tried rewriting this using tail recursion, but the generated java byte code was less than optimal + while(abm!=0) { + // highest remaining bit in abm + val alsb = abm ^ (abm & (abm - 1)) + // highest remaining bit in bbm + val blsb = bbm ^ (bbm & (bbm - 1)) + // if both trees have a bit set at the same position, we need to check the subtrees + if (alsb == blsb) { + // we are doing a comparison of a child of this with a child of that, + // so we have to increase the level by 5 to keep track of how deep we are in the tree + if (!a(ai).subsetOf0(b(bi), level + 5)) + return false + // clear lowest remaining one bit in abm and increase the a index + abm &= ~alsb; ai += 1 + } + // clear lowermost remaining one bit in bbm and increase the b index + // we must do this in any case + bbm &= ~blsb; bi += 1 + } + true + } else { + // the bitmap of this contains more one bits than the bitmap of that, + // so this can not possibly be a subset of that + false + } + case _ => + // if the other set is a HashTrieSet but has less elements than this, it can not be a subset + // if the other set is a HashSet1, we can not be a subset of it because we are a HashTrieSet with at least two children (see assertion) + // if the other set is a HashSetCollision1, we can not be a subset of it because we are a HashTrieSet with at least two different hash codes + // if the other set is the empty set, we are not a subset of it because we are not empty + false + } + + override protected def filter0(p: A => Boolean, negate: Boolean, level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = { + // current offset + var offset = offset0 + // result size + var rs = 0 + // bitmap for kept elems + var kept = 0 + // loop over all elements + var i = 0 + while (i < elems.length) { + val result = elems(i).filter0(p, negate, level + 5, buffer, offset) + if (result ne null) { + buffer(offset) = result + offset += 1 + // add the result size + rs += result.size + // mark the bit i as kept + kept |= (1 << i) + } + i += 1 + } + if (offset == offset0) { + // empty + null + } else if (rs == size0) { + // unchanged + this + } else if (offset == offset0 + 1 && !buffer(offset0).isInstanceOf[HashTrieSet[A]]) { + // leaf + buffer(offset0) + } else { + // we have to return a HashTrieSet + val length = offset - offset0 + val elems1 = new Array[HashSet[A]](length) + System.arraycopy(buffer, offset0, elems1, 0, length) + val bitmap1 = if (length == elems.length) { + // we can reuse the original bitmap + bitmap + } else { + // calculate new bitmap by keeping just bits in the kept bitmask + keepBits(bitmap, kept) + } + new HashTrieSet(bitmap1, elems1, rs) + } + } + override def iterator = new TrieIterator[A](elems.asInstanceOf[Array[Iterable[A]]]) { final override def getElem(cc: AnyRef): A = cc.asInstanceOf[HashSet1[A]].key } @@ -292,6 +975,54 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } + /** + * Calculates the maximum buffer size given the maximum possible total size of the trie-based collection + * @param size the maximum size of the collection to be generated + * @return the maximum buffer size + */ + @inline private def bufferSize(size: Int): Int = (size + 6) min (32 * 7) + + /** + * In many internal operations the empty set is represented as null for performance reasons. This method converts + * null to the empty set for use in public methods + */ + @inline private def nullToEmpty[A](s: HashSet[A]): HashSet[A] = if (s eq null) empty[A] else s + + /** + * Utility method to keep a subset of all bits in a given bitmap + * + * Example + * bitmap (binary): 00000001000000010000000100000001 + * keep (binary): 1010 + * result (binary): 00000001000000000000000100000000 + * + * @param bitmap the bitmap + * @param keep a bitmask containing which bits to keep + * @return the original bitmap with all bits where keep is not 1 set to 0 + */ + private def keepBits(bitmap: Int, keep: Int): Int = { + var result = 0 + var current = bitmap + var kept = keep + while (kept != 0) { + // lowest remaining bit in current + val lsb = current ^ (current & (current - 1)) + if ((kept & 1) != 0) { + // mark bit in result bitmap + result |= lsb + } + // clear lowest remaining one bit in abm + current &= ~lsb + // look at the next kept bit + kept >>>= 1 + } + result + } + + // unsigned comparison + @inline private[this] def unsignedCompare(i: Int, j: Int) = + (i < j) ^ (i < 0) ^ (j < 0) + @SerialVersionUID(2L) private class SerializationProxy[A,B](@transient private var orig: HashSet[A]) extends Serializable { private def writeObject(out: java.io.ObjectOutputStream) { val s = orig.size diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 90aabc5a9a..c3728fa02a 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -325,36 +325,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] // Create a proxy for Java serialization that allows us to avoid mutation // during de-serialization. This is the Serialization Proxy Pattern. - protected final def writeReplace(): AnyRef = new SerializationProxy(this) -} - -@SerialVersionUID(1L) -private class SerializationProxy[B](@transient private var orig: List[B]) extends Serializable { - - private def writeObject(out: ObjectOutputStream) { - var xs: List[B] = orig - while (!xs.isEmpty) { - out.writeObject(xs.head) - xs = xs.tail - } - out.writeObject(ListSerializeEnd) - } - - // Java serialization calls this before readResolve during de-serialization. - // Read the whole list and store it in `orig`. - private def readObject(in: ObjectInputStream) { - val builder = List.newBuilder[B] - while (true) in.readObject match { - case ListSerializeEnd => - orig = builder.result() - return - case a => - builder += a.asInstanceOf[B] - } - } - - // Provide the result stored in `orig` for Java serialization - private def readResolve(): AnyRef = orig + protected final def writeReplace(): AnyRef = new List.SerializationProxy(this) } /** The empty list. @@ -385,8 +356,7 @@ case object Nil extends List[Nothing] { * @version 1.0, 15/07/2003 * @since 2.8 */ -final case class ::[B](private val hd: B, private[scala] var tl: List[B]) extends List[B] { - override def head : B = hd +final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] { override def tail : List[B] = tl override def isEmpty: Boolean = false } @@ -405,6 +375,35 @@ object List extends SeqFactory[List] { override def empty[A]: List[A] = Nil override def apply[A](xs: A*): List[A] = xs.toList + + @SerialVersionUID(1L) + private class SerializationProxy[A](@transient private var orig: List[A]) extends Serializable { + + private def writeObject(out: ObjectOutputStream) { + var xs: List[A] = orig + while (!xs.isEmpty) { + out.writeObject(xs.head) + xs = xs.tail + } + out.writeObject(ListSerializeEnd) + } + + // Java serialization calls this before readResolve during de-serialization. + // Read the whole list and store it in `orig`. + private def readObject(in: ObjectInputStream) { + val builder = List.newBuilder[A] + while (true) in.readObject match { + case ListSerializeEnd => + orig = builder.result() + return + case a => + builder += a.asInstanceOf[A] + } + } + + // Provide the result stored in `orig` for Java serialization + private def readResolve(): AnyRef = orig + } } /** Only used for list serialization */ diff --git a/src/library/scala/collection/immutable/ListMap.scala b/src/library/scala/collection/immutable/ListMap.scala index b2a1b1ce29..7c40e84280 100644 --- a/src/library/scala/collection/immutable/ListMap.scala +++ b/src/library/scala/collection/immutable/ListMap.scala @@ -123,12 +123,12 @@ extends AbstractMap[A, B] def hasNext = !self.isEmpty def next(): (A,B) = if (!hasNext) throw new NoSuchElementException("next on empty iterator") - else { val res = (self.key, self.value); self = self.tail; res } + else { val res = (self.key, self.value); self = self.next; res } }.toList.reverseIterator protected def key: A = throw new NoSuchElementException("empty map") protected def value: B = throw new NoSuchElementException("empty map") - override def tail: ListMap[A, B] = throw new NoSuchElementException("empty map") + protected def next: ListMap[A, B] = throw new NoSuchElementException("empty map") /** This class represents an entry in the `ListMap`. */ @@ -142,7 +142,7 @@ extends AbstractMap[A, B] override def size: Int = size0(this, 0) // to allow tail recursion and prevent stack overflows - @tailrec private def size0(cur: ListMap[A, B1], acc: Int): Int = if (cur.isEmpty) acc else size0(cur.tail, acc + 1) + @tailrec private def size0(cur: ListMap[A, B1], acc: Int): Int = if (cur.isEmpty) acc else size0(cur.next, acc + 1) /** Is this an empty map? * @@ -163,7 +163,7 @@ extends AbstractMap[A, B] @tailrec private def apply0(cur: ListMap[A, B1], k: A): B1 = if (cur.isEmpty) throw new NoSuchElementException("key not found: "+k) else if (k == cur.key) cur.value - else apply0(cur.tail, k) + else apply0(cur.next, k) /** Checks if this map maps `key` to a value and return the * value if it exists. @@ -175,7 +175,7 @@ extends AbstractMap[A, B] @tailrec private def get0(cur: ListMap[A, B1], k: A): Option[B1] = if (k == cur.key) Some(cur.value) - else if (cur.tail.nonEmpty) get0(cur.tail, k) else None + else if (cur.next.nonEmpty) get0(cur.next, k) else None /** This method allows one to create a new map with an additional mapping * from `key` to `value`. If the map contains already a mapping for `key`, @@ -196,12 +196,12 @@ extends AbstractMap[A, B] if (cur.isEmpty) acc.last else if (k == cur.key) - (cur.tail /: acc) { + (cur.next /: acc) { case (t, h) => val tt = t; new tt.Node(h.key, h.value) // SI-7459 } else - remove0(k, cur.tail, cur::acc) + remove0(k, cur.next, cur::acc) - override def tail: ListMap[A, B1] = ListMap.this + override protected def next: ListMap[A, B1] = ListMap.this } } diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala index 7ebaa26d26..1bb07eb02d 100644 --- a/src/library/scala/collection/immutable/ListSet.scala +++ b/src/library/scala/collection/immutable/ListSet.scala @@ -22,10 +22,11 @@ import mutable.{ ListBuffer, Builder } object ListSet extends ImmutableSetFactory[ListSet] { /** setCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListSet[A]] = setCanBuildFrom[A] - override def empty[A] = EmptyListSet.asInstanceOf[ListSet[A]] + override def newBuilder[A]: Builder[A, ListSet[A]] = new ListSetBuilder[A] private object EmptyListSet extends ListSet[Any] { } + private[collection] def emptyInstance: ListSet[Any] = EmptyListSet /** A custom builder because forgetfully adding elements one at * a time to a list backed set puts the "squared" in N^2. There is a diff --git a/src/library/scala/collection/immutable/Map.scala b/src/library/scala/collection/immutable/Map.scala index 8933c7cf77..5178d5a862 100644 --- a/src/library/scala/collection/immutable/Map.scala +++ b/src/library/scala/collection/immutable/Map.scala @@ -32,9 +32,9 @@ trait Map[A, +B] extends Iterable[(A, B)] with MapLike[A, B, Map[A, B]] { self => override def empty: Map[A, B] = Map.empty - + /** Returns this $coll as an immutable map. - * + * * A new map will not be built; lazy collections will stay lazy. */ @deprecatedOverriding("Immutable maps should do nothing on toMap except return themselves cast as a map.", "2.11.0") @@ -191,4 +191,4 @@ object Map extends ImmutableMapFactory[Map] { } /** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractMap[A, +B] extends scala.collection.AbstractMap[A, B] with Map[A, B] +abstract class AbstractMap[A, +B] extends scala.collection.AbstractMap[A, B] with Map[A, B] diff --git a/src/library/scala/collection/immutable/NumericRange.scala b/src/library/scala/collection/immutable/NumericRange.scala index 486c2b6c8f..f1ac161e9a 100644 --- a/src/library/scala/collection/immutable/NumericRange.scala +++ b/src/library/scala/collection/immutable/NumericRange.scala @@ -175,9 +175,36 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { catch { case _: ClassCastException => false } final override def sum[B >: T](implicit num: Numeric[B]): B = { - if (isEmpty) this.num fromInt 0 - else if (numRangeElements == 1) head - else ((this.num fromInt numRangeElements) * (head + last) / (this.num fromInt 2)) + // arithmetic series formula can be used for regular addition + if ((num eq scala.math.Numeric.IntIsIntegral)|| + (num eq scala.math.Numeric.BigIntIsIntegral)|| + (num eq scala.math.Numeric.ShortIsIntegral)|| + (num eq scala.math.Numeric.ByteIsIntegral)|| + (num eq scala.math.Numeric.CharIsIntegral)|| + (num eq scala.math.Numeric.LongIsIntegral)|| + (num eq scala.math.Numeric.FloatAsIfIntegral)|| + (num eq scala.math.Numeric.BigDecimalIsFractional)|| + (num eq scala.math.Numeric.DoubleAsIfIntegral)) { + val numAsIntegral = num.asInstanceOf[Integral[B]] + import numAsIntegral._ + if (isEmpty) num fromInt 0 + else if (numRangeElements == 1) head + else ((num fromInt numRangeElements) * (head + last) / (num fromInt 2)) + } else { + // user provided custom Numeric, we cannot rely on arithmetic series formula + if (isEmpty) num.zero + else { + var acc = num.zero + var i = head + var idx = 0 + while(idx < length) { + acc = num.plus(acc, i) + i = i + step + idx = idx + 1 + } + acc + } + } } override lazy val hashCode = super.hashCode() @@ -214,28 +241,79 @@ object NumericRange { else if (start == end) if (isInclusive) 1 else 0 else if (upward != posStep) 0 else { - val diff = num.minus(end, start) - val jumps = num.toLong(num.quot(diff, step)) - val remainder = num.rem(diff, step) - val longCount = jumps + ( - if (!isInclusive && zero == remainder) 0 else 1 - ) - - /* The edge cases keep coming. Since e.g. - * Long.MaxValue + 1 == Long.MinValue - * we do some more improbable seeming checks lest - * overflow turn up as an empty range. + /* We have to be frightfully paranoid about running out of range. + * We also can't assume that the numbers will fit in a Long. + * We will assume that if a > 0, -a can be represented, and if + * a < 0, -a+1 can be represented. We also assume that if we + * can't fit in Int, we can represent 2*Int.MaxValue+3 (at least). + * And we assume that numbers wrap rather than cap when they overflow. */ - // The second condition contradicts an empty result. - val isOverflow = longCount == 0 && num.lt(num.plus(start, step), end) == upward - - if (longCount > scala.Int.MaxValue || longCount < 0L || isOverflow) { - val word = if (isInclusive) "to" else "until" - val descr = List(start, word, end, "by", step) mkString " " - - throw new IllegalArgumentException(descr + ": seqs cannot contain more than Int.MaxValue elements.") + // Check whether we can short-circuit by deferring to Int range. + val startint = num.toInt(start) + if (start == num.fromInt(startint)) { + val endint = num.toInt(end) + if (end == num.fromInt(endint)) { + val stepint = num.toInt(step) + if (step == num.fromInt(stepint)) { + return { + if (isInclusive) Range.inclusive(startint, endint, stepint).length + else Range (startint, endint, stepint).length + } + } + } + } + // If we reach this point, deferring to Int failed. + // Numbers may be big. + val one = num.one + val limit = num.fromInt(Int.MaxValue) + def check(t: T): T = + if (num.gt(t, limit)) throw new IllegalArgumentException("More than Int.MaxValue elements.") + else t + // If the range crosses zero, it might overflow when subtracted + val startside = num.signum(start) + val endside = num.signum(end) + num.toInt{ + if (startside*endside >= 0) { + // We're sure we can subtract these numbers. + // Note that we do not use .rem because of different conventions for Long and BigInt + val diff = num.minus(end, start) + val quotient = check(num.quot(diff, step)) + val remainder = num.minus(diff, num.times(quotient, step)) + if (!isInclusive && zero == remainder) quotient else check(num.plus(quotient, one)) + } + else { + // We might not even be able to subtract these numbers. + // Jump in three pieces: + // * start to -1 or 1, whichever is closer (waypointA) + // * one step, which will take us at least to 0 (ends at waypointB) + // * there to the end + val negone = num.fromInt(-1) + val startlim = if (posStep) negone else one + val startdiff = num.minus(startlim, start) + val startq = check(num.quot(startdiff, step)) + val waypointA = if (startq == zero) start else num.plus(start, num.times(startq, step)) + val waypointB = num.plus(waypointA, step) + check { + if (num.lt(waypointB, end) != upward) { + // No last piece + if (isInclusive && waypointB == end) num.plus(startq, num.fromInt(2)) + else num.plus(startq, one) + } + else { + // There is a last piece + val enddiff = num.minus(end,waypointB) + val endq = check(num.quot(enddiff, step)) + val last = if (endq == zero) waypointB else num.plus(waypointB, num.times(endq, step)) + // Now we have to tally up all the pieces + // 1 for the initial value + // startq steps to waypointA + // 1 step to waypointB + // endq steps to the end (one less if !isInclusive and last==end) + num.plus(startq, num.plus(endq, if (!isInclusive && last==end) one else num.fromInt(2))) + } + } + } } - longCount.toInt } } diff --git a/src/library/scala/collection/immutable/PagedSeq.scala b/src/library/scala/collection/immutable/PagedSeq.scala index 589661a343..3a64820be6 100644 --- a/src/library/scala/collection/immutable/PagedSeq.scala +++ b/src/library/scala/collection/immutable/PagedSeq.scala @@ -188,7 +188,10 @@ extends scala.collection.AbstractSeq[T] val s = start + _start val e = if (_end == UndeterminedEnd) _end else start + _end var f = first1 - while (f.end <= s && !f.isLast) f = f.next + while (f.end <= s && !f.isLast) { + if (f.next eq null) f.addMore(more) + f = f.next + } new PagedSeq(more, f, s, e) } diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index 00f398a4b0..26ccd09803 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -23,6 +23,15 @@ import scala.collection.parallel.immutable.ParRange * println(r2.length) // = 5 * }}} * + * Ranges that contain more than `Int.MaxValue` elements can be created, but + * these overfull ranges have only limited capabilities. Any method that + * could require a collection of over `Int.MaxValue` length to be created, or + * could be asked to index beyond `Int.MaxValue` elements will throw an + * exception. Overfull ranges can safely be reduced in size by changing + * the step size (e.g. `by 3`) or taking/dropping elements. `contains`, + * `equals`, and access to the ends of the range (`head`, `last`, `tail`, + * `init`) are also permitted on overfull ranges. + * * @param start the start of this range. * @param end the exclusive end of the range. * @param step the step for the range. @@ -77,10 +86,24 @@ extends scala.collection.AbstractSeq[Int] } } @deprecated("This method will be made private, use `last` instead.", "2.11") - final val lastElement = start + (numRangeElements - 1) * step + final val lastElement = + if (isEmpty) start - step + else step match { + case 1 => if (isInclusive) end else end-1 + case -1 => if (isInclusive) end else end+1 + case _ => + val remainder = (gap % step).toInt + if (remainder != 0) end - remainder + else if (isInclusive) end + else end - step + } + @deprecated("This method will be made private.", "2.11") - final val terminalElement = start + numRangeElements * step + final val terminalElement = lastElement + step + /** The last element of this range. This method will return the correct value + * even if there are too many elements to iterate over. + */ override def last = if (isEmpty) Nil.last else lastElement override def head = if (isEmpty) Nil.head else start @@ -149,8 +172,12 @@ extends scala.collection.AbstractSeq[Int] */ final override def take(n: Int): Range = ( if (n <= 0 || isEmpty) newEmptyRange(start) - else if (n >= numRangeElements) this - else new Range.Inclusive(start, locationAfterN(n - 1), step) + else if (n >= numRangeElements && numRangeElements >= 0) this + else { + // May have more than Int.MaxValue elements in range (numRangeElements < 0) + // but the logic is the same either way: take the first n + new Range.Inclusive(start, locationAfterN(n - 1), step) + } ) /** Creates a new range containing all the elements of this range except the first `n` elements. @@ -162,8 +189,12 @@ extends scala.collection.AbstractSeq[Int] */ final override def drop(n: Int): Range = ( if (n <= 0 || isEmpty) this - else if (n >= numRangeElements) newEmptyRange(end) - else copy(locationAfterN(n), end, step) + else if (n >= numRangeElements && numRangeElements >= 0) newEmptyRange(end) + else { + // May have more than Int.MaxValue elements (numRangeElements < 0) + // but the logic is the same either way: go forwards n steps, keep the rest + copy(locationAfterN(n), end, step) + } ) /** Creates a new range containing all the elements of this range except the last one. @@ -192,23 +223,17 @@ extends scala.collection.AbstractSeq[Int] drop(1) } - // Counts how many elements from the start meet the given test. - private def skipCount(p: Int => Boolean): Int = { - var current = start - var counted = 0 - - while (counted < numRangeElements && p(current)) { - counted += 1 - current += step + // Advance from the start while we meet the given test + private def argTakeWhile(p: Int => Boolean): Long = { + if (isEmpty) start + else { + var current = start + val stop = last + while (current != stop && p(current)) current += step + if (current != stop || !p(current)) current + else current.toLong + step } - counted } - // Tests whether a number is within the endpoints, without testing - // whether it is a member of the sequence (i.e. when step > 1.) - private def isWithinBoundaries(elem: Int) = !isEmpty && ( - (step > 0 && start <= elem && elem <= last ) || - (step < 0 && last <= elem && elem <= start) - ) // Methods like apply throw exceptions on invalid n, but methods like take/drop // are forgiving: therefore the checks are with the methods. private def locationAfterN(n: Int) = start + (step * n) @@ -219,9 +244,33 @@ extends scala.collection.AbstractSeq[Int] // based on the given value. private def newEmptyRange(value: Int) = new Range(value, value, step) - final override def takeWhile(p: Int => Boolean): Range = take(skipCount(p)) - final override def dropWhile(p: Int => Boolean): Range = drop(skipCount(p)) - final override def span(p: Int => Boolean): (Range, Range) = splitAt(skipCount(p)) + final override def takeWhile(p: Int => Boolean): Range = { + val stop = argTakeWhile(p) + if (stop==start) newEmptyRange(start) + else { + val x = (stop - step).toInt + if (x == last) this + else new Range.Inclusive(start, x, step) + } + } + final override def dropWhile(p: Int => Boolean): Range = { + val stop = argTakeWhile(p) + if (stop == start) this + else { + val x = (stop - step).toInt + if (x == last) newEmptyRange(last) + else new Range.Inclusive(x + step, last, step) + } + } + final override def span(p: Int => Boolean): (Range, Range) = { + val border = argTakeWhile(p) + if (border == start) (newEmptyRange(start), this) + else { + val x = (border - step).toInt + if (x == last) (this, newEmptyRange(last)) + else (new Range.Inclusive(start, x, step), new Range.Inclusive(x+step, last, step)) + } + } /** Creates a pair of new ranges, first consisting of elements before `n`, and the second * of elements after `n`. @@ -234,13 +283,32 @@ extends scala.collection.AbstractSeq[Int] * * $doesNotUseBuilders */ - final override def takeRight(n: Int): Range = drop(numRangeElements - n) + final override def takeRight(n: Int): Range = { + if (n <= 0) newEmptyRange(start) + else if (numRangeElements >= 0) drop(numRangeElements - n) + else { + // Need to handle over-full range separately + val y = last + val x = y - step.toLong*(n-1) + if ((step > 0 && x < start) || (step < 0 && x > start)) this + else new Range.Inclusive(x.toInt, y, step) + } + } /** Creates a new range consisting of the initial `length - n` elements of the range. * * $doesNotUseBuilders */ - final override def dropRight(n: Int): Range = take(numRangeElements - n) + final override def dropRight(n: Int): Range = { + if (n <= 0) this + else if (numRangeElements >= 0) take(numRangeElements - n) + else { + // Need to handle over-full range separately + val y = last - step.toInt*n + if ((step > 0 && y < start) || (step < 0 && y > start)) newEmptyRange(start) + else new Range.Inclusive(start, y.toInt, step) + } + } /** Returns the reverse of this range. * @@ -256,12 +324,37 @@ extends scala.collection.AbstractSeq[Int] if (isInclusive) this else new Range.Inclusive(start, end, step) - final def contains(x: Int) = isWithinBoundaries(x) && ((x - start) % step == 0) + final def contains(x: Int) = { + if (x==end && !isInclusive) false + else if (step > 0) { + if (x < start || x > end) false + else (step == 1) || (((x - start) % step) == 0) + } + else { + if (x < end || x > start) false + else (step == -1) || (((x - start) % step) == 0) + } + } final override def sum[B >: Int](implicit num: Numeric[B]): Int = { - if (isEmpty) 0 - else if (numRangeElements == 1) head - else (numRangeElements.toLong * (head + last) / 2).toInt + if (num eq scala.math.Numeric.IntIsIntegral) { + // this is normal integer range with usual addition. arithmetic series formula can be used + if (isEmpty) 0 + else if (numRangeElements == 1) head + else (numRangeElements.toLong * (head + last) / 2).toInt + } else { + // user provided custom Numeric, we cannot rely on arithmetic series formula + if (isEmpty) num.toInt(num.zero) + else { + var acc = num.zero + var i = head + while(i != terminalElement) { + acc = num.plus(acc, i) + i = i + step + } + num.toInt(acc) + } + } } override def toIterable = this @@ -270,9 +363,15 @@ extends scala.collection.AbstractSeq[Int] override def equals(other: Any) = other match { case x: Range => - (x canEqual this) && (length == x.length) && ( - isEmpty || // all empty sequences are equal - (start == x.start && last == x.last) // same length and same endpoints implies equality + // Note: this must succeed for overfull ranges (length > Int.MaxValue) + (x canEqual this) && ( + isEmpty || // all empty sequences are equal + (start == x.start && { // Otherwise, must have same start + val l0 = last + (l0 == x.last && ( // And same end + start == l0 || step == x.step // And either the same step, or not take any steps + )) + }) ) case _ => super.equals(other) @@ -282,7 +381,8 @@ extends scala.collection.AbstractSeq[Int] */ override def toString() = { - val endStr = if (numRangeElements > Range.MAX_PRINT) ", ... )" else ")" + val endStr = + if (numRangeElements > Range.MAX_PRINT || (!isEmpty && numRangeElements < 0)) ", ... )" else ")" take(Range.MAX_PRINT).mkString("Range(", ", ", endStr) } } diff --git a/src/library/scala/collection/immutable/Set.scala b/src/library/scala/collection/immutable/Set.scala index a888955bb2..0fbf7942d4 100644 --- a/src/library/scala/collection/immutable/Set.scala +++ b/src/library/scala/collection/immutable/Set.scala @@ -53,8 +53,7 @@ trait Set[A] extends Iterable[A] object Set extends ImmutableSetFactory[Set] { /** $setCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A] - override def empty[A]: Set[A] = EmptySet.asInstanceOf[Set[A]] - + /** An optimized representation for immutable empty sets */ private object EmptySet extends AbstractSet[Any] with Set[Any] with Serializable { override def size: Int = 0 @@ -64,6 +63,7 @@ object Set extends ImmutableSetFactory[Set] { def iterator: Iterator[Any] = Iterator.empty override def foreach[U](f: Any => U): Unit = {} } + private[collection] def emptyInstance: Set[Any] = EmptySet /** An optimized representation for immutable sets of size 1 */ @SerialVersionUID(1233385750652442003L) @@ -82,6 +82,16 @@ object Set extends ImmutableSetFactory[Set] { override def foreach[U](f: A => U): Unit = { f(elem1) } + override def exists(f: A => Boolean): Boolean = { + f(elem1) + } + override def forall(f: A => Boolean): Boolean = { + f(elem1) + } + override def find(f: A => Boolean): Option[A] = { + if (f(elem1)) Some(elem1) + else None + } } /** An optimized representation for immutable sets of size 2 */ @@ -102,6 +112,17 @@ object Set extends ImmutableSetFactory[Set] { override def foreach[U](f: A => U): Unit = { f(elem1); f(elem2) } + override def exists(f: A => Boolean): Boolean = { + f(elem1) || f(elem2) + } + override def forall(f: A => Boolean): Boolean = { + f(elem1) && f(elem2) + } + override def find(f: A => Boolean): Option[A] = { + if (f(elem1)) Some(elem1) + else if (f(elem2)) Some(elem2) + else None + } } /** An optimized representation for immutable sets of size 3 */ @@ -123,6 +144,18 @@ object Set extends ImmutableSetFactory[Set] { override def foreach[U](f: A => U): Unit = { f(elem1); f(elem2); f(elem3) } + override def exists(f: A => Boolean): Boolean = { + f(elem1) || f(elem2) || f(elem3) + } + override def forall(f: A => Boolean): Boolean = { + f(elem1) && f(elem2) && f(elem3) + } + override def find(f: A => Boolean): Option[A] = { + if (f(elem1)) Some(elem1) + else if (f(elem2)) Some(elem2) + else if (f(elem3)) Some(elem3) + else None + } } /** An optimized representation for immutable sets of size 4 */ @@ -145,6 +178,19 @@ object Set extends ImmutableSetFactory[Set] { override def foreach[U](f: A => U): Unit = { f(elem1); f(elem2); f(elem3); f(elem4) } + override def exists(f: A => Boolean): Boolean = { + f(elem1) || f(elem2) || f(elem3) || f(elem4) + } + override def forall(f: A => Boolean): Boolean = { + f(elem1) && f(elem2) && f(elem3) && f(elem4) + } + override def find(f: A => Boolean): Option[A] = { + if (f(elem1)) Some(elem1) + else if (f(elem2)) Some(elem2) + else if (f(elem3)) Some(elem3) + else if (f(elem4)) Some(elem4) + else None + } } } diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index a82e31f5da..60de147477 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -960,14 +960,16 @@ self => * }}} */ override def flatten[B](implicit asTraversable: A => /*<:<!!!*/ GenTraversableOnce[B]): Stream[B] = { - def flatten1(t: Traversable[B]): Stream[B] = - if (!t.isEmpty) - cons(t.head, flatten1(t.tail)) - else - tail.flatten - - if (isEmpty) Stream.empty - else flatten1(asTraversable(head).seq.toTraversable) + var st: Stream[A] = this + while (st.nonEmpty) { + val h = asTraversable(st.head) + if (h.isEmpty) { + st = st.tail + } else { + return h.toStream #::: st.tail.flatten + } + } + Stream.empty } override def view = new StreamView[A, Stream[A]] { @@ -1106,11 +1108,15 @@ object Stream extends SeqFactory[Stream] { override def isEmpty = false override def head = hd @volatile private[this] var tlVal: Stream[A] = _ - def tailDefined: Boolean = tlVal ne null + @volatile private[this] var tlGen = tl _ + def tailDefined: Boolean = tlGen eq null override def tail: Stream[A] = { if (!tailDefined) synchronized { - if (!tailDefined) tlVal = tl + if (!tailDefined) { + tlVal = tlGen() + tlGen = null + } } tlVal diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala index 5a0d24ddd2..8e1d950d00 100644 --- a/src/library/scala/collection/immutable/StringLike.scala +++ b/src/library/scala/collection/immutable/StringLike.scala @@ -131,6 +131,7 @@ self => * end characters, i.e. apply `.stripLineEnd` to all lines * returned by `linesWithSeparators`. */ + @deprecated("Use `lines` instead.","2.11.0") def linesIterator: Iterator[String] = linesWithSeparators map (line => new WrappedString(line).stripLineEnd) @@ -164,8 +165,8 @@ self => * @return the resulting string */ def replaceAllLiterally(literal: String, replacement: String): String = { - val arg1 = java.util.regex.Pattern.quote(literal) - val arg2 = java.util.regex.Matcher.quoteReplacement(replacement) + val arg1 = Regex.quote(literal) + val arg2 = Regex.quoteReplacement(replacement) toString.replaceAll(arg1, arg2) } diff --git a/src/library/scala/collection/mutable/AVLTree.scala b/src/library/scala/collection/mutable/AVLTree.scala index d2205f9994..de09bb2040 100644 --- a/src/library/scala/collection/mutable/AVLTree.scala +++ b/src/library/scala/collection/mutable/AVLTree.scala @@ -11,10 +11,10 @@ package collection package mutable /** - * An immutable AVL Tree implementation used by mutable.TreeSet + * An immutable AVL Tree implementation formerly used by mutable.TreeSet * * @author Lucien Pereira - * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11") + * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0") */ private[mutable] sealed trait AVLTree[+A] extends Serializable { def balance: Int @@ -65,7 +65,7 @@ private[mutable] sealed trait AVLTree[+A] extends Serializable { } /** - * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11") + * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0") */ private case object Leaf extends AVLTree[Nothing] { override val balance: Int = 0 @@ -74,7 +74,7 @@ private case object Leaf extends AVLTree[Nothing] { } /** - * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11") + * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0") */ private case class Node[A](data: A, left: AVLTree[A], right: AVLTree[A]) extends AVLTree[A] { override val balance: Int = right.depth - left.depth @@ -211,7 +211,7 @@ private case class Node[A](data: A, left: AVLTree[A], right: AVLTree[A]) extends } /** - * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11") + * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0") */ private class AVLIterator[A](root: Node[A]) extends Iterator[A] { val stack = mutable.ArrayStack[Node[A]](root) diff --git a/src/library/scala/collection/mutable/AnyRefMap.scala b/src/library/scala/collection/mutable/AnyRefMap.scala index df74bb5187..47fb66744e 100644 --- a/src/library/scala/collection/mutable/AnyRefMap.scala +++ b/src/library/scala/collection/mutable/AnyRefMap.scala @@ -22,9 +22,9 @@ import generic.CanBuildFrom * on a map that will no longer have elements removed but will be * used heavily may save both time and storage space. * - * This map is not indended to contain more than 2^29 entries (approximately - * 500 million). The maximum capacity is 2^30, but performance will degrade - * rapidly as 2^30 is approached. + * This map is not intended to contain more than 2^29^ entries (approximately + * 500 million). The maximum capacity is 2^30^, but performance will degrade + * rapidly as 2^30^ is approached. * */ final class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initialBufferSize: Int, initBlank: Boolean) @@ -129,9 +129,20 @@ extends AbstractMap[K, V] override def getOrElseUpdate(key: K, defaultValue: => V): V = { val h = hashOf(key) - val i = seekEntryOrOpen(h, key) + var i = seekEntryOrOpen(h, key) if (i < 0) { - val value = defaultValue + // It is possible that the default value computation was side-effecting + // Our hash table may have resized or even contain what we want now + // (but if it does, we'll replace it) + val value = { + val oh = _hashes + val ans = defaultValue + if (oh ne _hashes) { + i = seekEntryOrOpen(h, key) + if (i >= 0) _size -= 1 + } + ans + } _size += 1 val j = i & IndexMask _hashes(j) = h @@ -280,24 +291,21 @@ extends AbstractMap[K, V] private[this] val vz = _values private[this] var index = 0 - private[this] var found = false - def hasNext = found || (index<hz.length && { + def hasNext: Boolean = index<hz.length && { var h = hz(index) - if (h+h != 0) found = true - else { + while (h+h == 0) { index += 1 - while (index < hz.length && { h = hz(index); h+h == 0 }) index += 1 - found = (index < hz.length) + if (index >= hz.length) return false + h = hz(index) } - found - }) + true + } - def next = { - if (found || hasNext) { - val ans = (_keys(index).asInstanceOf[K], _values(index).asInstanceOf[V]) + def next: (K, V) = { + if (hasNext) { + val ans = (kz(index).asInstanceOf[K], vz(index).asInstanceOf[V]) index += 1 - found = false ans } else throw new NoSuchElementException("next") diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index e1f18a7036..e342e134b4 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -53,14 +53,14 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza super.toArray[U] } - def :+[B >: T: scala.reflect.ClassTag](elem: B): Array[B] = { + def :+[B >: T: ClassTag](elem: B): Array[B] = { val result = Array.ofDim[B](repr.length + 1) Array.copy(repr, 0, result, 0, repr.length) result(repr.length) = elem result } - def +:[B >: T: scala.reflect.ClassTag](elem: B): Array[B] = { + def +:[B >: T: ClassTag](elem: B): Array[B] = { val result = Array.ofDim[B](repr.length + 1) result(0) = elem Array.copy(repr, 0, result, 1, repr.length) @@ -107,6 +107,54 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza bb.result() } } + + /** Converts an array of pairs into an array of first elements and an array of second elements. + * + * @tparam T1 the type of the first half of the element pairs + * @tparam T2 the type of the second half of the element pairs + * @param asPair an implicit conversion which asserts that the element type + * of this Array is a pair. + * @return a pair of Arrays, containing, respectively, the first and second half + * of each element pair of this Array. + */ + def unzip[T1: ClassTag, T2: ClassTag](implicit asPair: T => (T1, T2)): (Array[T1], Array[T2]) = { + val a1 = new Array[T1](length) + val a2 = new Array[T2](length) + var i = 0 + while (i < length) { + val e = apply(i) + a1(i) = e._1 + a2(i) = e._2 + i += 1 + } + (a1, a2) + } + + /** Converts an array of triples into three arrays, one containing the elements from each position of the triple. + * + * @tparam T1 the type of the first of three elements in the triple + * @tparam T2 the type of the second of three elements in the triple + * @tparam T3 the type of the third of three elements in the triple + * @param asTriple an implicit conversion which asserts that the element type + * of this Array is a triple. + * @return a triple of Arrays, containing, respectively, the first, second, and third + * elements from each element triple of this Array. + */ + def unzip3[T1: ClassTag, T2: ClassTag, T3: ClassTag](implicit asTriple: T => (T1, T2, T3)): (Array[T1], Array[T2], Array[T3]) = { + val a1 = new Array[T1](length) + val a2 = new Array[T2](length) + val a3 = new Array[T3](length) + var i = 0 + while (i < length) { + val e = apply(i) + a1(i) = e._1 + a2(i) = e._2 + a3(i) = e._3 + i += 1 + } + (a1, a2, a3) + } + def seq = thisCollection diff --git a/src/library/scala/collection/mutable/Buffer.scala b/src/library/scala/collection/mutable/Buffer.scala index d2e33badbe..7ec7b06333 100644 --- a/src/library/scala/collection/mutable/Buffer.scala +++ b/src/library/scala/collection/mutable/Buffer.scala @@ -46,4 +46,4 @@ object Buffer extends SeqFactory[Buffer] { } /** Explicit instantiation of the `Buffer` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractBuffer[A] extends AbstractSeq[A] with Buffer[A] +abstract class AbstractBuffer[A] extends AbstractSeq[A] with Buffer[A] diff --git a/src/library/scala/collection/mutable/Iterable.scala b/src/library/scala/collection/mutable/Iterable.scala index f7a794e357..92313c9ccd 100644 --- a/src/library/scala/collection/mutable/Iterable.scala +++ b/src/library/scala/collection/mutable/Iterable.scala @@ -38,4 +38,4 @@ object Iterable extends TraversableFactory[Iterable] { } /** Explicit instantiation of the `Iterable` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractIterable[A] extends scala.collection.AbstractIterable[A] with Iterable[A] +abstract class AbstractIterable[A] extends scala.collection.AbstractIterable[A] with Iterable[A] diff --git a/src/library/scala/collection/mutable/LongMap.scala b/src/library/scala/collection/mutable/LongMap.scala index 81c381279f..984ae6f7cc 100644 --- a/src/library/scala/collection/mutable/LongMap.scala +++ b/src/library/scala/collection/mutable/LongMap.scala @@ -160,9 +160,20 @@ extends AbstractMap[Long, V] else minValue.asInstanceOf[V] } else { - val i = seekEntryOrOpen(key) + var i = seekEntryOrOpen(key) if (i < 0) { - val value = defaultValue + // It is possible that the default value computation was side-effecting + // Our hash table may have resized or even contain what we want now + // (but if it does, we'll replace it) + val value = { + val ok = _keys + val ans = defaultValue + if (ok ne _keys) { + i = seekEntryOrOpen(key) + if (i >= 0) _size -= 1 + } + ans + } _size += 1 val j = i & IndexMask _keys(j) = key diff --git a/src/library/scala/collection/mutable/Map.scala b/src/library/scala/collection/mutable/Map.scala index 01f6f725ab..fe29ce4221 100644 --- a/src/library/scala/collection/mutable/Map.scala +++ b/src/library/scala/collection/mutable/Map.scala @@ -89,4 +89,4 @@ object Map extends MutableMapFactory[Map] { } /** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractMap[A, B] extends scala.collection.AbstractMap[A, B] with Map[A, B] +abstract class AbstractMap[A, B] extends scala.collection.AbstractMap[A, B] with Map[A, B] diff --git a/src/library/scala/collection/mutable/Seq.scala b/src/library/scala/collection/mutable/Seq.scala index 11fbdd13f3..eafde70a2d 100644 --- a/src/library/scala/collection/mutable/Seq.scala +++ b/src/library/scala/collection/mutable/Seq.scala @@ -45,4 +45,4 @@ object Seq extends SeqFactory[Seq] { } /** Explicit instantiation of the `Seq` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractSeq[A] extends scala.collection.AbstractSeq[A] with Seq[A] +abstract class AbstractSeq[A] extends scala.collection.AbstractSeq[A] with Seq[A] diff --git a/src/library/scala/collection/mutable/Set.scala b/src/library/scala/collection/mutable/Set.scala index 4439880976..97574718e8 100644 --- a/src/library/scala/collection/mutable/Set.scala +++ b/src/library/scala/collection/mutable/Set.scala @@ -43,4 +43,4 @@ object Set extends MutableSetFactory[Set] { } /** Explicit instantiation of the `Set` trait to reduce class file size in subclasses. */ -private[scala] abstract class AbstractSet[A] extends AbstractIterable[A] with Set[A] +abstract class AbstractSet[A] extends AbstractIterable[A] with Set[A] diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index d3c5a6b019..a55432fd71 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -14,9 +14,45 @@ import scala.annotation.implicitNotFound import scala.util.Try /** - * An `ExecutionContext` is an abstraction over an entity that can execute program logic. + * An `ExecutionContext` can execute program logic, typically but not + * necessarily on a thread pool. + * + * APIs such as `Future.onComplete` require you to provide a callback + * and an implicit `ExecutionContext`. The implicit `ExecutionContext` + * will be used to execute the callback. + * + * It is possible to simply import + * `scala.concurrent.ExecutionContext.Implicits.global` to obtain an + * implicit `ExecutionContext`. This global context is a reasonable + * default thread pool. + * + * However, application developers should carefully consider where they + * want to set policy; ideally, one place per application (or per + * logically-related section of code) will make a decision about + * which `ExecutionContext` to use. That is, you might want to avoid + * hardcoding `scala.concurrent.ExecutionContext.Implicits.global` all + * over the place in your code. + * One approach is to add `(implicit ec: ExecutionContext)` + * to methods which need an `ExecutionContext`. Then import a specific + * context in one place for the entire application or module, + * passing it implicitly to individual methods. + * + * A custom `ExecutionContext` may be appropriate to execute code + * which blocks on IO or performs long-running computations. + * `ExecutionContext.fromExecutorService` and `ExecutionContext.fromExecutor` + * are good ways to create a custom `ExecutionContext`. + * + * The intent of `ExecutionContext` is to lexically scope code execution. + * That is, each method, class, file, package, or application determines + * how to run its own code. This avoids issues such as running + * application callbacks on a thread pool belonging to a networking library. + * The size of a networking library's thread pool can be safely configured, + * knowing that only that library's network operations will be affected. + * Application callback execution can be configured separately. */ -@implicitNotFound("Cannot find an implicit ExecutionContext, either import scala.concurrent.ExecutionContext.Implicits.global or use a custom one") +@implicitNotFound("""Cannot find an implicit ExecutionContext. You might pass +an (implicit ec: ExecutionContext) parameter to your method +or import scala.concurrent.ExecutionContext.Implicits.global.""") trait ExecutionContext { /** Runs a block of code on this execution context. diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index d271c4cdeb..4ed0687334 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -494,9 +494,9 @@ object Future { /** Simple version of `Future.traverse`. Transforms a `TraversableOnce[Future[A]]` into a `Future[TraversableOnce[A]]`. * Useful for reducing many `Future`s into a single `Future`. */ - def sequence[A, M[_] <: TraversableOnce[_]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = { + def sequence[A, M[X] <: TraversableOnce[X]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = { in.foldLeft(successful(cbf(in))) { - (fr, fa) => for (r <- fr; a <- fa.asInstanceOf[Future[A]]) yield (r += a) + (fr, fa) => for (r <- fr; a <- fa) yield (r += a) } map (_.result()) } @@ -569,9 +569,9 @@ object Future { * val myFutureList = Future.traverse(myList)(x => Future(myFunc(x))) * }}} */ - def traverse[A, B, M[_] <: TraversableOnce[_]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] = + def traverse[A, B, M[X] <: TraversableOnce[X]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] = in.foldLeft(successful(cbf(in))) { (fr, a) => - val fb = fn(a.asInstanceOf[A]) + val fb = fn(a) for (r <- fr; b <- fb) yield (r += b) }.map(_.result()) diff --git a/src/library/scala/io/Position.scala b/src/library/scala/io/Position.scala index 85149223ee..011d0f17af 100644 --- a/src/library/scala/io/Position.scala +++ b/src/library/scala/io/Position.scala @@ -34,7 +34,7 @@ package io * @author Burak Emir (translated from work by Matthias Zenger and others) */ @deprecated("This class will be removed.", "2.10.0") -abstract class Position { +private[scala] abstract class Position { /** Definable behavior for overflow conditions. */ def checkInput(line: Int, column: Int): Unit @@ -68,7 +68,7 @@ abstract class Position { def toString(pos: Int): String = line(pos) + ":" + column(pos) } -object Position extends Position { +private[scala] object Position extends Position { def checkInput(line: Int, column: Int) { if (line < 0) throw new IllegalArgumentException(line + " < 0") diff --git a/src/library/scala/io/ReadStdin.scala b/src/library/scala/io/StdIn.scala index e82c26ef7a..64836ecd6e 100644 --- a/src/library/scala/io/ReadStdin.scala +++ b/src/library/scala/io/StdIn.scala @@ -7,7 +7,7 @@ import java.text.MessageFormat * in the standard library, at least not in this idiosyncractic form. * Factored into trait because it is better code structure regardless. */ -private[scala] trait ReadStdin { +private[scala] trait StdIn { import scala.Console._ /** Read a full line from the default input. Returns `null` if the end of the @@ -17,7 +17,7 @@ private[scala] trait ReadStdin { */ def readLine(): String = in.readLine() - /** Print formatted text to the default output and read a full line from the default input. + /** Print and flush formatted text to the default output, and read a full line from the default input. * Returns `null` if the end of the input stream has been reached. * * @param text the format of the text to print out, as in `printf`. @@ -26,6 +26,7 @@ private[scala] trait ReadStdin { */ def readLine(text: String, args: Any*): String = { printf(text, args: _*) + out.flush() readLine() } @@ -225,4 +226,4 @@ private[scala] trait ReadStdin { } } -object ReadStdin extends ReadStdin { } +object StdIn extends StdIn diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index d783dd29f5..bcbed645a7 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -16,36 +16,165 @@ import scala.collection.immutable.NumericRange import scala.language.implicitConversions -/** +/** * @author Stephane Micheloud - * @version 1.0 + * @author Rex Kerr + * @version 1.1 * @since 2.7 */ object BigDecimal { + private final val maximumHashScale = 4934 // Quit maintaining hash identity with BigInt beyond this scale + private final val hashCodeNotComputed = 0x5D50690F // Magic value (happens to be "BigDecimal" old MurmurHash3 value) + private final val deci2binary = 3.3219280948873626 // Ratio of log(10) to log(2) private val minCached = -512 private val maxCached = 512 val defaultMathContext = MathContext.DECIMAL128 - /** Cache ony for defaultMathContext using BigDecimals in a small range. */ + /** Cache only for defaultMathContext using BigDecimals in a small range. */ private lazy val cache = new Array[BigDecimal](maxCached - minCached + 1) object RoundingMode extends Enumeration { + // Annoying boilerplate to ensure consistency with java.math.RoundingMode + import java.math.{RoundingMode => RM} type RoundingMode = Value - // These are supposed to be the same as java.math.RoundingMode.values, - // though it seems unwise to rely on the correspondence. - val UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN, UNNECESSARY = Value + val UP = Value(RM.UP.ordinal) + val DOWN = Value(RM.DOWN.ordinal) + val CEILING = Value(RM.CEILING.ordinal) + val FLOOR = Value(RM.FLOOR.ordinal) + val HALF_UP = Value(RM.HALF_UP.ordinal) + val HALF_DOWN = Value(RM.HALF_DOWN.ordinal) + val HALF_EVEN = Value(RM.HALF_EVEN.ordinal) + val UNNECESSARY = Value(RM.UNNECESSARY.ordinal) + } + + /** Constructs a `BigDecimal` using the decimal text representation of `Double` value `d`, rounding if necessary. */ + def decimal(d: Double, mc: MathContext): BigDecimal = + new BigDecimal(new BigDec(java.lang.Double.toString(d), mc)) + + /** Constructs a `BigDecimal` using the decimal text representation of `Double` value `d`. */ + def decimal(d: Double): BigDecimal = decimal(d, defaultMathContext) + + /** Constructs a `BigDecimal` using the decimal text representation of `Float` value `f`, rounding if necessary. + * Note that `BigDecimal.decimal(0.1f) != 0.1f` since equality agrees with the `Double` representation, and + * `0.1 != 0.1f`. + */ + def decimal(f: Float, mc: MathContext): BigDecimal = + new BigDecimal(new BigDec(java.lang.Float.toString(f), mc)) + + /** Constructs a `BigDecimal` using the decimal text representation of `Float` value `f`. + * Note that `BigDecimal.decimal(0.1f) != 0.1f` since equality agrees with the `Double` representation, and + * `0.1 != 0.1f`. + */ + def decimal(f: Float): BigDecimal = decimal(f, defaultMathContext) + + // This exists solely to avoid conversion from Int/Long to Float, screwing everything up. + /** Constructs a `BigDecimal` from a `Long`, rounding if necessary. This is identical to `BigDecimal(l, mc)`. */ + def decimal(l: Long, mc: MathContext): BigDecimal = apply(l, mc) + + // This exists solely to avoid conversion from Int/Long to Float, screwing everything up. + /** Constructs a `BigDecimal` from a `Long`. This is identical to `BigDecimal(l)`. */ + def decimal(l: Long): BigDecimal = apply(l) + + /** Constructs a `BigDecimal` using a `java.math.BigDecimal`, rounding if necessary. */ + def decimal(bd: BigDec, mc: MathContext): BigDecimal = new BigDecimal(bd.round(mc), mc) + + /** Constructs a `BigDecimal` by expanding the binary fraction + * contained by `Double` value `d` into a decimal representation, + * rounding if necessary. When a `Float` is converted to a + * `Double`, the binary fraction is preserved, so this method + * also works for converted `Float`s. + */ + def binary(d: Double, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(d, mc), mc) + + /** Constructs a `BigDecimal` by expanding the binary fraction + * contained by `Double` value `d` into a decimal representation. + * Note: this also works correctly on converted `Float`s. + */ + def binary(d: Double): BigDecimal = binary(d, defaultMathContext) + + /** Constructs a `BigDecimal` from a `java.math.BigDecimal`. The + * precision is the default for `BigDecimal` or enough to represent + * the `java.math.BigDecimal` exactly, whichever is greater. + */ + def exact(repr: BigDec): BigDecimal = { + val mc = + if (repr.precision <= defaultMathContext.getPrecision) defaultMathContext + else new MathContext(repr.precision, java.math.RoundingMode.HALF_EVEN) + new BigDecimal(repr, mc) } + + /** Constructs a `BigDecimal` by fully expanding the binary fraction + * contained by `Double` value `d`, adjusting the precision as + * necessary. Note: this works correctly on converted `Float`s also. + */ + def exact(d: Double): BigDecimal = exact(new BigDec(d)) + + /** Constructs a `BigDecimal` that exactly represents a `BigInt`. + */ + def exact(bi: BigInt): BigDecimal = exact(new BigDec(bi.bigInteger)) + + /** Constructs a `BigDecimal` that exactly represents a `Long`. Note that + * all creation methods for `BigDecimal` that do not take a `MathContext` + * represent a `Long`; this is equivalent to `apply`, `valueOf`, etc.. + */ + def exact(l: Long): BigDecimal = apply(l) + + /** Constructs a `BigDecimal` that exactly represents the number + * specified in a `String`. + */ + def exact(s: String): BigDecimal = exact(new BigDec(s)) + + /** Constructs a 'BigDecimal` that exactly represents the number + * specified in base 10 in a character array. + */ + def exact(cs: Array[Char]): BigDecimal = exact(new BigDec(cs)) + /** Constructs a `BigDecimal` using the java BigDecimal static - * valueOf constructor. + * valueOf constructor. Equivalent to `BigDecimal.decimal`. * * @param d the specified double value * @return the constructed `BigDecimal` */ def valueOf(d: Double): BigDecimal = apply(BigDec valueOf d) + + /** Constructs a `BigDecimal` using the java BigDecimal static + * valueOf constructor, specifying a `MathContext` that is + * used for computations but isn't used for rounding. Use + * `BigDecimal.decimal` to use `MathContext` for rounding, + * or `BigDecimal(java.math.BigDecimal.valueOf(d), mc)` for + * no rounding. + * + * @param d the specified double value + * @param mc the `MathContext` used for future computations + * @return the constructed `BigDecimal` + */ + @deprecated("MathContext is not applied to Doubles in valueOf. Use BigDecimal.decimal to use rounding, or java.math.BigDecimal.valueOf to avoid it.","2.11") def valueOf(d: Double, mc: MathContext): BigDecimal = apply(BigDec valueOf d, mc) - def valueOf(x: Long): BigDecimal = apply(x.toDouble) + + /** Constructs a `BigDecimal` using the java BigDecimal static + * valueOf constructor. + * + * @param x the specified `Long` value + * @return the constructed `BigDecimal` + */ + def valueOf(x: Long): BigDecimal = apply(x) + + /** Constructs a `BigDecimal` using the java BigDecimal static + * valueOf constructor. This is unlikely to do what you want; + * use `valueOf(f.toDouble)` or `decimal(f)` instead. + */ + @deprecated("Float arguments to valueOf may not do what you wish. Use decimal or valueOf(f.toDouble).","2.11") + def valueOf(f: Float): BigDecimal = valueOf(f.toDouble) + + /** Constructs a `BigDecimal` using the java BigDecimal static + * valueOf constructor. This is unlikely to do what you want; + * use `valueOf(f.toDouble)` or `decimal(f)` instead. + */ + @deprecated("Float arguments to valueOf may not do what you wish. Use decimal or valueOf(f.toDouble).","2.11") + def valueOf(f: Float, mc: MathContext): BigDecimal = valueOf(f.toDouble, mc) + /** Constructs a `BigDecimal` whose value is equal to that of the * specified `Integer` value. * @@ -53,6 +182,14 @@ object BigDecimal { * @return the constructed `BigDecimal` */ def apply(i: Int): BigDecimal = apply(i, defaultMathContext) + + /** Constructs a `BigDecimal` whose value is equal to that of the + * specified `Integer` value, rounding if necessary. + * + * @param i the specified integer value + * @param mc the precision and rounding mode for creation of this value and future operations on it + * @return the constructed `BigDecimal` + */ def apply(i: Int, mc: MathContext): BigDecimal = if (mc == defaultMathContext && minCached <= i && i <= maxCached) { val offset = i - minCached @@ -60,7 +197,7 @@ object BigDecimal { if (n eq null) { n = new BigDecimal(BigDec.valueOf(i.toLong), mc); cache(offset) = n } n } - else new BigDecimal(BigDec.valueOf(i.toLong), mc) + else apply(i.toLong, mc) /** Constructs a `BigDecimal` whose value is equal to that of the * specified long value. @@ -72,6 +209,13 @@ object BigDecimal { if (minCached <= l && l <= maxCached) apply(l.toInt) else new BigDecimal(BigDec.valueOf(l), defaultMathContext) + /** Constructs a `BigDecimal` whose value is equal to that of the + * specified long value, but rounded if necessary. + * + * @param l the specified long value + * @param mc the precision and rounding mode for creation of this value and future operations on it + * @return the constructed `BigDecimal` + */ def apply(l: Long, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(l, mc), mc) @@ -85,35 +229,62 @@ object BigDecimal { def apply(unscaledVal: Long, scale: Int): BigDecimal = apply(BigInt(unscaledVal), scale) + /** Constructs a `BigDecimal` whose unscaled value is equal to that + * of the specified long value, but rounded if necessary. + * + * @param unscaledVal the value + * @param scale the scale + * @param mc the precision and rounding mode for creation of this value and future operations on it + * @return the constructed `BigDecimal` + */ def apply(unscaledVal: Long, scale: Int, mc: MathContext): BigDecimal = apply(BigInt(unscaledVal), scale, mc) /** Constructs a `BigDecimal` whose value is equal to that of the - * specified double value. + * specified double value. Equivalent to `BigDecimal.decimal`. * * @param d the specified `Double` value * @return the constructed `BigDecimal` */ - def apply(d: Double): BigDecimal = apply(d, defaultMathContext) + def apply(d: Double): BigDecimal = decimal(d, defaultMathContext) + // note we don't use the static valueOf because it doesn't let us supply // a MathContext, but we should be duplicating its logic, modulo caching. - def apply(d: Double, mc: MathContext): BigDecimal = - new BigDecimal(new BigDec(jl.Double.toString(d), mc), mc) + /** Constructs a `BigDecimal` whose value is equal to that of the + * specified double value, but rounded if necessary. Equivalent to + * `BigDecimal.decimal`. + * + * @param d the specified `Double` value + * @param mc the precision and rounding mode for creation of this value and future operations on it + * @return the constructed `BigDecimal` + */ + def apply(d: Double, mc: MathContext): BigDecimal = decimal(d, mc) + @deprecated("The default conversion from Float may not do what you want. Use BigDecimal.decimal for a String representation, or explicitly convert the Float with .toDouble.", "2.11") def apply(x: Float): BigDecimal = apply(x.toDouble) + + @deprecated("The default conversion from Float may not do what you want. Use BigDecimal.decimal for a String representation, or explicitly convert the Float with .toDouble.", "2.11") def apply(x: Float, mc: MathContext): BigDecimal = apply(x.toDouble, mc) /** Translates a character array representation of a `BigDecimal` * into a `BigDecimal`. */ - def apply(x: Array[Char]): BigDecimal = apply(x, defaultMathContext) + def apply(x: Array[Char]): BigDecimal = exact(x) + + /** Translates a character array representation of a `BigDecimal` + * into a `BigDecimal`, rounding if necessary. + */ def apply(x: Array[Char], mc: MathContext): BigDecimal = - new BigDecimal(new BigDec(x.mkString, mc), mc) + new BigDecimal(new BigDec(x, mc), mc) /** Translates the decimal String representation of a `BigDecimal` * into a `BigDecimal`. */ - def apply(x: String): BigDecimal = apply(x, defaultMathContext) + def apply(x: String): BigDecimal = exact(x) + + /** Translates the decimal String representation of a `BigDecimal` + * into a `BigDecimal`, rounding if necessary. + */ def apply(x: String, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(x, mc), mc) @@ -123,7 +294,15 @@ object BigDecimal { * @param x the specified `BigInt` value * @return the constructed `BigDecimal` */ - def apply(x: BigInt): BigDecimal = apply(x, defaultMathContext) + def apply(x: BigInt): BigDecimal = exact(x) + + /** Constructs a `BigDecimal` whose value is equal to that of the + * specified `BigInt` value, rounding if necessary. + * + * @param x the specified `BigInt` value + * @param mc the precision and rounding mode for creation of this value and future operations on it + * @return the constructed `BigDecimal` + */ def apply(x: BigInt, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(x.bigInteger, mc), mc) @@ -134,11 +313,24 @@ object BigDecimal { * @param scale the scale * @return the constructed `BigDecimal` */ - def apply(unscaledVal: BigInt, scale: Int): BigDecimal = apply(unscaledVal, scale, defaultMathContext) + def apply(unscaledVal: BigInt, scale: Int): BigDecimal = + exact(new BigDec(unscaledVal.bigInteger, scale)) + + /** Constructs a `BigDecimal` whose unscaled value is equal to that + * of the specified `BigInt` value. + * + * @param unscaledVal the specified `BigInt` value + * @param scale the scale + * @param mc the precision and rounding mode for creation of this value and future operations on it + * @return the constructed `BigDecimal` + */ def apply(unscaledVal: BigInt, scale: Int, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(unscaledVal.bigInteger, scale, mc), mc) + /** Constructs a `BigDecimal` from a `java.math.BigDecimal`. */ def apply(bd: BigDec): BigDecimal = apply(bd, defaultMathContext) + + @deprecated("This method appears to round a java.math.BigDecimal but actually doesn't. Use new BigDecimal(bd, mc) instead for no rounding, or BigDecimal.decimal(bd, mc) for rounding.", "2.11") def apply(bd: BigDec, mc: MathContext): BigDecimal = new BigDecimal(bd, mc) /** Implicit conversion from `Int` to `BigDecimal`. */ @@ -148,43 +340,123 @@ object BigDecimal { implicit def long2bigDecimal(l: Long): BigDecimal = apply(l) /** Implicit conversion from `Double` to `BigDecimal`. */ - implicit def double2bigDecimal(d: Double): BigDecimal = valueOf(d, defaultMathContext) + implicit def double2bigDecimal(d: Double): BigDecimal = decimal(d) /** Implicit conversion from `java.math.BigDecimal` to `scala.BigDecimal`. */ implicit def javaBigDecimal2bigDecimal(x: BigDec): BigDecimal = apply(x) } /** + * `BigDecimal` represents decimal floating-point numbers of arbitrary precision. + * By default, the precision approximately matches that of IEEE 128-bit floating + * point numbers (34 decimal digits, `HALF_EVEN` rounding mode). Within the range + * of IEEE binary128 numbers, `BigDecimal` will agree with `BigInt` for both + * equality and hash codes (and will agree with primitive types as well). Beyond + * that range--numbers with more than 4934 digits when written out in full--the + * `hashCode` of `BigInt` and `BigDecimal` is allowed to diverge due to difficulty + * in efficiently computing both the decimal representation in `BigDecimal` and the + * binary representation in `BigInt`. + * + * When creating a `BigDecimal` from a `Double` or `Float`, care must be taken as + * the binary fraction representation of `Double` and `Float` does not easily + * convert into a decimal representation. Three explicit schemes are available + * for conversion. `BigDecimal.decimal` will convert the floating-point number + * to a decimal text representation, and build a `BigDecimal` based on that. + * `BigDecimal.binary` will expand the binary fraction to the requested or default + * precision. `BigDecimal.exact` will expand the binary fraction to the + * full number of digits, thus producing the exact decimal value corrsponding to + * the binary fraction of that floating-point number. `BigDecimal` equality + * matches the decimal expansion of `Double`: `BigDecimal.decimal(0.1) == 0.1`. + * Note that since `0.1f != 0.1`, the same is not true for `Float`. Instead, + * `0.1f == BigDecimal.decimal((0.1f).toDouble)`. + * + * To test whether a `BigDecimal` number can be converted to a `Double` or + * `Float` and then back without loss of information by using one of these + * methods, test with `isDecimalDouble`, `isBinaryDouble`, or `isExactDouble` + * or the corresponding `Float` versions. Note that `BigInt`'s `isValidDouble` + * will agree with `isExactDouble`, not the `isDecimalDouble` used by default. + * + * `BigDecimal` uses the decimal representation of binary floating-point numbers + * to determine equality and hash codes. This yields different answers than + * conversion between `Long` and `Double` values, where the exact form is used. + * As always, since floating-point is a lossy representation, it is advisable to + * take care when assuming identity will be maintained across multiple conversions. + * + * `BigDecimal` maintains a `MathContext` that determines the rounding that + * is applied to certain calculations. In most cases, the value of the + * `BigDecimal` is also rounded to the precision specified by the `MathContext`. + * To create a `BigDecimal` with a different precision than its `MathContext`, + * use `new BigDecimal(new java.math.BigDecimal(...), mc)`. Rounding will + * be applied on those mathematical operations that can dramatically change the + * number of digits in a full representation, namely multiplication, division, + * and powers. The left-hand argument's `MathContext` always determines the + * degree of rounding, if any, and is the one propagated through arithmetic + * operations that do not apply rounding themselves. + * * @author Stephane Micheloud - * @version 1.0 + * @author Rex Kerr + * @version 1.1 */ -final class BigDecimal( - val bigDecimal: BigDec, - val mc: MathContext) +final class BigDecimal(val bigDecimal: BigDec, val mc: MathContext) extends ScalaNumber with ScalaNumericConversions with Serializable { def this(bigDecimal: BigDec) = this(bigDecimal, BigDecimal.defaultMathContext) import BigDecimal.RoundingMode._ - - /** Cuts way down on the wrapper noise. */ - private implicit def bigdec2BigDecimal(x: BigDec): BigDecimal = new BigDecimal(x, mc) - + import BigDecimal.{decimal, binary, exact} + + if (bigDecimal eq null) throw new IllegalArgumentException("null value for BigDecimal") + if (mc eq null) throw new IllegalArgumentException("null MathContext for BigDecimal") + + // There was an implicit to cut down on the wrapper noise for BigDec -> BigDecimal. + // However, this may mask introduction of surprising behavior (e.g. lack of rounding + // where one might expect it). Wrappers should be applied explicitly with an + // eye to correctness. + + // Sane hash code computation (which is surprisingly hard). + // Note--not lazy val because we can't afford the extra space. + private final var computedHashCode: Int = BigDecimal.hashCodeNotComputed + private final def computeHashCode(): Unit = { + computedHashCode = + if (isWhole && (precision - scale) < BigDecimal.maximumHashScale) toBigInt.hashCode + else if (isValidDouble) doubleValue.## + else { + val temp = bigDecimal.stripTrailingZeros + scala.util.hashing.MurmurHash3.mixLast( temp.scaleByPowerOfTen(temp.scale).toBigInteger.hashCode, temp.scale ) + } + } + /** Returns the hash code for this BigDecimal. - * Note that this does not use the underlying java object's - * hashCode because we compare BigDecimals with compareTo + * Note that this does not merely use the underlying java object's + * `hashCode` because we compare `BigDecimal`s with `compareTo` * which deems 2 == 2.00, whereas in java these are unequal - * with unequal hashCodes. - */ - override def hashCode(): Int = - if (isWhole()) unifiedPrimitiveHashcode() - else doubleValue.## + * with unequal `hashCode`s. These hash codes agree with `BigInt` + * for whole numbers up ~4934 digits (the range of IEEE 128 bit floating + * point). Beyond this, hash codes will disagree; this prevents the + * explicit represention of the `BigInt` form for `BigDecimal` values + * with large exponents. + */ + override def hashCode(): Int = { + if (computedHashCode == BigDecimal.hashCodeNotComputed) computeHashCode + computedHashCode + } - /** Compares this BigDecimal with the specified value for equality. + /** Compares this BigDecimal with the specified value for equality. Where `Float` and `Double` + * disagree, `BigDecimal` will agree with the `Double` value */ override def equals (that: Any): Boolean = that match { case that: BigDecimal => this equals that - case that: BigInt => this.toBigIntExact exists (that equals _) - case that: Double => isValidDouble && toDouble == that - case that: Float => isValidFloat && toFloat == that + case that: BigInt => + that.bitLength > (precision-scale-2)*BigDecimal.deci2binary && + this.toBigIntExact.exists(that equals _) + case that: Double => + !that.isInfinity && { + val d = toDouble + !d.isInfinity && d == that && equals(decimal(d)) + } + case that: Float => + !that.isInfinity && { + val f = toFloat + !f.isInfinity && f == that && equals(decimal(f.toDouble)) + } case _ => isValidLong && unifiedPrimitiveEquals(that) } override def isValidByte = noArithmeticException(toByteExact) @@ -192,26 +464,71 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { override def isValidChar = isValidInt && toIntExact >= Char.MinValue && toIntExact <= Char.MaxValue override def isValidInt = noArithmeticException(toIntExact) def isValidLong = noArithmeticException(toLongExact) - /** Returns `true` iff this can be represented exactly by [[scala.Float]]; otherwise returns `false`. + /** Tests whether the value is a valid Float. "Valid" has several distinct meanings, however. Use + * `isExactFloat`, `isBinaryFloat`, or `isDecimalFloat`, depending on the intended meaning. + * By default, `decimal` creation is used, so `isDecimalFloat` is probably what you want. */ + @deprecated("What constitutes validity is unclear. Use `isExactFloat`, `isBinaryFloat`, or `isDecimalFloat` instead.", "2.11") def isValidFloat = { val f = toFloat - !f.isInfinity && bigDecimal.compareTo(new java.math.BigDecimal(f.toDouble)) == 0 + !f.isInfinity && bigDecimal.compareTo(new BigDec(f.toDouble)) == 0 } - /** Returns `true` iff this can be represented exactly by [[scala.Double]]; otherwise returns `false`. + /** Tests whether the value is a valid Double. "Valid" has several distinct meanings, however. Use + * `isExactDouble`, `isBinaryDouble`, or `isDecimalDouble`, depending on the intended meaning. + * By default, `decimal` creation is used, so `isDecimalDouble` is probably what you want. */ + @deprecated("Validity has two distinct meanings. Use `isExactBinaryDouble` or `equivalentToDouble` instead.", "2.11") def isValidDouble = { val d = toDouble - !d.isInfinity && bigDecimal.compareTo(new java.math.BigDecimal(d)) == 0 + !d.isInfinity && bigDecimal.compareTo(new BigDec(d)) == 0 + } + + /** Tests whether this `BigDecimal` holds the decimal representation of a `Double`. */ + def isDecimalDouble = { + val d = toDouble + !d.isInfinity && equals(decimal(d)) + } + + /** Tests whether this `BigDecimal` holds the decimal representation of a `Float`. */ + def isDecimalFloat = { + val f = toFloat + !f.isInfinity && equals(decimal(f)) + } + + /** Tests whether this `BigDecimal` holds, to within precision, the binary representation of a `Double`. */ + def isBinaryDouble = { + val d = toDouble + !d.isInfinity && equals(binary(d,mc)) + } + + /** Tests whether this `BigDecimal` holds, to within precision, the binary representation of a `Float`. */ + def isBinaryFloat = { + val f = toFloat + !f.isInfinity && equals(binary(f,mc)) + } + + /** Tests whether this `BigDecimal` holds the exact expansion of a `Double`'s binary fractional form into base 10. */ + def isExactDouble = { + val d = toDouble + !d.isInfinity && equals(exact(d)) + } + + /** Tests whether this `BigDecimal` holds the exact expansion of a `Float`'s binary fractional form into base 10. */ + def isExactFloat = { + val f = toFloat + !f.isInfinity && equals(exact(f.toDouble)) } + private def noArithmeticException(body: => Unit): Boolean = { try { body ; true } catch { case _: ArithmeticException => false } } - def isWhole() = (this remainder 1) == BigDecimal(0) + def isWhole() = scale <= 0 || bigDecimal.stripTrailingZeros.scale <= 0 + def underlying = bigDecimal + /** Compares this BigDecimal with the specified BigDecimal for equality. */ @@ -239,60 +556,66 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { /** Addition of BigDecimals */ - def + (that: BigDecimal): BigDecimal = this.bigDecimal.add(that.bigDecimal) + def + (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal add that.bigDecimal, mc) /** Subtraction of BigDecimals */ - def - (that: BigDecimal): BigDecimal = this.bigDecimal.subtract(that.bigDecimal) + def - (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal subtract that.bigDecimal, mc) /** Multiplication of BigDecimals */ - def * (that: BigDecimal): BigDecimal = this.bigDecimal.multiply(that.bigDecimal, mc) + def * (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal.multiply(that.bigDecimal, mc), mc) /** Division of BigDecimals */ - def / (that: BigDecimal): BigDecimal = this.bigDecimal.divide(that.bigDecimal, mc) + def / (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal.divide(that.bigDecimal, mc), mc) /** Division and Remainder - returns tuple containing the result of - * divideToIntegralValue and the remainder. + * divideToIntegralValue and the remainder. The computation is exact: no rounding is applied. */ def /% (that: BigDecimal): (BigDecimal, BigDecimal) = this.bigDecimal.divideAndRemainder(that.bigDecimal) match { - case Array(q, r) => (q, r) + case Array(q, r) => (new BigDecimal(q, mc), new BigDecimal(r, mc)) } /** Divide to Integral value. */ def quot (that: BigDecimal): BigDecimal = - this.bigDecimal.divideToIntegralValue(that.bigDecimal) + new BigDecimal(this.bigDecimal divideToIntegralValue that.bigDecimal, mc) - /** Returns the minimum of this and that + /** Returns the minimum of this and that, or this if the two are equal */ - def min (that: BigDecimal): BigDecimal = this.bigDecimal min that.bigDecimal - - /** Returns the maximum of this and that + def min (that: BigDecimal): BigDecimal = (this compare that) match { + case x if x <= 0 => this + case _ => that + } + + /** Returns the maximum of this and that, or this if the two are equal */ - def max (that: BigDecimal): BigDecimal = this.bigDecimal max that.bigDecimal - + def max (that: BigDecimal): BigDecimal = (this compare that) match { + case x if x >= 0 => this + case _ => that + } + /** Remainder after dividing this by that. */ - def remainder (that: BigDecimal): BigDecimal = this.bigDecimal.remainder(that.bigDecimal) + def remainder (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal remainder that.bigDecimal, mc) /** Remainder after dividing this by that. */ - def % (that: BigDecimal): BigDecimal = this.remainder(that) + def % (that: BigDecimal): BigDecimal = this remainder that /** Returns a BigDecimal whose value is this ** n. */ - def pow (n: Int): BigDecimal = this.bigDecimal.pow(n, mc) + def pow (n: Int): BigDecimal = new BigDecimal(this.bigDecimal.pow(n, mc), mc) /** Returns a BigDecimal whose value is the negation of this BigDecimal */ - def unary_- : BigDecimal = this.bigDecimal.negate() + def unary_- : BigDecimal = new BigDecimal(this.bigDecimal.negate(), mc) /** Returns the absolute value of this BigDecimal */ - def abs: BigDecimal = this.bigDecimal.abs + def abs: BigDecimal = if (signum < 0) unary_- else this /** Returns the sign of this BigDecimal, i.e. * -1 if it is less than 0, @@ -305,9 +628,19 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { */ def precision: Int = this.bigDecimal.precision() - /** Returns a BigDecimal rounded according to the MathContext settings. + /** Returns a BigDecimal rounded according to the supplied MathContext settings, but + * preserving its own MathContext for future operations. */ - def round(mc: MathContext): BigDecimal = this.bigDecimal round mc + def round(mc: MathContext): BigDecimal = { + val r = this.bigDecimal round mc + if (r eq bigDecimal) this else new BigDecimal(r, this.mc) + } + + /** Returns a `BigDecimal` rounded according to its own `MathContext` */ + def rounded: BigDecimal = { + val r = bigDecimal round mc + if (r eq bigDecimal) this else new BigDecimal(r, mc) + } /** Returns the scale of this `BigDecimal`. */ @@ -315,19 +648,22 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { /** Returns the size of an ulp, a unit in the last place, of this BigDecimal. */ - def ulp: BigDecimal = this.bigDecimal.ulp + def ulp: BigDecimal = new BigDecimal(this.bigDecimal.ulp, mc) - /** Returns a new BigDecimal based on the supplied MathContext. + /** Returns a new BigDecimal based on the supplied MathContext, rounded as needed. */ - def apply(mc: MathContext): BigDecimal = BigDecimal(this.bigDecimal.toString, mc) + def apply(mc: MathContext): BigDecimal = new BigDecimal(this.bigDecimal round mc, mc) /** Returns a `BigDecimal` whose scale is the specified value, and whose value is * numerically equal to this BigDecimal's. */ - def setScale(scale: Int): BigDecimal = this.bigDecimal setScale scale + def setScale(scale: Int): BigDecimal = + if (this.scale == scale) this + else new BigDecimal(this.bigDecimal setScale scale, mc) def setScale(scale: Int, mode: RoundingMode): BigDecimal = - this.bigDecimal.setScale(scale, mode.id) + if (this.scale == scale) this + else new BigDecimal(this.bigDecimal.setScale(scale, mode.id), mc) /** Converts this BigDecimal to a Byte. * If the BigDecimal is too big to fit in a Byte, only the low-order 8 bits are returned. @@ -442,8 +778,11 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { * can be done losslessly, returning Some(BigInt) or None. */ def toBigIntExact(): Option[BigInt] = - try Some(new BigInt(this.bigDecimal.toBigIntegerExact())) - catch { case _: ArithmeticException => None } + if (isWhole()) { + try Some(new BigInt(this.bigDecimal.toBigIntegerExact())) + catch { case _: ArithmeticException => None } + } + else None /** Returns the decimal String representation of this BigDecimal. */ diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index 5e70bdc2f6..689fc0c3e1 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -119,7 +119,7 @@ final class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNum */ override def equals(that: Any): Boolean = that match { case that: BigInt => this equals that - case that: BigDecimal => that.toBigIntExact exists (this equals _) + case that: BigDecimal => that equals this case that: Double => isValidDouble && toDouble == that case that: Float => isValidFloat && toFloat == that case x => isValidLong && unifiedPrimitiveEquals(x) diff --git a/src/library/scala/reflect/package.scala b/src/library/scala/reflect/package.scala index 74c1f2172c..509d181d87 100644 --- a/src/library/scala/reflect/package.scala +++ b/src/library/scala/reflect/package.scala @@ -61,21 +61,6 @@ package object reflect { // using the mechanism implemented in `scala.tools.reflect.FastTrack` // todo. once we have implicit macros for tag generation, we can remove this anchor private[scala] def materializeClassTag[T](): ClassTag[T] = macro ??? - - @deprecated("Use `@scala.beans.BeanDescription` instead", "2.10.0") - type BeanDescription = scala.beans.BeanDescription - @deprecated("Use `@scala.beans.BeanDisplayName` instead", "2.10.0") - type BeanDisplayName = scala.beans.BeanDisplayName - @deprecated("Use `@scala.beans.BeanInfo` instead", "2.10.0") - type BeanInfo = scala.beans.BeanInfo - @deprecated("Use `@scala.beans.BeanInfoSkip` instead", "2.10.0") - type BeanInfoSkip = scala.beans.BeanInfoSkip - @deprecated("Use `@scala.beans.BeanProperty` instead", "2.10.0") - type BeanProperty = scala.beans.BeanProperty - @deprecated("Use `@scala.beans.BooleanBeanProperty` instead", "2.10.0") - type BooleanBeanProperty = scala.beans.BooleanBeanProperty - @deprecated("Use `@scala.beans.ScalaBeanInfo` instead", "2.10.0") - type ScalaBeanInfo = scala.beans.ScalaBeanInfo } /** An exception that indicates an error during Scala reflection */ diff --git a/src/library/scala/runtime/AbstractPartialFunction.scala b/src/library/scala/runtime/AbstractPartialFunction.scala index 7129f22f60..986cd0390f 100644 --- a/src/library/scala/runtime/AbstractPartialFunction.scala +++ b/src/library/scala/runtime/AbstractPartialFunction.scala @@ -35,15 +35,3 @@ abstract class AbstractPartialFunction[@specialized(scala.Int, scala.Long, scala // let's not make it final so as not to confuse anyone /*final*/ def apply(x: T1): R = applyOrElse(x, PartialFunction.empty) } - -// Manual stand-ins for formerly specialized variations. -// Not comprehensive, only sufficent to run scala-check built scala 2.11.0-M5 -// TODO Scala 2.10.0.M6 Remove this once scalacheck is published against M6. -private[runtime] abstract class AbstractPartialFunction$mcIL$sp extends scala.runtime.AbstractPartialFunction[Any, Int] { - override def apply(x: Any): Int = apply$mcIL$sp(x) - def apply$mcIL$sp(x: Any): Int = applyOrElse(x, PartialFunction.empty) -} -private[runtime] abstract class AbstractPartialFunction$mcFL$sp extends scala.runtime.AbstractPartialFunction[Any, Float] { - override def apply(x: Any): Float = apply$mcIL$sp(x) - def apply$mcIL$sp(x: Any): Float = applyOrElse(x, PartialFunction.empty) -} diff --git a/src/library/scala/sys/process/ProcessBuilder.scala b/src/library/scala/sys/process/ProcessBuilder.scala index 88c0cf8e58..ac86495001 100644 --- a/src/library/scala/sys/process/ProcessBuilder.scala +++ b/src/library/scala/sys/process/ProcessBuilder.scala @@ -30,9 +30,7 @@ import ProcessBuilder._ * "ls".! * * // Execute "ls" and assign a `Stream[String]` of its output to "contents". - * // Because [[scala.Predef]] already defines a `lines` method for `String`, - * // we use [[scala.sys.process.Process]]'s object companion to create it. - * val contents = Process("ls").lines + * val contents = Process("ls").lineStream * * // Here we use a `Seq` to make the parameter whitespace-safe * def contentsOf(dir: String): String = Seq("ls", dir).!! @@ -82,11 +80,11 @@ import ProcessBuilder._ * of the last one in the chain of execution. * - `!!`: blocks until all external commands exit, and returns a `String` * with the output generated. - * - `lines`: returns immediately like `run`, and the output being generared + * - `lineStream`: returns immediately like `run`, and the output being generated * is provided through a `Stream[String]`. Getting the next element of that * `Stream` may block until it becomes available. This method will throw an * exception if the return code is different than zero -- if this is not - * desired, use the `lines_!` method. + * desired, use the `lineStream_!` method. * * ==Handling Input and Output== * @@ -131,6 +129,14 @@ import ProcessBuilder._ * * Note: though it is not shown above, the equivalent of a shell's `;` would be * `###`. The reason for this name is that `;` is a reserved token in Scala. + * + * Note: the `lines` method, though deprecated, may conflict with the `StringLike` + * method of the same name. To avoid this, one may wish to call the builders in + * `Process` instead of importing `scala.sys.process._`. The example above would be + * {{{ + * import scala.sys.process.Process + * Process("find src -name *.scala -exec grep null {} ;") #| Process("xargs test -z") #&& Process("echo null-free") #|| Process("echo null detected") ! + * }}} */ trait ProcessBuilder extends Source with Sink { /** Starts the process represented by this builder, blocks until it exits, and @@ -165,7 +171,11 @@ trait ProcessBuilder extends Source with Sink { * with a non-zero value, the Stream will provide all lines up to termination * and then throw an exception. */ - def lines: Stream[String] + def lineStream: Stream[String] + + /** Deprecated (renamed). Use `lineStream` instead. */ + @deprecated("Use lineStream instead.", "2.11.0") + def lines: Stream[String] = lineStream /** Starts the process represented by this builder. The output is returned as * a Stream that blocks when lines are not available but the process has not @@ -173,7 +183,11 @@ trait ProcessBuilder extends Source with Sink { * process exits with a non-zero value, the Stream will provide all lines up * to termination and then throw an exception. */ - def lines(log: ProcessLogger): Stream[String] + def lineStream(log: ProcessLogger): Stream[String] + + /** Deprecated (renamed). Use `lineStream(log: ProcessLogger)` instead. */ + @deprecated("Use stream instead.", "2.11.0") + def lines(log: ProcessLogger): Stream[String] = lineStream(log) /** Starts the process represented by this builder. The output is returned as * a Stream that blocks when lines are not available but the process has not @@ -181,7 +195,11 @@ trait ProcessBuilder extends Source with Sink { * with a non-zero value, the Stream will provide all lines up to termination * but will not throw an exception. */ - def lines_! : Stream[String] + def lineStream_! : Stream[String] + + /** Deprecated (renamed). Use `lineStream_!` instead. */ + @deprecated("Use lineStream_! instead.", "2.11.0") + def lines_! : Stream[String] = lineStream_! /** Starts the process represented by this builder. The output is returned as * a Stream that blocks when lines are not available but the process has not @@ -189,7 +207,11 @@ trait ProcessBuilder extends Source with Sink { * process exits with a non-zero value, the Stream will provide all lines up * to termination but will not throw an exception. */ - def lines_!(log: ProcessLogger): Stream[String] + def lineStream_!(log: ProcessLogger): Stream[String] + + /** Deprecated (renamed). Use `lineStream_!(log: ProcessLogger)` instead. */ + @deprecated("Use stream_! instead.", "2.11.0") + def lines_!(log: ProcessLogger): Stream[String] = lineStream_!(log) /** Starts the process represented by this builder, blocks until it exits, and * returns the exit code. Standard output and error are sent to the console. diff --git a/src/library/scala/sys/process/ProcessBuilderImpl.scala b/src/library/scala/sys/process/ProcessBuilderImpl.scala index adf6d1e724..236baaf038 100644 --- a/src/library/scala/sys/process/ProcessBuilderImpl.scala +++ b/src/library/scala/sys/process/ProcessBuilderImpl.scala @@ -104,10 +104,10 @@ private[process] trait ProcessBuilderImpl { def !!< = slurp(None, withIn = true) def !!<(log: ProcessLogger) = slurp(Some(log), withIn = true) - def lines: Stream[String] = lines(withInput = false, nonZeroException = true, None) - def lines(log: ProcessLogger): Stream[String] = lines(withInput = false, nonZeroException = true, Some(log)) - def lines_! : Stream[String] = lines(withInput = false, nonZeroException = false, None) - def lines_!(log: ProcessLogger): Stream[String] = lines(withInput = false, nonZeroException = false, Some(log)) + def lineStream: Stream[String] = lineStream(withInput = false, nonZeroException = true, None) + def lineStream(log: ProcessLogger): Stream[String] = lineStream(withInput = false, nonZeroException = true, Some(log)) + def lineStream_! : Stream[String] = lineStream(withInput = false, nonZeroException = false, None) + def lineStream_!(log: ProcessLogger): Stream[String] = lineStream(withInput = false, nonZeroException = false, Some(log)) def ! = run(connectInput = false).exitValue() def !(io: ProcessIO) = run(io).exitValue() @@ -132,7 +132,7 @@ private[process] trait ProcessBuilderImpl { else scala.sys.error("Nonzero exit value: " + code) } - private[this] def lines( + private[this] def lineStream( withInput: Boolean, nonZeroException: Boolean, log: Option[ProcessLogger] diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala index 13f2362d00..d597feb898 100644 --- a/src/library/scala/util/Properties.scala +++ b/src/library/scala/util/Properties.scala @@ -173,7 +173,7 @@ private[scala] trait PropertiesTrait { * isJavaAtLeast("1.6") // true * isJavaAtLeast("1.7") // true * isJavaAtLeast("1.8") // false - * }} + * }}} */ def isJavaAtLeast(version: String): Boolean = { def parts(x: String) = { diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala index 22dbb37789..6743b9e42a 100644 --- a/src/library/scala/util/matching/Regex.scala +++ b/src/library/scala/util/matching/Regex.scala @@ -67,7 +67,21 @@ import java.util.regex.{ Pattern, Matcher } * Regex, such as `findFirstIn` or `findAllIn`, or using it as an extractor in a * pattern match. * - * Note, however, that when Regex is used as an extractor in a pattern match, it + * Note that, when calling `findAllIn`, the resulting [[scala.util.matching.Regex.MatchIterator]] + * needs to be initialized (by calling `hasNext` or `next()`, or causing these to be + * called) before information about a match can be retrieved: + * + * {{{ + * val msg = "I love Scala" + * + * // val start = " ".r.findAllIn(msg).start // throws an IllegalStateException + * + * val matches = " ".r.findAllIn(msg) + * matches.hasNext // initializes the matcher + * val start = matches.start + * }}} + * + * When Regex is used as an extractor in a pattern match, note that it * only succeeds if the whole text can be matched. For this reason, one usually * calls a method to find the matching substrings, and then use it as an extractor * to break match into subgroups. @@ -267,6 +281,10 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * that can be queried for data such as the text that precedes the * match, subgroups, etc. * + * Attempting to retrieve information about a match before initializing + * the iterator can result in [[java.lang.IllegalStateException]]s. See + * [[scala.util.matching.Regex.MatchIterator]] for details. + * * @param source The text to match against. * @return A [[scala.util.matching.Regex.MatchIterator]] of all matches. * @example {{{for (words <- """\w+""".r findAllIn "A simple example.") yield words}}} @@ -476,15 +494,7 @@ trait UnanchoredRegex extends Regex { } /** This object defines inner classes that describe - * regex matches and helper objects. The class hierarchy - * is as follows: - * - * {{{ - * MatchData - * / \ - * MatchIterator Match - * }}} - * + * regex matches and helper objects. */ object Regex { @@ -634,7 +644,15 @@ object Regex { def unapplySeq(m: Match): Option[Seq[String]] = if (m.groupCount > 0) Some(1 to m.groupCount map m.group) else None } - /** A class to step through a sequence of regex matches + /** A class to step through a sequence of regex matches. + * + * All methods inherited from [[scala.util.matching.Regex.MatchData]] will throw + * a [[java.lang.IllegalStateException]] until the matcher is initialized. The + * matcher can be initialized by calling `hasNext` or `next()` or causing these + * methods to be called, such as by invoking `toString` or iterating through + * the iterator's elements. + * + * @see [[java.util.regex.Matcher]] */ class MatchIterator(val source: CharSequence, val regex: Regex, val groupNames: Seq[String]) extends AbstractIterator[String] with Iterator[String] with MatchData { self => @@ -704,6 +722,14 @@ object Regex { def replace(rs: String) = matcher.appendReplacement(sb, rs) } + /** Quotes strings to be used literally in regex patterns. + * + * All regex metacharacters in the input match themselves literally in the output. + * + * @example {{{List("US$", "CAN$").map(Regex.quote).mkString("|").r}}} + */ + def quote(text: String): String = Pattern quote text + /** Quotes replacement strings to be used in replacement methods. * * Replacement methods give special meaning to backslashes (`\`) and diff --git a/src/manual/scala/man1/scala.scala b/src/manual/scala/man1/scala.scala index f48b99bd5a..6b3be8b77f 100644 --- a/src/manual/scala/man1/scala.scala +++ b/src/manual/scala/man1/scala.scala @@ -39,16 +39,16 @@ object scala extends Command { CmdOptionBound("howtorun:", Argument("how")), "How to execute " & Argument("torun") & ", if it is present. " & "Options for " & Argument("how") & " are " & Mono("guess") & - " (the default), " & Mono("script") & ", and " & Mono("object") & + " (the default), " & Mono("script") & ", " & Mono("jar") & ", and " & Mono("object") & "."), Definition( - CmdOption("i"), + CmdOption("i", Argument("file")), "Requests that a file be pre-loaded. It is only " & "meaningful for interactive shells."), Definition( - CmdOption("e"), + CmdOption("e", Argument("string")), "Requests that its argument be executed as Scala code."), Definition( diff --git a/src/manual/scala/man1/scalac.scala b/src/manual/scala/man1/scalac.scala index 1c0c7c4a96..52e918595c 100644 --- a/src/manual/scala/man1/scalac.scala +++ b/src/manual/scala/man1/scalac.scala @@ -109,6 +109,9 @@ object scalac extends Command { CmdOption("extdirs", Argument("dirs")), "Override location of installed extensions."), Definition( + CmdOption("feature"), + "Emit warning and location for usages of features that should be imported explicitly."), + Definition( CmdOptionBound("g:", "{none,source,line,vars,notailcalls}"), SeqPara( Mono("\"none\"") & " generates no debugging info,", @@ -128,6 +131,9 @@ object scalac extends Command { CmdOption("javaextdirs", Argument("path")), "Override Java extdirs classpath."), Definition( + CmdOptionBound("language:", Argument("feature")), + "Enable one or more language features."), + Definition( CmdOption("no-specialization"), "Ignore " & MItalic("@specialize") & " annotations."), Definition( @@ -146,6 +152,12 @@ object scalac extends Command { CmdOption("sourcepath", Argument("path")), "Specify location(s) of source files."), Definition( + CmdOptionBound("target:", "{jvm-1.5,jvm-1.6,jvm-1.7}"), + SeqPara( + Mono("\"jvm-1.5\"") & " target JVM 1.5 (deprecated),", + Mono("\"jvm-1.6\"") & " target JVM 1.6 (default),", + Mono("\"jvm-1.7\"") & " target JVM 1.7,")), + Definition( CmdOption("toolcp", Argument("path")), "Add to the runner classpath."), Definition( @@ -159,6 +171,12 @@ object scalac extends Command { CmdOption("uniqid"), "Uniquely tag all identifiers in debugging output."), Definition( + CmdOption("usejavacp"), + "Utilize the java.class.path in classpath resolution."), + Definition( + CmdOption("usemanifestcp"), + "Utilize the manifest in classpath resolution."), + Definition( CmdOption("verbose"), "Output messages about what the compiler is doing"), Definition( @@ -175,11 +193,11 @@ object scalac extends Command { Section("Advanced Options", DefinitionList( Definition( - CmdOption("Xcheck-null"), - "Warn upon selection of nullable reference"), - Definition( CmdOption("Xcheckinit"), "Wrap field accessors to throw an exception on uninitialized access."), + Definition( + CmdOption("Xdev"), + "Enable warnings for developers working on the Scala compiler"), Definition( CmdOption("Xdisable-assertions"), "Generate no assertions and assumptions"), @@ -193,6 +211,9 @@ object scalac extends Command { Definition( CmdOption("Xfatal-warnings"), "Fail the compilation if there are any warnings."), + Definition( + CmdOption("Xfull-lubs"), + "Retain pre 2.10 behavior of less aggressive truncation of least upper bounds."), Definition( CmdOption("Xfuture"), "Turn on future language features."), @@ -202,18 +223,39 @@ object scalac extends Command { Definition( CmdOption("Xlint"), "Enable recommended additional warnings."), + Definition( + CmdOption("Xlog-free-terms"), + "Print a message when reification creates a free term."), + Definition( + CmdOption("Xlog-free-types"), + "Print a message when reification resorts to generating a free type."), + Definition( + CmdOption("Xlog-implicit-conversions"), + "Print a message whenever an implicit conversion is inserted."), Definition( CmdOption("Xlog-implicits"), "Show more detail on why some implicits are not applicable."), + Definition( + CmdOption("Xlog-reflective-calls"), + "Print a message when a reflective method call is generated."), + Definition( + CmdOptionBound("Xmacro-settings:", Argument("option")), + "Custom settings for macros."), + Definition( + CmdOption("Xmain-class", Argument("path")), + "Class for manifest's Main-Class entry (only useful with -d <jar>)."), Definition( CmdOption("Xmax-classfile-name", Argument("n")), "Maximum filename length for generated classes."), Definition( - CmdOption("Xmigration"), - "Warn about constructs whose behavior may have changed between 2.7 and 2.8."), + CmdOptionBound("Xmigration:", Argument("version")), + "Warn about constructs whose behavior may have changed since" & Argument("version") & "."), Definition( CmdOption("Xno-forwarders"), "Do not generate static forwarders in mirror classes."), + Definition( + CmdOption("Xno-patmat-analysis"), + "Don't perform exhaustivity/unreachability analysis. Also, ignore " & MItalic("@switch") & " annotation."), Definition( CmdOption("Xno-uescape"), "Disable handling of " & BSlash & "u unicode escapes"), @@ -221,26 +263,26 @@ object scalac extends Command { CmdOption("Xnojline"), "Do not use JLine for editing."), Definition( - CmdOptionBound("Xplugin:", Argument("file")), - "Load a plugin from a file"), + CmdOptionBound("Xplugin:", Argument("paths")), + "Load a plugin from each classpath."), Definition( CmdOptionBound("Xplugin-disable:", Argument("plugin")), - "Disable a plugin"), + "Disable plugins by name."), Definition( CmdOption("Xplugin-list"), - "Print a synopsis of loaded plugins"), + "Print a synopsis of loaded plugins."), Definition( CmdOptionBound("Xplugin-require:", Argument("plugin")), - "Abort unless the given plugin(s) are available"), + "Abort if a named plugin is not loaded."), Definition( CmdOption("Xpluginsdir", Argument("path")), - "Path to search compiler plugins."), + "Path to search for plugin archives."), Definition( CmdOptionBound("Xprint:", Argument("phases")), "Print out program after " & Argument("phases") & " (see below)."), Definition( - CmdOption("Xprint-icode"), - "Log internal icode to *.icode files."), + CmdOptionBound("Xprint-icode", "[:" & Argument("phases") & "]"), + "Log internal icode to *.icode files after" & Argument("phases") & " (default: icode)."), Definition( CmdOption("Xprint-pos"), "Print tree positions, as offsets."), @@ -269,9 +311,12 @@ object scalac extends Command { Definition( CmdOption("Xsource-reader", Argument("classname")), "Specify a custom method for reading source files."), + Definition( + CmdOption("Xstrict-inference"), + "Don't infer known-unsound types."), Definition( CmdOption("Xverify"), - "Verify generic signatures in generated bytecode."), + "Verify generic signatures in generated bytecode (asm backend only)."), Definition( CmdOption("Y"), "Print a synopsis of private options.") @@ -281,65 +326,101 @@ object scalac extends Command { Section("Compilation Phases", DefinitionList( Definition( - MItalic("initial"), - "initializing compiler"), - Definition( - MItalic("parse"), - "parse source files"), + MItalic("parser"), + "parse source into ASTs, perform simple desugaring"), Definition( MItalic("namer"), - "create symbols"), + "resolve names, attach symbols to named trees"), + Definition( + MItalic("packageobjects"), + "load package objects"), + Definition( + MItalic("typer"), + "the meat and potatoes: type the trees"), + Definition( + MItalic("patmat"), + "translate match expressions"), + Definition( + MItalic("superaccessors"), + "add super accessors in traits and nested classes"), + Definition( + MItalic("extmethods"), + "add extension methods for inline classes"), + Definition( + MItalic("pickler"), + "serialize symbol tables"), + Definition( + MItalic("refchecks"), + "reference/override checking, translate nested objects"), + Definition( + MItalic("selectiveanf"), + "ANF pre-transform for " & MItalic("@cps") & " (CPS plugin)"), + Definition( + MItalic("selectivecps"), + MItalic("@cps") & "-driven transform of selectiveanf assignements (CPS plugin)"), + Definition( + MItalic("uncurry"), + "uncurry, translate function values to anonymous classes"), Definition( - MItalic("analyze"), - "name and type analysis"), + MItalic("tailcalls"), + "replace tail calls by jumps"), Definition( - MItalic("refcheck"), - "reference checking"), + MItalic("specialize"), + MItalic("@specialized") & "-driven class and method specialization"), Definition( - MItalic("uncurry"), - "uncurry function types and applications"), + MItalic("explicitouter"), + "this refs to outer pointers, translate patterns"), + Definition( + MItalic("erasure"), + "erase types, add interfaces for traits"), + Definition( + MItalic("posterasure"), + "clean up erased inline classes"), + Definition( + MItalic("lazyvals"), + "allocate bitmaps, translate lazy vals into lazified defs"), Definition( MItalic("lambdalift"), - "lambda lifter"), + "move nested functions to top level"), Definition( - MItalic("typesasvalues"), - "represent types as values"), + MItalic("constructors"), + "move field definitions into constructors"), Definition( - MItalic("addaccessors"), - "add accessors for constructor arguments"), + MItalic("flatten"), + "eliminate inner classes"), Definition( - MItalic("explicitouterclasses"), - "make links from inner classes to enclosing one explicit"), + MItalic("mixin"), + "mixin composition"), Definition( - MItalic("addconstructors"), - "add explicit constructor for each class"), + MItalic("cleanup"), + "platform-specific cleanups, generate reflective calls"), Definition( - MItalic("tailcall"), - "add tail-calls"), + MItalic("delambdafy"), + "remove lambdas"), Definition( - MItalic("wholeprog"), - "perform whole program analysis"), + MItalic("icode"), + "generate portable intermediate code"), Definition( - MItalic("addinterfaces"), - "add one interface per class"), + MItalic("inliner"), + "optimization: do inlining"), Definition( - MItalic("expandmixins"), - "expand mixins by code copying"), + MItalic("inlineHandlers"), + "optimization: inline exception handlers"), Definition( - MItalic("boxing"), - "makes boxing explicit"), + MItalic("closelim"), + "optimization: eliminate uncalled closures"), Definition( - MItalic("erasure"), - "type eraser"), + MItalic("constopt"), + "optimization: optimize null and other constants"), Definition( - MItalic("icode"), - "generate icode"), + MItalic("dce"), + "optimization: eliminate dead code"), Definition( - MItalic("codegen"), - "enable code generation"), + MItalic("jvm"), + "generate JVM bytecode"), Definition( MItalic("terminal"), - "compilation terminated"), + "the last phase in the compiler chain"), Definition( MItalic("all"), "matches all phases")))) diff --git a/src/partest-extras/scala/tools/partest/Util.scala b/src/partest-extras/scala/tools/partest/Util.scala index 8214396291..60e9dbb0f9 100644 --- a/src/partest-extras/scala/tools/partest/Util.scala +++ b/src/partest-extras/scala/tools/partest/Util.scala @@ -16,8 +16,8 @@ object Util { */ def trace[A](a: A) = macro traceImpl[A] - import scala.reflect.macros.BlackboxContext - def traceImpl[A: c.WeakTypeTag](c: BlackboxContext)(a: c.Expr[A]): c.Expr[A] = { + import scala.reflect.macros.blackbox.Context + def traceImpl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]): c.Expr[A] = { import c.universe._ import definitions._ diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 6971175f88..ec20a89a10 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -72,6 +72,8 @@ private[reflect] trait BuildUtils { self: Universe => def setSymbol[T <: Tree](tree: T, sym: Symbol): T + def toStats(tree: Tree): List[Tree] + def mkAnnotation(tree: Tree): Tree def mkAnnotation(trees: List[Tree]): List[Tree] @@ -94,6 +96,13 @@ private[reflect] trait BuildUtils { self: Universe => def freshTypeName(prefix: String): TypeName + val ImplicitParams: ImplicitParamsExtractor + + trait ImplicitParamsExtractor { + def apply(paramss: List[List[ValDef]], implparams: List[ValDef]): List[List[ValDef]] + def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])] + } + val ScalaDot: ScalaDotExtractor trait ScalaDotExtractor { @@ -126,8 +135,8 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticClassDefExtractor { def apply(mods: Modifiers, name: TypeName, tparams: List[Tree], - constrMods: Modifiers, vparamss: List[List[Tree]], earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef + constrMods: Modifiers, vparamss: List[List[Tree]], + earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], Modifiers, List[List[ValDef]], List[Tree], List[Tree], ValDef, List[Tree])] } @@ -145,7 +154,7 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticObjectDefExtractor { def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]): Tree + parents: List[Tree], selfType: Tree, body: List[Tree]): ModuleDef def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])] } @@ -153,7 +162,7 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticPackageObjectDefExtractor { def apply(name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]): Tree + parents: List[Tree], selfType: Tree, body: List[Tree]): PackageDef def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] } @@ -189,17 +198,18 @@ private[reflect] trait BuildUtils { self: Universe => val SyntacticFunction: SyntacticFunctionExtractor trait SyntacticFunctionExtractor { - def apply(params: List[Tree], body: Tree): Tree + def apply(params: List[Tree], body: Tree): Function - def unapply(tree: Tree): Option[(List[ValDef], Tree)] + def unapply(tree: Function): Option[(List[ValDef], Tree)] } val SyntacticDefDef: SyntacticDefDefExtractor trait SyntacticDefDefExtractor { - def apply(mods: Modifiers, name: TermName, tparams: List[Tree], vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef + def apply(mods: Modifiers, name: TermName, tparams: List[Tree], + vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef - def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[List[ValDef]], Tree, Tree)] + def unapply(tree: Tree): Option[(Modifiers, TermName, List[TypeDef], List[List[ValDef]], Tree, Tree)] } val SyntacticValDef: SyntacticValDefExtractor @@ -238,6 +248,13 @@ private[reflect] trait BuildUtils { self: Universe => def unapply(tree: Tree): Option[(Tree)] } + val SyntacticEmptyTypeTree: SyntacticEmptyTypeTreeExtractor + + trait SyntacticEmptyTypeTreeExtractor { + def apply(): TypeTree + def unapply(tt: TypeTree): Boolean + } + val SyntacticFor: SyntacticForExtractor val SyntacticForYield: SyntacticForExtractor @@ -246,13 +263,13 @@ private[reflect] trait BuildUtils { self: Universe => def unapply(tree: Tree): Option[(List[Tree], Tree)] } - def UnliftHelper1[T](unliftable: Unliftable[T]): UnliftHelper1[T] - trait UnliftHelper1[T] { + def UnliftListElementwise[T](unliftable: Unliftable[T]): UnliftListElementwise[T] + trait UnliftListElementwise[T] { def unapply(lst: List[Tree]): Option[List[T]] } - def UnliftHelper2[T](unliftable: Unliftable[T]): UnliftHelper2[T] - trait UnliftHelper2[T] { + def UnliftListOfListsElementwise[T](unliftable: Unliftable[T]): UnliftListOfListsElementwise[T] + trait UnliftListOfListsElementwise[T] { def unapply(lst: List[List[Tree]]): Option[List[List[T]]] } @@ -273,5 +290,11 @@ private[reflect] trait BuildUtils { self: Universe => def apply(name: Name, isBackquoted: Boolean = false): Ident def unapply(tree: Ident): Option[(Name, Boolean)] } + + val SyntacticImport: SyntacticImportExtractor + trait SyntacticImportExtractor { + def apply(expr: Tree, selectors: List[Tree]): Import + def unapply(imp: Import): Some[(Tree, List[Tree])] + } } } diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala index 50c8aa8779..5b6ff2325c 100644 --- a/src/reflect/scala/reflect/api/Exprs.scala +++ b/src/reflect/scala/reflect/api/Exprs.scala @@ -106,7 +106,7 @@ trait Exprs { self: Universe => * * The corresponding macro implementation should have the following signature (note how the return type denotes path-dependency on x): * {{{ - * object Impls { def foo_impl(c: BlackboxContext)(x: c.Expr[X]): c.Expr[x.value.T] = ... } + * object Impls { def foo_impl(c: Context)(x: c.Expr[X]): c.Expr[x.value.T] = ... } * }}} */ @compileTimeOnly("cannot use value except for signatures of macro implementations") diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala index 3d5a213f2f..54b65166d8 100644 --- a/src/reflect/scala/reflect/api/FlagSets.scala +++ b/src/reflect/scala/reflect/api/FlagSets.scala @@ -169,6 +169,14 @@ trait FlagSets { self: Universe => /** Flag indicating that tree was generated by the compiler */ val SYNTHETIC: FlagSet + + /** Flag indicating that tree represents an enum. + * + * It can only appear at + * - the enum's class + * - enum constants + **/ + val ENUM: FlagSet } /** The empty set of flags diff --git a/src/reflect/scala/reflect/api/Importers.scala b/src/reflect/scala/reflect/api/Importers.scala index e239b86452..6539137cee 100644 --- a/src/reflect/scala/reflect/api/Importers.scala +++ b/src/reflect/scala/reflect/api/Importers.scala @@ -34,7 +34,7 @@ package api * {{{ * def staticEval[T](x: T) = macro staticEval[T] * - * def staticEval[T](c: scala.reflect.macros.BlackboxContext)(x: c.Expr[T]) = { + * def staticEval[T](c: scala.reflect.macros.blackbox.Context)(x: c.Expr[T]) = { * // creates a runtime reflection universe to host runtime compilation * import scala.reflect.runtime.{universe => ru} * val mirror = ru.runtimeMirror(c.libraryClassLoader) @@ -52,7 +52,7 @@ package api * val imported = importer.importTree(tree) * * // after the tree is imported, it can be evaluated as usual - * val tree = toolBox.resetAllAttrs(imported.duplicate) + * val tree = toolBox.untypecheck(imported.duplicate) * val valueOfX = toolBox.eval(imported).asInstanceOf[T] * ... * } diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala index a4cd531053..f11b9a5c55 100644 --- a/src/reflect/scala/reflect/api/Mirrors.scala +++ b/src/reflect/scala/reflect/api/Mirrors.scala @@ -29,19 +29,19 @@ package api * Compile-time `Mirror`s make use of only classloader `Mirror`s to load `Symbol`s * by name. * - * The entry point to classloader `Mirror`s is via [[scala.reflect.macros.BlackboxContext#mirror]] or [[scala.reflect.macros.WhiteboxContext#mirror]]. + * The entry point to classloader `Mirror`s is via [[scala.reflect.macros.blackbox.Context#mirror]] or [[scala.reflect.macros.whitebox.Context#mirror]]. * Typical methods which use classloader `Mirror`s include [[scala.reflect.api.Mirror#staticClass]], * [[scala.reflect.api.Mirror#staticModule]], and [[scala.reflect.api.Mirror#staticPackage]]. For * example: * {{{ - * import scala.reflect.macros.BlackboxContext + * import scala.reflect.macros.blackbox.Context * * case class Location(filename: String, line: Int, column: Int) * * object Macros { * def currentLocation: Location = macro impl * - * def impl(c: BlackboxContext): c.Expr[Location] = { + * def impl(c: Context): c.Expr[Location] = { * import c.universe._ * val pos = c.macroApplication.pos * val clsLocation = c.mirror.staticModule("Location") // get symbol of "Location" object @@ -153,7 +153,7 @@ package api * * '''[[scala.reflect.api.Mirrors#ClassMirror]]'''. Used for creating invoker mirrors for constructors. * Entry points: for ''static classes'' `val cm1 = m.reflectClass(<class symbol>)`, - * for ''inner classes'' `val mm2 = im.reflectClass(<module symbol>)`. + * for ''inner classes'' `val mm2 = im.reflectClass(<class symbol>)`. * Example: * {{{ * scala> case class C(x: Int) diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala index 1e0854d171..5bc92d3893 100644 --- a/src/reflect/scala/reflect/api/Printers.scala +++ b/src/reflect/scala/reflect/api/Printers.scala @@ -201,6 +201,25 @@ trait Printers { self: Universe => */ protected def newTreePrinter(out: PrintWriter): TreePrinter + /** + * Renders the code of the passed tree, so that: + * 1) it can be later compiled by scalac retaining the same meaning, + * 2) it looks pretty. + * At the moment we have handled #1 for unattributed trees and + * later on plan to account for typical idiosyncrasies of the typechecker. + * #2 is more or less okay indentation-wise, but at the moment there's a lot of desugaring + * left in place, and that's what we also plan to improve in the future. + * + * @group Printers + */ + def showCode(tree: Tree) = render(tree, newCodePrinter) + + /** + * Hook to define what `showCode(...)` means. + * @group Printers + */ + protected def newCodePrinter(out: PrintWriter): TreePrinter + /** Renders internal structure of a reflection artifact as the * visualization of a Scala syntax tree. * diff --git a/src/reflect/scala/reflect/api/StandardDefinitions.scala b/src/reflect/scala/reflect/api/StandardDefinitions.scala index e255d305f7..1a8885e6b5 100644 --- a/src/reflect/scala/reflect/api/StandardDefinitions.scala +++ b/src/reflect/scala/reflect/api/StandardDefinitions.scala @@ -214,6 +214,14 @@ trait StandardDefinitions { /** The module symbol of module `scala.Some`. */ def SomeModule: ModuleSymbol + /** Function-like api that lets you acess symbol + * of the definition with given arity and also look + * through all known symbols via `seq`. + */ + abstract class VarArityClassApi extends (Int => Symbol) { + def seq: Seq[ClassSymbol] + } + /** Function-like object that maps arity to symbols for classes `scala.ProductX`. * - 0th element is `Unit` * - 1st element is `Product1` @@ -222,7 +230,7 @@ trait StandardDefinitions { * - 23nd element is `NoSymbol` * - ... */ - def ProductClass: Int => Symbol + def ProductClass: VarArityClassApi /** Function-like object that maps arity to symbols for classes `scala.FunctionX`. * - 0th element is `Function0` @@ -232,17 +240,17 @@ trait StandardDefinitions { * - 23nd element is `NoSymbol` * - ... */ - def FunctionClass: Int => Symbol + def FunctionClass: VarArityClassApi /** Function-like object that maps arity to symbols for classes `scala.TupleX`. * - 0th element is `NoSymbol` - * - 1st element is `Product1` + * - 1st element is `Tuple1` * - ... - * - 22nd element is `Product22` + * - 22nd element is `Tuple22` * - 23nd element is `NoSymbol` * - ... */ - def TupleClass: Int => Symbol + def TupleClass: VarArityClassApi /** Contains Scala primitive value classes: * - Byte diff --git a/src/reflect/scala/reflect/api/StandardLiftables.scala b/src/reflect/scala/reflect/api/StandardLiftables.scala index 6756d5e114..a1292d04ef 100644 --- a/src/reflect/scala/reflect/api/StandardLiftables.scala +++ b/src/reflect/scala/reflect/api/StandardLiftables.scala @@ -11,16 +11,16 @@ trait StandardLiftables { self: Universe => private def callCollection(name: Name)(args: List[Tree]) = callScala(nme.collection, nme.immutable, name)(args) private def liftAsLiteral[T]: Liftable[T] = Liftable { v => Literal(Constant(v)) } - implicit def liftByte[T <: Byte]: Liftable[T] = liftAsLiteral[T] - implicit def liftShort[T <: Short]: Liftable[T] = liftAsLiteral[T] - implicit def liftChar[T <: Char]: Liftable[T] = liftAsLiteral[T] - implicit def liftInt[T <: Int]: Liftable[T] = liftAsLiteral[T] - implicit def liftLong[T <: Long]: Liftable[T] = liftAsLiteral[T] - implicit def liftFloat[T <: Float]: Liftable[T] = liftAsLiteral[T] - implicit def liftDouble[T <: Double]: Liftable[T] = liftAsLiteral[T] - implicit def liftBoolean: Liftable[Boolean] = liftAsLiteral[Boolean] - implicit def liftUnit: Liftable[Unit] = liftAsLiteral[Unit] - implicit def liftString: Liftable[String] = liftAsLiteral[String] + implicit def liftByte[T <: Byte]: Liftable[T] = liftAsLiteral[T] + implicit def liftShort[T <: Short]: Liftable[T] = liftAsLiteral[T] + implicit def liftChar[T <: Char]: Liftable[T] = liftAsLiteral[T] + implicit def liftInt[T <: Int]: Liftable[T] = liftAsLiteral[T] + implicit def liftLong[T <: Long]: Liftable[T] = liftAsLiteral[T] + implicit def liftFloat[T <: Float]: Liftable[T] = liftAsLiteral[T] + implicit def liftDouble[T <: Double]: Liftable[T] = liftAsLiteral[T] + implicit def liftBoolean[T <: Boolean]: Liftable[T] = liftAsLiteral[T] + implicit def liftUnit: Liftable[Unit] = liftAsLiteral[Unit] + implicit def liftString[T <: String]: Liftable[T] = liftAsLiteral[T] implicit def liftScalaSymbol: Liftable[scala.Symbol] = Liftable { v => callScala(nme.Symbol)(Literal(Constant(v.name)) :: Nil) @@ -35,16 +35,22 @@ trait StandardLiftables { self: Universe => implicit def liftArray[T: Liftable]: Liftable[Array[T]] = Liftable { arr => callScala(nme.Array)(arr.map(lift(_)).toList) } implicit def liftVector[T: Liftable]: Liftable[Vector[T]] = Liftable { vect => callCollection(nme.Vector)(vect.map(lift(_)).toList) } implicit def liftList[T: Liftable]: Liftable[List[T]] = Liftable { lst => callCollection(nme.List)(lst.map(lift(_))) } + implicit def liftNil: Liftable[Nil.type] = Liftable { _ => selectScala(nme.collection, nme.immutable, nme.Nil) } implicit def liftMap[K: Liftable, V: Liftable]: Liftable[Map[K, V]] = Liftable { m => callCollection(nme.Map)(m.toList.map(lift(_))) } implicit def liftSet[T: Liftable]: Liftable[Set[T]] = Liftable { s => callCollection(nme.Set)(s.toList.map(lift(_))) } + implicit def liftSome[T: Liftable]: Liftable[Some[T]] = Liftable { case Some(v) => callScala(nme.Some)(lift(v) :: Nil) } + implicit def liftNone: Liftable[None.type] = Liftable { _ => selectScala(nme.None) } implicit def liftOption[T: Liftable]: Liftable[Option[T]] = Liftable { - case Some(v) => callScala(nme.Some)(lift(v) :: Nil) - case None => selectScala(nme.None) + case some: Some[T] => lift(some) + case none: None.type => lift(none) } + + implicit def liftLeft[L: Liftable, R]: Liftable[Left[L, R]] = Liftable { case Left(v) => callScala(nme.util, nme.Left)(lift(v) :: Nil) } + implicit def liftRight[L, R: Liftable]: Liftable[Right[L, R]] = Liftable { case Right(v) => callScala(nme.util, nme.Right)(lift(v) :: Nil) } implicit def liftEither[L: Liftable, R: Liftable]: Liftable[Either[L, R]] = Liftable { - case Left(l) => callScala(nme.util, nme.Left)(lift(l) :: Nil) - case Right(r) => callScala(nme.util, nme.Right)(lift(r) :: Nil) + case left: Left[L, R] => lift(left) + case right: Right[L, R] => lift(right) } implicit def liftTuple1[T1](implicit liftT1: Liftable[T1]): Liftable[Tuple1[T1]] = Liftable { t => @@ -137,7 +143,7 @@ trait StandardLiftables { self: Universe => case Apply(ScalaDot(symbol), List(Literal(Constant(name: String)))) if symbol == nme.Symbol => scala.Symbol(name) } - implicit def unliftName[T <: Name : ClassTag]: Unliftable[T] = Unliftable[T] { case Ident(name: T) => name; case Bind(name: T, Ident(nme.WILDCARD)) => name} + implicit def unliftName[T <: Name : ClassTag]: Unliftable[T] = Unliftable[T] { case Ident(name: T) => name; case Bind(name: T, Ident(nme.WILDCARD)) => name } implicit def unliftType: Unliftable[Type] = Unliftable[Type] { case tt: TypeTree if tt.tpe != null => tt.tpe } implicit def unliftConstant: Unliftable[Constant] = Unliftable[Constant] { case Literal(const) => const } @@ -220,6 +226,7 @@ trait StandardLiftables { self: Universe => val List = TermName("List") val Map = TermName("Map") val None = TermName("None") + val Nil = TermName("Nil") val Right = TermName("Right") val Set = TermName("Set") val Some = TermName("Some") diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index 83da5141b9..60e00ca5fd 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -1066,7 +1066,7 @@ trait Trees { self: Universe => * UnApply( * // a dummy node that carries the type of unapplication to patmat * // the <unapply-selector> here doesn't have an underlying symbol - * // it only has a type assigned, therefore after `resetAllAttrs` this tree is no longer typeable + * // it only has a type assigned, therefore after `untypecheck` this tree is no longer typeable * Apply(Select(Ident(Foo), newTermName("unapply")), List(Ident(newTermName("<unapply-selector>")))), * // arguments of the unapply => nothing synthetic here * List(Bind(newTermName("x"), Ident(nme.WILDCARD)))), diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala index 7457910226..be76758224 100644 --- a/src/reflect/scala/reflect/api/TypeTags.scala +++ b/src/reflect/scala/reflect/api/TypeTags.scala @@ -134,7 +134,7 @@ import scala.language.implicitConversions * reflection APIs provided by Java (for classes) and Scala (for types).</li> * * <li>'''Certain manifest operations(i.e., <:<, >:> and typeArguments) are not - * supported.''' <br/>Instead, one culd use the reflection APIs provided by Java (for + * supported.''' <br/>Instead, one could use the reflection APIs provided by Java (for * classes) and Scala (for types).</li> *</ul> * diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala index 9d2d06da69..4892b46e16 100644 --- a/src/reflect/scala/reflect/api/Types.scala +++ b/src/reflect/scala/reflect/api/Types.scala @@ -707,14 +707,14 @@ trait Types { val AnnotatedType: AnnotatedTypeExtractor /** An extractor class to create and pattern match with syntax - * `AnnotatedType(annotations, underlying, selfsym)`. + * `AnnotatedType(annotations, underlying)`. * Here, `annotations` are the annotations decorating the underlying type `underlying`. * `selfSym` is a symbol representing the annotated type itself. * @group Extractors */ abstract class AnnotatedTypeExtractor { - def apply(annotations: List[Annotation], underlying: Type, selfsym: Symbol): AnnotatedType - def unapply(tpe: AnnotatedType): Option[(List[Annotation], Type, Symbol)] + def apply(annotations: List[Annotation], underlying: Type): AnnotatedType + def unapply(tpe: AnnotatedType): Option[(List[Annotation], Type)] } /** The API that all annotated types support. @@ -727,9 +727,6 @@ trait Types { /** The annotee. */ def underlying: Type - - /** A symbol that represents the annotated type itself. */ - def selfsym: Symbol } /** The `TypeBounds` type signature is used to indicate lower and upper type bounds diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala index 1da2c24306..85a8ee0185 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -41,11 +41,11 @@ package api * res1: reflect.runtime.universe.Type = scala.Either[String,Int] * }}} * - * To obtain a `Universe` for use within a Scala macro, use [[scala.reflect.macros.BlackboxContext#universe]]. - * or [[scala.reflect.macros.WhiteboxContext#universe]]. For example: + * To obtain a `Universe` for use within a Scala macro, use [[scala.reflect.macros.blackbox.Context#universe]]. + * or [[scala.reflect.macros.whitebox.Context#universe]]. For example: * {{{ * def printf(format: String, params: Any*): Unit = macro impl - * def impl(c: BlackboxContext)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = { + * def impl(c: Context)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = { * import c.universe._ * ... * } @@ -81,14 +81,14 @@ abstract class Universe extends Symbols with Liftables with Quasiquotes { - /** Use `refiy` to produce the abstract syntax tree representing a given Scala expression. + /** Use `reify` to produce the abstract syntax tree representing a given Scala expression. * * For example: * * {{{ - * val five = reify{ 5 } // Literal(Constant(5)) - * reify{ 2 + 4 } // Apply( Select( Literal(Constant(2)), newTermName("\$plus")), List( Literal(Constant(4)) ) ) - * reify{ five.splice + 4 } // Apply( Select( Literal(Constant(5)), newTermName("\$plus")), List( Literal(Constant(4)) ) ) + * val five = reify{ 5 } // Literal(Constant(5)) + * reify{ 5.toString } // Apply(Select(Literal(Constant(5)), TermName("toString")), List()) + * reify{ five.splice.toString } // Apply(Select(five, TermName("toString")), List()) * }}} * * The produced tree is path dependent on the Universe `reify` was called from. diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index f45fa40f89..d634034fe9 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -48,7 +48,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => /** Tests for, get, or remove an annotation */ def hasAnnotation(cls: Symbol): Boolean = //OPT inlined from exists to save on #closures; was: annotations exists (_ matches cls) - dropOtherAnnotations(annotations, cls).nonEmpty + dropOtherAnnotations(annotations, cls) ne Nil def getAnnotation(cls: Symbol): Option[AnnotationInfo] = //OPT inlined from exists to save on #closures; was: annotations find (_ matches cls) @@ -290,8 +290,8 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => * metaAnnotations = List(setter, field). */ def metaAnnotations: List[AnnotationInfo] = atp match { - case AnnotatedType(metas, _, _) => metas - case _ => Nil + case AnnotatedType(metas, _) => metas + case _ => Nil } /** The default kind of members to which this annotation is attached. diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala index 19c67879f5..0ca8611719 100644 --- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala +++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala @@ -166,9 +166,10 @@ trait BaseTypeSeqs { val index = new Array[Int](nparents) var i = 0 for (p <- parents) { + val parentBts = p.dealias.baseTypeSeq // dealias need for SI-8046. pbtss(i) = - if (p.baseTypeSeq eq undetBaseTypeSeq) AnyClass.info.baseTypeSeq - else p.baseTypeSeq + if (parentBts eq undetBaseTypeSeq) AnyClass.info.baseTypeSeq + else parentBts index(i) = 0 i += 1 } diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 0a81bfa2a5..c5581601de 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -33,19 +33,19 @@ trait BuildUtils { self: SymbolTable => } def newFreeTerm(name: String, value: => Any, flags: Long = 0L, origin: String = null): FreeTermSymbol = - newFreeTermSymbol(newTermName(name), value, flags, origin) + newFreeTermSymbol(newTermName(name), value, flags, origin).markFlagsCompleted(mask = AllFlags) def newFreeType(name: String, flags: Long = 0L, origin: String = null): FreeTypeSymbol = - newFreeTypeSymbol(newTypeName(name), flags, origin) + newFreeTypeSymbol(newTypeName(name), flags, origin).markFlagsCompleted(mask = AllFlags) def newNestedSymbol(owner: Symbol, name: Name, pos: Position, flags: Long, isClass: Boolean): Symbol = - owner.newNestedSymbol(name, pos, flags, isClass) + owner.newNestedSymbol(name, pos, flags, isClass).markFlagsCompleted(mask = AllFlags) def setAnnotations[S <: Symbol](sym: S, annots: List[AnnotationInfo]): S = sym.setAnnotations(annots) def setTypeSignature[S <: Symbol](sym: S, tpe: Type): S = - sym.setTypeSignature(tpe) + sym.setTypeSignature(tpe).markAllCompleted() def This(sym: Symbol): Tree = self.This(sym) @@ -61,6 +61,8 @@ trait BuildUtils { self: SymbolTable => def setSymbol[T <: Tree](tree: T, sym: Symbol): T = { tree.setSymbol(sym); tree } + def toStats(tree: Tree): List[Tree] = SyntacticBlock.unapply(tree).get + def mkAnnotation(tree: Tree): Tree = tree match { case SyntacticNew(Nil, SyntacticApplied(SyntacticTypeApplied(_, _), _) :: Nil, noSelfType, Nil) => tree @@ -71,18 +73,25 @@ trait BuildUtils { self: SymbolTable => def mkAnnotation(trees: List[Tree]): List[Tree] = trees.map(mkAnnotation) - def mkVparamss(argss: List[List[Tree]]): List[List[ValDef]] = argss.map(_.map(mkParam)) + def mkParam(argss: List[List[Tree]], extraFlags: FlagSet = NoFlags): List[List[ValDef]] = + argss.map { args => args.map { mkParam(_, extraFlags) } } - def mkParam(tree: Tree): ValDef = tree match { + def mkParam(tree: Tree, extraFlags: FlagSet): ValDef = tree match { + case Typed(Ident(name: TermName), tpt) => + mkParam(ValDef(NoMods, name, tpt, EmptyTree), extraFlags) case vd: ValDef => - var newmods = (vd.mods | PARAM) & (~DEFERRED) + var newmods = vd.mods & (~DEFERRED) if (vd.rhs.nonEmpty) newmods |= DEFAULTPARAM - copyValDef(vd)(mods = newmods) + copyValDef(vd)(mods = newmods | extraFlags) case _ => - throw new IllegalArgumentException(s"$tree is not valid represenation of function parameter, " + + throw new IllegalArgumentException(s"$tree is not valid represenation of a parameter, " + """consider reformatting it into q"val $name: $T = $default" shape""") } + def mkImplicitParam(args: List[Tree]): List[ValDef] = args.map(mkImplicitParam) + + def mkImplicitParam(tree: Tree): ValDef = mkParam(tree, IMPLICIT | PARAM) + def mkTparams(tparams: List[Tree]): List[TypeDef] = tparams.map { case td: TypeDef => copyTypeDef(td)(mods = (td.mods | PARAM) & (~DEFERRED)) @@ -134,12 +143,22 @@ trait BuildUtils { self: SymbolTable => def RefTree(qual: Tree, sym: Symbol) = self.RefTree(qual, sym.name) setSymbol sym - def freshTermName(prefix: String): TermName = self.freshTermName(prefix) + def freshTermName(prefix: String = nme.FRESH_TERM_NAME_PREFIX): TermName = self.freshTermName(prefix) def freshTypeName(prefix: String): TypeName = self.freshTypeName(prefix) protected implicit def fresh: FreshNameCreator = self.currentFreshNameCreator + object ImplicitParams extends ImplicitParamsExtractor { + def apply(paramss: List[List[ValDef]], implparams: List[ValDef]): List[List[ValDef]] = + if (implparams.nonEmpty) paramss :+ mkImplicitParam(implparams) else paramss + + def unapply(vparamss: List[List[ValDef]]): Some[(List[List[ValDef]], List[ValDef])] = vparamss match { + case init :+ (last @ (initlast :: _)) if initlast.mods.isImplicit => Some((init, last)) + case _ => Some((vparamss, Nil)) + } + } + object FlagsRepr extends FlagsReprExtractor { def apply(bits: Long): FlagSet = bits def unapply(flags: Long): Some[Long] = Some(flags) @@ -239,14 +258,10 @@ trait BuildUtils { self: SymbolTable => object SyntacticClassDef extends SyntacticClassDefExtractor { def apply(mods: Modifiers, name: TypeName, tparams: List[Tree], - constrMods: Modifiers, vparamss: List[List[Tree]], earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = { + constrMods: Modifiers, vparamss: List[List[Tree]], + earlyDefs: List[Tree], parents: List[Tree], selfType: Tree, body: List[Tree]): ClassDef = { val extraFlags = PARAMACCESSOR | (if (mods.isCase) CASEACCESSOR else 0L) - val vparamss0 = vparamss.map { _.map { - case vd: ValDef => copyValDef(vd)(mods = (vd.mods | extraFlags) & (~DEFERRED)) - case tree => throw new IllegalArgumentException(s"$tree is not valid representation of class parameter, " + - """consider reformatting it into q"val $name: $T = $default" shape""") - } } + val vparamss0 = mkParam(vparamss, extraFlags) val tparams0 = mkTparams(tparams) val parents0 = gen.mkParents(mods, if (mods.isCase) parents.filter { @@ -289,7 +304,7 @@ trait BuildUtils { self: SymbolTable => object SyntacticObjectDef extends SyntacticObjectDefExtractor { def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]) = + parents: List[Tree], selfType: Tree, body: List[Tree]): ModuleDef = ModuleDef(mods, name, gen.mkTemplate(parents, mkSelfType(selfType), NoMods, Nil, earlyDefs ::: body)) def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match { @@ -302,7 +317,7 @@ trait BuildUtils { self: SymbolTable => object SyntacticPackageObjectDef extends SyntacticPackageObjectDefExtractor { def apply(name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfType: Tree, body: List[Tree]): Tree = + parents: List[Tree], selfType: Tree, body: List[Tree]): PackageDef = gen.mkPackageObject(SyntacticObjectDef(NoMods, name, earlyDefs, parents, selfType, body)) def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match { @@ -381,27 +396,52 @@ trait BuildUtils { self: SymbolTable => } } + object SyntheticUnit { + def unapply(tree: Tree): Boolean = tree match { + case Literal(Constant(())) if tree.hasAttachment[SyntheticUnitAttachment.type] => true + case _ => false + } + } + + /** Syntactic combinator that abstracts over Block tree. + * + * Apart from providing a more straightforward api that exposes + * block as a list of elements rather than (stats, expr) pair + * it also: + * + * 1. Treats of q"" (empty tree) as zero-element block. + * + * 2. Strips trailing synthetic units which are inserted by the + * compiler if the block ends with a definition rather + * than an expression. + * + * 3. Matches non-block term trees and recognizes them as + * single-element blocks for sake of consistency with + * compiler's default to treat single-element blocks with + * expressions as just expressions. + */ object SyntacticBlock extends SyntacticBlockExtractor { - def apply(stats: List[Tree]): Tree = gen.mkBlock(stats) + def apply(stats: List[Tree]): Tree = + if (stats.isEmpty) EmptyTree + else gen.mkBlock(stats) def unapply(tree: Tree): Option[List[Tree]] = tree match { - case self.Block(stats, expr) => Some(stats :+ expr) - case _ if tree.isTerm => Some(tree :: Nil) - case _ => None + case self.Block(stats, SyntheticUnit()) => Some(stats) + case self.Block(stats, expr) => Some(stats :+ expr) + case EmptyTree => Some(Nil) + case _ if tree.isTerm => Some(tree :: Nil) + case _ => None } } object SyntacticFunction extends SyntacticFunctionExtractor { - def apply(params: List[Tree], body: Tree): Tree = { - val params0 :: Nil = mkVparamss(params :: Nil) + def apply(params: List[Tree], body: Tree): Function = { + val params0 :: Nil = mkParam(params :: Nil, PARAM) require(params0.forall { _.rhs.isEmpty }, "anonymous functions don't support parameters with default values") Function(params0, body) } - def unapply(tree: Tree): Option[(List[ValDef], Tree)] = tree match { - case Function(params, body) => Some((params, body)) - case _ => None - } + def unapply(tree: Function): Option[(List[ValDef], Tree)] = Function.unapply(tree) } object SyntacticNew extends SyntacticNewExtractor { @@ -420,11 +460,15 @@ trait BuildUtils { self: SymbolTable => } object SyntacticDefDef extends SyntacticDefDefExtractor { - def apply(mods: Modifiers, name: TermName, tparams: List[Tree], vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef = - DefDef(mods, name, mkTparams(tparams), mkVparamss(vparamss), tpt, rhs) + def apply(mods: Modifiers, name: TermName, tparams: List[Tree], + vparamss: List[List[Tree]], tpt: Tree, rhs: Tree): DefDef = { + val vparamss0 = mkParam(vparamss, PARAM) + DefDef(mods, name, mkTparams(tparams), vparamss0, tpt, rhs) + } - def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[List[ValDef]], Tree, Tree)] = tree match { - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => Some((mods, name, tparams, vparamss, tpt, rhs)) + def unapply(tree: Tree): Option[(Modifiers, TermName, List[TypeDef], List[List[ValDef]], Tree, Tree)] = tree match { + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + Some((mods, name, tparams, vparamss, tpt, rhs)) case _ => None } } @@ -455,14 +499,14 @@ trait BuildUtils { self: SymbolTable => } } - def UnliftHelper1[T](unliftable: Unliftable[T]) = new UnliftHelper1[T] { + def UnliftListElementwise[T](unliftable: Unliftable[T]) = new UnliftListElementwise[T] { def unapply(lst: List[Tree]): Option[List[T]] = { val unlifted = lst.flatMap { unliftable.unapply(_) } if (unlifted.length == lst.length) Some(unlifted) else None } } - def UnliftHelper2[T](unliftable: Unliftable[T]) = new UnliftHelper2[T] { + def UnliftListOfListsElementwise[T](unliftable: Unliftable[T]) = new UnliftListOfListsElementwise[T] { def unapply(lst: List[List[Tree]]): Option[List[List[T]]] = { val unlifted = lst.map { l => l.flatMap { unliftable.unapply(_) } } if (unlifted.flatten.length == lst.flatten.length) Some(unlifted) else None @@ -490,13 +534,15 @@ trait BuildUtils { self: SymbolTable => def unapply(tree: Tree): Option[Tree] = gen.Filter.unapply(tree) } - // abstract over possible alternative representations of no type in valdef - protected object EmptyTypTree { - def unapply(tree: Tree): Boolean = tree match { - case EmptyTree => true - case tt: TypeTree if (tt.original == null || tt.original.isEmpty) => true - case _ => false - } + // If a tree in type position isn't provided by the user (e.g. `tpt` fields of + // `ValDef` and `DefDef`, function params etc), then it's going to be parsed as + // TypeTree with empty original and empty tpe. This extractor matches such trees + // so that one can write q"val x = 2" to match typecheck(q"val x = 2"). Note that + // TypeTree() is the only possible representation for empty trees in type positions. + // We used to sometimes receive EmptyTree in such cases, but not anymore. + object SyntacticEmptyTypeTree extends SyntacticEmptyTypeTreeExtractor { + def apply(): TypeTree = self.TypeTree() + def unapply(tt: TypeTree): Boolean = tt.original == null || tt.original.isEmpty } // match a sequence of desugared `val $pat = $value` @@ -514,8 +560,8 @@ trait BuildUtils { self: SymbolTable => case ValDef(_, name1, _, Match(MaybeUnchecked(value), CaseDef(pat, EmptyTree, Ident(name2)) :: Nil)) :: UnPatSeq(rest) if name1 == name2 => Some((pat, value) :: rest) - // case q"${_} val $name: ${EmptyTypTree()} = $value" :: UnPatSeq(rest) => - case ValDef(_, name, EmptyTypTree(), value) :: UnPatSeq(rest) => + // case q"${_} val $name: ${SyntacticEmptyTypeTree()} = $value" :: UnPatSeq(rest) => + case ValDef(_, name, SyntacticEmptyTypeTree(), value) :: UnPatSeq(rest) => Some((Bind(name, self.Ident(nme.WILDCARD)), value) :: rest) // case q"${_} val $name: $tpt = $value" :: UnPatSeq(rest) => case ValDef(_, name, tpt, value) :: UnPatSeq(rest) => @@ -557,8 +603,8 @@ trait BuildUtils { self: SymbolTable => def unapply(tree: Tree): Option[(Tree, Tree)] = tree match { case Function(ValDef(Modifiers(PARAM, _, _), name, tpt, EmptyTree) :: Nil, body) => tpt match { - case EmptyTypTree() => Some((Bind(name, self.Ident(nme.WILDCARD)), body)) - case _ => Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), body)) + case SyntacticEmptyTypeTree() => Some((Bind(name, self.Ident(nme.WILDCARD)), body)) + case _ => Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), body)) } case UnVisitor(_, CaseDef(pat, EmptyTree, body) :: Nil) => Some((pat, body)) @@ -723,6 +769,146 @@ trait BuildUtils { self: SymbolTable => } def unapply(tree: Ident): Some[(Name, Boolean)] = Some((tree.name, tree.hasAttachment[BackquotedIdentifierAttachment.type])) } + + /** Facade over Imports and ImportSelectors that lets to structurally + * deconstruct/reconstruct them. + * + * Selectors are represented in the following way: + * 1. q"import foo._" <==> q"import foo.${pq"_"}" + * 2. q"import foo.bar" <==> q"import foo.${pq"bar"}" + * 3. q"import foo.{bar => baz}" <==> q"import foo.${pq"bar -> baz"}" + * 4. q"import foo.{bar => _}" <==> q"import foo.${pq"bar -> _"}" + * + * All names in selectors are TermNames despite the fact ImportSelector + * can theoretically contain TypeNames too (but they never do in practice.) + */ + object SyntacticImport extends SyntacticImportExtractor { + // construct/deconstruct {_} import selector + private object WildcardSelector { + def apply(offset: Int): ImportSelector = ImportSelector(nme.WILDCARD, offset, null, -1) + def unapply(sel: ImportSelector): Option[Int] = sel match { + case ImportSelector(nme.WILDCARD, offset, null, -1) => Some(offset) + case _ => None + } + } + + // construct/deconstruct {foo} import selector + private object NameSelector { + def apply(name: TermName, offset: Int): ImportSelector = ImportSelector(name, offset, name, offset) + def unapply(sel: ImportSelector): Option[(TermName, Int)] = sel match { + case ImportSelector(name1, offset1, name2, offset2) if name1 == name2 && offset1 == offset2 => + Some((name1.toTermName, offset1)) + case _ => + None + } + } + + // construct/deconstruct {foo => bar} import selector + private object RenameSelector { + def apply(name1: TermName, offset1: Int, name2: TermName, offset2: Int): ImportSelector = + ImportSelector(name1, offset1, name2, offset2) + def unapply(sel: ImportSelector): Option[(TermName, Int, TermName, Int)] = sel match { + case ImportSelector(_, _, null | nme.WILDCARD, _) => + None + case ImportSelector(name1, offset1, name2, offset2) if name1 != name2 => + Some((name1.toTermName, offset1, name2.toTermName, offset2)) + case _ => + None + } + } + + // construct/deconstruct {foo => _} import selector + private object UnimportSelector { + def apply(name: TermName, offset: Int): ImportSelector = + ImportSelector(name, offset, nme.WILDCARD, -1) + def unapply(sel: ImportSelector): Option[(TermName, Int)] = sel match { + case ImportSelector(name, offset, nme.WILDCARD, _) => Some((name.toTermName, offset)) + case _ => None + } + } + + // represent {_} import selector as pq"_" + private object WildcardSelectorRepr { + def apply(pos: Position): Tree = atPos(pos)(self.Ident(nme.WILDCARD)) + def unapply(tree: Tree): Option[Position] = tree match { + case self.Ident(nme.WILDCARD) => Some(tree.pos) + case _ => None + } + } + + // represent {foo} import selector as pq"foo" + private object NameSelectorRepr { + def apply(name: TermName, pos: Position): Tree = atPos(pos)(Bind(name, WildcardSelectorRepr(pos))) + def unapply(tree: Tree): Option[(TermName, Position)] = tree match { + case Bind(name, WildcardSelectorRepr(_)) => Some((name.toTermName, tree.pos)) + case _ => None + } + } + + // pq"left -> right" + private object Arrow { + def apply(left: Tree, right: Tree): Apply = + Apply(self.Ident(nme.MINGT), left :: right :: Nil) + def unapply(tree: Apply): Option[(Tree, Tree)] = tree match { + case Apply(self.Ident(nme.MINGT), left :: right :: Nil) => Some((left, right)) + case _ => None + } + } + + // represent {foo => bar} import selector as pq"foo -> bar" + private object RenameSelectorRepr { + def apply(name1: TermName, pos1: Position, name2: TermName, pos2: Position): Tree = { + val left = NameSelectorRepr(name1, pos1) + val right = NameSelectorRepr(name2, pos2) + atPos(wrappingPos(left :: right :: Nil))(Arrow(left, right)) + } + def unapply(tree: Tree): Option[(TermName, Position, TermName, Position)] = tree match { + case Arrow(NameSelectorRepr(name1, pos1), NameSelectorRepr(name2, pos2)) => + Some((name1.toTermName, pos1, name2.toTermName, pos2)) + case _ => + None + } + } + + // represent {foo => _} import selector as pq"foo -> _" + private object UnimportSelectorRepr { + def apply(name: TermName, pos: Position): Tree = + atPos(pos)(Arrow(NameSelectorRepr(name, pos), WildcardSelectorRepr(pos))) + def unapply(tree: Tree): Option[(TermName, Position)] = tree match { + case Arrow(NameSelectorRepr(name, pos), WildcardSelectorRepr(_)) => + Some((name, pos)) + case _ => + None + } + } + + private def derivedPos(t: Tree, offset: Int): Position = + if (t.pos == NoPosition) NoPosition else t.pos.withPoint(offset) + + private def derivedOffset(pos: Position): Int = + if (pos == NoPosition) -1 else pos.point + + def apply(expr: Tree, selectors: List[Tree]): Import = { + val importSelectors = selectors.map { + case WildcardSelectorRepr(pos) => WildcardSelector(derivedOffset(pos)) + case NameSelectorRepr(name, pos) => NameSelector(name, derivedOffset(pos)) + case RenameSelectorRepr(name1, pos1, name2, pos2) => RenameSelector(name1, derivedOffset(pos1), name2, derivedOffset(pos2)) + case UnimportSelectorRepr(name, pos) => UnimportSelector(name, derivedOffset(pos)) + case tree => throw new IllegalArgumentException(s"${showRaw(tree)} doesn't correspond to import selector") + } + Import(expr, importSelectors) + } + + def unapply(imp: Import): Some[(Tree, List[Tree])] = { + val selectors = imp.selectors.map { + case WildcardSelector(offset) => WildcardSelectorRepr(derivedPos(imp, offset)) + case NameSelector(name, offset) => NameSelectorRepr(name, derivedPos(imp, offset)) + case RenameSelector(name1, offset1, name2, offset2) => RenameSelectorRepr(name1, derivedPos(imp, offset1), name2, derivedPos(imp, offset2)) + case UnimportSelector(name, offset) => UnimportSelectorRepr(name, derivedPos(imp, offset)) + } + Some((imp.expr, selectors)) + } + } } val build: BuildImpl = new BuildImpl diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 38be6fcf56..645d6aa4ff 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -30,12 +30,13 @@ trait Definitions extends api.StandardDefinitions { private def enterNewClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): ClassSymbol = { val clazz = owner.newClassSymbol(name, NoPosition, flags) - clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz) + clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz) markAllCompleted } private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long): MethodSymbol = { val msym = owner.newMethod(name.encode, NoPosition, flags) val params = msym.newSyntheticValueParams(formals) - msym setInfo MethodType(params, restpe) + val info = if (owner.isJavaDefined) JavaMethodType(params, restpe) else MethodType(params, restpe) + msym setInfo info markAllCompleted } private def enterNewMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): MethodSymbol = owner.info.decls enter newMethod(owner, name, formals, restpe, flags) @@ -251,8 +252,8 @@ trait Definitions extends api.StandardDefinitions { } // top types - lazy val AnyClass = enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) - lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectTpe) + lazy val AnyClass = enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) markAllCompleted + lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectTpe) markAllCompleted lazy val ObjectClass = getRequiredClass(sn.Object.toString) // Cached types for core monomorphic classes @@ -275,7 +276,7 @@ trait Definitions extends api.StandardDefinitions { val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, AnyTpe :: Nil, ABSTRACT) val av_constr = anyval.newClassConstructor(NoPosition) anyval.info.decls enter av_constr - anyval + anyval markAllCompleted }).asInstanceOf[ClassSymbol] def AnyVal_getClass = getMemberMethod(AnyValClass, nme.getClass_) @@ -287,8 +288,10 @@ trait Definitions extends api.StandardDefinitions { locally { this initFlags ABSTRACT | FINAL this setInfoAndEnter ClassInfoType(List(parent.tpe), newScope, this) + this markAllCompleted } final override def isBottomClass = true + final override def isThreadsafe(purpose: SymbolOps): Boolean = true } final object NothingClass extends BottomClassSymbol(tpnme.Nothing, AnyClass) { override def isSubClass(that: Symbol) = true @@ -357,12 +360,13 @@ trait Definitions extends api.StandardDefinitions { def delayedInitMethod = getMemberMethod(DelayedInitClass, nme.delayedInit) lazy val TypeConstraintClass = requiredClass[scala.annotation.TypeConstraint] - lazy val SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, AnyTpe :: Nil, ABSTRACT | TRAIT | FINAL) + lazy val SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, AnyTpe :: Nil, ABSTRACT | TRAIT | FINAL) markAllCompleted lazy val SerializableClass = requiredClass[scala.Serializable] lazy val JavaSerializableClass = requiredClass[java.io.Serializable] modifyInfo fixupAsAnyTrait lazy val ComparableClass = requiredClass[java.lang.Comparable[_]] modifyInfo fixupAsAnyTrait lazy val JavaCloneableClass = requiredClass[java.lang.Cloneable] lazy val JavaNumberClass = requiredClass[java.lang.Number] + lazy val JavaEnumClass = requiredClass[java.lang.Enum[_]] lazy val RemoteInterfaceClass = requiredClass[java.rmi.Remote] lazy val RemoteExceptionClass = requiredClass[java.rmi.RemoteException] @@ -482,12 +486,8 @@ trait Definitions extends api.StandardDefinitions { lazy val TypeCreatorClass = getClassIfDefined("scala.reflect.api.TypeCreator") // defined in scala-reflect.jar, so we need to be careful lazy val TreeCreatorClass = getClassIfDefined("scala.reflect.api.TreeCreator") // defined in scala-reflect.jar, so we need to be careful - lazy val BlackboxMacroClass = getClassIfDefined("scala.reflect.macros.BlackboxMacro") // defined in scala-reflect.jar, so we need to be careful - def BlackboxMacroContextValue = BlackboxMacroClass.map(sym => getMemberValue(sym, nme.c)) - lazy val WhiteboxMacroClass = getClassIfDefined("scala.reflect.macros.WhiteboxMacro") // defined in scala-reflect.jar, so we need to be careful - def WhiteboxMacroContextValue = WhiteboxMacroClass.map(sym => getMemberValue(sym, nme.c)) - lazy val BlackboxContextClass = getClassIfDefined("scala.reflect.macros.BlackboxContext") // defined in scala-reflect.jar, so we need to be careful - lazy val WhiteboxContextClass = getClassIfDefined("scala.reflect.macros.WhiteboxContext") // defined in scala-reflect.jar, so we need to be careful + lazy val BlackboxContextClass = getClassIfDefined("scala.reflect.macros.blackbox.Context") // defined in scala-reflect.jar, so we need to be careful + lazy val WhiteboxContextClass = getClassIfDefined("scala.reflect.macros.whitebox.Context") // defined in scala-reflect.jar, so we need to be careful def MacroContextPrefix = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.prefix)) def MacroContextPrefixType = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.PrefixType)) def MacroContextUniverse = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.universe)) @@ -525,7 +525,7 @@ trait Definitions extends api.StandardDefinitions { def hasJavaMainMethod(sym: Symbol): Boolean = (sym.tpe member nme.main).alternatives exists isJavaMainMethod - class VarArityClass(name: String, maxArity: Int, countFrom: Int = 0, init: Option[ClassSymbol] = None) extends (Int => Symbol) { + class VarArityClass(name: String, maxArity: Int, countFrom: Int = 0, init: Option[ClassSymbol] = None) extends VarArityClassApi { private val offset = countFrom - init.size private def isDefinedAt(i: Int) = i < seq.length + offset && i >= offset val seq: IndexedSeq[ClassSymbol] = (init ++: countFrom.to(maxArity).map { i => getRequiredClass("scala." + name + i) }).toVector @@ -603,32 +603,32 @@ trait Definitions extends api.StandardDefinitions { def isWhiteboxContextType(tp: Type) = isMacroContextType(tp) && (tp <:< WhiteboxContextClass.tpe) - def mightBeMacroBundleType(tp: Type) = - tp.baseClasses.contains(WhiteboxMacroClass) || - tp.baseClasses.contains(BlackboxMacroClass) - - def isMacroBundleType(tp: Type) = tp.baseClasses match { - case _ :: proto :: _ if isMacroBundleProtoType(proto.tpe) => true - case _ => false + private def macroBundleParamInfo(tp: Type) = { + val ctor = tp.erasure.typeSymbol.primaryConstructor + ctor.paramss match { + case List(List(c)) => + val sym = c.info.typeSymbol + val isContextCompatible = sym.isNonBottomSubClass(BlackboxContextClass) || sym.isNonBottomSubClass(WhiteboxContextClass) + if (isContextCompatible) c.info else NoType + case _ => + NoType + } } - def isBlackboxMacroBundleType(tp: Type) = - isMacroBundleType(tp) && (tp <:< BlackboxMacroClass.tpe) && !(tp <:< WhiteboxMacroClass.tpe) + def looksLikeMacroBundleType(tp: Type) = + macroBundleParamInfo(tp) != NoType - def isMacroBundleProtoType(tp: Type) = { - val sym = tp.typeSymbol - val isNonTrivial = tp != ErrorType && tp != NothingTpe && tp != NullTpe - def subclasses(sym: Symbol) = sym != NoSymbol && tp.baseClasses.contains(sym) - val isMacroCompatible = subclasses(BlackboxMacroClass) ^ subclasses(WhiteboxMacroClass) - val isBundlePrototype = sym != BlackboxMacroClass && sym != WhiteboxMacroClass && sym.isTrait && { - val c = sym.info.member(nme.c) - def overrides(sym: Symbol) = c.overrideChain.contains(sym) - val cIsOk = (overrides(BlackboxMacroContextValue) || overrides(WhiteboxMacroContextValue)) && c.isDeferred - cIsOk && sym.isMonomorphicType - } - isNonTrivial && isMacroCompatible && isBundlePrototype + def isMacroBundleType(tp: Type) = { + val isContextCompatible = macroBundleParamInfo(tp) != NoType + val hasSingleConstructor = !tp.declaration(nme.CONSTRUCTOR).isOverloaded + val nonAbstract = !tp.erasure.typeSymbol.isAbstractClass + isContextCompatible && hasSingleConstructor && nonAbstract } + def isBlackboxMacroBundleType(tp: Type) = + isMacroBundleType(tp) && (macroBundleParamInfo(tp) <:< BlackboxContextClass.tpe) + + def isListType(tp: Type) = tp <:< classExistentialType(ListClass) def isIterableType(tp: Type) = tp <:< classExistentialType(IterableClass) // These "direct" calls perform no dealiasing. They are most needed when @@ -692,7 +692,7 @@ trait Definitions extends api.StandardDefinitions { case TypeRef(pre, sym, _) if sym.isModuleClass => isStable(pre) case TypeRef(_, _, _) if tp ne tp.dealias => isStable(tp.dealias) case TypeVar(origin, _) => isStable(origin) - case AnnotatedType(_, atp, _) => isStable(atp) // Really? + case AnnotatedType(_, atp) => isStable(atp) // Really? case _: SimpleTypeProxy => isStable(tp.underlying) case _ => false } @@ -812,46 +812,32 @@ trait Definitions extends api.StandardDefinitions { def byNameType(arg: Type) = appliedType(ByNameParamClass, arg) def iteratorOfType(tp: Type) = appliedType(IteratorClass, tp) def javaRepeatedType(arg: Type) = appliedType(JavaRepeatedParamClass, arg) + def optionType(tp: Type) = appliedType(OptionClass, tp) def scalaRepeatedType(arg: Type) = appliedType(RepeatedParamClass, arg) def seqType(arg: Type) = appliedType(SeqClass, arg) // FYI the long clunky name is because it's really hard to put "get" into the // name of a method without it sounding like the method "get"s something, whereas // this method is about a type member which just happens to be named get. - def typeOfMemberNamedGet(tp: Type) = resultOfMatchingMethod(tp, nme.get)() - def typeOfMemberNamedHead(tp: Type) = resultOfMatchingMethod(tp, nme.head)() - def typeOfMemberNamedApply(tp: Type) = resultOfMatchingMethod(tp, nme.apply)(IntTpe) - def typeOfMemberNamedDrop(tp: Type) = resultOfMatchingMethod(tp, nme.drop)(IntTpe) - def typeOfMemberNamedGetOrSelf(tp: Type) = typeOfMemberNamedGet(tp) orElse tp - def typesOfSelectors(tp: Type) = getterMemberTypes(tp, productSelectors(tp)) - def typesOfCaseAccessors(tp: Type) = getterMemberTypes(tp, tp.typeSymbol.caseFieldAccessors) - - /** If this is a case class, the case field accessors (which may be an empty list.) - * Otherwise, if there are any product selectors, that list. - * Otherwise, a list containing only the type itself. - */ - def typesOfSelectorsOrSelf(tp: Type): List[Type] = ( - if (tp.typeSymbol.isCase) - typesOfCaseAccessors(tp) - else typesOfSelectors(tp) match { - case Nil => tp :: Nil - case tps => tps - } - ) - - /** If the given type has one or more product selectors, the type of the last one. - * Otherwise, the type itself. - */ - def typeOfLastSelectorOrSelf(tp: Type) = typesOfSelectorsOrSelf(tp).last - - def elementTypeOfLastSelectorOrSelf(tp: Type) = { - val last = typeOfLastSelectorOrSelf(tp) - ( typeOfMemberNamedHead(last) - orElse typeOfMemberNamedApply(last) - orElse elementType(ArrayClass, last) - ) + def typeOfMemberNamedGet(tp: Type) = typeArgOfBaseTypeOr(tp, OptionClass)(resultOfMatchingMethod(tp, nme.get)()) + def typeOfMemberNamedHead(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.head)()) + def typeOfMemberNamedApply(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.apply)(IntTpe)) + def typeOfMemberNamedDrop(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.drop)(IntTpe)) + def typesOfSelectors(tp: Type) = getterMemberTypes(tp, productSelectors(tp)) + // SI-8128 Still using the type argument of the base type at Seq/Option if this is an old-style (2.10 compatible) + // extractor to limit exposure to regressions like the reported problem with existentials. + // TODO fix the existential problem in the general case, see test/pending/pos/t8128.scala + private def typeArgOfBaseTypeOr(tp: Type, baseClass: Symbol)(or: => Type): Type = (tp baseType baseClass).typeArgs match { + case x :: Nil => x + case _ => or } + // Can't only check for _1 thanks to pos/t796. + def hasSelectors(tp: Type) = ( + (tp.members containsName nme._1) + && (tp.members containsName nme._2) + ) + /** Returns the method symbols for members _1, _2, ..., _N * which exist in the given type. */ @@ -861,7 +847,9 @@ trait Definitions extends api.StandardDefinitions { case m if m.paramss.nonEmpty => Nil case m => m :: loop(n + 1) } - loop(1) + // Since ErrorType always returns a symbol from a call to member, we + // had better not start looking for _1, _2, etc. expecting it to run out. + if (tpe.isErroneous) Nil else loop(1) } /** If `tp` has a term member `name`, the first parameter list of which @@ -910,15 +898,24 @@ trait Definitions extends api.StandardDefinitions { * * C[E1, ..., En] forSome { E1 >: LB1 <: UB1 ... en >: LBn <: UBn }. */ + // TODO Review the way this is used. I see two potential problems: + // 1. `existentialAbstraction` here doesn't create fresh existential type symbols, it just + // uses the class type parameter symbols directly as the list of quantified symbols. + // See SI-8244 for the trouble that this can cause. + // Compare with callers of `typeParamsToExistentials` (used in Java raw type handling) + // 2. Why don't we require a prefix? Could its omission lead to wrong results in CheckabilityChecker? def classExistentialType(clazz: Symbol): Type = existentialAbstraction(clazz.typeParams, clazz.tpe_*) - def unsafeClassExistentialType(clazz: Symbol): Type = - existentialAbstraction(clazz.unsafeTypeParams, clazz.tpe_*) - // members of class scala.Any + + // TODO these aren't final! They are now overriden in AnyRef/Object. Prior to the fix + // for SI-8129, they were actually *overloaded* by the members in AnyRef/Object. + // We should unfinalize these, override in AnyValClass, and make the overrides final. + // Refchecks never actually looks at these, so its just for consistency. lazy val Any_== = enterNewMethod(AnyClass, nme.EQ, AnyTpe :: Nil, BooleanTpe, FINAL) lazy val Any_!= = enterNewMethod(AnyClass, nme.NE, AnyTpe :: Nil, BooleanTpe, FINAL) + lazy val Any_equals = enterNewMethod(AnyClass, nme.equals_, AnyTpe :: Nil, BooleanTpe) lazy val Any_hashCode = enterNewMethod(AnyClass, nme.hashCode_, Nil, IntTpe) lazy val Any_toString = enterNewMethod(AnyClass, nme.toString_, Nil, StringTpe) @@ -1025,8 +1022,8 @@ trait Definitions extends api.StandardDefinitions { // members of class java.lang.{ Object, String } lazy val Object_## = enterNewMethod(ObjectClass, nme.HASHHASH, Nil, IntTpe, FINAL) - lazy val Object_== = enterNewMethod(ObjectClass, nme.EQ, AnyRefTpe :: Nil, BooleanTpe, FINAL) - lazy val Object_!= = enterNewMethod(ObjectClass, nme.NE, AnyRefTpe :: Nil, BooleanTpe, FINAL) + lazy val Object_== = enterNewMethod(ObjectClass, nme.EQ, AnyTpe :: Nil, BooleanTpe, FINAL) + lazy val Object_!= = enterNewMethod(ObjectClass, nme.NE, AnyTpe :: Nil, BooleanTpe, FINAL) lazy val Object_eq = enterNewMethod(ObjectClass, nme.eq, AnyRefTpe :: Nil, BooleanTpe, FINAL) lazy val Object_ne = enterNewMethod(ObjectClass, nme.ne, AnyRefTpe :: Nil, BooleanTpe, FINAL) lazy val Object_isInstanceOf = newT1NoParamsMethod(ObjectClass, nme.isInstanceOf_Ob, FINAL | SYNTHETIC | ARTIFACT)(_ => BooleanTpe) @@ -1142,6 +1139,7 @@ trait Definitions extends api.StandardDefinitions { lazy val AnnotationDefaultAttr: ClassSymbol = { val sym = RuntimePackageClass.newClassSymbol(tpnme.AnnotationDefaultATTR, NoPosition, 0L) sym setInfo ClassInfoType(List(AnnotationClass.tpe), newScope, sym) + markAllCompleted(sym) RuntimePackageClass.info.decls.toList.filter(_.name == sym.name) match { case existing :: _ => existing.asInstanceOf[ClassSymbol] @@ -1241,7 +1239,7 @@ trait Definitions extends api.StandardDefinitions { val tparam = clazz.newSyntheticTypeParam("T0", flags) val parents = List(AnyRefTpe, parentFn(tparam)) - clazz setInfo GenPolyType(List(tparam), ClassInfoType(parents, newScope, clazz)) + clazz setInfo GenPolyType(List(tparam), ClassInfoType(parents, newScope, clazz)) markAllCompleted } def newPolyMethod(typeParamCount: Int, owner: Symbol, name: TermName, flags: Long)(createFn: PolyMethodCreator): MethodSymbol = { @@ -1252,7 +1250,7 @@ trait Definitions extends api.StandardDefinitions { case (_, restpe) => NullaryMethodType(restpe) } - msym setInfoAndEnter genPolyType(tparams, mtpe) + msym setInfoAndEnter genPolyType(tparams, mtpe) markAllCompleted } /** T1 means one type parameter. diff --git a/src/reflect/scala/reflect/internal/FlagSets.scala b/src/reflect/scala/reflect/internal/FlagSets.scala index 84825ff2da..799f85054a 100644 --- a/src/reflect/scala/reflect/internal/FlagSets.scala +++ b/src/reflect/scala/reflect/internal/FlagSets.scala @@ -43,5 +43,6 @@ trait FlagSets extends api.FlagSets { self: SymbolTable => val PRESUPER : FlagSet = Flags.PRESUPER val DEFAULTINIT : FlagSet = Flags.DEFAULTINIT val SYNTHETIC : FlagSet = Flags.SYNTHETIC + val ENUM : FlagSet = Flags.ENUM } } diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index dcdf6728ce..e66ed9a3d4 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -63,7 +63,7 @@ import scala.collection.{ mutable, immutable } // 45: SYNCHRONIZED/M // 46: ARTIFACT // 47: DEFAULTMETHOD/M -// 48: +// 48: ENUM // 49: // 50: // 51: lateDEFERRED @@ -119,6 +119,7 @@ class ModifierFlags { final val DEFAULTINIT = 1L << 41 // symbol is initialized to the default value: used by -Xcheckinit final val ARTIFACT = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode final val DEFAULTMETHOD = 1L << 47 // symbol is a java default method + final val ENUM = 1L << 48 // symbol is an enum /** Symbols which are marked ARTIFACT. (Expand this list?) * @@ -142,7 +143,7 @@ class ModifierFlags { } object ModifierFlags extends ModifierFlags -/** All flags and associated operatins */ +/** All flags and associated operations */ class Flags extends ModifierFlags { final val METHOD = 1 << 6 // a method final val MODULE = 1 << 8 // symbol is module or class implementing a module @@ -446,7 +447,7 @@ class Flags extends ModifierFlags { case SYNCHRONIZED => "<synchronized>" // (1L << 45) case ARTIFACT => "<artifact>" // (1L << 46) case DEFAULTMETHOD => "<defaultmethod>" // (1L << 47) - case 0x1000000000000L => "" // (1L << 48) + case ENUM => "<enum>" // (1L << 48) case 0x2000000000000L => "" // (1L << 49) case 0x4000000000000L => "" // (1L << 50) case `lateDEFERRED` => "<latedeferred>" // (1L << 51) @@ -478,7 +479,7 @@ class Flags extends ModifierFlags { ) @deprecated("Use flagString on the flag-carrying member", "2.10.0") - def flagsToString(flags: Long, privateWithin: String): String = { + private[scala] def flagsToString(flags: Long, privateWithin: String): String = { val access = accessString(flags, privateWithin) val nonAccess = flagsToString(flags & ~AccessFlags) @@ -486,7 +487,7 @@ class Flags extends ModifierFlags { } @deprecated("Use flagString on the flag-carrying member", "2.10.0") - def flagsToString(flags: Long): String = { + private[scala] def flagsToString(flags: Long): String = { // Fast path for common case if (flags == 0L) "" else { var sb: StringBuilder = null diff --git a/src/reflect/scala/reflect/internal/FreshNames.scala b/src/reflect/scala/reflect/internal/FreshNames.scala index bb488aa2a8..7e9a568266 100644 --- a/src/reflect/scala/reflect/internal/FreshNames.scala +++ b/src/reflect/scala/reflect/internal/FreshNames.scala @@ -8,13 +8,17 @@ package internal import scala.reflect.internal.util.FreshNameCreator -trait FreshNames { self: Names => +trait FreshNames { self: Names with StdNames => + // SI-6879 Keeps track of counters that are supposed to be globally unique + // as opposed to traditional freshers that are unique to compilation units. + val globalFreshNameCreator = new FreshNameCreator + // default fresh name creator used to abstract over currentUnit.fresh and runtime fresh name creator def currentFreshNameCreator: FreshNameCreator // create fresh term/type name using implicit fresh name creator - def freshTermName(prefix: String = "x$")(implicit creator: FreshNameCreator): TermName = newTermName(creator.newName(prefix)) - def freshTypeName(prefix: String)(implicit creator: FreshNameCreator): TypeName = newTypeName(creator.newName(prefix)) + def freshTermName(prefix: String = nme.FRESH_TERM_NAME_PREFIX)(implicit creator: FreshNameCreator): TermName = newTermName(creator.newName(prefix)) + def freshTypeName(prefix: String)(implicit creator: FreshNameCreator): TypeName = newTypeName(creator.newName(prefix)) // Extractor that matches names which were generated by some // FreshNameCreator with known prefix. Extracts user-specified @@ -32,4 +36,4 @@ trait FreshNames { self: Names => else Some(NameTransformer.decode(sname.replaceFirst(quotedCreatorPrefix, "").replaceAll("\\d*$", ""))) } } -}
\ No newline at end of file +} diff --git a/src/reflect/scala/reflect/internal/HasFlags.scala b/src/reflect/scala/reflect/internal/HasFlags.scala index ecbf839bab..1131c94da0 100644 --- a/src/reflect/scala/reflect/internal/HasFlags.scala +++ b/src/reflect/scala/reflect/internal/HasFlags.scala @@ -82,6 +82,7 @@ trait HasFlags { def hasAbstractFlag = hasFlag(ABSTRACT) def hasAccessorFlag = hasFlag(ACCESSOR) def hasDefault = hasFlag(DEFAULTPARAM) && hasFlag(METHOD | PARAM) // Second condition disambiguates with TRAIT + def hasEnumFlag = hasFlag(ENUM) def hasLocalFlag = hasFlag(LOCAL) def hasModuleFlag = hasFlag(MODULE) def hasPackageFlag = hasFlag(PACKAGE) diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index 91ba552012..ff91b08ea1 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -4,6 +4,7 @@ package internal import scala.collection.mutable.WeakHashMap import scala.ref.WeakReference +import scala.reflect.internal.Flags._ // SI-6241: move importers to a mirror trait Importers extends api.Importers { to: SymbolTable => @@ -87,6 +88,7 @@ trait Importers extends api.Importers { to: SymbolTable => } my setInfo GenPolyType(mytypeParams, importType(theirCore)) my setAnnotations (their.annotations map importAnnotationInfo) + markAllCompleted(my) } } } finally { @@ -142,6 +144,7 @@ trait Importers extends api.Importers { to: SymbolTable => myowner.newTypeSymbol(myname.toTypeName, mypos, myflags) } symMap.weakUpdate(their, my) + markFlagsCompleted(my)(mask = AllFlags) my setInfo recreatedSymbolCompleter(my, their) } @@ -260,14 +263,16 @@ trait Importers extends api.Importers { to: SymbolTable => newExistentialType(tparams map importSymbol, importType(result)) case from.OverloadedType(pre, alts) => OverloadedType(importType(pre), alts map importSymbol) + case from.ImportType(qual) => + ImportType(importTree(qual)) case from.AntiPolyType(pre, targs) => AntiPolyType(importType(pre), targs map importType) case their: from.TypeVar => val myconstr = new TypeConstraint(their.constr.loBounds map importType, their.constr.hiBounds map importType) myconstr.inst = importType(their.constr.inst) TypeVar(importType(their.origin), myconstr, their.typeArgs map importType, their.params map importSymbol) - case from.AnnotatedType(annots, result, selfsym) => - AnnotatedType(annots map importAnnotationInfo, importType(result), importSymbol(selfsym)) + case from.AnnotatedType(annots, result) => + AnnotatedType(annots map importAnnotationInfo, importType(result)) case from.ErrorType => ErrorType case from.WildcardType => diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 9c5a593ca5..6cf4944d18 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -186,6 +186,15 @@ trait Mirrors extends api.Mirrors { def getPackageObjectIfDefined(fullname: TermName): Symbol = wrapMissing(getPackageObject(fullname)) + + final def getPackageObjectWithMember(pre: Type, sym: Symbol): Symbol = { + // The owner of a symbol which requires package qualification may be the + // package object iself, but it also could be any superclass of the package + // object. In the latter case, we must go through the qualifier's info + // to obtain the right symbol. + if (sym.owner.isModuleClass) sym.owner.sourceModule // fast path, if the member is owned by a module class, that must be linked to the package object + else pre member nme.PACKAGE // otherwise we have to findMember + } override def staticPackage(fullname: String): ModuleSymbol = ensurePackageSymbol(fullname.toString, getModuleOrClass(newTermNameCached(fullname)), allowModules = false) diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index 4075653674..73ce59feb2 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -345,6 +345,13 @@ trait Names extends api.Names { i += 1 i == prefix.length } + final def startsWith(prefix: String, start: Int): Boolean = { + var i = 0 + while (i < prefix.length && start + i < len && + chrs(index + start + i) == prefix.charAt(i)) + i += 1 + i == prefix.length + } /** Does this name end with suffix? */ final def endsWith(suffix: Name): Boolean = endsWith(suffix, len) @@ -357,6 +364,13 @@ trait Names extends api.Names { i += 1 i > suffix.length } + final def endsWith(suffix: String, end: Int): Boolean = { + var i = 1 + while (i <= suffix.length && i <= end && + chrs(index + end - i) == suffix.charAt(suffix.length - i)) + i += 1 + i > suffix.length + } final def containsName(subname: String): Boolean = containsName(newTermName(subname)) final def containsName(subname: Name): Boolean = { @@ -382,9 +396,9 @@ trait Names extends api.Names { final def startChar: Char = this charAt 0 final def endChar: Char = this charAt len - 1 final def startsWith(char: Char): Boolean = len > 0 && startChar == char - final def startsWith(name: String): Boolean = startsWith(newTermName(name)) + final def startsWith(name: String): Boolean = startsWith(name, 0) final def endsWith(char: Char): Boolean = len > 0 && endChar == char - final def endsWith(name: String): Boolean = endsWith(newTermName(name)) + final def endsWith(name: String): Boolean = endsWith(name, len) /** Rewrite the confusing failure indication via result == length to * the normal failure indication via result == -1. @@ -443,9 +457,10 @@ trait Names extends api.Names { } /** TODO - find some efficiency. */ - def append(ch: Char) = newName("" + this + ch) - def append(suffix: String) = newName("" + this + suffix) - def append(suffix: Name) = newName("" + this + suffix) + def append(ch: Char) = newName(toString + ch) + def append(suffix: String) = newName(toString + suffix) + def append(suffix: Name) = newName(toString + suffix) + def append(separator: Char, suffix: Name) = newName(toString + separator + suffix) def prepend(prefix: String) = newName("" + prefix + this) def decodedName: ThisNameType = newName(decode) @@ -463,7 +478,7 @@ trait Names extends api.Names { */ final class NameOps[T <: Name](name: T) { import NameTransformer._ - def stripSuffix(suffix: String): T = stripSuffix(suffix: TermName) + def stripSuffix(suffix: String): T = if (name endsWith suffix) dropRight(suffix.length) else name // OPT avoid creating a Name with `suffix` def stripSuffix(suffix: Name): T = if (name endsWith suffix) dropRight(suffix.length) else name def take(n: Int): T = name.subName(0, n).asInstanceOf[T] def drop(n: Int): T = name.subName(n, name.length).asInstanceOf[T] @@ -500,21 +515,21 @@ trait Names extends api.Names { /** TermName_S and TypeName_S have fields containing the string version of the name. * TermName_R and TypeName_R recreate it each time toString is called. */ - private class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) { + private final class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) { protected def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString) override def newName(str: String): TermName = newTermNameCached(str) } - private class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) { + private final class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) { protected def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString) override def newName(str: String): TypeName = newTypeNameCached(str) } - private class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) { + private final class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) { protected def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h) override def toString = new String(chrs, index, len) } - private class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) { + private final class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) { protected def createCompanionName(h: Int): TermName = new TermName_R(index, len, h) override def toString = new String(chrs, index, len) } diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 424e73dce8..519d1047a6 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -17,8 +17,6 @@ trait Printers extends api.Printers { self: SymbolTable => //nsc import treeInfo.{ IsTrue, IsFalse } - final val showOuterTests = false - /** Adds backticks if the name is a scala keyword. */ def quotedName(name: Name, decode: Boolean): String = { val s = if (decode) name.decode else name.toString @@ -53,8 +51,8 @@ trait Printers extends api.Printers { self: SymbolTable => */ def backquotedPath(t: Tree): String = { t match { - case Select(qual, name) if name.isTermName => "%s.%s".format(backquotedPath(qual), symName(t, name)) - case Select(qual, name) if name.isTypeName => "%s#%s".format(backquotedPath(qual), symName(t, name)) + case Select(qual, name) if name.isTermName => s"${backquotedPath(qual)}.${symName(t, name)}" + case Select(qual, name) if name.isTypeName => s"${backquotedPath(qual)}#${symName(t, name)}" case Ident(name) => symName(t, name) case _ => t.toString } @@ -76,7 +74,7 @@ trait Printers extends api.Printers { self: SymbolTable => def printPosition(tree: Tree) = if (printPositions) print(tree.pos.show) - def println() { + def println() = { out.println() while (indentMargin > indentString.length()) indentString += indentString @@ -84,116 +82,221 @@ trait Printers extends api.Printers { self: SymbolTable => out.write(indentString, 0, indentMargin) } - def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit) { + def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit): Unit = ls match { case List() => case List(x) => printelem(x) case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep) } - } - def printColumn(ts: List[Tree], start: String, sep: String, end: String) { + def printColumn(ts: List[Tree], start: String, sep: String, end: String) = { print(start); indent(); println() printSeq(ts){print(_)}{print(sep); println()}; undent(); println(); print(end) } - def printRow(ts: List[Tree], start: String, sep: String, end: String) { + def printRow(ts: List[Tree], start: String, sep: String, end: String): Unit = { print(start); printSeq(ts){print(_)}{print(sep)}; print(end) } - def printRow(ts: List[Tree], sep: String) { printRow(ts, "", sep, "") } + def printRow(ts: List[Tree], sep: String): Unit = printRow(ts, "", sep, "") - def printTypeParams(ts: List[TypeDef]) { - if (!ts.isEmpty) { + def printTypeParams(ts: List[TypeDef]): Unit = + if (ts.nonEmpty) { print("["); printSeq(ts){ t => printAnnotations(t) + if (t.mods.hasFlag(CONTRAVARIANT)) { + print("-") + } else if (t.mods.hasFlag(COVARIANT)) { + print("+") + } printParam(t) }{print(", ")}; print("]") } - } - def printLabelParams(ps: List[Ident]) { + def printLabelParams(ps: List[Ident]) = { print("(") printSeq(ps){printLabelParam}{print(", ")} print(")") } - def printLabelParam(p: Ident) { + def printLabelParam(p: Ident) = { print(symName(p, p.name)); printOpt(": ", TypeTree() setType p.tpe) } - def printValueParams(ts: List[ValDef]) { - print("(") - if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "") - printSeq(ts){printParam}{print(", ")} - print(")") + protected def parenthesize(condition: Boolean = true)(body: => Unit) = { + if (condition) print("(") + body + if (condition) print(")") } + + protected def printImplicitInParamsList(vds: List[ValDef]) = + if (vds.nonEmpty) printFlags(vds.head.mods.flags & IMPLICIT, "") + + def printValueParams(ts: List[ValDef], inParentheses: Boolean = true): Unit = + parenthesize(inParentheses){ + printImplicitInParamsList(ts) + printSeq(ts){printParam}{print(", ")} + } - def printParam(tree: Tree) { + def printParam(tree: Tree) = tree match { - case ValDef(mods, name, tp, rhs) => + case vd @ ValDef(mods, name, tp, rhs) => printPosition(tree) - printAnnotations(tree) + printAnnotations(vd) print(symName(tree, name)); printOpt(": ", tp); printOpt(" = ", rhs) case TypeDef(mods, name, tparams, rhs) => printPosition(tree) print(symName(tree, name)) printTypeParams(tparams); print(rhs) } - } - def printBlock(tree: Tree) { + def printBlock(tree: Tree) = tree match { case Block(_, _) => print(tree) case _ => printColumn(List(tree), "{", ";", "}") } - } private def symFn[T](tree: Tree, f: Symbol => T, orElse: => T): T = tree.symbol match { - case null | NoSymbol => orElse - case sym => f(sym) + case null | NoSymbol => orElse + case sym => f(sym) } private def ifSym(tree: Tree, p: Symbol => Boolean) = symFn(tree, p, false) - def printOpt(prefix: String, tree: Tree) { - if (!tree.isEmpty) { print(prefix, tree) } - } + def printOpt(prefix: String, tree: Tree) = if (tree.nonEmpty) { print(prefix, tree) } def printModifiers(tree: Tree, mods: Modifiers): Unit = printFlags( - if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + ( - if (tree.symbol == NoSymbol) mods.privateWithin - else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name - else "" + if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + ( + if (tree.symbol == NoSymbol) mods.privateWithin + else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name + else "" ) ) - def printFlags(flags: Long, privateWithin: String) { + def printFlags(flags: Long, privateWithin: String) = { val mask: Long = if (settings.debug) -1L else PrintableFlags val s = flagsToString(flags & mask, privateWithin) if (s != "") print(s + " ") } - def printAnnotations(tree: Tree) { + def printAnnotations(tree: MemberDef) = { // SI-5885: by default this won't print annotations of not yet initialized symbols val annots = tree.symbol.annotations match { - case Nil => tree.asInstanceOf[MemberDef].mods.annotations + case Nil => tree.mods.annotations case anns => anns } - annots foreach (annot => print("@"+annot+" ")) + annots foreach (annot => print(s"@$annot ")) } private var currentOwner: Symbol = NoSymbol private var selectorType: Type = NoType + + protected def printPackageDef(tree: PackageDef, separator: String) = { + val PackageDef(packaged, stats) = tree + printAnnotations(tree) + print("package ", packaged); printColumn(stats, " {", separator, "}") + } + + protected def printValDef(tree: ValDef, resultName: => String)(printTypeSignature: => Unit)(printRhs: => Unit) = { + val ValDef(mods, name, tp, rhs) = tree + printAnnotations(tree) + printModifiers(tree, mods) + print(if (mods.isMutable) "var " else "val ", resultName) + printTypeSignature + printRhs + } + + protected def printDefDef(tree: DefDef, resultName: => String)(printTypeSignature: => Unit)(printRhs: => Unit) = { + val DefDef(mods, name, tparams, vparamss, tp, rhs) = tree + printAnnotations(tree) + printModifiers(tree, mods) + print("def " + resultName) + printTypeParams(tparams); + vparamss foreach {printValueParams(_)} + printTypeSignature + printRhs + } + + protected def printTypeDef(tree: TypeDef, resultName: => String) = { + val TypeDef(mods, name, tparams, rhs) = tree + if (mods hasFlag (PARAM | DEFERRED)) { + printAnnotations(tree) + printModifiers(tree, mods) + print("type ") + printParam(tree) + } else { + printAnnotations(tree) + printModifiers(tree, mods) + print("type " + resultName) + printTypeParams(tparams) + printOpt(" = ", rhs) + } + } + + protected def printImport(tree: Import, resSelect: => String) = { + val Import(expr, selectors) = tree + // Is this selector renaming a name (i.e, {name1 => name2}) + def isNotRename(s: ImportSelector): Boolean = + s.name == nme.WILDCARD || s.name == s.rename + + def selectorToString(s: ImportSelector): String = { + val from = quotedName(s.name) + if (isNotRename(s)) from + else from + "=>" + quotedName(s.rename) + } + print("import ", resSelect, ".") + selectors match { + case List(s) => + // If there is just one selector and it is not renaming a name, no braces are needed + if (isNotRename(s)) print(selectorToString(s)) + else print("{", selectorToString(s), "}") + // If there is more than one selector braces are always needed + case many => + print(many.map(selectorToString).mkString("{", ", ", "}")) + } + } + + protected def printCaseDef(tree: CaseDef) = { + val CaseDef(pat, guard, body) = tree + print("case ") + def patConstr(pat: Tree): Tree = pat match { + case Apply(fn, args) => patConstr(fn) + case _ => pat + } + + print(pat); printOpt(" if ", guard) + print(" => ", body) + } + + protected def printFunction(tree: Function)(printValueParams: => Unit) = { + val Function(vparams, body) = tree + print("("); + printValueParams + print(" => ", body, ")") + if (printIds && tree.symbol != null) print("#" + tree.symbol.id) + } + + protected def printSuper(tree: Super, resultName: => String) = { + val Super(This(qual), mix) = tree + if (qual.nonEmpty || tree.symbol != NoSymbol) print(resultName + ".") + print("super") + if (mix.nonEmpty) print(s"[$mix]") + } + + protected def printThis(tree: This, resultName: => String) = { + val This(qual) = tree + if (qual.nonEmpty) print(resultName + ".") + print("this") + } - def printTree(tree: Tree) { + def printTree(tree: Tree) = { tree match { case EmptyTree => print("<empty>") - case ClassDef(mods, name, tparams, impl) => - printAnnotations(tree) + case cd @ ClassDef(mods, name, tparams, impl) => + printAnnotations(cd) printModifiers(tree, mods) val word = if (mods.isTrait) "trait" @@ -204,81 +307,45 @@ trait Printers extends api.Printers { self: SymbolTable => printTypeParams(tparams) print(if (mods.isDeferred) " <: " else " extends ", impl) - case PackageDef(packaged, stats) => - printAnnotations(tree) - print("package ", packaged); printColumn(stats, " {", ";", "}") + case pd @ PackageDef(packaged, stats) => + printPackageDef(pd, ";") - case ModuleDef(mods, name, impl) => - printAnnotations(tree) + case md @ ModuleDef(mods, name, impl) => + printAnnotations(md) printModifiers(tree, mods) print("object " + symName(tree, name), " extends ", impl) - case ValDef(mods, name, tp, rhs) => - printAnnotations(tree) - printModifiers(tree, mods) - print(if (mods.isMutable) "var " else "val ", symName(tree, name)) - printOpt(": ", tp) - if (!mods.isDeferred) - print(" = ", if (rhs.isEmpty) "_" else rhs) + case vd @ ValDef(mods, name, tp, rhs) => + printValDef(vd, symName(tree, name))(printOpt(": ", tp)) { + if (!mods.isDeferred) print(" = ", if (rhs.isEmpty) "_" else rhs) + } - case DefDef(mods, name, tparams, vparamss, tp, rhs) => - printAnnotations(tree) - printModifiers(tree, mods) - print("def " + symName(tree, name)) - printTypeParams(tparams); vparamss foreach printValueParams - printOpt(": ", tp); printOpt(" = ", rhs) + case dd @ DefDef(mods, name, tparams, vparamss, tp, rhs) => + printDefDef(dd, symName(tree, name))(printOpt(": ", tp))(printOpt(" = ", rhs)) - case TypeDef(mods, name, tparams, rhs) => - if (mods hasFlag (PARAM | DEFERRED)) { - printAnnotations(tree) - printModifiers(tree, mods); print("type "); printParam(tree) - } else { - printAnnotations(tree) - printModifiers(tree, mods); print("type " + symName(tree, name)) - printTypeParams(tparams); printOpt(" = ", rhs) - } + case td @ TypeDef(mods, name, tparams, rhs) => + printTypeDef(td, symName(tree, name)) case LabelDef(name, params, rhs) => print(symName(tree, name)); printLabelParams(params); printBlock(rhs) - case Import(expr, selectors) => - // Is this selector remapping a name (i.e, {name1 => name2}) - def isNotRemap(s: ImportSelector) : Boolean = (s.name == nme.WILDCARD || s.name == s.rename) - def selectorToString(s: ImportSelector): String = { - val from = quotedName(s.name) - if (isNotRemap(s)) from - else from + "=>" + quotedName(s.rename) - } - print("import ", backquotedPath(expr), ".") - selectors match { - case List(s) => - // If there is just one selector and it is not remapping a name, no braces are needed - if (isNotRemap(s)) print(selectorToString(s)) - else print("{", selectorToString(s), "}") - // If there is more than one selector braces are always needed - case many => - print(many.map(selectorToString).mkString("{", ", ", "}")) - } + case imp @ Import(expr, _) => + printImport(imp, backquotedPath(expr)) - case Template(parents, self, body) => + case Template(parents, self, body) => val currentOwner1 = currentOwner if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner -// if (parents exists isReferenceToAnyVal) { -// print("AnyVal") -// } -// else { printRow(parents, " with ") - if (!body.isEmpty) { + if (body.nonEmpty) { if (self.name != nme.WILDCARD) { print(" { ", self.name); printOpt(": ", self.tpt); print(" => ") - } else if (!self.tpt.isEmpty) { + } else if (self.tpt.nonEmpty) { print(" { _ : ", self.tpt, " => ") } else { print(" {") } printColumn(body, "", ";", "}") } -// } currentOwner = currentOwner1 case Block(stats, expr) => @@ -290,18 +357,8 @@ trait Printers extends api.Printers { self: SymbolTable => print(selector); printColumn(cases, " match {", "", "}") selectorType = selectorType1 - case CaseDef(pat, guard, body) => - print("case ") - def patConstr(pat: Tree): Tree = pat match { - case Apply(fn, args) => patConstr(fn) - case _ => pat - } - if (showOuterTests && - needsOuterTest( - patConstr(pat).tpe.finalResultType, selectorType, currentOwner)) - print("???") - print(pat); printOpt(" if ", guard) - print(" => ", body) + case cd @ CaseDef(pat, guard, body) => + printCaseDef(cd) case Alternative(trees) => printRow(trees, "(", "| ", ")") @@ -318,9 +375,8 @@ trait Printers extends api.Printers { self: SymbolTable => case ArrayValue(elemtpt, trees) => print("Array[", elemtpt); printRow(trees, "]{", ", ", "}") - case Function(vparams, body) => - print("("); printValueParams(vparams); print(" => ", body, ")") - if (printIds && tree.symbol != null) print("#"+tree.symbol.id) + case f @ Function(vparams, body) => + printFunction(f)(printValueParams(vparams)) case Assign(lhs, rhs) => print(lhs, " = ", rhs) @@ -331,7 +387,7 @@ trait Printers extends api.Printers { self: SymbolTable => case If(cond, thenp, elsep) => print("if (", cond, ")"); indent(); println() print(thenp); undent() - if (!elsep.isEmpty) { + if (elsep.nonEmpty) { println(); print("else"); indent(); println(); print(elsep); undent() } @@ -340,7 +396,7 @@ trait Printers extends api.Printers { self: SymbolTable => case Try(block, catches, finalizer) => print("try "); printBlock(block) - if (!catches.isEmpty) printColumn(catches, " catch {", "", "}") + if (catches.nonEmpty) printColumn(catches, " catch {", "", "}") printOpt(" finally ", finalizer) case Throw(expr) => @@ -362,22 +418,18 @@ trait Printers extends api.Printers { self: SymbolTable => print("<apply-dynamic>(", qual, "#", tree.symbol.nameString) printRow(vargs, ", (", ", ", "))") - case Super(This(qual), mix) => - if (!qual.isEmpty || tree.symbol != NoSymbol) print(symName(tree, qual) + ".") - print("super") - if (!mix.isEmpty) - print("[" + mix + "]") + case st @ Super(This(qual), mix) => + printSuper(st, symName(tree, qual)) case Super(qual, mix) => print(qual, ".super") - if (!mix.isEmpty) + if (mix.nonEmpty) print("[" + mix + "]") - case This(qual) => - if (!qual.isEmpty) print(symName(tree, qual) + ".") - print("this") + case th @ This(qual) => + printThis(th, symName(tree, qual)) - case Select(qual @ New(tpe), name) if !settings.debug => + case Select(qual: New, name) if !settings.debug => print(qual) case Select(qualifier, name) => @@ -400,10 +452,10 @@ trait Printers extends api.Printers { self: SymbolTable => print(tree.tpe.toString) } - case Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) => + case an @ Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) => def printAnnot() { print("@", tpt) - if (!args.isEmpty) + if (args.nonEmpty) printRow(args, "(", ",", ")") } print(tree, if (tree.isType) " " else ": ") @@ -435,11 +487,11 @@ trait Printers extends api.Printers { self: SymbolTable => print(tpt) printColumn(whereClauses, " forSome { ", ";", "}") -// SelectFromArray is no longer visible in scala.reflect.internal. -// eliminated until we figure out what we will do with both Printers and -// SelectFromArray. -// case SelectFromArray(qualifier, name, _) => -// print(qualifier); print(".<arr>"); print(symName(tree, name)) + // SelectFromArray is no longer visible in scala.reflect.internal. + // eliminated until we figure out what we will do with both Printers and + // SelectFromArray. + // case SelectFromArray(qualifier, name, _) => + // print(qualifier); print(".<arr>"); print(symName(tree, name)) case tree => xprintTree(this, tree) @@ -459,11 +511,498 @@ trait Printers extends api.Printers { self: SymbolTable => out.print(if (arg == null) "null" else arg.toString) } } + + // it's the printer for trees after parser and before typer phases + class ParsedTreePrinter(out: PrintWriter) extends TreePrinter(out) { + override def withTypes = this + override def withIds = this + override def withKinds = this + override def withMirrors = this + override def withPositions = this + + // TODO: add print parameters to typed trees printer + printTypes = false + printIds = false + printKinds = false + printMirrors = false + printPositions = false + + protected val parentsStack = scala.collection.mutable.Stack[Tree]() + + protected def currentTree = if (parentsStack.nonEmpty) Some(parentsStack.top) else None + + protected def currentParent = if (parentsStack.length > 1) Some(parentsStack(1)) else None + + protected def printedName(name: Name, decoded: Boolean = true) = { + import Chars._ + val decName = name.decoded + val bslash = '\\' + val brackets = List('[',']','(',')','{','}') + + def addBackquotes(s: String) = + if (decoded && (decName.exists(ch => brackets.contains(ch) || isWhitespace(ch)) || + (name.isOperatorName && decName.exists(isOperatorPart) && decName.exists(isScalaLetter) && !decName.contains(bslash)))) + s"`$s`" else s + + if (name == nme.CONSTRUCTOR) "this" + else addBackquotes(quotedName(name, decoded)) + } + + protected def isIntLitWithDecodedOp(qual: Tree, name: Name) = { + val qualIsIntLit = qual match { + case Literal(Constant(x: Int)) => true + case _ => false + } + qualIsIntLit && name.isOperatorName + } + + protected def needsParentheses(parent: Tree)(insideIf: Boolean = true, insideMatch: Boolean = true, + insideTry: Boolean = true, insideAnnotated: Boolean = true, insideBlock: Boolean = true, insideLabelDef: Boolean = true) = { + parent match { + case _: If => insideIf + case _: Match => insideMatch + case _: Try => insideTry + case _: Annotated => insideAnnotated + case _: Block => insideBlock + case _: LabelDef => insideLabelDef + case _ => false + } + } + + protected def checkForBlank(cond: Boolean) = if (cond) " " else "" + protected def blankForOperatorName(name: Name) = checkForBlank(name.isOperatorName) + protected def blankForName(name: Name) = checkForBlank(name.isOperatorName || name.endsWith("_")) + + protected def resolveSelect(t: Tree): String = { + t match { + // case for: 1) (if (a) b else c).meth1.meth2 or 2) 1 + 5 should be represented as (1).+(5) + case Select(qual, name) if (name.isTermName && needsParentheses(qual)(insideLabelDef = false)) || isIntLitWithDecodedOp(qual, name) => s"(${resolveSelect(qual)}).${printedName(name)}" + case Select(qual, name) if name.isTermName => s"${resolveSelect(qual)}.${printedName(name)}" + case Select(qual, name) if name.isTypeName => s"${resolveSelect(qual)}#${blankForOperatorName(name)}%${printedName(name)}" + case Ident(name) => printedName(name) + case _ => showCode(t) + } + } + + val defaultClasses = List(tpnme.AnyRef) + val defaultTraitsForCase = List(tpnme.Product, tpnme.Serializable) + protected def removeDefaultTypesFromList(trees: List[Tree])(classesToRemove: List[Name] = defaultClasses)(traitsToRemove: List[Name]) = { + def removeDefaultTraitsFromList(trees: List[Tree], traitsToRemove: List[Name]): List[Tree] = + trees match { + case Nil => trees + case init :+ last => last match { + case Select(Ident(sc), name) if traitsToRemove.contains(name) && sc == nme.scala_ => + removeDefaultTraitsFromList(init, traitsToRemove) + case _ => trees + } + } + + removeDefaultTraitsFromList(removeDefaultClassesFromList(trees, classesToRemove), traitsToRemove) + } + + protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) = trees filter { + case Select(Ident(sc), name) => !(classesToRemove.contains(name) && sc == nme.scala_) + case _ => true + } + + def printFlags(mods: Modifiers, primaryCtorParam: Boolean = false): Unit = { + val base = AccessFlags | OVERRIDE | ABSTRACT | FINAL | SEALED | LAZY + val mask = if (primaryCtorParam) base else base | IMPLICIT + + val s = mods.flagString(mask) + if (s != "") print(s"$s ") + // case flag should be the last + if (mods.isCase) print(mods.flagBitsToString(CASE) + " ") + if (mods.isAbstractOverride) print("abstract override ") + } + + override def printModifiers(tree: Tree, mods: Modifiers): Unit = printModifiers(mods, primaryCtorParam = false) + + def printModifiers(mods: Modifiers, primaryCtorParam: Boolean): Unit = { + def modsAccepted = List(currentTree, currentParent) exists (_ map { + case _: ClassDef | _: ModuleDef | _: Template | _: PackageDef => true + case _ => false + } getOrElse false) + + if (currentParent.isEmpty || modsAccepted) + printFlags(mods, primaryCtorParam) + else + List(IMPLICIT, CASE, LAZY, SEALED).foreach{flag => if (mods.hasFlag(flag)) print(s"${mods.flagBitsToString(flag)} ")} + } + + def printParam(tree: Tree, primaryCtorParam: Boolean): Unit = + tree match { + case vd @ ValDef(mods, name, tp, rhs) => + printAnnotations(vd) + val mutableOrOverride = mods.isOverride || mods.isMutable + val hideCtorMods = mods.isParamAccessor && mods.isPrivateLocal && !mutableOrOverride + val hideCaseCtorMods = mods.isCaseAccessor && mods.isPublic && !mutableOrOverride + + if (primaryCtorParam && !(hideCtorMods || hideCaseCtorMods)) { + printModifiers(mods, primaryCtorParam) + print(if (mods.isMutable) "var " else "val "); + } + print(printedName(name), blankForName(name)); + printOpt(": ", tp); + printOpt(" = ", rhs) + case TypeDef(_, name, tparams, rhs) => + print(printedName(name)) + printTypeParams(tparams); + print(rhs) + case _ => + super.printParam(tree) + } + + override def printParam(tree: Tree): Unit = { + printParam(tree, primaryCtorParam = false) + } + + protected def printArgss(argss: List[List[Tree]]) = + argss foreach {x: List[Tree] => if (!(x.isEmpty && argss.size == 1)) printRow(x, "(", ", ", ")")} + + override def printAnnotations(tree: MemberDef) = { + val annots = tree.mods.annotations + annots foreach {annot => printAnnot(annot); print(" ")} + } + + protected def printAnnot(tree: Tree) = { + tree match { + case treeInfo.Applied(core, _, argss) => + print("@") + core match { + case Select(New(tree), _) => print(tree) + case _ => + } + printArgss(argss) + case _ => super.printTree(tree) + } + } + + override def printTree(tree: Tree): Unit = { + parentsStack.push(tree) + tree match { + case cl @ ClassDef(mods, name, tparams, impl) => + if (mods.isJavaDefined) super.printTree(cl) + printAnnotations(cl) + // traits + val clParents: List[Tree] = if (mods.isTrait) { + // avoid abstract modifier for traits + printModifiers(tree, mods &~ ABSTRACT) + print("trait ", printedName(name)) + printTypeParams(tparams) + + val build.SyntacticTraitDef(_, _, _, _, parents, _, _) = tree + parents + // classes + } else { + printModifiers(tree, mods) + print("class ", printedName(name)) + printTypeParams(tparams) + + val build.SyntacticClassDef(_, _, _, ctorMods, vparamss, earlyDefs, parents, selfType, body) = cl + + // constructor's modifier + if (ctorMods.hasFlag(AccessFlags)) { + print(" ") + printModifiers(ctorMods, primaryCtorParam = false) + } + + def printConstrParams(ts: List[ValDef]): Unit = { + parenthesize() { + printImplicitInParamsList(ts) + printSeq(ts)(printParam(_, primaryCtorParam = true))(print(", ")) + } + } + // constructor's params processing (don't print single empty constructor param list) + vparamss match { + case Nil | List(Nil) if (!mods.isCase && !ctorMods.hasFlag(AccessFlags)) => + case _ => vparamss foreach printConstrParams + } + parents + } + + // get trees without default classes and traits (when they are last) + val printedParents = removeDefaultTypesFromList(clParents)()(if (mods.hasFlag(CASE)) defaultTraitsForCase else Nil) + print(if (mods.isDeferred) "<: " else if (printedParents.nonEmpty) " extends " else "", impl) + + case pd @ PackageDef(packaged, stats) => + packaged match { + case Ident(name) if name == nme.EMPTY_PACKAGE_NAME => + printSeq(stats) { + print(_) + } { + print(";"); + println() + }; + case _ => + val separator = scala.util.Properties.lineSeparator + printPackageDef(pd, separator) + } + + case md @ ModuleDef(mods, name, impl) => + printAnnotations(md) + printModifiers(tree, mods) + val Template(parents, self, methods) = impl + val parWithoutAnyRef = removeDefaultClassesFromList(parents) + print("object " + printedName(name), if (parWithoutAnyRef.nonEmpty) " extends " else "", impl) + + case vd @ ValDef(mods, name, tp, rhs) => + printValDef(vd, printedName(name)) { + // place space after symbolic def name (val *: Unit does not compile) + printOpt(s"${blankForName(name)}: ", tp) + } { + if (!mods.isDeferred) print(" = ", if (rhs.isEmpty) "_" else rhs) + } + + case dd @ DefDef(mods, name, tparams, vparamss, tp, rhs) => + printDefDef(dd, printedName(name)) { + if (tparams.isEmpty && (vparamss.isEmpty || vparamss(0).isEmpty)) print(blankForName(name)) + printOpt(": ", tp) + } { + printOpt(" = " + (if (mods.isMacro) "macro " else ""), rhs) + } + + case td @ TypeDef(mods, name, tparams, rhs) => + printTypeDef(td, printedName(name)) + + case LabelDef(name, params, rhs) => + if (name.startsWith(nme.WHILE_PREFIX)) { + val If(cond, thenp, elsep) = rhs + print("while (", cond, ") ") + val Block(list, wh) = thenp + printColumn(list, "", ";", "") + } else if (name.startsWith(nme.DO_WHILE_PREFIX)) { + val Block(bodyList, ifCond @ If(cond, thenp, elsep)) = rhs + print("do ") + printColumn(bodyList, "", ";", "") + print(" while (", cond, ") ") + } else { + print(printedName(name)); printLabelParams(params); + printBlock(rhs) + } + + case imp @ Import(expr, _) => + printImport(imp, resolveSelect(expr)) + + case Template(parents, self, body) => + val printedParents = + currentParent map { + case _: CompoundTypeTree => parents + case ClassDef(mods, name, _, _) if mods.isCase => removeDefaultTypesFromList(parents)()(List(tpnme.Product, tpnme.Serializable)) + case _ => removeDefaultClassesFromList(parents) + } getOrElse (parents) + + val primaryCtr = treeInfo.firstConstructor(body) + val ap: Option[Apply] = primaryCtr match { + case DefDef(_, _, _, _, _, Block(ctBody, _)) => + val earlyDefs = treeInfo.preSuperFields(ctBody) ::: body.filter { + case td: TypeDef => treeInfo.isEarlyDef(td) + case _ => false + } + if (earlyDefs.nonEmpty) { + print("{") + printColumn(earlyDefs, "", ";", "") + print("} " + (if (printedParents.nonEmpty) "with " else "")) + } + ctBody collectFirst { + case apply: Apply => apply + } + case _ => None + } + + if (printedParents.nonEmpty) { + val (clParent :: traits) = printedParents + print(clParent) + + val constrArgss = ap match { + case Some(treeInfo.Applied(_, _, argss)) => argss + case _ => Nil + } + printArgss(constrArgss) + if (traits.nonEmpty) { + printRow(traits, " with ", " with ", "") + } + } + /* Remove primary constr def and constr val and var defs + * right contains all constructors + */ + val (left, right) = body.filter { + // remove valdefs defined in constructor and presuper vals + case vd: ValDef => !vd.mods.isParamAccessor && !treeInfo.isEarlyValDef(vd) + // remove $this$ from traits + case dd: DefDef => dd.name != nme.MIXIN_CONSTRUCTOR + case td: TypeDef => !treeInfo.isEarlyDef(td) + case EmptyTree => false + case _ => true + } span { + case dd: DefDef => dd.name != nme.CONSTRUCTOR + case _ => true + } + val modBody = left ::: right.drop(1) + val showBody = !(modBody.isEmpty && (self == noSelfType || self.isEmpty)) + if (showBody) { + if (self.name != nme.WILDCARD) { + print(" { ", self.name); + printOpt(": ", self.tpt); + print(" =>") + } else if (self.tpt.nonEmpty) { + print(" { _ : ", self.tpt, " =>") + } else { + print(" {") + } + printColumn(modBody, "", ";", "}") + } + + case Block(stats, expr) => super.printTree(tree) + + case Match(selector, cases) => + /* Insert braces if match is inner + * make this function available for other cases + * passing required type for checking + */ + def insertBraces(body: => Unit): Unit = + if (parentsStack.nonEmpty && parentsStack.tail.exists(_.isInstanceOf[Match])) { + print("(") + body + print(")") + } else body + + val printParentheses = needsParentheses(selector)(insideLabelDef = false) + tree match { + case Match(EmptyTree, cs) => + printColumn(cases, "{", "", "}") + case _ => + insertBraces { + parenthesize(printParentheses)(print(selector)) + printColumn(cases, " match {", "", "}") + } + } + + case cd @ CaseDef(pat, guard, body) => + printCaseDef(cd) + + case Star(elem) => + print(elem, "*") + + case Bind(name, t) => + if (t == EmptyTree) print("(", printedName(name), ")") + else if (t.exists(_.isInstanceOf[Star])) print(printedName(name), " @ ", t) + else print("(", printedName(name), " @ ", t, ")") + + case f @ Function(vparams, body) => + // parentheses are not allowed for val a: Int => Int = implicit x => x + val printParentheses = vparams match { + case head :: _ => !head.mods.isImplicit + case _ => true + } + printFunction(f)(printValueParams(vparams, inParentheses = printParentheses)) + + case Typed(expr, tp) => + tp match { + case Function(List(), EmptyTree) => print("(", expr, " _)") //func _ + // parentheses required when (a match {}) : Type + case _ => print("((", expr, "): ", tp, ")") + } + + case Apply(fun, vargs) => + tree match { + // processing methods ending on colons (x \: list) + case Apply(Block(l1 @ List(sVD: ValDef), a1 @ Apply(Select(_, methodName), l2 @ List(Ident(iVDName)))), l3) + if sVD.mods.isSynthetic && treeInfo.isLeftAssoc(methodName) && sVD.name == iVDName => + val printBlock = Block(l1, Apply(a1, l3)) + print(printBlock) + case Apply(tree1, _) if (needsParentheses(tree1)(insideAnnotated = false)) => + parenthesize()(print(fun)); printRow(vargs, "(", ", ", ")") + case _ => super.printTree(tree) + } + + case st @ Super(This(qual), mix) => + printSuper(st, printedName(qual)) + + case th @ This(qual) => + printThis(th, printedName(qual)) + + case Select(qual: New, name) => + print(qual) + + case Select(qualifier, name) => { + val printParentheses = needsParentheses(qualifier)(insideAnnotated = false) || isIntLitWithDecodedOp(qualifier, name) + if (printParentheses) print("(", resolveSelect(qualifier), ").", printedName(name)) + else print(resolveSelect(qualifier), ".", printedName(name)) + } + + case id @ Ident(name) => + if (name.nonEmpty) { + if (name == nme.dollarScope) { + print(s"scala.xml.${nme.TopScope}") + } else { + val str = printedName(name) + val strIsBackquoted = str.startsWith("`") && str.endsWith("`") + print(if (id.isBackquoted && !strIsBackquoted) "`" + str + "`" else str) + } + } else { + print("") + } + + case l @ Literal(x) => + import Chars.LF + x match { + case Constant(v: String) if { + val strValue = x.stringValue + strValue.contains(LF) && strValue.contains("\"\"\"") && strValue.size > 1 + } => + val splitValue = x.stringValue.split(s"$LF").toList + val multilineStringValue = if (x.stringValue.endsWith(s"$LF")) splitValue :+ "" else splitValue + val trQuotes = "\"\"\"" + print(trQuotes); printSeq(multilineStringValue) { print(_) } { print(LF) }; print(trQuotes) + case _ => + // processing Float constants + val printValue = x.escapedStringValue + (if (x.value.isInstanceOf[Float]) "F" else "") + print(printValue) + } + + case an @ Annotated(ap, tree) => + val printParentheses = needsParentheses(tree)() + parenthesize(printParentheses) { print(tree) }; print(if (tree.isType) " " else ": ") + printAnnot(ap) + + case SelectFromTypeTree(qualifier, selector) => + print("(", qualifier, ")#", blankForOperatorName(selector), printedName(selector)) + + case AppliedTypeTree(tp, args) => + // it's possible to have (=> String) => String type but Function1[=> String, String] is not correct + val containsByNameTypeParam = args exists treeInfo.isByNameParamType + + if (containsByNameTypeParam) { + print("(") + printRow(args.init, "(", ", ", ")") + print(" => ", args.last, ")") + } else { + if (treeInfo.isRepeatedParamType(tree) && args.nonEmpty) { + print(args(0), "*") + } else if (treeInfo.isByNameParamType(tree)) { + print("=> ", if (args.isEmpty) "()" else args(0)) + } else + super.printTree(tree) + } + + case ExistentialTypeTree(tpt, whereClauses) => + print("(", tpt); + printColumn(whereClauses, " forSome { ", ";", "})") + + case EmptyTree => + + case tree => super.printTree(tree) + } + parentsStack.pop() + } + } /** Hook for extensions */ def xprintTree(treePrinter: TreePrinter, tree: Tree) = treePrinter.print(tree.productPrefix+tree.productIterator.mkString("(", ", ", ")")) + def newCodePrinter(writer: PrintWriter): TreePrinter = new ParsedTreePrinter(writer) def newTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer) def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream)) def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter)) diff --git a/src/reflect/scala/reflect/internal/Required.scala b/src/reflect/scala/reflect/internal/Required.scala index 14db252a16..009bc39d4c 100644 --- a/src/reflect/scala/reflect/internal/Required.scala +++ b/src/reflect/scala/reflect/internal/Required.scala @@ -6,6 +6,9 @@ import settings.MutableSettings trait Required { self: SymbolTable => def picklerPhase: Phase + + def erasurePhase: Phase + def settings: MutableSettings @deprecated("Interactive is implemented with a custom Global; this flag is ignored", "2.11.0") def forInteractive = false diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala index b7a1681838..cf3f356daa 100644 --- a/src/reflect/scala/reflect/internal/Scopes.scala +++ b/src/reflect/scala/reflect/internal/Scopes.scala @@ -387,7 +387,7 @@ trait Scopes extends api.Scopes { self: SymbolTable => if (toList forall p) this else newScopeWith(toList filter p: _*) ) - @deprecated("Use `toList.reverse` instead", "2.10.0") + @deprecated("Use `toList.reverse` instead", "2.10.0") // Used in SBT 0.12.4 def reverse: List[Symbol] = toList.reverse override def mkString(start: String, sep: String, end: String) = diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala index 09fd996f39..139a79ffe1 100644 --- a/src/reflect/scala/reflect/internal/StdAttachments.scala +++ b/src/reflect/scala/reflect/internal/StdAttachments.scala @@ -36,6 +36,10 @@ trait StdAttachments { */ case object ForAttachment extends PlainAttachment + /** Identifies unit constants which were inserted by the compiler (e.g. gen.mkBlock) + */ + case object SyntheticUnitAttachment extends PlainAttachment + /** Untyped list of subpatterns attached to selector dummy. */ case class SubpatternsAttachment(patterns: List[Tree]) } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index ea6afa7349..679186f938 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -53,14 +53,17 @@ trait StdNames { * * We obtain the formula: * - * FileNameLength = 2*(MaxNameLength / 4) + 2.marker.length + 32 + 6 + * FileNameLength = 2*(MaxNameLength / 4) + 2.marker.length + 32 + suffixLength * - * (+6 for ".class"). MaxNameLength can therefore be computed as follows: + * (+suffixLength for ".class" and potential module class suffix that is added *after* this transform). + * + * MaxNameLength can therefore be computed as follows: */ val marker = "$$$$" + val maxSuffixLength = "$.class".length + 1 // potential module class suffix and file extension val MaxNameLength = math.min( - settings.maxClassfileName.value - 6, - 2 * (settings.maxClassfileName.value - 6 - 2*marker.length - 32) + settings.maxClassfileName.value - maxSuffixLength, + 2 * (settings.maxClassfileName.value - maxSuffixLength - 2*marker.length - 32) ) def toMD5(s: String, edge: Int): String = { val prefix = s take edge @@ -250,12 +253,13 @@ trait StdNames { final val Quasiquote: NameType = "Quasiquote" // quasiquote-specific names - final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$" - final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$" - final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$" - final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$" final val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$" + final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$" + final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$" final val QUASIQUOTE_PACKAGE_STAT: NameType = "$quasiquote$package$stat$" + final val QUASIQUOTE_PARAM: NameType = "$quasiquote$param$" + final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$" + final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$" // Annotation simple names, used in Namer final val BeanPropertyAnnot: NameType = "BeanProperty" @@ -291,20 +295,23 @@ trait StdNames { protected implicit def createNameType(name: String): TermName = newTermNameCached(name) /** Base strings from which synthetic names are derived. */ - val BITMAP_PREFIX = "bitmap$" - val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$" - val DEFAULT_GETTER_STRING = "$default$" - val DEFAULT_GETTER_INIT_STRING = NameTransformer.encode("<init>") + DEFAULT_GETTER_STRING - val DO_WHILE_PREFIX = "doWhile$" - val EVIDENCE_PARAM_PREFIX = "evidence$" - val EXCEPTION_RESULT_PREFIX = "exceptionResult" - val EXPAND_SEPARATOR_STRING = "$$" - val INTERPRETER_IMPORT_WRAPPER = "$iw" - val LOCALDUMMY_PREFIX = "<local " // owner of local blocks - val PROTECTED_PREFIX = "protected$" - val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set" - val SUPER_PREFIX_STRING = "super$" - val WHILE_PREFIX = "while$" + val BITMAP_PREFIX = "bitmap$" + val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$" + val DEFAULT_GETTER_STRING = "$default$" + val DEFAULT_GETTER_INIT_STRING = NameTransformer.encode("<init>") + DEFAULT_GETTER_STRING + val DO_WHILE_PREFIX = "doWhile$" + val EVIDENCE_PARAM_PREFIX = "evidence$" + val EXCEPTION_RESULT_PREFIX = "exceptionResult" + val EXPAND_SEPARATOR_STRING = "$$" + val FRESH_TERM_NAME_PREFIX = "x$" + val INTERPRETER_IMPORT_WRAPPER = "$iw" + val LOCALDUMMY_PREFIX = "<local " // owner of local blocks + val PROTECTED_PREFIX = "protected$" + val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set" + val SUPER_PREFIX_STRING = "super$" + val WHILE_PREFIX = "while$" + val FRESH_PREFIX = "fresh" + val FRESH_SUFFIX = "macro$" // uses a keyword to avoid collisions with mangled names // Compiler internal names val ANYname: NameType = "<anyname>" @@ -575,6 +582,7 @@ trait StdNames { val Flag : NameType = "Flag" val FlagsRepr: NameType = "FlagsRepr" val Ident: NameType = "Ident" + val ImplicitParams: NameType = "ImplicitParams" val Import: NameType = "Import" val Literal: NameType = "Literal" val LiteralAnnotArg: NameType = "LiteralAnnotArg" @@ -595,12 +603,14 @@ trait StdNames { val SyntacticBlock: NameType = "SyntacticBlock" val SyntacticClassDef: NameType = "SyntacticClassDef" val SyntacticDefDef: NameType = "SyntacticDefDef" + val SyntacticEmptyTypeTree: NameType = "SyntacticEmptyTypeTree" val SyntacticFilter: NameType = "SyntacticFilter" val SyntacticFor: NameType = "SyntacticFor" val SyntacticForYield: NameType = "SyntacticForYield" val SyntacticFunction: NameType = "SyntacticFunction" val SyntacticFunctionType: NameType = "SyntacticFunctionType" val SyntacticIdent: NameType = "SyntacticIdent" + val SyntacticImport: NameType = "SyntacticImport" val SyntacticMatch: NameType = "SyntacticMatch" val SyntacticNew: NameType = "SyntacticNew" val SyntacticObjectDef: NameType = "SyntacticObjectDef" @@ -686,6 +696,7 @@ trait StdNames { val inlinedEquals: NameType = "inlinedEquals" val isArray: NameType = "isArray" val isDefinedAt: NameType = "isDefinedAt" + val isEmpty: NameType = "isEmpty" val isInstanceOf_ : NameType = "isInstanceOf" val isInstanceOf_Ob : NameType = "$isInstanceOf" val java: NameType = "java" @@ -702,9 +713,9 @@ trait StdNames { val materializeTypeTag: NameType = "materializeTypeTag" val moduleClass : NameType = "moduleClass" val mkAnnotation: NameType = "mkAnnotation" - val mkRefineStat: NameType = "mkRefineStat" val mkEarlyDef: NameType = "mkEarlyDef" val mkPackageStat: NameType = "mkPackageStat" + val mkRefineStat: NameType = "mkRefineStat" val ne: NameType = "ne" val newArray: NameType = "newArray" val newFreeTerm: NameType = "newFreeTerm" @@ -749,6 +760,7 @@ trait StdNames { val toArray: NameType = "toArray" val toList: NameType = "toList" val toObjectArray : NameType = "toObjectArray" + val toStats: NameType = "toStats" val TopScope: NameType = "TopScope" val toString_ : NameType = "toString" val toTypeConstructor: NameType = "toTypeConstructor" @@ -762,8 +774,8 @@ trait StdNames { val unapplySeq: NameType = "unapplySeq" val unbox: NameType = "unbox" val universe: NameType = "universe" - val UnliftHelper1: NameType = "UnliftHelper1" - val UnliftHelper2: NameType = "UnliftHelper2" + val UnliftListElementwise: NameType = "UnliftListElementwise" + val UnliftListOfListsElementwise: NameType = "UnliftListOfListsElementwise" val update: NameType = "update" val updateDynamic: NameType = "updateDynamic" val value: NameType = "value" @@ -813,31 +825,33 @@ trait StdNames { def newLazyValSlowComputeName(lzyValName: Name) = lzyValName append LAZY_SLOW_SUFFIX // ASCII names for operators - val ADD = encode("+") - val AND = encode("&") - val ASR = encode(">>") - val CONS = encode("::") - val DIV = encode("/") - val EQ = encode("==") - val EQL = encode("=") - val GE = encode(">=") - val GT = encode(">") - val HASHHASH = encode("##") - val LE = encode("<=") - val LSL = encode("<<") - val LSR = encode(">>>") - val LT = encode("<") - val MINUS = encode("-") - val MOD = encode("%") - val MUL = encode("*") - val NE = encode("!=") - val OR = encode("|") - val PLUS = ADD // technically redundant, but ADD looks funny with MINUS - val PLUSPLUS = encode("++") - val SUB = MINUS // ... as does SUB with PLUS - val XOR = encode("^") - val ZAND = encode("&&") - val ZOR = encode("||") + val ADD = encode("+") + val AND = encode("&") + val ASR = encode(">>") + val CONS = encode("::") + val COLONPLUS = encode(":+") + val DIV = encode("/") + val EQ = encode("==") + val EQL = encode("=") + val GE = encode(">=") + val GT = encode(">") + val HASHHASH = encode("##") + val LE = encode("<=") + val LSL = encode("<<") + val LSR = encode(">>>") + val LT = encode("<") + val MINUS = encode("-") + val MINGT = encode("->") + val MOD = encode("%") + val MUL = encode("*") + val NE = encode("!=") + val OR = encode("|") + val PLUS = ADD // technically redundant, but ADD looks funny with MINUS + val PLUSPLUS = encode("++") + val SUB = MINUS // ... as does SUB with PLUS + val XOR = encode("^") + val ZAND = encode("&&") + val ZOR = encode("||") // unary operators val UNARY_~ = encode("unary_~") diff --git a/src/reflect/scala/reflect/internal/SymbolPairs.scala b/src/reflect/scala/reflect/internal/SymbolPairs.scala index b538648b36..c088e8f57c 100644 --- a/src/reflect/scala/reflect/internal/SymbolPairs.scala +++ b/src/reflect/scala/reflect/internal/SymbolPairs.scala @@ -125,7 +125,7 @@ abstract class SymbolPairs { * considered as a (lo, high) pair? Types always match. Term symbols * match if their member types relative to `self` match. */ - protected def matches(sym1: Symbol, sym2: Symbol): Boolean + protected def matches(lo: Symbol, high: Symbol): Boolean /** The parents and base classes of `base`. Can be refined in subclasses. */ diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index c46a559d6d..802bd18a4e 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -65,9 +65,6 @@ abstract class SymbolTable extends macros.Universe def isPastTyper = false protected def isDeveloper: Boolean = settings.debug - @deprecated("Give us a reason", "2.10.0") - def abort(): Nothing = abort("unknown error") - @deprecated("Use devWarning if this is really a warning; otherwise use log", "2.11.0") def debugwarn(msg: => String): Unit = devWarning(msg) @@ -356,29 +353,33 @@ abstract class SymbolTable extends macros.Universe // Weak references so the garbage collector will take care of // letting us know when a cache is really out of commission. - private val caches = WeakHashSet[Clearable]() + import java.lang.ref.WeakReference + private var caches = List[WeakReference[Clearable]]() def recordCache[T <: Clearable](cache: T): T = { - caches += cache + caches ::= new WeakReference(cache) cache } def clearAll() = { debuglog("Clearing " + caches.size + " caches.") - caches foreach (_.clear) + caches foreach (ref => Option(ref.get).foreach(_.clear)) + caches = caches.filterNot(_.get == null) } def newWeakMap[K, V]() = recordCache(mutable.WeakHashMap[K, V]()) def newMap[K, V]() = recordCache(mutable.HashMap[K, V]()) def newSet[K]() = recordCache(mutable.HashSet[K]()) def newWeakSet[K <: AnyRef]() = recordCache(new WeakHashSet[K]()) + + def newAnyRefMap[K <: AnyRef, V]() = recordCache(mutable.AnyRefMap[K, V]()) def newGeneric[T](f: => T): () => T = { val NoCached: T = null.asInstanceOf[T] var cached: T = NoCached var cachedRunId = NoRunId - caches += new Clearable { + recordCache(new Clearable { def clear(): Unit = cached = NoCached - } + }) () => { if (currentRunId != cachedRunId || cached == NoCached) { cached = f @@ -403,10 +404,9 @@ abstract class SymbolTable extends macros.Universe */ def isCompilerUniverse = false - @deprecated("Use enteringPhase", "2.10.0") + @deprecated("Use enteringPhase", "2.10.0") // Used in SBT 0.12.4 @inline final def atPhase[T](ph: Phase)(op: => T): T = enteringPhase(ph)(op) - @deprecated("Use enteringPhaseNotLaterThan", "2.10.0") - @inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T = enteringPhaseNotLaterThan(target)(op) + /** * Adds the `sm` String interpolator to a [[scala.StringContext]]. diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index e15b33e5d7..81e78d4c5d 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -55,16 +55,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => def newFreeTypeSymbol(name: TypeName, flags: Long = 0L, origin: String): FreeTypeSymbol = new FreeTypeSymbol(name, origin) initFlags flags - /** Determines whether the given information request should trigger the given symbol's completer. - * See comments to `Symbol.needsInitialize` for details. - */ - protected def shouldTriggerCompleter(symbol: Symbol, completer: Type, isFlagRelated: Boolean, mask: Long) = - completer match { - case null => false - case _: FlagAgnosticCompleter => !isFlagRelated - case _ => abort(s"unsupported completer: $completer of class ${if (completer != null) completer.getClass else null} for symbol ${symbol.fullName}") - } - /** The original owner of a class. Used by the backend to generate * EnclosingMethod attributes. */ @@ -106,18 +96,27 @@ trait Symbols extends api.Symbols { self: SymbolTable => } def knownDirectSubclasses = { - if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize + // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method. + if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize children } def selfType = { - if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize + // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method. + if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize typeOfThis } def baseClasses = info.baseClasses def module = sourceModule def thisPrefix: Type = thisType + + // automatic full initialization on access to info from reflection API is a double-edged sword + // on the one hand, it's convenient so that the users don't have to deal with initialization themselves before printing out stuff + // (e.g. printing out a method's signature without fully initializing it would result in <_>'s for parameters + // on the other hand, this strategy can potentially cause unexpected effects due to being inconsistent with compiler's behavior + // so far I think user convenience outweighs the scariness, but we need to keep the tradeoff in mind + // NOTE: if you end up removing the call to fullyInitializeSymbol, consider that it would affect both runtime reflection and macros def typeSignature: Type = { fullyInitializeSymbol(this); info } def typeSignatureIn(site: Type): Type = { fullyInitializeSymbol(this); site memberInfo this } @@ -140,6 +139,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => with Annotatable[Symbol] with Attachable { + // makes sure that all symbols that runtime reflection deals with are synchronized + private def isSynchronized = this.isInstanceOf[scala.reflect.runtime.SynchronizedSymbols#SynchronizedSymbol] + private def isAprioriThreadsafe = isThreadsafe(AllOps) + assert(isCompilerUniverse || isSynchronized || isAprioriThreadsafe, s"unsafe symbol $initName (child of $initOwner) in runtime reflection universe") + type AccessBoundaryType = Symbol type AnnotationType = AnnotationInfo @@ -609,20 +613,55 @@ trait Symbols extends api.Symbols { self: SymbolTable => && isTopLevel && nme.isReplWrapperName(name) ) + + /** In our current architecture, symbols for top-level classes and modules + * are created as dummies. Package symbols just call newClass(name) or newModule(name) and + * consider their job done. + * + * In order for such a dummy to provide meaningful info (e.g. a list of its members), + * it needs to go through unpickling. Unpickling is a process of reading Scala metadata + * from ScalaSignature annotations and assigning it to symbols and types. + * + * A single unpickling session takes a top-level class or module, parses the ScalaSignature annotation + * and then reads metadata for the unpicklee, its companion (if any) and all their members recursively + * (i.e. the pickle not only contains info about directly nested classes/modules, but also about + * classes/modules nested into those and so on). + * + * Unpickling is triggered automatically whenever typeSignature (info in compiler parlance) is called. + * This happens because package symbols assign completer thunks to the dummies they create. + * Therefore metadata loading happens lazily and transparently. + * + * Almost transparently. Unfortunately metadata isn't limited to just signatures (i.e. lists of members). + * It also includes flags (which determine e.g. whether a class is sealed or not), annotations and privateWithin. + * This gives rise to unpleasant effects like in SI-6277, when a flag test called on an uninitialize symbol + * produces incorrect results. + * + * One might think that the solution is simple: automatically call the completer + * whenever one needs flags, annotations and privateWithin - just like it's done for typeSignature. + * Unfortunately, this leads to weird crashes in scalac, and currently we can't attempt + * to fix the core of the compiler risk stability a few weeks before the final release. + * upd. Haha, "a few weeks before the final release". This surely sounds familiar :) + * + * However we do need to fix this for runtime reflection, since this idionsynchrazy is not something + * we'd like to expose to reflection users. Therefore a proposed solution is to check whether we're in a + * runtime reflection universe, and if yes and if we've not yet loaded the requested info, then to commence initialization. + */ final def getFlag(mask: Long): Long = { - if (!isCompilerUniverse && needsInitialize(isFlagRelated = true, mask = mask)) initialize + if (!isCompilerUniverse && !isThreadsafe(purpose = FlagOps(mask))) initialize flags & mask } /** Does symbol have ANY flag in `mask` set? */ final def hasFlag(mask: Long): Boolean = { - if (!isCompilerUniverse && needsInitialize(isFlagRelated = true, mask = mask)) initialize + // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method. + if (!isCompilerUniverse && !isThreadsafe(purpose = FlagOps(mask))) initialize (flags & mask) != 0 } def hasFlag(mask: Int): Boolean = hasFlag(mask.toLong) /** Does symbol have ALL the flags in `mask` set? */ final def hasAllFlags(mask: Long): Boolean = { - if (!isCompilerUniverse && needsInitialize(isFlagRelated = true, mask = mask)) initialize + // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method. + if (!isCompilerUniverse && !isThreadsafe(purpose = FlagOps(mask))) initialize (flags & mask) == mask } @@ -789,7 +828,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * * Stability and volatility are checked separately to allow volatile paths in patterns that amount to equality checks. SI-6815 */ - def isStable = isTerm && !isMutable && !(hasFlag(BYNAMEPARAM)) && (!isMethod || hasStableFlag) + final def isStable = isTerm && !isMutable && !(hasFlag(BYNAMEPARAM)) && (!isMethod || hasStableFlag) final def hasVolatileType = tpe.isVolatile && !hasAnnotation(uncheckedStableClass) /** Does this symbol denote the primary constructor of its enclosing class? */ @@ -943,12 +982,21 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isInitialized: Boolean = validTo != NoPeriod - /** Some completers call sym.setInfo when still in-flight and then proceed with initialization (e.g. see LazyPackageType) - * setInfo sets _validTo to current period, which means that after a call to setInfo isInitialized will start returning true. - * Unfortunately, this doesn't mean that info becomes ready to be used, because subsequent initialization might change the info. - * Therefore we need this method to distinguish between initialized and really initialized symbol states. + /** We consider a symbol to be thread-safe, when multiple concurrent threads can call its methods + * (either directly or indirectly via public reflection or internal compiler infrastructure), + * without any locking and everything works as it should work. + * + * In its basic form, `isThreadsafe` always returns false. Runtime reflection augments reflection infrastructure + * with threadsafety-tracking mechanism implemented in `SynchronizedSymbol` that communicates with underlying completers + * and can sometimes return true if the symbol has been completed to the point of thread safety. + * + * The `purpose` parameter signifies whether we want to just check immutability of certain flags for the given mask. + * This is necessary to enable robust auto-initialization of `Symbol.flags` for runtime reflection, and is also quite handy + * in avoiding unnecessary initializations when requesting for flags that have already been set. */ - final def isFullyInitialized: Boolean = _validTo != NoPeriod && (flags & LOCKED) == 0 + def isThreadsafe(purpose: SymbolOps): Boolean = false + def markFlagsCompleted(mask: Long): this.type = this + def markAllCompleted(): this.type = this /** Can this symbol be loaded by a reflective mirror? * @@ -1102,7 +1150,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def fullNameInternal(separator: Char): Name = ( if (isRoot || isRootPackage || this == NoSymbol) name else if (owner.isEffectiveRoot) name - else ((effectiveOwner.enclClass.fullNameAsName(separator) append separator): Name) append name + else effectiveOwner.enclClass.fullNameAsName(separator) append (separator, name) ) def fullNameAsName(separator: Char): Name = fullNameInternal(separator).dropLocal @@ -1225,7 +1273,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ private[this] var _privateWithin: Symbol = _ def privateWithin = { - if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize + // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method. + if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize _privateWithin } def privateWithin_=(sym: Symbol) { _privateWithin = sym } @@ -1483,46 +1532,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => catch { case _: CyclicReference => debuglog("Hit cycle in maybeInitialize of $this") ; false } } - /** Called when the programmer requests information that might require initialization of the underlying symbol. - * - * `isFlagRelated` and `mask` describe the nature of this information. - * isFlagRelated = true means that the programmer needs particular bits in flags. - * isFlagRelated = false means that the request is unrelated to flags (annotations or privateWithin). - * - * In our current architecture, symbols for top-level classes and modules - * are created as dummies. Package symbols just call newClass(name) or newModule(name) and - * consider their job done. - * - * In order for such a dummy to provide meaningful info (e.g. a list of its members), - * it needs to go through unpickling. Unpickling is a process of reading Scala metadata - * from ScalaSignature annotations and assigning it to symbols and types. - * - * A single unpickling session takes a top-level class or module, parses the ScalaSignature annotation - * and then reads metadata for the unpicklee, its companion (if any) and all their members recursively - * (i.e. the pickle not only contains info about directly nested classes/modules, but also about - * classes/modules nested into those and so on). - * - * Unpickling is triggered automatically whenever typeSignature (info in compiler parlance) is called. - * This happens because package symbols assign completer thunks to the dummies they create. - * Therefore metadata loading happens lazily and transparently. - * - * Almost transparently. Unfortunately metadata isn't limited to just signatures (i.e. lists of members). - * It also includes flags (which determine e.g. whether a class is sealed or not), annotations and privateWithin. - * This gives rise to unpleasant effects like in SI-6277, when a flag test called on an uninitialize symbol - * produces incorrect results. - * - * One might think that the solution is simple: automatically call the completer whenever one needs - * flags, annotations and privateWithin - just like it's done for typeSignature. Unfortunately, this - * leads to weird crashes in scalac, and currently we can't attempt to fix the core of the compiler - * risk stability a few weeks before the final release. - * - * However we do need to fix this for runtime reflection, since it's not something we'd like to - * expose to reflection users. Therefore a proposed solution is to check whether we're in a - * runtime reflection universe and if yes then to commence initialization. - */ - protected def needsInitialize(isFlagRelated: Boolean, mask: Long) = - !isInitialized && (flags & LOCKED) == 0 && shouldTriggerCompleter(this, if (infos ne null) infos.info else null, isFlagRelated, mask) - /** Was symbol's type updated during given phase? */ final def hasTypeAt(pid: Phase#Id): Boolean = { assert(isCompilerUniverse) @@ -1681,7 +1690,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => * the annotations attached to member a definition (class, method, type, field). */ def annotations: List[AnnotationInfo] = { - if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize + // See `getFlag` to learn more about the `isThreadsafe` call in the body of this method. + if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize _annotations } @@ -2037,9 +2047,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => * (or, for traits: `$init`) of `C`. * */ - def logicallyEnclosingMember: Symbol = + final def logicallyEnclosingMember: Symbol = if (isLocalDummy) enclClass.primaryConstructor - else if (isMethod || isClass) this + else if (isMethod || isClass || this == NoSymbol) this + else if (this == NoSymbol) { devWarningDumpStack("NoSymbol.logicallyEnclosingMember", 15); this } else owner.logicallyEnclosingMember /** The top-level class containing this symbol. */ @@ -2419,7 +2430,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => else if (isTrait) ("trait", "trait", "TRT") else if (isClass) ("class", "class", "CLS") else if (isType) ("type", "type", "TPE") - else if (isClassConstructor && isPrimaryConstructor) ("primary constructor", "constructor", "PCTOR") + else if (isClassConstructor && (owner.hasCompleteInfo && isPrimaryConstructor)) ("primary constructor", "constructor", "PCTOR") else if (isClassConstructor) ("constructor", "constructor", "CTOR") else if (isSourceMethod) ("method", "method", "METH") else if (isTerm) ("value", "value", "VAL") @@ -2519,6 +2530,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (settings.debug.value) parentsString(tp.parents) else briefParentsString(tp.parents) ) + def isStructuralThisType = ( + // prevents disasters like SI-8158 + owner.isInitialized && owner.isStructuralRefinement && tp == owner.tpe + ) if (isType) typeParamsString(tp) + ( if (isClass) " extends " + parents else if (isAliasType) " = " + tp.resultType @@ -2529,10 +2544,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => ) else if (isModule) "" // avoid "object X of type X.type" else tp match { - case PolyType(tparams, res) => typeParamsString(tp) + infoString(res) - case NullaryMethodType(res) => infoString(res) - case MethodType(params, res) => valueParamsString(tp) + infoString(res) - case _ => ": " + tp + case PolyType(tparams, res) => typeParamsString(tp) + infoString(res) + case NullaryMethodType(res) => infoString(res) + case MethodType(params, res) => valueParamsString(tp) + infoString(res) + case _ if isStructuralThisType => ": " + owner.name + case _ => ": " + tp } } @@ -3399,8 +3415,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => * @return the new list of info-adjusted symbols */ def deriveSymbols(syms: List[Symbol], symFn: Symbol => Symbol): List[Symbol] = { - val syms1 = syms map symFn - syms1 map (_ substInfo (syms, syms1)) + val syms1 = mapList(syms)(symFn) + mapList(syms1)(_ substInfo (syms, syms1)) } /** Derives a new Type by first deriving new symbols as in deriveSymbols, @@ -3440,9 +3456,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => * @return the newly created, info-adjusted symbols */ def cloneSymbolsAndModify(syms: List[Symbol], infoFn: Type => Type): List[Symbol] = - cloneSymbols(syms) map (_ modifyInfo infoFn) + mapList(cloneSymbols(syms))(_ modifyInfo infoFn) def cloneSymbolsAtOwnerAndModify(syms: List[Symbol], owner: Symbol, infoFn: Type => Type): List[Symbol] = - cloneSymbolsAtOwner(syms, owner) map (_ modifyInfo infoFn) + mapList(cloneSymbolsAtOwner(syms, owner))(_ modifyInfo infoFn) /** Functions which perform the standard clone/substituting on the given symbols and type, * then call the creator function with the new symbols and type as arguments. @@ -3505,6 +3521,17 @@ trait Symbols extends api.Symbols { self: SymbolTable => Statistics.newView("#symbols")(ids) + +// -------------- Completion -------------------------------------------------------- + + // is used to differentiate levels of thread-safety in `Symbol.isThreadsafe` + case class SymbolOps(isFlagRelated: Boolean, mask: Long) + val AllOps = SymbolOps(isFlagRelated = false, mask = 0L) + def FlagOps(mask: Long) = SymbolOps(isFlagRelated = true, mask = mask) + + private def relevantSymbols(syms: Seq[Symbol]) = syms.flatMap(sym => List(sym, sym.moduleClass, sym.sourceModule)) + def markFlagsCompleted(syms: Symbol*)(mask: Long): Unit = relevantSymbols(syms).foreach(_.markFlagsCompleted(mask)) + def markAllCompleted(syms: Symbol*): Unit = relevantSymbols(syms).foreach(_.markAllCompleted) } object SymbolsStats { diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index f6d21ec9bd..29fdba2781 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -49,10 +49,10 @@ abstract class TreeGen extends macros.TreeBuilder { mkMethodCall(Select(receiver, method), targs, args) def mkMethodCall(target: Tree, targs: List[Type], args: List[Tree]): Tree = - Apply(mkTypeApply(target, targs map TypeTree), args) + Apply(mkTypeApply(target, mapList(targs)(TypeTree)), args) def mkNullaryCall(method: Symbol, targs: List[Type]): Tree = - mkTypeApply(mkAttributedRef(method), targs map TypeTree) + mkTypeApply(mkAttributedRef(method), mapList(targs)(TypeTree)) /** Builds a reference to value whose type is given stable prefix. * The type must be suitable for this. For example, it @@ -95,7 +95,7 @@ abstract class TreeGen extends macros.TreeBuilder { case ConstantType(value) => Literal(value) setType tpe - case AnnotatedType(_, atp, _) => + case AnnotatedType(_, atp) => mkAttributedQualifier(atp) case RefinedType(parents, _) => @@ -191,11 +191,7 @@ abstract class TreeGen extends macros.TreeBuilder { ) val pkgQualifier = if (needsPackageQualifier) { - // The owner of a symbol which requires package qualification may be the - // package object iself, but it also could be any superclass of the package - // object. In the latter case, we must go through the qualifier's info - // to obtain the right symbol. - val packageObject = if (sym.owner.isModuleClass) sym.owner.sourceModule else qual.tpe member nme.PACKAGE + val packageObject = rootMirror.getPackageObjectWithMember(qual.tpe, sym) Select(qual, nme.PACKAGE) setSymbol packageObject setType singleType(qual.tpe, packageObject) } else qual @@ -285,7 +281,7 @@ abstract class TreeGen extends macros.TreeBuilder { case tree :: Nil if flattenUnary => tree case _ => - Apply(scalaDot(TupleClass(elems.length).companionModule.name), elems) + Apply(scalaDot(TupleClass(elems.length).name.toTermName), elems) } def mkTupleType(elems: List[Tree], flattenUnary: Boolean = true): Tree = elems match { @@ -346,7 +342,7 @@ abstract class TreeGen extends macros.TreeBuilder { } param } - + val (edefs, rest) = body span treeInfo.isEarlyDef val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef val gvdefs = evdefs map { @@ -385,11 +381,11 @@ abstract class TreeGen extends macros.TreeBuilder { } constr foreach (ensureNonOverlapping(_, parents ::: gvdefs, focus = false)) // Field definitions for the class - remove defaults. - + val fieldDefs = vparamss.flatten map (vd => { val field = copyValDef(vd)(mods = vd.mods &~ DEFAULTPARAM, rhs = EmptyTree) // Prevent overlapping of `field` end's position with default argument's start position. - // This is needed for `Positions.Locator(pos).traverse` to return the correct tree when + // This is needed for `Positions.Locator(pos).traverse` to return the correct tree when // the `pos` is a point position with all its values equal to `vd.rhs.pos.start`. if(field.pos.isRange && vd.rhs.pos.isRange) field.pos = field.pos.withEnd(vd.rhs.pos.start - 1) field @@ -448,13 +444,23 @@ abstract class TreeGen extends macros.TreeBuilder { def mkFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = AppliedTypeTree(rootScalaDot(newTypeName("Function" + argtpes.length)), argtpes ::: List(restpe)) + /** Create a literal unit tree that is inserted by the compiler but not + * written by end user. It's important to distinguish the two so that + * quasiquotes can strip synthetic ones away. + */ + def mkSyntheticUnit() = Literal(Constant(())).updateAttachment(SyntheticUnitAttachment) + /** Create block of statements `stats` */ def mkBlock(stats: List[Tree]): Tree = if (stats.isEmpty) Literal(Constant(())) - else if (!stats.last.isTerm) Block(stats, Literal(Constant(()))) + else if (!stats.last.isTerm) Block(stats, mkSyntheticUnit()) else if (stats.length == 1) stats.head else Block(stats.init, stats.last) + /** Create a block that wraps multiple statements but don't + * do any wrapping if there is just one statement. Used by + * quasiquotes, macro c.parse api and toolbox. + */ def mkTreeOrBlock(stats: List[Tree]) = stats match { case Nil => EmptyTree case head :: Nil => head diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 8fdf4dc27a..8cad2497c1 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -284,17 +284,17 @@ abstract class TreeInfo { /** Is tree a self constructor call this(...)? I.e. a call to a constructor of the * same object? */ - def isSelfConstrCall(tree: Tree): Boolean = tree match { - case Applied(Ident(nme.CONSTRUCTOR), _, _) => true - case Applied(Select(This(_), nme.CONSTRUCTOR), _, _) => true - case _ => false + def isSelfConstrCall(tree: Tree): Boolean = dissectApplied(tree).core match { + case Ident(nme.CONSTRUCTOR) => true + case Select(This(_), nme.CONSTRUCTOR) => true + case _ => false } /** Is tree a super constructor call? */ - def isSuperConstrCall(tree: Tree): Boolean = tree match { - case Applied(Select(Super(_, _), nme.CONSTRUCTOR), _, _) => true - case _ => false + def isSuperConstrCall(tree: Tree): Boolean = dissectApplied(tree).core match { + case Select(Super(_, _), nme.CONSTRUCTOR) => true + case _ => false } /** @@ -612,8 +612,8 @@ abstract class TreeInfo { def effectivePatternArity(args: List[Tree]): Int = flattenedPatternArgs(args).length def flattenedPatternArgs(args: List[Tree]): List[Tree] = args map unbind match { - case Apply(fun, xs) :: Nil if isTupleSymbol(fun.symbol) => xs - case xs => xs + case build.SyntacticTuple(xs) :: Nil => xs + case xs => xs } // used in the symbols for labeldefs and valdefs emitted by the pattern matcher @@ -735,6 +735,17 @@ abstract class TreeInfo { unapply(dissectApplied(tree)) } + /** Does list of trees start with a definition of + * a class of module with given name (ignoring imports) + */ + def firstDefinesClassOrObject(trees: List[Tree], name: Name): Boolean = trees match { + case Import(_, _) :: xs => firstDefinesClassOrObject(xs, name) + case Annotated(_, tree1) :: _ => firstDefinesClassOrObject(List(tree1), name) + case ModuleDef(_, `name`, _) :: _ => true + case ClassDef(_, `name`, _, _) :: _ => true + case _ => false + } + /** Locates the synthetic Apply node corresponding to an extractor's call to * unapply (unwrapping nested Applies) and returns the fun part of that Apply. */ @@ -750,8 +761,7 @@ abstract class TreeInfo { } /** Is this file the body of a compilation unit which should not - * have Predef imported? This is the case iff the first import in the - * unit explicitly refers to Predef. + * have Predef imported? */ def noPredefImportForUnit(body: Tree) = { // Top-level definition whose leading imports include Predef. @@ -760,7 +770,13 @@ abstract class TreeInfo { case Import(expr, _) => isReferenceToPredef(expr) case _ => false } - isLeadingPredefImport(body) + // Compilation unit is class or object 'name' in package 'scala' + def isUnitInScala(tree: Tree, name: Name) = tree match { + case PackageDef(Ident(nme.scala_), defs) => firstDefinesClassOrObject(defs, name) + case _ => false + } + + isUnitInScala(body, nme.Predef) || isLeadingPredefImport(body) } def isAbsTypeDef(tree: Tree) = tree match { @@ -848,8 +864,10 @@ abstract class TreeInfo { case _ => false }) - def isMacroApplication(tree: Tree): Boolean = - !tree.isDef && tree.symbol != null && tree.symbol.isTermMacro && !tree.symbol.isErroneous + def isMacroApplication(tree: Tree): Boolean = !tree.isDef && { + val sym = tree.symbol + sym != null && sym.isTermMacro && !sym.isErroneous + } def isMacroApplicationOrBlock(tree: Tree): Boolean = tree match { case Block(_, expr) => isMacroApplicationOrBlock(expr) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 437b962abf..6010d4eb12 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -8,7 +8,6 @@ package reflect package internal import scala.collection.{ mutable, immutable, generic } -import generic.Clearable import scala.ref.WeakReference import mutable.ListBuffer import Flags._ @@ -44,7 +43,7 @@ import TypeConstants._ // parent1 with ... with parentn { defs } case ExistentialType(tparams, result) => // result forSome { tparams } - case AnnotatedType(annots, tp, selfsym) => + case AnnotatedType(annots, tp) => // tp @annots // the following are non-value types; you cannot write them down in Scala source. @@ -83,6 +82,7 @@ trait Types with tpe.GlbLubs with tpe.TypeMaps with tpe.TypeConstraints + with tpe.FindMembers with util.Collections { self: SymbolTable => import definitions._ @@ -244,18 +244,6 @@ trait Types } } - /** Same as a call to narrow unless existentials are visible - * after widening the type. In that case, narrow from the widened - * type instead of the proxy. This gives buried existentials a - * chance to make peace with the other types. See SI-5330. - */ - private def narrowForFindMember(tp: Type): Type = { - val w = tp.widen - // Only narrow on widened type when we have to -- narrow is expensive unless the target is a singleton type. - if ((tp ne w) && containsExistential(w)) w.narrow - else tp.narrow - } - /** The base class for all types */ abstract class Type extends TypeApiImpl with Annotatable[Type] { /** Types for which asSeenFrom always is the identity, no matter what @@ -895,12 +883,12 @@ trait Types if (sym == btssym) return mid else if (sym isLess btssym) hi = mid - 1 else if (btssym isLess sym) lo = mid + 1 - else abort() + else abort("sym is neither `sym == btssym`, `sym isLess btssym` nor `btssym isLess sym`") } -1 } - /** If this is a poly- or methodtype, a copy with cloned type / value parameters + /** If this is a ExistentialType, PolyType or MethodType, a copy with cloned type / value parameters * owned by `owner`. Identity for all other types. */ def cloneInfo(owner: Symbol) = this @@ -990,64 +978,7 @@ trait Types * */ def findMembers(excludedFlags: Long, requiredFlags: Long): Scope = { - def findMembersInternal: Scope = { - var members: Scope = null - if (Statistics.canEnable) Statistics.incCounter(findMembersCount) - val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMembersNanos) else null - - //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG - var required = requiredFlags - var excluded = excludedFlags | DEFERRED - var retryForDeferred = true - var self: Type = null - while (retryForDeferred) { - retryForDeferred = false - val bcs0 = baseClasses - var bcs = bcs0 - while (!bcs.isEmpty) { - val decls = bcs.head.info.decls - var entry = decls.elems - while (entry ne null) { - val sym = entry.sym - val flags = sym.flags - if ((flags & required) == required) { - val excl = flags & excluded - if (excl == 0L && - (// omit PRIVATE LOCALS unless selector class is contained in class owning the def. - (bcs eq bcs0) || - (flags & PrivateLocal) != PrivateLocal || - (bcs0.head.hasTransOwner(bcs.head)))) { - if (members eq null) members = newFindMemberScope - var others: ScopeEntry = members.lookupEntry(sym.name) - var symtpe: Type = null - while ((others ne null) && { - val other = others.sym - (other ne sym) && - ((other.owner eq sym.owner) || - (flags & PRIVATE) != 0 || { - if (self eq null) self = narrowForFindMember(this) - if (symtpe eq null) symtpe = self.memberType(sym) - !(self.memberType(other) matches symtpe) - })}) { - others = members lookupNextEntry others - } - if (others eq null) members enter sym - } else if (excl == DEFERRED) { - retryForDeferred = (excludedFlags & DEFERRED) == 0 - } - } - entry = entry.next - } // while (entry ne null) - // excluded = excluded | LOCAL - bcs = bcs.tail - } // while (!bcs.isEmpty) - required |= DEFERRED - excluded &= ~(DEFERRED.toLong) - } // while (retryForDeferred) - if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) - if (members eq null) EmptyScope else members - } - + def findMembersInternal = new FindMembers(this, excludedFlags, requiredFlags).apply() if (this.isGround) findMembersInternal else suspendingTypeVars(typeVarsInType(this))(findMembersInternal) } @@ -1056,110 +987,13 @@ trait Types * Find member(s) in this type. If several members matching criteria are found, they are * returned in an OverloadedSymbol * - * @param name The member's name, where nme.ANYNAME means `unspecified` + * @param name The member's name * @param excludedFlags Returned members do not have these flags * @param requiredFlags Returned members do have these flags * @param stableOnly If set, return only members that are types or stable values */ - //TODO: use narrow only for modules? (correct? efficiency gain?) def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean): Symbol = { - def findMemberInternal: Symbol = { - var member: Symbol = NoSymbol - var members: List[Symbol] = null - var lastM: ::[Symbol] = null - if (Statistics.canEnable) Statistics.incCounter(findMemberCount) - val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMemberNanos) else null - - //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG - var membertpe: Type = null - var required = requiredFlags - var excluded = excludedFlags | DEFERRED - var continue = true - var self: Type = null - - while (continue) { - continue = false - val bcs0 = baseClasses - var bcs = bcs0 - // omit PRIVATE LOCALS unless selector class is contained in class owning the def. - def admitPrivateLocal(owner: Symbol): Boolean = { - val selectorClass = this match { - case tt: ThisType => tt.sym // SI-7507 the first base class is not necessarily the selector class. - case _ => bcs0.head - } - selectorClass.hasTransOwner(owner) - } - while (!bcs.isEmpty) { - val decls = bcs.head.info.decls - var entry = decls.lookupEntry(name) - while (entry ne null) { - val sym = entry.sym - val flags = sym.flags - if ((flags & required) == required) { - val excl = flags & excluded - if (excl == 0L && - ( - (bcs eq bcs0) || - (flags & PrivateLocal) != PrivateLocal || - admitPrivateLocal(bcs.head))) { - if (name.isTypeName || (stableOnly && sym.isStable && !sym.hasVolatileType)) { - if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) - return sym - } else if (member eq NoSymbol) { - member = sym - } else if (members eq null) { - if ((member ne sym) && - ((member.owner eq sym.owner) || - (flags & PRIVATE) != 0 || { - if (self eq null) self = narrowForFindMember(this) - if (membertpe eq null) membertpe = self.memberType(member) - !(membertpe matches self.memberType(sym)) - })) { - lastM = new ::(sym, null) - members = member :: lastM - } - } else { - var others: List[Symbol] = members - var symtpe: Type = null - while ((others ne null) && { - val other = others.head - (other ne sym) && - ((other.owner eq sym.owner) || - (flags & PRIVATE) != 0 || { - if (self eq null) self = narrowForFindMember(this) - if (symtpe eq null) symtpe = self.memberType(sym) - !(self.memberType(other) matches symtpe) - })}) { - others = others.tail - } - if (others eq null) { - val lastM1 = new ::(sym, null) - lastM.tl = lastM1 - lastM = lastM1 - } - } - } else if (excl == DEFERRED) { - continue = true - } - } - entry = decls lookupNextEntry entry - } // while (entry ne null) - // excluded = excluded | LOCAL - bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail - } // while (!bcs.isEmpty) - required |= DEFERRED - excluded &= ~(DEFERRED.toLong) - } // while (continue) - if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) - if (members eq null) { - if (member == NoSymbol) if (Statistics.canEnable) Statistics.incCounter(noMemberCount) - member - } else { - if (Statistics.canEnable) Statistics.incCounter(multMemberCount) - lastM.tl = Nil - baseClasses.head.newOverloaded(this, members) - } - } + def findMemberInternal = new FindMember(this, name, excludedFlags, requiredFlags, stableOnly).apply() if (this.isGround) findMemberInternal else suspendingTypeVars(typeVarsInType(this))(findMemberInternal) @@ -1191,13 +1025,6 @@ trait Types def setAnnotations(annots: List[AnnotationInfo]): Type = annotatedType(annots, this) def withAnnotations(annots: List[AnnotationInfo]): Type = annotatedType(annots, this) - /** Set the self symbol of an annotated type, or do nothing - * otherwise. */ - def withSelfsym(sym: Symbol) = this - - /** The selfsym of an annotated type, or NoSymbol of anything else */ - def selfsym: Symbol = NoSymbol - /** The kind of this type; used for debugging */ def kind: String = "unknown type of class "+getClass() } @@ -1457,7 +1284,7 @@ trait Types override def safeToString = scalaNotation(_.toString) - /** Bounds notation used in Scala sytanx. + /** Bounds notation used in Scala syntax. * For example +This <: scala.collection.generic.Sorted[K,This]. */ private[internal] def scalaNotation(typeString: Type => String): String = { @@ -1977,15 +1804,15 @@ trait Types def apply(value: Constant) = unique(new UniqueConstantType(value)) } - private var _volatileRecursions: Int = 0 - def volatileRecursions = _volatileRecursions - def volatileRecursions_=(value: Int) = _volatileRecursions = value - - private val _pendingVolatiles = new mutable.HashSet[Symbol] - def pendingVolatiles = _pendingVolatiles + /* Syncnote: The `volatile` var and `pendingVolatiles` mutable set need not be protected + * with synchronized, because they are accessed only from isVolatile, which is called only from + * Typer. + */ + private var volatileRecursions: Int = 0 + private val pendingVolatiles = new mutable.HashSet[Symbol] class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) { - require(args0.nonEmpty, this) + require(args0 ne Nil, this) /** No unapplied type params size it has (should have) equally as many args. */ override def isHigherKinded = false @@ -1996,10 +1823,39 @@ trait Types // too little information is known to determine its kind, and // it later turns out not to have kind *. See SI-4070. Only // logging it for now. - if (sym.typeParams.size != args.size) + val tparams = sym.typeParams + if (tparams.size != args.size) devWarning(s"$this.transform($tp), but tparams.isEmpty and args=$args") - - asSeenFromOwner(tp).instantiateTypeParams(sym.typeParams, args) + def asSeenFromInstantiated(tp: Type) = + asSeenFromOwner(tp).instantiateTypeParams(tparams, args) + // If we're called with a poly type, and we were to run the `asSeenFrom`, over the entire + // type, we can end up with new symbols for the type parameters (clones from TypeMap). + // The subsequent substitution of type arguments would fail. This problem showed up during + // the fix for SI-8046, however the solution taken there wasn't quite right, and led to + // SI-8170. + // + // Now, we detect the PolyType before both the ASF *and* the substitution, and just operate + // on the result type. + // + // TODO: Revisit this and explore the questions raised: + // + // AM: I like this better than the old code, but is there any way the tparams would need the ASF treatment as well? + // JZ: I think its largely irrelevant, as they are no longer referred to in the result type. + // In fact, you can get away with returning a type of kind * here and the sky doesn't fall: + // `case PolyType(`tparams`, result) => asSeenFromInstantiated(result)` + // But I thought it was better to retain the kind. + // AM: I've been experimenting with apply-type-args-then-ASF, but running into cycles. + // In general, it seems iffy the tparams can never occur in the result + // then we might as well represent the type as a no-arg typeref. + // AM: I've also been trying to track down uses of transform (pretty generic name for something that + // does not seem that widely applicable). + // It's kind of a helper for computing baseType (since it tries to propagate our type args to some + // other type, which has to be related to this type for that to make sense). + // + tp match { + case PolyType(`tparams`, result) => PolyType(tparams, asSeenFromInstantiated(result)) + case _ => asSeenFromInstantiated(tp) + } } // note: does not go through typeRef. There's no need to because @@ -2041,7 +1897,7 @@ trait Types // to a java or scala symbol, but it does matter whether it occurs in java or scala code. // TypeRefs w/o type params that occur in java signatures/code are considered raw types, and are // represented as existential types. - override def isHigherKinded = typeParams.nonEmpty + override def isHigherKinded = (typeParams ne Nil) override def typeParams = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams private def isRaw = !phase.erasedTypes && isRawIfWithoutArgs(sym) @@ -2161,22 +2017,51 @@ trait Types // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) override def betaReduce = transform(sym.info.resultType) - // #3731: return sym1 for which holds: pre bound sym.name to sym and - // pre1 now binds sym.name to sym1, conceptually exactly the same - // symbol as sym. The selection of sym on pre must be updated to the - // selection of sym1 on pre1, since sym's info was probably updated - // by the TypeMap to yield a new symbol, sym1 with transformed info. - // @returns sym1 - override def coevolveSym(pre1: Type): Symbol = - if (pre eq pre1) sym else (pre, pre1) match { - // don't look at parents -- it would be an error to override alias types anyway - case (RefinedType(_, _), RefinedType(_, decls1)) => decls1 lookup sym.name - // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre? - case _ => sym - } + /** SI-3731, SI-8177: when prefix is changed to `newPre`, maintain consistency of prefix and sym + * (where the symbol refers to a declaration "embedded" in the prefix). + * + * @returns newSym so that `newPre` binds `sym.name` to `newSym`, + * to remain consistent with `pre` previously binding `sym.name` to `sym`. + * + * `newSym` and `sym` are conceptually the same symbols, but some change to our `prefix` + * got them out of whack. (Usually triggered by substitution or `asSeenFrom`.) + * The only kind of "binds" we consider is where `prefix` (or its underlying type) + * is a refined type that declares `sym` (since the old prefix was discarded, + * the old symbol is now stale and we should update it, like in `def rebind`, + * except this is not for overriding symbols -- a vertical move -- but a "lateral" change.) + * + * The reason for this hack is that substitution and asSeenFrom clone RefinedTypes and + * their members, without updating the potential references to those members -- here, we aim to patch + * this up, so that: when changing a TypeRef(pre, sym, args) to a TypeRef(pre', sym', args'), and pre + * embeds a symbol sym (pre is a RefinedType(_, Scope(..., sym,...)) or a SingleType with such an + * underlying type), make sure that we update sym' to compensate for the change of pre -> pre' (which may + * have created a new symbol for the one the original sym referred to) + */ + override def coevolveSym(newPre: Type): Symbol = + if ((pre ne newPre) && embeddedSymbol(pre, sym.name) == sym) { + val newSym = embeddedSymbol(newPre, sym.name) + debuglog(s"co-evolve: ${pre} -> ${newPre}, $sym : ${sym.info} -> $newSym : ${newSym.info}") + // To deal with erroneous `preNew`, fallback via `orElse sym`, in case `preNew` does not have a decl named `sym.name`. + newSym orElse sym + } else sym + override def kind = "AliasTypeRef" } + // Return the symbol named `name` that's "embedded" in tp + // This is the case if `tp` is a `T{...; type/val $name ; ...}`, + // or a singleton type with such an underlying type. + private def embeddedSymbol(tp: Type, name: Name): Symbol = + // normalize to flatten nested RefinedTypes + // don't check whether tp is a RefinedType -- it may be a ThisType of one, for example + // TODO: check the resulting symbol is owned by the refinement class? likely an invariant... + if (tp.typeSymbol.isRefinementClass) tp.normalize.decls lookup name + else { + debuglog(s"no embedded symbol $name found in ${showRaw(tp)} --> ${tp.normalize.decls lookup name}") + NoSymbol + } + + trait AbstractTypeRef extends NonClassTypeRef { require(sym.isAbstractType, sym) @@ -2231,7 +2116,7 @@ trait Types //OPT specialize hashCode override final def computeHashCode = { import scala.util.hashing.MurmurHash3._ - val hasArgs = args.nonEmpty + val hasArgs = args ne Nil var h = productSeed h = mix(h, pre.hashCode) h = mix(h, sym.hashCode) @@ -2313,7 +2198,14 @@ trait Types } thisInfo.decls } - protected[Types] def baseTypeSeqImpl: BaseTypeSeq = sym.info.baseTypeSeq map transform + protected[Types] def baseTypeSeqImpl: BaseTypeSeq = + if (sym.info.baseTypeSeq exists (_.typeSymbolDirect.isAbstractType)) + // SI-8046 base type sequence might have more elements in a subclass, we can't map it element wise. + transform(sym.info).baseTypeSeq + else + // Optimization: no abstract types, we can compute the BTS of this TypeRef as an element-wise map + // of the BTS of the referenced symbol. + sym.info.baseTypeSeq map transform override def baseTypeSeq: BaseTypeSeq = { val cache = baseTypeSeqCache @@ -2415,7 +2307,7 @@ trait Types object TypeRef extends TypeRefExtractor { def apply(pre: Type, sym: Symbol, args: List[Type]): Type = unique({ - if (args.nonEmpty) { + if (args ne Nil) { if (sym.isAliasType) new AliasArgsTypeRef(pre, sym, args) else if (sym.isAbstractType) new AbstractArgsTypeRef(pre, sym, args) else new ClassArgsTypeRef(pre, sym, args) @@ -2488,7 +2380,7 @@ trait Types true } - def isImplicit = params.nonEmpty && params.head.isImplicit + def isImplicit = (params ne Nil) && params.head.isImplicit def isJava = false // can we do something like for implicits? I.e. do Java methods without parameters need to be recognized? //assert(paramTypes forall (pt => !pt.typeSymbol.isImplClass))//DEBUG @@ -2496,7 +2388,7 @@ trait Types override def paramss: List[List[Symbol]] = params :: resultType.paramss - override def paramTypes = params map (_.tpe) + override def paramTypes = mapList(params)(symTpe) // OPT use mapList rather than .map override def boundSyms = resultType.boundSyms ++ params @@ -2659,8 +2551,57 @@ trait Types override def baseTypeSeq = underlying.baseTypeSeq map maybeRewrap override def isHigherKinded = false - override def skolemizeExistential(owner: Symbol, origin: AnyRef) = + /** [SI-6169, SI-8197 -- companion to SI-1786] + * + * Approximation to improve the bounds of a Java-defined existential type, + * based on the bounds of the type parameters of the quantified type + * In Scala syntax, given a java-defined class C[T <: String], the existential type C[_] + * is improved to C[_ <: String] before skolemization, which captures (get it?) what Java does: + * enter the type paramers' bounds into the context when checking subtyping/type equality of existential types + * + * (Also tried doing this once during class file parsing or when creating the existential type, + * but that causes cyclic errors because it happens too early.) + * + * TODO: figure out how to do this earlier without running into cycles, so this can subsume the fix for SI-1786 + */ + private def sharpenQuantifierBounds(): Unit = { + /* Check that we're looking at rawToExistential's handiwork + * (`existentialAbstraction(eparams, typeRef(apply(pre), sym, eparams map (_.tpe)))`). + * We can't do this sharpening there because we'll run into cycles. + */ + def rawToExistentialCreatedMe = (quantified corresponds underlying.typeArgs){ (q, a) => q.tpe =:= a } + + if (underlying.typeSymbol.isJavaDefined && rawToExistentialCreatedMe) { + val tpars = underlying.typeSymbol.initialize.typeParams // TODO: is initialize needed? + debuglog(s"sharpen bounds: $this | ${underlying.typeArgs.map(_.typeSymbol)} <-- ${tpars.map(_.info)}") + + foreach2(quantified, tpars) { (quant, tparam) => + // TODO: check `tparam.info.substSym(tpars, quantified) <:< quant.info` instead (for some weird reason not working for test/t6169/ExistF) + // for now, crude approximation for the common case + if (quant.info.bounds.isEmptyBounds && !tparam.info.bounds.isEmptyBounds) { + // avoid creating cycles [pos/t2940] that consist of an existential quantifier's + // bounded by an existential type that unhygienically has that quantifier as its own quantifier + // (TODO: clone latter existential with fresh quantifiers -- not covering this case for now) + if ((existentialsInType(tparam.info) intersect quantified).isEmpty) + quant setInfo tparam.info.substSym(tpars, quantified) + } + } + } + + _sharpenQuantifierBounds = false + } + private[this] var _sharpenQuantifierBounds = true + + override def skolemizeExistential(owner: Symbol, origin: AnyRef) = { + // do this here because it's quite close to what Java does: + // when checking subtyping/type equality, enter constraints + // derived from the existentially quantified type into the typing environment + // (aka \Gamma, which tracks types for variables and constraints/kinds for types) + // as a nice bonus, delaying this until we need it avoids cyclic errors + if (_sharpenQuantifierBounds) sharpenQuantifierBounds + deriveType(quantified, tparam => (owner orElse tparam.owner).newExistentialSkolem(tparam, origin))(underlying) + } private def wildcardArgsString(qset: Set[Symbol], args: List[Type]): List[String] = args map { case TypeRef(_, sym, _) if (qset contains sym) => @@ -2751,6 +2692,10 @@ trait Types case _ => OverloadedType(pre, alternatives) } + case class ImportType(expr: Tree) extends Type { + override def safeToString = "ImportType("+expr+")" + } + /** A class remembering a type instantiation for some a set of overloaded * polymorphic symbols. * Not used after phase `typer`. @@ -2877,6 +2822,8 @@ trait Types override def params: List[Symbol] = zippedArgs map (_._1) override def typeArgs: List[Type] = zippedArgs map (_._2) + + override def safeToString: String = super.safeToString + typeArgs.map(_.safeToString).mkString("[", ", ", "]") } trait UntouchableTypeVar extends TypeVar { @@ -2997,15 +2944,19 @@ trait Types def addLoBound(tp: Type, isNumericBound: Boolean = false) { assert(tp != this, tp) // implies there is a cycle somewhere (?) //println("addLoBound: "+(safeToString, debugString(tp))) //DEBUG - undoLog record this - constr.addLoBound(tp, isNumericBound) + if (!sharesConstraints(tp)) { + undoLog record this + constr.addLoBound(tp, isNumericBound) + } } def addHiBound(tp: Type, isNumericBound: Boolean = false) { // assert(tp != this) //println("addHiBound: "+(safeToString, debugString(tp))) //DEBUG - undoLog record this - constr.addHiBound(tp, isNumericBound) + if (!sharesConstraints(tp)) { + undoLog record this + constr.addHiBound(tp, isNumericBound) + } } // </region> @@ -3017,6 +2968,16 @@ trait Types case ConstantTrue => true case tv: TypeVar => tv.suspended } + + /** `AppliedTypeVar`s share the same `TypeConstraint` with the `HKTypeVar` that it was spawned from. + * A type inference session can also have more than one ATV. + * If we don't detect that, we end up with "cyclic constraint" when we try to instantiate type parameters + * after solving in, pos/t8237 + */ + protected final def sharesConstraints(other: Type): Boolean = other match { + case other: TypeVar => constr == other.constr // SI-8237 avoid cycles. Details in pos/t8237.scala + case _ => false + } private[Types] def suspended_=(b: Boolean): Unit = _suspended = if (b) ConstantTrue else ConstantFalse // SI-7785 Link the suspended attribute of a TypeVar created in, say, a TypeMap (e.g. AsSeenFrom) to its originator private[Types] def linkSuspended(origin: TypeVar): Unit = _suspended = origin @@ -3239,13 +3200,9 @@ trait Types * * @param annotations the list of annotations on the type * @param underlying the type without the annotation - * @param selfsym a "self" symbol with type `underlying`; - * only available if -Yself-in-annots is turned on. Can be `NoSymbol` - * if it is not used. */ case class AnnotatedType(override val annotations: List[AnnotationInfo], - override val underlying: Type, - override val selfsym: Symbol) + override val underlying: Type) extends RewrappingTypeProxy with AnnotatedTypeApi { assert(!annotations.isEmpty, "" + underlying) @@ -3278,9 +3235,6 @@ trait Types */ override def withoutAnnotations = underlying.withoutAnnotations - /** Set the self symbol */ - override def withSelfsym(sym: Symbol) = copy(selfsym = sym) - /** Drop the annotations on the bounds, unless the low and high * bounds are exactly tp. */ @@ -3295,7 +3249,7 @@ trait Types formals, actuals), info.args, info.assocs).setPos(info.pos)) val underlying1 = underlying.instantiateTypeParams(formals, actuals) if ((annotations1 eq annotations) && (underlying1 eq underlying)) this - else AnnotatedType(annotations1, underlying1, selfsym) + else AnnotatedType(annotations1, underlying1) } /** Return the base type sequence of tp, dropping the annotations, unless the base type sequence of tp @@ -3314,9 +3268,9 @@ trait Types /** Creator for AnnotatedTypes. It returns the underlying type if annotations.isEmpty * rather than walking into the assertion. */ - def annotatedType(annots: List[AnnotationInfo], underlying: Type, selfsym: Symbol = NoSymbol): Type = + def annotatedType(annots: List[AnnotationInfo], underlying: Type): Type = if (annots.isEmpty) underlying - else AnnotatedType(annots, underlying, selfsym) + else AnnotatedType(annots, underlying) object AnnotatedType extends AnnotatedTypeExtractor @@ -3569,7 +3523,7 @@ trait Types case RefinedType(parents, decls) => RefinedType(parents map (appliedType(_, args)), decls) // @PP: Can this be right? case TypeBounds(lo, hi) => TypeBounds(appliedType(lo, args), appliedType(hi, args)) // @PP: Can this be right? case tv@TypeVar(_, _) => tv.applyArgs(args) - case AnnotatedType(annots, underlying, self) => AnnotatedType(annots, appliedType(underlying, args), self) + case AnnotatedType(annots, underlying) => AnnotatedType(annots, appliedType(underlying, args)) case ErrorType | WildcardType => tycon case _ => abort(debugString(tycon)) } @@ -3605,7 +3559,7 @@ trait Types } def genPolyType(params: List[Symbol], tpe: Type): Type = GenPolyType(params, tpe) - @deprecated("use genPolyType(...) instead", "2.10.0") + @deprecated("use genPolyType(...) instead", "2.10.0") // Used in reflection API def polyType(params: List[Symbol], tpe: Type): Type = GenPolyType(params, tpe) /** A creator for anonymous type functions, where the symbol for the type function still needs to be created. @@ -3664,7 +3618,11 @@ trait Types if (Statistics.canEnable) Statistics.incCounter(rawTypeCount) if (uniqueRunId != currentRunId) { uniques = util.WeakHashSet[Type](initialUniquesCapacity) - perRunCaches.recordCache(uniques) + // JZ: We used to register this as a perRunCache so it would be cleared eagerly at + // the end of the compilation run. But, that facility didn't actually clear this map (SI-8129)! + // When i fixed that bug, run/tpeCache-tyconCache.scala started failing. Why was that? + // I've removed the registration for now. I don't think its particularly harmful anymore + // as a) this is now a weak set, and b) it is discarded completely before the next run. uniqueRunId = currentRunId } (uniques findEntryOrUpdate tp).asInstanceOf[T] @@ -3674,7 +3632,7 @@ trait Types class TypeUnwrapper(poly: Boolean, existential: Boolean, annotated: Boolean, nullary: Boolean) extends (Type => Type) { def apply(tp: Type): Type = tp match { - case AnnotatedType(_, underlying, _) if annotated => apply(underlying) + case AnnotatedType(_, underlying) if annotated => apply(underlying) case ExistentialType(_, underlying) if existential => apply(underlying) case PolyType(_, underlying) if poly => apply(underlying) case NullaryMethodType(underlying) if nullary => apply(underlying) @@ -3717,7 +3675,7 @@ trait Types def transparentShallowTransform(container: Symbol, tp: Type)(f: Type => Type): Type = { def loop(tp: Type): Type = tp match { - case tp @ AnnotatedType(_, underlying, _) => tp.copy(underlying = loop(underlying)) + case tp @ AnnotatedType(_, underlying) => tp.copy(underlying = loop(underlying)) case tp @ ExistentialType(_, underlying) => tp.copy(underlying = loop(underlying)) case tp @ PolyType(_, resultType) => tp.copy(resultType = loop(resultType)) case tp @ NullaryMethodType(resultType) => tp.copy(resultType = loop(resultType)) @@ -4078,7 +4036,7 @@ trait Types private def isValueElseNonValue(tp: Type): Boolean = tp match { case tp if isAlwaysValueType(tp) => true case tp if isAlwaysNonValueType(tp) => false - case AnnotatedType(_, underlying, _) => isValueElseNonValue(underlying) + case AnnotatedType(_, underlying) => isValueElseNonValue(underlying) case SingleType(_, sym) => sym.isValue // excludes packages and statics case TypeRef(_, _, _) if tp.isHigherKinded => false // excludes type constructors case ThisType(sym) => !sym.isPackageClass // excludes packages @@ -4122,7 +4080,7 @@ trait Types && (variance.isCovariant || isSubType(t2, t1, depth)) ) - corresponds3(tps1, tps2, tparams map (_.variance))(isSubArg) + corresponds3(tps1, tps2, mapList(tparams)(_.variance))(isSubArg) } def specializesSym(tp: Type, sym: Symbol, depth: Depth): Boolean = { @@ -4306,7 +4264,7 @@ trait Types } def instantiatedBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = - tparams map (_.info.asSeenFrom(pre, owner).instantiateTypeParams(tparams, targs).bounds) + mapList(tparams)(_.info.asSeenFrom(pre, owner).instantiateTypeParams(tparams, targs).bounds) def elimAnonymousClass(t: Type) = t match { case TypeRef(pre, clazz, Nil) if clazz.isAnonymousClass => @@ -4555,7 +4513,10 @@ trait Types private[scala] val typeIsExistentiallyBound = (tp: Type) => tp.typeSymbol.isExistentiallyBound private[scala] val typeIsErroneous = (tp: Type) => tp.isErroneous private[scala] val symTypeIsError = (sym: Symbol) => sym.tpe.isError - private[scala] val typeHasAnnotations = (tp: Type) => tp.annotations.nonEmpty + private[scala] val treeTpe = (t: Tree) => t.tpe + private[scala] val symTpe = (sym: Symbol) => sym.tpe + private[scala] val symInfo = (sym: Symbol) => sym.info + private[scala] val typeHasAnnotations = (tp: Type) => tp.annotations ne Nil private[scala] val boundsContainType = (bounds: TypeBounds, tp: Type) => bounds containsType tp private[scala] val typeListIsEmpty = (ts: List[Type]) => ts.isEmpty private[scala] val typeIsSubTypeOfSerializable = (tp: Type) => tp <:< SerializableTpe diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala index cd09e83cd3..a7cac5254c 100644 --- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -84,7 +84,7 @@ trait Variances { loop(base, Covariant) } def isUncheckedVariance(tp: Type) = tp match { - case AnnotatedType(annots, _, _) => annots exists (_ matches definitions.uncheckedVarianceClass) + case AnnotatedType(annots, _) => annots exists (_ matches definitions.uncheckedVarianceClass) case _ => false } @@ -202,7 +202,7 @@ trait Variances { case MethodType(params, restpe) => inSyms(params).flip & inType(restpe) case PolyType(tparams, restpe) => inSyms(tparams).flip & inType(restpe) case ExistentialType(tparams, restpe) => inSyms(tparams) & inType(restpe) - case AnnotatedType(annots, tp, _) => inTypes(annots map (_.atp)) & inType(tp) + case AnnotatedType(annots, tp) => inTypes(annots map (_.atp)) & inType(tp) } inType(tp) diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index 3d222fce10..42f794736a 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -275,6 +275,7 @@ abstract class UnPickler { def pflags = flags & PickledFlags def finishSym(sym: Symbol): Symbol = { + markFlagsCompleted(sym)(mask = AllFlags) sym.privateWithin = privateWithin sym.info = ( if (atEnd) { @@ -362,7 +363,7 @@ abstract class UnPickler { case METHODtpe => MethodTypeRef(readTypeRef(), readSymbols()) case POLYtpe => PolyOrNullaryType(readTypeRef(), readSymbols()) case EXISTENTIALtpe => ExistentialType(underlying = readTypeRef(), quantified = readSymbols()) - case ANNOTATEDtpe => AnnotatedType(underlying = readTypeRef(), annotations = readAnnots(), selfsym = NoSymbol) + case ANNOTATEDtpe => AnnotatedType(underlying = readTypeRef(), annotations = readAnnots()) } } @@ -663,7 +664,7 @@ abstract class UnPickler { private class LazyTypeRef(i: Int) extends LazyType with FlagAgnosticCompleter { private val definedAtRunId = currentRunId private val p = phase - override def complete(sym: Symbol) : Unit = try { + protected def completeInternal(sym: Symbol) : Unit = try { val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType` if (p ne null) slowButSafeEnteringPhase(p) (sym setInfo tp) @@ -673,6 +674,10 @@ abstract class UnPickler { catch { case e: MissingRequirementError => throw toTypeError(e) } + override def complete(sym: Symbol) : Unit = { + completeInternal(sym) + if (!isCompilerUniverse) markAllCompleted(sym) + } override def load(sym: Symbol) { complete(sym) } } @@ -680,8 +685,9 @@ abstract class UnPickler { * of completed symbol to symbol at index `j`. */ private class LazyTypeRefAndAlias(i: Int, j: Int) extends LazyTypeRef(i) { - override def complete(sym: Symbol) = try { - super.complete(sym) + override def completeInternal(sym: Symbol) = try { + super.completeInternal(sym) + var alias = at(j, readSymbol) if (alias.isOverloaded) alias = slowButSafeEnteringPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt)))) diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala index 28afd18fe0..816916787e 100644 --- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala @@ -51,6 +51,8 @@ abstract class MutableSettings extends AbsSettings { def Yrecursion: IntSetting def maxClassfileName: IntSetting + + def isScala211: Boolean } object MutableSettings { diff --git a/src/reflect/scala/reflect/internal/tpe/FindMembers.scala b/src/reflect/scala/reflect/internal/tpe/FindMembers.scala new file mode 100644 index 0000000000..de54f3768e --- /dev/null +++ b/src/reflect/scala/reflect/internal/tpe/FindMembers.scala @@ -0,0 +1,288 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2014 LAMP/EPFL + * @author Jason Zaugg + */ +package scala.reflect.internal +package tpe + +import Flags._ +import util.Statistics +import TypesStats._ + +trait FindMembers { + this: SymbolTable => + + /** Implementatation of `Type#{findMember, findMembers}` */ + private[internal] abstract class FindMemberBase[T](tpe: Type, name: Name, excludedFlags: Long, requiredFlags: Long) { + protected val initBaseClasses: List[Symbol] = tpe.baseClasses + + // The first base class, or the symbol of the ThisType + // e.g in: + // trait T { self: C => } + // + // The selector class of `T.this.type` is `T`, and *not* the first base class, `C`. + private[this] var _selectorClass: Symbol = null + private def selectorClass: Symbol = { + if (_selectorClass eq null) { + _selectorClass = tpe match { + case tt: ThisType => tt.sym // SI-7507 the first base class is not necessarily the selector class. + case _ => initBaseClasses.head + } + } + _selectorClass + } + + // Cache for the narrowed type of `tp` (in `tp.findMember`). + // This is needed to avoid mismatched existential types are reported in SI-5330. + private[this] var _self: Type = null + protected def self: Type = { + // TODO: use narrow only for modules? (correct? efficiency gain?) (<-- Note: this comment predates SI-5330) + if (_self eq null) _self = narrowForFindMember(tpe) + _self + } + + // Main entry point + def apply(): T = { + if (Statistics.canEnable) Statistics.incCounter(findMemberCount) + val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMemberNanos) else null + try searchConcreteThenDeferred + finally if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start) + } + + protected def result: T + + // SLS 5.1.3 First, a concrete definition always overrides an abstract definition + private def searchConcreteThenDeferred: T = { + val deferredSeen = walkBaseClasses(requiredFlags, excludedFlags | DEFERRED) + if (deferredSeen) // OPT: the `if` avoids a second pass if the first pass didn't spot any candidates. + walkBaseClasses(requiredFlags | DEFERRED, excludedFlags & ~(DEFERRED.toLong)) + result + } + + /* + * Walk up through the decls of each base class. + * + * Called in two passes: first excluding deferred, then mandating it. + * + * @return if a potential deferred member was seen on the first pass that calls for a second pass, + and `excluded & DEFERRED != 0L` + */ + private def walkBaseClasses(required: Long, excluded: Long): Boolean = { + var bcs = initBaseClasses + + // Have we seen a candidate deferred member? + var deferredSeen = false + + // All direct parents of refinement classes in the base class sequence + // from the current `walkBaseClasses` + var refinementParents: List[Symbol] = Nil + + // Has the current `walkBaseClasses` encountered a non-refinement class? + var seenFirstNonRefinementClass = false + + val findAll = name == nme.ANYname + + while (!bcs.isEmpty) { + val currentBaseClass = bcs.head + val decls = currentBaseClass.info.decls + var entry = if (findAll) decls.elems else decls.lookupEntry(name) + while (entry ne null) { + val sym = entry.sym + val flags = sym.flags + val meetsRequirements = (flags & required) == required + if (meetsRequirements) { + val excl: Long = flags & excluded + val isExcluded: Boolean = excl != 0L + if (!isExcluded && isPotentialMember(sym, flags, currentBaseClass, seenFirstNonRefinementClass, refinementParents)) { + if (shortCircuit(sym)) return false + else addMemberIfNew(sym) + } else if (excl == DEFERRED) { + deferredSeen = true + } + } + entry = if (findAll) entry.next else decls lookupNextEntry entry + } + + // SLS 5.2 The private modifier can be used with any definition or declaration in a template. + // They are not inherited by subclasses [...] + if (currentBaseClass.isRefinementClass) + // SLS 3.2.7 A compound type T1 with . . . with Tn {R } represents objects with members as given in + // the component types T1, ..., Tn and the refinement {R } + // + // => private members should be included from T1, ... Tn. (SI-7475) + refinementParents :::= currentBaseClass.parentSymbols + else if (currentBaseClass.isClass) + seenFirstNonRefinementClass = true // only inherit privates of refinement parents after this point + + bcs = bcs.tail + } + deferredSeen + } + + /* Should this symbol be returned immediately as the sole result? */ + protected def shortCircuit(sym: Symbol): Boolean + + /* Add this member to the final result, unless an already-found member matches it. */ + protected def addMemberIfNew(sym: Symbol): Unit + + // Is `sym` a potentially member of `baseClass`? + // + // Q. When does a potential member fail to be a an actual member? + // A. if it is subsumed by an member in a subclass. + private def isPotentialMember(sym: Symbol, flags: Long, owner: Symbol, + seenFirstNonRefinementClass: Boolean, refinementParents: List[Symbol]): Boolean = { + // conservatively (performance wise) doing this with flags masks rather than `sym.isPrivate` + // to avoid multiple calls to `Symbol#flags`. + val isPrivate = (flags & PRIVATE) == PRIVATE + val isPrivateLocal = (flags & PrivateLocal) == PrivateLocal + + // TODO Is the special handling of `private[this]` vs `private` backed up by the spec? + def admitPrivate(sym: Symbol): Boolean = + (selectorClass == owner) || ( + !isPrivateLocal // private[this] only a member from within the selector class. (Optimization only? Does the spec back this up?) + && ( + !seenFirstNonRefinementClass + || refinementParents.contains(owner) + ) + ) + + (!isPrivate || admitPrivate(sym)) && (sym.name != nme.CONSTRUCTOR || owner == initBaseClasses.head) + } + + // True unless the already-found member of type `memberType` matches the candidate symbol `other`. + protected def isNewMember(member: Symbol, other: Symbol): Boolean = + ( (other ne member) + && ( (member.owner eq other.owner) // same owner, therefore overload + || (member.flags & PRIVATE) != 0 // (unqualified) private members never participate in overriding + || (other.flags & PRIVATE) != 0 // ... as overrider or overridee. + || !(memberTypeLow(member) matches memberTypeHi(other)) // do the member types match? If so, its an override. Otherwise it's an overload. + ) + ) + + // Cache for the member type of a candidate member when comparing against multiple, already-found existing members + // + // TODO this cache is probably unnecessary, `tp.memberType(sym: MethodSymbol)` is already cached internally. + private[this] var _memberTypeHiCache: Type = null + private[this] var _memberTypeHiCacheSym: Symbol = null + + protected def memberTypeHi(sym: Symbol): Type = { + if (_memberTypeHiCacheSym ne sym) { + _memberTypeHiCache = self.memberType(sym) + _memberTypeHiCacheSym = sym + } + _memberTypeHiCache + } + + // member type of the LHS of `matches` call. This is an extension point to enable a cache in + // FindMember. + protected def memberTypeLow(sym: Symbol): Type = self.memberType(sym) + + /** Same as a call to narrow unless existentials are visible + * after widening the type. In that case, narrow from the widened + * type instead of the proxy. This gives buried existentials a + * chance to make peace with the other types. See SI-5330. + */ + private def narrowForFindMember(tp: Type): Type = { + val w = tp.widen + // Only narrow on widened type when we have to -- narrow is expensive unless the target is a singleton type. + if ((tp ne w) && containsExistential(w)) w.narrow + else tp.narrow + } + } + + private[reflect] final class FindMembers(tpe: Type, excludedFlags: Long, requiredFlags: Long) + extends FindMemberBase[Scope](tpe, nme.ANYname, excludedFlags, requiredFlags) { + private[this] var _membersScope: Scope = null + private def membersScope: Scope = { + if (_membersScope eq null) _membersScope = newFindMemberScope + _membersScope + } + + protected def shortCircuit(sym: Symbol): Boolean = false + protected def result: Scope = membersScope + + protected def addMemberIfNew(sym: Symbol): Unit = { + val members = membersScope + var others = members.lookupEntry(sym.name) + var isNew = true + while ((others ne null) && isNew) { + val member = others.sym + if (!isNewMember(member, sym)) + isNew = false + others = members lookupNextEntry others // next existing member with the same name. + } + if (isNew) members.enter(sym) + } + } + + private[reflect] final class FindMember(tpe: Type, name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean) + extends FindMemberBase[Symbol](tpe, name, excludedFlags, requiredFlags) { + // Gathering the results into a hand rolled ListBuffer + // TODO Try just using a ListBuffer to see if this low-level-ness is worth it. + private[this] var member0: Symbol = NoSymbol + private[this] var members: List[Symbol] = null + private[this] var lastM: ::[Symbol] = null + + private def clearAndAddResult(sym: Symbol): Unit = { + member0 = sym + members = null + lastM = null + } + + protected def shortCircuit(sym: Symbol): Boolean = (name.isTypeName || (stableOnly && sym.isStable && !sym.hasVolatileType)) && { + clearAndAddResult(sym) + true + } + + protected def addMemberIfNew(sym: Symbol): Unit = + if (member0 eq NoSymbol) { + member0 = sym // The first found member + } else if (members eq null) { + // We've found exactly one member so far... + if (isNewMember(member0, sym)) { + // ... make that two. + lastM = new ::(sym, null) + members = member0 :: lastM + } + } else { + // Already found 2 or more members + var ms: List[Symbol] = members + + var isNew = true + while ((ms ne null) && isNew) { + val member = ms.head + if (!isNewMember(member, sym)) + isNew = false + ms = ms.tail + } + if (isNew) { + val lastM1 = new ::(sym, null) + lastM.tl = lastM1 + lastM = lastM1 + } + } + + // Cache for the member type of the first member we find. + private[this] var _member0Tpe: Type = null + private[this] def member0Tpe: Type = { + assert(member0 != null) + if (_member0Tpe eq null) _member0Tpe = self.memberType(member0) + _member0Tpe + } + + override protected def memberTypeLow(sym: Symbol): Type = + if (sym eq member0) member0Tpe else super.memberTypeLow(sym) + + // Assemble the result from the hand-rolled ListBuffer + protected def result: Symbol = if (members eq null) { + if (member0 == NoSymbol) { + if (Statistics.canEnable) Statistics.incCounter(noMemberCount) + NoSymbol + } else member0 + } else { + if (Statistics.canEnable) Statistics.incCounter(multMemberCount) + lastM.tl = Nil + initBaseClasses.head.newOverloaded(tpe, members) + } + } +} diff --git a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala index 6b33aca025..1c4d05ae32 100644 --- a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala +++ b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala @@ -316,7 +316,7 @@ private[internal] trait GlbLubs { NullaryMethodType(lub0(matchingRestypes(ts, Nil))) case ts @ TypeBounds(_, _) :: rest => TypeBounds(glb(ts map (_.bounds.lo), depth), lub(ts map (_.bounds.hi), depth)) - case ts @ AnnotatedType(annots, tpe, _) :: rest => + case ts @ AnnotatedType(annots, tpe) :: rest => annotationsLub(lub0(ts map (_.withoutAnnotations)), ts) case ts => lubResults get ((depth, ts)) match { diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala index b60fecd66e..f9b10c90be 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala @@ -17,20 +17,15 @@ trait TypeComparers { private val _pendingSubTypes = new mutable.HashSet[SubTypePair] def pendingSubTypes = _pendingSubTypes - class SubTypePair(val tp1: Type, val tp2: Type) { - override def hashCode = tp1.hashCode * 41 + tp2.hashCode - override def equals(other: Any) = (this eq other.asInstanceOf[AnyRef]) || (other match { - // suspend TypeVars in types compared by =:=, - // since we don't want to mutate them simply to check whether a subtype test is pending - // in addition to making subtyping "more correct" for type vars, - // it should avoid the stackoverflow that's been plaguing us (https://groups.google.com/d/topic/scala-internals/2gHzNjtB4xA/discussion) - // this method is only called when subtyping hits a recursion threshold (subsametypeRecursions >= LogPendingSubTypesThreshold) - case stp: SubTypePair => - val tvars = List(tp1, stp.tp1, tp2, stp.tp2) flatMap (t => if (t.isGround) Nil else typeVarsInType(t)) - suspendingTypeVars(tvars)(tp1 =:= stp.tp1 && tp2 =:= stp.tp2) - case _ => - false - }) + final case class SubTypePair(tp1: Type, tp2: Type) { + // SI-8146 we used to implement equality here in terms of pairwise =:=. + // But, this was inconsistent with hashCode, which was based on the + // Type#hashCode, based on the structure of types, not the meaning. + // Now, we use `Type#{equals,hashCode}` as the (consistent) basis for + // detecting cycles (aka keeping subtyping decidable.) + // + // I added a tests to show that we detect the cycle: neg/t8146-no-finitary* + override def toString = tp1+" <:<? "+tp2 } @@ -170,11 +165,20 @@ trait TypeComparers { // corresponds does not check length of two sequences before checking the predicate, // but SubstMap assumes it has been checked (SI-2956) ( sameLength(tparams1, tparams2) - && (tparams1 corresponds tparams2)((p1, p2) => p1.info =:= subst(p2.info)) + && (tparams1 corresponds tparams2)((p1, p2) => methodHigherOrderTypeParamsSameVariance(p1, p2) && p1.info =:= subst(p2.info)) && (res1 =:= subst(res2)) ) } + // SI-2066 This prevents overrides with incompatible variance in higher order type parameters. + private def methodHigherOrderTypeParamsSameVariance(sym1: Symbol, sym2: Symbol) = { + def ignoreVariance(sym: Symbol) = !(sym.isHigherOrderTypeParameter && sym.logicallyEnclosingMember.isMethod) + !settings.isScala211 || ignoreVariance(sym1) || ignoreVariance(sym2) || sym1.variance == sym2.variance + } + + private def methodHigherOrderTypeParamsSubVariance(low: Symbol, high: Symbol) = + !settings.isScala211 || methodHigherOrderTypeParamsSameVariance(low, high) || low.variance.isInvariant + def isSameType2(tp1: Type, tp2: Type): Boolean = { def retry(lhs: Type, rhs: Type) = ((lhs ne tp1) || (rhs ne tp2)) && isSameType(lhs, rhs) @@ -262,7 +266,7 @@ trait TypeComparers { if (subsametypeRecursions >= LogPendingSubTypesThreshold) { val p = new SubTypePair(tp1, tp2) if (pendingSubTypes(p)) - false + false // see neg/t8146-no-finitary* else try { pendingSubTypes += p @@ -327,7 +331,10 @@ trait TypeComparers { val substitutes = if (isMethod) tparams1 else cloneSymbols(tparams1) def sub1(tp: Type) = if (isMethod) tp else tp.substSym(tparams1, substitutes) def sub2(tp: Type) = tp.substSym(tparams2, substitutes) - def cmp(p1: Symbol, p2: Symbol) = sub2(p2.info) <:< sub1(p1.info) + def cmp(p1: Symbol, p2: Symbol) = ( + methodHigherOrderTypeParamsSubVariance(p2, p1) + && sub2(p2.info) <:< sub1(p1.info) + ) (tparams1 corresponds tparams2)(cmp) && (sub1(res1) <:< sub2(res2)) } @@ -403,14 +410,14 @@ trait TypeComparers { case _ => secondTry } - case AnnotatedType(_, _, _) => + case AnnotatedType(_, _) => isSubType(tp1.withoutAnnotations, tp2.withoutAnnotations, depth) && annotationsConform(tp1, tp2) case BoundedWildcardType(bounds) => isSubType(tp1, bounds.hi, depth) case tv2 @ TypeVar(_, constr2) => tp1 match { - case AnnotatedType(_, _, _) | BoundedWildcardType(_) => + case AnnotatedType(_, _) | BoundedWildcardType(_) => secondTry case _ => tv2.registerBound(tp1, isLowerBound = true) @@ -425,7 +432,7 @@ trait TypeComparers { * - handle existential types by skolemization. */ def secondTry = tp1 match { - case AnnotatedType(_, _, _) => + case AnnotatedType(_, _) => isSubType(tp1.withoutAnnotations, tp2.withoutAnnotations, depth) && annotationsConform(tp1, tp2) case BoundedWildcardType(bounds) => diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala index e2159d30f5..564cbb1ce3 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala @@ -257,6 +257,12 @@ private[internal] trait TypeConstraints { // println("solving "+tvars+"/"+tparams+"/"+(tparams map (_.info))) foreach3(tvars, tparams, variances)(solveOne) - tvars forall (tv => tv.instWithinBounds || util.andFalse(log(s"Inferred type for ${tv.originString} does not conform to bounds: ${tv.constr}"))) + + def logBounds(tv: TypeVar) = log { + val what = if (!tv.instValid) "is invalid" else s"does not conform to bounds: ${tv.constr}" + s"Inferred type for ${tv.originString} (${tv.inst}) $what" + } + + tvars forall (tv => tv.instWithinBounds || util.andFalse(logBounds(tv))) } } diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala index f5aa048e6a..07c9242bf3 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala @@ -48,7 +48,7 @@ private[internal] trait TypeMaps { case TypeRef(_, sym, _) if sym.isAliasType => apply(tp.dealias) case TypeRef(_, sym, _) if sym.isAbstractType => apply(tp.bounds.hi) case rtp @ RefinedType(parents, decls) => copyRefinedType(rtp, parents mapConserve this, decls) - case AnnotatedType(_, _, _) => mapOver(tp) + case AnnotatedType(_, _) => mapOver(tp) case _ => tp // no recursion - top level only } } @@ -174,12 +174,12 @@ private[internal] trait TypeMaps { case tv@TypeVar(_, constr) => if (constr.instValid) this(constr.inst) else tv.applyArgs(mapOverArgs(tv.typeArgs, tv.params)) //@M !args.isEmpty implies !typeParams.isEmpty - case AnnotatedType(annots, atp, selfsym) => + case AnnotatedType(annots, atp) => val annots1 = mapOverAnnotations(annots) val atp1 = this(atp) if ((annots1 eq annots) && (atp1 eq atp)) tp else if (annots1.isEmpty) atp1 - else AnnotatedType(annots1, atp1, selfsym) + else AnnotatedType(annots1, atp1) /* case ErrorType => tp case WildcardType => tp @@ -861,33 +861,26 @@ private[internal] trait TypeMaps { class InstantiateDependentMap(params: List[Symbol], actuals0: List[Type]) extends TypeMap with KeepOnlyTypeConstraints { private val actuals = actuals0.toIndexedSeq private val existentials = new Array[Symbol](actuals.size) - def existentialsNeeded: List[Symbol] = existentials.filter(_ ne null).toList - - private object StableArg { - def unapply(param: Symbol) = Arg unapply param map actuals filter (tp => - tp.isStable && (tp.typeSymbol != NothingClass) - ) - } - private object Arg { - def unapply(param: Symbol) = Some(params indexOf param) filter (_ >= 0) - } - - def apply(tp: Type): Type = mapOver(tp) match { - // unsound to replace args by unstable actual #3873 - case SingleType(NoPrefix, StableArg(arg)) => arg - // (soundly) expand type alias selections on implicit arguments, - // see depmet_implicit_oopsla* test cases -- typically, `param.isImplicit` - case tp1 @ TypeRef(SingleType(NoPrefix, Arg(pid)), sym, targs) => - val arg = actuals(pid) - val res = typeRef(arg, sym, targs) - if (res.typeSymbolDirect.isAliasType) res.dealias else tp1 - // don't return the original `tp`, which may be different from `tp1`, - // due to dropping annotations - case tp1 => tp1 + def existentialsNeeded: List[Symbol] = existentials.iterator.filter(_ ne null).toList + + private object StableArgTp { + // type of actual arg corresponding to param -- if the type is stable + def unapply(param: Symbol): Option[Type] = (params indexOf param) match { + case -1 => None + case pid => + val tp = actuals(pid) + if (tp.isStable && (tp.typeSymbol != NothingClass)) Some(tp) + else None + } } - /* Return the type symbol for referencing a parameter inside the existential quantifier. - * (Only needed if the actual is unstable.) + /** Return the type symbol for referencing a parameter that's instantiated to an unstable actual argument. + * + * To soundly abstract over an unstable value (x: T) while retaining the most type information, + * use `x.type forSome { type x.type <: T with Singleton}` + * `typeOf[T].narrowExistentially(symbolOf[x])`. + * + * See also: captureThis in AsSeenFromMap. */ private def existentialFor(pid: Int) = { if (existentials(pid) eq null) { @@ -900,6 +893,38 @@ private[internal] trait TypeMaps { existentials(pid) } + private object UnstableArgTp { + // existential quantifier and type of corresponding actual arg with unstable type + def unapply(param: Symbol): Option[(Symbol, Type)] = (params indexOf param) match { + case -1 => None + case pid => + val sym = existentialFor(pid) + Some((sym, sym.tpe_*)) // refers to an actual value, must be kind-* + } + } + + private object StabilizedArgTp { + def unapply(param: Symbol): Option[Type] = + param match { + case StableArgTp(tp) => Some(tp) // (1) + case UnstableArgTp(_, tp) => Some(tp) // (2) + case _ => None + } + } + + /** instantiate `param.type` to the (sound approximation of the) type `T` + * of the actual argument `arg` that was passed in for `param` + * + * (1) If `T` is stable, we can just use that. + * + * (2) SI-3873: it'd be unsound to instantiate `param.type` to an unstable `T`, + * so we approximate to `X forSome {type X <: T with Singleton}` -- we can't soundly say more. + */ + def apply(tp: Type): Type = tp match { + case SingleType(NoPrefix, StabilizedArgTp(tp)) => tp + case _ => mapOver(tp) + } + //AM propagate more info to annotations -- this seems a bit ad-hoc... (based on code by spoon) override def mapOver(arg: Tree, giveup: ()=>Nothing): Tree = { // TODO: this should be simplified; in the stable case, one can @@ -922,13 +947,9 @@ private[internal] trait TypeMaps { // Both examples are from run/constrained-types.scala. object treeTrans extends Transformer { override def transform(tree: Tree): Tree = tree.symbol match { - case StableArg(actual) => - gen.mkAttributedQualifier(actual, tree.symbol) - case Arg(pid) => - val sym = existentialFor(pid) - Ident(sym) copyAttrs tree setType typeRef(NoPrefix, sym, Nil) - case _ => - super.transform(tree) + case StableArgTp(tp) => gen.mkAttributedQualifier(tp, tree.symbol) + case UnstableArgTp(quant, tp) => Ident(quant) copyAttrs tree setType tp + case _ => super.transform(tree) } } treeTrans transform arg @@ -1142,7 +1163,7 @@ private[internal] trait TypeMaps { case SuperType(_, _) => mapOver(tp) case TypeBounds(_, _) => mapOver(tp) case TypeVar(_, _) => mapOver(tp) - case AnnotatedType(_,_,_) => mapOver(tp) + case AnnotatedType(_, _) => mapOver(tp) case ExistentialType(_, _) => mapOver(tp) case _ => tp } diff --git a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala index ebc4394d25..a062fc8209 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala @@ -3,19 +3,29 @@ package reflect package internal package tpe +import scala.collection.mutable.HashSet + private[internal] trait TypeToStrings { self: SymbolTable => /** The maximum number of recursions allowed in toString */ - final val maxTostringRecursions = 50 + final val maxToStringRecursions = 50 + + private var _toStringRecursions = 0 + def toStringRecursions = _toStringRecursions + def toStringRecursions_=(value: Int) = _toStringRecursions = value - private var _tostringRecursions = 0 - def tostringRecursions = _tostringRecursions - def tostringRecursions_=(value: Int) = _tostringRecursions = value + private var _toStringSubjects = HashSet[Type]() + def toStringSubjects = _toStringSubjects protected def typeToString(tpe: Type): String = - if (tostringRecursions >= maxTostringRecursions) { + // if (toStringSubjects contains tpe) { + // // handles self-referential anonymous classes and who knows what else + // "..." + // } + // else + if (toStringRecursions >= maxToStringRecursions) { devWarning("Exceeded recursion depth attempting to print " + util.shortClassOfInstance(tpe)) if (settings.debug) (new Throwable).printStackTrace @@ -24,9 +34,15 @@ private[internal] trait TypeToStrings { } else try { - tostringRecursions += 1 + toStringRecursions += 1 + // TODO: study performance impact of this cache + // to quote Jason: + // I'm a little uneasy with the performance impact of the fail-safe. We end up calling Type#toString + // when we generate error messages, including, importantly, errors issued during silent mode that are never issued. + // toStringSubjects += tpe tpe.safeToString } finally { - tostringRecursions -= 1 + // toStringSubjects -= tpe + toStringRecursions -= 1 } } diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index addc7eb389..786ff2210c 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -144,7 +144,7 @@ trait Erasure { else apply(mt.resultType(mt.paramTypes))) case RefinedType(parents, decls) => apply(mergeParents(parents)) - case AnnotatedType(_, atp, _) => + case AnnotatedType(_, atp) => apply(atp) case ClassInfoType(parents, decls, clazz) => ClassInfoType( diff --git a/src/reflect/scala/reflect/internal/transform/PostErasure.scala b/src/reflect/scala/reflect/internal/transform/PostErasure.scala new file mode 100644 index 0000000000..f0c7d0f050 --- /dev/null +++ b/src/reflect/scala/reflect/internal/transform/PostErasure.scala @@ -0,0 +1,19 @@ +package scala.reflect +package internal +package transform + +trait PostErasure { + val global: SymbolTable + import global._ + import definitions._ + + object elimErasedValueType extends TypeMap { + def apply(tp: Type) = tp match { + case ConstantType(Constant(tp: Type)) => ConstantType(Constant(apply(tp))) + case ErasedValueType(_, underlying) => underlying + case _ => mapOver(tp) + } + } + + def transformInfo(sym: Symbol, tp: Type) = elimErasedValueType(tp) +} diff --git a/src/reflect/scala/reflect/internal/transform/Transforms.scala b/src/reflect/scala/reflect/internal/transform/Transforms.scala index fa185db22f..296ccde443 100644 --- a/src/reflect/scala/reflect/internal/transform/Transforms.scala +++ b/src/reflect/scala/reflect/internal/transform/Transforms.scala @@ -26,17 +26,20 @@ trait Transforms { self: SymbolTable => private val refChecksLazy = new Lazy(new { val global: Transforms.this.type = self } with RefChecks) private val uncurryLazy = new Lazy(new { val global: Transforms.this.type = self } with UnCurry) private val erasureLazy = new Lazy(new { val global: Transforms.this.type = self } with Erasure) + private val postErasureLazy = new Lazy(new { val global: Transforms.this.type = self } with PostErasure) def refChecks = refChecksLazy.force def uncurry = uncurryLazy.force def erasure = erasureLazy.force + def postErasure = postErasureLazy.force def transformedType(sym: Symbol) = - erasure.transformInfo(sym, - uncurry.transformInfo(sym, - refChecks.transformInfo(sym, sym.info))) + postErasure.transformInfo(sym, + erasure.transformInfo(sym, + uncurry.transformInfo(sym, + refChecks.transformInfo(sym, sym.info)))) def transformedType(tpe: Type) = - erasure.scalaErasure(uncurry.uncurry(tpe)) + postErasure.elimErasedValueType(erasure.scalaErasure(uncurry.uncurry(tpe))) } diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala index 7cc2952c96..d128521be8 100644 --- a/src/reflect/scala/reflect/internal/util/Collections.scala +++ b/src/reflect/scala/reflect/internal/util/Collections.scala @@ -47,6 +47,30 @@ trait Collections { final def mforeach[A](xss: List[List[A]])(f: A => Unit) = xss foreach (_ foreach f) final def mforeach[A](xss: Traversable[Traversable[A]])(f: A => Unit) = xss foreach (_ foreach f) + /** A version of List#map, specialized for List, and optimized to avoid allocation if `as` is empty */ + final def mapList[A, B](as: List[A])(f: A => B): List[B] = if (as eq Nil) Nil else { + val head = new ::[B](f(as.head), Nil) + var tail: ::[B] = head + var rest = as.tail + while (rest ne Nil) { + val next = new ::(f(rest.head), Nil) + tail.tl = next + tail = next + rest = rest.tail + } + head + } + + final def collectFirst[A, B](as: List[A])(pf: PartialFunction[A, B]): Option[B] = { + @tailrec + def loop(rest: List[A]): Option[B] = rest match { + case Nil => None + case a :: as if pf.isDefinedAt(a) => Some(pf(a)) + case a :: as => loop(as) + } + loop(as) + } + final def map2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => C): List[C] = { val lb = new ListBuffer[C] var ys1 = xs1 @@ -99,15 +123,19 @@ trait Collections { else f(xs1.head, xs2.head, xs3.head) :: map3(xs1.tail, xs2.tail, xs3.tail)(f) } final def flatMap2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => List[C]): List[C] = { - val lb = new ListBuffer[C] + var lb: ListBuffer[C] = null var ys1 = xs1 var ys2 = xs2 while (!ys1.isEmpty && !ys2.isEmpty) { - lb ++= f(ys1.head, ys2.head) + val cs = f(ys1.head, ys2.head) + if (cs ne Nil) { + if (lb eq null) lb = new ListBuffer[C] + lb ++= cs + } ys1 = ys1.tail ys2 = ys2.tail } - lb.toList + if (lb eq null) Nil else lb.result } final def flatCollect[A, B](elems: List[A])(pf: PartialFunction[A, Traversable[B]]): List[B] = { diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala index 15cfda26b5..f3eedb88e7 100644 --- a/src/reflect/scala/reflect/internal/util/Position.scala +++ b/src/reflect/scala/reflect/internal/util/Position.scala @@ -202,12 +202,31 @@ private[util] trait InternalPositionImpl { def line: Int = if (hasSource) source.offsetToLine(point) + 1 else 0 def column: Int = if (hasSource) calculateColumn() else 0 def lineContent: String = if (hasSource) source.lineToString(line - 1) else "" - def lineCarat: String = if (hasSource) " " * (column - 1) + "^" else "" - - def showError(msg: String): String = finalPosition match { - case FakePos(fmsg) => s"$fmsg $msg" - case NoPosition => msg - case pos => s"${pos.line}: $msg\n${pos.lineContent}\n${pos.lineCarat}" + def lineCaret: String = if (hasSource) " " * (column - 1) + "^" else "" + @deprecated("use `lineCaret`", since="2.11.0") + def lineCarat: String = lineCaret + + def showError(msg: String): String = { + def escaped(s: String) = { + def u(c: Int) = f"\\u$c%04x" + def uable(c: Int) = (c < 0x20 && c != '\t') || c == 0x7F + if (s exists (c => uable(c))) { + val sb = new StringBuilder + s foreach (c => sb append (if (uable(c)) u(c) else c)) + sb.toString + } else s + } + def errorAt(p: Pos) = { + def where = p.line + def content = escaped(p.lineContent) + def indicator = p.lineCaret + f"$where: $msg%n$content%n$indicator" + } + finalPosition match { + case FakePos(fmsg) => s"$fmsg $msg" + case NoPosition => msg + case pos => errorAt(pos) + } } def showDebug: String = toString def show = ( @@ -239,8 +258,8 @@ private[util] trait InternalPositionImpl { private[util] trait DeprecatedPosition { self: Position => - @deprecated("use `point`", "2.9.0") - def offset: Option[Int] = if (isDefined) Some(point) else None // used by sbt + @deprecated("use `point`", "2.9.0") // Used in SBT 0.12.4 + def offset: Option[Int] = if (isDefined) Some(point) else None @deprecated("use `focus`", "2.11.0") def toSingleLine: Position = this @@ -254,7 +273,7 @@ private[util] trait DeprecatedPosition { @deprecated("use `finalPosition`", "2.11.0") def inUltimateSource(source: SourceFile): Position = source positionInUltimateSource this - @deprecated("use `lineCarat`", "2.11.0") + @deprecated("use `lineCaret`", since="2.11.0") def lineWithCarat(maxWidth: Int): (String, String) = ("", "") @deprecated("Use `withSource(source)` and `withShift`", "2.11.0") diff --git a/src/reflect/scala/reflect/internal/util/SourceFile.scala b/src/reflect/scala/reflect/internal/util/SourceFile.scala index 3b6c57e955..8791d8eb23 100644 --- a/src/reflect/scala/reflect/internal/util/SourceFile.scala +++ b/src/reflect/scala/reflect/internal/util/SourceFile.scala @@ -16,12 +16,13 @@ import scala.reflect.internal.Chars._ /** abstract base class of a source file used in the compiler */ abstract class SourceFile { - def content : Array[Char] // normalized, must end in SU - def file : AbstractFile - def isLineBreak(idx : Int) : Boolean + def content: Array[Char] // normalized, must end in SU + def file : AbstractFile + def isLineBreak(idx: Int): Boolean + def isEndOfLine(idx: Int): Boolean def isSelfContained: Boolean def length : Int - def position(offset: Int) : Position = { + def position(offset: Int): Position = { assert(offset < length, file + ": " + offset + " >= " + length) Position.offset(this, offset) } @@ -36,8 +37,12 @@ abstract class SourceFile { override def toString() = file.name def path = file.path - def lineToString(index: Int): String = - content drop lineToOffset(index) takeWhile (c => !isLineBreakChar(c.toChar)) mkString "" + def lineToString(index: Int): String = { + val start = lineToOffset(index) + var end = start + while (!isEndOfLine(end) && end <= length) end += 1 + new String(content, start, end - start) + } @tailrec final def skipWhitespace(offset: Int): Int = @@ -52,6 +57,7 @@ object NoSourceFile extends SourceFile { def content = Array() def file = NoFile def isLineBreak(idx: Int) = false + def isEndOfLine(idx: Int) = false def isSelfContained = true def length = -1 def offsetToLine(offset: Int) = -1 @@ -128,18 +134,30 @@ class BatchSourceFile(val file : AbstractFile, val content0: Array[Char]) extend super.identifier(pos) } - def isLineBreak(idx: Int) = - if (idx >= length) false else { - val ch = content(idx) - // don't identify the CR in CR LF as a line break, since LF will do. - if (ch == CR) (idx + 1 == length) || (content(idx + 1) != LF) - else isLineBreakChar(ch) - } + private def charAtIsEOL(idx: Int)(p: Char => Boolean) = { + // don't identify the CR in CR LF as a line break, since LF will do. + def notCRLF0 = content(idx) != CR || !content.isDefinedAt(idx + 1) || content(idx + 1) != LF + + idx < length && notCRLF0 && p(content(idx)) + } + + def isLineBreak(idx: Int) = charAtIsEOL(idx)(isLineBreakChar) + + /** True if the index is included by an EOL sequence. */ + def isEndOfLine(idx: Int) = (content isDefinedAt idx) && PartialFunction.cond(content(idx)) { + case CR | LF => true + } + + /** True if the index is end of an EOL sequence. */ + def isAtEndOfLine(idx: Int) = charAtIsEOL(idx) { + case CR | LF => true + case _ => false + } def calculateLineIndices(cs: Array[Char]) = { val buf = new ArrayBuffer[Int] buf += 0 - for (i <- 0 until cs.length) if (isLineBreak(i)) buf += i + 1 + for (i <- 0 until cs.length) if (isAtEndOfLine(i)) buf += i + 1 buf += cs.length // sentinel, so that findLine below works smoother buf.toArray } @@ -149,8 +167,8 @@ class BatchSourceFile(val file : AbstractFile, val content0: Array[Char]) extend private var lastLine = 0 - /** Convert offset to line in this source file - * Lines are numbered from 0 + /** Convert offset to line in this source file. + * Lines are numbered from 0. */ def offsetToLine(offset: Int): Int = { val lines = lineIndices diff --git a/src/reflect/scala/reflect/macros/Aliases.scala b/src/reflect/scala/reflect/macros/Aliases.scala index ca599dbd49..d2b878d081 100644 --- a/src/reflect/scala/reflect/macros/Aliases.scala +++ b/src/reflect/scala/reflect/macros/Aliases.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that defines shorthands for the + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that defines shorthands for the * most frequently used types and functions of the underlying compiler universe. */ trait Aliases { - self: BlackboxContext => + self: blackbox.Context => /** The type of symbols representing declarations. */ type Symbol = universe.Symbol @@ -40,10 +40,16 @@ trait Aliases { /** The type of tree modifiers. */ type Modifiers = universe.Modifiers - /** The type of compilation runs. */ + /** The type of compilation runs. + * @see [[scala.reflect.macros.Enclosures]] + */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") type Run = universe.Run - /** The type of compilation units. */ + /** The type of compilation units. + * @see [[scala.reflect.macros.Enclosures]] + */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") type CompilationUnit = universe.CompilationUnit /** Expr wraps an abstract syntax tree and tags it with its type. */ diff --git a/src/reflect/scala/reflect/macros/Attachments.scala b/src/reflect/scala/reflect/macros/Attachments.scala index 039e75fbee..5ccdc15a03 100644 --- a/src/reflect/scala/reflect/macros/Attachments.scala +++ b/src/reflect/scala/reflect/macros/Attachments.scala @@ -43,7 +43,7 @@ abstract class Attachments { self => /** Check underlying payload contains an instance of type `T`. */ def contains[T: ClassTag]: Boolean = - all exists matchesTag[T] + !isEmpty && (all exists matchesTag[T]) /** Creates a copy of this attachment with the payload slot of T added/updated with the provided value. * Replaces an existing payload of the same type, if exists. @@ -57,6 +57,8 @@ abstract class Attachments { self => if (newAll.isEmpty) pos.asInstanceOf[Attachments { type Pos = self.Pos }] else new NonemptyAttachments[Pos](this.pos, newAll) } + + def isEmpty: Boolean = true } // SI-7018: This used to be an inner class of `Attachments`, but that led to a memory leak in the @@ -64,4 +66,5 @@ abstract class Attachments { self => private final class NonemptyAttachments[P >: Null](override val pos: P, override val all: Set[Any]) extends Attachments { type Pos = P def withPos(newPos: Pos) = new NonemptyAttachments(newPos, all) + override def isEmpty: Boolean = false } diff --git a/src/reflect/scala/reflect/macros/BlackboxMacro.scala b/src/reflect/scala/reflect/macros/BlackboxMacro.scala deleted file mode 100644 index df142e9238..0000000000 --- a/src/reflect/scala/reflect/macros/BlackboxMacro.scala +++ /dev/null @@ -1,36 +0,0 @@ -package scala.reflect -package macros - -/** - * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> - * - * Traditionally macro implementations are defined as methods, - * but this trait provides an alternative way of encoding macro impls as - * bundles, traits which extend `scala.reflect.macros.BlackboxMacro` or`scala.reflect.macros.WhiteboxMacro` . - * - * Instead of: - * - * def impl[T: c.WeakTypeTag](c: BlackboxContext)(x: c.Expr[Int]) = ... - * - * One can write: - * - * trait Impl extends BlackboxMacro { - * def apply[T: c.WeakTypeTag](x: c.Expr[Int]) = ... - * } - * - * Without changing anything else at all. - * - * This language feature is useful in itself in cases when macro implementations - * are complex and need to be modularized. State of the art technique of addressing this need is quite heavyweight: - * http://docs.scala-lang.org/overviews/macros/overview.html#writing_bigger_macros. - * - * @see `scala.reflect.macros.WhiteboxMacro` - */ -trait BlackboxMacro { - /** The context to be used by the macro implementation. - * - * Vanilla macro implementations have to carry it in their signatures, however when a macro is a full-fledged module, - * it can define the context next to the implementation, makes implementation signature more lightweight. - */ - val c: BlackboxContext -} diff --git a/src/reflect/scala/reflect/macros/Enclosures.scala b/src/reflect/scala/reflect/macros/Enclosures.scala index f3e934d12b..1ced2e54c6 100644 --- a/src/reflect/scala/reflect/macros/Enclosures.scala +++ b/src/reflect/scala/reflect/macros/Enclosures.scala @@ -7,13 +7,25 @@ import scala.language.existentials // SI-6541 /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that exposes - * enclosing trees (method, class, compilation unit and currently compiled application), + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that exposes + * enclosing trees (method, class, compilation unit and currently compiled macro application), * the enclosing position of the macro expansion, as well as macros and implicits * that are currently in-flight. + * + * Starting from Scala 2.11.0, the APIs to get the trees enclosing by the current macro application are deprecated, + * and the reasons for that are two-fold. Firstly, we would like to move towards the philosophy of locally-expanded macros, + * as it has proven to be important for understanding of code. Secondly, within the current architecture of scalac, + * we are unable to have c.enclosingTree-style APIs working robustly. Required changes to the typechecker would greatly + * exceed the effort that we would like to expend on this feature given the existence of more pressing concerns at the moment. + * This is somewhat aligned with the overall evolution of macros during the 2.11 development cycle, where we played with + * `c.introduceTopLevel` and `c.introduceMember`, but at the end of the day decided to reject them. + * + * If you're relying on the now deprecated APIs, consider reformulating your macros in terms of completely local expansion + * and/or joining a discussion of a somewhat related potential language feature at [[https://groups.google.com/forum/#!topic/scala-debate/f4CLmYShX6Q]]. + * We also welcome questions and suggestions on our mailing lists, where we would be happy to further discuss this matter. */ trait Enclosures { - self: BlackboxContext => + self: blackbox.Context => /** The tree that undergoes macro expansion. * Can be useful to get an offset or a range position of the entire tree being processed. @@ -30,7 +42,7 @@ trait Enclosures { * Unlike `openMacros`, this is a val, which means that it gets initialized when the context is created * and always stays the same regardless of whatever happens during macro expansion. */ - def enclosingMacros: List[BlackboxContext] + def enclosingMacros: List[blackbox.Context] /** Tries to guess a position for the enclosing application. * But that is simple, right? Just dereference `pos` of `macroApplication`? Not really. @@ -40,46 +52,62 @@ trait Enclosures { def enclosingPosition: Position /** Tree that corresponds to the enclosing method, or EmptyTree if not applicable. + * @see [[scala.reflect.macros.Enclosures]] */ - @deprecated("Use enclosingDef instead, but be wary of changes in semantics", "2.10.1") + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingMethod: Tree /** Tree that corresponds to the enclosing class, or EmptyTree if not applicable. + * @see [[scala.reflect.macros.Enclosures]] */ - @deprecated("Use enclosingImpl instead, but be wary of changes in semantics", "2.10.1") + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingClass: Tree /** Tree that corresponds to the enclosing DefDef tree. * Throws `EnclosureException` if there's no such enclosing tree. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingDef: universe.DefDef /** Tree that corresponds to the enclosing Template tree. * Throws `EnclosureException` if there's no such enclosing tree. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingTemplate: universe.Template /** Tree that corresponds to the enclosing ImplDef tree (i.e. either ClassDef or ModuleDef). * Throws `EnclosureException` if there's no such enclosing tree. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingImpl: universe.ImplDef /** Tree that corresponds to the enclosing PackageDef tree. * Throws `EnclosureException` if there's no such enclosing tree. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingPackage: universe.PackageDef /** Compilation unit that contains this macro application. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingUnit: CompilationUnit /** Compilation run that contains this macro application. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def enclosingRun: Run /** Indicates than one of the enclosure methods failed to find a tree * of required type among enclosing trees. + * @see [[scala.reflect.macros.Enclosures]] */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") case class EnclosureException(expected: Class[_], enclosingTrees: List[Tree]) extends Exception(s"Couldn't find a tree of type $expected among enclosing trees $enclosingTrees") } diff --git a/src/reflect/scala/reflect/macros/Evals.scala b/src/reflect/scala/reflect/macros/Evals.scala index eb37e83cad..68e07dd319 100644 --- a/src/reflect/scala/reflect/macros/Evals.scala +++ b/src/reflect/scala/reflect/macros/Evals.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that provides + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that provides * a facility to evaluate trees. */ trait Evals { - self: BlackboxContext => + self: blackbox.Context => /** Takes a typed wrapper for a tree of type `T` and evaluates it to a value of type `T`. * @@ -17,16 +17,16 @@ trait Evals { * permitted by the shape of the arguments. * * Known issues: because of [[https://issues.scala-lang.org/browse/SI-5748 https://issues.scala-lang.org/browse/SI-5748]] - * trees being evaluated first need to undergo `resetAllAttrs`. Resetting symbols and types + * trees being evaluated first need to undergo `untypecheck`. Resetting symbols and types * mutates the tree in place, therefore the conventional approach is to `duplicate` the tree first. * * {{{ - * scala> def impl(c: BlackboxContext)(x: c.Expr[String]) = { - * | val x1 = c.Expr[String](c.resetAllAttrs(x.tree.duplicate)) - * | println(s"compile-time value is: \${c.eval(x1)}") + * scala> def impl(c: Context)(x: c.Expr[String]) = { + * | val x1 = c.Expr[String](c.untypecheck(x.tree.duplicate)) + * | println(s"compile-time value is: ${c.eval(x1)}") * | x * | } - * impl: (c: BlackboxContext)(x: c.Expr[String])c.Expr[String] + * impl: (c: Context)(x: c.Expr[String])c.Expr[String] * * scala> def test(x: String) = macro impl * test: (x: String)String diff --git a/src/reflect/scala/reflect/macros/ExprUtils.scala b/src/reflect/scala/reflect/macros/ExprUtils.scala index 58b61e446a..c438653c92 100644 --- a/src/reflect/scala/reflect/macros/ExprUtils.scala +++ b/src/reflect/scala/reflect/macros/ExprUtils.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that defines shorthands for the + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that defines shorthands for the * most common `Expr`-creating functions. */ trait ExprUtils { - self: BlackboxContext => + self: blackbox.Context => /** Shorthand for `Literal(Constant(null))` in the underlying `universe`. */ @deprecated("Use quasiquotes instead", "2.11.0") diff --git a/src/reflect/scala/reflect/macros/FrontEnds.scala b/src/reflect/scala/reflect/macros/FrontEnds.scala index 3a910d89ad..a770f325b2 100644 --- a/src/reflect/scala/reflect/macros/FrontEnds.scala +++ b/src/reflect/scala/reflect/macros/FrontEnds.scala @@ -5,12 +5,12 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that * provides facilities to communicate with the compiler's front end * (emit warnings, errors and other sorts of messages). */ trait FrontEnds { - self: BlackboxContext => + self: blackbox.Context => /** For sending a message which should not be labeled as a warning/error, * but also shouldn't require -verbose to be visible. diff --git a/src/reflect/scala/reflect/macros/Infrastructure.scala b/src/reflect/scala/reflect/macros/Infrastructure.scala index b6585f94d2..0f2d9ce4cf 100644 --- a/src/reflect/scala/reflect/macros/Infrastructure.scala +++ b/src/reflect/scala/reflect/macros/Infrastructure.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that * provides facilities to communicate with the compiler's infrastructure. */ trait Infrastructure { - self: BlackboxContext => + self: blackbox.Context => /** Exposes macro-specific settings as a list of strings. * These settings are passed to the compiler via the "-Xmacro-settings:setting1,setting2...,settingN" command-line option. diff --git a/src/reflect/scala/reflect/macros/Names.scala b/src/reflect/scala/reflect/macros/Names.scala index 6bd3e1a199..4f3448e1ed 100644 --- a/src/reflect/scala/reflect/macros/Names.scala +++ b/src/reflect/scala/reflect/macros/Names.scala @@ -5,34 +5,52 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that - * provides functions that generate unique names. + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that + * provides functions that generate fresh names. + * + * In the current implementation, fresh names are more or less unique in the sense that + * within the same compilation run they are guaranteed not to clash with: + * 1) Results of past and future invocations of functions of `freshName` family + * 2) User-defined or macro-generated names that don't contain dollar symbols + * 3) Macro-generated names that are created by concatenating names from the first, second and third categories + * + * Uniqueness of fresh names across compilation runs is not guaranteed, but that's something + * that we would like to improve upon in future releases. See [[https://issues.scala-lang.org/browse/SI-6879]] for more information. + * + * @define freshNameNoParams + * Creates a string that represents a more or less unique name. + * Consult [[scala.reflect.macros.Names]] for more information on uniqueness of such names. + * + * @define freshNameStringParam + * Creates a string that represents a more or less unique name having a given prefix. + * Consult [[scala.reflect.macros.Names]] for more information on uniqueness of such names. + * + * @define freshNameNameParam + * Creates a more or less unique name having a given name as a prefix and + * having the same flavor (term name or type name) as the given name. + * Consult [[scala.reflect.macros.Names]] for more information on uniqueness of such names. */ trait Names { - self: BlackboxContext => + self: blackbox.Context => - /** Creates a unique string. */ + /** $freshNameNoParams */ @deprecated("Use freshName instead", "2.11.0") def fresh(): String - /** Creates a unique string having a given prefix. */ + /** $freshNameStringParam */ @deprecated("Use freshName instead", "2.11.0") def fresh(name: String): String - /** Creates a unique name having a given name as a prefix and - * having the same flavor (term name or type name) as the given name. - */ + /** $freshNameNameParam */ @deprecated("Use freshName instead", "2.11.0") def fresh[NameType <: Name](name: NameType): NameType - /** Creates a unique string. */ + /** $freshNameNoParams */ def freshName(): String - /** Creates a unique string having a given prefix. */ + /** $freshNameStringParam */ def freshName(name: String): String - /** Creates a unique name having a given name as a prefix and - * having the same flavor (term name or type name) as the given name. - */ + /** $freshNameNameParam */ def freshName[NameType <: Name](name: NameType): NameType } diff --git a/src/reflect/scala/reflect/macros/Parsers.scala b/src/reflect/scala/reflect/macros/Parsers.scala index 9d4a7e2953..720b754649 100644 --- a/src/reflect/scala/reflect/macros/Parsers.scala +++ b/src/reflect/scala/reflect/macros/Parsers.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that * exposes functions to parse strings with Scala code into trees. */ trait Parsers { - self: BlackboxContext => + self: blackbox.Context => /** Parses a string with a Scala expression into an abstract syntax tree. * Only works for expressions, i.e. parsing a package declaration will fail. diff --git a/src/reflect/scala/reflect/macros/Reifiers.scala b/src/reflect/scala/reflect/macros/Reifiers.scala index 67d10dc10a..ff1f7a3b28 100644 --- a/src/reflect/scala/reflect/macros/Reifiers.scala +++ b/src/reflect/scala/reflect/macros/Reifiers.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that * exposes functions to save reflection artifacts for runtime. */ trait Reifiers { - self: BlackboxContext => + self: blackbox.Context => /** Given a tree, generate a tree that when compiled and executed produces the original tree. * For more information and examples see the documentation for `Universe.reify`. diff --git a/src/reflect/scala/reflect/macros/Typers.scala b/src/reflect/scala/reflect/macros/Typers.scala index 5a25801335..6c077de1d2 100644 --- a/src/reflect/scala/reflect/macros/Typers.scala +++ b/src/reflect/scala/reflect/macros/Typers.scala @@ -5,11 +5,11 @@ package macros /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> * - * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that + * A slice of [[scala.reflect.macros.blackbox.Context the Scala macros context]] that * partially exposes the type checker to macro writers. */ trait Typers { - self: BlackboxContext => + self: blackbox.Context => /** Contexts that represent macros in-flight, including the current one. Very much like a stack trace, but for macros only. * Can be useful for interoperating with other macros and for imposing compiler-friendly limits on macro expansion. @@ -21,7 +21,7 @@ trait Typers { * Unlike `enclosingMacros`, this is a def, which means that it gets recalculated on every invocation, * so it might change depending on what is going on during macro expansion. */ - def openMacros: List[BlackboxContext] + def openMacros: List[blackbox.Context] /** @see `Typers.typecheck` */ @@ -68,19 +68,27 @@ trait Typers { */ def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree - /** Recursively resets symbols and types in a given tree. - * - * Note that this does not revert the tree to its pre-typer shape. - * For more info, read up https://issues.scala-lang.org/browse/SI-5464. + /** Recursively resets locally defined symbols and types in a given tree. + * WARNING: Don't use this API, go for [[untypecheck]] instead. */ - def resetAllAttrs(tree: Tree): Tree + @deprecated("Use `c.untypecheck` instead", "2.11.0") + def resetLocalAttrs(tree: Tree): Tree - /** Recursively resets locally defined symbols and types in a given tree. + /** In the current implementation of Scala's reflection API, untyped trees (also known as parser trees or unattributed trees) + * are observationally different from typed trees (also known as typer trees, typechecked trees or attributed trees), * - * Note that this does not revert the tree to its pre-typer shape. - * For more info, read up https://issues.scala-lang.org/browse/SI-5464. + * Usually, if some compiler API takes a tree, then both untyped and typed trees will do. However in some cases, + * only untyped or only typed trees are appropriate. For example, [[eval]] only accepts untyped trees and one can only splice + * typed trees inside typed trees. Therefore in the current reflection API, there is a need in functions + * that go back and forth between untyped and typed trees. For this we have [[typecheck]] and `untypecheck`. + * + * Note that `untypecheck` is currently afflicted by https://issues.scala-lang.org/browse/SI-5464, + * which makes it sometimes corrupt trees so that they don't make sense anymore. Unfortunately, there's no workaround for that. + * We plan to fix this issue soon, but for now please keep it in mind. + * + * @see [[http://stackoverflow.com/questions/20936509/scala-macros-what-is-the-difference-between-typed-aka-typechecked-an-untyped]] */ - def resetLocalAttrs(tree: Tree): Tree + def untypecheck(tree: Tree): Tree } /** Indicates an error during one of the methods in [[scala.reflect.macros.Typers]]. diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index 297bac2999..bc5c8b2840 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -122,7 +122,7 @@ abstract class Universe extends scala.reflect.api.Universe { def setType(tp: Type): Tree /** Like `setType`, but if this is a previously empty TypeTree that - * fact is remembered so that resetAllAttrs will snap back. + * fact is remembered so that `untypecheck` will snap back. * * \@PP: Attempting to elaborate on the above, I find: If defineType * is called on a TypeTree whose type field is null or NoType, @@ -130,7 +130,8 @@ abstract class Universe extends scala.reflect.api.Universe { * ResetAttrsTraverser, which nulls out the type field of TypeTrees * for which wasEmpty is true, leaving the others alone. * - * resetAllAttrs is used in situations where some speculative + * `untypecheck` (or `resetAttrs` in compiler parlance) is used + * in situations where some speculative * typing of a tree takes place, fails, and the tree needs to be * returned to its former state to try again. So according to me: * using `defineType` instead of `setType` is how you communicate @@ -197,34 +198,44 @@ abstract class Universe extends scala.reflect.api.Universe { def capturedVariableType(vble: Symbol): Type /** The type of compilation runs. + * @see [[scala.reflect.macros.Enclosures]] * @template * @group Macros */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") type Run <: RunContextApi /** Compilation run uniquely identifies current invocation of the compiler * (e.g. can be used to implement per-run caches for macros) and provides access to units of work * of the invocation (currently processed unit of work and the list of all units). + * @see [[scala.reflect.macros.Enclosures]] * @group API */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") trait RunContextApi { /** Currently processed unit of work (a real or a virtual file). */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def currentUnit: CompilationUnit /** All units of work comprising this compilation run. */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def units: Iterator[CompilationUnit] } /** The type of compilation units. + * @see [[scala.reflect.macros.Enclosures]] * @template * @group Macros */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") type CompilationUnit <: CompilationUnitContextApi /** Compilation unit describes a unit of work of the compilation run. * It provides such information as file name, textual representation of the unit and the underlying AST. + * @see [[scala.reflect.macros.Enclosures]] * @group API */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") trait CompilationUnitContextApi { /** Source file corresponding to this compilation unit. * @@ -235,9 +246,11 @@ abstract class Universe extends scala.reflect.api.Universe { * It should not be used unless you know what you are doing. In subsequent releases, this API will be refined * and exposed as a part of scala.reflect.api. */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def source: scala.reflect.internal.util.SourceFile /** The AST that corresponds to this compilation unit. */ + @deprecated("c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information", "2.11.0") def body: Tree } } diff --git a/src/reflect/scala/reflect/macros/WhiteboxMacro.scala b/src/reflect/scala/reflect/macros/WhiteboxMacro.scala deleted file mode 100644 index 1c581313eb..0000000000 --- a/src/reflect/scala/reflect/macros/WhiteboxMacro.scala +++ /dev/null @@ -1,36 +0,0 @@ -package scala.reflect -package macros - -/** - * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> - * - * Traditionally macro implementations are defined as methods, - * but this trait provides an alternative way of encoding macro impls as - * bundles, traits which extend `scala.reflect.macros.BlackboxMacro` or`scala.reflect.macros.WhiteboxMacro` . - * - * Instead of: - * - * def impl[T: c.WeakTypeTag](c: WhiteboxContext)(x: c.Expr[Int]) = ... - * - * One can write: - * - * trait Impl extends WhiteboxMacro { - * def apply[T: c.WeakTypeTag](x: c.Expr[Int]) = ... - * } - * - * Without changing anything else at all. - * - * This language feature is useful in itself in cases when macro implementations - * are complex and need to be modularized. State of the art technique of addressing this need is quite heavyweight: - * http://docs.scala-lang.org/overviews/macros/overview.html#writing_bigger_macros. - * - * @see `scala.reflect.macros.BlackboxMacro` - */ -trait WhiteboxMacro { - /** The context to be used by the macro implementation. - * - * Vanilla macro implementations have to carry it in their signatures, however when a macro is a full-fledged module, - * it can define the context next to the implementation, makes implementation signature more lightweight. - */ - val c: WhiteboxContext -} diff --git a/src/reflect/scala/reflect/macros/BlackboxContext.scala b/src/reflect/scala/reflect/macros/blackbox/Context.scala index 2c77289866..05d9595c3a 100644 --- a/src/reflect/scala/reflect/macros/BlackboxContext.scala +++ b/src/reflect/scala/reflect/macros/blackbox/Context.scala @@ -1,6 +1,7 @@ package scala package reflect package macros +package blackbox /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> @@ -24,24 +25,24 @@ package macros * enclosing trees and compilation units, evaluating trees, logging warnings/errors and much more. * Refer to the documentation of top-level traits in this package to learn the details. * - * If a macro def refers to a macro impl that uses `BlackboxContext`, then this macro def becomes a blackbox macro, + * If a macro def refers to a macro impl that uses `blackbox.Context`, then this macro def becomes a blackbox macro, * which means that its expansion will be upcast to its return type, enforcing faithfullness of that macro to its - * type signature. Whitebox macros, i.e. the ones defined with `WhiteboxContext`, aren't bound by this restriction, + * type signature. Whitebox macros, i.e. the ones defined with `whitebox.Context`, aren't bound by this restriction, * which enables a number of important use cases, but they are also going to enjoy less support than blackbox macros, * so choose wisely. See the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]] for more information. * - * @see `scala.reflect.macros.WhiteboxContext` + * @see `scala.reflect.macros.whitebox.Context` */ -trait BlackboxContext extends Aliases - with Enclosures - with Names - with Reifiers - with FrontEnds - with Infrastructure - with Typers - with Parsers - with Evals - with ExprUtils { +trait Context extends Aliases + with Enclosures + with Names + with Reifiers + with FrontEnds + with Infrastructure + with Typers + with Parsers + with Evals + with ExprUtils { /** The compile-time universe. */ val universe: Universe @@ -63,7 +64,7 @@ trait BlackboxContext extends Aliases * scala> class Coll[T] { * | def filter(p: T => Boolean): Coll[T] = macro M.filter[T] * | }; object M { - * | def filter[T](c: BlackboxContext { type PrefixType = Coll[T] }) + * | def filter[T](c: Context { type PrefixType = Coll[T] }) * | (p: c.Expr[T => Boolean]): c.Expr[Coll[T]] = * | { * | println(c.prefix.tree) diff --git a/src/reflect/scala/reflect/macros/package.scala b/src/reflect/scala/reflect/macros/package.scala index 6a8434a163..cc7111d794 100644 --- a/src/reflect/scala/reflect/macros/package.scala +++ b/src/reflect/scala/reflect/macros/package.scala @@ -19,10 +19,10 @@ package object macros { * with the former being better supported and the latter being more powerful. You can read about * the details of the split and the associated trade-offs in the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]]. * - * `scala.reflect.macros.Context` follows this tendency and turns into `scala.reflect.macros.BlackboxContext` - * and `scala.reflect.macros.WhiteboxContext`. The original `Context` is left in place for compatibility reasons, + * `scala.reflect.macros.Context` follows this tendency and turns into `scala.reflect.macros.blackbox.Context` + * and `scala.reflect.macros.whitebox.Context`. The original `Context` is left in place for compatibility reasons, * but it is now deprecated, nudging the users to choose between blackbox and whitebox macros. */ - @deprecated("Use BlackboxContext or WhiteboxContext instead", "2.11.0") - type Context = WhiteboxContext + @deprecated("Use blackbox.Context or whitebox.Context instead", "2.11.0") + type Context = whitebox.Context }
\ No newline at end of file diff --git a/src/reflect/scala/reflect/macros/WhiteboxContext.scala b/src/reflect/scala/reflect/macros/whitebox/Context.scala index 9d65a5c16e..bd48df46cc 100644 --- a/src/reflect/scala/reflect/macros/WhiteboxContext.scala +++ b/src/reflect/scala/reflect/macros/whitebox/Context.scala @@ -1,6 +1,7 @@ package scala package reflect package macros +package whitebox /** * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span> @@ -24,22 +25,22 @@ package macros * enclosing trees and compilation units, evaluating trees, logging warnings/errors and much more. * Refer to the documentation of top-level traits in this package to learn the details. * - * If a macro def refers to a macro impl that uses `WhiteboxContext`, then this macro def becomes a whitebox macro, + * If a macro def refers to a macro impl that uses `whitebox.Context`, then this macro def becomes a whitebox macro, * gaining the ability to refine the type of its expansion beyond its official return type, which enables a number of important use cases. - * Blackbox macros, i.e. the ones defined with `BlackboxContext`, can't do that, so they are less powerful. + * Blackbox macros, i.e. the ones defined with `blackbox.Context`, can't do that, so they are less powerful. * However blackbox macros are also going to enjoy better support than whitebox macros, so choose wisely. * See the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]] for more information. * - * @see `scala.reflect.macros.BlackboxContext` + * @see `scala.reflect.macros.blackbox.Context` */ -trait WhiteboxContext extends BlackboxContext { +trait Context extends blackbox.Context { /** @inheritdoc */ - def openMacros: List[WhiteboxContext] + def openMacros: List[Context] /** @inheritdoc */ - def enclosingMacros: List[WhiteboxContext] + def enclosingMacros: List[Context] /** Information about one of the currently considered implicit candidates. * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters, diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 7cc5176507..bc95b839b7 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -16,7 +16,7 @@ import java.io.IOException import scala.reflect.internal.{ MissingRequirementError, JavaAccFlags, JMethodOrConstructor } import internal.pickling.ByteCodecs import internal.pickling.UnPickler -import scala.collection.mutable.{ HashMap, ListBuffer } +import scala.collection.mutable.{ HashMap, ListBuffer, ArrayBuffer } import internal.Flags._ import ReflectionUtils._ import scala.language.existentials @@ -42,7 +42,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni // overriden by ReflectGlobal def rootClassLoader: ClassLoader = this.getClass.getClassLoader - trait JavaClassCompleter extends FlagAssigningCompleter + trait JavaClassCompleter def runtimeMirror(cl: ClassLoader): Mirror = gilSynchronized { mirrors get cl match { @@ -63,10 +63,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private[reflect] lazy val runDefinitions = new definitions.RunDefinitions // only one "run" in the reflection universe import runDefinitions._ - override lazy val RootPackage = new RootPackage with SynchronizedTermSymbol - override lazy val RootClass = new RootClass with SynchronizedModuleClassSymbol - override lazy val EmptyPackage = new EmptyPackage with SynchronizedTermSymbol - override lazy val EmptyPackageClass = new EmptyPackageClass with SynchronizedModuleClassSymbol + override lazy val RootPackage = (new RootPackage with SynchronizedTermSymbol).markFlagsCompleted(mask = AllFlags) + override lazy val RootClass = (new RootClass with SynchronizedModuleClassSymbol).markFlagsCompleted(mask = AllFlags) + override lazy val EmptyPackage = (new EmptyPackage with SynchronizedTermSymbol).markFlagsCompleted(mask = AllFlags) + override lazy val EmptyPackageClass = (new EmptyPackageClass with SynchronizedModuleClassSymbol).markFlagsCompleted(mask = AllFlags) /** The lazy type for root. */ @@ -118,15 +118,16 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private def abort(msg: String) = throw new ScalaReflectionException(msg) - private def ErrorInnerClass(sym: Symbol) = abort(s"$sym is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror") - private def ErrorInnerModule(sym: Symbol) = abort(s"$sym is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror") - private def ErrorStaticClass(sym: Symbol) = abort(s"$sym is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror") - private def ErrorStaticModule(sym: Symbol) = abort(s"$sym is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror") - private def ErrorNotMember(sym: Symbol, owner: Symbol) = abort(s"expected a member of $owner, you provided ${sym.kindString} ${sym.fullName}") - private def ErrorNotField(sym: Symbol) = abort(s"expected a field or an accessor method symbol, you provided $sym") - private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = abort(s"expected a constructor of $owner, you provided $sym") - private def ErrorFree(member: Symbol, freeType: Symbol) = abort(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}") - private def ErrorNonExistentField(sym: Symbol) = abort( + private def ErrorInnerClass(sym: Symbol) = abort(s"$sym is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror") + private def ErrorInnerModule(sym: Symbol) = abort(s"$sym is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror") + private def ErrorStaticClass(sym: Symbol) = abort(s"$sym is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror") + private def ErrorStaticModule(sym: Symbol) = abort(s"$sym is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror") + private def ErrorNotMember(sym: Symbol, owner: Symbol) = abort(s"expected a member of $owner, you provided ${sym.kindString} ${sym.fullName}") + private def ErrorNotField(sym: Symbol) = abort(s"expected a field or an accessor method symbol, you provided $sym") + private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = abort(s"expected a constructor of $owner, you provided $sym") + private def ErrorArrayConstructor(sym: Symbol, owner: Symbol) = abort(s"Cannot instantiate arrays with mirrors. Consider using `scala.reflect.ClassTag(<class of element>).newArray(<length>)` instead") + private def ErrorFree(member: Symbol, freeType: Symbol) = abort(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}") + private def ErrorNonExistentField(sym: Symbol) = abort( sm"""Scala field ${sym.name} isn't represented as a Java field, neither it has a Java accessor method |note that private parameters of class constructors don't get mapped onto fields and/or accessors, |unless they are used outside of their declaring constructors.""") @@ -221,6 +222,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private def checkConstructorOf(sym: Symbol, owner: ClassSymbol) { if (!sym.isClassConstructor) ErrorNotConstructor(sym, owner) + if (owner == ArrayClass) ErrorArrayConstructor(sym, owner) ensuringNotFree(sym) { if (!owner.info.decls.toList.contains(sym)) ErrorNotConstructor(sym, owner) } @@ -247,7 +249,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni } def reflectMethod(method: MethodSymbol): MethodMirror = { checkMemberOf(method, symbol) - mkJavaMethodMirror(instance, method) + mkMethodMirror(instance, method) } def reflectClass(cls: ClassSymbol): ClassMirror = { if (cls.isStatic) ErrorStaticClass(cls) @@ -262,16 +264,35 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni override def toString = s"instance mirror for $instance" } - private class JavaFieldMirror(val receiver: Any, val symbol: TermSymbol) + // caches value class metadata, so that we minimize the work that needs to be done during Mirror.apply + private class DerivedValueClassMetadata(info: Type) { + val symbol = info.typeSymbol + val isDerivedValueClass = symbol.isDerivedValueClass + lazy val boxer = runtimeClass(symbol.toType).getDeclaredConstructors().head + lazy val unboxer = { + val fields @ (field :: _) = symbol.toType.declarations.collect{ case ts: TermSymbol if ts.isParamAccessor && ts.isMethod => ts }.toList + assert(fields.length == 1, s"$symbol: $fields") + runtimeClass(symbol.asClass).getDeclaredMethod(field.name.toString) + } + } + + private class JavaFieldMirror(val receiver: Any, val symbol: TermSymbol, metadata: DerivedValueClassMetadata) extends FieldMirror { + def this(receiver: Any, symbol: TermSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.info)) + def bind(newReceiver: Any) = new JavaFieldMirror(newReceiver, symbol, metadata) + import metadata._ + lazy val jfield = ensureAccessible(fieldToJava(symbol)) - def get = jfield get receiver + def get = { + val value = jfield get receiver + if (isDerivedValueClass) boxer.newInstance(value) else value + } def set(value: Any) = { // it appears useful to be able to set values of vals, therefore I'm disabling this check // if (!symbol.isMutable) ErrorSetImmutableField(symbol) - jfield.set(receiver, value) + jfield.set(receiver, if (isDerivedValueClass) unboxer.invoke(value) else value) } - def bind(newReceiver: Any) = new JavaFieldMirror(newReceiver, symbol) + override def toString = s"field mirror for ${symbol.fullName} (bound to $receiver)" } @@ -312,13 +333,17 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni bytecodelessMethodOwners(meth.owner) && !bytecodefulObjectMethods(meth) } + private def isByNameParam(p: Type) = isByNameParamType(p) + private def isValueClassParam(p: Type) = p.typeSymbol.isDerivedValueClass + // unlike other mirrors, method mirrors are created by a factory // that's because we want to have decent performance // therefore we move special cases into separate subclasses // rather than have them on a hot path them in a unified implementation of the `apply` method - private def mkJavaMethodMirror[T: ClassTag](receiver: T, symbol: MethodSymbol): JavaMethodMirror = { - if (isBytecodelessMethod(symbol)) new JavaBytecodelessMethodMirror(receiver, symbol) - else if (symbol.paramss.flatten exists (p => isByNameParamType(p.info))) new JavaByNameMethodMirror(receiver, symbol) + private def mkMethodMirror[T: ClassTag](receiver: T, symbol: MethodSymbol): MethodMirror = { + def existsParam(pred: Type => Boolean) = symbol.paramss.flatten.map(_.info).exists(pred) + if (isBytecodelessMethod(symbol)) new BytecodelessMethodMirror(receiver, symbol) + else if (existsParam(isByNameParam) || existsParam(isValueClassParam)) new JavaTransformingMethodMirror(receiver, symbol) else { symbol.paramss.flatten.length match { case 0 => new JavaVanillaMethodMirror0(receiver, symbol) @@ -330,68 +355,123 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni } } } - private abstract class JavaMethodMirror(val symbol: MethodSymbol) extends MethodMirror { + + private abstract class JavaMethodMirror(val symbol: MethodSymbol, protected val ret: DerivedValueClassMetadata) extends MethodMirror { lazy val jmeth = ensureAccessible(methodToJava(symbol)) - def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*) + lazy val jconstr = ensureAccessible(constructorToJava(symbol)) - def jinvoke(jmeth: jMethod, receiver: Any, args: Seq[Any]): Any = { - val result = jinvokeraw(jmeth, receiver, args) - if (jmeth.getReturnType == java.lang.Void.TYPE) () + def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*) + else if (receiver == null) jconstr.newInstance(args.asInstanceOf[Seq[AnyRef]]: _*) + else jconstr.newInstance((receiver +: args).asInstanceOf[Seq[AnyRef]]: _*) + def jinvoke(args: Seq[Any]): Any = { + val result = jinvokeraw(args) + if (!symbol.isConstructor && jmeth.getReturnType == java.lang.Void.TYPE) () + else if (!symbol.isConstructor && ret.isDerivedValueClass) ret.boxer.newInstance(result.asInstanceOf[AnyRef]) else result } - override def toString = s"method mirror for ${showMethodSig(symbol)} (bound to $receiver)" - } - - private class JavaVanillaMethodMirror(val receiver: Any, symbol: MethodSymbol) - extends JavaMethodMirror(symbol) { - def bind(newReceiver: Any) = new JavaVanillaMethodMirror(newReceiver, symbol) - def apply(args: Any*): Any = jinvoke(jmeth, receiver, args) - } - - private class JavaVanillaMethodMirror0(receiver: Any, symbol: MethodSymbol) - extends JavaVanillaMethodMirror(receiver, symbol) { - override def bind(newReceiver: Any) = new JavaVanillaMethodMirror0(newReceiver, symbol) - override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver) - } - - private class JavaVanillaMethodMirror1(receiver: Any, symbol: MethodSymbol) - extends JavaVanillaMethodMirror(receiver, symbol) { - override def bind(newReceiver: Any) = new JavaVanillaMethodMirror1(newReceiver, symbol) - override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef]) - } - - private class JavaVanillaMethodMirror2(receiver: Any, symbol: MethodSymbol) - extends JavaVanillaMethodMirror(receiver, symbol) { - override def bind(newReceiver: Any) = new JavaVanillaMethodMirror2(newReceiver, symbol) - override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef]) - } - - private class JavaVanillaMethodMirror3(receiver: Any, symbol: MethodSymbol) - extends JavaVanillaMethodMirror(receiver, symbol) { - override def bind(newReceiver: Any) = new JavaVanillaMethodMirror3(newReceiver, symbol) - override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef]) + override def toString = { + val what = if (symbol.isConstructor) "constructor mirror" else "method mirror" + s"$what for ${showMethodSig(symbol)} (bound to $receiver)" + } } - private class JavaVanillaMethodMirror4(receiver: Any, symbol: MethodSymbol) - extends JavaVanillaMethodMirror(receiver, symbol) { - override def bind(newReceiver: Any) = new JavaVanillaMethodMirror4(newReceiver, symbol) - override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef]) - } + private class JavaVanillaMethodMirror(val receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaMethodMirror(symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + def bind(newReceiver: Any) = new JavaVanillaMethodMirror(newReceiver, symbol, ret) + def apply(args: Any*): Any = jinvoke(args) + } + + private class JavaVanillaMethodMirror0(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaVanillaMethodMirror(receiver, symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + override def bind(newReceiver: Any) = new JavaVanillaMethodMirror0(newReceiver, symbol, ret) + override def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver) + else if (receiver == null) jconstr.newInstance() + else jconstr.newInstance(receiver.asInstanceOf[AnyRef]) + } + + private class JavaVanillaMethodMirror1(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaVanillaMethodMirror(receiver, symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + override def bind(newReceiver: Any) = new JavaVanillaMethodMirror1(newReceiver, symbol, ret) + override def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef]) + else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef]) + else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef]) + } + + private class JavaVanillaMethodMirror2(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaVanillaMethodMirror(receiver, symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + override def bind(newReceiver: Any) = new JavaVanillaMethodMirror2(newReceiver, symbol, ret) + override def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef]) + else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef]) + else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef]) + } + + private class JavaVanillaMethodMirror3(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaVanillaMethodMirror(receiver, symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + override def bind(newReceiver: Any) = new JavaVanillaMethodMirror3(newReceiver, symbol, ret) + override def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef]) + else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef]) + else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef]) + } + + private class JavaVanillaMethodMirror4(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata) + extends JavaVanillaMethodMirror(receiver, symbol, ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType)) + override def bind(newReceiver: Any) = new JavaVanillaMethodMirror4(newReceiver, symbol, ret) + override def jinvokeraw(args: Seq[Any]) = + if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef]) + else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef]) + else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef]) + } + + // caches MethodSymbol metadata, so that we minimize the work that needs to be done during Mirror.apply + // TODO: vararg is only supported in the last parameter list (SI-6182), so we don't need to worry about the rest for now + private class MethodMetadata(symbol: MethodSymbol) { + private val params = symbol.paramss.flatten.toArray + private val vcMetadata = params.map(p => new DerivedValueClassMetadata(p.info)) + val isByName = params.map(p => isByNameParam(p.info)) + def isDerivedValueClass(i: Int) = vcMetadata(i).isDerivedValueClass + def paramUnboxers(i: Int) = vcMetadata(i).unboxer + val paramCount = params.length + val ret = new DerivedValueClassMetadata(symbol.returnType) + } + + private class JavaTransformingMethodMirror(val receiver: Any, symbol: MethodSymbol, metadata: MethodMetadata) + extends JavaMethodMirror(symbol, metadata.ret) { + def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new MethodMetadata(symbol)) + override def bind(newReceiver: Any) = new JavaTransformingMethodMirror(newReceiver, symbol, metadata) + import metadata._ - private class JavaByNameMethodMirror(val receiver: Any, symbol: MethodSymbol) - extends JavaMethodMirror(symbol) { - def bind(newReceiver: Any) = new JavaByNameMethodMirror(newReceiver, symbol) def apply(args: Any*): Any = { - val transformed = map2(args.toList, symbol.paramss.flatten)((arg, param) => if (isByNameParamType(param.info)) () => arg else arg) - jinvoke(jmeth, receiver, transformed) + val args1 = new Array[Any](args.length) + var i = 0 + while (i < args1.length) { + val arg = args(i) + if (i >= paramCount) args1(i) = arg // don't transform varargs + else if (isByName(i)) args1(i) = () => arg // don't transform by-name value class params + else if (isDerivedValueClass(i)) args1(i) = paramUnboxers(i).invoke(arg) + i += 1 + } + jinvoke(args1) } } - private class JavaBytecodelessMethodMirror[T: ClassTag](val receiver: T, symbol: MethodSymbol) - extends JavaMethodMirror(symbol) { - def bind(newReceiver: Any) = new JavaBytecodelessMethodMirror(newReceiver.asInstanceOf[T], symbol) - def apply(args: Any*): Any = { + private class BytecodelessMethodMirror[T: ClassTag](val receiver: T, val symbol: MethodSymbol) + extends MethodMirror { + def bind(newReceiver: Any) = new BytecodelessMethodMirror(newReceiver.asInstanceOf[T], symbol) + override def toString = s"bytecodeless method mirror for ${showMethodSig(symbol)} (bound to $receiver)" + + def apply(args: Any*): Any = { // checking type conformance is too much of a hassle, so we don't do it here // actually it's not even necessary, because we manually dispatch arguments below val params = symbol.paramss.flatten @@ -414,7 +494,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni def invokePrimitiveMethod = { val jmeths = classOf[BoxesRunTime].getDeclaredMethods.filter(_.getName == nme.primitiveMethodName(symbol.name).toString) assert(jmeths.length == 1, jmeths.toList) - jinvoke(jmeths.head, null, objReceiver +: objArgs) + val jmeth = jmeths.head + val result = jmeth.invoke(null, (objReceiver +: objArgs).asInstanceOf[Seq[AnyRef]]: _*) + if (jmeth.getReturnType == java.lang.Void.TYPE) () + else result } symbol match { @@ -445,23 +528,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni } } - private class JavaConstructorMirror(val outer: AnyRef, val symbol: MethodSymbol) - extends MethodMirror { - def bind(newReceiver: Any) = new JavaConstructorMirror(newReceiver.asInstanceOf[AnyRef], symbol) - override val receiver = outer - lazy val jconstr = ensureAccessible(constructorToJava(symbol)) - def apply(args: Any*): Any = { - if (symbol.owner == ArrayClass) - abort("Cannot instantiate arrays with mirrors. Consider using `scala.reflect.ClassTag(<class of element>).newArray(<length>)` instead") - - val effectiveArgs = - if (outer == null) args.asInstanceOf[Seq[AnyRef]] - else outer +: args.asInstanceOf[Seq[AnyRef]] - jconstr.newInstance(effectiveArgs: _*) - } - override def toString = s"constructor mirror for ${showMethodSig(symbol)} (bound to $outer)" - } - private abstract class JavaTemplateMirror extends TemplateMirror { def outer: AnyRef @@ -474,7 +540,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni def isStatic = false def reflectConstructor(constructor: MethodSymbol) = { checkConstructorOf(constructor, symbol) - new JavaConstructorMirror(outer, constructor) + mkMethodMirror(outer, constructor) } override def toString = s"class mirror for ${symbol.fullName} (bound to $outer)" } @@ -575,6 +641,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni val bytes = ssig.getBytes val len = ByteCodecs.decode(bytes) unpickler.unpickle(bytes take len, 0, clazz, module, jclazz.getName) + markAllCompleted(clazz, module) case None => loadBytes[Array[String]]("scala.reflect.ScalaLongSignature") match { case Some(slsig) => @@ -583,6 +650,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni val len = ByteCodecs.decode(encoded) val decoded = encoded.take(len) unpickler.unpickle(decoded, 0, clazz, module, jclazz.getName) + markAllCompleted(clazz, module) case None => // class does not have a Scala signature; it's a Java class info("translating reflection info for Java " + jclazz) //debug @@ -605,6 +673,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private def createTypeParameter(jtvar: jTypeVariable[_ <: GenericDeclaration]): TypeSymbol = { val tparam = sOwner(jtvar).newTypeParameter(newTypeName(jtvar.getName)) .setInfo(new TypeParamCompleter(jtvar)) + markFlagsCompleted(tparam)(mask = AllFlags) tparamCache enter (jtvar, tparam) tparam } @@ -617,6 +686,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni override def load(sym: Symbol) = complete(sym) override def complete(sym: Symbol) = { sym setInfo TypeBounds.upper(glb(jtvar.getBounds.toList map typeToScala map objToAny)) + markAllCompleted(sym) } } @@ -655,7 +725,16 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni * @param module The Scala companion object for which info is copied * @param jclazz The Java class */ - private class FromJavaClassCompleter(clazz: Symbol, module: Symbol, jclazz: jClass[_]) extends LazyType with JavaClassCompleter with FlagAssigningCompleter { + private class FromJavaClassCompleter(clazz: Symbol, module: Symbol, jclazz: jClass[_]) extends LazyType with JavaClassCompleter with FlagAgnosticCompleter { + // one doesn't need to do non-trivial computations to assign flags for Java-based reflection artifacts + // therefore I'm moving flag-assigning logic from completion to construction + val flags = jclazz.scalaFlags + clazz setFlag (flags | JAVA) + if (module != NoSymbol) { + module setFlag (flags & PRIVATE | JAVA) + module.moduleClass setFlag (flags & PRIVATE | JAVA) + } + markFlagsCompleted(clazz, module)(mask = AllFlags) /** used to avoid cycles while initializing classes */ private var parentsLevel = 0 @@ -665,12 +744,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni override def load(sym: Symbol): Unit = { debugInfo("completing from Java " + sym + "/" + clazz.fullName)//debug assert(sym == clazz || (module != NoSymbol && (sym == module || sym == module.moduleClass)), sym) - val flags = jclazz.scalaFlags - clazz setFlag (flags | JAVA) - if (module != NoSymbol) { - module setFlag (flags & PRIVATE | JAVA) - module.moduleClass setFlag (flags & PRIVATE | JAVA) - } propagatePackageBoundary(jclazz, relatedSymbols: _*) copyAnnotations(clazz, jclazz) @@ -686,6 +759,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni override def complete(sym: Symbol): Unit = { load(sym) completeRest() + markAllCompleted(clazz, module) } def completeRest(): Unit = gilSynchronized { @@ -738,6 +812,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni class LazyPolyType(override val typeParams: List[Symbol]) extends LazyType with FlagAgnosticCompleter { override def complete(sym: Symbol) { completeRest() + markAllCompleted(clazz, module) } } } @@ -892,6 +967,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni val pkg = owner.newPackage(name) pkg.moduleClass setInfo new LazyPackageType pkg setInfoAndEnter pkg.moduleClass.tpe + markFlagsCompleted(pkg)(mask = AllFlags) info("made Scala "+pkg) pkg } else @@ -1074,6 +1150,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni fieldCache.enter(jfield, field) propagatePackageBoundary(jfield, field) copyAnnotations(field, jfield) + markAllCompleted(field) field } @@ -1100,11 +1177,9 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni setMethType(meth, tparams, paramtpes, resulttpe) propagatePackageBoundary(jmeth.javaFlags, meth) copyAnnotations(meth, jmeth) - - if (jmeth.javaFlags.isVarargs) - meth modifyInfo arrayToRepeated - else - meth + if (jmeth.javaFlags.isVarargs) meth modifyInfo arrayToRepeated + markAllCompleted(meth) + meth } /** @@ -1127,6 +1202,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni constr setInfo GenPolyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe)) propagatePackageBoundary(jconstr.javaFlags, constr) copyAnnotations(constr, jconstr) + markAllCompleted(constr) constr } diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index 54b75b8e5b..f6556a442d 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -12,6 +12,8 @@ class JavaUniverse extends internal.SymbolTable with JavaUniverseForce with Refl override def inform(msg: String): Unit = log(msg) def picklerPhase = internal.SomePhase + def erasurePhase = internal.SomePhase + lazy val settings = new Settings private val isLogging = sys.props contains "scala.debug.reflect" @@ -21,7 +23,7 @@ class JavaUniverse extends internal.SymbolTable with JavaUniverseForce with Refl def newStrictTreeCopier: TreeCopier = new StrictTreeCopier def newLazyTreeCopier: TreeCopier = new LazyTreeCopier - val currentFreshNameCreator = new reflect.internal.util.FreshNameCreator + def currentFreshNameCreator = globalFreshNameCreator // can't put this in runtime.Trees since that's mixed with Global in ReflectGlobal, which has the definition from internal.Trees object treeInfo extends { diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index c87995275f..0fcf215580 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -27,28 +27,8 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.settings this.treeInfo - // inaccessible: this.scala$reflect$runtime$Gil$$gil - // inaccessible: this.uniqueLock - // inaccessible: this._skolemizationLevel - // inaccessible: this._undoLog - // inaccessible: this._intersectionWitness - // inaccessible: this._volatileRecursions - // inaccessible: this._pendingVolatiles - // inaccessible: this._subsametypeRecursions - // inaccessible: this._pendingSubTypes - // inaccessible: this._basetypeRecursions - // inaccessible: this._pendingBaseTypes - // inaccessible: this._lubResults - // inaccessible: this._glbResults - // inaccessible: this._indent - // inaccessible: this._tostringRecursions - // inaccessible: this.atomicIds - // inaccessible: this.atomicExistentialIds - // inaccessible: this._recursionTable - // inaccessible: this.mirrors this.rootMirror this.treeBuild - // inaccessible: this.SimpleNameOrdering this.traceSymbols this.perRunCaches this.FreshNameExtractor @@ -57,10 +37,10 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.CompoundTypeTreeOriginalAttachment this.BackquotedIdentifierAttachment this.ForAttachment + this.SyntheticUnitAttachment this.SubpatternsAttachment this.noPrint this.typeDebug - // inaccessible: this.maxFree this.Range // inaccessible: this.posAssigner this.ConsoleWriter @@ -116,7 +96,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.pendingSuperCall this.emptyValDef this.EmptyTreeTypeSubstituter - // inaccessible: this.duplicator this.UnmappableAnnotArg this.LiteralAnnotArg this.ArrayAnnotArg @@ -127,7 +106,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.UnmappableAnnotation this.ErroneousAnnotation this.ThrownException - // inaccessible: this.compactify this.tpnme this.fulltpnme this.binarynme @@ -147,7 +125,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.ProperTypeKind this.TypeConKind this.inferKind - // inaccessible: this.substTypeMapCache this.UnmappableTree this.ErrorType this.WildcardType @@ -169,6 +146,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.PolyType this.ExistentialType this.OverloadedType + this.ImportType this.AntiPolyType this.HasTypeMember this.ArrayTypeRef @@ -183,9 +161,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.unwrapToStableClass this.unwrapWrapperTypes this.RecoverableCyclicReference - // inaccessible: this._undoLog - // inaccessible: this.numericLoBound - // inaccessible: this.numericHiBound this.TypeConstraint this.normalizeAliases this.dropSingletonType @@ -197,17 +172,16 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.typeVarToOriginMap this.ErroneousCollector this.adaptToNewRunMap - // inaccessible: this.commonOwnerMapObj + this.SubTypePair this.SymbolKind this.NoSymbol this.CyclicReference - // inaccessible: this.TypeHistory + this.SymbolOps this.TermName this.TypeName this.Liftable this.Unliftable this.BooleanFlag - // inaccessible: this.CachedNames this.WeakTypeTag this.TypeTag this.Expr @@ -273,6 +247,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.ComparableClass definitions.JavaCloneableClass definitions.JavaNumberClass + definitions.JavaEnumClass definitions.RemoteInterfaceClass definitions.RemoteExceptionClass definitions.ByNameParamClass @@ -319,8 +294,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.MirrorClass definitions.TypeCreatorClass definitions.TreeCreatorClass - definitions.BlackboxMacroClass - definitions.WhiteboxMacroClass definitions.BlackboxContextClass definitions.WhiteboxContextClass definitions.MacroImplAnnotation @@ -425,14 +398,12 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.languageFeatureModule definitions.metaAnnotations definitions.AnnotationDefaultAttr - // inaccessible: definitions.erasurePhase definitions.isPhantomClass definitions.syntheticCoreClasses definitions.syntheticCoreMethods definitions.hijackedCoreClasses definitions.symbolsNotPresentInBytecode definitions.isPossibleSyntheticParent - // inaccessible: definitions.boxedValueClassesSet definitions.abbrvTag definitions.numericWeight definitions.boxedModule diff --git a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala index 813c0e1386..d642b25127 100644 --- a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala +++ b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala @@ -12,7 +12,7 @@ import scala.reflect.internal.util.AbstractFileClassLoader /** A few java-reflection oriented utility functions useful during reflection bootstrapping. */ -private[scala] object ReflectionUtils { +object ReflectionUtils { // Unwraps some chained exceptions which arise during reflective calls. def unwrapThrowable(x: Throwable): Throwable = x match { case _: InvocationTargetException | // thrown by reflectively invoked method or constructor diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala index 11db83d7d5..de5ba99900 100644 --- a/src/reflect/scala/reflect/runtime/Settings.scala +++ b/src/reflect/scala/reflect/runtime/Settings.scala @@ -48,4 +48,5 @@ private[reflect] class Settings extends MutableSettings { val Yrecursion = new IntSetting(0) val maxClassfileName = new IntSetting(255) + def isScala211 = true } diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index 30a3855d70..c56bc28d90 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -6,6 +6,7 @@ import internal.Flags import java.lang.{Class => jClass, Package => jPackage} import scala.collection.mutable import scala.reflect.runtime.ReflectionUtils.scalacShouldntLoadClass +import scala.reflect.internal.Flags._ private[reflect] trait SymbolLoaders { self: SymbolTable => @@ -17,6 +18,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => * is found, a package is created instead. */ class TopClassCompleter(clazz: Symbol, module: Symbol) extends SymLoader with FlagAssigningCompleter { + markFlagsCompleted(clazz, module)(mask = ~TopLevelPickledFlags) override def complete(sym: Symbol) = { debugInfo("completing "+sym+"/"+clazz.fullName) assert(sym == clazz || sym == module || sym == module.moduleClass) @@ -24,6 +26,8 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => val loadingMirror = mirrorThatLoaded(sym) val javaClass = loadingMirror.javaClass(clazz.javaClassName) loadingMirror.unpickleClass(clazz, module, javaClass) + // NOTE: can't mark as thread-safe here, because unpickleClass might decide to delegate to FromJavaClassCompleter + // if (!isCompilerUniverse) markAllCompleted(clazz, module) } } override def load(sym: Symbol) = complete(sym) @@ -64,6 +68,7 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => sym setInfo new ClassInfoType(List(), new PackageScope(sym), sym) // override def safeToString = pkgClass.toString openPackageModule(sym) + markAllCompleted(sym) } } diff --git a/src/reflect/scala/reflect/runtime/SymbolTable.scala b/src/reflect/scala/reflect/runtime/SymbolTable.scala index ddbf3bd629..02155578f8 100644 --- a/src/reflect/scala/reflect/runtime/SymbolTable.scala +++ b/src/reflect/scala/reflect/runtime/SymbolTable.scala @@ -28,19 +28,4 @@ private[scala] trait SymbolTable extends internal.SymbolTable with JavaMirrors w * in order to prevent memory leaks: http://groups.google.com/group/scala-internals/browse_thread/thread/eabcf3d406dab8b2. */ override def isCompilerUniverse = false - - /** Unlike compiler universes, reflective universes can auto-initialize symbols on flag requests. - * - * scalac wasn't designed with such auto-initialization in mind, and quite often it makes assumptions - * that flag requests won't cause initialization. Therefore enabling auto-init leads to cyclic errors. - * We could probably fix those, but at the moment it's too risky. - * - * Reflective universes share codebase with scalac, but their surface is much smaller, which means less assumptions. - * These assumptions are taken care of in this overriden `shouldTriggerCompleter` method. - */ - override protected def shouldTriggerCompleter(symbol: Symbol, completer: Type, isFlagRelated: Boolean, mask: Long) = - completer match { - case _: TopClassCompleter | _: JavaClassCompleter => !isFlagRelated || (mask & TopLevelPickledFlags) != 0 - case _ => super.shouldTriggerCompleter(symbol, completer, isFlagRelated, mask) - } } diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 1a232c8de1..f5e16c6640 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -4,6 +4,7 @@ package runtime import scala.reflect.io.AbstractFile import scala.collection.{ immutable, mutable } +import scala.reflect.internal.Flags._ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable => @@ -31,23 +32,105 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb trait SynchronizedSymbol extends Symbol { - def gilSynchronizedIfNotInited[T](body: => T): T = { - // TODO JZ desired, but prone to race conditions. We need the runtime reflection based - // type completers to establish a memory barrier upon initialization. Maybe a volatile - // write? We need to consult with the experts here. Until them, lock pessimistically. - // - // `run/reflection-sync-subtypes.scala` fails about 1/50 times otherwise. - // - // if (isFullyInitialized) body - // else gilSynchronized { body } + /** (Things written in this comment only applies to runtime reflection. Compile-time reflection, + * especially across phases and runs, is somewhat more complicated, but we won't be touching it, + * because at the moment we only care about synchronizing runtime reflection). + * + * As it has been noted on multiple occasions, generally speaking, reflection artifacts aren't thread-safe. + * Reasons for that differ from artifact to artifact. In some cases it's quite bad (e.g. types use a number + * of non-concurrent compiler caches, so we need to serialize certain operations on types in order to make + * sure that things stay deterministic). However, in case of symbols there's hope, because it's only during + * initializaton that symbols are thread-unsafe. After everything's set up, symbols become immutable + * (sans a few deterministic caches that can be populated simultaneously by multiple threads) and therefore thread-safe. + * + * Note that by saying "symbols become immutable" I mean literally that. In a very common case of PackageClassSymbol's, + * even when a symbol finishes its initialization and becomes immutable, its info forever remains mutable. + * Therefore even if we no longer need to synchronize a PackageClassSymbol after it's initialized, we still have to take + * care of its ClassInfoType (or, more precisely, of the underlying Scope), but that's done elsewhere, and + * here we don't need to worry about that. + * + * Okay, so now we simply check `Symbol.isInitialized` and if it's true, then everything's fine? Haha, nope! + * The thing is that some completers call sym.setInfo when still in-flight and then proceed with initialization + * (e.g. see LazyPackageType). Consequently, setInfo sets _validTo to current period, which means that after + * a call to setInfo isInitialized will start returning true. Unfortunately, this doesn't mean that info becomes + * ready to be used, because subsequent initialization might change the info. + * + * Therefore we need to somehow distinguish between initialized and really initialized symbol states. + * Okay, let's do it on per-completer basis. We have seven kinds of completers to worry about: + * 1) LazyPackageType that initializes packages and their underlying package classes + * 2) TopClassCompleter that initializes top-level Scala-based class-module companion pairs of static definitions + * 3) LazyTypeRef and LazyTypeRefAndAlias set up by TopClassCompleter that initialize (transitive members) of top-level classes/modules + * 4) FromJavaClassCompleter that does the same for both top-level and non-toplevel Java-based classes/modules + * 5) Fully-initialized signatures of non-class/module Java-based reflection artifacts + * 6) Importing completer that transfers metadata from one universe to another + * 7) Signatures of special symbols such as roots and symbolsNotPresentInBytecode + * + * The mechanisms underlying completion are quite complex, and it'd be only natural to suppose that over time we're going to overlook something. + * Wrt isThreadsafe we could have two wrong situations: false positives (isThreadsafe = true, but the symbol isn't actually threadsafe) + * and false negatives (isThreadsafe = false, but the symbol is actually threadsafe). However, even though both are wrong, only the former + * is actively malicious. Indeed, false positives might lead to races, inconsistent state and crashes, while the latter would only cause + * `initialize` to be called and a gil to be taken on every potentially auto-initializable operation. Unpleasant yes, but still robust. + * + * What makes me hopeful is that: + * 1) By default (e.g. if some new completion mechanism gets introduced for a special flavor of symbols and we forget to call markCompleted) + * isThreadsafe is always in false negative state, which is unpleasant but safe. + * 2) Calls to `markCompleted` which are the only potential source of erroneous behavior are few and are relatively easy to place: + * just put them just before your completer's `complete` returns, and you should be fine. + * + * upd. Actually, there's another problem of not keeping initialization mask up-to-date. If we're not careful enough, + * then it might so happen that getting a certain flag that the compiler assumes to be definitively set will spuriously + * return isThreadsafe(purpose = FlagsOp(<flag>)) = false and that will lead to spurious auto-initialization, + * which will cause an SO or a cyclic reference or some other crash. I've done my best to go through all possible completers + * and call `markFlagsCompleted` where appropriate, but again over time something might be overlooked, so to guard against that + * I'm only considering TopLevelPickledFlags to be sources of potential initialization. This ensures that such system flags as + * isMethod, isModule or isPackage are never going to auto-initialize. + */ + override def isThreadsafe(purpose: SymbolOps) = { + if (isCompilerUniverse) false + else if (_initialized) true + else purpose.isFlagRelated && (_initializationMask & purpose.mask & TopLevelPickledFlags) == 0 + } + + /** Communicates with completers declared in scala.reflect.runtime.SymbolLoaders + * about the status of initialization of the underlying symbol. + * + * Unfortunately, it's not as easy as just introducing the `markThreadsafe` method that would be called + * by the completers when they are really done (as opposed to `setInfo` that, as mentioned above, doesn't mean anything). + * + * Since we also want to auto-initialize symbols when certain methods are being called (`Symbol.hasFlag` for example), + * we need to track the identity of the initializer, so as to block until initialization is complete if the caller + * comes from a different thread, but to skip auto-initialization if we're the initializing thread. + * + * Just a volatile var is fine, because: + * 1) Status can only be changed in a single-threaded fashion (this is enforced by gilSynchronized + * that effecively guards `Symbol.initialize`), which means that there can't be update conflicts. + * 2) If someone reads a stale value of status, then the worst thing that might happen is that this someone + * is going to spuriously call `initialize`, which is either a gil-protected operation (if the symbol isn't inited yet) + * or a no-op (if the symbol is already inited), and that is fine in both cases. + * + * upd. It looks like we also need to keep track of a mask of initialized flags to make sure + * that normal symbol initialization routines don't trigger auto-init in Symbol.flags-related routines (e.g. Symbol.getFlag). + * Due to the same reasoning as above, a single volatile var is enough for to store the mask. + */ + @volatile private[this] var _initialized = false + @volatile private[this] var _initializationMask = TopLevelPickledFlags + override def markFlagsCompleted(mask: Long): this.type = { _initializationMask = _initializationMask & ~mask; this } + override def markAllCompleted(): this.type = { _initializationMask = 0L; _initialized = true; this } + + def gilSynchronizedIfNotThreadsafe[T](body: => T): T = { + // TODO: debug and fix the race that doesn't allow us uncomment this optimization + // if (isCompilerUniverse || isThreadsafe(purpose = AllOps)) body + // else gilSynchronized { body } gilSynchronized { body } } - override def validTo = gilSynchronizedIfNotInited { super.validTo } - override def info = gilSynchronizedIfNotInited { super.info } - override def rawInfo: Type = gilSynchronizedIfNotInited { super.rawInfo } + override def validTo = gilSynchronizedIfNotThreadsafe { super.validTo } + override def info = gilSynchronizedIfNotThreadsafe { super.info } + override def rawInfo: Type = gilSynchronizedIfNotThreadsafe { super.rawInfo } + override def typeSignature: Type = gilSynchronizedIfNotThreadsafe { super.typeSignature } + override def typeSignatureIn(site: Type): Type = gilSynchronizedIfNotThreadsafe { super.typeSignatureIn(site) } - override def typeParams: List[Symbol] = gilSynchronizedIfNotInited { + override def typeParams: List[Symbol] = gilSynchronizedIfNotThreadsafe { if (isCompilerUniverse) super.typeParams else { if (isMonomorphicType) Nil @@ -63,7 +146,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb } } } - override def unsafeTypeParams: List[Symbol] = gilSynchronizedIfNotInited { + override def unsafeTypeParams: List[Symbol] = gilSynchronizedIfNotThreadsafe { if (isCompilerUniverse) super.unsafeTypeParams else { if (isMonomorphicType) Nil @@ -71,8 +154,6 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb } } - override def isStable: Boolean = gilSynchronized { super.isStable } - // ------ creators ------------------------------------------------------------------- override protected def createAbstractTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AbstractTypeSymbol = @@ -126,7 +207,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb // we can keep this lock fine-grained, because it's just a cache over asSeenFrom, which makes deadlocks impossible // unfortunately we cannot elide this lock, because the cache depends on `pre` private lazy val typeAsMemberOfLock = new Object - override def typeAsMemberOf(pre: Type): Type = gilSynchronizedIfNotInited { typeAsMemberOfLock.synchronized { super.typeAsMemberOf(pre) } } + override def typeAsMemberOf(pre: Type): Type = gilSynchronizedIfNotThreadsafe { typeAsMemberOfLock.synchronized { super.typeAsMemberOf(pre) } } } trait SynchronizedModuleSymbol extends ModuleSymbol with SynchronizedTermSymbol @@ -135,7 +216,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb // unlike with typeConstructor, a lock is necessary here, because tpe calculation relies on // temporarily assigning NoType to tpeCache to detect cyclic reference errors private lazy val tpeLock = new Object - override def tpe_* : Type = gilSynchronizedIfNotInited { tpeLock.synchronized { super.tpe_* } } + override def tpe_* : Type = gilSynchronizedIfNotThreadsafe { tpeLock.synchronized { super.tpe_* } } } trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala index de78e527a7..9bcf85dd6f 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala @@ -50,13 +50,6 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa private lazy val _intersectionWitness = mkThreadLocalStorage(perRunCaches.newWeakMap[List[Type], sWeakRef[Type]]()) override def intersectionWitness = _intersectionWitness.get - private lazy val _volatileRecursions = mkThreadLocalStorage(0) - override def volatileRecursions = _volatileRecursions.get - override def volatileRecursions_=(value: Int) = _volatileRecursions.set(value) - - private lazy val _pendingVolatiles = mkThreadLocalStorage(new mutable.HashSet[Symbol]) - override def pendingVolatiles = _pendingVolatiles.get - private lazy val _subsametypeRecursions = mkThreadLocalStorage(0) override def subsametypeRecursions = _subsametypeRecursions.get override def subsametypeRecursions_=(value: Int) = _subsametypeRecursions.set(value) @@ -81,9 +74,12 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa override def indent = _indent.get override def indent_=(value: String) = _indent.set(value) - private lazy val _tostringRecursions = mkThreadLocalStorage(0) - override def tostringRecursions = _tostringRecursions.get - override def tostringRecursions_=(value: Int) = _tostringRecursions.set(value) + private lazy val _toStringRecursions = mkThreadLocalStorage(0) + override def toStringRecursions = _toStringRecursions.get + override def toStringRecursions_=(value: Int) = _toStringRecursions.set(value) + + private lazy val _toStringSubjects = mkThreadLocalStorage(new mutable.HashSet[Type]) + override def toStringSubjects = _toStringSubjects.get /* The idea of caches is as follows. * When in reflexive mode, a cache is either null, or one sentinal diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala index 3a7688aa2c..3c9bbccba3 100644 --- a/src/reflect/scala/reflect/runtime/package.scala +++ b/src/reflect/scala/reflect/runtime/package.scala @@ -26,7 +26,7 @@ package object runtime { package runtime { private[scala] object Macros { - def currentMirror(c: scala.reflect.macros.BlackboxContext): c.Expr[universe.Mirror] = { + def currentMirror(c: scala.reflect.macros.blackbox.Context): c.Expr[universe.Mirror] = { import c.universe._ val runtimeClass = c.reifyEnclosingRuntimeClass if (runtimeClass.isEmpty) c.abort(c.enclosingPosition, "call site does not have an enclosing class") diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 8fba1e538e..d261fc5be9 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -18,7 +18,7 @@ import scala.reflect.internal.util.{ BatchSourceFile, SourceFile } import scala.tools.util.PathResolver import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.typechecker.{ TypeStrings, StructuredTypeStrings } -import scala.tools.nsc.util.{ ScalaClassLoader, stringFromWriter, StackTraceOps } +import scala.tools.nsc.util.{ ScalaClassLoader, stringFromReader, stringFromWriter, StackTraceOps } import scala.tools.nsc.util.Exceptional.unwrap import javax.script.{AbstractScriptEngine, Bindings, ScriptContext, ScriptEngine, ScriptEngineFactory, ScriptException, CompiledScript, Compilable} @@ -534,8 +534,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set var code = "" var bound = false - @throws[ScriptException] - def compile(script: String): CompiledScript = { + def compiled(script: String): CompiledScript = { if (!bound) { quietBind("engine" -> this.asInstanceOf[ScriptEngine]) bound = true @@ -562,18 +561,6 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set } } - @throws[ScriptException] - def compile(reader: java.io.Reader): CompiledScript = { - val writer = new java.io.StringWriter() - var c = reader.read() - while(c != -1) { - writer.write(c) - c = reader.read() - } - reader.close() - compile(writer.toString()) - } - private class WrappedRequest(val req: Request) extends CompiledScript { var recorded = false @@ -1014,10 +1001,16 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set } @throws[ScriptException] - def eval(script: String, context: ScriptContext): Object = compile(script).eval(context) + def compile(script: String): CompiledScript = eval("new javax.script.CompiledScript { def eval(context: javax.script.ScriptContext): Object = { " + script + " }.asInstanceOf[Object]; def getEngine: javax.script.ScriptEngine = engine }").asInstanceOf[CompiledScript] + + @throws[ScriptException] + def compile(reader: java.io.Reader): CompiledScript = compile(stringFromReader(reader)) + + @throws[ScriptException] + def eval(script: String, context: ScriptContext): Object = compiled(script).eval(context) @throws[ScriptException] - def eval(reader: java.io.Reader, context: ScriptContext): Object = compile(reader).eval(context) + def eval(reader: java.io.Reader, context: ScriptContext): Object = eval(stringFromReader(reader), context) override def finalize = close diff --git a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala index 496d5face1..915fd57bf8 100644 --- a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala +++ b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala @@ -11,7 +11,6 @@ import java.lang.{ ClassLoader => JavaClassLoader, Iterable => JIterable } import scala.tools.nsc.util.ScalaClassLoader import java.io.{ ByteArrayInputStream, CharArrayWriter, FileNotFoundException, PrintWriter, Writer } import java.util.{ Locale } -import java.util.regex.Pattern import java.util.concurrent.ConcurrentLinkedQueue import javax.tools.{ Diagnostic, DiagnosticCollector, DiagnosticListener, ForwardingJavaFileManager, JavaFileManager, JavaFileObject, @@ -20,6 +19,7 @@ import scala.reflect.io.{ AbstractFile, Directory, File, Path } import scala.io.Source import scala.util.{ Try, Success, Failure } import scala.util.Properties.lineSeparator +import scala.util.matching.Regex import scala.collection.JavaConverters import scala.collection.generic.Clearable import java.net.URL @@ -608,12 +608,12 @@ object JavapClass { // class k, candidate f without prefix def isFunOfClass(k: String, f: String) = { - val p = (s"${Pattern quote k}\\$$+anonfun").r + val p = (s"${Regex quote k}\\$$+anonfun").r (p findPrefixOf f).nonEmpty } // class k, candidate f without prefix, method m def isFunOfMethod(k: String, m: String, f: String) = { - val p = (s"${Pattern quote k}\\$$+anonfun\\$$${Pattern quote m}\\$$").r + val p = (s"${Regex quote k}\\$$+anonfun\\$$${Regex quote m}\\$$").r (p findPrefixOf f).nonEmpty } def isFunOfTarget(k: String, m: Option[String], f: String) = diff --git a/src/repl/scala/tools/nsc/interpreter/Naming.scala b/src/repl/scala/tools/nsc/interpreter/Naming.scala index cf38a2ae3a..e09c6f315e 100644 --- a/src/repl/scala/tools/nsc/interpreter/Naming.scala +++ b/src/repl/scala/tools/nsc/interpreter/Naming.scala @@ -8,6 +8,7 @@ package tools.nsc package interpreter import scala.util.Properties.lineSeparator +import scala.util.matching.Regex /** This is for name logic which is independent of the compiler (notice there's no Global.) * That includes at least generating, metaquoting, mangling, and unmangling. @@ -38,12 +39,10 @@ trait Naming { // // $line3.$read.$iw.$iw.Bippy = // $line3.$read$$iw$$iw$Bippy@4a6a00ca - - private def noMeta(s: String) = "\\Q" + s + "\\E" lazy val lineRegex = { val sn = sessionNames - val members = List(sn.read, sn.eval, sn.print) map noMeta mkString ("(?:", "|", ")") - debugging("lineRegex")(noMeta(sn.line) + """\d+[./]""" + members + """[$.]""") + val members = List(sn.read, sn.eval, sn.print) map Regex.quote mkString ("(?:", "|", ")") + debugging("lineRegex")(Regex.quote(sn.line) + """\d+[./]""" + members + """[$.]""") } private def removeLineWrapper(s: String) = s.replaceAll(lineRegex, "") diff --git a/src/scaladoc/scala/tools/nsc/doc/Settings.scala b/src/scaladoc/scala/tools/nsc/doc/Settings.scala index e5dbaa3fd5..5ea1443a19 100644 --- a/src/scaladoc/scala/tools/nsc/doc/Settings.scala +++ b/src/scaladoc/scala/tools/nsc/doc/Settings.scala @@ -122,6 +122,11 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_)) "Hide the members inherited by the given comma separated, fully qualified implicit conversions. Add dot (.) to include default conversions." ) + val docAuthor = BooleanSetting ( + "-author", + "Include authors." + ) + val docDiagrams = BooleanSetting ( "-diagrams", "Create inheritance diagrams for classes, traits and packages." @@ -207,7 +212,7 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_)) // For improved help output. def scaladocSpecific = Set[Settings#Setting]( docformat, doctitle, docfooter, docversion, docUncompilable, docsourceurl, docgenerator, docRootContent, useStupidTypes, - docDiagrams, docDiagramsDebug, docDiagramsDotPath, + docAuthor, docDiagrams, docDiagramsDebug, docDiagramsDotPath, docDiagramsDotTimeout, docDiagramsDotRestart, docImplicits, docImplicitsDebug, docImplicitsShowAll, docImplicitsHide, docDiagramsMaxNormalClasses, docDiagramsMaxImplicitClasses, diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala index 119d4e0143..26ee005d3e 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala @@ -351,6 +351,14 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp if (mbr.comment.isEmpty) NodeSeq.Empty else <div class="comment cmt">{ commentToHtml(mbr.comment) }</div> + val authorComment = + if (! s.docAuthor || mbr.comment.isEmpty || + mbr.comment.isDefined && mbr.comment.get.authors.isEmpty) NodeSeq.Empty + else <div class="comment cmt"> + {if (mbr.comment.get.authors.size > 1) <h6>Authors:</h6> else <h6>Author:</h6>} + { mbr.comment.get.authors map bodyToHtml} + </div> + val paramComments = { val prs: List[ParameterEntity] = mbr match { case cls: Class => cls.typeParams ::: cls.valueParams.flatten @@ -681,7 +689,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp val typeHierarchy = createDiagram(_.inheritanceDiagram, "Type Hierarchy", "inheritance-diagram") val contentHierarchy = createDiagram(_.contentDiagram, "Content Hierarchy", "content-diagram") - memberComment ++ paramComments ++ attributesBlock ++ linearization ++ subclasses ++ typeHierarchy ++ contentHierarchy + memberComment ++ authorComment ++ paramComments ++ attributesBlock ++ linearization ++ subclasses ++ typeHierarchy ++ contentHierarchy } def boundsToHtml(hi: Option[TypeEntity], lo: Option[TypeEntity], hasLinks: Boolean): NodeSeq = { diff --git a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala index 8f217e087c..ef84ac42ba 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala @@ -10,6 +10,7 @@ import diagram._ import scala.collection._ import scala.util.matching.Regex +import scala.reflect.macros.internal.macroImpl import symtab.Flags import io._ @@ -80,7 +81,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def inTemplate: TemplateImpl = inTpl def toRoot: List[EntityImpl] = this :: inTpl.toRoot def qualifiedName = name - def annotations = sym.annotations.map(makeAnnotation) + def annotations = sym.annotations.filterNot(_.tpe =:= typeOf[macroImpl]).map(makeAnnotation) def inPackageObject: Boolean = sym.owner.isModuleClass && sym.owner.sourceModule.isPackageObject def isType = sym.name.isTypeName } @@ -145,6 +146,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { * any abstract terms, otherwise it would fail compilation. So we reset the DEFERRED flag. */ if (!sym.isTrait && (sym hasFlag Flags.DEFERRED) && (!isImplicitlyInherited)) fgs += Paragraph(Text("abstract")) if (!sym.isModule && (sym hasFlag Flags.FINAL)) fgs += Paragraph(Text("final")) + if (sym.isMacro) fgs += Paragraph(Text("macro")) fgs.toList } def deprecation = diff --git a/src/swing/scala/swing/Publisher.scala b/src/swing/scala/swing/Publisher.scala deleted file mode 100644 index 578ef71e09..0000000000 --- a/src/swing/scala/swing/Publisher.scala +++ /dev/null @@ -1,174 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2007-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.swing - -import scala.collection.mutable -import mutable.Buffer -import event.Event - -/** <p> - * Notifies registered reactions when an event is published. Publishers are - * also reactors and listen to themselves per default as a convenience. - * </p> - * <p> - * In order to reduce memory leaks, reactions are weakly referenced by default, - * unless they implement <code>Reactions.StronglyReferenced</code>. That way, - * the lifetime of reactions are more easily bound to the registering object, - * which are reactors in common client code and hold strong references to their - * reactions. As a result, reactors can be garbage collected even though they - * still have reactions registered at some publisher, but not vice versa - * since reactors (strongly) reference publishers they are interested in. - * </p> - */ -trait Publisher extends Reactor { - import Reactions._ - - protected val listeners = new RefSet[Reaction] { - import scala.ref._ - val underlying = new mutable.HashSet[Reference[Reaction]] - protected def Ref(a: Reaction) = a match { - case a: StronglyReferenced => new StrongReference[Reaction](a) with super.Ref[Reaction] - case _ => new WeakReference[Reaction](a, referenceQueue) with super.Ref[Reaction] - } - } - - private[swing] def subscribe(listener: Reaction) { listeners += listener } - private[swing] def unsubscribe(listener: Reaction) { listeners -= listener } - - /** - * Notify all registered reactions. - */ - def publish(e: Event) { for (l <- listeners) if (l.isDefinedAt(e)) l(e) } - - listenTo(this) -} - -/** - * A publisher that subscribes itself to an underlying event source not before the first - * reaction is installed. Can unsubscribe itself when the last reaction is uninstalled. - */ -private[swing] trait LazyPublisher extends Publisher { - import Reactions._ - - protected def onFirstSubscribe() - protected def onLastUnsubscribe() - - override def subscribe(listener: Reaction) { - if(listeners.size == 1) onFirstSubscribe() - super.subscribe(listener) - } - override def unsubscribe(listener: Reaction) { - super.unsubscribe(listener) - if(listeners.size == 1) onLastUnsubscribe() - } -} - - - -import scala.ref._ - -private[swing] trait SingleRefCollection[+A <: AnyRef] extends Iterable[A] { self => - - trait Ref[+A <: AnyRef] extends Reference[A] { - override def hashCode() = get match { - case Some(x) => x.## - case _ => 0 - } - override def equals(that: Any) = that match { - case that: ReferenceWrapper[_] => - val v1 = this.get - val v2 = that.get - v1 == v2 - case _ => false - } - } - - //type Ref <: Reference[A] // TODO: could use higher kinded types, but currently crashes - protected[this] def Ref(a: A): Ref[A] - protected[this] val referenceQueue = new ReferenceQueue[A] - - protected val underlying: Iterable[Reference[A]] - - def purgeReferences() { - var ref = referenceQueue.poll - while (ref != None) { - removeReference(ref.get.asInstanceOf[Reference[A]]) - ref = referenceQueue.poll - } - } - - protected[this] def removeReference(ref: Reference[A]) - - def iterator = new Iterator[A] { - private val elems = self.underlying.iterator - private var hd: A = _ - private var ahead: Boolean = false - private def skip(): Unit = - while (!ahead && elems.hasNext) { - // make sure we have a reference to the next element, - // otherwise it might be garbage collected - val next = elems.next.get - ahead = next != None - if (ahead) hd = next.get - } - def hasNext: Boolean = { skip; ahead } - def next(): A = - if (hasNext) { ahead = false; hd } - else throw new NoSuchElementException("next on empty iterator") - } -} - -private[swing] class StrongReference[+T <: AnyRef](value: T) extends Reference[T] { - private[this] var ref: Option[T] = Some(value) - def isValid: Boolean = ref != None - def apply(): T = ref.get - def get : Option[T] = ref - override def toString = get.map(_.toString).getOrElse("<deleted>") - def clear() { ref = None } - def enqueue(): Boolean = false - def isEnqueued(): Boolean = false - } - -abstract class RefBuffer[A <: AnyRef] extends Buffer[A] with SingleRefCollection[A] { self => - protected val underlying: Buffer[Reference[A]] - - def +=(el: A): this.type = { purgeReferences(); underlying += Ref(el); this } - def +=:(el: A) = { purgeReferences(); Ref(el) +=: underlying; this } - def remove(el: A) { underlying -= Ref(el); purgeReferences(); } - def remove(n: Int) = { val el = apply(n); remove(el); el } - def insertAll(n: Int, iter: Iterable[A]) { - purgeReferences() - underlying.insertAll(n, iter.view.map(Ref(_))) - } - def update(n: Int, el: A) { purgeReferences(); underlying(n) = Ref(el) } - def apply(n: Int) = { - purgeReferences() - var el = underlying(n).get - while (el == None) { - purgeReferences(); el = underlying(n).get - } - el.get - } - - def length = { purgeReferences(); underlying.length } - def clear() { underlying.clear(); purgeReferences() } - - protected[this] def removeReference(ref: Reference[A]) { underlying -= ref } -} - -private[swing] abstract class RefSet[A <: AnyRef] extends mutable.Set[A] with SingleRefCollection[A] { self => - protected val underlying: mutable.Set[Reference[A]] - - def -=(el: A): this.type = { underlying -= Ref(el); purgeReferences(); this } - def +=(el: A): this.type = { purgeReferences(); underlying += Ref(el); this } - def contains(el: A): Boolean = { purgeReferences(); underlying.contains(Ref(el)) } - override def size = { purgeReferences(); underlying.size } - - protected[this] def removeReference(ref: Reference[A]) { underlying -= ref } -} diff --git a/test/disabled/run/t7843-jsr223-service.scala b/test/disabled/run/t7843-jsr223-service.scala deleted file mode 100644 index e2ea850698..0000000000 --- a/test/disabled/run/t7843-jsr223-service.scala +++ /dev/null @@ -1,18 +0,0 @@ -/*DISABLED: - For Paul, it steals focus when it runs. - - For me, it fails with some platform specific extra output: - - -ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider apple.applescript.AppleScriptEngin - n: Object = 10 - 12345678910 -*/ -import javax.script._ -import scala.tools.nsc.interpreter.IMain - -object Test extends App { - val engine = new ScriptEngineManager getEngineByName "scala" - engine.asInstanceOf[IMain].settings.usejavacp.value = true - engine put ("n", 10) - engine eval "1 to n.asInstanceOf[Int] foreach print" -} diff --git a/test/files/filters b/test/files/filters index 70d7dcff70..51a7507848 100644 --- a/test/files/filters +++ b/test/files/filters @@ -4,3 +4,5 @@ Java HotSpot\(TM\) .* warning: # Hotspot receiving VM options through the $_JAVA_OPTIONS # env variable outputs them on stderr Picked up _JAVA_OPTIONS: +# Filter out a message caused by this bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8021205 +objc\[\d+\]: Class JavaLaunchHelper is implemented in both .* and .*\. One of the two will be used\. Which one is undefined\. diff --git a/test/files/jvm/bigints.scala b/test/files/jvm/bigints.scala index f0d05f8b71..06197cbb43 100644 --- a/test/files/jvm/bigints.scala +++ b/test/files/jvm/bigints.scala @@ -31,7 +31,6 @@ object Test_BigDecimal { val xi: BigDecimal = 1 val xd: BigDecimal = 1.0 - val xf: BigDecimal = BigDecimal(1.0f) val xs: BigDecimal = BigDecimal("1.0") val xbi: BigDecimal = BigDecimal(scala.BigInt(1)) diff --git a/test/files/jvm/daemon-actor-termination.scala b/test/files/jvm/daemon-actor-termination.scala index 40acd8583e..9bac6340ba 100644 --- a/test/files/jvm/daemon-actor-termination.scala +++ b/test/files/jvm/daemon-actor-termination.scala @@ -11,7 +11,7 @@ object Test { react { case 'hello => println("MSG1") - reply() + reply(()) react { case 'bye => println("done") diff --git a/test/files/jvm/future-spec/FutureTests.scala b/test/files/jvm/future-spec/FutureTests.scala index cfdcc31ac5..a290af9cd3 100644 --- a/test/files/jvm/future-spec/FutureTests.scala +++ b/test/files/jvm/future-spec/FutureTests.scala @@ -1,6 +1,3 @@ - - - import scala.concurrent._ import scala.concurrent.duration._ import scala.concurrent.duration.Duration.Inf @@ -518,7 +515,7 @@ class FutureTests extends MinimalScalaTest { } "should not deadlock with nested await (ticket 1313)" in { - val simple = Future() map { + val simple = Future(()) map { _ => val unit = Future(()) val umap = unit map { _ => () } @@ -527,7 +524,7 @@ class FutureTests extends MinimalScalaTest { Await.ready(simple, Inf).isCompleted mustBe (true) val l1, l2 = new TestLatch - val complex = Future() map { + val complex = Future(()) map { _ => blocking { val nested = Future(()) @@ -549,5 +546,3 @@ class FutureTests extends MinimalScalaTest { } } - - diff --git a/test/files/jvm/interpreter.check b/test/files/jvm/interpreter.check index 6e5fada381..b55ecc10e6 100644 --- a/test/files/jvm/interpreter.check +++ b/test/files/jvm/interpreter.check @@ -58,7 +58,7 @@ t1513: Array[Null] = Array(null) scala> // ambiguous toString problem from #547 -scala> val atom = new scala.xml.Atom() +scala> val atom = new scala.xml.Atom(()) atom: scala.xml.Atom[Unit] = () scala> // overriding toString problem from #1404 diff --git a/test/files/jvm/interpreter.scala b/test/files/jvm/interpreter.scala index bd1851053f..c68c064c31 100644 --- a/test/files/jvm/interpreter.scala +++ b/test/files/jvm/interpreter.scala @@ -25,7 +25,7 @@ println("hello") // ticket #1513 val t1513 = Array(null) // ambiguous toString problem from #547 -val atom = new scala.xml.Atom() +val atom = new scala.xml.Atom(()) // overriding toString problem from #1404 class S(override val toString : String) val fish = new S("fish") diff --git a/test/files/jvm/t6941/Analyzed_1.scala b/test/files/jvm/t6941/Analyzed_1.scala index 549abd5e64..b6951f71ee 100644 --- a/test/files/jvm/t6941/Analyzed_1.scala +++ b/test/files/jvm/t6941/Analyzed_1.scala @@ -6,6 +6,6 @@ class SameBytecode { } def b(xs: List[Int]) = xs match { - case xs: ::[Int] => xs.hd$1 + case xs: ::[Int] => xs.head } }
\ No newline at end of file diff --git a/test/files/jvm/try-type-tests.scala b/test/files/jvm/try-type-tests.scala index e5e53ee737..962afbd30f 100644 --- a/test/files/jvm/try-type-tests.scala +++ b/test/files/jvm/try-type-tests.scala @@ -3,139 +3,139 @@ import scala.util.{Try, Success, Failure} // tests the basic combinators on Try trait TryStandard { - def testForeachSuccess(): Unit = { - val t = Success(1) - var res = 0 - t.foreach(x => res = x * 10) - assert(res == 10) - } - - def testForeachFailure(): Unit = { - val t = Failure(new Exception("foo")) - t.foreach(x => assert(false)) - } - - def testFlatMapSuccess(): Unit = { - val t = Success(1) - val n = t.flatMap(x => Try(x * 10)) - assert(n.get == 10) - } - - def testFlatMapFailure(): Unit = { - val t = Failure(new Exception("foo")) - val n = t.flatMap{ x => assert(false); Try() } - } - - def testMapSuccess(): Unit = { - val t = Success(1) - val n = t.map(x => x * 10) - assert(n.get == 10) - } - - def testMapFailure(): Unit = { - val t = Failure(new Exception("foo")) - val n = t.map(x => assert(false)) - } - - def testFilterSuccessTrue(): Unit = { - val t = Success(1) - val n = t.filter(x => x > 0) - assert(n.get == 1) - } - - def testFilterSuccessFalse(): Unit = { - val t = Success(1) - val n = t.filter(x => x < 0) - n match { - case Success(v) => assert(false) - case Failure(e: NoSuchElementException) => assert(true) + def testForeachSuccess(): Unit = { + val t = Success(1) + var res = 0 + t.foreach(x => res = x * 10) + assert(res == 10) + } + + def testForeachFailure(): Unit = { + val t = Failure(new Exception("foo")) + t.foreach(x => assert(false)) + } + + def testFlatMapSuccess(): Unit = { + val t = Success(1) + val n = t.flatMap(x => Try(x * 10)) + assert(n.get == 10) + } + + def testFlatMapFailure(): Unit = { + val t = Failure(new Exception("foo")) + val n = t.flatMap{ x => assert(false); Try(()) } + } + + def testMapSuccess(): Unit = { + val t = Success(1) + val n = t.map(x => x * 10) + assert(n.get == 10) + } + + def testMapFailure(): Unit = { + val t = Failure(new Exception("foo")) + val n = t.map(x => assert(false)) + } + + def testFilterSuccessTrue(): Unit = { + val t = Success(1) + val n = t.filter(x => x > 0) + assert(n.get == 1) + } + + def testFilterSuccessFalse(): Unit = { + val t = Success(1) + val n = t.filter(x => x < 0) + n match { + case Success(v) => assert(false) + case Failure(e: NoSuchElementException) => assert(true) case _ => assert(false) - } - } - - def testFilterFailure(): Unit = { - val t = Failure(new Exception("foo")) - val n = t.filter{ x => assert(false); true } - } - - def testRescueSuccess(): Unit = { - val t = Success(1) - t.recoverWith{ case x => assert(false); Try() } - } - - def testRescueFailure(): Unit = { - val t = Failure(new Exception("foo")) - val n = t.recoverWith{ case x => Try(1) } - assert(n.get == 1) - } - - def testRecoverSuccess(): Unit = { - val t = Success(1) - t.recover{ case x => assert(false); 99 } - } - - def testRecoverFailure(): Unit = { - val t = Failure(new Exception("foo")) - val n = t.recover{ case x => 1 } - assert(n.get == 1) - } - - def testFlattenSuccess(): Unit = { - val f = Failure(new Exception("foo")) - val t = Success(f) - assert(t.flatten == f) - } - - def testFailedSuccess(): Unit = { - val t = Success(1) - val n = t.failed - n match { - case Failure(e: UnsupportedOperationException) => assert(true) - case _ => assert(false) - } - } - - def testFailedFailure(): Unit = { - val t = Failure(new Exception("foo")) - val n = t.failed - n match { - case Success(e: Exception) => assert(true) - case _ => assert(false) - } - } - - def testSuccessTransform(): Unit = { - val s = Success(1) - val succ = (x: Int) => Success(x * 10) - val fail = (x: Throwable) => Success(0) - assert(s.transform(succ, fail).get == 10) - } - - def testFailureTransform(): Unit = { - val f = Failure(new Exception("foo")) - val succ = (x: Int) => Success(x * 10) - val fail = (x: Throwable) => Success(0) - assert(f.transform(succ, fail).get == 0) - } - - testForeachSuccess() - testForeachFailure() - testFlatMapSuccess() - testFlatMapFailure() - testMapSuccess() - testMapFailure() - testFilterSuccessTrue() - testFilterSuccessFalse() - testFilterFailure() - testRescueSuccess() - testRescueFailure() - testRecoverSuccess() - testRecoverFailure() - testFlattenSuccess() - testFailedSuccess() - testFailedFailure() - testSuccessTransform() - testFailureTransform() + } + } + + def testFilterFailure(): Unit = { + val t = Failure(new Exception("foo")) + val n = t.filter{ x => assert(false); true } + } + + def testRescueSuccess(): Unit = { + val t = Success(1) + t.recoverWith{ case x => assert(false); Try(()) } + } + + def testRescueFailure(): Unit = { + val t = Failure(new Exception("foo")) + val n = t.recoverWith{ case x => Try(1) } + assert(n.get == 1) + } + + def testRecoverSuccess(): Unit = { + val t = Success(1) + t.recover{ case x => assert(false); 99 } + } + + def testRecoverFailure(): Unit = { + val t = Failure(new Exception("foo")) + val n = t.recover{ case x => 1 } + assert(n.get == 1) + } + + def testFlattenSuccess(): Unit = { + val f = Failure(new Exception("foo")) + val t = Success(f) + assert(t.flatten == f) + } + + def testFailedSuccess(): Unit = { + val t = Success(1) + val n = t.failed + n match { + case Failure(e: UnsupportedOperationException) => assert(true) + case _ => assert(false) + } + } + + def testFailedFailure(): Unit = { + val t = Failure(new Exception("foo")) + val n = t.failed + n match { + case Success(e: Exception) => assert(true) + case _ => assert(false) + } + } + + def testSuccessTransform(): Unit = { + val s = Success(1) + val succ = (x: Int) => Success(x * 10) + val fail = (x: Throwable) => Success(0) + assert(s.transform(succ, fail).get == 10) + } + + def testFailureTransform(): Unit = { + val f = Failure(new Exception("foo")) + val succ = (x: Int) => Success(x * 10) + val fail = (x: Throwable) => Success(0) + assert(f.transform(succ, fail).get == 0) + } + + testForeachSuccess() + testForeachFailure() + testFlatMapSuccess() + testFlatMapFailure() + testMapSuccess() + testMapFailure() + testFilterSuccessTrue() + testFilterSuccessFalse() + testFilterFailure() + testRescueSuccess() + testRescueFailure() + testRecoverSuccess() + testRecoverFailure() + testFlattenSuccess() + testFailedSuccess() + testFailedFailure() + testSuccessTransform() + testFailureTransform() } object Test diff --git a/test/files/neg/abstract-report2.check b/test/files/neg/abstract-report2.check index 6ea949353a..9be3d822f2 100644 --- a/test/files/neg/abstract-report2.check +++ b/test/files/neg/abstract-report2.check @@ -61,7 +61,7 @@ it has 13 unimplemented members. class Baz[T] extends Collection[T] ^ -abstract-report2.scala:11: error: class Dingus needs to be abstract, since: +abstract-report2.scala:15: error: class Dingus needs to be abstract, since: it has 24 unimplemented members. /** As seen from class Dingus, the missing signatures are as follows. * For convenience, these are usable as stub implementations. @@ -84,9 +84,6 @@ it has 24 unimplemented members. def toIterator: Iterator[(Set[Int], String)] = ??? def toStream: Stream[(Set[Int], String)] = ??? - // Members declared in scala.math.Ordering - def compare(x: List[Int],y: List[Int]): Int = ??? - // Members declared in scala.collection.TraversableOnce def copyToArray[B >: (Set[Int], String)](xs: Array[B],start: Int,len: Int): Unit = ??? def exists(p: ((Set[Int], String)) => Boolean): Boolean = ??? @@ -98,6 +95,9 @@ it has 24 unimplemented members. def seq: scala.collection.TraversableOnce[(Set[Int], String)] = ??? def toTraversable: Traversable[(Set[Int], String)] = ??? + // Members declared in Xyz + def foo(x: List[Int]): Boolean = ??? + class Dingus extends Bippy[String, Set[Int], List[Int]] ^ four errors found diff --git a/test/files/neg/abstract-report2.scala b/test/files/neg/abstract-report2.scala index b6327b0766..8825340d4a 100644 --- a/test/files/neg/abstract-report2.scala +++ b/test/files/neg/abstract-report2.scala @@ -6,6 +6,10 @@ class Bar extends Collection[List[_ <: String]] class Baz[T] extends Collection[T] -trait Bippy[T1, T2, T3] extends Collection[T1] with TraversableOnce[(T2, String)] with Ordering[T3] +trait Xyz[T] { + def foo(x: T): Boolean +} + +trait Bippy[T1, T2, T3] extends Collection[T1] with TraversableOnce[(T2, String)] with Xyz[T3] class Dingus extends Bippy[String, Set[Int], List[Int]]
\ No newline at end of file diff --git a/test/files/neg/accesses.check b/test/files/neg/accesses.check index 5a5e03233e..db58af12ce 100644 --- a/test/files/neg/accesses.check +++ b/test/files/neg/accesses.check @@ -1,3 +1,7 @@ +accesses.scala:23: error: overriding method f2 in class A of type ()Unit; + method f2 has weaker access privileges; it should not be private + private def f2(): Unit = () + ^ accesses.scala:24: error: overriding method f3 in class A of type ()Unit; method f3 has weaker access privileges; it should be at least protected private[p2] def f3(): Unit = () @@ -10,4 +14,4 @@ accesses.scala:26: error: overriding method f5 in class A of type ()Unit; method f5 has weaker access privileges; it should be at least protected[p1] protected[p2] def f5(): Unit ^ -three errors found +four errors found diff --git a/test/files/neg/accesses2.check b/test/files/neg/accesses2.check index 554a7b4c81..66cf9a116e 100644 --- a/test/files/neg/accesses2.check +++ b/test/files/neg/accesses2.check @@ -1,4 +1,12 @@ +accesses2.scala:6: error: overriding method f2 in class A of type ()Int; + method f2 has weaker access privileges; it should not be private + private def f2(): Int = 1 + ^ accesses2.scala:5: error: class B1 needs to be abstract, since method f2 in class A of type ()Int is not defined class B1 extends A { ^ -one error found +accesses2.scala:9: error: overriding method f2 in class A of type ()Int; + method f2 has weaker access privileges; it should not be private + private def f2(): Int = 1 + ^ +three errors found diff --git a/test/files/neg/dotless-targs.check b/test/files/neg/dotless-targs.check new file mode 100644 index 0000000000..4aab939f61 --- /dev/null +++ b/test/files/neg/dotless-targs.check @@ -0,0 +1,4 @@ +dotless-targs.scala:2: error: type application is not allowed for postfix operators + def f1 = "f1" isInstanceOf[String] // not ok + ^ +one error found diff --git a/test/files/neg/dotless-targs.scala b/test/files/neg/dotless-targs.scala new file mode 100644 index 0000000000..eff63cbec4 --- /dev/null +++ b/test/files/neg/dotless-targs.scala @@ -0,0 +1,5 @@ +class A { + def f1 = "f1" isInstanceOf[String] // not ok + def f2 = "f2".isInstanceOf[String] // ok + def f3 = "f3" toList // ok +} diff --git a/test/files/neg/forgot-interpolator.check b/test/files/neg/forgot-interpolator.check index 157cbb4802..8988458982 100644 --- a/test/files/neg/forgot-interpolator.check +++ b/test/files/neg/forgot-interpolator.check @@ -10,9 +10,6 @@ forgot-interpolator.scala:30: warning: `$beppo` looks like an interpolated ident forgot-interpolator.scala:34: warning: `$aleppo` looks like an interpolated identifier! Did you forget the interpolator? def f = "$aleppo is a pepper and a city." // warn 4 ^ -forgot-interpolator.scala:42: warning: `$bar` looks like an interpolated identifier! Did you forget the interpolator? - def f = "$bar is private, shall we warn just in case?" // warn 5 - ^ forgot-interpolator.scala:47: warning: `$hippo` looks like an interpolated identifier! Did you forget the interpolator? def h = "$hippo takes an implicit" // warn 6 ^ @@ -26,5 +23,5 @@ forgot-interpolator.scala:90: warning: `$calico` looks like an interpolated iden def f4 = "I also salute $calico" // warn 9 ^ error: No warnings can be incurred under -Xfatal-warnings. -9 warnings found +8 warnings found one error found diff --git a/test/files/neg/forgot-interpolator.scala b/test/files/neg/forgot-interpolator.scala index 34a7c7aef4..a53054d890 100644 --- a/test/files/neg/forgot-interpolator.scala +++ b/test/files/neg/forgot-interpolator.scala @@ -39,7 +39,7 @@ package test { if (bar > 8) ??? // use it to avoid extra warning } class Baz extends Bar { - def f = "$bar is private, shall we warn just in case?" // warn 5 + def f = "$bar is private, shall we warn just in case?" // no longer a warning, private members aren't inherited! } class G { def g = "$greppo takes an arg" // no warn diff --git a/test/files/neg/macro-abort/Macros_1.scala b/test/files/neg/macro-abort/Macros_1.scala index 577e640089..2077e99ad7 100644 --- a/test/files/neg/macro-abort/Macros_1.scala +++ b/test/files/neg/macro-abort/Macros_1.scala @@ -1,8 +1,8 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { c.abort(c.enclosingPosition, "aborted") } def abort = macro impl diff --git a/test/files/neg/macro-basic-mamdmi/Impls_Macros_Test_1.scala b/test/files/neg/macro-basic-mamdmi/Impls_Macros_Test_1.scala index ae34815d37..325bb7276f 100644 --- a/test/files/neg/macro-basic-mamdmi/Impls_Macros_Test_1.scala +++ b/test/files/neg/macro-basic-mamdmi/Impls_Macros_Test_1.scala @@ -1,17 +1,17 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def foo(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ c.Expr[Int](q"$x + 1") } - def bar(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def bar(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ c.Expr[Int](q"$x + 2") } - def quux(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def quux(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ c.Expr[Int](q"$x + 3") } diff --git a/test/files/neg/macro-blackbox-dynamic-materialization/Macros_1.scala b/test/files/neg/macro-blackbox-dynamic-materialization/Macros_1.scala index a00d195005..3cfbdf45e9 100644 --- a/test/files/neg/macro-blackbox-dynamic-materialization/Macros_1.scala +++ b/test/files/neg/macro-blackbox-dynamic-materialization/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import scala.language.experimental.macros trait Foo[T] @@ -15,7 +15,7 @@ object Foo extends LowPriority { } object Macros { - def impl[T: c.WeakTypeTag](c: BlackboxContext) = { + def impl[T: c.WeakTypeTag](c: Context) = { import c.universe._ val tpe = weakTypeOf[T] if (tpe.members.exists(_.typeSignature =:= typeOf[Int])) diff --git a/test/files/neg/macro-blackbox-extractor/Macros_1.scala b/test/files/neg/macro-blackbox-extractor/Macros_1.scala index f0bfe53aa2..64b6270b74 100644 --- a/test/files/neg/macro-blackbox-extractor/Macros_1.scala +++ b/test/files/neg/macro-blackbox-extractor/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros object Extractor { @@ -6,7 +6,7 @@ object Extractor { } object Macros { - def unapplyImpl(c: BlackboxContext)(x: c.Tree) = { + def unapplyImpl(c: Context)(x: c.Tree) = { import c.universe._ q""" new { diff --git a/test/files/neg/macro-blackbox-fundep-materialization/Macros_1.scala b/test/files/neg/macro-blackbox-fundep-materialization/Macros_1.scala index 6bddef4b9d..a6f7de23bb 100644 --- a/test/files/neg/macro-blackbox-fundep-materialization/Macros_1.scala +++ b/test/files/neg/macro-blackbox-fundep-materialization/Macros_1.scala @@ -1,5 +1,5 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context trait Iso[T, U] { def to(t : T) : U @@ -8,7 +8,7 @@ trait Iso[T, U] { object Iso { implicit def materializeIso[T, U]: Iso[T, U] = macro impl[T, U] - def impl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: BlackboxContext): c.Expr[Iso[T, U]] = { + def impl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: Context): c.Expr[Iso[T, U]] = { import c.universe._ import definitions._ import Flag._ diff --git a/test/files/neg/macro-blackbox-structural/Impls_Macros_1.scala b/test/files/neg/macro-blackbox-structural/Impls_Macros_1.scala index f5e85d57ea..a86a26d2c0 100644 --- a/test/files/neg/macro-blackbox-structural/Impls_Macros_1.scala +++ b/test/files/neg/macro-blackbox-structural/Impls_Macros_1.scala @@ -1,7 +1,7 @@ import scala.language.experimental.macros object Macros { - def impl(c: scala.reflect.macros.BlackboxContext) = { + def impl(c: scala.reflect.macros.blackbox.Context) = { import c.universe._ q""" trait Foo { diff --git a/test/files/neg/macro-bundle-abstract.check b/test/files/neg/macro-bundle-abstract.check index 8ef59106b8..3afd079521 100644 --- a/test/files/neg/macro-bundle-abstract.check +++ b/test/files/neg/macro-bundle-abstract.check @@ -1,4 +1,4 @@ -macro-bundle-abstract.scala:4: error: class Bundle$Bundle needs to be abstract, since method deferred in trait Bundle of type => Int is not defined -trait Bundle extends BlackboxMacro { - ^ +macro-bundle-abstract.scala:10: error: macro bundles must be concrete classes having a single constructor with a `val c: Context` parameter + def foo = macro Bundle.impl + ^ one error found diff --git a/test/files/neg/macro-bundle-abstract.scala b/test/files/neg/macro-bundle-abstract.scala index f7778d03be..0afeaafc01 100644 --- a/test/files/neg/macro-bundle-abstract.scala +++ b/test/files/neg/macro-bundle-abstract.scala @@ -1,7 +1,7 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxMacro +import scala.reflect.macros.blackbox.Context -trait Bundle extends BlackboxMacro { +abstract class Bundle(c: Context) { def deferred: Int def impl = ??? } diff --git a/test/files/neg/macro-bundle-class.check b/test/files/neg/macro-bundle-class.check deleted file mode 100644 index 7108c15b8d..0000000000 --- a/test/files/neg/macro-bundle-class.check +++ /dev/null @@ -1,4 +0,0 @@ -macro-bundle-class.scala:10: error: macro bundles must be monomorphic traits extending either BlackboxMacro or WhiteboxMacro and not implementing their `val c: BlackboxContext/WhiteboxContext` member - def foo = macro Bundle.impl - ^ -one error found diff --git a/test/files/neg/macro-bundle-class.scala b/test/files/neg/macro-bundle-class.scala deleted file mode 100644 index 024e2dbaaa..0000000000 --- a/test/files/neg/macro-bundle-class.scala +++ /dev/null @@ -1,11 +0,0 @@ -import scala.language.experimental.macros -import scala.reflect.macros.BlackboxMacro -import scala.reflect.macros.BlackboxContext - -class Bundle(val c: BlackboxContext) extends BlackboxMacro { - def impl = ??? -} - -object Macros { - def foo = macro Bundle.impl -}
\ No newline at end of file diff --git a/test/files/neg/macro-bundle-mixbox.check b/test/files/neg/macro-bundle-mixbox.check deleted file mode 100644 index c3136d9369..0000000000 --- a/test/files/neg/macro-bundle-mixbox.check +++ /dev/null @@ -1,4 +0,0 @@ -macro-bundle-mixbox.scala:9: error: macro bundles must be monomorphic traits extending either BlackboxMacro or WhiteboxMacro and not implementing their `val c: BlackboxContext/WhiteboxContext` member - def foo = macro Bundle.impl - ^ -one error found diff --git a/test/files/neg/macro-bundle-mixbox.scala b/test/files/neg/macro-bundle-mixbox.scala deleted file mode 100644 index 1e36f3d94c..0000000000 --- a/test/files/neg/macro-bundle-mixbox.scala +++ /dev/null @@ -1,10 +0,0 @@ -import scala.language.experimental.macros -import scala.reflect.macros.{BlackboxMacro, WhiteboxMacro} - -trait Bundle extends BlackboxMacro with WhiteboxMacro { - def impl = ??? -} - -object Macros { - def foo = macro Bundle.impl -}
\ No newline at end of file diff --git a/test/files/neg/macro-bundle-noncontext.check b/test/files/neg/macro-bundle-noncontext.check new file mode 100644 index 0000000000..bb5d0851f5 --- /dev/null +++ b/test/files/neg/macro-bundle-noncontext.check @@ -0,0 +1,4 @@ +macro-bundle-noncontext.scala:8: error: not found: value Bundle + def foo = Bundle.impl + ^ +one error found diff --git a/test/files/neg/macro-bundle-nonmacro.scala b/test/files/neg/macro-bundle-noncontext.scala index c7d99f4582..c228827e70 100644 --- a/test/files/neg/macro-bundle-nonmacro.scala +++ b/test/files/neg/macro-bundle-noncontext.scala @@ -1,6 +1,6 @@ import scala.language.experimental.macros -trait Bundle { +class Bundle { def impl = ??? } diff --git a/test/files/neg/macro-bundle-nonmacro.check b/test/files/neg/macro-bundle-nonmacro.check deleted file mode 100644 index 5a265b5724..0000000000 --- a/test/files/neg/macro-bundle-nonmacro.check +++ /dev/null @@ -1,4 +0,0 @@ -macro-bundle-nonmacro.scala:8: error: not found: value Bundle - def foo = Bundle.impl - ^ -one error found diff --git a/test/files/neg/macro-bundle-object.check b/test/files/neg/macro-bundle-object.check index 78e7119fa7..b8800105f5 100644 --- a/test/files/neg/macro-bundle-object.check +++ b/test/files/neg/macro-bundle-object.check @@ -1,6 +1,6 @@ macro-bundle-object.scala:10: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext): c.Expr[Nothing] - or : (c: scala.reflect.macros.BlackboxContext): c.Tree + required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Nothing] + or : (c: scala.reflect.macros.blackbox.Context): c.Tree found : : Nothing number of parameter sections differ def foo = macro Bundle.impl diff --git a/test/files/neg/macro-bundle-object.scala b/test/files/neg/macro-bundle-object.scala index 105c81f1f5..6e1eec1686 100644 --- a/test/files/neg/macro-bundle-object.scala +++ b/test/files/neg/macro-bundle-object.scala @@ -1,8 +1,8 @@ import scala.language.experimental.macros -import scala.reflect.macros.{BlackboxMacro, BlackboxContext} +import scala.reflect.macros.blackbox.Context -object Bundle extends BlackboxMacro { - val c: BlackboxContext = ??? +object Bundle { + val c: Context = ??? def impl = ??? } diff --git a/test/files/neg/macro-bundle-overloaded.check b/test/files/neg/macro-bundle-overloaded.check new file mode 100644 index 0000000000..fc94ff0000 --- /dev/null +++ b/test/files/neg/macro-bundle-overloaded.check @@ -0,0 +1,4 @@ +macro-bundle-overloaded.scala:11: error: macro bundles must be concrete classes having a single constructor with a `val c: Context` parameter + def foo = macro Bundle.impl + ^ +one error found diff --git a/test/files/neg/macro-bundle-overloaded.scala b/test/files/neg/macro-bundle-overloaded.scala new file mode 100644 index 0000000000..a4bc66f974 --- /dev/null +++ b/test/files/neg/macro-bundle-overloaded.scala @@ -0,0 +1,12 @@ +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.{Context => BlackboxContext} +import scala.reflect.macros.whitebox.{Context => WhiteboxContext} + +class Bundle(val c: BlackboxContext) { + def this(c: WhiteboxContext) = this(c: BlackboxContext) + def impl = ??? +} + +object Macros { + def foo = macro Bundle.impl +}
\ No newline at end of file diff --git a/test/files/neg/macro-bundle-polymorphic.check b/test/files/neg/macro-bundle-polymorphic.check deleted file mode 100644 index e024fcde93..0000000000 --- a/test/files/neg/macro-bundle-polymorphic.check +++ /dev/null @@ -1,10 +0,0 @@ -macro-bundle-polymorphic.scala:9: error: macro bundles must be monomorphic traits extending either BlackboxMacro or WhiteboxMacro and not implementing their `val c: BlackboxContext/WhiteboxContext` member - def foo = macro Bundle.impl - ^ -macro-bundle-polymorphic.scala:10: error: macro bundles must be monomorphic traits extending either BlackboxMacro or WhiteboxMacro and not implementing their `val c: BlackboxContext/WhiteboxContext` member - def foo = macro Bundle[Int].impl - ^ -macro-bundle-polymorphic.scala:11: error: macro bundles must be monomorphic traits extending either BlackboxMacro or WhiteboxMacro and not implementing their `val c: BlackboxContext/WhiteboxContext` member - def foo = macro Bundle[Int, Nothing].impl - ^ -three errors found diff --git a/test/files/neg/macro-bundle-polymorphic.scala b/test/files/neg/macro-bundle-polymorphic.scala deleted file mode 100644 index faf1e2e9e5..0000000000 --- a/test/files/neg/macro-bundle-polymorphic.scala +++ /dev/null @@ -1,12 +0,0 @@ -import scala.language.experimental.macros -import scala.reflect.macros.BlackboxMacro - -trait Bundle[T] extends BlackboxMacro { - def impl = ??? -} - -object Macros { - def foo = macro Bundle.impl - def foo = macro Bundle[Int].impl - def foo = macro Bundle[Int, Nothing].impl -}
\ No newline at end of file diff --git a/test/files/neg/macro-bundle-trait.check b/test/files/neg/macro-bundle-trait.check index 3cb7985013..869c67e1e3 100644 --- a/test/files/neg/macro-bundle-trait.check +++ b/test/files/neg/macro-bundle-trait.check @@ -1,4 +1,4 @@ -macro-bundle-trait.scala:11: error: macro bundles must be monomorphic traits extending either BlackboxMacro or WhiteboxMacro and not implementing their `val c: BlackboxContext/WhiteboxContext` member +macro-bundle-trait.scala:10: error: not found: value Bundle def foo = macro Bundle.impl ^ one error found diff --git a/test/files/neg/macro-bundle-trait.scala b/test/files/neg/macro-bundle-trait.scala index 62ade49953..2aa63216f5 100644 --- a/test/files/neg/macro-bundle-trait.scala +++ b/test/files/neg/macro-bundle-trait.scala @@ -1,9 +1,8 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxMacro -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context -trait Bundle extends BlackboxMacro { - val c: BlackboxContext = ??? +trait Bundle { + val c: Context = ??? def impl = ??? } diff --git a/test/files/neg/macro-cyclic/Impls_Macros_1.scala b/test/files/neg/macro-cyclic/Impls_Macros_1.scala index ba08345bcc..ad6890144d 100644 --- a/test/files/neg/macro-cyclic/Impls_Macros_1.scala +++ b/test/files/neg/macro-cyclic/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { c.universe.reify { implicitly[SourceLocation] } } diff --git a/test/files/neg/macro-divergence-controlled/Impls_Macros_1.scala b/test/files/neg/macro-divergence-controlled/Impls_Macros_1.scala index 9fb374800b..186c285871 100644 --- a/test/files/neg/macro-divergence-controlled/Impls_Macros_1.scala +++ b/test/files/neg/macro-divergence-controlled/Impls_Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import language.experimental.macros trait Complex[T] @@ -6,7 +6,7 @@ trait Complex[T] class Foo(val foo: Foo) object Complex { - def impl[T: c.WeakTypeTag](c: WhiteboxContext): c.Expr[Complex[T]] = { + def impl[T: c.WeakTypeTag](c: Context): c.Expr[Complex[T]] = { import c.universe._ val tpe = weakTypeOf[T] for (f <- tpe.declarations.collect{case f: TermSymbol if f.isParamAccessor && !f.isMethod => f}) { diff --git a/test/files/neg/macro-exception/Macros_1.scala b/test/files/neg/macro-exception/Macros_1.scala index 7bd8415e4f..3d6109dc9d 100644 --- a/test/files/neg/macro-exception/Macros_1.scala +++ b/test/files/neg/macro-exception/Macros_1.scala @@ -1,8 +1,8 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { throw new Exception() } def exception = macro impl diff --git a/test/files/neg/macro-false-deprecation-warning/Impls_Macros_1.scala b/test/files/neg/macro-false-deprecation-warning/Impls_Macros_1.scala index 1bd808d55d..a97dfd4ddf 100644 --- a/test/files/neg/macro-false-deprecation-warning/Impls_Macros_1.scala +++ b/test/files/neg/macro-false-deprecation-warning/Impls_Macros_1.scala @@ -1,11 +1,11 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Helper { def unapplySeq[T](x: List[T]): Option[Seq[T]] = } object Macros { - def impl[T: c.WeakTypeTag](c: BlackboxContext)(x: c.Expr[List[T]]) = { + def impl[T: c.WeakTypeTag](c: Context)(x: c.Expr[List[T]]) = { c.universe.reify(Helper.unapplySeq(x.splice)) } diff --git a/test/files/neg/macro-incompatible-macro-engine/Macros_2.scala b/test/files/neg/macro-incompatible-macro-engine/Macros_2.scala index ad57a3cb36..39708eee49 100644 --- a/test/files/neg/macro-incompatible-macro-engine/Macros_2.scala +++ b/test/files/neg/macro-incompatible-macro-engine/Macros_2.scala @@ -1,7 +1,7 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext) = c.universe.Literal(c.universe.Constant(())) + def impl(c: Context) = c.universe.Literal(c.universe.Constant(())) def foo: Unit = macro impl }
\ No newline at end of file diff --git a/test/files/neg/macro-invalidimpl.check b/test/files/neg/macro-invalidimpl.check index 5eff401bef..ea7d71c667 100644 --- a/test/files/neg/macro-invalidimpl.check +++ b/test/files/neg/macro-invalidimpl.check @@ -19,28 +19,28 @@ macro [<macro bundle>].<method name>[[<type args>]] def foo(x: Any) = macro Impls4.foo ^ Macros_Test_2.scala:26: error: ambiguous reference to overloaded definition, -both method foo in object Impls5 of type (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Any], y: c.Expr[Any])Nothing -and method foo in object Impls5 of type (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Any])Nothing +both method foo in object Impls5 of type (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Any], y: c.Expr[Any])Nothing +and method foo in object Impls5 of type (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Any])Nothing match expected type ? def foo(x: Any) = macro Impls5.foo ^ Macros_Test_2.scala:27: error: ambiguous reference to overloaded definition, -both method foo in object Impls5 of type (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Any], y: c.Expr[Any])Nothing -and method foo in object Impls5 of type (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Any])Nothing +both method foo in object Impls5 of type (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Any], y: c.Expr[Any])Nothing +and method foo in object Impls5 of type (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Any])Nothing match expected type ? def foo(x: Any, y: Any) = macro Impls5.foo ^ Macros_Test_2.scala:31: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext): c.Expr[Unit] - or : (c: scala.reflect.macros.BlackboxContext): c.Tree - found : (c: scala.reflect.macros.BlackboxContext)(): c.Expr[Unit] + required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Unit] + or : (c: scala.reflect.macros.blackbox.Context): c.Tree + found : (c: scala.reflect.macros.blackbox.Context)(): c.Expr[Unit] number of parameter sections differ def foo1 = macro Impls6.fooEmpty ^ Macros_Test_2.scala:32: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext)(): c.Expr[Unit] - or : (c: scala.reflect.macros.BlackboxContext)(): c.Tree - found : (c: scala.reflect.macros.BlackboxContext): c.Expr[Unit] + required: (c: scala.reflect.macros.blackbox.Context)(): c.Expr[Unit] + or : (c: scala.reflect.macros.blackbox.Context)(): c.Tree + found : (c: scala.reflect.macros.blackbox.Context): c.Expr[Unit] number of parameter sections differ def bar1() = macro Impls6.fooNullary ^ diff --git a/test/files/neg/macro-invalidimpl/Impls_1.scala b/test/files/neg/macro-invalidimpl/Impls_1.scala index b85ac9ee43..a1c885a4bf 100644 --- a/test/files/neg/macro-invalidimpl/Impls_1.scala +++ b/test/files/neg/macro-invalidimpl/Impls_1.scala @@ -1,39 +1,39 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context class Impls1 { - def foo(c: BlackboxContext)(x: c.Expr[Any]) = ??? + def foo(c: Context)(x: c.Expr[Any]) = ??? } object Impls2 { - def foo(c: BlackboxContext)(x: c.Expr[Any]) = ??? + def foo(c: Context)(x: c.Expr[Any]) = ??? } trait MacroHelpers { object Impls4 { - def foo(c: BlackboxContext)(x: c.Expr[Any]) = x + def foo(c: Context)(x: c.Expr[Any]) = x } } object Impls5 { - def foo(c: BlackboxContext)(x: c.Expr[Any]) = ??? - def foo(c: BlackboxContext)(x: c.Expr[Any], y: c.Expr[Any]) = ??? + def foo(c: Context)(x: c.Expr[Any]) = ??? + def foo(c: Context)(x: c.Expr[Any], y: c.Expr[Any]) = ??? } object Impls6 { - def fooNullary(c: BlackboxContext) = { + def fooNullary(c: Context) = { import c.universe._ c.Expr[Unit](q"""Predef.println("it works")""") } - def fooEmpty(c: BlackboxContext)() = fooNullary(c) + def fooEmpty(c: Context)() = fooNullary(c) } object Impls7 { - def foo[U <: Int](c: BlackboxContext) = ??? + def foo[U <: Int](c: Context) = ??? } package foo { object Impls8 { - private[foo] def impl(c: BlackboxContext) = ??? + private[foo] def impl(c: Context) = ??? } }
\ No newline at end of file diff --git a/test/files/neg/macro-invalidimpl/Macros_Test_2.scala b/test/files/neg/macro-invalidimpl/Macros_Test_2.scala index 0df7d2e0c5..6760d99959 100644 --- a/test/files/neg/macro-invalidimpl/Macros_Test_2.scala +++ b/test/files/neg/macro-invalidimpl/Macros_Test_2.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros1 { val impls = new Impls1 @@ -12,7 +12,7 @@ object Macros2 { class Macros3 { object Impls3 { - def foo(c: BlackboxContext)(x: c.Expr[Any]) = ??? + def foo(c: Context)(x: c.Expr[Any]) = ??? } def foo(x: Any) = macro Impls3.foo diff --git a/test/files/neg/macro-invalidret.check b/test/files/neg/macro-invalidret.check index 6c5baf76b4..568cc7c570 100644 --- a/test/files/neg/macro-invalidret.check +++ b/test/files/neg/macro-invalidret.check @@ -1,14 +1,14 @@ Macros_Test_2.scala:2: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext): c.Expr[Any] - or : (c: scala.reflect.macros.BlackboxContext): c.Tree - found : (c: scala.reflect.macros.BlackboxContext): Int + required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Any] + or : (c: scala.reflect.macros.blackbox.Context): c.Tree + found : (c: scala.reflect.macros.blackbox.Context): Int type mismatch for return type: Int does not conform to c.Expr[Any] def foo1 = macro Impls.foo1 ^ Macros_Test_2.scala:3: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext): c.Expr[Any] - or : (c: scala.reflect.macros.BlackboxContext): c.Tree - found : (c: scala.reflect.macros.BlackboxContext): reflect.runtime.universe.Literal + required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Any] + or : (c: scala.reflect.macros.blackbox.Context): c.Tree + found : (c: scala.reflect.macros.blackbox.Context): reflect.runtime.universe.Literal type mismatch for return type: reflect.runtime.universe.Literal does not conform to c.Expr[Any] def foo2 = macro Impls.foo2 ^ @@ -20,7 +20,7 @@ Macros_Test_2.scala:7: warning: macro defs must have explicitly specified return ^ Macros_Test_2.scala:14: error: exception during macro expansion: scala.NotImplementedError: an implementation is missing - at scala.Predef$.$qmark$qmark$qmark(Predef.scala:227) + at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225) at Impls$.foo3(Impls_1.scala:7) foo3 diff --git a/test/files/neg/macro-invalidret/Impls_1.scala b/test/files/neg/macro-invalidret/Impls_1.scala index b32463899e..434aeef10f 100644 --- a/test/files/neg/macro-invalidret/Impls_1.scala +++ b/test/files/neg/macro-invalidret/Impls_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import scala.reflect.runtime.{universe => ru} object Impls { - def foo1(c: BlackboxContext) = 2 - def foo2(c: BlackboxContext) = ru.Literal(ru.Constant(42)) - def foo3(c: BlackboxContext) = ??? - def foo5(c: BlackboxContext) = c.universe.Literal(c.universe.Constant(42)) - def foo6(c: BlackboxContext) = c.Expr[Int](c.universe.Literal(c.universe.Constant(42))) + def foo1(c: Context) = 2 + def foo2(c: Context) = ru.Literal(ru.Constant(42)) + def foo3(c: Context) = ??? + def foo5(c: Context) = c.universe.Literal(c.universe.Constant(42)) + def foo6(c: Context) = c.Expr[Int](c.universe.Literal(c.universe.Constant(42))) } diff --git a/test/files/neg/macro-invalidshape/Impls_1.scala b/test/files/neg/macro-invalidshape/Impls_1.scala index 3d5da9a2ed..acc6b52b7b 100644 --- a/test/files/neg/macro-invalidshape/Impls_1.scala +++ b/test/files/neg/macro-invalidshape/Impls_1.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Any]) = ??? + def foo(c: Context)(x: c.Expr[Any]) = ??? } diff --git a/test/files/neg/macro-invalidshape/Macros_Test_2.scala b/test/files/neg/macro-invalidshape/Macros_Test_2.scala index 8f643ab281..160bbf5f53 100644 --- a/test/files/neg/macro-invalidshape/Macros_Test_2.scala +++ b/test/files/neg/macro-invalidshape/Macros_Test_2.scala @@ -3,7 +3,7 @@ object Macros { def foo2(x: Any) = macro Impls.foo(null)(null) def foo3(x: Any) = macro {2; Impls.foo} { - def impl(c: scala.reflect.macros.BlackboxContext) = { import c.universe._; c.Expr[Unit](q"()") } + def impl(c: scala.reflect.macros.blackbox.Context) = { import c.universe._; c.Expr[Unit](q"()") } def foo = macro impl foo } diff --git a/test/files/neg/macro-invalidsig-params-badtype.check b/test/files/neg/macro-invalidsig-params-badtype.check index d6b5c5521d..159754c72e 100644 --- a/test/files/neg/macro-invalidsig-params-badtype.check +++ b/test/files/neg/macro-invalidsig-params-badtype.check @@ -1,7 +1,7 @@ Impls_Macros_1.scala:8: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Int]): c.Expr[Nothing] - or : (c: scala.reflect.macros.BlackboxContext)(x: c.Tree): c.Tree - found : (c: scala.reflect.macros.BlackboxContext)(x: Int): Nothing + required: (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Int]): c.Expr[Nothing] + or : (c: scala.reflect.macros.blackbox.Context)(x: c.Tree): c.Tree + found : (c: scala.reflect.macros.blackbox.Context)(x: Int): Nothing type mismatch for parameter x: c.Expr[Int] does not conform to Int def foo(x: Int) = macro Impls.foo ^ diff --git a/test/files/neg/macro-invalidsig-params-badtype/Impls_Macros_1.scala b/test/files/neg/macro-invalidsig-params-badtype/Impls_Macros_1.scala index 5f468424bd..e549cc9576 100644 --- a/test/files/neg/macro-invalidsig-params-badtype/Impls_Macros_1.scala +++ b/test/files/neg/macro-invalidsig-params-badtype/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: Int) = ??? + def foo(c: Context)(x: Int) = ??? } object Macros { diff --git a/test/files/neg/macro-invalidsig.check b/test/files/neg/macro-invalidsig.check index 5ff4ed18cb..8898ffc3de 100644 --- a/test/files/neg/macro-invalidsig.check +++ b/test/files/neg/macro-invalidsig.check @@ -2,30 +2,30 @@ Macros_Test_2.scala:2: error: macro implementations cannot have implicit paramet def foo[U]: Int = macro Impls1.foo[U] ^ Macros_Test_2.scala:6: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext): c.Expr[Nothing] - or : (c: scala.reflect.macros.BlackboxContext): c.Tree + required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Nothing] + or : (c: scala.reflect.macros.blackbox.Context): c.Tree found : : Nothing number of parameter sections differ def foo = macro Impls2.foo ^ Macros_Test_2.scala:10: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext): c.Expr[Nothing] - or : (c: scala.reflect.macros.BlackboxContext): c.Tree + required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Nothing] + or : (c: scala.reflect.macros.blackbox.Context): c.Tree found : (c: scala.reflect.api.Universe): Nothing -type mismatch for parameter c: scala.reflect.macros.BlackboxContext does not conform to scala.reflect.api.Universe +type mismatch for parameter c: scala.reflect.macros.blackbox.Context does not conform to scala.reflect.api.Universe def foo = macro Impls3.foo ^ Macros_Test_2.scala:14: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext): c.Expr[Nothing] - or : (c: scala.reflect.macros.BlackboxContext): c.Tree - found : (cs: scala.reflect.macros.BlackboxContext*): Nothing + required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Nothing] + or : (c: scala.reflect.macros.blackbox.Context): c.Tree + found : (cs: scala.reflect.macros.blackbox.Context*): Nothing types incompatible for parameter cs: corresponding is not a vararg parameter def foo = macro Impls4.foo ^ Macros_Test_2.scala:18: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Any]): c.Expr[Nothing] - or : (c: scala.reflect.macros.BlackboxContext)(x: c.Tree): c.Tree - found : (c: scala.reflect.macros.BlackboxContext): Nothing + required: (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Any]): c.Expr[Nothing] + or : (c: scala.reflect.macros.blackbox.Context)(x: c.Tree): c.Tree + found : (c: scala.reflect.macros.blackbox.Context): Nothing number of parameter sections differ def foo(x: Any) = macro Impls5.foo ^ @@ -33,37 +33,37 @@ Macros_Test_2.scala:22: error: macro implementations cannot have implicit parame def foo[U](x: Int) = macro Impls6.foo[T, U] ^ Macros_Test_2.scala:26: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Int]): c.Expr[Nothing] - or : (c: scala.reflect.macros.BlackboxContext)(x: c.Tree): c.Tree - found : (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Int], y: c.Expr[Int]): Nothing + required: (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Int]): c.Expr[Nothing] + or : (c: scala.reflect.macros.blackbox.Context)(x: c.Tree): c.Tree + found : (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Int], y: c.Expr[Int]): Nothing parameter lists have different length, found extra parameter y: c.Expr[Int] def foo(x: Int) = macro Impls7.foo ^ Macros_Test_2.scala:30: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Int]): c.Expr[Nothing] - or : (c: scala.reflect.macros.BlackboxContext)(x: c.Tree): c.Tree - found : (c: scala.reflect.macros.BlackboxContext)(x: c.universe.Symbol): Nothing + required: (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Int]): c.Expr[Nothing] + or : (c: scala.reflect.macros.blackbox.Context)(x: c.Tree): c.Tree + found : (c: scala.reflect.macros.blackbox.Context)(x: c.universe.Symbol): Nothing type mismatch for parameter x: c.Expr[Int] does not conform to c.universe.Symbol def foo(x: Int) = macro Impls8.foo ^ Macros_Test_2.scala:34: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Int], y: c.Expr[Int]): c.Expr[Nothing] - or : (c: scala.reflect.macros.BlackboxContext)(x: c.Tree, y: c.Tree): c.Tree - found : (c: scala.reflect.macros.BlackboxContext)(xs: c.Expr[Int]*): Nothing + required: (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Int], y: c.Expr[Int]): c.Expr[Nothing] + or : (c: scala.reflect.macros.blackbox.Context)(x: c.Tree, y: c.Tree): c.Tree + found : (c: scala.reflect.macros.blackbox.Context)(xs: c.Expr[Int]*): Nothing parameter lists have different length, required extra parameter y: c.Expr[Int] def foo(x: Int, y: Int) = macro Impls9.foo ^ Macros_Test_2.scala:38: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Int], y: c.Expr[Int]): c.Expr[Nothing] - or : (c: scala.reflect.macros.BlackboxContext)(x: c.Tree, y: c.Tree): c.Tree - found : (c: scala.reflect.macros.BlackboxContext)(y: c.Expr[Int], x: c.Expr[Int]): Nothing + required: (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Int], y: c.Expr[Int]): c.Expr[Nothing] + or : (c: scala.reflect.macros.blackbox.Context)(x: c.Tree, y: c.Tree): c.Tree + found : (c: scala.reflect.macros.blackbox.Context)(y: c.Expr[Int], x: c.Expr[Int]): Nothing parameter names differ: x != y def foo(x: Int, y: Int) = macro Impls10.foo ^ Macros_Test_2.scala:42: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext): c.Expr[Nothing] - or : (c: scala.reflect.macros.BlackboxContext): c.Tree - found : (c: scala.reflect.macros.BlackboxContext)(U: c.universe.Type): Nothing + required: (c: scala.reflect.macros.blackbox.Context): c.Expr[Nothing] + or : (c: scala.reflect.macros.blackbox.Context): c.Tree + found : (c: scala.reflect.macros.blackbox.Context)(U: c.universe.Type): Nothing number of parameter sections differ def foo[U] = macro Impls11.foo[U] ^ @@ -73,13 +73,13 @@ Macros_Test_2.scala:46: error: type arguments [U] do not conform to method foo's Macros_Test_2.scala:50: error: type arguments [U] do not conform to method foo's type parameter bounds [U <: String] def foo[U <: Int] = macro Impls13.foo[U] ^ -Macros_Test_2.scala:54: error: macro implementation reference has too few type arguments for method foo: [U](c: scala.reflect.macros.BlackboxContext)(implicit evidence$4: c.WeakTypeTag[U])Nothing +Macros_Test_2.scala:54: error: macro implementation reference has too few type arguments for method foo: [U](c: scala.reflect.macros.blackbox.Context)(implicit evidence$4: c.WeakTypeTag[U])Nothing def foo = macro Impls14.foo ^ -Macros_Test_2.scala:59: error: macro implementation reference has too few type arguments for method foo: [T, U, V](c: scala.reflect.macros.BlackboxContext)(implicit evidence$5: c.WeakTypeTag[T], implicit evidence$6: c.WeakTypeTag[U], implicit V: c.WeakTypeTag[V])c.Expr[Unit] +Macros_Test_2.scala:59: error: macro implementation reference has too few type arguments for method foo: [T, U, V](c: scala.reflect.macros.blackbox.Context)(implicit evidence$5: c.WeakTypeTag[T], implicit evidence$6: c.WeakTypeTag[U], implicit V: c.WeakTypeTag[V])c.Expr[Unit] def foo15[V]: Unit = macro Impls15.foo ^ -Macros_Test_2.scala:60: error: wrong number of type parameters for method foo: [T, U, V](c: scala.reflect.macros.BlackboxContext)(implicit evidence$7: c.WeakTypeTag[T], implicit evidence$8: c.WeakTypeTag[U], implicit V: c.WeakTypeTag[V])c.Expr[Unit] +Macros_Test_2.scala:60: error: wrong number of type parameters for method foo: [T, U, V](c: scala.reflect.macros.blackbox.Context)(implicit evidence$7: c.WeakTypeTag[T], implicit evidence$8: c.WeakTypeTag[U], implicit V: c.WeakTypeTag[V])c.Expr[Unit] def foo16[V]: Unit = macro Impls16.foo[V] ^ 16 errors found diff --git a/test/files/neg/macro-invalidsig/Impls_1.scala b/test/files/neg/macro-invalidsig/Impls_1.scala index 7c98160925..b0a3912380 100644 --- a/test/files/neg/macro-invalidsig/Impls_1.scala +++ b/test/files/neg/macro-invalidsig/Impls_1.scala @@ -1,8 +1,8 @@ import scala.reflect.runtime.universe._ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Impls1 { - def foo[U: c.WeakTypeTag: Numeric](c: BlackboxContext) = { import c.universe._; q"42" } + def foo[U: c.WeakTypeTag: Numeric](c: Context) = { import c.universe._; q"42" } } object Impls2 { @@ -14,15 +14,15 @@ object Impls3 { } object Impls4 { - def foo(cs: BlackboxContext*) = ??? + def foo(cs: Context*) = ??? } object Impls5 { - def foo(c: BlackboxContext) = ??? + def foo(c: Context) = ??? } object Impls6 { - def foo[T, U: c.WeakTypeTag](c: BlackboxContext)(implicit x: c.Expr[Int]) = { + def foo[T, U: c.WeakTypeTag](c: Context)(implicit x: c.Expr[Int]) = { import c.{prefix => prefix} import c.universe._ c.Expr[Unit](q""" @@ -34,39 +34,39 @@ object Impls6 { } object Impls7 { - def foo(c: BlackboxContext)(x: c.Expr[Int], y: c.Expr[Int]) = ??? + def foo(c: Context)(x: c.Expr[Int], y: c.Expr[Int]) = ??? } object Impls8 { - def foo(c: BlackboxContext)(x: c.universe.Symbol) = ??? + def foo(c: Context)(x: c.universe.Symbol) = ??? } object Impls9 { - def foo(c: BlackboxContext)(xs: c.Expr[Int]*) = ??? + def foo(c: Context)(xs: c.Expr[Int]*) = ??? } object Impls10 { - def foo(c: BlackboxContext)(y: c.Expr[Int], x: c.Expr[Int]) = ??? + def foo(c: Context)(y: c.Expr[Int], x: c.Expr[Int]) = ??? } object Impls11 { - def foo[U](c: BlackboxContext)(U: c.universe.Type) = ??? + def foo[U](c: Context)(U: c.universe.Type) = ??? } object Impls12 { - def foo[U <: String](c: BlackboxContext) = ??? + def foo[U <: String](c: Context) = ??? } object Impls13 { - def foo[U <: String](c: BlackboxContext) = ??? + def foo[U <: String](c: Context) = ??? } object Impls14 { - def foo[U: c.WeakTypeTag](c: BlackboxContext) = ??? + def foo[U: c.WeakTypeTag](c: Context) = ??? } object Impls15 { - def foo[T: c.WeakTypeTag, U: c.WeakTypeTag, V](c: BlackboxContext)(implicit V: c.WeakTypeTag[V]): c.Expr[Unit] = { + def foo[T: c.WeakTypeTag, U: c.WeakTypeTag, V](c: Context)(implicit V: c.WeakTypeTag[V]): c.Expr[Unit] = { import c.universe._ println(implicitly[c.WeakTypeTag[T]]) println(implicitly[c.WeakTypeTag[U]]) @@ -76,7 +76,7 @@ object Impls15 { } object Impls16 { - def foo[T: c.WeakTypeTag, U: c.WeakTypeTag, V](c: BlackboxContext)(implicit V: c.WeakTypeTag[V]): c.Expr[Unit] = { + def foo[T: c.WeakTypeTag, U: c.WeakTypeTag, V](c: Context)(implicit V: c.WeakTypeTag[V]): c.Expr[Unit] = { import c.universe._ println(implicitly[c.WeakTypeTag[T]]) println(implicitly[c.WeakTypeTag[U]]) diff --git a/test/files/neg/macro-invalidusage-badargs/Impls_1.scala b/test/files/neg/macro-invalidusage-badargs/Impls_1.scala index 678cb53929..8765cfbd5f 100644 --- a/test/files/neg/macro-invalidusage-badargs/Impls_1.scala +++ b/test/files/neg/macro-invalidusage-badargs/Impls_1.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int]) = x + def foo(c: Context)(x: c.Expr[Int]) = x } diff --git a/test/files/neg/macro-invalidusage-badbounds/Impls_1.scala b/test/files/neg/macro-invalidusage-badbounds/Impls_1.scala index 393f7de976..1769da91e1 100644 --- a/test/files/neg/macro-invalidusage-badbounds/Impls_1.scala +++ b/test/files/neg/macro-invalidusage-badbounds/Impls_1.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo[U <: String](c: Ctx) = { import c.universe._; c.Expr[Unit](q"()") } + def foo[U <: String](c: Context) = { import c.universe._; c.Expr[Unit](q"()") } } diff --git a/test/files/neg/macro-invalidusage-badtargs/Impls_1.scala b/test/files/neg/macro-invalidusage-badtargs/Impls_1.scala index 678cb53929..8765cfbd5f 100644 --- a/test/files/neg/macro-invalidusage-badtargs/Impls_1.scala +++ b/test/files/neg/macro-invalidusage-badtargs/Impls_1.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int]) = x + def foo(c: Context)(x: c.Expr[Int]) = x } diff --git a/test/files/neg/macro-invalidusage-methodvaluesyntax/Impls_1.scala b/test/files/neg/macro-invalidusage-methodvaluesyntax/Impls_1.scala index 15894efb68..776f8bf71c 100644 --- a/test/files/neg/macro-invalidusage-methodvaluesyntax/Impls_1.scala +++ b/test/files/neg/macro-invalidusage-methodvaluesyntax/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.universe._ c.Expr[Unit](q"""println("it works")""") } diff --git a/test/files/neg/macro-invalidusage-nontypeable/Impls_Macros_1.scala b/test/files/neg/macro-invalidusage-nontypeable/Impls_Macros_1.scala index 44e508a1c6..b6b9611743 100644 --- a/test/files/neg/macro-invalidusage-nontypeable/Impls_Macros_1.scala +++ b/test/files/neg/macro-invalidusage-nontypeable/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.universe._ val body = Ident(TermName("IDoNotExist")) c.Expr[Int](body) diff --git a/test/files/neg/macro-invalidusage-presuper/Impls_1.scala b/test/files/neg/macro-invalidusage-presuper/Impls_1.scala index 02c87b5a81..ea98f01fa4 100644 --- a/test/files/neg/macro-invalidusage-presuper/Impls_1.scala +++ b/test/files/neg/macro-invalidusage-presuper/Impls_1.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Impls { - def impl(c: BlackboxContext) = { import c.universe._; c.Expr[Unit](q"()") } + def impl(c: Context) = { import c.universe._; c.Expr[Unit](q"()") } }
\ No newline at end of file diff --git a/test/files/neg/macro-noexpand/Impls_1.scala b/test/files/neg/macro-noexpand/Impls_1.scala index 3d5da9a2ed..acc6b52b7b 100644 --- a/test/files/neg/macro-noexpand/Impls_1.scala +++ b/test/files/neg/macro-noexpand/Impls_1.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Any]) = ??? + def foo(c: Context)(x: c.Expr[Any]) = ??? } diff --git a/test/files/neg/macro-nontypeablebody/Impls_1.scala b/test/files/neg/macro-nontypeablebody/Impls_1.scala index 3d5da9a2ed..acc6b52b7b 100644 --- a/test/files/neg/macro-nontypeablebody/Impls_1.scala +++ b/test/files/neg/macro-nontypeablebody/Impls_1.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Any]) = ??? + def foo(c: Context)(x: c.Expr[Any]) = ??? } diff --git a/test/files/neg/macro-override-macro-overrides-abstract-method-a/Impls_Macros_1.scala b/test/files/neg/macro-override-macro-overrides-abstract-method-a/Impls_Macros_1.scala index 9c05db83e3..916b454463 100644 --- a/test/files/neg/macro-override-macro-overrides-abstract-method-a/Impls_Macros_1.scala +++ b/test/files/neg/macro-override-macro-overrides-abstract-method-a/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def impl(c: Ctx)(x: c.Expr[Int]) = x + def impl(c: Context)(x: c.Expr[Int]) = x } trait Foo { diff --git a/test/files/neg/macro-override-macro-overrides-abstract-method-b/Impls_Macros_1.scala b/test/files/neg/macro-override-macro-overrides-abstract-method-b/Impls_Macros_1.scala index c98279b2b8..17827abf7a 100644 --- a/test/files/neg/macro-override-macro-overrides-abstract-method-b/Impls_Macros_1.scala +++ b/test/files/neg/macro-override-macro-overrides-abstract-method-b/Impls_Macros_1.scala @@ -1,8 +1,8 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros trait T { def t(): Unit } trait A { def t(): Unit = () } -object Macro { def t(c: BlackboxContext)(): c.Expr[Unit] = c.universe.reify(()) } +object Macro { def t(c: Context)(): c.Expr[Unit] = c.universe.reify(()) } trait C extends T { self: A => override def t(): Unit = macro Macro.t } diff --git a/test/files/neg/macro-override-method-overrides-macro/Impls_1.scala b/test/files/neg/macro-override-method-overrides-macro/Impls_1.scala index f2d3f67ccc..f3917e3093 100644 --- a/test/files/neg/macro-override-method-overrides-macro/Impls_1.scala +++ b/test/files/neg/macro-override-method-overrides-macro/Impls_1.scala @@ -1,14 +1,14 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def impl(c: Ctx)(tag: String, x: c.Expr[_]) = { + def impl(c: Context)(tag: String, x: c.Expr[_]) = { import c.{prefix => prefix} import c.universe._ c.Expr[Unit](q"println($tag, ${prefix.toString}, $x)") } - def fooBString(c: Ctx)(x: c.Expr[_]) = impl(c)("fooBString", x) - def fooBInt(c: Ctx)(x: c.Expr[_]) = impl(c)("fooBInt", x) - def fooDInt(c: Ctx)(x: c.Expr[_]) = impl(c)("fooDInt", x) - def fooZString(c: Ctx)(x: c.Expr[_]) = impl(c)("fooZString", x) + def fooBString(c: Context)(x: c.Expr[_]) = impl(c)("fooBString", x) + def fooBInt(c: Context)(x: c.Expr[_]) = impl(c)("fooBInt", x) + def fooDInt(c: Context)(x: c.Expr[_]) = impl(c)("fooDInt", x) + def fooZString(c: Context)(x: c.Expr[_]) = impl(c)("fooZString", x) }
\ No newline at end of file diff --git a/test/files/neg/macro-quasiquotes/Macros_1.scala b/test/files/neg/macro-quasiquotes/Macros_1.scala index 098e4b3b92..b123c475c2 100644 --- a/test/files/neg/macro-quasiquotes/Macros_1.scala +++ b/test/files/neg/macro-quasiquotes/Macros_1.scala @@ -1,7 +1,7 @@ import language.experimental.macros -import scala.reflect.macros.BlackboxMacro +import scala.reflect.macros.blackbox.Context -trait Impls extends BlackboxMacro { +class Impls(val c: Context) { import c.universe._ def impl1(x: Expr[Int]) = q"println(x)" def impl2(x: Tree) = q"println(x)" diff --git a/test/files/neg/macro-reify-splice-splice/Macros_1.scala b/test/files/neg/macro-reify-splice-splice/Macros_1.scala index 691f22ad07..306e78ad97 100644 --- a/test/files/neg/macro-reify-splice-splice/Macros_1.scala +++ b/test/files/neg/macro-reify-splice-splice/Macros_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Macros { def foo = macro Impls.foo object Impls { - def foo(c: Ctx) = c.universe.reify { + def foo(c: Context) = c.universe.reify { { c.universe.reify(c.universe.reify("hello world")) }.splice.splice } } diff --git a/test/files/neg/macro-without-xmacros-a/Impls_1.scala b/test/files/neg/macro-without-xmacros-a/Impls_1.scala index 6b73a96184..035913f3e3 100644 --- a/test/files/neg/macro-without-xmacros-a/Impls_1.scala +++ b/test/files/neg/macro-without-xmacros-a/Impls_1.scala @@ -1,17 +1,17 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo_impl(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def foo_impl(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ c.Expr(q"$x + 1") } - def bar_impl(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def bar_impl(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ c.Expr(q"$x + 2") } - def quux_impl(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def quux_impl(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ c.Expr(q"$x + 3") } diff --git a/test/files/neg/macro-without-xmacros-b/Impls_1.scala b/test/files/neg/macro-without-xmacros-b/Impls_1.scala index 6b73a96184..035913f3e3 100644 --- a/test/files/neg/macro-without-xmacros-b/Impls_1.scala +++ b/test/files/neg/macro-without-xmacros-b/Impls_1.scala @@ -1,17 +1,17 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo_impl(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def foo_impl(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ c.Expr(q"$x + 1") } - def bar_impl(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def bar_impl(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ c.Expr(q"$x + 2") } - def quux_impl(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def quux_impl(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ c.Expr(q"$x + 3") } diff --git a/test/files/neg/missing-param-type-tuple.check b/test/files/neg/missing-param-type-tuple.check index bc46ba1023..3a4258ff8c 100644 --- a/test/files/neg/missing-param-type-tuple.check +++ b/test/files/neg/missing-param-type-tuple.check @@ -1,6 +1,6 @@ missing-param-type-tuple.scala:3: error: missing parameter type Note: The expected type requires a one-argument function accepting a 2-Tuple. - Consider a pattern matching anoynmous function, `{ case (a, b) => ... }` + Consider a pattern matching anonymous function, `{ case (a, b) => ... }` val x: ((Int, Int)) => Int = (a, b) => 0 ^ missing-param-type-tuple.scala:3: error: missing parameter type @@ -8,7 +8,7 @@ missing-param-type-tuple.scala:3: error: missing parameter type ^ missing-param-type-tuple.scala:5: error: missing parameter type Note: The expected type requires a one-argument function accepting a 3-Tuple. - Consider a pattern matching anoynmous function, `{ case (param1, ..., param3) => ... }` + Consider a pattern matching anonymous function, `{ case (param1, ..., param3) => ... }` val y: ((Int, Int, Int)) => Int = (a, b, !!) => 0 ^ missing-param-type-tuple.scala:5: error: missing parameter type @@ -19,7 +19,7 @@ missing-param-type-tuple.scala:5: error: missing parameter type ^ missing-param-type-tuple.scala:7: error: missing parameter type Note: The expected type requires a one-argument function accepting a 3-Tuple. - Consider a pattern matching anoynmous function, `{ case (param1, ..., param3) => ... }` + Consider a pattern matching anonymous function, `{ case (param1, ..., param3) => ... }` val z: ((Int, Int, Int)) => Int = (a, NotAVariablePatternName, c) => 0 ^ missing-param-type-tuple.scala:7: error: missing parameter type diff --git a/test/files/neg/name-lookup-stable.check b/test/files/neg/name-lookup-stable.check new file mode 100644 index 0000000000..751df9505e --- /dev/null +++ b/test/files/neg/name-lookup-stable.check @@ -0,0 +1,11 @@ +name-lookup-stable.scala:15: error: reference to PrimaryKey is ambiguous; +it is both defined in class A and imported subsequently by +import ColumnOption._ + (null: Any) match { case PrimaryKey => } + ^ +name-lookup-stable.scala:17: error: reference to PrimaryKey is ambiguous; +it is both defined in class A and imported subsequently by +import ColumnOption._ + PrimaryKey // was already ambigious in 2.10.3 + ^ +two errors found diff --git a/test/files/neg/name-lookup-stable.scala b/test/files/neg/name-lookup-stable.scala new file mode 100644 index 0000000000..0d862f06e1 --- /dev/null +++ b/test/files/neg/name-lookup-stable.scala @@ -0,0 +1,20 @@ +// This used to compile under 2.10.3 but the ambiguity is now noticed +// in 2.11.x (after a70c8219). I think the new behaviour is correct; +// we shouldn't discard names based on "expected stability" before +// evaluating ambiguity. +object ColumnOption { + object PrimaryKey +} + +class A { + def PrimaryKey: Any = ??? + + { + import ColumnOption._ + + (null: Any) match { case PrimaryKey => } + + PrimaryKey // was already ambigious in 2.10.3 + } +} + diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index 880ddc4327..20ddd55f1f 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -88,7 +88,7 @@ names-defaults-neg.scala:76: error: no type parameters for method test4: (x: T[T --- because --- argument expression's type is not compatible with formal parameter type; found : List[Int] - required: ?T + required: ?T[?T[List[?T[X forSome { type X }]]]] Error occurred in an application involving default arguments. test4() ^ diff --git a/test/files/neg/no-implicit-to-anyref-any-val.check b/test/files/neg/no-implicit-to-anyref-any-val.check new file mode 100644 index 0000000000..5953e1bd6d --- /dev/null +++ b/test/files/neg/no-implicit-to-anyref-any-val.check @@ -0,0 +1,34 @@ +no-implicit-to-anyref-any-val.scala:11: error: the result type of an implicit conversion must be more specific than AnyRef + 1: AnyRef + ^ +no-implicit-to-anyref-any-val.scala:17: error: type mismatch; + found : Any + required: AnyRef + (null: Any): AnyRef + ^ +no-implicit-to-anyref-any-val.scala:21: error: type mismatch; + found : AnyVal + required: AnyRef + (0: AnyVal): AnyRef + ^ +no-implicit-to-anyref-any-val.scala:27: error: type mismatch; + found : Test.AV + required: AnyRef +Note that AV extends Any, not AnyRef. +Such types can participate in value classes, but instances +cannot appear in singleton types or in reference comparisons. + new AV(0): AnyRef + ^ +no-implicit-to-anyref-any-val.scala:30: error: the result type of an implicit conversion must be more specific than AnyVal + "": AnyVal + ^ +no-implicit-to-anyref-any-val.scala:32: error: type mismatch; + found : Object + required: AnyVal +Note that implicit conversions are not applicable because they are ambiguous: + both method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A] + and method Ensuring in object Predef of type [A](self: A)Ensuring[A] + are possible conversion functions from Object to AnyVal + new Object() : AnyVal + ^ +6 errors found diff --git a/test/files/neg/no-implicit-to-anyref.scala b/test/files/neg/no-implicit-to-anyref-any-val.scala index 3e3d373e38..f5daf541af 100644 --- a/test/files/neg/no-implicit-to-anyref.scala +++ b/test/files/neg/no-implicit-to-anyref-any-val.scala @@ -26,4 +26,8 @@ object Test { locally { new AV(0): AnyRef } + + "": AnyVal + + new Object() : AnyVal } diff --git a/test/files/neg/no-implicit-to-anyref.check b/test/files/neg/no-implicit-to-anyref.check deleted file mode 100644 index fe417ad8b0..0000000000 --- a/test/files/neg/no-implicit-to-anyref.check +++ /dev/null @@ -1,22 +0,0 @@ -no-implicit-to-anyref.scala:11: error: the result type of an implicit conversion must be more specific than AnyRef - 1: AnyRef - ^ -no-implicit-to-anyref.scala:17: error: type mismatch; - found : Any - required: AnyRef - (null: Any): AnyRef - ^ -no-implicit-to-anyref.scala:21: error: type mismatch; - found : AnyVal - required: AnyRef - (0: AnyVal): AnyRef - ^ -no-implicit-to-anyref.scala:27: error: type mismatch; - found : Test.AV - required: AnyRef -Note that AV extends Any, not AnyRef. -Such types can participate in value classes, but instances -cannot appear in singleton types or in reference comparisons. - new AV(0): AnyRef - ^ -four errors found diff --git a/test/files/neg/quasiquotes-syntax-error-position.check b/test/files/neg/quasiquotes-syntax-error-position.check index 25e5b8d75a..14fef16e01 100644 --- a/test/files/neg/quasiquotes-syntax-error-position.check +++ b/test/files/neg/quasiquotes-syntax-error-position.check @@ -29,4 +29,7 @@ quasiquotes-syntax-error-position.scala:13: error: end of quote expected but 'ca quasiquotes-syntax-error-position.scala:14: error: ')' expected but end of quote found. pq"$a(bar" ^ -10 errors found +quasiquotes-syntax-error-position.scala:15: error: ':' expected but ')' found. + q"def foo(x)" + ^ +11 errors found diff --git a/test/files/neg/quasiquotes-syntax-error-position.scala b/test/files/neg/quasiquotes-syntax-error-position.scala index b97af52cfc..7b1d66ba00 100644 --- a/test/files/neg/quasiquotes-syntax-error-position.scala +++ b/test/files/neg/quasiquotes-syntax-error-position.scala @@ -12,4 +12,5 @@ object test extends App { tq"$t => $t $t]" cq"pattern => body ; case pattern2 =>" pq"$a(bar" -}
\ No newline at end of file + q"def foo(x)" +} diff --git a/test/files/neg/stringinterpolation_macro-neg.check b/test/files/neg/stringinterpolation_macro-neg.check index 457f497f2f..703846ad62 100644 --- a/test/files/neg/stringinterpolation_macro-neg.check +++ b/test/files/neg/stringinterpolation_macro-neg.check @@ -1,61 +1,61 @@ -stringinterpolation_macro-neg.scala:8: error: too few parts +stringinterpolation_macro-neg.scala:13: error: there are no parts new StringContext().f() ^ -stringinterpolation_macro-neg.scala:9: error: too few arguments for interpolated string +stringinterpolation_macro-neg.scala:14: error: too few arguments for interpolated string new StringContext("", " is ", "%2d years old").f(s) ^ -stringinterpolation_macro-neg.scala:10: error: too many arguments for interpolated string +stringinterpolation_macro-neg.scala:15: error: too many arguments for interpolated string new StringContext("", " is ", "%2d years old").f(s, d, d) ^ -stringinterpolation_macro-neg.scala:11: error: too few arguments for interpolated string +stringinterpolation_macro-neg.scala:16: error: too few arguments for interpolated string new StringContext("", "").f() ^ -stringinterpolation_macro-neg.scala:14: error: type mismatch; +stringinterpolation_macro-neg.scala:19: error: type mismatch; found : String required: Boolean f"$s%b" ^ -stringinterpolation_macro-neg.scala:15: error: type mismatch; +stringinterpolation_macro-neg.scala:20: error: type mismatch; found : String required: Char f"$s%c" ^ -stringinterpolation_macro-neg.scala:16: error: type mismatch; +stringinterpolation_macro-neg.scala:21: error: type mismatch; found : Double required: Char f"$f%c" ^ -stringinterpolation_macro-neg.scala:17: error: type mismatch; +stringinterpolation_macro-neg.scala:22: error: type mismatch; found : String required: Int f"$s%x" ^ -stringinterpolation_macro-neg.scala:18: error: type mismatch; +stringinterpolation_macro-neg.scala:23: error: type mismatch; found : Boolean required: Int f"$b%d" ^ -stringinterpolation_macro-neg.scala:19: error: type mismatch; +stringinterpolation_macro-neg.scala:24: error: type mismatch; found : String required: Int f"$s%d" ^ -stringinterpolation_macro-neg.scala:20: error: type mismatch; +stringinterpolation_macro-neg.scala:25: error: type mismatch; found : Double required: Int f"$f%o" ^ -stringinterpolation_macro-neg.scala:21: error: type mismatch; +stringinterpolation_macro-neg.scala:26: error: type mismatch; found : String required: Double f"$s%e" ^ -stringinterpolation_macro-neg.scala:22: error: type mismatch; +stringinterpolation_macro-neg.scala:27: error: type mismatch; found : Boolean required: Double f"$b%f" ^ -stringinterpolation_macro-neg.scala:27: error: type mismatch; +stringinterpolation_macro-neg.scala:32: error: type mismatch; found : String required: Int Note that implicit conversions are not applicable because they are ambiguous: @@ -64,7 +64,109 @@ Note that implicit conversions are not applicable because they are ambiguous: are possible conversion functions from String to Int f"$s%d" ^ -stringinterpolation_macro-neg.scala:30: error: illegal conversion character +stringinterpolation_macro-neg.scala:35: error: illegal conversion character 'i' f"$s%i" ^ -15 errors found +stringinterpolation_macro-neg.scala:38: error: Illegal flag '+' + f"$s%+ 0,(s" + ^ +stringinterpolation_macro-neg.scala:38: error: Illegal flag ' ' + f"$s%+ 0,(s" + ^ +stringinterpolation_macro-neg.scala:38: error: Illegal flag '0' + f"$s%+ 0,(s" + ^ +stringinterpolation_macro-neg.scala:38: error: Illegal flag ',' + f"$s%+ 0,(s" + ^ +stringinterpolation_macro-neg.scala:38: error: Illegal flag '(' + f"$s%+ 0,(s" + ^ +stringinterpolation_macro-neg.scala:39: error: Only '-' allowed for c conversion + f"$c%#+ 0,(c" + ^ +stringinterpolation_macro-neg.scala:40: error: # not allowed for d conversion + f"$d%#d" + ^ +stringinterpolation_macro-neg.scala:41: error: ',' only allowed for d conversion of integral types + f"$d%,x" + ^ +stringinterpolation_macro-neg.scala:42: error: only use '+' for BigInt conversions to o, x, X + f"$d%+ (x" + ^ +stringinterpolation_macro-neg.scala:42: error: only use ' ' for BigInt conversions to o, x, X + f"$d%+ (x" + ^ +stringinterpolation_macro-neg.scala:42: error: only use '(' for BigInt conversions to o, x, X + f"$d%+ (x" + ^ +stringinterpolation_macro-neg.scala:43: error: ',' not allowed for a, A + f"$f%,(a" + ^ +stringinterpolation_macro-neg.scala:43: error: '(' not allowed for a, A + f"$f%,(a" + ^ +stringinterpolation_macro-neg.scala:44: error: Only '-' allowed for date/time conversions + f"$t%#+ 0,(tT" + ^ +stringinterpolation_macro-neg.scala:47: error: precision not allowed + f"$c%.2c" + ^ +stringinterpolation_macro-neg.scala:48: error: precision not allowed + f"$d%.2d" + ^ +stringinterpolation_macro-neg.scala:49: error: precision not allowed + f"%.2%" + ^ +stringinterpolation_macro-neg.scala:50: error: precision not allowed + f"%.2n" + ^ +stringinterpolation_macro-neg.scala:51: error: precision not allowed + f"$f%.2a" + ^ +stringinterpolation_macro-neg.scala:52: error: precision not allowed + f"$t%.2tT" + ^ +stringinterpolation_macro-neg.scala:55: error: No last arg + f"%<s" + ^ +stringinterpolation_macro-neg.scala:56: error: No last arg + f"%<c" + ^ +stringinterpolation_macro-neg.scala:57: error: No last arg + f"%<tT" + ^ +stringinterpolation_macro-neg.scala:58: error: Argument index out of range + f"${8}%d ${9}%d%3$$d" + ^ +stringinterpolation_macro-neg.scala:59: error: Argument index out of range + f"${8}%d ${9}%d%0$$d" + ^ +stringinterpolation_macro-neg.scala:62: warning: Index is not this arg + f"${8}%d ${9}%1$$d" + ^ +stringinterpolation_macro-neg.scala:63: warning: Argument index ignored if '<' flag is present + f"$s%s $s%s %1$$<s" + ^ +stringinterpolation_macro-neg.scala:64: warning: Index is not this arg + f"$s%s $s%1$$s" + ^ +stringinterpolation_macro-neg.scala:67: error: type mismatch; + found : String + required: java.util.Formattable + f"$s%#s" + ^ +stringinterpolation_macro-neg.scala:70: error: 'G' doesn't seem to be a date or time conversion + f"$t%tG" + ^ +stringinterpolation_macro-neg.scala:71: error: Date/time conversion must have two characters + f"$t%t" + ^ +stringinterpolation_macro-neg.scala:72: error: Missing conversion operator in '%10.5'; use %% for literal %, %n for newline + f"$s%10.5" + ^ +stringinterpolation_macro-neg.scala:75: error: conversions must follow a splice; use %% for literal %, %n for newline + f"${d}random-leading-junk%d" + ^ +three warnings found +45 errors found diff --git a/test/files/neg/stringinterpolation_macro-neg.scala b/test/files/neg/stringinterpolation_macro-neg.scala index ac9d97d678..3869d42d66 100644 --- a/test/files/neg/stringinterpolation_macro-neg.scala +++ b/test/files/neg/stringinterpolation_macro-neg.scala @@ -3,6 +3,11 @@ object Test extends App { val d = 8 val b = false val f = 3.14159 + val c = 'c' + val t = new java.util.Date + val x = new java.util.Formattable { + def formatTo(ff: java.util.Formatter, g: Int, w: Int, p: Int): Unit = ff format "xxx" + } // 1) number of arguments new StringContext().f() @@ -28,4 +33,44 @@ object Test extends App { } f"$s%i" + + // 3) flag mismatches + f"$s%+ 0,(s" + f"$c%#+ 0,(c" + f"$d%#d" + f"$d%,x" + f"$d%+ (x" + f"$f%,(a" + f"$t%#+ 0,(tT" + + // 4) bad precisions + f"$c%.2c" + f"$d%.2d" + f"%.2%" + f"%.2n" + f"$f%.2a" + f"$t%.2tT" + + // 5) bad indexes + f"%<s" + f"%<c" + f"%<tT" + f"${8}%d ${9}%d%3$$d" + f"${8}%d ${9}%d%0$$d" + + // warnings + f"${8}%d ${9}%1$$d" + f"$s%s $s%s %1$$<s" + f"$s%s $s%1$$s" + + // 6) bad arg types + f"$s%#s" + + // 7) misunderstood conversions + f"$t%tG" + f"$t%t" + f"$s%10.5" + + // 8) other brain failures + f"${d}random-leading-junk%d" } diff --git a/test/files/neg/t0764.check b/test/files/neg/t0764.check deleted file mode 100644 index 6156b52712..0000000000 --- a/test/files/neg/t0764.check +++ /dev/null @@ -1,7 +0,0 @@ -t0764.scala:13: error: type mismatch; - found : Node{type T = _1.type} where val _1: Node{type T = NextType} - required: Node{type T = Main.this.AType} - (which expands to) Node{type T = Node{type T = NextType}} - new Main[AType]( (value: AType).prepend ) - ^ -one error found diff --git a/test/files/neg/t0764.scala b/test/files/neg/t0764.scala deleted file mode 100644 index f2cc65cf7d..0000000000 --- a/test/files/neg/t0764.scala +++ /dev/null @@ -1,14 +0,0 @@ -class Top[A] { - type AType = A -} - -trait Node { outer => - type T <: Node - def prepend = new Node { type T = outer.type } -} - -class Main[NextType <: Node](value: Node { type T = NextType }) - extends Top[Node { type T = NextType }] { - - new Main[AType]( (value: AType).prepend ) -} diff --git a/test/files/neg/t2066.check b/test/files/neg/t2066.check new file mode 100644 index 0000000000..efade87e26 --- /dev/null +++ b/test/files/neg/t2066.check @@ -0,0 +1,21 @@ +t2066.scala:6: error: overriding method f in trait A1 of type [T[_]]=> Unit; + method f has incompatible type + override def f[T[+_]] = () + ^ +t2066.scala:10: error: overriding method f in trait A1 of type [T[_]]=> Unit; + method f has incompatible type + override def f[T[-_]] = () + ^ +t2066.scala:23: error: overriding method f in trait A2 of type [T[+_]]=> Unit; + method f has incompatible type + override def f[T[-_]] = () + ^ +t2066.scala:45: error: overriding method f in trait A4 of type [T[X[+_]]]=> Unit; + method f has incompatible type + override def f[T[X[_]]] = () + ^ +t2066.scala:53: error: overriding method f in trait A5 of type [T[X[-_]]]=> Unit; + method f has incompatible type + override def f[T[X[_]]] = () + ^ +5 errors found diff --git a/test/files/neg/t2066.scala b/test/files/neg/t2066.scala new file mode 100644 index 0000000000..7f15d39c67 --- /dev/null +++ b/test/files/neg/t2066.scala @@ -0,0 +1,70 @@ +trait A1 { + def f[T[_]] = () +} + +trait B1 extends A1 { + override def f[T[+_]] = () +} + +trait C1 extends A1 { + override def f[T[-_]] = () +} + + +trait A2 { + def f[T[+_]] = () +} + +trait B2 extends A2 { + override def f[T[_]] = () // okay +} + +trait C2 extends A2 { + override def f[T[-_]] = () +} + + +trait A3 { + def f[T[-_]] = () +} + +trait B3 extends A3 { + override def f[T[_]] = () // okay +} + +trait C3 extends A3 { + override def f[T[-_]] = () +} + + +trait A4 { + def f[T[X[+_]]] = () +} + +trait B4 extends A4 { + override def f[T[X[_]]] = () +} + +trait A5 { + def f[T[X[-_]]] = () +} + +trait B5 extends A5 { + override def f[T[X[_]]] = () +} + + + +trait A6 { + def f[T[X[_]]] = () +} + +trait B6 extends A6 { + override def f[T[X[+_]]] = () // okay +} +trait C6 extends A6 { + override def f[T[X[_]]] = () // okay +} +trait D6 extends A6 { + override def f[T[X[-_]]] = () +} diff --git a/test/files/neg/t2066b.check b/test/files/neg/t2066b.check new file mode 100644 index 0000000000..097c44fef3 --- /dev/null +++ b/test/files/neg/t2066b.check @@ -0,0 +1,5 @@ +t2066b.scala:7: error: overriding method f in trait A of type [T[_]](x: T[Int])T[Any]; + method f has incompatible type + def f[T[+_]](x : T[Int]) : T[Any] = x + ^ +one error found diff --git a/test/pending/neg/t2066.scala b/test/files/neg/t2066b.scala index 46177b19f7..46177b19f7 100644 --- a/test/pending/neg/t2066.scala +++ b/test/files/neg/t2066b.scala diff --git a/test/files/neg/t3403.scala b/test/files/neg/t3403.scala index 8be6ab2a31..7cf0c3e0f7 100644 --- a/test/files/neg/t3403.scala +++ b/test/files/neg/t3403.scala @@ -1,2 +1,2 @@ -import scala.reflect.{BeanProperty => bp} +import scala.beans.{BeanProperty => bp} class Foo { @bp var bar: Int = 1 } diff --git a/test/files/neg/t3873.check b/test/files/neg/t3873.check index 54d6abdf63..f9f413aeaf 100644 --- a/test/files/neg/t3873.check +++ b/test/files/neg/t3873.check @@ -1,6 +1,6 @@ t3873.scala:11: error: type mismatch; found : Test.a.B - required: a.B - wrongf(new A)(a.b) // should not compile -- TODO: improve error message? the "a" is ambiguous + required: a.B where val a: A + wrongf(new A)(a.b) // should not compile ^ one error found diff --git a/test/files/neg/t3873.scala b/test/files/neg/t3873.scala index e7815f0937..b27b4e9c9d 100644 --- a/test/files/neg/t3873.scala +++ b/test/files/neg/t3873.scala @@ -8,5 +8,5 @@ object Test { val a = new A wrongf(a)(a.b) - wrongf(new A)(a.b) // should not compile -- TODO: improve error message? the "a" is ambiguous + wrongf(new A)(a.b) // should not compile }
\ No newline at end of file diff --git a/test/files/neg/t4425.check b/test/files/neg/t4425.check index 95b88a6b3d..00006c08f0 100644 --- a/test/files/neg/t4425.check +++ b/test/files/neg/t4425.check @@ -1,12 +1,12 @@ -t4425.scala:3: error: object X is not a case class constructor, nor does it have an unapply/unapplySeq method +t4425.scala:3: error: object X is not a case class, nor does it have an unapply/unapplySeq member Note: def unapply(x: Int)(y: Option[Int]): None.type exists in object X, but it cannot be used as an extractor due to its second non-implicit parameter list 42 match { case _ X _ => () } ^ -t4425.scala:8: error: object X is not a case class constructor, nor does it have an unapply/unapplySeq method +t4425.scala:8: error: object X is not a case class, nor does it have an unapply/unapplySeq member Note: def unapply(x: Int)(y: Int): Some[(Int, Int)] exists in object X, but it cannot be used as an extractor due to its second non-implicit parameter list 42 match { case _ X _ => () } ^ -t4425.scala:13: error: object X is not a case class constructor, nor does it have an unapply/unapplySeq method +t4425.scala:13: error: object X is not a case class, nor does it have an unapply/unapplySeq member Note: def unapply(x: String)(y: String): Some[(Int, Int)] exists in object X, but it cannot be used as an extractor due to its second non-implicit parameter list "" match { case _ X _ => () } ^ diff --git a/test/files/neg/t4425b.check b/test/files/neg/t4425b.check index 1186e8b609..8418b4fd12 100644 --- a/test/files/neg/t4425b.check +++ b/test/files/neg/t4425b.check @@ -1,61 +1,49 @@ -t4425b.scala:5: error: object X is not a case class constructor, nor does it have an unapply/unapplySeq method +t4425b.scala:5: error: object X is not a case class, nor does it have an unapply/unapplySeq member Note: def unapply(x: String)(y: String): Nothing exists in object X, but it cannot be used as an extractor due to its second non-implicit parameter list println( "" match { case _ X _ => "ok" ; case _ => "fail" }) ^ -t4425b.scala:6: error: object X is not a case class constructor, nor does it have an unapply/unapplySeq method +t4425b.scala:6: error: object X is not a case class, nor does it have an unapply/unapplySeq member Note: def unapply(x: String)(y: String): Nothing exists in object X, but it cannot be used as an extractor due to its second non-implicit parameter list println((X: Any) match { case _ X _ => "ok" ; case _ => "fail" }) ^ -t4425b.scala:7: error: object X is not a case class constructor, nor does it have an unapply/unapplySeq method +t4425b.scala:7: error: object X is not a case class, nor does it have an unapply/unapplySeq member Note: def unapply(x: String)(y: String): Nothing exists in object X, but it cannot be used as an extractor due to its second non-implicit parameter list println( "" match { case X(_) => "ok" ; case _ => "fail" }) ^ -t4425b.scala:8: error: object X is not a case class constructor, nor does it have an unapply/unapplySeq method +t4425b.scala:8: error: object X is not a case class, nor does it have an unapply/unapplySeq member Note: def unapply(x: String)(y: String): Nothing exists in object X, but it cannot be used as an extractor due to its second non-implicit parameter list println((X: Any) match { case X(_) => "ok" ; case _ => "fail" }) ^ -t4425b.scala:9: error: object X is not a case class constructor, nor does it have an unapply/unapplySeq method +t4425b.scala:9: error: object X is not a case class, nor does it have an unapply/unapplySeq member Note: def unapply(x: String)(y: String): Nothing exists in object X, but it cannot be used as an extractor due to its second non-implicit parameter list println( "" match { case X(_, _) => "ok" ; case _ => "fail" }) ^ -t4425b.scala:10: error: object X is not a case class constructor, nor does it have an unapply/unapplySeq method +t4425b.scala:10: error: object X is not a case class, nor does it have an unapply/unapplySeq member Note: def unapply(x: String)(y: String): Nothing exists in object X, but it cannot be used as an extractor due to its second non-implicit parameter list println((X: Any) match { case X(_, _) => "ok" ; case _ => "fail" }) ^ -t4425b.scala:18: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 +t4425b.scala:18: error: too many patterns for object X: expected 1, found 2 println( "" match { case _ X _ => "ok" ; case _ => "fail" }) ^ -t4425b.scala:19: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 +t4425b.scala:19: error: too many patterns for object X: expected 1, found 2 println((X: Any) match { case _ X _ => "ok" ; case _ => "fail" }) ^ -t4425b.scala:22: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 +t4425b.scala:22: error: too many patterns for object X: expected 1, found 2 println( "" match { case X(_, _) => "ok" ; case _ => "fail" }) ^ -t4425b.scala:22: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 - println( "" match { case X(_, _) => "ok" ; case _ => "fail" }) - ^ -t4425b.scala:23: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 +t4425b.scala:23: error: too many patterns for object X: expected 1, found 2 println((X: Any) match { case X(_, _) => "ok" ; case _ => "fail" }) ^ -t4425b.scala:23: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 - println((X: Any) match { case X(_, _) => "ok" ; case _ => "fail" }) - ^ -t4425b.scala:31: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 +t4425b.scala:31: error: too many patterns for object X offering Nothing: expected 1, found 2 println( "" match { case _ X _ => "ok" ; case _ => "fail" }) ^ -t4425b.scala:32: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 +t4425b.scala:32: error: too many patterns for object X offering Nothing: expected 1, found 2 println((X: Any) match { case _ X _ => "ok" ; case _ => "fail" }) ^ -t4425b.scala:35: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 +t4425b.scala:35: error: too many patterns for object X offering Nothing: expected 1, found 2 println( "" match { case X(_, _) => "ok" ; case _ => "fail" }) ^ -t4425b.scala:35: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 - println( "" match { case X(_, _) => "ok" ; case _ => "fail" }) - ^ -t4425b.scala:36: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 +t4425b.scala:36: error: too many patterns for object X offering Nothing: expected 1, found 2 println((X: Any) match { case X(_, _) => "ok" ; case _ => "fail" }) ^ -t4425b.scala:36: error: wrong number of patterns for object X offering Nothing: expected 1, found 2 - println((X: Any) match { case X(_, _) => "ok" ; case _ => "fail" }) - ^ -18 errors found +14 errors found diff --git a/test/files/neg/t4818.check b/test/files/neg/t4818.check index 8a2c024b30..a5e15e456b 100644 --- a/test/files/neg/t4818.check +++ b/test/files/neg/t4818.check @@ -1,6 +1,6 @@ t4818.scala:4: error: type mismatch; found : Int(5) - required: A + required: Nothing def f(x: Any) = x match { case Fn(f) => f(5) } ^ one error found diff --git a/test/files/neg/t4851.check b/test/files/neg/t4851.check index 4f2919807e..132dd91b50 100644 --- a/test/files/neg/t4851.check +++ b/test/files/neg/t4851.check @@ -1,10 +1,10 @@ -S.scala:2: warning: Adapting argument list by inserting (): leaky (Object-receiving) target makes this especially dangerous. +S.scala:2: warning: Adaptation of argument list by inserting () has been deprecated: leaky (Object-receiving) target makes this especially dangerous. signature: J(x: Any): J given arguments: <none> after adaptation: new J((): Unit) val x1 = new J ^ -S.scala:3: warning: Adapting argument list by inserting (): leaky (Object-receiving) target makes this especially dangerous. +S.scala:3: warning: Adaptation of argument list by inserting () has been deprecated: leaky (Object-receiving) target makes this especially dangerous. signature: J(x: Any): J given arguments: <none> after adaptation: new J((): Unit) @@ -28,13 +28,13 @@ S.scala:7: warning: Adapting argument list by creating a 3-tuple: this may not b after adaptation: new Some((1, 2, 3): (Int, Int, Int)) val y2 = new Some(1, 2, 3) ^ -S.scala:9: warning: Adapting argument list by inserting (): this is unlikely to be what you want. +S.scala:9: warning: Adaptation of argument list by inserting () has been deprecated: this is unlikely to be what you want. signature: J2[T](x: T): J2[T] given arguments: <none> after adaptation: new J2((): Unit) val z1 = new J2 ^ -S.scala:10: warning: Adapting argument list by inserting (): this is unlikely to be what you want. +S.scala:10: warning: Adaptation of argument list by inserting () has been deprecated: this is unlikely to be what you want. signature: J2[T](x: T): J2[T] given arguments: <none> after adaptation: new J2((): Unit) diff --git a/test/files/neg/t4851.flags b/test/files/neg/t4851.flags index 0545cb8b84..ca0d0a0ba3 100644 --- a/test/files/neg/t4851.flags +++ b/test/files/neg/t4851.flags @@ -1 +1 @@ --Ywarn-adapted-args -Xfatal-warnings +-Ywarn-adapted-args -Xfatal-warnings -deprecation diff --git a/test/files/neg/t5189.check b/test/files/neg/t5189.check index aecc1d11c4..4885de99cd 100644 --- a/test/files/neg/t5189.check +++ b/test/files/neg/t5189.check @@ -1,5 +1,5 @@ t5189.scala:3: error: type mismatch; - found : T => U + found : Nothing => Any required: Any => Any def f(x: Any): Any => Any = x match { case Foo(bar) => bar } ^ diff --git a/test/files/neg/t5689.check b/test/files/neg/t5689.check index 9271f709ca..7d4f7fb63a 100644 --- a/test/files/neg/t5689.check +++ b/test/files/neg/t5689.check @@ -1,7 +1,7 @@ t5689.scala:4: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext)(i: c.Expr[Double]): c.Expr[String] - or : (c: scala.reflect.macros.BlackboxContext)(i: c.Tree): c.Tree - found : (c: scala.reflect.macros.BlackboxContext)(i: c.Expr[Double]): c.Expr[Int] + required: (c: scala.reflect.macros.blackbox.Context)(i: c.Expr[Double]): c.Expr[String] + or : (c: scala.reflect.macros.blackbox.Context)(i: c.Tree): c.Tree + found : (c: scala.reflect.macros.blackbox.Context)(i: c.Expr[Double]): c.Expr[Int] type mismatch for return type: c.Expr[Int] does not conform to c.Expr[String] def returnsString(i: Double): String = macro returnsIntImpl ^ diff --git a/test/files/neg/t5689.scala b/test/files/neg/t5689.scala index d0e468849d..d757a55417 100644 --- a/test/files/neg/t5689.scala +++ b/test/files/neg/t5689.scala @@ -1,6 +1,6 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { def returnsString(i: Double): String = macro returnsIntImpl - def returnsIntImpl(c: BlackboxContext)(i: c.Expr[Double]): c.Expr[Int] = ??? + def returnsIntImpl(c: Context)(i: c.Expr[Double]): c.Expr[Int] = ??? } diff --git a/test/files/neg/t5753/Impls_Macros_1.scala b/test/files/neg/t5753/Impls_Macros_1.scala index 0e81e21c77..9872c69171 100644 --- a/test/files/neg/t5753/Impls_Macros_1.scala +++ b/test/files/neg/t5753/Impls_Macros_1.scala @@ -1,6 +1,6 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context trait Impls { - def impl(c: Ctx)(x: c.Expr[Any]) = x + def impl(c: Context)(x: c.Expr[Any]) = x } diff --git a/test/files/neg/t5753/Test_2.scala b/test/files/neg/t5753/Test_2.scala index 150850a0eb..d52ed65c60 100644 --- a/test/files/neg/t5753/Test_2.scala +++ b/test/files/neg/t5753/Test_2.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Macros extends Impls { def foo(x: Any): Any = macro impl diff --git a/test/files/neg/t5903a.check b/test/files/neg/t5903a.check index 2e5cc87167..34003b0a82 100644 --- a/test/files/neg/t5903a.check +++ b/test/files/neg/t5903a.check @@ -1,4 +1,4 @@ -Test_2.scala:4: error: wrong number of patterns for <$anon: AnyRef> offering (SomeTree.type, SomeTree.type): expected 2, found 3 +Test_2.scala:4: error: too many patterns for <$anon: AnyRef> offering (SomeTree.type, SomeTree.type): expected 2, found 3 case nq"$x + $y + $z" => println((x, y)) ^ one error found diff --git a/test/files/neg/t5903a/Macros_1.scala b/test/files/neg/t5903a/Macros_1.scala index ce1b035260..5d084ceed5 100644 --- a/test/files/neg/t5903a/Macros_1.scala +++ b/test/files/neg/t5903a/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import language.experimental.macros trait Tree @@ -13,7 +13,7 @@ object NewQuasiquotes { } object QuasiquoteMacros { - def unapplyImpl(c: WhiteboxContext)(t: c.Tree) = { + def unapplyImpl(c: Context)(t: c.Tree) = { import c.universe._ q""" new { diff --git a/test/files/neg/t5903b/Macros_1.scala b/test/files/neg/t5903b/Macros_1.scala index dfe9d8d489..6ce49c0228 100644 --- a/test/files/neg/t5903b/Macros_1.scala +++ b/test/files/neg/t5903b/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros object Interpolation { @@ -10,7 +10,7 @@ object Interpolation { } object Macros { - def unapplyImpl[T: c.WeakTypeTag](c: BlackboxContext)(x: c.Tree) = { + def unapplyImpl[T: c.WeakTypeTag](c: Context)(x: c.Tree) = { import c.universe._ q""" new { diff --git a/test/files/neg/t5903c/Macros_1.scala b/test/files/neg/t5903c/Macros_1.scala index d13c3c2ec2..4792f00454 100644 --- a/test/files/neg/t5903c/Macros_1.scala +++ b/test/files/neg/t5903c/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros object Interpolation { @@ -10,7 +10,7 @@ object Interpolation { } object Macros { - def unapplyImpl[T: c.WeakTypeTag](c: BlackboxContext)(x: c.Tree) = { + def unapplyImpl[T: c.WeakTypeTag](c: Context)(x: c.Tree) = { import c.universe._ if (!(c.weakTypeOf[Int] =:= c.weakTypeOf[T])) c.abort(c.enclosingPosition, s"${c.weakTypeOf[T]} is not supported") else { diff --git a/test/files/neg/t5903d/Macros_1.scala b/test/files/neg/t5903d/Macros_1.scala index 2d26e998a1..3500c2a782 100644 --- a/test/files/neg/t5903d/Macros_1.scala +++ b/test/files/neg/t5903d/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros object Interpolation { @@ -10,7 +10,7 @@ object Interpolation { } object Macros { - def unapplyImpl(c: BlackboxContext)(x: c.Tree) = { + def unapplyImpl(c: Context)(x: c.Tree) = { import c.universe._ q""" class Match(x: Int) { diff --git a/test/files/neg/t5903e/Macros_1.scala b/test/files/neg/t5903e/Macros_1.scala index 5bdc25b832..a64ff7e0b9 100644 --- a/test/files/neg/t5903e/Macros_1.scala +++ b/test/files/neg/t5903e/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import language.experimental.macros object Interpolation { @@ -10,7 +10,7 @@ object Interpolation { } object Macros { - def unapplyImpl(c: WhiteboxContext)(x: c.Tree) = { + def unapplyImpl(c: Context)(x: c.Tree) = { import c.universe._ q""" new { diff --git a/test/files/neg/t6123-explaintypes-macros.check b/test/files/neg/t6123-explaintypes-macros.check index ef545fcc32..2c86f3c9cc 100644 --- a/test/files/neg/t6123-explaintypes-macros.check +++ b/test/files/neg/t6123-explaintypes-macros.check @@ -1,9 +1,9 @@ c.universe.Expr[Any]* <: c.universe.Expr[String]*? false BadMac_2.scala:6: error: macro implementation has incompatible shape: - required: (c: scala.reflect.macros.BlackboxContext)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] - or : (c: scala.reflect.macros.BlackboxContext)(format: c.Tree, params: Tree*): c.Tree - found : (c: scala.reflect.macros.BlackboxContext)(format: c.Expr[String], params: c.Expr[String]*): c.Expr[Unit] + required: (c: scala.reflect.macros.blackbox.Context)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] + or : (c: scala.reflect.macros.blackbox.Context)(format: c.Tree, params: Tree*): c.Tree + found : (c: scala.reflect.macros.blackbox.Context)(format: c.Expr[String], params: c.Expr[String]*): c.Expr[Unit] type mismatch for parameter params: c.Expr[Any]* does not conform to c.Expr[String]* def printf(format: String, params: Any*): Unit = macro printf_impl ^ diff --git a/test/files/neg/t6123-explaintypes-macros/BadMac_2.scala b/test/files/neg/t6123-explaintypes-macros/BadMac_2.scala index 456e753893..75ded4ef7d 100644 --- a/test/files/neg/t6123-explaintypes-macros/BadMac_2.scala +++ b/test/files/neg/t6123-explaintypes-macros/BadMac_2.scala @@ -1,8 +1,8 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context // explain some macro types to me object BadMac { def printf(format: String, params: Any*): Unit = macro printf_impl - def printf_impl(c: BlackboxContext)(format: c.Expr[String], params: c.Expr[String]*): c.Expr[Unit] = ??? + def printf_impl(c: Context)(format: c.Expr[String], params: c.Expr[String]*): c.Expr[Unit] = ??? } diff --git a/test/files/neg/t6123-explaintypes-macros/Macros.scala b/test/files/neg/t6123-explaintypes-macros/Macros.scala index cdcea34272..f2238b39a7 100644 --- a/test/files/neg/t6123-explaintypes-macros/Macros.scala +++ b/test/files/neg/t6123-explaintypes-macros/Macros.scala @@ -1,9 +1,9 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { def printf(format: String, params: Any*): Unit = macro printf_impl - def printf_impl(c: BlackboxContext)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = ??? + def printf_impl(c: Context)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = ??? } // something trivial to run diff --git a/test/files/neg/t6260-named.check b/test/files/neg/t6260-named.check new file mode 100644 index 0000000000..ed6ab5e76f --- /dev/null +++ b/test/files/neg/t6260-named.check @@ -0,0 +1,13 @@ +t6260-named.scala:12: error: bridge generated for member method apply: (a: C[Any])C[Any] in object O +which overrides method apply: (v1: T1)R in trait Function1 +clashes with definition of the member itself; +both have erased type (v1: Object)Object + def apply(a: C[Any]) = a + ^ +t6260-named.scala:14: error: bridge generated for member method apply: (a: C[Any])C[Any] in class X +which overrides method apply: (a: A)A in trait T +clashes with definition of the member itself; +both have erased type (a: Object)Object + class X extends T[C[Any]] { def apply(a: C[Any]) = a } + ^ +two errors found diff --git a/test/files/neg/t6260-named.scala b/test/files/neg/t6260-named.scala new file mode 100644 index 0000000000..7cd9ce8473 --- /dev/null +++ b/test/files/neg/t6260-named.scala @@ -0,0 +1,15 @@ +class C[A](private val a: Any) extends AnyVal +trait T[A] { + def apply(a: A): A +} + +object Test { + (x: C[Any]) => {println(s"f($x)"); x} // okay + new T[C[Any]] { def apply(a: C[Any]) = a } // okay + + // we can't rename the specific apply method to avoid the clash + object O extends Function1[C[Any], C[Any]] { + def apply(a: C[Any]) = a + } + class X extends T[C[Any]] { def apply(a: C[Any]) = a } +} diff --git a/test/files/neg/t6260.check b/test/files/neg/t6260.check deleted file mode 100644 index 60c4add143..0000000000 --- a/test/files/neg/t6260.check +++ /dev/null @@ -1,13 +0,0 @@ -t6260.scala:3: error: bridge generated for member method apply: (bx: Box[X])Box[Y] in <$anon: Box[X] => Box[Y]> -which overrides method apply: (v1: T1)R in trait Function1 -clashes with definition of the member itself; -both have erased type (v1: Object)Object - ((bx: Box[X]) => new Box(f(bx.x)))(this) - ^ -t6260.scala:8: error: bridge generated for member method apply: (bx: Box[X])Box[Y] in <$anon: Box[X] => Box[Y]> -which overrides method apply: (v1: T1)R in trait Function1 -clashes with definition of the member itself; -both have erased type (v1: Object)Object - ((bx: Box[X]) => new Box(f(bx.x)))(self) - ^ -two errors found diff --git a/test/files/neg/t6260b.check b/test/files/neg/t6260b.check deleted file mode 100644 index 3a7e8947aa..0000000000 --- a/test/files/neg/t6260b.check +++ /dev/null @@ -1,7 +0,0 @@ -t6260b.scala:3: error: bridge generated for member method apply: ()X in <$anon: () => X> -which overrides method apply: ()R in trait Function0 -clashes with definition of the member itself; -both have erased type ()Object -class Y { def f = new X("") or new X("") } - ^ -one error found diff --git a/test/files/neg/t6426.check b/test/files/neg/t6426.check deleted file mode 100644 index 149f74c4de..0000000000 --- a/test/files/neg/t6426.check +++ /dev/null @@ -1,7 +0,0 @@ -t6426.scala:4: error: wildcard invalid as backquoted identifier - println(`_`.Buffer(0)) - ^ -t6426.scala:5: error: ')' expected but '}' found. -} -^ -two errors found diff --git a/test/files/neg/t6426.scala b/test/files/neg/t6426.scala deleted file mode 100644 index a27d18eb58..0000000000 --- a/test/files/neg/t6426.scala +++ /dev/null @@ -1,5 +0,0 @@ -class A { - import collection.{mutable => _, _} - - println(`_`.Buffer(0)) -} diff --git a/test/files/neg/t6539/Macro_1.scala b/test/files/neg/t6539/Macro_1.scala index 454489752c..60db669c46 100644 --- a/test/files/neg/t6539/Macro_1.scala +++ b/test/files/neg/t6539/Macro_1.scala @@ -1,9 +1,9 @@ import language.experimental.macros -import reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object M { def m(a: Any, b: Any): Any = macro mImpl - def mImpl(c: BlackboxContext)(a: c.Expr[Any], b: c.Expr[Any]) = c.universe.reify(println(a.splice)) + def mImpl(c: Context)(a: c.Expr[Any], b: c.Expr[Any]) = c.universe.reify(println(a.splice)) @reflect.internal.annotations.compileTimeOnly("cto may only be used as an argument to " + "m") def cto = 0 diff --git a/test/files/neg/t6563.check b/test/files/neg/t6563.check new file mode 100644 index 0000000000..75dca1507d --- /dev/null +++ b/test/files/neg/t6563.check @@ -0,0 +1,4 @@ +t6563.scala:4: error: not found: value e + e("f") + ^ +one error found diff --git a/test/files/neg/t6563.scala b/test/files/neg/t6563.scala new file mode 100644 index 0000000000..b0077b6f94 --- /dev/null +++ b/test/files/neg/t6563.scala @@ -0,0 +1,8 @@ +class A{ + def b(c: => Unit){} + b{ + e("f") + new G()(){} + } +} +class G(h:String="i")() diff --git a/test/files/neg/t6675b.check b/test/files/neg/t6675b.check new file mode 100644 index 0000000000..77f6b3ccbc --- /dev/null +++ b/test/files/neg/t6675b.check @@ -0,0 +1,37 @@ +t6675b.scala:17: warning: object LeftOrRight expects 2 patterns to hold (Int, Int) but crushing into 2-tuple to fit single pattern (SI-6675) + def f1 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case LeftOrRight(a) => a } // warn + ^ +t6675b.scala:19: error: constructor cannot be instantiated to expected type; + found : (T1, T2, T3) + required: (Int, Int) + def f3 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case LeftOrRight((a, b, c)) => a } // fail + ^ +t6675b.scala:24: warning: object LeftOrRight expects 2 patterns to hold (A, A) but crushing into 2-tuple to fit single pattern (SI-6675) + def f2[A](x: A) = (Left(x -> x): Either[(A, A), (A, A)]) match { case LeftOrRight(a) => a } // warn + ^ +t6675b.scala:26: error: constructor cannot be instantiated to expected type; + found : (T1, T2, T3) + required: (?A11, ?A12) where type ?A12 <: A (this is a GADT skolem), type ?A11 <: A (this is a GADT skolem) + def f4[A](x: A) = (Left(x -> x): Either[(A, A), (A, A)]) match { case LeftOrRight((a, b, c)) => a } // fail + ^ +t6675b.scala:30: warning: object NativelyTwo expects 2 patterns to hold ((Int, Int), (Int, Int)) but crushing into 2-tuple to fit single pattern (SI-6675) + def f1 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case NativelyTwo(a) => a } // warn + ^ +t6675b.scala:32: error: constructor cannot be instantiated to expected type; + found : (T1, T2, T3) + required: ((Int, Int), (Int, Int)) + def f3 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case NativelyTwo((a, b, c)) => a } // fail + ^ +t6675b.scala:36: warning: object NativelyTwo expects 2 patterns to hold (A, A) but crushing into 2-tuple to fit single pattern (SI-6675) + def f1[A](x: A) = (Left(x): Either[A, A]) match { case NativelyTwo(a) => a } // warn + ^ +t6675b.scala:37: warning: object NativelyTwo expects 2 patterns to hold ((A, A), (A, A)) but crushing into 2-tuple to fit single pattern (SI-6675) + def f2[A](x: A) = (Left(x -> x): Either[(A, A), (A, A)]) match { case NativelyTwo(a) => a } // warn + ^ +t6675b.scala:39: error: constructor cannot be instantiated to expected type; + found : (T1, T2, T3) + required: ((?A17, ?A18), (?A19, ?A20)) where type ?A20 <: A (this is a GADT skolem), type ?A19 <: A (this is a GADT skolem), type ?A18 <: A (this is a GADT skolem), type ?A17 <: A (this is a GADT skolem) + def f4[A](x: A) = (Left(x -> x): Either[(A, A), (A, A)]) match { case NativelyTwo((a, b, c)) => a } // fail + ^ +5 warnings found +four errors found diff --git a/test/files/neg/t6675b.flags b/test/files/neg/t6675b.flags new file mode 100644 index 0000000000..1008b0a70c --- /dev/null +++ b/test/files/neg/t6675b.flags @@ -0,0 +1 @@ +-Xlint diff --git a/test/files/neg/t6675b.scala b/test/files/neg/t6675b.scala new file mode 100644 index 0000000000..c86c9c3955 --- /dev/null +++ b/test/files/neg/t6675b.scala @@ -0,0 +1,40 @@ +object LeftOrRight { + def unapply[A](value: Either[A, A]): Option[A] = value match { + case scala.Left(x) => Some(x) + case scala.Right(x) => Some(x) + } +} + +object NativelyTwo { + def unapply[A](value: Either[A, A]): Option[(A, A)] = value match { + case scala.Left(x) => Some(x -> x) + case scala.Right(x) => Some(x -> x) + } +} + + +class A { + def f1 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case LeftOrRight(a) => a } // warn + def f2 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case LeftOrRight((a, b)) => a } // no warn + def f3 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case LeftOrRight((a, b, c)) => a } // fail +} + +class B { + def f1[A](x: A) = (Left(x): Either[A, A]) match { case LeftOrRight(a) => a } // no warn + def f2[A](x: A) = (Left(x -> x): Either[(A, A), (A, A)]) match { case LeftOrRight(a) => a } // warn + def f3[A](x: A) = (Left(x -> x): Either[(A, A), (A, A)]) match { case LeftOrRight((a, b)) => a } // no warn + def f4[A](x: A) = (Left(x -> x): Either[(A, A), (A, A)]) match { case LeftOrRight((a, b, c)) => a } // fail +} + +class C { + def f1 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case NativelyTwo(a) => a } // warn + def f2 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case NativelyTwo((a, b)) => a } // no warn + def f3 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case NativelyTwo((a, b, c)) => a } // fail +} + +class D { + def f1[A](x: A) = (Left(x): Either[A, A]) match { case NativelyTwo(a) => a } // warn + def f2[A](x: A) = (Left(x -> x): Either[(A, A), (A, A)]) match { case NativelyTwo(a) => a } // warn + def f3[A](x: A) = (Left(x -> x): Either[(A, A), (A, A)]) match { case NativelyTwo((a, b)) => a } // no warn + def f4[A](x: A) = (Left(x -> x): Either[(A, A), (A, A)]) match { case NativelyTwo((a, b, c)) => a } // fail +} diff --git a/test/files/neg/t6680a.flags b/test/files/neg/t6680a.flags new file mode 100644 index 0000000000..19243266d1 --- /dev/null +++ b/test/files/neg/t6680a.flags @@ -0,0 +1 @@ +-Xstrict-inference
\ No newline at end of file diff --git a/test/files/neg/t6829.check b/test/files/neg/t6829.check index a0b43e3b52..914a1c9260 100644 --- a/test/files/neg/t6829.check +++ b/test/files/neg/t6829.check @@ -16,32 +16,32 @@ t6829.scala:49: error: not found: value nextState val (s,a,s2) = (state,actions(agent),nextState) ^ t6829.scala:50: error: type mismatch; - found : s.type (with underlying type T1) + found : s.type (with underlying type Any) required: _53.State where val _53: G val r = rewards(agent).r(s,a,s2) ^ t6829.scala:50: error: type mismatch; - found : a.type (with underlying type T2) + found : a.type (with underlying type Any) required: _53.Action where val _53: G val r = rewards(agent).r(s,a,s2) ^ t6829.scala:50: error: type mismatch; - found : s2.type (with underlying type T3) + found : s2.type (with underlying type Any) required: _53.State where val _53: G val r = rewards(agent).r(s,a,s2) ^ t6829.scala:51: error: type mismatch; - found : s.type (with underlying type T1) + found : s.type (with underlying type Any) required: _50.State agent.learn(s,a,s2,r): G#Agent ^ t6829.scala:51: error: type mismatch; - found : a.type (with underlying type T2) + found : a.type (with underlying type Any) required: _50.Action agent.learn(s,a,s2,r): G#Agent ^ t6829.scala:51: error: type mismatch; - found : s2.type (with underlying type T3) + found : s2.type (with underlying type Any) required: _50.State agent.learn(s,a,s2,r): G#Agent ^ diff --git a/test/files/neg/t6844.check b/test/files/neg/t6844.check new file mode 100644 index 0000000000..1fc2485520 --- /dev/null +++ b/test/files/neg/t6844.check @@ -0,0 +1,6 @@ +t6844.scala:4: error: type mismatch; + found : reflect.runtime.universe.TermName + required: reflect.runtime.universe.Tree + q"def foo($x)" + ^ +one error found diff --git a/test/files/neg/t6844.scala b/test/files/neg/t6844.scala new file mode 100644 index 0000000000..809d9d0f98 --- /dev/null +++ b/test/files/neg/t6844.scala @@ -0,0 +1,5 @@ +import scala.reflect.runtime.universe._ +object Test extends App { + val x = TermName("x") + q"def foo($x)" +} diff --git a/test/files/neg/t7157/Impls_Macros_1.scala b/test/files/neg/t7157/Impls_Macros_1.scala index 16cb001422..31d4d786d0 100644 --- a/test/files/neg/t7157/Impls_Macros_1.scala +++ b/test/files/neg/t7157/Impls_Macros_1.scala @@ -1,31 +1,31 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros object Macros { - def impl1_0_0(c: BlackboxContext)() = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } - def impl1_1_1(c: BlackboxContext)(x: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } - def impl1_2_2(c: BlackboxContext)(x: c.Expr[Int], y: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl1_0_0(c: Context)() = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl1_1_1(c: Context)(x: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl1_2_2(c: Context)(x: c.Expr[Int], y: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } def m1_0_0() = macro impl1_0_0 def m1_1_1(x: Int) = macro impl1_1_1 def m1_2_2(x: Int, y: Int) = macro impl1_2_2 - def impl1_0_inf(c: BlackboxContext)(x: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } - def impl1_1_inf(c: BlackboxContext)(x: c.Expr[Int], y: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } - def impl1_2_inf(c: BlackboxContext)(x: c.Expr[Int], y: c.Expr[Int], z: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl1_0_inf(c: Context)(x: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl1_1_inf(c: Context)(x: c.Expr[Int], y: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl1_2_inf(c: Context)(x: c.Expr[Int], y: c.Expr[Int], z: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } def m1_0_inf(x: Int*) = macro impl1_0_inf def m1_1_inf(x: Int, y: Int*) = macro impl1_1_inf def m1_2_inf(x: Int, y: Int, z: Int*) = macro impl1_2_inf - def impl2_0_0(c: BlackboxContext)()() = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } - def impl2_1_1(c: BlackboxContext)()(x: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } - def impl2_2_2(c: BlackboxContext)()(x: c.Expr[Int], y: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl2_0_0(c: Context)()() = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl2_1_1(c: Context)()(x: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl2_2_2(c: Context)()(x: c.Expr[Int], y: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } def m2_0_0()() = macro impl2_0_0 def m2_1_1()(x: Int) = macro impl2_1_1 def m2_2_2()(x: Int, y: Int) = macro impl2_2_2 - def impl2_0_inf(c: BlackboxContext)()(x: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } - def impl2_1_inf(c: BlackboxContext)()(x: c.Expr[Int], y: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } - def impl2_2_inf(c: BlackboxContext)()(x: c.Expr[Int], y: c.Expr[Int], z: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl2_0_inf(c: Context)()(x: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl2_1_inf(c: Context)()(x: c.Expr[Int], y: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def impl2_2_inf(c: Context)()(x: c.Expr[Int], y: c.Expr[Int], z: c.Expr[Int]*) = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } def m2_0_inf()(x: Int*) = macro impl2_0_inf def m2_1_inf()(x: Int, y: Int*) = macro impl2_1_inf def m2_2_inf()(x: Int, y: Int, z: Int*) = macro impl2_2_inf diff --git a/test/files/neg/t7214neg.check b/test/files/neg/t7214neg.check index 0660cccd02..291af04578 100644 --- a/test/files/neg/t7214neg.check +++ b/test/files/neg/t7214neg.check @@ -1,7 +1,4 @@ -t7214neg.scala:28: error: wrong number of patterns for object Extractor offering Any: expected 1, found 0 +t7214neg.scala:28: error: not enough patterns for object Extractor offering Any: expected 1, found 0 case Extractor() => ^ -t7214neg.scala:28: error: wrong number of patterns for object Extractor offering Any: expected 1, found 0 - case Extractor() => - ^ -two errors found +one error found diff --git a/test/files/neg/t7325.check b/test/files/neg/t7325.check index d2c40f4df8..61c33f99b1 100644 --- a/test/files/neg/t7325.check +++ b/test/files/neg/t7325.check @@ -1,13 +1,13 @@ -t7325.scala:2: error: conversions must follow a splice; use %% for literal %, %n for newline +t7325.scala:2: error: Missing conversion operator in '%'; use %% for literal %, %n for newline println(f"%") ^ -t7325.scala:4: error: conversions must follow a splice; use %% for literal %, %n for newline +t7325.scala:4: error: Missing conversion operator in '%'; use %% for literal %, %n for newline println(f"%%%") ^ -t7325.scala:6: error: conversions must follow a splice; use %% for literal %, %n for newline +t7325.scala:6: error: Missing conversion operator in '%'; use %% for literal %, %n for newline println(f"%%%%%") ^ -t7325.scala:16: error: wrong conversion string +t7325.scala:16: error: Missing conversion operator in '%'; use %% for literal %, %n for newline println(f"${0}%") ^ t7325.scala:19: error: conversions must follow a splice; use %% for literal %, %n for newline diff --git a/test/files/neg/t7475c.check b/test/files/neg/t7475c.check new file mode 100644 index 0000000000..472808131a --- /dev/null +++ b/test/files/neg/t7475c.check @@ -0,0 +1,7 @@ +t7475c.scala:6: error: value a is not a member of A.this.B + println(this.a) // wait, what? + ^ +t7475c.scala:7: error: value b is not a member of A.this.B + println(this.b) // wait, what? + ^ +two errors found diff --git a/test/files/neg/t7475c.scala b/test/files/neg/t7475c.scala new file mode 100644 index 0000000000..cd4a8762ca --- /dev/null +++ b/test/files/neg/t7475c.scala @@ -0,0 +1,9 @@ +class A { + private val a: Int = 0 + private[this] val b: Int = 0 + class B extends A { + def foo(a: A) = a.a // okay + println(this.a) // wait, what? + println(this.b) // wait, what? + } +} diff --git a/test/files/neg/t7475d.check b/test/files/neg/t7475d.check new file mode 100644 index 0000000000..6bd1da0d44 --- /dev/null +++ b/test/files/neg/t7475d.check @@ -0,0 +1,7 @@ +t7475d.scala:4: error: value priv is not a member of T.this.TT + (??? : TT).priv + ^ +t7475d.scala:10: error: value priv is not a member of U.this.UU + (??? : UU).priv + ^ +two errors found diff --git a/test/files/neg/t7475e.check b/test/files/neg/t7475e.check new file mode 100644 index 0000000000..48af2be51a --- /dev/null +++ b/test/files/neg/t7475e.check @@ -0,0 +1,4 @@ +t7475e.scala:8: error: value priv is not a member of Base.this.TT + (??? : TT).priv + ^ +one error found diff --git a/test/files/neg/t7475e.scala b/test/files/neg/t7475e.scala new file mode 100644 index 0000000000..e5c4877d6e --- /dev/null +++ b/test/files/neg/t7475e.scala @@ -0,0 +1,12 @@ +trait U { +} + +trait Base { + private val priv = 0 + + type TT = U with T // should exclude `priv` + (??? : TT).priv +} + +trait T extends Base { +} diff --git a/test/files/neg/t7475f.check b/test/files/neg/t7475f.check new file mode 100644 index 0000000000..a07a4480e2 --- /dev/null +++ b/test/files/neg/t7475f.check @@ -0,0 +1,10 @@ +t7475f.scala:12: error: method c1 in class C cannot be accessed in C[T] + c1 // a member, but inaccessible. + ^ +t7475f.scala:13: error: not found: value c2 + c2 // a member, but inaccessible. + ^ +t7475f.scala:26: error: value d2 is not a member of D[Any] + other.d2 // not a member + ^ +three errors found diff --git a/test/files/neg/t7475f.scala b/test/files/neg/t7475f.scala new file mode 100644 index 0000000000..6c5feadf19 --- /dev/null +++ b/test/files/neg/t7475f.scala @@ -0,0 +1,28 @@ +class C[T] extends D[T] { + private def c1 = 0 + private[this] def c2 = 0 +} + +trait D[T] { + self: C[T] => + + private def d1 = 0 + private[this] def d2 = 0 + + c1 // a member, but inaccessible. + c2 // a member, but inaccessible. + + d1 // okay + d2 // okay + + + class C { + d1 + d2 + } + + def x(other: D[Any]) { + other.d1 + other.d2 // not a member + } +} diff --git a/test/files/neg/t7507.check b/test/files/neg/t7507.check index d402869fd4..de30fc7057 100644 --- a/test/files/neg/t7507.check +++ b/test/files/neg/t7507.check @@ -1,4 +1,4 @@ -t7507.scala:6: error: value bippy in trait Cake cannot be accessed in Cake +t7507.scala:6: error: not found: value bippy locally(bippy) ^ one error found diff --git a/test/files/neg/t7850.check b/test/files/neg/t7850.check new file mode 100644 index 0000000000..317be2bbce --- /dev/null +++ b/test/files/neg/t7850.check @@ -0,0 +1,7 @@ +t7850.scala:11: error: an unapply result must have a member `def isEmpty: Boolean (found: def isEmpty: Casey) + val Casey(x1) = new Casey(1) + ^ +t7850.scala:12: error: an unapply result must have a member `def isEmpty: Boolean + val Dingy(x2) = new Dingy(1) + ^ +two errors found diff --git a/test/files/neg/t7850.scala b/test/files/neg/t7850.scala new file mode 100644 index 0000000000..04edad82b5 --- /dev/null +++ b/test/files/neg/t7850.scala @@ -0,0 +1,16 @@ +// isEmpty returns non-boolean +class Casey(a: Int) { def isEmpty = this; def get = this } +object Casey { def unapply(a: Casey) = a } + +// no isEmpty method at all +class Dingy(a: Int) { def get = this } +object Dingy { def unapply(a: Dingy) = a } + +object Test { + def main(args: Array[String]) { + val Casey(x1) = new Casey(1) + val Dingy(x2) = new Dingy(1) + println(s"$x1 $x2") + } +} + diff --git a/test/files/neg/t7886.check b/test/files/neg/t7886.check deleted file mode 100644 index 338eee9708..0000000000 --- a/test/files/neg/t7886.check +++ /dev/null @@ -1,6 +0,0 @@ -t7886.scala:10: error: type mismatch; - found : Contra[A] - required: Contra[Any] - case Unravel(m, msg) => g(m) - ^ -one error found diff --git a/test/files/neg/t7897.check b/test/files/neg/t7897.check new file mode 100644 index 0000000000..48eff511c7 --- /dev/null +++ b/test/files/neg/t7897.check @@ -0,0 +1,4 @@ +t7897.scala:19: error: value length is not a member of p0.Single + case p0.Single(x) => println(s"`$x` has ${x.length} chars") + ^ +one error found diff --git a/test/files/neg/t7897.scala b/test/files/neg/t7897.scala new file mode 100644 index 0000000000..87c966b1e0 --- /dev/null +++ b/test/files/neg/t7897.scala @@ -0,0 +1,23 @@ +package p0 { + class Single(val x: Any) extends AnyRef with Product1[String] { + private def s = "" + x + override def canEqual(x: Any) = this eq x.asInstanceOf[AnyRef] + def isEmpty = false + def get = this + def _1 = s + " only" + + override def toString = s"Single(${_1})" + } + + object Single { + def unapply(x: Any): Single = new Single(x) + } +} +object Test { + def main(args: Array[String]): Unit = { + "catdog" match { + case p0.Single(x) => println(s"`$x` has ${x.length} chars") + case x => println("fail: " + x) + } + } +} diff --git a/test/files/neg/t8015-ffa.check b/test/files/neg/t8015-ffa.check new file mode 100644 index 0000000000..0f28be7fe7 --- /dev/null +++ b/test/files/neg/t8015-ffa.check @@ -0,0 +1,6 @@ +t8015-ffa.scala:7: error: type mismatch; + found : String("3") + required: Int + val i: Int = "3" // error line 7 (was 8) + ^ +one error found diff --git a/test/files/neg/t8015-ffa.scala b/test/files/neg/t8015-ffa.scala new file mode 100644 index 0000000000..60876d9139 --- /dev/null +++ b/test/files/neg/t8015-ffa.scala @@ -0,0 +1,8 @@ + +package foo + +//-------object Next + +trait F { + val i: Int = "3" // error line 7 (was 8) +} diff --git a/test/files/neg/t8015-ffb.check b/test/files/neg/t8015-ffb.check new file mode 100644 index 0000000000..9b2171ea47 --- /dev/null +++ b/test/files/neg/t8015-ffb.check @@ -0,0 +1,6 @@ +t8015-ffb.scala:10: warning: side-effecting nullary methods are discouraged: suggest defining as `def w()` instead + def w = { x\u000c() } // ^L is colored blue on this screen, hardly visible + ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/t8015-ffb.flags b/test/files/neg/t8015-ffb.flags new file mode 100644 index 0000000000..7949c2afa2 --- /dev/null +++ b/test/files/neg/t8015-ffb.flags @@ -0,0 +1 @@ +-Xlint -Xfatal-warnings diff --git a/test/files/neg/t8015-ffb.scala b/test/files/neg/t8015-ffb.scala new file mode 100644 index 0000000000..dbdd942555 --- /dev/null +++ b/test/files/neg/t8015-ffb.scala @@ -0,0 +1,11 @@ + +trait G { + val c: Char = '\u000a' // disallowed! + def x\u000d\u000a = 9 // as nl + def y() = x + def z() = { + y()\u000a() // was Int does not take parameters + } + def v = y()\u000c() // was Int does not take parameters + def w = { x() } // ^L is colored blue on this screen, hardly visible +} diff --git a/test/files/neg/t8035-deprecated.check b/test/files/neg/t8035-deprecated.check new file mode 100644 index 0000000000..01f27e5310 --- /dev/null +++ b/test/files/neg/t8035-deprecated.check @@ -0,0 +1,21 @@ +t8035-deprecated.scala:2: warning: Adaptation of argument list by inserting () has been deprecated: this is unlikely to be what you want. + signature: GenSetLike.apply(elem: A): Boolean + given arguments: <none> + after adaptation: GenSetLike((): Unit) + List(1,2,3).toSet() + ^ +t8035-deprecated.scala:5: warning: Adaptation of argument list by inserting () has been deprecated: this is unlikely to be what you want. + signature: A(x: T): Foo.A[T] + given arguments: <none> + after adaptation: new A((): Unit) + new A + ^ +t8035-deprecated.scala:9: warning: Adaptation of argument list by inserting () has been deprecated: leaky (Object-receiving) target makes this especially dangerous. + signature: Format.format(x$1: Any): String + given arguments: <none> + after adaptation: Format.format((): Unit) + sdf.format() + ^ +error: No warnings can be incurred under -Xfatal-warnings. +three warnings found +one error found diff --git a/test/files/neg/t8035-deprecated.flags b/test/files/neg/t8035-deprecated.flags new file mode 100644 index 0000000000..c6bfaf1f64 --- /dev/null +++ b/test/files/neg/t8035-deprecated.flags @@ -0,0 +1 @@ +-deprecation -Xfatal-warnings diff --git a/test/files/neg/t8035-deprecated.scala b/test/files/neg/t8035-deprecated.scala new file mode 100644 index 0000000000..6423157530 --- /dev/null +++ b/test/files/neg/t8035-deprecated.scala @@ -0,0 +1,10 @@ +object Foo { + List(1,2,3).toSet() + + class A[T](val x: T) + new A + + import java.text.SimpleDateFormat + val sdf = new SimpleDateFormat("yyyyMMdd-HH0000") + sdf.format() +} diff --git a/test/files/neg/t8035-removed.check b/test/files/neg/t8035-removed.check new file mode 100644 index 0000000000..e24a0b4e63 --- /dev/null +++ b/test/files/neg/t8035-removed.check @@ -0,0 +1,16 @@ +t8035-removed.scala:2: error: Adaptation of argument list by inserting () has been removed. + signature: GenSetLike.apply(elem: A): Boolean + given arguments: <none> + List(1,2,3).toSet() + ^ +t8035-removed.scala:5: error: Adaptation of argument list by inserting () has been removed. + signature: A(x: T): Foo.A[T] + given arguments: <none> + new A + ^ +t8035-removed.scala:9: error: Adaptation of argument list by inserting () has been removed. + signature: Format.format(x$1: Any): String + given arguments: <none> + sdf.format() + ^ +three errors found diff --git a/test/files/neg/t8035-removed.flags b/test/files/neg/t8035-removed.flags new file mode 100644 index 0000000000..29f4ede37a --- /dev/null +++ b/test/files/neg/t8035-removed.flags @@ -0,0 +1 @@ +-Xfuture diff --git a/test/files/neg/t8035-removed.scala b/test/files/neg/t8035-removed.scala new file mode 100644 index 0000000000..6423157530 --- /dev/null +++ b/test/files/neg/t8035-removed.scala @@ -0,0 +1,10 @@ +object Foo { + List(1,2,3).toSet() + + class A[T](val x: T) + new A + + import java.text.SimpleDateFormat + val sdf = new SimpleDateFormat("yyyyMMdd-HH0000") + sdf.format() +} diff --git a/test/files/neg/t8104/Macros_1.scala b/test/files/neg/t8104/Macros_1.scala index 21d81a3687..2ad4bc5a99 100644 --- a/test/files/neg/t8104/Macros_1.scala +++ b/test/files/neg/t8104/Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context object Macros { - def impl[T](c: WhiteboxContext)(implicit T: c.WeakTypeTag[T]) = { + def impl[T](c: Context)(implicit T: c.WeakTypeTag[T]) = { import c.universe._ import definitions._ val fields = T.tpe.declarations.toList.collect{ case x: TermSymbol if x.isVal && x.isCaseAccessor => x } diff --git a/test/files/neg/t8143a.check b/test/files/neg/t8143a.check new file mode 100644 index 0000000000..4e11000a2a --- /dev/null +++ b/test/files/neg/t8143a.check @@ -0,0 +1,5 @@ +t8143a.scala:2: error: overriding method f in class Foo of type => Int; + method f has weaker access privileges; it should not be private +class Bar extends Foo { private def f = 10 } + ^ +one error found diff --git a/test/files/neg/t8143a.scala b/test/files/neg/t8143a.scala new file mode 100644 index 0000000000..4ec539e671 --- /dev/null +++ b/test/files/neg/t8143a.scala @@ -0,0 +1,15 @@ +class Foo { def f = 5 } +class Bar extends Foo { private def f = 10 } + + +class Foo1 { private def f = 5 } +class Bar1 extends Foo1 { def f = 10 } // okay + +class Foo2 { private def f = 5 } +class Bar2 extends Foo2 { private def f = 10 } // okay + +class Foo3 { private[this] def f = 5 } +class Bar3 extends Foo3 { private def f = 10 } // okay + +class Foo4 { private def f = 5 } +class Bar4 extends Foo4 { private[this] def f = 10 } // okay
\ No newline at end of file diff --git a/test/files/neg/t8146-non-finitary-2.check b/test/files/neg/t8146-non-finitary-2.check new file mode 100644 index 0000000000..8c2e1436c2 --- /dev/null +++ b/test/files/neg/t8146-non-finitary-2.check @@ -0,0 +1,9 @@ +t8146-non-finitary-2.scala:5: error: class graph is not finitary because type parameter X is expansively recursive +trait C[X] extends N[N[C[D[X]]]] + ^ +t8146-non-finitary-2.scala:7: error: type mismatch; + found : C[Int] + required: N[C[Int]] + def foo(c: C[Int]): N[C[Int]] = c + ^ +two errors found diff --git a/test/files/neg/t8146-non-finitary-2.scala b/test/files/neg/t8146-non-finitary-2.scala new file mode 100644 index 0000000000..c12f5f8f49 --- /dev/null +++ b/test/files/neg/t8146-non-finitary-2.scala @@ -0,0 +1,8 @@ +// Example 3 from "On Decidability of Nominal Subtyping with Variance" (Pierce, Kennedy) +// http://research.microsoft.com/pubs/64041/fool2007.pdf +trait N[-Z] +trait D[Y] +trait C[X] extends N[N[C[D[X]]]] +object Test { + def foo(c: C[Int]): N[C[Int]] = c +} diff --git a/test/files/neg/t8146-non-finitary.check b/test/files/neg/t8146-non-finitary.check new file mode 100644 index 0000000000..8363b750ca --- /dev/null +++ b/test/files/neg/t8146-non-finitary.check @@ -0,0 +1,9 @@ +t8146-non-finitary.scala:4: error: class graph is not finitary because type parameter A is expansively recursive +trait C[A] extends N[N[C[C[A]]]] + ^ +t8146-non-finitary.scala:6: error: type mismatch; + found : C[Int] + required: N[C[Int]] + def foo(c: C[Int]): N[C[Int]] = c + ^ +two errors found diff --git a/test/files/neg/t8146-non-finitary.scala b/test/files/neg/t8146-non-finitary.scala new file mode 100644 index 0000000000..3d8a3074c7 --- /dev/null +++ b/test/files/neg/t8146-non-finitary.scala @@ -0,0 +1,7 @@ +// Example 3 from "On Decidability of Nominal Subtyping with Variance" (Pierce, Kennedy) +// http://research.microsoft.com/pubs/64041/fool2007.pdf +trait N[-A] +trait C[A] extends N[N[C[C[A]]]] +object Test { + def foo(c: C[Int]): N[C[Int]] = c +} diff --git a/test/files/neg/t8157.check b/test/files/neg/t8157.check new file mode 100644 index 0000000000..9a21a49a07 --- /dev/null +++ b/test/files/neg/t8157.check @@ -0,0 +1,4 @@ +t8157.scala:1: error: in object Test, multiple overloaded alternatives of method foo define default arguments. +object Test { + ^ +one error found diff --git a/test/files/neg/t8157.scala b/test/files/neg/t8157.scala new file mode 100644 index 0000000000..462d4fa3f1 --- /dev/null +++ b/test/files/neg/t8157.scala @@ -0,0 +1,4 @@ +object Test { + def foo(printer: Any, question: => String, show: Boolean = false)(op: => Any): Any = ??? + def foo[T](question: => String, show: Boolean)(op: => Any = ()): Any = ??? +} diff --git a/test/files/neg/t8158.check b/test/files/neg/t8158.check new file mode 100644 index 0000000000..fa6b744ba5 --- /dev/null +++ b/test/files/neg/t8158.check @@ -0,0 +1,4 @@ +Test_2.scala:10: error: not enough patterns for <$anon: AnyRef> offering AnyRef{def isEmpty: Boolean; def get: $anon; def unapply(x: String): $anon}: expected 1, found 0 + case X() => + ^ +one error found diff --git a/test/files/neg/t8158/Macros_1.scala b/test/files/neg/t8158/Macros_1.scala new file mode 100644 index 0000000000..b84e3ed8d3 --- /dev/null +++ b/test/files/neg/t8158/Macros_1.scala @@ -0,0 +1,34 @@ +import scala.language.experimental.macros +import scala.reflect.macros.whitebox.Context + +object Max { + def impl(c: Context)(any: c.Expr[Any]): c.Expr[Any] = { + import c.universe._ + def fail(msg: String) = c.abort(c.enclosingPosition, msg) + val t = c.macroApplication match { + case q"$_.unapply($unargs)" => + /* hangs + */ + q""" + new { + def isEmpty = false + def get = this + def unapply(x: String) = this + }.unapply($unargs) + """ + /* + if get returns Unit or Boolean: + wrong number of patterns for <$anon: AnyRef> offering Unit: expected 1, found 0 + */ + /* straightforward + q""" + new { + def unapply(x: String) = true + }.unapply($unargs) + """ + */ + case _ => fail("bad appl") + } + c.Expr[Any](t) + } +}
\ No newline at end of file diff --git a/test/files/neg/t8158/Test_2.scala b/test/files/neg/t8158/Test_2.scala new file mode 100644 index 0000000000..f5ac6616bb --- /dev/null +++ b/test/files/neg/t8158/Test_2.scala @@ -0,0 +1,14 @@ +import scala.language.experimental.macros + +object X { + def unapply(any: Any): Any = macro Max.impl +} + +class BugTest { + def bug(): Unit = { + "any" match { + case X() => + case _ => ??? + } + } +}
\ No newline at end of file diff --git a/test/files/neg/t8182.check b/test/files/neg/t8182.check new file mode 100644 index 0000000000..a156d70883 --- /dev/null +++ b/test/files/neg/t8182.check @@ -0,0 +1,22 @@ +t8182.scala:4: error: illegal start of simple pattern +} +^ +t8182.scala:7: error: illegal start of simple pattern +} +^ +t8182.scala:6: error: type application is not allowed in pattern + val a b[B] // error then continue as for X + ^ +t8182.scala:10: error: illegal start of simple pattern + case a b[B] => // bumpy recovery + ^ +t8182.scala:10: error: type application is not allowed in pattern + case a b[B] => // bumpy recovery + ^ +t8182.scala:11: error: '=>' expected but '}' found. + } + ^ +t8182.scala:16: error: type application is not allowed in pattern + case a B[T] b => + ^ +7 errors found diff --git a/test/files/neg/t8182.scala b/test/files/neg/t8182.scala new file mode 100644 index 0000000000..1b3bc9821f --- /dev/null +++ b/test/files/neg/t8182.scala @@ -0,0 +1,18 @@ + +trait X { + val a b // something missing +} +trait Y { + val a b[B] // error then continue as for X +} +trait Z { + (null: Any) match { + case a b[B] => // bumpy recovery + } +} +object B { def unapply[W](a: Any) = Some((1,2)) } +trait Z { + (null: Any) match { + case a B[T] b => + } +} diff --git a/test/files/neg/t8207.check b/test/files/neg/t8207.check new file mode 100644 index 0000000000..59facd897a --- /dev/null +++ b/test/files/neg/t8207.check @@ -0,0 +1,7 @@ +t8207.scala:1: error: '.' expected but '}' found. +class C { import C.this.toString } + ^ +t8207.scala:3: error: '.' expected but '}' found. +class D { import D.this.toString } + ^ +two errors found diff --git a/test/files/neg/t8207.scala b/test/files/neg/t8207.scala new file mode 100644 index 0000000000..738ce381f4 --- /dev/null +++ b/test/files/neg/t8207.scala @@ -0,0 +1,3 @@ +class C { import C.this.toString } + +class D { import D.this.toString } diff --git a/test/files/neg/t8219-any-any-ref-equals.check b/test/files/neg/t8219-any-any-ref-equals.check new file mode 100644 index 0000000000..95d2536fba --- /dev/null +++ b/test/files/neg/t8219-any-any-ref-equals.check @@ -0,0 +1,10 @@ +t8219-any-any-ref-equals.scala:5: error: method ==: (x$1: Any)Boolean does not take type parameters. + "".==[Int] + ^ +t8219-any-any-ref-equals.scala:6: error: method ==: (x$1: Any)Boolean does not take type parameters. + ("": AnyRef).==[Int] + ^ +t8219-any-any-ref-equals.scala:7: error: method ==: (x$1: Any)Boolean does not take type parameters. + ("": Object).==[Int] + ^ +three errors found diff --git a/test/files/neg/t8219-any-any-ref-equals.scala b/test/files/neg/t8219-any-any-ref-equals.scala new file mode 100644 index 0000000000..f1b81fa734 --- /dev/null +++ b/test/files/neg/t8219-any-any-ref-equals.scala @@ -0,0 +1,8 @@ +object Test { + // The error message tells us that AnyRef#== and Any#== are overloaded. + // A real class couldn't define such an overload, why do we allow AnyRef + // to do so? + "".==[Int] + ("": AnyRef).==[Int] + ("": Object).==[Int] +} diff --git a/test/files/neg/t8228.check b/test/files/neg/t8228.check new file mode 100644 index 0000000000..02eff4b1b7 --- /dev/null +++ b/test/files/neg/t8228.check @@ -0,0 +1,4 @@ +t8228.scala:4: error: recursive value foo needs type + val foo = foo(null) + ^ +one error found diff --git a/test/files/neg/t8228.scala b/test/files/neg/t8228.scala new file mode 100644 index 0000000000..19d71aeab4 --- /dev/null +++ b/test/files/neg/t8228.scala @@ -0,0 +1,7 @@ +object X { + def bar = { + def foo(x: Any) = "" + val foo = foo(null) + foo(null) // cycle in isApplicableBasedOnArity + } +} diff --git a/test/files/neg/t8237-default.check b/test/files/neg/t8237-default.check new file mode 100644 index 0000000000..59fe21ed03 --- /dev/null +++ b/test/files/neg/t8237-default.check @@ -0,0 +1,13 @@ +t8237-default.scala:5: error: no type parameters for method test4: (x: T[T[List[T[X forSome { type X }]]]])Nothing exist so that it can be applied to arguments (List[Int]) + --- because --- +argument expression's type is not compatible with formal parameter type; + found : List[Int] + required: ?T[?T[List[?T[X forSome { type X }]]]] + test4(test4$default$1) + ^ +t8237-default.scala:5: error: type mismatch; + found : List[Int] + required: T[T[List[T[X forSome { type X }]]]] + test4(test4$default$1) + ^ +two errors found diff --git a/test/files/neg/t8237-default.scala b/test/files/neg/t8237-default.scala new file mode 100644 index 0000000000..f695aa523f --- /dev/null +++ b/test/files/neg/t8237-default.scala @@ -0,0 +1,29 @@ +// This test case was extracte from `names-defaults-neg.scala` +// It pinpoints an improvement an error message that results from +// a type inference failure +object Test extends App { + test4(test4$default$1) + + def test4[T[P]](x: T[T[List[T[X forSome { type X }]]]]) = ??? + def test4$default$1[T[P]]: List[Int] = ??? +} + +/* +OLD: + no type parameters for method test4: (x: T[T[List[T[X forSome { type X }]]]])Nothing exist so that it can be applied to arguments (List[Int]) + --- because --- +argument expression's type is not compatible with formal parameter type; + found : List[Int] + required: ?T + test4(test4$default$1) + ^ + +NEW: + +no type parameters for method test4: (x: T[T[List[T[X forSome { type X }]]]])Nothing exist so that it can be applied to arguments (List[Int]) + --- because --- +argument expression's type is not compatible with formal parameter type; + found : List[Int] + required: ?T[?T[List[?T[X forSome { type X }]]] + test4(test4$default$1) +*/ diff --git a/test/files/neg/t8244.check b/test/files/neg/t8244.check new file mode 100644 index 0000000000..90b2bf6f46 --- /dev/null +++ b/test/files/neg/t8244.check @@ -0,0 +1,4 @@ +Test_2.scala:9: error: value exxx is not a member of ?0 + raw.t.exxx // java.lang.ClassCastException: java.lang.String cannot be cast to X + ^ +one error found diff --git a/test/files/neg/t8244/Raw_1.java b/test/files/neg/t8244/Raw_1.java new file mode 100644 index 0000000000..0c667f1106 --- /dev/null +++ b/test/files/neg/t8244/Raw_1.java @@ -0,0 +1,4 @@ +public abstract class Raw_1<T>{ + public Raw_1 raw() { return new Raw_1<String>() { public String t() { return ""; } }; } + public abstract T t(); +} diff --git a/test/files/neg/t8244/Test_2.scala b/test/files/neg/t8244/Test_2.scala new file mode 100644 index 0000000000..152bb0b870 --- /dev/null +++ b/test/files/neg/t8244/Test_2.scala @@ -0,0 +1,12 @@ +class X extends Raw_1[X] { + override def t = this + def exxx = 0 +} + +object Test extends App { + def c(s: X) = { + val raw = s.raw + raw.t.exxx // java.lang.ClassCastException: java.lang.String cannot be cast to X + } + c(new X()) +} diff --git a/test/files/neg/t8244b.check b/test/files/neg/t8244b.check new file mode 100644 index 0000000000..f6cbf99eb5 --- /dev/null +++ b/test/files/neg/t8244b.check @@ -0,0 +1,4 @@ +t8244b.scala:15: error: value exxx is not a member of _$1 + raw.t.exxx + ^ +one error found diff --git a/test/files/neg/t8244b.scala b/test/files/neg/t8244b.scala new file mode 100644 index 0000000000..2fb4f451a1 --- /dev/null +++ b/test/files/neg/t8244b.scala @@ -0,0 +1,18 @@ +class Raw_1[T]{ + def raw(): Raw_1[_] = { new Raw_1[String] { def t() = "" } } + def t(): T +} + + +class X extends Raw_1[X] { + override def t = this + def exxx = 0 +} + +object Test extends App { + def c(s: X) = { + val raw = s.raw + raw.t.exxx + } + c(new X()) +} diff --git a/test/files/neg/t8244c.check b/test/files/neg/t8244c.check new file mode 100644 index 0000000000..fd58a5847c --- /dev/null +++ b/test/files/neg/t8244c.check @@ -0,0 +1,4 @@ +t8244c.scala:15: error: value exxx is not a member of _$1 + raw.t.exxx + ^ +one error found diff --git a/test/files/neg/t8244c.scala b/test/files/neg/t8244c.scala new file mode 100644 index 0000000000..2fb4f451a1 --- /dev/null +++ b/test/files/neg/t8244c.scala @@ -0,0 +1,18 @@ +class Raw_1[T]{ + def raw(): Raw_1[_] = { new Raw_1[String] { def t() = "" } } + def t(): T +} + + +class X extends Raw_1[X] { + override def t = this + def exxx = 0 +} + +object Test extends App { + def c(s: X) = { + val raw = s.raw + raw.t.exxx + } + c(new X()) +} diff --git a/test/files/neg/t8244e.check b/test/files/neg/t8244e.check new file mode 100644 index 0000000000..ebd74036e5 --- /dev/null +++ b/test/files/neg/t8244e.check @@ -0,0 +1,4 @@ +Test.scala:9: error: value exxx is not a member of ?0 + raw.t.exxx // java.lang.ClassCastException: java.lang.String cannot be cast to X + ^ +one error found diff --git a/test/files/neg/t8244e/Raw.java b/test/files/neg/t8244e/Raw.java new file mode 100644 index 0000000000..53202e319d --- /dev/null +++ b/test/files/neg/t8244e/Raw.java @@ -0,0 +1,4 @@ +public abstract class Raw<T>{ + public Raw raw() { return new Raw<String>() { public String t() { return ""; } }; } + public abstract T t(); +} diff --git a/test/files/neg/t8244e/Test.scala b/test/files/neg/t8244e/Test.scala new file mode 100644 index 0000000000..ca2a90583f --- /dev/null +++ b/test/files/neg/t8244e/Test.scala @@ -0,0 +1,12 @@ +class X extends Raw[X] { + override def t = this + def exxx = 0 +} + +object Test extends App { + def c(s: X) = { + val raw = s.raw + raw.t.exxx // java.lang.ClassCastException: java.lang.String cannot be cast to X + } + c(new X()) +} diff --git a/test/files/neg/t997.check b/test/files/neg/t997.check index 8c41060ba2..b118792229 100644 --- a/test/files/neg/t997.check +++ b/test/files/neg/t997.check @@ -1,7 +1,4 @@ -t997.scala:13: error: wrong number of patterns for object Foo offering (String, String): expected 2, found 3 +t997.scala:13: error: too many patterns for object Foo offering (String, String): expected 2, found 3 "x" match { case Foo(a, b, c) => Console.println((a,b,c)) } ^ -t997.scala:13: error: wrong number of patterns for object Foo offering (String, String): expected 2, found 3 -"x" match { case Foo(a, b, c) => Console.println((a,b,c)) } - ^ -two errors found +one error found diff --git a/test/files/pos/annotated-original/M_1.scala b/test/files/pos/annotated-original/M_1.scala index 089a3a13c5..84a01bcce5 100644 --- a/test/files/pos/annotated-original/M_1.scala +++ b/test/files/pos/annotated-original/M_1.scala @@ -1,7 +1,7 @@ import language.experimental.macros -import reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object M { - def impl(c: BlackboxContext)(a: c.Expr[Any]) = c.Expr[Any](c.resetLocalAttrs(a.tree)) + def impl(c: Context)(a: c.Expr[Any]) = c.Expr[Any](c.untypecheck(a.tree)) def m(a: Any) = macro impl } diff --git a/test/files/pos/annotated-treecopy/Impls_Macros_1.scala b/test/files/pos/annotated-treecopy/Impls_Macros_1.scala index 50c671707d..fdf9c72c31 100644 --- a/test/files/pos/annotated-treecopy/Impls_Macros_1.scala +++ b/test/files/pos/annotated-treecopy/Impls_Macros_1.scala @@ -1,5 +1,5 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import collection.mutable.ListBuffer import collection.mutable.Stack @@ -12,7 +12,7 @@ object Macros { def tree[T,U](f:Function1[T,U]): Function1[T,U] = macro tree_impl[T,U] - def tree_impl[T:c.WeakTypeTag,U:c.WeakTypeTag](c: BlackboxContext) + def tree_impl[T:c.WeakTypeTag,U:c.WeakTypeTag](c: Context) (f:c.Expr[Function1[T,U]]): c.Expr[Function1[T,U]] = { import c.universe._ val ttag = c.weakTypeTag[U] @@ -44,7 +44,7 @@ object Macros { val typeOut = c.Expr[String](q"${ttag.tpe.toString}").splice def apply(_arg: T): U = c.Expr[U](b1)(ttag.asInstanceOf[c.WeakTypeTag[U]]).splice }) - val untyped = c.resetLocalAttrs(template.tree) + val untyped = c.untypecheck(template.tree) c.Expr[T => U](untyped) case _ => sys.error("Bad function type") diff --git a/test/files/pos/attachments-typed-another-ident/Impls_1.scala b/test/files/pos/attachments-typed-another-ident/Impls_1.scala index 6271359921..8016143a4c 100644 --- a/test/files/pos/attachments-typed-another-ident/Impls_1.scala +++ b/test/files/pos/attachments-typed-another-ident/Impls_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros object MyAttachment object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ val ident = Ident(TermName("bar")) updateAttachment MyAttachment assert(ident.attachments.get[MyAttachment.type].isDefined, ident.attachments) diff --git a/test/files/pos/attachments-typed-ident/Impls_1.scala b/test/files/pos/attachments-typed-ident/Impls_1.scala index f24ea88a5d..af2cc59ecd 100644 --- a/test/files/pos/attachments-typed-ident/Impls_1.scala +++ b/test/files/pos/attachments-typed-ident/Impls_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros object MyAttachment object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ val ident = Ident(TermName("bar")) updateAttachment MyAttachment assert(ident.attachments.get[MyAttachment.type].isDefined, ident.attachments) diff --git a/test/files/pos/bcode_throw_null/TN.scala b/test/files/pos/bcode_throw_null/TN.scala new file mode 100644 index 0000000000..ed38b59bae --- /dev/null +++ b/test/files/pos/bcode_throw_null/TN.scala @@ -0,0 +1,7 @@ +object TN { + + def pre1(b: Boolean) { + println(if (b) 1 else throw null) + } + +} diff --git a/test/files/pos/debug-reset-local-attrs.flags b/test/files/pos/debug-reset-local-attrs.flags new file mode 100644 index 0000000000..9c7d6400fc --- /dev/null +++ b/test/files/pos/debug-reset-local-attrs.flags @@ -0,0 +1 @@ +-Ydebug diff --git a/test/files/pos/debug-reset-local-attrs.scala b/test/files/pos/debug-reset-local-attrs.scala new file mode 100644 index 0000000000..8348657965 --- /dev/null +++ b/test/files/pos/debug-reset-local-attrs.scala @@ -0,0 +1 @@ +case class FT(f : Float) diff --git a/test/files/neg/delambdafy_t6260_method.check b/test/files/pos/delambdafy_t6260_method.check index f5cd6947d1..f5cd6947d1 100644 --- a/test/files/neg/delambdafy_t6260_method.check +++ b/test/files/pos/delambdafy_t6260_method.check diff --git a/test/files/neg/delambdafy_t6260_method.flags b/test/files/pos/delambdafy_t6260_method.flags index 48b438ddf8..48b438ddf8 100644 --- a/test/files/neg/delambdafy_t6260_method.flags +++ b/test/files/pos/delambdafy_t6260_method.flags diff --git a/test/files/neg/delambdafy_t6260_method.scala b/test/files/pos/delambdafy_t6260_method.scala index 93b5448227..93b5448227 100644 --- a/test/files/neg/delambdafy_t6260_method.scala +++ b/test/files/pos/delambdafy_t6260_method.scala diff --git a/test/files/pos/dotless-targs.scala b/test/files/pos/dotless-targs.scala new file mode 100644 index 0000000000..8c0e244e4e --- /dev/null +++ b/test/files/pos/dotless-targs.scala @@ -0,0 +1,9 @@ +class A { + def fn1 = List apply 1 + def fn2 = List apply[Int] 2 + + def g1: Char = "g1" toList 0 + def g2: Char = "g2" apply 1 + + def h1 = List apply[List[Int]] (List(1), List(2)) mapConserve[List[Any]] (x => x) +} diff --git a/test/files/pos/implicit-anyval-2.10.flags b/test/files/pos/implicit-anyval-2.10.flags new file mode 100644 index 0000000000..94c8056747 --- /dev/null +++ b/test/files/pos/implicit-anyval-2.10.flags @@ -0,0 +1 @@ +-Xsource:2.10 diff --git a/test/files/pos/implicit-anyval-2.10.scala b/test/files/pos/implicit-anyval-2.10.scala new file mode 100644 index 0000000000..3082af73b8 --- /dev/null +++ b/test/files/pos/implicit-anyval-2.10.scala @@ -0,0 +1,3 @@ +object Test { + "": AnyVal // newly prohibited in 2.11, allowed under -Xsourse:2.10 +}
\ No newline at end of file diff --git a/test/files/pos/macro-implicit-invalidate-on-error.scala b/test/files/pos/macro-implicit-invalidate-on-error.scala index f9756d965f..bb83e3cc38 100644 --- a/test/files/pos/macro-implicit-invalidate-on-error.scala +++ b/test/files/pos/macro-implicit-invalidate-on-error.scala @@ -1,5 +1,5 @@ import scala.language.experimental.macros -import scala.reflect.macros.Context +import scala.reflect.macros.blackbox.Context trait LegacyLiftable[T] { def apply(universe: scala.reflect.api.Universe, value: T): universe.Tree diff --git a/test/files/pos/overzealous-assert-genbcode.scala b/test/files/pos/overzealous-assert-genbcode.scala new file mode 100644 index 0000000000..ddd70b0c44 --- /dev/null +++ b/test/files/pos/overzealous-assert-genbcode.scala @@ -0,0 +1,10 @@ +object Test { + + def main(args: Array[String]) { + args(0) match { + case a: String => while(a == null) {} + } + } + +} + diff --git a/test/files/pos/t0764.scala b/test/files/pos/t0764.scala new file mode 100644 index 0000000000..f1084f5ff8 --- /dev/null +++ b/test/files/pos/t0764.scala @@ -0,0 +1,27 @@ +class Top[A] { + type AType = A +} + +trait Node { outer => + type T <: Node + def prepend = new Node { type T = outer.type } +} + +class Main[NextType <: Node](value: Node { type T = NextType }) + extends Top[Node { type T = NextType }] { + + new Main[AType]( (value: AType).prepend ) +} + +/* this used to be a neg test, even though it should've compiled +SI-8177 fixed this. + +Behold the equivalent program which type checks without the fix for SI-8177. +(Expand type alias, convert type member to type param; +note the covariance to encode subtyping on type members.) + +class Node[+T <: Node[_]] { def prepend = new Node[this.type] } +class Main[NextType <: Node[_]](value: Node[NextType]) { + new Main(value.prepend) +} +*/
\ No newline at end of file diff --git a/test/files/pos/t0764b.scala b/test/files/pos/t0764b.scala new file mode 100644 index 0000000000..6ae3c105c9 --- /dev/null +++ b/test/files/pos/t0764b.scala @@ -0,0 +1,61 @@ +// In all cases when calling "prepend" the receiver 'v' +// has static type NodeAlias[A] or (equivalently) Node { type T = A }. +// Since prepend explicitly returns the singleton type of the receiver, +// the return type of prepend in all cases is "v.type", and so the call +// to "new Main" can be parameterized with any of the following, in order +// of decreasing specificity with a tie for second place: +// +// new Main[v.type](v.prepend) +// new Main[NodeAlias[A]](v.prepend) +// new Main[Node { type T = A }](v.prepend) +// new Main(v.prepend) + +// the `fail` comments below denote what didn't compile before SI-8177 fixed all of them + +package p1 { + object t0764 { + type NodeAlias[A] = Node { type T = A } + trait Node { outer => + type T <: Node + def prepend: Node { type T = outer.type } = ??? + } + + class Main1[A <: Node](v: NodeAlias[A]) { + private[this] def f1 = new Main1(v.prepend) // fail + private[this] def f2 = new Main1[NodeAlias[A]](v.prepend) // fail + private[this] def f3 = new Main1[Node { type T = A }](v.prepend) // fail + private[this] def f4 = new Main1[v.type](v.prepend) // ok + } + + class Main2[A <: Node](v: Node { type T = A }) { + private[this] def f1 = new Main2(v.prepend) // fail + private[this] def f2 = new Main2[NodeAlias[A]](v.prepend) // fail + private[this] def f3 = new Main2[Node { type T = A }](v.prepend) // fail + private[this] def f4 = new Main2[v.type](v.prepend) // ok + } + } +} + +package p2 { + object t0764 { + type NodeAlias[A] = Node { type T = A } + trait Node { outer => + type T <: Node + def prepend: NodeAlias[outer.type] = ??? + } + + class Main1[A <: Node](v: NodeAlias[A]) { + private[this] def f1 = new Main1(v.prepend) // ok! <<========== WOT + private[this] def f2 = new Main1[NodeAlias[A]](v.prepend) // fail + private[this] def f3 = new Main1[Node { type T = A }](v.prepend) // fail + private[this] def f4 = new Main1[v.type](v.prepend) // ok + } + + class Main2[A <: Node](v: Node { type T = A }) { + private[this] def f1 = new Main2(v.prepend) // fail + private[this] def f2 = new Main2[NodeAlias[A]](v.prepend) // fail + private[this] def f3 = new Main2[Node { type T = A }](v.prepend) // fail + private[this] def f4 = new Main2[v.type](v.prepend) // ok + } + } +} diff --git a/test/files/pos/t1786-counter.scala b/test/files/pos/t1786-counter.scala new file mode 100644 index 0000000000..c1ad2c204f --- /dev/null +++ b/test/files/pos/t1786-counter.scala @@ -0,0 +1,38 @@ +trait ShapeLevel + +object Fail { + abstract class ProductNodeShape[Level <: ShapeLevel, C, M <: C, U <: C, P <: C] extends Shape[Level, M, U, P] { + def copy(shapes: Seq[Shape[_, _, _, _]]): Shape[Level, _, _, _] + } + + abstract class Shape[Level <: ShapeLevel, -Mixed_, Unpacked_, Packed_] + + final class TupleShape[Level <: ShapeLevel, M <: Product, U <: Product, P <: Product](val shapes: Shape[_, _, _, _]*) extends ProductNodeShape[Level, Product, M, U, P] { + def copy(shapes: Seq[Shape[_, _, _, _]]): Shape[Level, _, _, _] = ??? + } + + trait ShapeLevel +} + +object Ok { + abstract class Shape[Level <: ShapeLevel, -Mixed_, Unpacked_, Packed_] + + abstract class ProductNodeShape[Level <: ShapeLevel, C, M <: C, U <: C, P <: C] extends Shape[Level, M, U, P] { + def copy(shapes: Seq[Shape[_, _, _, _]]): Shape[Level, _, _, _] + } + + final class TupleShape[Level <: ShapeLevel, M <: Product, U <: Product, P <: Product](val shapes: Shape[_, _, _, _]*) extends ProductNodeShape[Level, Product, M, U, P] { + def copy(shapes: Seq[Shape[_, _, _, _]]): Shape[Level, _, _, _] = ??? + } +} + +// This is why we reverted the fix for SI-1786 -- see SI-6169 for a potential alternative that could be extended to cover this. +// both objects type check on 2.10.3, but only Ok was accepted by 2.11 after the original fix to SI-1786. +// Fail results in: +/* +t1786-counter.scala:10: error: class TupleShape needs to be abstract, since method copy in class ProductNodeShape of type (shapes: Seq[Fail.Shape[_, _, _, _]])Fail.Shape[Level, _, _, _] is not defined +(Note that Seq[Fail.Shape[_, _, _, _]] does not match Seq[Fail.Shape[_ <: Fail.ShapeLevel, _, _, _]]: their type parameters differ) + final class TupleShape[Level <: ShapeLevel, M <: Product, U <: Product, P <: Product](val shapes: Shape[_, _, _, _]*) extends ProductNodeShape[Level, Product, M, U, P] { + ^ +one error found +*/
\ No newline at end of file diff --git a/test/files/pos/t2066-2.10-compat.flags b/test/files/pos/t2066-2.10-compat.flags new file mode 100644 index 0000000000..94c8056747 --- /dev/null +++ b/test/files/pos/t2066-2.10-compat.flags @@ -0,0 +1 @@ +-Xsource:2.10 diff --git a/test/files/pos/t2066-2.10-compat.scala b/test/files/pos/t2066-2.10-compat.scala new file mode 100644 index 0000000000..fb8103e4ad --- /dev/null +++ b/test/files/pos/t2066-2.10-compat.scala @@ -0,0 +1,71 @@ +import language._ +trait A1 { + def f[T[_]] = () +} + +trait B1 extends A1 { + override def f[T[+_]] = () +} + +trait C1 extends A1 { + override def f[T[-_]] = () +} + + +trait A2 { + def f[T[+_]] = () +} + +trait B2 extends A2 { + override def f[T[_]] = () // okay +} + +trait C2 extends A2 { + override def f[T[-_]] = () +} + + +trait A3 { + def f[T[-_]] = () +} + +trait B3 extends A3 { + override def f[T[_]] = () // okay +} + +trait C3 extends A3 { + override def f[T[-_]] = () +} + + +trait A4 { + def f[T[X[+_]]] = () +} + +trait B4 extends A4 { + override def f[T[X[_]]] = () +} + +trait A5 { + def f[T[X[-_]]] = () +} + +trait B5 extends A5 { + override def f[T[X[_]]] = () +} + + + +trait A6 { + def f[T[X[_]]] = () +} + +trait B6 extends A6 { + override def f[T[X[+_]]] = () // okay +} +trait C6 extends A6 { + override def f[T[X[_]]] = () // okay +} +trait D6 extends A6 { + override def f[T[X[-_]]] = () +} diff --git a/test/files/pos/t2066.scala b/test/files/pos/t2066.scala new file mode 100644 index 0000000000..30cb99d45c --- /dev/null +++ b/test/files/pos/t2066.scala @@ -0,0 +1,25 @@ +trait A1 { + def f[T[+_]] = () +} + +trait B1 extends A1 { + override def f[T[_]] = () +} + + +trait A2 { + def f[T[-_]] = () +} + +trait B2 extends A2 { + override def f[T[_]] = () +} + + +trait A3 { + def f[T[X[_]]] = () +} + +trait B3 extends A3 { + override def f[T[X[+_]]] = () +} diff --git a/test/files/pos/t261-ab.scala b/test/files/pos/t261-ab.scala deleted file mode 100644 index df641e811a..0000000000 --- a/test/files/pos/t261-ab.scala +++ /dev/null @@ -1,9 +0,0 @@ -trait A { val foo: String = "A" } -trait B { - private val foo: String = "B" - def f = println(foo) -} -object Test extends App with B with A { - println(foo) // prints "A", as expected - f // prints "B", as expected -} diff --git a/test/files/pos/t261-ba.scala b/test/files/pos/t261-ba.scala deleted file mode 100644 index 6c9c5b10b7..0000000000 --- a/test/files/pos/t261-ba.scala +++ /dev/null @@ -1,9 +0,0 @@ -trait B { - private val foo: String = "B" - def f = println(foo) -} -trait A { val foo: String = "A" } -object Test extends App with B with A { - println(foo) // prints "A", as expected - f // prints "B", as expected -} diff --git a/test/files/pos/t5692a/Macros_1.scala b/test/files/pos/t5692a/Macros_1.scala index 0e91f4d6a0..440e37d75d 100644 --- a/test/files/pos/t5692a/Macros_1.scala +++ b/test/files/pos/t5692a/Macros_1.scala @@ -1,6 +1,6 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl[T](c: BlackboxContext) = { import c.universe._; c.Expr[Unit](q"()") } + def impl[T](c: Context) = { import c.universe._; c.Expr[Unit](q"()") } def foo[T] = macro impl[T] }
\ No newline at end of file diff --git a/test/files/pos/t5692b/Macros_1.scala b/test/files/pos/t5692b/Macros_1.scala index 1034a1ea4a..98fb882844 100644 --- a/test/files/pos/t5692b/Macros_1.scala +++ b/test/files/pos/t5692b/Macros_1.scala @@ -1,6 +1,6 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl[T, U](c: BlackboxContext) = { import c.universe._; c.Expr[Unit](q"()") } + def impl[T, U](c: Context) = { import c.universe._; c.Expr[Unit](q"()") } def foo[T, U] = macro impl[T, U] }
\ No newline at end of file diff --git a/test/files/pos/t5706.scala b/test/files/pos/t5706.scala index 1970f5971f..6f0207366b 100644 --- a/test/files/pos/t5706.scala +++ b/test/files/pos/t5706.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.BlackboxContext -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.blackbox.{Context => BlackboxContext} +import scala.reflect.macros.whitebox.{Context => WhiteboxContext} class Logger { def error1(message: String) = macro Impls.error1 diff --git a/test/files/pos/t5744/Macros_1.scala b/test/files/pos/t5744/Macros_1.scala index 0fc13c12d7..6e2bf4825b 100644 --- a/test/files/pos/t5744/Macros_1.scala +++ b/test/files/pos/t5744/Macros_1.scala @@ -1,18 +1,18 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { def foo[U: Numeric](x: U) = macro foo_impl[U] def bar[U: Numeric : Equiv, Y <% String](x: U)(implicit s: String) = macro bar_impl[U, Y] - def foo_impl[U](c: BlackboxContext)(x: c.Expr[U])(numeric: c.Expr[Numeric[U]]) = { + def foo_impl[U](c: Context)(x: c.Expr[U])(numeric: c.Expr[Numeric[U]]) = { import c.universe._ val plusOne = Apply(Select(numeric.tree, newTermName("plus")), List(x.tree, Literal(Constant(1)))) val body = Apply(Select(Ident(definitions.PredefModule), newTermName("println")), List(plusOne)) c.Expr[Unit](body) } - def bar_impl[U, Y](c: BlackboxContext)(x: c.Expr[U])(numeric: c.Expr[Numeric[U]], equiv: c.Expr[Equiv[U]], viewAsString: c.Expr[Y => String], s: c.Expr[String]) = { + def bar_impl[U, Y](c: Context)(x: c.Expr[U])(numeric: c.Expr[Numeric[U]], equiv: c.Expr[Equiv[U]], viewAsString: c.Expr[Y => String], s: c.Expr[String]) = { import c.universe._ val plusOne = Apply(Select(numeric.tree, newTermName("plus")), List(x.tree, Literal(Constant(1)))) val plusLen = Apply(Select(numeric.tree, newTermName("plus")), List(plusOne, Select(s.tree, newTermName("length")))) diff --git a/test/files/pos/t5900a.scala b/test/files/pos/t5900a.scala new file mode 100644 index 0000000000..cb02f67fb2 --- /dev/null +++ b/test/files/pos/t5900a.scala @@ -0,0 +1,9 @@ +case class Transition[S](x: S) + +object C + +object Test { + (??? : Any) match { + case Transition(C) => + } +} diff --git a/test/files/pos/t6047.scala b/test/files/pos/t6047.scala index c5bb44d87e..8c3dd18953 100644 --- a/test/files/pos/t6047.scala +++ b/test/files/pos/t6047.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import java.io.InputStream object Macros { def unpack[A](input: InputStream): A = macro unpack_impl[A] - def unpack_impl[A: c.WeakTypeTag](c: BlackboxContext)(input: c.Expr[InputStream]): c.Expr[A] = { + def unpack_impl[A: c.WeakTypeTag](c: Context)(input: c.Expr[InputStream]): c.Expr[A] = { import c.universe._ def unpackcode(tpe: c.Type): c.Expr[_] = { diff --git a/test/files/pos/t6169/Exist.java b/test/files/pos/t6169/Exist.java new file mode 100644 index 0000000000..dfc6b36b33 --- /dev/null +++ b/test/files/pos/t6169/Exist.java @@ -0,0 +1,4 @@ +public class Exist<T extends String> { + // java helpfully re-interprets Exist<?> as Exist<? extends String> + public Exist<?> foo() { throw new RuntimeException(); } +}
\ No newline at end of file diff --git a/test/files/pos/t6169/ExistF.java b/test/files/pos/t6169/ExistF.java new file mode 100644 index 0000000000..70fabd74cf --- /dev/null +++ b/test/files/pos/t6169/ExistF.java @@ -0,0 +1,4 @@ +public class ExistF<T extends ExistF<T>> { + // java helpfully re-interprets ExistF<?> as ExistF<?0 extends ExistF<?0>> + public ExistF<?> foo() { throw new RuntimeException(); } +}
\ No newline at end of file diff --git a/test/files/pos/t6169/ExistIndir.java b/test/files/pos/t6169/ExistIndir.java new file mode 100644 index 0000000000..e66d1698c4 --- /dev/null +++ b/test/files/pos/t6169/ExistIndir.java @@ -0,0 +1,4 @@ +public class ExistIndir<T extends String, U extends T> { + // java helpfully re-interprets ExistIndir<?> as ExistIndir<? extends String> + public ExistIndir<?, ?> foo() { throw new RuntimeException(); } +} diff --git a/test/files/pos/t6169/OP.java b/test/files/pos/t6169/OP.java new file mode 100644 index 0000000000..15e4c5640f --- /dev/null +++ b/test/files/pos/t6169/OP.java @@ -0,0 +1 @@ +public abstract class OP<T> { } diff --git a/test/files/pos/t6169/Skin.java b/test/files/pos/t6169/Skin.java new file mode 100644 index 0000000000..780de1ee09 --- /dev/null +++ b/test/files/pos/t6169/Skin.java @@ -0,0 +1 @@ +public interface Skin<C extends Skinnable> { } diff --git a/test/files/pos/t6169/Skinnable.java b/test/files/pos/t6169/Skinnable.java new file mode 100644 index 0000000000..f91eaa30d8 --- /dev/null +++ b/test/files/pos/t6169/Skinnable.java @@ -0,0 +1,3 @@ +public interface Skinnable { + OP<Skin<?>> skinProperty(); +} diff --git a/test/files/pos/t6169/skinnable.scala b/test/files/pos/t6169/skinnable.scala new file mode 100644 index 0000000000..3ba2734526 --- /dev/null +++ b/test/files/pos/t6169/skinnable.scala @@ -0,0 +1,14 @@ +object ObjectProperty { + implicit def jfxObjectProperty2sfx[T](p: OP[T]) = new ObjectProperty[T](p) +} + +class ObjectProperty[T](val delegate: OP[T]) + +trait TestWildcardBoundInference { + def delegate: Skinnable + def skin: ObjectProperty[Skin[_ /* inferred: <: Skinnable */]] = ObjectProperty.jfxObjectProperty2sfx(delegate.skinProperty) + skin: ObjectProperty[Skin[_ <: Skinnable]] + + def skinCheckInference = delegate.skinProperty + skinCheckInference: ObjectProperty[Skin[_ <: Skinnable]] +}
\ No newline at end of file diff --git a/test/files/pos/t6169/t6169.scala b/test/files/pos/t6169/t6169.scala new file mode 100644 index 0000000000..37f42619ca --- /dev/null +++ b/test/files/pos/t6169/t6169.scala @@ -0,0 +1,7 @@ +class Test { + class MyExist extends ExistF[MyExist] + // SI-8197, SI-6169: java infers the bounds of existentials, so we have to as well now that SI-1786 is fixed... + def stringy: Exist[_ <: String] = (new Exist[String]).foo + def fbounded: (ExistF[t] forSome {type t <: ExistF[t] }) = (new MyExist).foo + def indir: ExistIndir[_ <: String, _ <: String] = (new ExistIndir[String, String]).foo +}
\ No newline at end of file diff --git a/test/files/neg/t6260.flags b/test/files/pos/t6260.flags index 2349d8294d..2349d8294d 100644 --- a/test/files/neg/t6260.flags +++ b/test/files/pos/t6260.flags diff --git a/test/files/neg/t6260.scala b/test/files/pos/t6260.scala index 93b5448227..93b5448227 100644 --- a/test/files/neg/t6260.scala +++ b/test/files/pos/t6260.scala diff --git a/test/files/neg/t6260b.scala b/test/files/pos/t6260b.scala index 73e2e58f73..73e2e58f73 100644 --- a/test/files/neg/t6260b.scala +++ b/test/files/pos/t6260b.scala diff --git a/test/files/pos/t6447.scala b/test/files/pos/t6447.scala index 8203c0cddd..6ef69d4852 100644 --- a/test/files/pos/t6447.scala +++ b/test/files/pos/t6447.scala @@ -1,18 +1,18 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context class X { type T } object X { // this works def foo(x: X): x.T = macro fooImpl - def fooImpl(c: BlackboxContext)(x: c.Expr[X]): c.Expr[x.value.T] = ??? + def fooImpl(c: Context)(x: c.Expr[X]): c.Expr[x.value.T] = ??? // this doesn't def bar(x: X, y: X): (x.T, y.T) = macro barImpl - def barImpl(c: BlackboxContext)(x: c.Expr[X], y: c.Expr[X]): c.Expr[(x.value.T, y.value.T)] = ??? + def barImpl(c: Context)(x: c.Expr[X], y: c.Expr[X]): c.Expr[(x.value.T, y.value.T)] = ??? // neither does this def baz(x: X)(xs: List[x.T]): Unit = macro bazImpl - def bazImpl(c: BlackboxContext)(x: c.Expr[X])(xs: c.Expr[List[x.value.T]]): c.Expr[Unit] = ??? + def bazImpl(c: Context)(x: c.Expr[X])(xs: c.Expr[List[x.value.T]]): c.Expr[Unit] = ??? } diff --git a/test/files/pos/t6485a/Macros_1.scala b/test/files/pos/t6485a/Macros_1.scala index c637c2cfee..570c987709 100644 --- a/test/files/pos/t6485a/Macros_1.scala +++ b/test/files/pos/t6485a/Macros_1.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def crash(c: BlackboxContext): c.Expr[Unit] = c.universe.reify(()) + def crash(c: Context): c.Expr[Unit] = c.universe.reify(()) }
\ No newline at end of file diff --git a/test/files/pos/t6485b/Test.scala b/test/files/pos/t6485b/Test.scala index 9897987516..3b81c6f8ab 100644 --- a/test/files/pos/t6485b/Test.scala +++ b/test/files/pos/t6485b/Test.scala @@ -1,10 +1,10 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context final class Ops[T](val x: T) extends AnyVal { def f = macro Macros.crash } object Macros { - def crash(c: BlackboxContext): c.Expr[Unit] = c.universe.reify(()) + def crash(c: Context): c.Expr[Unit] = c.universe.reify(()) }
\ No newline at end of file diff --git a/test/files/pos/t6516.scala b/test/files/pos/t6516.scala index aed359976e..2980d83eb6 100644 --- a/test/files/pos/t6516.scala +++ b/test/files/pos/t6516.scala @@ -1,17 +1,17 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import scala.collection.TraversableLike // This one compiles object Test { - type Alias[T, CC[_]] = BlackboxContext { type PrefixType = TraversableLike[T, CC[T]] } + type Alias[T, CC[_]] = Context { type PrefixType = TraversableLike[T, CC[T]] } def f() = macro f_impl def f_impl(c: Alias[Int, List])() = ??? } // This one doesn't object Test2 { - type Ctx = scala.reflect.macros.BlackboxContext + type Ctx = scala.reflect.macros.blackbox.Context type Alias[T, CC[_]] = Ctx { type PrefixType = TraversableLike[T, CC[T]] } def f() = macro f_impl diff --git a/test/files/pos/t6948.scala b/test/files/pos/t6948.scala new file mode 100644 index 0000000000..12a1d7eaf2 --- /dev/null +++ b/test/files/pos/t6948.scala @@ -0,0 +1,10 @@ +object t6948 { + val rand = new scala.util.Random() + def a1 = rand.shuffle(0 to 5) + // Tis not to be + // def a2 = rand.shuffle(0 until 5) + def a3 = rand.shuffle(Vector(1, 2, 3)) + def a4 = rand.shuffle(scala.collection.Seq(1, 2, 3)) + def a5 = rand.shuffle(scala.collection.immutable.Seq(1, 2, 3)) + def a6 = rand.shuffle(scala.collection.mutable.Seq(1, 2, 3)) +} diff --git a/test/files/pos/t7322.scala b/test/files/pos/t7322.scala new file mode 100644 index 0000000000..006bf89e9f --- /dev/null +++ b/test/files/pos/t7322.scala @@ -0,0 +1,11 @@ + +package object t7322 { + implicit class X(sc: StringContext) { + def x_?(args: Any*) = "hi there" + } +} +package t7322 { + trait Y { + x_?"junk" // assume that if it compiles, it works + } +} diff --git a/test/files/pos/t7377/Macro_1.scala b/test/files/pos/t7377/Macro_1.scala index 7280cfeaf5..b38687c8b3 100644 --- a/test/files/pos/t7377/Macro_1.scala +++ b/test/files/pos/t7377/Macro_1.scala @@ -1,7 +1,7 @@ import language.experimental._ -import reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object M { - def noopImpl[A](c: BlackboxContext)(expr: c.Expr[A]): c.Expr[A] = c.Expr(c.typecheck(c.resetLocalAttrs(expr.tree))) + def noopImpl[A](c: Context)(expr: c.Expr[A]): c.Expr[A] = c.Expr(c.typecheck(c.untypecheck(expr.tree))) def noop[A](expr: A): A = macro noopImpl[A] } diff --git a/test/files/pos/t7461/Macros_1.scala b/test/files/pos/t7461/Macros_1.scala index 89ae7c70e3..ca84d75624 100644 --- a/test/files/pos/t7461/Macros_1.scala +++ b/test/files/pos/t7461/Macros_1.scala @@ -1,8 +1,8 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ val wut = c.typecheck(Select(Literal(Constant(10)), newTermName("$minus")), silent = true) // println(showRaw(wut, printIds = true, printTypes = true)) diff --git a/test/files/pos/t7475a.scala b/test/files/pos/t7475a.scala new file mode 100644 index 0000000000..810ce9a05c --- /dev/null +++ b/test/files/pos/t7475a.scala @@ -0,0 +1,11 @@ +trait AbstractPublic { + def queue: Any +} +trait ConcretePrivate { + private val queue: Any = () +} + +abstract class Mix + extends ConcretePrivate with AbstractPublic { + final def queue: Any = () +} diff --git a/test/files/pos/t7475b.scala b/test/files/pos/t7475b.scala new file mode 100644 index 0000000000..a34743b8be --- /dev/null +++ b/test/files/pos/t7475b.scala @@ -0,0 +1,8 @@ +trait U { +} + +trait T { + type TT = Any with T with U + private val priv = 0 + (??? : TT).priv +} diff --git a/test/files/pos/t7475d.scala b/test/files/pos/t7475d.scala new file mode 100644 index 0000000000..497c2bf443 --- /dev/null +++ b/test/files/pos/t7475d.scala @@ -0,0 +1,11 @@ +trait T { + type TT = T with Any + private val priv = 0 + (??? : TT).priv +} + +trait U { + type UU = Any with U + private val priv = 0 + (??? : UU).priv +} diff --git a/test/files/pos/t7475e.scala b/test/files/pos/t7475e.scala new file mode 100644 index 0000000000..fbc965c4ca --- /dev/null +++ b/test/files/pos/t7475e.scala @@ -0,0 +1,13 @@ +trait U { + private val priv = 0 + type TT = U with T // should allow `priv` + (??? : TT).priv +} + +trait Base { + +} + +trait T extends Base { + +} diff --git a/test/files/pos/t7516/A_1.scala b/test/files/pos/t7516/A_1.scala index 3bba19966d..3bd477dcda 100644 --- a/test/files/pos/t7516/A_1.scala +++ b/test/files/pos/t7516/A_1.scala @@ -3,7 +3,7 @@ import scala.reflect._,macros._, scala.language.experimental.macros object A { def impl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[List[T]] = { val r = c.universe.reify { List(t.splice) } - c.Expr[List[T]]( c.resetLocalAttrs(r.tree) ) + c.Expr[List[T]]( c.untypecheck(r.tree) ) } def demo[T](t: T): List[T] = macro impl[T] } diff --git a/test/files/pos/t7649.scala b/test/files/pos/t7649.scala index fa5d13369f..d70dc05ea4 100644 --- a/test/files/pos/t7649.scala +++ b/test/files/pos/t7649.scala @@ -1,5 +1,5 @@ object Test { - val c: reflect.macros.BlackboxContext = ??? + val c: scala.reflect.macros.blackbox.Context = ??? import c.universe._ reify { // The lookup of the implicit WeakTypeTag[Any] diff --git a/test/files/pos/t7753.scala b/test/files/pos/t7753.scala new file mode 100644 index 0000000000..93ad23f114 --- /dev/null +++ b/test/files/pos/t7753.scala @@ -0,0 +1,36 @@ +import scala.language.{ higherKinds, implicitConversions } + +trait Foo { type Out } + +trait SI { + val instance: Foo + type Out +} + +object Test { + def test { + def indirect(si: SI)(v: si.instance.Out) = v + + val foo: Foo { type Out = Int } = ??? + def conv(i: Foo): SI { type Out = i.Out; val instance: i.type } = ??? + + val converted = conv(foo) + + val v1: Int = indirect(converted)(23) // Okay (after refining the return type `instance` in the return type of `conv`) + /* + indirect(converted){(v: converted.instance.Out)converted.instance.Out}( + 23{Int(23)} + ){converted.instance.Out}; + */ + + val v2: Int = indirect(conv(foo))(23) // Used to fail as follows: + /* + indirect( + conv(foo){si.SI{type Out = foo.Out; val instance: si.Test.<refinement>.type}} + ){(v: si.instance.Out)si.instance.Out}( + 23{<error>} + ){<error>}; + */ + + } +} diff --git a/test/files/pos/t7776.scala b/test/files/pos/t7776.scala index e0584b70e2..a36497a7a1 100644 --- a/test/files/pos/t7776.scala +++ b/test/files/pos/t7776.scala @@ -1,5 +1,5 @@ import scala.language.experimental.macros -import scala.reflect.macros.Context +import scala.reflect.macros.blackbox.Context class MacroErasure { def app(f: Any => Any, x: Any): Any = macro MacroErasure.appMacro diff --git a/test/files/pos/t7919.scala b/test/files/pos/t7919.scala new file mode 100644 index 0000000000..64f261ec16 --- /dev/null +++ b/test/files/pos/t7919.scala @@ -0,0 +1,6 @@ + +object X { + val x = s"" + val y = true +} + diff --git a/test/files/pos/t8001/Macros_1.scala b/test/files/pos/t8001/Macros_1.scala index fd26016d4b..3b80b88295 100644 --- a/test/files/pos/t8001/Macros_1.scala +++ b/test/files/pos/t8001/Macros_1.scala @@ -1,9 +1,9 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { def foo: Unit = macro impl - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ q"()" } diff --git a/test/files/pos/t8013/inpervolator_1.scala b/test/files/pos/t8013/inpervolator_1.scala index fb71571afc..89b7c22709 100644 --- a/test/files/pos/t8013/inpervolator_1.scala +++ b/test/files/pos/t8013/inpervolator_1.scala @@ -4,7 +4,7 @@ package t8013 // perverse macro to confuse Xlint import scala.language.experimental.macros -import scala.reflect.macros.{ BlackboxContext => Context } +import scala.reflect.macros.blackbox.Context object Perverse { diff --git a/test/files/pos/t8045.scala b/test/files/pos/t8045.scala new file mode 100644 index 0000000000..21154e386a --- /dev/null +++ b/test/files/pos/t8045.scala @@ -0,0 +1,17 @@ +object Test extends App { + case class Number(i: Int) + + object UnliftNumber { + def unapply(t: Any): Option[Number] = t match { + case i: Int => Some(Number(i)) + case _ => None + } + } + + def eval(expr: Any): Option[Number] = expr match { + case UnliftNumber(n) => Some(n) + case _ => None + } + + println(eval(1)) +} diff --git a/test/files/pos/t8046.scala b/test/files/pos/t8046.scala new file mode 100644 index 0000000000..304d70b6b8 --- /dev/null +++ b/test/files/pos/t8046.scala @@ -0,0 +1,20 @@ +trait One { + type Op[A] + type Alias[A] = Op[A] +} + +trait Two extends One { + trait Op[A] extends (A => A) + + // This compiles + class View1 extends Op[Int] { def apply(xs: Int) = xs } + + // ??? base class View2 not found in basetypes of class View2 + // ./a.scala:9: error: class View2 needs to be abstract, since \ + // method apply in trait Function1 of type (v1: T1)R is not defined + // (Note that T1 does not match Int) + // class View2 extends Alias[Int] { def apply(xs: Int) = xs } + // ^ + // one error found + class View2 extends Alias[Int] { def apply(xs: Int) = xs } +} diff --git a/test/files/pos/t8046b.scala b/test/files/pos/t8046b.scala new file mode 100644 index 0000000000..45b99fd7e0 --- /dev/null +++ b/test/files/pos/t8046b.scala @@ -0,0 +1,16 @@ +trait One { + type Op[A] + type Alias = Op[Int] +} + +trait Two extends One { + trait Op[A] extends M[A] + //(a: Alias) => a.value.toChar // okay + // (=> A).asSeenFrom(a.type, trait M): => Int + class View2 extends Alias { value.toChar } // toChar is not a member of type parameter A + // (=> A).asSeenFrom(View2.this.type, trait M): => A + + // override type Alias = Op[Int] // works with this +} + +trait M[A] { def value: A = sys.error("") } diff --git a/test/files/pos/t8046c.scala b/test/files/pos/t8046c.scala new file mode 100644 index 0000000000..f05b4c15b5 --- /dev/null +++ b/test/files/pos/t8046c.scala @@ -0,0 +1,19 @@ +trait One { + type Op[A] + type Alias[A] = Op[A] +} + +trait Three extends One { + trait Op[A] extends (A => A) + + def f1(f: Op[Int]) = f(5) + def f2(f: Alias[Int]) = f(5) + def f3[T <: Op[Int]](f: T) = f(5) + def f4[T <: Alias[Int]](f: T) = f(5) + // ./a.scala:12: error: type mismatch; + // found : Int(5) + // required: T1 + // def f4[T <: Alias[Int]](f: T) = f(5) + // ^ +} + diff --git a/test/files/pos/t8062.flags b/test/files/pos/t8062.flags new file mode 100644 index 0000000000..49d036a887 --- /dev/null +++ b/test/files/pos/t8062.flags @@ -0,0 +1 @@ +-optimize diff --git a/test/files/pos/t8062/A_1.scala b/test/files/pos/t8062/A_1.scala new file mode 100644 index 0000000000..ca0411dae8 --- /dev/null +++ b/test/files/pos/t8062/A_1.scala @@ -0,0 +1,5 @@ +package warmup + +object Warmup { + def filter[A](p: Any => Boolean): Any = filter[Any](p) +} diff --git a/test/files/pos/t8062/B_2.scala b/test/files/pos/t8062/B_2.scala new file mode 100644 index 0000000000..f0a6761488 --- /dev/null +++ b/test/files/pos/t8062/B_2.scala @@ -0,0 +1,3 @@ +object Test { + warmup.Warmup.filter[Any](x => false) +} diff --git a/test/files/pos/t8064/Macro_1.scala b/test/files/pos/t8064/Macro_1.scala index 4fabd54a89..9f1e6955b4 100644 --- a/test/files/pos/t8064/Macro_1.scala +++ b/test/files/pos/t8064/Macro_1.scala @@ -1,10 +1,10 @@ import language.experimental.macros -import scala.reflect.macros.Context +import scala.reflect.macros.blackbox.Context object Macro { def apply(a: Any): Any = macro impl def impl(c: Context)(a: c.Tree): c.Tree = { - c.resetLocalAttrs(a) + c.untypecheck(a) } } diff --git a/test/files/pos/t8064b/Macro_1.scala b/test/files/pos/t8064b/Macro_1.scala index 82582356c0..60996bfeca 100644 --- a/test/files/pos/t8064b/Macro_1.scala +++ b/test/files/pos/t8064b/Macro_1.scala @@ -1,5 +1,5 @@ import language.experimental.macros -import scala.reflect.macros.Context +import scala.reflect.macros.blackbox.Context object Macro { def apply(a: Any): Any = macro impl diff --git a/test/files/pos/t8111.scala b/test/files/pos/t8111.scala new file mode 100644 index 0000000000..0d63a16ba4 --- /dev/null +++ b/test/files/pos/t8111.scala @@ -0,0 +1,24 @@ +trait T { + + def crashy(ma: Any) { + // okay + val f1 = (u: Unit) => ma + foo(f1)() + foo((u: Unit) => ma) + foo(0, (u: Any) => ma) apply () + + // crash due to side effects on the onwer of the symbol in the + // qualifier or arguments of the application during an abandoned + // names/defaults transform. The code type checkes because of + // autp-tupling which promotes and empty parmater list to `(): Unit` + foo((u: Any) => ma)() + + {{(u: Any) => ma}; this}.foo(0)() + + foo({def foo = ma; 0})() + + {def foo = ma; this}.foo(0)() + } + + def foo(f: Any): Any => Any +} diff --git a/test/files/pos/t8128.scala b/test/files/pos/t8128.scala new file mode 100644 index 0000000000..b6f76691b0 --- /dev/null +++ b/test/files/pos/t8128.scala @@ -0,0 +1,15 @@ +object G { + def unapply(m: Any): Option[_] = Some("") +} + +object H { + def unapplySeq(m: Any): Option[Seq[_]] = None +} + +object Test { + (0: Any) match { + case G(v) => v + case H(v) => v + case _ => + } +} diff --git a/test/files/pos/t8132.scala b/test/files/pos/t8132.scala new file mode 100644 index 0000000000..b4d6fd9441 --- /dev/null +++ b/test/files/pos/t8132.scala @@ -0,0 +1,5 @@ +trait T { + protected def s: String +} + +case class G(override protected val s: String) extends T diff --git a/test/files/pos/t8138.scala b/test/files/pos/t8138.scala new file mode 100644 index 0000000000..b980930955 --- /dev/null +++ b/test/files/pos/t8138.scala @@ -0,0 +1,24 @@ + +class U { + trait Transformer { + def transform(a: Tree): Tree = ??? + } + trait Tree +} + +object Test { + def m(u: U) = { + class C extends u.Transformer { + override def transform(t: u.Tree): u.Tree = { + null match { + case _ => + // crashes in GenICode: + // error: Unknown type: <notype>, <notype> [class scala.reflect.internal.Types$NoType$, class scala.reflect.internal.Types$NoType$] TypeRef? false + (y: Any) => super.transform(???) + null + } + ??? + } + } + } +} diff --git a/test/files/pos/t8146a.scala b/test/files/pos/t8146a.scala new file mode 100644 index 0000000000..e4eb8d3fd1 --- /dev/null +++ b/test/files/pos/t8146a.scala @@ -0,0 +1,9 @@ +trait M[+A] + +object Test { + type Inty = Int + def t1( + x: M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[Int @unchecked]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] + ): M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[M[Inty @unchecked]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] + = x +} diff --git a/test/files/pos/t8146b.scala b/test/files/pos/t8146b.scala new file mode 100644 index 0000000000..dd031f66c8 --- /dev/null +++ b/test/files/pos/t8146b.scala @@ -0,0 +1,77 @@ +// non-deterministic type errors, non-termination. +// seems to be due to inconsistent hashing/equality in SubTypePair + +import scala.language.{existentials, implicitConversions} +import scala.annotation.unchecked.uncheckedVariance + +trait Column[T] + +// Turning this into a trait reduces (eliminates?) the likelihood of type errors (but not of non-termination) +abstract class Shape[Level <: ShapeLevel, -Mixed_, Unpacked_, Packed_] + +trait ShapeLevel +trait NestedShapeLevel extends ShapeLevel +trait FlatShapeLevel extends NestedShapeLevel +trait ColumnsShapeLevel extends FlatShapeLevel + +trait ProvenShape[U] + +object ProvenShape { + implicit def proveShapeOf[T, U](v: T)(implicit sh: Shape[_ <: FlatShapeLevel, T, U, _]): ProvenShape[U] = ??? +} + +sealed abstract class HList { + type Self <: HList + type :: [E] = HCons[E, Self] + final def :: [E](elem: E): :: [E] = ??? +} + +final class HCons[+H, +T <: HList](val head: H, val tail: T) extends HList { + type Self = HCons[H @uncheckedVariance, T @uncheckedVariance] +} + +final object HNil extends HList { + type Self = HNil.type +} + +// Success is more likely when not using these aliases +object syntax { + type :: [+H, +T <: HList] = HCons[H, T] + type HNil = HNil.type +} + +class HListBench { + + import syntax._ + + implicit def columnShape[T, Level <: ShapeLevel]: Shape[Level, Column[T], T, Column[T]] = ??? + implicit def provenShape[T, P](implicit shape: Shape[_ <: FlatShapeLevel, T, _, P]): Shape[FlatShapeLevel, ProvenShape[T], T, P] = ??? + final class HListShape[Level <: ShapeLevel, M <: HList, U <: HList, P <: HList](val shapes: Seq[Shape[_ <: ShapeLevel, _, _, _]]) extends Shape[Level, M, U, P] + implicit def hnilShape[Level <: ShapeLevel] = new HListShape[Level, HNil.type, HNil.type, HNil.type](Nil) + implicit def hconsShape[Level <: ShapeLevel, M1, M2 <: HList, U1, U2 <: HList, P1, P2 <: HList] + (implicit s1: Shape[_ <: Level, M1, U1, P1], s2: HListShape[_ <: Level, M2, U2, P2]) = + new HListShape[Level, M1 :: M2, U1 :: U2, P1 :: P2](s1 +: s2.shapes) + + trait A[T] { + def * : ProvenShape[T] + } + + trait B extends A[ + Int :: Int :: Int :: Int :: Int :: + Int :: Int :: Int :: Int :: Int :: + Int :: Int :: Int :: Int :: Int :: + Int :: Int :: Int :: Int :: Int :: + Int :: Int :: Int :: Int :: Int :: + Int :: Int :: HNil ] { + + def c: Column[Int] + + def * = c :: c :: c :: c :: c :: + c :: c :: c :: c :: c :: + c :: c :: c :: c :: c :: + c :: c :: c :: c :: c :: + c :: c :: c :: c :: c :: + c :: c :: HNil + + } +} diff --git a/test/files/pos/t8170.scala b/test/files/pos/t8170.scala new file mode 100644 index 0000000000..b65f4b8572 --- /dev/null +++ b/test/files/pos/t8170.scala @@ -0,0 +1,27 @@ +object O { + trait X + trait B extends A { + override type T[F1 <: X] = F1 + } + trait A { + type T[F <: X] + } +} + +object Test { + import O._ + val a: B = ??? + val b: a.T[X] = ??? + b.ensuring(x => true) // trigger an implicit search +} + + +/* +this = {AliasArgsTypeRef@3004}"Test#7680.a#14899.T#14823[O#7702.X#7793]" + sym = type T#14823 + info = namer: [F#14824 <: O#7703.X#7793]F#14824 +result = {AbstractNoArgsTypeRef@3237}"F#24451" +tp = {PolyType@3235}"[F#14824 <: O#7703.X#7793]F#14824" +tparams = + (0) = {AbstractTypeSymbol@3247}"type F#24451" +*/
\ No newline at end of file diff --git a/test/files/pos/t8170b.scala b/test/files/pos/t8170b.scala new file mode 100644 index 0000000000..53036f6c8a --- /dev/null +++ b/test/files/pos/t8170b.scala @@ -0,0 +1,25 @@ +import language._ + +object ScalaZeee { + trait HFold[M[_], U] { + type Apply[E, A <: U] <: U + } + trait GenericCons[M[_], H, +T <: GenericList[M]] extends GenericList[M] { + val tail: T + override type Folded[N[X] >: M[X], U, F <: HFold[N, U]] = F#Apply[H, tail.Folded[N, U, F]] + } + val KNil: GenericList[Nothing] = ??? + sealed trait GenericList[+M[_]] { + type Folded[N[X] >: M[X], U, F <: HFold[N, U]] <: U + } +} + +object TypelevelUsage { + import ScalaZeee._ + type T = GenericCons[Some, String, KNil.type] + val klist1: T = ??? + type T2 = klist1.Folded[Option, Int, HFold[Option, Int]] + val count2: T2 = ??? + + count2.ensuring(x => true).toChar // trigger an implicit search +} diff --git a/test/files/pos/t8177.scala b/test/files/pos/t8177.scala new file mode 100644 index 0000000000..fe265f8d0a --- /dev/null +++ b/test/files/pos/t8177.scala @@ -0,0 +1,12 @@ +// exercise coevolveSym: SingleType with an underlying RefinedType +trait Thing { type A } +object IntThing extends Thing { type A = Int } + +// The following erroneously failed with error: method f overrides nothing. +// because asSeenFrom produced a typeref of the shape T'#A where A referred to a symbol defined in a T of times past +// More precisely, the TypeRef case of TypeMap's mapOver correctly modified prefix +// from having an underlying type of { type A = Ain } to { type A = Int }, with a new symbol for A (now with info Int), +// but the symbol in the outer type ref wasn't co-evolved (so it still referred to the { type A = AIn } underlying the old prefix) +// coEvolveSym used to only look at prefixes that were directly RefinedTypes, but they could also be SingleTypes with an underlying RefinedType +class View[AIn](val in: Thing { type A = AIn }) { def f(p: in.A): in.A = p } +class SubView extends View[Int](IntThing) { override def f(p: in.A): in.A = p } diff --git a/test/files/pos/t8177a.scala b/test/files/pos/t8177a.scala new file mode 100644 index 0000000000..7e2cfb386c --- /dev/null +++ b/test/files/pos/t8177a.scala @@ -0,0 +1,9 @@ +// exercise coevolveSym +trait Thing { type A; var p: A = _ } +class AA[T](final val x: Thing { type A = T }) { + def foo: x.A = ??? +} + +class B extends AA[Int](null) { + override def foo: B.this.x.A = super.foo +} diff --git a/test/files/pos/t8177b.scala b/test/files/pos/t8177b.scala new file mode 100644 index 0000000000..b7ed9342a3 --- /dev/null +++ b/test/files/pos/t8177b.scala @@ -0,0 +1,13 @@ +// exercise coevolveSym: SingleType with an underlying RefinedType, via a type alias +trait Thing { type A } +object IntThing extends Thing { type A = Int } +object ThingHolder { type Alias[AIn] = Thing { type A = AIn } } + +// The following erroneously failed with error: method f overrides nothing. +// because asSeenFrom produced a typeref of the shape T'#A where A referred to a symbol defined in a T of times past +// More precisely, the TypeRef case of TypeMap's mapOver correctly modified prefix +// from having an underlying type of { type A = Ain } to { type A = Int }, with a new symbol for A (now with info Int), +// but the symbol in the outer type ref wasn't co-evolved (so it still referred to the { type A = AIn } underlying the old prefix) +// coEvolveSym used to only look at prefixes that were directly RefinedTypes, but they could also be SingleTypes with an underlying RefinedType +class View[AIn](val in: ThingHolder.Alias[AIn]) { def f(p: in.A): in.A = p } +class SubView extends View[Int](IntThing) { override def f(p: in.A): in.A = p }
\ No newline at end of file diff --git a/test/files/pos/t8177d.scala b/test/files/pos/t8177d.scala new file mode 100644 index 0000000000..d15a05a359 --- /dev/null +++ b/test/files/pos/t8177d.scala @@ -0,0 +1,12 @@ +// exercise coevolveSym +trait HasElem { type A } +trait View[AIn] { + val tc: HasElem { type A = AIn } + def f2(p: tc.A): tc.A = p +} + +object Test { + val view: View[Int] = null + + view f2 5 // fails +} diff --git a/test/files/pos/t8177e.scala b/test/files/pos/t8177e.scala new file mode 100644 index 0000000000..cb1136ff11 --- /dev/null +++ b/test/files/pos/t8177e.scala @@ -0,0 +1,3 @@ +// exercise coevolveSym +trait T[A] { val foo: { type B = A } = ???; def bar(b: foo.B) = () } +object O extends T[Int] { bar(0) } diff --git a/test/files/pos/t8177g.scala b/test/files/pos/t8177g.scala new file mode 100644 index 0000000000..bb66d32021 --- /dev/null +++ b/test/files/pos/t8177g.scala @@ -0,0 +1,11 @@ +// exercise coevolveSym: ThisType +trait HasA { type A } +class AA[T] { + type HasAT[T] = HasA{ type A = T } + val x: HasAT[T] = ??? + def foo: x.A = ??? +} + +class B extends AA[Int] { + override def foo: B.this.x.A = super.foo +}
\ No newline at end of file diff --git a/test/files/pos/t8207.scala b/test/files/pos/t8207.scala new file mode 100644 index 0000000000..680b40f379 --- /dev/null +++ b/test/files/pos/t8207.scala @@ -0,0 +1,6 @@ +class C { me => + import me.{toString => ts} + locally(this: me.type) + trait T + type X = me.T +} diff --git a/test/files/pos/t8209a.check b/test/files/pos/t8209a.check new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/files/pos/t8209a.check diff --git a/test/files/pos/t8209a/Macros_1.scala b/test/files/pos/t8209a/Macros_1.scala new file mode 100644 index 0000000000..17014b4744 --- /dev/null +++ b/test/files/pos/t8209a/Macros_1.scala @@ -0,0 +1,17 @@ +import scala.language.experimental.macros +import scala.language.implicitConversions +import scala.reflect.macros.blackbox.Context + +class A +object A { implicit def a2b(a: A): B = ??? } +class B +class C extends A + +object Macros { + def impl(c: Context) = { + import c.universe._ + q"new C" + } + + def foo: A = macro impl +}
\ No newline at end of file diff --git a/test/files/pos/t8209a/Test_2.scala b/test/files/pos/t8209a/Test_2.scala new file mode 100644 index 0000000000..e19d572f55 --- /dev/null +++ b/test/files/pos/t8209a/Test_2.scala @@ -0,0 +1,4 @@ +object Test extends App { + val a: A = Macros.foo + val b: B = Macros.foo +}
\ No newline at end of file diff --git a/test/files/pos/t8209b.check b/test/files/pos/t8209b.check new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/files/pos/t8209b.check diff --git a/test/files/pos/t8209b/Macros_1.scala b/test/files/pos/t8209b/Macros_1.scala new file mode 100644 index 0000000000..705f7d630c --- /dev/null +++ b/test/files/pos/t8209b/Macros_1.scala @@ -0,0 +1,17 @@ +import scala.language.experimental.macros +import scala.language.implicitConversions +import scala.reflect.macros.whitebox.Context + +class A +object A { implicit def a2b(a: A): B = ??? } +class B +class C extends A + +object Macros { + def impl(c: Context) = { + import c.universe._ + q"new C" + } + + def foo: A = macro impl +}
\ No newline at end of file diff --git a/test/files/pos/t8209b/Test_2.scala b/test/files/pos/t8209b/Test_2.scala new file mode 100644 index 0000000000..e19d572f55 --- /dev/null +++ b/test/files/pos/t8209b/Test_2.scala @@ -0,0 +1,4 @@ +object Test extends App { + val a: A = Macros.foo + val b: B = Macros.foo +}
\ No newline at end of file diff --git a/test/files/pos/t8219.scala b/test/files/pos/t8219.scala new file mode 100644 index 0000000000..e1653b6238 --- /dev/null +++ b/test/files/pos/t8219.scala @@ -0,0 +1,15 @@ +trait Equalizer[T] +trait Gen[A] + +class Broken { + implicit def const[T](x: T): Gen[T] = ??? + implicit def convertToEqualizer[T](left: T): Equalizer[T] = ??? + + def in(a: Any) = () + in { + import scala.None // any import will do.. + "" == "" // this no longer triggers the bug, as Object#== now overrides Any#== + } + + // We can still trigger the bug with a structural type, see pending/neg/t8219.scala +} diff --git a/test/files/pos/t8219b.scala b/test/files/pos/t8219b.scala new file mode 100644 index 0000000000..d55d3139e1 --- /dev/null +++ b/test/files/pos/t8219b.scala @@ -0,0 +1,49 @@ +trait Equalizer[T] +trait Gen[A] + +class Broken { + implicit def const[T](x: T): Gen[T] = ??? + implicit def convertToEqualizer[T](left: T): Equalizer[T] = ??? + + def in(a: Any) = () + in { + import scala.None // any import will do.. + "" == "" // no longer a problem, see pos/t8129.scala + } + + // We used to fall into the errant code path above when `Any#==` and `AnyRef#==` + // were overloaded. + // + // Real classes couldn't get away with that overloading; it would result in + // a compiler error because the variants would collapse into an overriding + // relationship after erasure. + // + // + // But, a structural type can! This triggers the same error, and served as + // a backstop for this test if we change the signatures of `AnyRef#==` to + // override `Any#==`. + type T = { + def a(a: AnyRef): Boolean + def a(a: Any): Boolean + } + + def t: T = ??? + + in { + import scala.None // any import will do.. + t.a("") + } + + // Or, we can get here with ambiguous implicits from the formal parameter + // type of the less specific overload to that of the more specific. + object T { + def foo(a: Any) = true + def foo(a: String) = true + } + in { + import scala.None + implicit def any2str1(a: Any) = "" + implicit def any2str2(a: Any) = "" + T.foo("") + } +} diff --git a/test/files/pos/t8223.scala b/test/files/pos/t8223.scala new file mode 100644 index 0000000000..52d6b0098e --- /dev/null +++ b/test/files/pos/t8223.scala @@ -0,0 +1,29 @@ +package p { + class ViewEnv[AIn] { + type A = AIn + class SubView { def has(x: A): Boolean = ??? } + def get: SubView = new SubView + } + + trait HasA { type A } + trait Indexable[R] extends HasA + class ArrayTC[AIn] extends Indexable[Array[AIn]] { type A = AIn } +} + +package object p { + implicit def arrayTypeClass[A] : ArrayTC[A] = new ArrayTC[A] + object intArrayTC extends ArrayTC[Int] + + type EnvAlias[W <: HasA] = ViewEnv[W#A] + type SubAlias[W <: HasA] = ViewEnv[W#A]#SubView + + def f0[R](xs: R)(implicit tc: Indexable[R]): ViewEnv[tc.A]#SubView = new ViewEnv[tc.A]() get + def f1[R](xs: R)(implicit tc: Indexable[R]): EnvAlias[tc.type]#SubView = new ViewEnv[tc.A]() get + def f2[R](xs: R)(implicit tc: Indexable[R]): SubAlias[tc.type] = new ViewEnv[tc.A]() get + + def g0 = f0(Array(1)) has 2 // ok + def g1 = f1(Array(1)) has 2 // ok + def g2 = f2(Array(1)) has 2 // "found: Int(2), required: tc.A" + def g3 = f2(Array(1))(new ArrayTC[Int]) has 2 // "found: Int(2), required: tc.A" + def g4 = f2(Array(1))(intArrayTC) has 2 // ok +} diff --git a/test/files/pos/t8237.scala b/test/files/pos/t8237.scala new file mode 100644 index 0000000000..005089079e --- /dev/null +++ b/test/files/pos/t8237.scala @@ -0,0 +1,29 @@ +import scala.language.higherKinds + +object TestExplicit { + trait TC[A] + def fTt[A,E[X] <: List[X]](a: A)(implicit tt: TC[E[A]]) = a + implicit def tc[T]: TC[T] = ??? + + // Typechecking results in SOE in TypeVar.isGround + fTt(1)(tc) + // fun = TestExplicit.this.fTt[Int, E](1) + // args = TestExplicit.this.tc[E[Int]] + // argTpes.head.instantiateTypeParams = TC[?E#1[Int]] + // formals.head.instantiateTypeParams = TC[?E#2[Int]] + // (where ?E#1 and ?E#2 as distinct AppliedTypeVars that resulted + // from separate applications of type args to the same HKTypeVar, ?E) + // + // As we check if the argument conforms to the formal, we would have + // AppliedTypeVars sharing the same TypeConstraints on the LHS and RHS, + // which leads to a cyclic constraint. +} + +object TestImplicit { + trait TC[A] + def fTt[A,E[X] <: List[X]](a: A)(implicit tt: TC[E[A]]) = a + implicit def tc[T]: TC[T] = ??? + + // Oddly enough, this one works. + fTt(1) +} diff --git a/test/files/pos/t8237b.scala b/test/files/pos/t8237b.scala new file mode 100644 index 0000000000..52bb310e8b --- /dev/null +++ b/test/files/pos/t8237b.scala @@ -0,0 +1,10 @@ +import scala.language.higherKinds +import scala.reflect.runtime.universe._ +object Test { + + def fTt[A,E[X]<:List[X]](a: A)(implicit tt: TypeTag[E[A]]) = a + + trait TC[A] + implicit def TCListInt[A]: TC[A] = ??? + fTt(1) +} diff --git a/test/files/pos/t8244d/InodeBase_1.java b/test/files/pos/t8244d/InodeBase_1.java new file mode 100644 index 0000000000..36c2123418 --- /dev/null +++ b/test/files/pos/t8244d/InodeBase_1.java @@ -0,0 +1,6 @@ +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +abstract class INodeBase_1<K, V> { + @SuppressWarnings("rawtypes") + public static final AtomicReferenceFieldUpdater<INodeBase_1, Object> updater = null; +} diff --git a/test/files/pos/t8244d/Test_2.scala b/test/files/pos/t8244d/Test_2.scala new file mode 100644 index 0000000000..cb39c9692c --- /dev/null +++ b/test/files/pos/t8244d/Test_2.scala @@ -0,0 +1,3 @@ +class INodeX[K, V] extends INodeBase_1[K, V] { + INodeBase_1.updater.set(this, null) +} diff --git a/test/files/presentation/callcc-interpreter.check b/test/files/presentation/callcc-interpreter.check index 1f868097ca..4bf68b3d4e 100644 --- a/test/files/presentation/callcc-interpreter.check +++ b/test/files/presentation/callcc-interpreter.check @@ -3,7 +3,7 @@ reload: CallccInterpreter.scala askTypeCompletion at CallccInterpreter.scala(51,34) ================================================================================ [response] askTypeCompletion at (51,34) -retrieved 59 members +retrieved 57 members abstract trait Term extends AnyRef abstract trait Value extends AnyRef case class Add extends callccInterpreter.Term with Product with Serializable @@ -38,10 +38,8 @@ def toString(): String def unitM[A](a: A): callccInterpreter.M[A] def →[B](y: B): (callccInterpreter.type, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean diff --git a/test/files/presentation/completion-implicit-chained.check b/test/files/presentation/completion-implicit-chained.check index f9d77f7a53..c583b7877c 100644 --- a/test/files/presentation/completion-implicit-chained.check +++ b/test/files/presentation/completion-implicit-chained.check @@ -3,7 +3,7 @@ reload: Completions.scala askTypeCompletion at Completions.scala(11,16) ================================================================================ [response] askTypeCompletion at (11,16) -retrieved 24 members +retrieved 22 members [inaccessible] protected[package lang] def clone(): Object [inaccessible] protected[package lang] def finalize(): Unit def equals(x$1: Any): Boolean @@ -11,10 +11,8 @@ def hashCode(): Int def map(x: Int => Int)(implicit a: DummyImplicit): test.O.type def toString(): String final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean diff --git a/test/files/presentation/ide-bug-1000349.check b/test/files/presentation/ide-bug-1000349.check index c59fa6843f..79bfde5343 100644 --- a/test/files/presentation/ide-bug-1000349.check +++ b/test/files/presentation/ide-bug-1000349.check @@ -3,7 +3,7 @@ reload: CompletionOnEmptyArgMethod.scala askTypeCompletion at CompletionOnEmptyArgMethod.scala(2,17) ================================================================================ [response] askTypeCompletion at (2,17) -retrieved 32 members +retrieved 30 members def +(other: String): String def ->[B](y: B): (Foo, B) def ensuring(cond: Boolean): Foo @@ -17,10 +17,8 @@ def hashCode(): Int def toString(): String def →[B](y: B): (Foo, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean diff --git a/test/files/presentation/ide-bug-1000475.check b/test/files/presentation/ide-bug-1000475.check index f5b4253e1a..4fb7f18285 100644 --- a/test/files/presentation/ide-bug-1000475.check +++ b/test/files/presentation/ide-bug-1000475.check @@ -3,7 +3,7 @@ reload: Foo.scala askTypeCompletion at Foo.scala(3,7) ================================================================================ [response] askTypeCompletion at (3,7) -retrieved 31 members +retrieved 29 members [inaccessible] protected[package lang] def clone(): Object [inaccessible] protected[package lang] def finalize(): Unit def +(other: String): String @@ -18,10 +18,8 @@ def hashCode(): Int def toString(): String def →[B](y: B): (Object, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean @@ -37,7 +35,7 @@ final def wait(x$1: Long,x$2: Int): Unit askTypeCompletion at Foo.scala(6,10) ================================================================================ [response] askTypeCompletion at (6,10) -retrieved 31 members +retrieved 29 members [inaccessible] protected[package lang] def clone(): Object [inaccessible] protected[package lang] def finalize(): Unit def +(other: String): String @@ -52,10 +50,8 @@ def hashCode(): Int def toString(): String def →[B](y: B): (Object, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean @@ -71,7 +67,7 @@ final def wait(x$1: Long,x$2: Int): Unit askTypeCompletion at Foo.scala(7,7) ================================================================================ [response] askTypeCompletion at (7,7) -retrieved 31 members +retrieved 29 members [inaccessible] protected[package lang] def clone(): Object [inaccessible] protected[package lang] def finalize(): Unit def +(other: String): String @@ -86,10 +82,8 @@ def hashCode(): Int def toString(): String def →[B](y: B): (Object, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean diff --git a/test/files/presentation/ide-bug-1000531.check b/test/files/presentation/ide-bug-1000531.check index dff89b155b..d8c7a369f7 100644 --- a/test/files/presentation/ide-bug-1000531.check +++ b/test/files/presentation/ide-bug-1000531.check @@ -3,7 +3,7 @@ reload: CrashOnLoad.scala askTypeCompletion at CrashOnLoad.scala(6,12) ================================================================================ [response] askTypeCompletion at (6,12) -retrieved 120 members +retrieved 117 members [inaccessible] protected[package lang] def clone(): Object [inaccessible] protected[package lang] def finalize(): Unit [inaccessible] protected[this] def reversed: List[B] @@ -107,10 +107,8 @@ def zipWithIndex: Iterator[(B, Int)] def zip[B](that: Iterator[B]): Iterator[(B, B)] def →[B](y: B): (java.util.Iterator[B], B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean diff --git a/test/files/presentation/implicit-member.check b/test/files/presentation/implicit-member.check index 5ad52b4dd3..3bd3d8af41 100644 --- a/test/files/presentation/implicit-member.check +++ b/test/files/presentation/implicit-member.check @@ -3,7 +3,7 @@ reload: ImplicitMember.scala askTypeCompletion at ImplicitMember.scala(7,7) ================================================================================ [response] askTypeCompletion at (7,7) -retrieved 34 members +retrieved 32 members def +(other: String): String def ->[B](y: B): (Implicit.type, B) def ensuring(cond: Boolean): Implicit.type @@ -17,10 +17,8 @@ def toString(): String def →[B](y: B): (Implicit.type, B) final class AppliedImplicit[A] extends AnyRef final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean diff --git a/test/files/presentation/ping-pong.check b/test/files/presentation/ping-pong.check index 20f17aa7d0..220bdf33b2 100644 --- a/test/files/presentation/ping-pong.check +++ b/test/files/presentation/ping-pong.check @@ -3,7 +3,7 @@ reload: PingPong.scala askTypeCompletion at PingPong.scala(10,23) ================================================================================ [response] askTypeCompletion at (10,23) -retrieved 35 members +retrieved 32 members [inaccessible] private[this] val ping: Ping [inaccessible] protected[package lang] def clone(): Object [inaccessible] protected[package lang] def finalize(): Unit @@ -19,10 +19,8 @@ def hashCode(): Int def poke(): Unit def →[B](y: B): (Pong, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean @@ -40,7 +38,7 @@ private[this] val name: String askTypeCompletion at PingPong.scala(19,20) ================================================================================ [response] askTypeCompletion at (19,20) -retrieved 35 members +retrieved 33 members [inaccessible] protected[package lang] def clone(): Object [inaccessible] protected[package lang] def finalize(): Unit def +(other: String): String @@ -57,10 +55,8 @@ def name: String def poke: Unit def →[B](y: B): (Ping, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean diff --git a/test/files/presentation/scope-completion-3.check b/test/files/presentation/scope-completion-3.check index df3007ab4e..b70a7d5c6b 100644 --- a/test/files/presentation/scope-completion-3.check +++ b/test/files/presentation/scope-completion-3.check @@ -3,19 +3,7 @@ reload: Completions.scala askScopeCompletion at Completions.scala(75,2) ================================================================================ [response] askScopeCompletion at (75,2) -retrieved 49 members -[inaccessible] private class Cb2 extends AnyRef -[inaccessible] private class Ct2 extends AnyRef -[inaccessible] private def fb2: Int -[inaccessible] private def ft2: Int -[inaccessible] private object Ob2 -[inaccessible] private object Ot2 -[inaccessible] private type tb2 = Completion1.this.tb2 -[inaccessible] private type tt2 = Completion1.this.tt2 -[inaccessible] private[this] val vb2: Int -[inaccessible] private[this] val vt2: Int -[inaccessible] private[this] var rb2: Int -[inaccessible] private[this] var rt2: Int +retrieved 37 members abstract class Base1 extends AnyRef abstract trait Trait1 extends AnyRef class Cb1 extends AnyRef @@ -58,19 +46,7 @@ type tt1 = Completion1.this.tt1 askScopeCompletion at Completions.scala(104,2) ================================================================================ [response] askScopeCompletion at (104,2) -retrieved 49 members -[inaccessible] private class Cb2 extends AnyRef -[inaccessible] private class Ct2 extends AnyRef -[inaccessible] private def fb2: Int -[inaccessible] private def ft2: Int -[inaccessible] private object Ob2 -[inaccessible] private object Ot2 -[inaccessible] private type tb2 = test.Completion2.tb2 -[inaccessible] private type tt2 = test.Completion2.tt2 -[inaccessible] private[this] val vb2: Int -[inaccessible] private[this] val vt2: Int -[inaccessible] private[this] var rb2: Int -[inaccessible] private[this] var rt2: Int +retrieved 37 members abstract class Base1 extends AnyRef abstract trait Trait1 extends AnyRef class Cb1 extends AnyRef diff --git a/test/files/presentation/scope-completion-import.check b/test/files/presentation/scope-completion-import.check index 220ffc399b..50197e5822 100644 --- a/test/files/presentation/scope-completion-import.check +++ b/test/files/presentation/scope-completion-import.check @@ -3,10 +3,8 @@ reload: Completions.scala askScopeCompletion at Completions.scala(23,4) ================================================================================ [response] askScopeCompletion at (23,4) -retrieved 18 members -[inaccessible] private[this] val pVCCC: Int +retrieved 16 members [inaccessible] private[this] val pVOOO: Int -[inaccessible] private[this] var pRCCC: Int [inaccessible] private[this] var pROOO: Int class C extends AnyRef class Foo extends AnyRef @@ -27,10 +25,8 @@ val o: test.O.type askScopeCompletion at Completions.scala(27,4) ================================================================================ [response] askScopeCompletion at (27,4) -retrieved 17 members -[inaccessible] private[this] val pVCCC: Int +retrieved 15 members [inaccessible] private[this] val pVOOO: Int -[inaccessible] private[this] var pRCCC: Int [inaccessible] private[this] var pROOO: Int class C extends AnyRef class Foo extends AnyRef @@ -126,10 +122,8 @@ val c: test.C askScopeCompletion at Completions.scala(49,4) ================================================================================ [response] askScopeCompletion at (49,4) -retrieved 18 members -[inaccessible] private[this] val pVCCC: Int +retrieved 16 members [inaccessible] private[this] val pVOOO: Int -[inaccessible] private[this] var pRCCC: Int [inaccessible] private[this] var pROOO: Int class C extends AnyRef class Foo extends AnyRef @@ -150,10 +144,8 @@ private[this] var rOOO: Int askScopeCompletion at Completions.scala(59,4) ================================================================================ [response] askScopeCompletion at (59,4) -retrieved 19 members -[inaccessible] private[this] val pVCCC: Int +retrieved 17 members [inaccessible] private[this] val pVOOO: Int -[inaccessible] private[this] var pRCCC: Int [inaccessible] private[this] var pROOO: Int class C extends AnyRef class Foo extends AnyRef diff --git a/test/files/presentation/t5708.check b/test/files/presentation/t5708.check index 04806b5867..4b33893e98 100644 --- a/test/files/presentation/t5708.check +++ b/test/files/presentation/t5708.check @@ -3,7 +3,7 @@ reload: Completions.scala askTypeCompletion at Completions.scala(17,9) ================================================================================ [response] askTypeCompletion at (17,9) -retrieved 39 members +retrieved 37 members [inaccessible] private def privateM: String [inaccessible] private[this] val privateV: String [inaccessible] private[this] val protectedV: String @@ -22,10 +22,8 @@ def hashCode(): Int def toString(): String def →[B](y: B): (test.Compat.type, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean diff --git a/test/files/presentation/t8085.check b/test/files/presentation/t8085.check new file mode 100644 index 0000000000..921ca7528b --- /dev/null +++ b/test/files/presentation/t8085.check @@ -0,0 +1,3 @@ +reload: NodeScalaSuite.scala +open package module: package object nodescala +Test OK diff --git a/test/files/presentation/t8085.flags b/test/files/presentation/t8085.flags new file mode 100644 index 0000000000..ec35b223d8 --- /dev/null +++ b/test/files/presentation/t8085.flags @@ -0,0 +1 @@ +-sourcepath src diff --git a/test/files/presentation/t8085/Test.scala b/test/files/presentation/t8085/Test.scala new file mode 100644 index 0000000000..e46b7ab8c8 --- /dev/null +++ b/test/files/presentation/t8085/Test.scala @@ -0,0 +1,27 @@ +import scala.tools.nsc.interactive.tests.InteractiveTest +import scala.reflect.internal.util.SourceFile +import scala.tools.nsc.interactive.Response + +object Test extends InteractiveTest { + + override def execute(): Unit = { + val src = loadSourceAndWaitUntilTypechecked("NodeScalaSuite.scala") + checkErrors(src) + } + + private def loadSourceAndWaitUntilTypechecked(sourceName: String): SourceFile = { + val sourceFile = sourceFiles.find(_.file.name == sourceName).head + askReload(List(sourceFile)).get + askLoadedTyped(sourceFile).get + sourceFile + } + + private def checkErrors(source: SourceFile): Unit = compiler.getUnitOf(source) match { + case Some(unit) => + val problems = unit.problems.toList + if(problems.isEmpty) reporter.println("Test OK") + else problems.foreach(problem => reporter.println(problem.msg)) + + case None => reporter.println("No compilation unit found for " + source.file.name) + } +} diff --git a/test/files/presentation/t8085/src/nodescala/Foo.scala b/test/files/presentation/t8085/src/nodescala/Foo.scala new file mode 100644 index 0000000000..19efdb65dd --- /dev/null +++ b/test/files/presentation/t8085/src/nodescala/Foo.scala @@ -0,0 +1,3 @@ +package nodescala + +class Foo diff --git a/test/files/presentation/t8085/src/nodescala/NodeScalaSuite.scala b/test/files/presentation/t8085/src/nodescala/NodeScalaSuite.scala new file mode 100644 index 0000000000..45e43c7afb --- /dev/null +++ b/test/files/presentation/t8085/src/nodescala/NodeScalaSuite.scala @@ -0,0 +1,10 @@ +package nodescala + +class NodeScalaSuite { + "".rich + + // This is here only to prove that the presentation compiler is instantiated with the + // correct `sourcepath` value (if it wasn't, you would see a `not found: type Foo` in + // the test's output + println(new Foo()) +} diff --git a/test/files/presentation/t8085/src/nodescala/package.scala b/test/files/presentation/t8085/src/nodescala/package.scala new file mode 100644 index 0000000000..26fb9f08e4 --- /dev/null +++ b/test/files/presentation/t8085/src/nodescala/package.scala @@ -0,0 +1,7 @@ +import scala.Some // <-- if you move the import *inside* the package object, then it all works fine!! + +package object nodescala { + implicit class StringOps(val f: String) { + def rich = 0 + } +} diff --git a/test/files/presentation/t8085b.check b/test/files/presentation/t8085b.check new file mode 100644 index 0000000000..921ca7528b --- /dev/null +++ b/test/files/presentation/t8085b.check @@ -0,0 +1,3 @@ +reload: NodeScalaSuite.scala +open package module: package object nodescala +Test OK diff --git a/test/files/presentation/t8085b.flags b/test/files/presentation/t8085b.flags new file mode 100644 index 0000000000..ec35b223d8 --- /dev/null +++ b/test/files/presentation/t8085b.flags @@ -0,0 +1 @@ +-sourcepath src diff --git a/test/files/presentation/t8085b/Test.scala b/test/files/presentation/t8085b/Test.scala new file mode 100644 index 0000000000..e46b7ab8c8 --- /dev/null +++ b/test/files/presentation/t8085b/Test.scala @@ -0,0 +1,27 @@ +import scala.tools.nsc.interactive.tests.InteractiveTest +import scala.reflect.internal.util.SourceFile +import scala.tools.nsc.interactive.Response + +object Test extends InteractiveTest { + + override def execute(): Unit = { + val src = loadSourceAndWaitUntilTypechecked("NodeScalaSuite.scala") + checkErrors(src) + } + + private def loadSourceAndWaitUntilTypechecked(sourceName: String): SourceFile = { + val sourceFile = sourceFiles.find(_.file.name == sourceName).head + askReload(List(sourceFile)).get + askLoadedTyped(sourceFile).get + sourceFile + } + + private def checkErrors(source: SourceFile): Unit = compiler.getUnitOf(source) match { + case Some(unit) => + val problems = unit.problems.toList + if(problems.isEmpty) reporter.println("Test OK") + else problems.foreach(problem => reporter.println(problem.msg)) + + case None => reporter.println("No compilation unit found for " + source.file.name) + } +} diff --git a/test/files/presentation/t8085b/src/p1/nodescala/Foo.scala b/test/files/presentation/t8085b/src/p1/nodescala/Foo.scala new file mode 100644 index 0000000000..8ed1ada6b6 --- /dev/null +++ b/test/files/presentation/t8085b/src/p1/nodescala/Foo.scala @@ -0,0 +1,4 @@ +package p1 +package nodescala + +class Foo diff --git a/test/files/presentation/t8085b/src/p1/nodescala/NodeScalaSuite.scala b/test/files/presentation/t8085b/src/p1/nodescala/NodeScalaSuite.scala new file mode 100644 index 0000000000..f6da67bdc7 --- /dev/null +++ b/test/files/presentation/t8085b/src/p1/nodescala/NodeScalaSuite.scala @@ -0,0 +1,11 @@ +package p1 +package nodescala + +class NodeScalaSuite { + "".rich + + // This is here only to prove that the presentation compiler is instantiated with the + // correct `sourcepath` value (if it wasn't, you would see a `not found: type Foo` in + // the test's output + println(new Foo()) +} diff --git a/test/files/presentation/t8085b/src/p1/nodescala/package.scala b/test/files/presentation/t8085b/src/p1/nodescala/package.scala new file mode 100644 index 0000000000..cc383f1bab --- /dev/null +++ b/test/files/presentation/t8085b/src/p1/nodescala/package.scala @@ -0,0 +1,9 @@ +import scala.Some // <-- if you move the import *inside* the package object, then it all works fine!! + +package p1 { + package object nodescala { + implicit class StringOps(val f: String) { + def rich = 0 + } + } +} diff --git a/test/files/presentation/visibility.check b/test/files/presentation/visibility.check index 217da34b9c..b77887f8f7 100644 --- a/test/files/presentation/visibility.check +++ b/test/files/presentation/visibility.check @@ -3,7 +3,7 @@ reload: Completions.scala askTypeCompletion at Completions.scala(14,12) ================================================================================ [response] askTypeCompletion at (14,12) -retrieved 37 members +retrieved 35 members [inaccessible] private[this] def secretPrivateThis(): Unit def +(other: String): String def ->[B](y: B): (accessibility.Foo, B) @@ -19,10 +19,8 @@ def someTests(other: accessibility.Foo): Unit def toString(): String def →[B](y: B): (accessibility.Foo, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean @@ -43,7 +41,7 @@ protected[package lang] def finalize(): Unit askTypeCompletion at Completions.scala(16,11) ================================================================================ [response] askTypeCompletion at (16,11) -retrieved 37 members +retrieved 35 members def +(other: String): String def ->[B](y: B): (accessibility.Foo, B) def ensuring(cond: Boolean): accessibility.Foo @@ -58,10 +56,8 @@ def someTests(other: accessibility.Foo): Unit def toString(): String def →[B](y: B): (accessibility.Foo, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean @@ -83,8 +79,7 @@ protected[package lang] def finalize(): Unit askTypeCompletion at Completions.scala(22,11) ================================================================================ [response] askTypeCompletion at (22,11) -retrieved 37 members -[inaccessible] private def secretPrivate(): Unit +retrieved 34 members def +(other: String): String def ->[B](y: B): (accessibility.AccessibilityChecks, B) def ensuring(cond: Boolean): accessibility.AccessibilityChecks @@ -100,10 +95,8 @@ def someTests: Unit def toString(): String def →[B](y: B): (accessibility.AccessibilityChecks, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean @@ -123,7 +116,7 @@ protected[package lang] def finalize(): Unit askTypeCompletion at Completions.scala(28,10) ================================================================================ [response] askTypeCompletion at (28,10) -retrieved 37 members +retrieved 35 members [inaccessible] private def secretPrivate(): Unit [inaccessible] private[this] def secretPrivateThis(): Unit [inaccessible] protected def secretProtected(): Unit @@ -143,10 +136,8 @@ def someTests(other: accessibility.Foo): Unit def toString(): String def →[B](y: B): (accessibility.Foo, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean @@ -163,7 +154,7 @@ protected[package accessibility] def secretProtectedInPackage(): Unit askTypeCompletion at Completions.scala(37,8) ================================================================================ [response] askTypeCompletion at (37,8) -retrieved 37 members +retrieved 35 members [inaccessible] private def secretPrivate(): Unit [inaccessible] private[this] def secretPrivateThis(): Unit [inaccessible] protected def secretProtected(): Unit @@ -184,10 +175,8 @@ def someTests(other: accessibility.Foo): Unit def toString(): String def →[B](y: B): (accessibility.Foo, B) final def !=(x$1: Any): Boolean -final def !=(x$1: AnyRef): Boolean final def ##(): Int final def ==(x$1: Any): Boolean -final def ==(x$1: AnyRef): Boolean final def asInstanceOf[T0]: T0 final def eq(x$1: AnyRef): Boolean final def isInstanceOf[T0]: Boolean diff --git a/test/files/run/Predef.readLine.scala b/test/files/run/Predef.readLine.scala index 54809f8071..ce8565864a 100644 --- a/test/files/run/Predef.readLine.scala +++ b/test/files/run/Predef.readLine.scala @@ -1,5 +1,5 @@ import java.io.StringReader -import scala.io.ReadStdin.readLine +import scala.io.StdIn.readLine object Test extends App { Console.withIn(new StringReader("")) { diff --git a/test/files/run/bigDecimalTest.check b/test/files/run/bigDecimalTest.check index 6d11c23fcd..36db6aaafe 100644 --- a/test/files/run/bigDecimalTest.check +++ b/test/files/run/bigDecimalTest.check @@ -3,4 +3,4 @@ 0 0 0 -14 +15 diff --git a/test/files/run/constrained-types.check b/test/files/run/constrained-types.check index d965d8a2ff..9a106785a1 100644 --- a/test/files/run/constrained-types.check +++ b/test/files/run/constrained-types.check @@ -149,13 +149,3 @@ scala> val x = 3 : Int @Annot(e+f+g+h) // should have a graceful error message ^ scala> - -scala> class Where(condition: Boolean) extends annotation.Annotation -defined class Where - -scala> - -scala> val x : Int @Where(self > 0 && self < 100) = 3 -x: Int @Where(self.>(0).&&(self.<(100))) = 3 - -scala> diff --git a/test/files/run/constrained-types.scala b/test/files/run/constrained-types.scala index 91bd856d00..7ec8f93d38 100644 --- a/test/files/run/constrained-types.scala +++ b/test/files/run/constrained-types.scala @@ -72,16 +72,10 @@ object A { val x = "hello" : String @ rep } val y = a.x // should drop the annotation val x = 3 : Int @Annot(e+f+g+h) // should have a graceful error message - -class Where(condition: Boolean) extends annotation.Annotation - -val x : Int @Where(self > 0 && self < 100) = 3 - """ override def transformSettings(s: Settings): Settings = { s.Xexperimental.value = true - s.selfInAnnots.value = true s.deprecation.value = true // when running that compiler, give it a scala-library to the classpath s.classpath.value = sys.props("java.class.path") diff --git a/test/files/run/global-showdef.scala b/test/files/run/global-showdef.scala index c3ace590ed..1d4891fd1f 100644 --- a/test/files/run/global-showdef.scala +++ b/test/files/run/global-showdef.scala @@ -54,7 +54,7 @@ object Bippy { val run = new compiler.Run() run.compileSources(List(src)) } - output.linesIterator.toList + output.lines.toList } def showClass(name: String) = lines("-Yshow:typer", "-Xshow-class", name) def showObject(name: String) = lines("-Yshow:typer", "-Xshow-object", name) diff --git a/test/files/run/idempotency-case-classes.scala b/test/files/run/idempotency-case-classes.scala index 81e119582b..4ad132174d 100644 --- a/test/files/run/idempotency-case-classes.scala +++ b/test/files/run/idempotency-case-classes.scala @@ -12,7 +12,7 @@ object Test extends App { val tb = cm.mkToolBox() val tcasee = tb.typecheck(casee.tree) println(tcasee) - val rtcasee = tb.resetAllAttrs(tcasee) + val rtcasee = tb.untypecheck(tcasee) try { println(tb.eval(rtcasee)) } catch { diff --git a/test/files/run/idempotency-extractors.scala b/test/files/run/idempotency-extractors.scala index b66b043be1..8c0a0b1106 100644 --- a/test/files/run/idempotency-extractors.scala +++ b/test/files/run/idempotency-extractors.scala @@ -12,7 +12,7 @@ object Test extends App { val tb = cm.mkToolBox() val textractor = tb.typecheck(extractor.tree) println(textractor) - val rtextractor = tb.resetAllAttrs(textractor) + val rtextractor = tb.untypecheck(textractor) try { println(tb.eval(rtextractor)) } catch { diff --git a/test/files/run/idempotency-labels.scala b/test/files/run/idempotency-labels.scala index f1a185d3d0..084c93d3c6 100644 --- a/test/files/run/idempotency-labels.scala +++ b/test/files/run/idempotency-labels.scala @@ -13,7 +13,7 @@ object Test extends App { val tb = cm.mkToolBox() val tlabel = tb.typecheck(label.tree) println(tlabel) - val rtlabel = tb.resetAllAttrs(tlabel) + val rtlabel = tb.untypecheck(tlabel) try { println(tb.eval(rtlabel)) } catch { diff --git a/test/files/run/idempotency-lazy-vals.scala b/test/files/run/idempotency-lazy-vals.scala index e763f2f3f4..9d677caeca 100644 --- a/test/files/run/idempotency-lazy-vals.scala +++ b/test/files/run/idempotency-lazy-vals.scala @@ -17,7 +17,7 @@ object Test extends App { val tb = cm.mkToolBox() val tlazee = tb.typecheck(lazee.tree) println(tlazee) - val rtlazee = tb.resetAllAttrs(tlazee) + val rtlazee = tb.untypecheck(tlazee) try { println(tb.eval(rtlazee)) } catch { diff --git a/test/files/run/idempotency-this.scala b/test/files/run/idempotency-this.scala index 2db1efd2d1..26917ab743 100644 --- a/test/files/run/idempotency-this.scala +++ b/test/files/run/idempotency-this.scala @@ -12,7 +12,7 @@ object Test extends App { val tthiss = tb.typecheck(thiss.tree) println(tthiss) println(showRaw(tthiss)) - val rtthiss = tb.resetAllAttrs(tthiss) + val rtthiss = tb.untypecheck(tthiss) try { println(tb.eval(rtthiss)) } catch { diff --git a/test/files/run/inferred-type-constructors.check b/test/files/run/inferred-type-constructors.check new file mode 100644 index 0000000000..5992ef02ad --- /dev/null +++ b/test/files/run/inferred-type-constructors.check @@ -0,0 +1,56 @@ +warning: there were 2 feature warning(s); re-run with -feature for details + p.Iterable[Int] + p.Set[Int] + p.Seq[Int] + p.m.Set[Int] + p.m.Seq[Int] + private[m] p.m.ASet[Int] + p.i.Seq[Int] + private[i] p.i.ASet[Int] + private[i] p.i.ASeq[Int] + p.Iterable[Int] + p.Iterable[Int] + p.Iterable[Int] + p.Iterable[Int] + p.Iterable[Int] + p.Iterable[Int] + p.Iterable[Int] + p.Iterable[Int] + p.Iterable[Int] + p.Set[Int] + p.Iterable[Int] + p.Set[Int] + p.Iterable[Int] + p.Set[Int] + p.Iterable[Int] + p.Iterable[Int] + p.Seq[Int] + p.Iterable[Int] + p.Seq[Int] + p.Iterable[Int] + p.Seq[Int] + p.Iterable[Int] + p.m.Set[Int] + p.Iterable[Int] + p.Set[Int] + p.Iterable[Int] + p.Iterable[Int] + p.Seq[Int] + p.Iterable[Int] + p.Seq[Int] + p.Iterable[Int] + private[p] p.ASet[Int] + private[p] p.AIterable[Int] + p.Iterable[Int] + p.i.Seq[Int] + private[p] p.AIterable[Int] + List[Nothing] + scala.collection.immutable.Vector[Nothing] + scala.collection.immutable.Iterable[(Int, Int)] + scala.collection.immutable.Set[Int] + Seq[Int] + Array[Int] + scala.collection.AbstractSet[Int] + Comparable[java.lang.String] + scala.collection.immutable.LinearSeq[Int] + Iterable[Int] diff --git a/test/files/run/inferred-type-constructors.scala b/test/files/run/inferred-type-constructors.scala new file mode 100644 index 0000000000..79a8653f68 --- /dev/null +++ b/test/files/run/inferred-type-constructors.scala @@ -0,0 +1,125 @@ +package p { + trait TCon[+CC[X]] { + def fPublic: CC[Int] = ??? + private[p] def fPackagePrivate: CC[Int] = ??? + protected[p] def fPackageProtected: CC[Int] = ??? + } + trait Iterable[+A] extends TCon[Iterable] + trait Set[A] extends Iterable[A] with TCon[Set] + trait Seq[+A] extends Iterable[A] with TCon[Seq] + + private[p] abstract class AIterable[+A] extends Iterable[A] + private[p] abstract class ASeq[+A] extends AIterable[A] with Seq[A] + private[p] abstract class ASet[A] extends AIterable[A] with Set[A] + + package m { + private[m] abstract class ASeq[A] extends p.ASeq[A] with Seq[A] + private[m] abstract class ASet[A] extends p.ASet[A] with Set[A] + trait Set[A] extends p.Set[A] with TCon[Set] + trait Seq[A] extends p.Seq[A] with TCon[Seq] + trait BitSet extends ASet[Int] + trait IntSeq extends ASeq[Int] + } + + package i { + private[i] abstract class ASeq[+A] extends p.ASeq[A] with Seq[A] + private[i] abstract class ASet[A] extends p.ASet[A] with Set[A] + trait Set[A] extends p.Set[A] with TCon[Set] + trait Seq[+A] extends p.Seq[A] with TCon[Seq] + trait BitSet extends ASet[Int] + trait IntSeq extends ASeq[Int] + } +} + +object Test { + import scala.reflect.runtime.universe._ + // Complicated by the absence of usable type constructor type tags. + def extract[A, CC[X]](xs: CC[A]): CC[A] = xs + def whatis[T: TypeTag](x: T): Unit = { + val tpe = typeOf[T] + val access = tpe.typeSymbol.asInstanceOf[scala.reflect.internal.HasFlags].accessString.replaceAllLiterally("package ", "") + println(f"$access%15s $tpe") + } + + trait IntIterable extends p.Iterable[Int] + trait IntSet extends p.Set[Int] + trait IntSeq extends p.Seq[Int] + + trait MutableIntSet extends p.m.Set[Int] + trait MutableIntSeq extends p.m.Seq[Int] + + trait ImmutableIntSet extends p.i.Set[Int] + trait ImmutableIntSeq extends p.i.Seq[Int] + + def f1: IntIterable = null + def f2: IntSet = null + def f3: IntSeq = null + + def g1: MutableIntSet = null + def g2: MutableIntSeq = null + def g3: p.m.BitSet = null + + def h1: ImmutableIntSeq = null + def h2: p.i.BitSet = null + def h3: p.i.IntSeq = null + + def main(args: Array[String]): Unit = { + whatis(extract(f1)) + whatis(extract(f2)) + whatis(extract(f3)) + whatis(extract(g1)) + whatis(extract(g2)) + whatis(extract(g3)) + whatis(extract(h1)) + whatis(extract(h2)) + whatis(extract(h3)) + + whatis(extract(if (true) f1 else f2)) + whatis(extract(if (true) f1 else f3)) + whatis(extract(if (true) f1 else g1)) + whatis(extract(if (true) f1 else g2)) + whatis(extract(if (true) f1 else g3)) + whatis(extract(if (true) f1 else h1)) + whatis(extract(if (true) f1 else h2)) + whatis(extract(if (true) f1 else h3)) + whatis(extract(if (true) f2 else f3)) + whatis(extract(if (true) f2 else g1)) + whatis(extract(if (true) f2 else g2)) + whatis(extract(if (true) f2 else g3)) + whatis(extract(if (true) f2 else h1)) + whatis(extract(if (true) f2 else h2)) + whatis(extract(if (true) f2 else h3)) + whatis(extract(if (true) f3 else g1)) + whatis(extract(if (true) f3 else g2)) + whatis(extract(if (true) f3 else g3)) + whatis(extract(if (true) f3 else h1)) + whatis(extract(if (true) f3 else h2)) + whatis(extract(if (true) f3 else h3)) + whatis(extract(if (true) g1 else g2)) + whatis(extract(if (true) g1 else g3)) + whatis(extract(if (true) g1 else h1)) + whatis(extract(if (true) g1 else h2)) + whatis(extract(if (true) g1 else h3)) + whatis(extract(if (true) g2 else g3)) + whatis(extract(if (true) g2 else h1)) + whatis(extract(if (true) g2 else h2)) + whatis(extract(if (true) g2 else h3)) + whatis(extract(if (true) g3 else h1)) + whatis(extract(if (true) g3 else h2)) + whatis(extract(if (true) g3 else h3)) + whatis(extract(if (true) h1 else h2)) + whatis(extract(if (true) h1 else h3)) + whatis(extract(if (true) h2 else h3)) + + whatis(extract(Nil)) + whatis(extract(Vector())) + whatis(extract(Map[Int,Int]())) + whatis(extract(Set[Int]())) + whatis(extract(Seq[Int]())) + whatis(extract(Array[Int]())) + whatis(extract(scala.collection.immutable.BitSet(1))) + whatis(extract("abc")) + whatis(extract(if (true) Stream(1) else List(1))) + whatis(extract(if (true) Seq(1) else Set(1))) + } +} diff --git a/test/files/run/is-valid-num.scala b/test/files/run/is-valid-num.scala index d314015dd4..65e8ceeca6 100644 --- a/test/files/run/is-valid-num.scala +++ b/test/files/run/is-valid-num.scala @@ -19,25 +19,27 @@ object Test { assert(!x.isValidChar, x) assert(!x.isValidShort, x) assert(!x.isValidByte, x) -// assert(y.isWhole, y) + assert(y.isWhole, y) assert(!y.isValidShort, y) assert(y.isValidChar, y) assert(y.isValidInt, y) - assert(y.isValidFloat, y) - assert(y.isValidDouble, y) + assert(y.isDecimalFloat, y) + assert(y.isDecimalDouble, y) assert(y.isValidLong, y) assert(!y.isValidByte, y) -// assert(!y1.isWhole) + assert(!y1.isWhole) assert(!y1.isValidLong, y1) - assert(!y1.isValidFloat, y1) - assert(!y1.isValidDouble, y1) + assert(y1.isDecimalFloat, y1) + assert(y1.isDecimalDouble, y1) + assert(!y1.isExactFloat, y1) + assert(!y1.isExactDouble, y1) assert(!y1.isValidInt, y1) assert(!y1.isValidChar, y1) assert(!y1.isValidShort, y1) assert(!y1.isValidByte, y1) assert(!y2.isValidLong, y2) - assert(y2.isValidFloat, y2) - assert(y2.isValidDouble, y2) + assert(y2.isExactFloat, y2) + assert(y2.isExactDouble, y2) assert(!l1.isValidInt && (l1 - 1).isValidInt, l1) assert(!l2.isValidInt && (l2 + 1).isValidInt, l2) @@ -170,8 +172,8 @@ object Test { if (!d.isInfinity) { val bd = BigDecimal(new java.math.BigDecimal(d)) // assert(!bd.isWhole, bd) - assert(bd.isValidDouble, bd) - assert(bd.isValidFloat == isFloat, bd) + assert(bd.isExactDouble, bd) + assert(bd.isExactFloat == isFloat, bd) assert(!bd.isValidLong, bd) assert(!bd.isValidInt, bd) assert(!bd.isValidChar, bd) @@ -210,9 +212,9 @@ object Test { val isFloat = !bi.toFloat.isInfinity && bd.compare(BigDecimal(new java.math.BigDecimal(bi.toFloat))) == 0 val isDouble = !bi.toDouble.isInfinity && bd.compare(BigDecimal(new java.math.BigDecimal(bi.toDouble))) == 0 -// assert(bd.isWhole, bd) - assert(bd.isValidDouble == isDouble, bd) - assert(bd.isValidFloat == isFloat, bd) + assert(bd.isWhole, bd) + assert(bd.isBinaryDouble == isDouble, bd) + assert(bd.isBinaryFloat == isFloat, bd) assert(bd.isValidLong == isLong, bd) assert(bd.isValidInt == isInt, bd) assert(bd.isValidChar == isChar, bd) diff --git a/test/files/run/large_code.check b/test/files/run/large_code.check new file mode 100644 index 0000000000..6ad50967bc --- /dev/null +++ b/test/files/run/large_code.check @@ -0,0 +1,3 @@ +newSource1.scala:1: error: Could not write class BigEnoughToFail because it exceeds JVM code size limits. Method tooLong's code too large! +class BigEnoughToFail { + ^ diff --git a/test/files/run/large_code.scala b/test/files/run/large_code.scala new file mode 100644 index 0000000000..f9d7f8c95b --- /dev/null +++ b/test/files/run/large_code.scala @@ -0,0 +1,24 @@ +import scala.tools.partest._ +import java.io.{Console => _, _} + +// a cold run of partest takes about 15s for this test on my laptop +object Test extends DirectTest { + override def extraSettings: String = "-usejavacp -d " + testOutput.path + + // test that we hit the code size limit and error out gracefully + // 5958 is the magic number (2^16/11 -- each `a(1,2,3,4,5,6)` is 11 bytes of bytecode) + override def code + = s""" + |class BigEnoughToFail { + | def a(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int): Unit = {} + | def tooLong: Unit = { + | ${(1 to 5958) map (_ => "a(1,2,3,4,5,6)") mkString(";")} + | } + |}""".stripMargin.trim + + override def show(): Unit = { + Console.withErr(System.out) { + compile() + } + } +} diff --git a/test/files/run/macro-abort-fresh.check b/test/files/run/macro-abort-fresh.check index 9fddee57d4..5064b96eef 100644 --- a/test/files/run/macro-abort-fresh.check +++ b/test/files/run/macro-abort-fresh.check @@ -1,6 +1,6 @@ -fresh$1 -qwe1 -qwe2 +fresh$macro$1 +qwe$macro$2 +qwe$macro$3 reflective compilation has failed: blargh diff --git a/test/files/run/macro-abort-fresh/Macros_1.scala b/test/files/run/macro-abort-fresh/Macros_1.scala index 350d7b41aa..2b03512efb 100644 --- a/test/files/run/macro-abort-fresh/Macros_1.scala +++ b/test/files/run/macro-abort-fresh/Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Impls { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ println(c.fresh()) println(c.fresh("qwe")) diff --git a/test/files/run/macro-auto-duplicate/Macros_1.scala b/test/files/run/macro-auto-duplicate/Macros_1.scala index 255dafd47e..2c910e6af7 100644 --- a/test/files/run/macro-auto-duplicate/Macros_1.scala +++ b/test/files/run/macro-auto-duplicate/Macros_1.scala @@ -1,8 +1,8 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ val x = Ident(newTermName("x")) def defAndUseX(rhs: Tree) = { diff --git a/test/files/run/macro-basic-ma-md-mi/Impls_1.scala b/test/files/run/macro-basic-ma-md-mi/Impls_1.scala index c63353164e..fc75b99ef2 100644 --- a/test/files/run/macro-basic-ma-md-mi/Impls_1.scala +++ b/test/files/run/macro-basic-ma-md-mi/Impls_1.scala @@ -1,19 +1,19 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def foo(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(1)))) c.Expr[Int](body) } - def bar(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def bar(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(2)))) c.Expr[Int](body) } - def quux(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def quux(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(3)))) c.Expr[Int](body) diff --git a/test/files/run/macro-basic-ma-mdmi/Impls_Macros_1.scala b/test/files/run/macro-basic-ma-mdmi/Impls_Macros_1.scala index 3cdd531316..73a5a971a4 100644 --- a/test/files/run/macro-basic-ma-mdmi/Impls_Macros_1.scala +++ b/test/files/run/macro-basic-ma-mdmi/Impls_Macros_1.scala @@ -1,19 +1,19 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def foo(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(1)))) c.Expr[Int](body) } - def bar(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def bar(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(2)))) c.Expr[Int](body) } - def quux(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def quux(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(3)))) c.Expr[Int](body) diff --git a/test/files/run/macro-basic-mamd-mi/Impls_1.scala b/test/files/run/macro-basic-mamd-mi/Impls_1.scala index 3feddd2786..0be915c119 100644 --- a/test/files/run/macro-basic-mamd-mi/Impls_1.scala +++ b/test/files/run/macro-basic-mamd-mi/Impls_1.scala @@ -1,17 +1,17 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def foo(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ c.Expr(Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(1))))) } - def bar(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def bar(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ c.Expr(Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(2))))) } - def quux(c: Ctx)(x: c.Expr[Int]): c.Expr[Int] = { + def quux(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(3)))) c.Expr[Int](body) diff --git a/test/files/run/macro-blackbox-materialization/Macros_1.scala b/test/files/run/macro-blackbox-materialization/Macros_1.scala index 7c31dd7dc2..ea8d1bed14 100644 --- a/test/files/run/macro-blackbox-materialization/Macros_1.scala +++ b/test/files/run/macro-blackbox-materialization/Macros_1.scala @@ -1,6 +1,6 @@ // For the full version of the test, take a look at run/t5923a -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros case class C[T](t: String) @@ -9,7 +9,7 @@ object C { } object Macros { - def impl[T: c.WeakTypeTag](c: BlackboxContext) = { + def impl[T: c.WeakTypeTag](c: Context) = { import c.universe._ reify(C[T](c.literal(weakTypeOf[T].toString).splice)) } diff --git a/test/files/run/macro-bodyexpandstoimpl/Impls_1.scala b/test/files/run/macro-bodyexpandstoimpl/Impls_1.scala index 8506239952..d46af4952d 100644 --- a/test/files/run/macro-bodyexpandstoimpl/Impls_1.scala +++ b/test/files/run/macro-bodyexpandstoimpl/Impls_1.scala @@ -1,5 +1,6 @@ import scala.language.experimental.macros -import scala.reflect.macros.{BlackboxContext, WhiteboxContext} +import scala.reflect.macros.blackbox.{Context => BlackboxContext} +import scala.reflect.macros.whitebox.{Context => WhiteboxContext} object Impls { def foo(c: BlackboxContext)(x: c.Expr[Int]) = x diff --git a/test/files/run/macro-bundle-repl.check b/test/files/run/macro-bundle-repl.check index 8487042d66..4a0b421606 100644 --- a/test/files/run/macro-bundle-repl.check +++ b/test/files/run/macro-bundle-repl.check @@ -4,17 +4,17 @@ Type :help for more information. scala> import scala.language.experimental.macros import scala.language.experimental.macros -scala> import scala.reflect.macros.BlackboxMacro -import scala.reflect.macros.BlackboxMacro +scala> import scala.reflect.macros.blackbox.Context +import scala.reflect.macros.blackbox.Context -scala> trait Bar extends BlackboxMacro { def impl = { import c.universe._; c.Expr[Unit](q"()") } };def bar: Unit = macro Bar.impl -defined trait Bar +scala> class Bar(val c: Context) { def impl = { import c.universe._; c.Expr[Unit](q"()") } };def bar: Unit = macro Bar.impl +defined class Bar defined term macro bar: Unit scala> bar -scala> trait Foo extends BlackboxMacro { def impl = { import c.universe._; c.Expr[Unit](q"()") } } -defined trait Foo +scala> class Foo(val c: Context) { def impl = { import c.universe._; c.Expr[Unit](q"()") } } +defined class Foo scala> def foo: Unit = macro Foo.impl defined term macro foo: Unit diff --git a/test/files/run/macro-bundle-repl.scala b/test/files/run/macro-bundle-repl.scala index db64f05943..8084418454 100644 --- a/test/files/run/macro-bundle-repl.scala +++ b/test/files/run/macro-bundle-repl.scala @@ -3,10 +3,10 @@ import scala.tools.partest.ReplTest object Test extends ReplTest { def code = """ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxMacro -trait Bar extends BlackboxMacro { def impl = { import c.universe._; c.Expr[Unit](q"()") } };def bar: Unit = macro Bar.impl +import scala.reflect.macros.blackbox.Context +class Bar(val c: Context) { def impl = { import c.universe._; c.Expr[Unit](q"()") } };def bar: Unit = macro Bar.impl bar -trait Foo extends BlackboxMacro { def impl = { import c.universe._; c.Expr[Unit](q"()") } } +class Foo(val c: Context) { def impl = { import c.universe._; c.Expr[Unit](q"()") } } def foo: Unit = macro Foo.impl foo """ diff --git a/test/files/run/macro-bundle-static/Impls_Macros_1.scala b/test/files/run/macro-bundle-static/Impls_Macros_1.scala index b859411325..0142e5d945 100644 --- a/test/files/run/macro-bundle-static/Impls_Macros_1.scala +++ b/test/files/run/macro-bundle-static/Impls_Macros_1.scala @@ -1,8 +1,8 @@ -import scala.reflect.macros.BlackboxMacro +import scala.reflect.macros.blackbox.Context import scala.language.experimental.macros object Enclosing { - trait Impl extends BlackboxMacro { + class Impl(val c: Context) { def mono = { import c.universe._; c.Expr[Unit](q"()") } def poly[T: c.WeakTypeTag] = { import c.universe._; c.Expr[String](q"${c.weakTypeOf[T].toString}") } def weird = macro mono @@ -16,7 +16,7 @@ object Macros { package pkg { object Enclosing { - trait Impl extends BlackboxMacro { + class Impl(val c: Context) { def mono = { import c.universe._; c.Expr[Boolean](q"true") } def poly[T: c.WeakTypeTag] = { import c.universe._; c.Expr[String](q"${c.weakTypeOf[T].toString + c.weakTypeOf[T].toString}") } def weird = macro mono diff --git a/test/files/run/macro-bundle-static/Test_2.scala b/test/files/run/macro-bundle-static/Test_2.scala index 72160f6ec2..e35260cdce 100644 --- a/test/files/run/macro-bundle-static/Test_2.scala +++ b/test/files/run/macro-bundle-static/Test_2.scala @@ -1,8 +1,8 @@ object Test extends App { println(Macros.mono) println(Macros.poly[Int]) - println(new Enclosing.Impl{val c = ???}.weird) + println(new Enclosing.Impl(???).weird) println(pkg.Macros.mono) println(pkg.Macros.poly[Int]) - println(new pkg.Enclosing.Impl{val c = ???}.weird) + println(new pkg.Enclosing.Impl(???).weird) }
\ No newline at end of file diff --git a/test/files/run/macro-bundle-toplevel/Impls_Macros_1.scala b/test/files/run/macro-bundle-toplevel/Impls_Macros_1.scala index e026768642..6fd7be3b25 100644 --- a/test/files/run/macro-bundle-toplevel/Impls_Macros_1.scala +++ b/test/files/run/macro-bundle-toplevel/Impls_Macros_1.scala @@ -1,6 +1,6 @@ -import scala.reflect.macros.BlackboxMacro +import scala.reflect.macros.blackbox.Context -trait Impl extends BlackboxMacro { +class Impl(val c: Context) { def mono = { import c.universe._; c.Expr[Unit](q"()") } def poly[T: c.WeakTypeTag] = { import c.universe._; c.Expr[String](q"${c.weakTypeOf[T].toString}") } def weird = macro mono @@ -12,7 +12,7 @@ object Macros { } package pkg { - trait Impl extends BlackboxMacro { + class Impl(val c: Context) { def mono = { import c.universe._; c.Expr[Boolean](q"true") } def poly[T: c.WeakTypeTag] = { import c.universe._; c.Expr[String](q"${c.weakTypeOf[T].toString + c.weakTypeOf[T].toString}") } def weird = macro mono diff --git a/test/files/run/macro-bundle-toplevel/Test_2.scala b/test/files/run/macro-bundle-toplevel/Test_2.scala index 139cc5bef2..195fb49262 100644 --- a/test/files/run/macro-bundle-toplevel/Test_2.scala +++ b/test/files/run/macro-bundle-toplevel/Test_2.scala @@ -1,8 +1,8 @@ object Test extends App { println(Macros.mono) println(Macros.poly[Int]) - println(new Impl{val c = ???}.weird) + println(new Impl(???).weird) println(pkg.Macros.mono) println(pkg.Macros.poly[Int]) - println(new pkg.Impl{val c = ???}.weird) + println(new pkg.Impl(???).weird) }
\ No newline at end of file diff --git a/test/files/run/macro-bundle-whitebox.check b/test/files/run/macro-bundle-whitebox.check new file mode 100644 index 0000000000..37c8eaf27a --- /dev/null +++ b/test/files/run/macro-bundle-whitebox.check @@ -0,0 +1,6 @@ +() +Int +() +true +IntInt +true diff --git a/test/files/run/macro-bundle-whitebox/Impls_Macros_1.scala b/test/files/run/macro-bundle-whitebox/Impls_Macros_1.scala new file mode 100644 index 0000000000..5e1b11895d --- /dev/null +++ b/test/files/run/macro-bundle-whitebox/Impls_Macros_1.scala @@ -0,0 +1,26 @@ +import scala.language.experimental.macros +import scala.reflect.macros.whitebox.Context + +class Impl(val c: Context) { + def mono = { import c.universe._; c.Expr[Unit](q"()") } + def poly[T: c.WeakTypeTag] = { import c.universe._; c.Expr[String](q"${c.weakTypeOf[T].toString}") } + def weird = macro mono +} + +object Macros { + def mono = macro Impl.mono + def poly[T] = macro Impl.poly[T] +} + +package pkg { + class Impl(val c: Context) { + def mono = { import c.universe._; c.Expr[Boolean](q"true") } + def poly[T: c.WeakTypeTag] = { import c.universe._; c.Expr[String](q"${c.weakTypeOf[T].toString + c.weakTypeOf[T].toString}") } + def weird = macro mono + } + + object Macros { + def mono = macro Impl.mono + def poly[T] = macro Impl.poly[T] + } +}
\ No newline at end of file diff --git a/test/files/run/macro-bundle-whitebox/Test_2.scala b/test/files/run/macro-bundle-whitebox/Test_2.scala new file mode 100644 index 0000000000..195fb49262 --- /dev/null +++ b/test/files/run/macro-bundle-whitebox/Test_2.scala @@ -0,0 +1,8 @@ +object Test extends App { + println(Macros.mono) + println(Macros.poly[Int]) + println(new Impl(???).weird) + println(pkg.Macros.mono) + println(pkg.Macros.poly[Int]) + println(new pkg.Impl(???).weird) +}
\ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent/Test_1.scala b/test/files/run/macro-def-path-dependent/Test_1.scala index bba97fcae1..4161a64303 100644 --- a/test/files/run/macro-def-path-dependent/Test_1.scala +++ b/test/files/run/macro-def-path-dependent/Test_1.scala @@ -2,7 +2,7 @@ // package test1 // -// import scala.reflect.macros.{BlackboxContext => Ctx} +// import scala.reflect.macros.blackbox.Context // // trait Exprs { // self: Universe => @@ -21,5 +21,5 @@ // trait Universe extends Exprs with Reifiers // // object Impls { -// def reify[T](cc: Ctx{ type PrefixType = Reifiers })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = ??? +// def reify[T](cc: Context{ type PrefixType = Reifiers })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = ??? // } diff --git a/test/files/run/macro-def-path-dependent/Test_2.scala b/test/files/run/macro-def-path-dependent/Test_2.scala index c884ab9d0b..75a03b54e7 100644 --- a/test/files/run/macro-def-path-dependent/Test_2.scala +++ b/test/files/run/macro-def-path-dependent/Test_2.scala @@ -1,6 +1,6 @@ package test2 -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context trait Exprs { self: Universe => @@ -18,5 +18,5 @@ trait Universe extends Exprs with Reifiers { } object Impls { - def reify[T](cc: Ctx{ type PrefixType = Universe })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = ??? + def reify[T](cc: Context{ type PrefixType = Universe })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = ??? } diff --git a/test/files/run/macro-def-path-dependent/Test_3.scala b/test/files/run/macro-def-path-dependent/Test_3.scala index 6d856d1450..1a5da8200b 100644 --- a/test/files/run/macro-def-path-dependent/Test_3.scala +++ b/test/files/run/macro-def-path-dependent/Test_3.scala @@ -1,6 +1,6 @@ package test3 -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context trait Exprs { self: Universe => @@ -18,5 +18,5 @@ trait Universe extends Exprs with Reifiers { } object Impls { - def reify[T](cc: Ctx{ type PrefixType = Universe })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = ??? + def reify[T](cc: Context{ type PrefixType = Universe })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = ??? } diff --git a/test/files/run/macro-def-path-dependent/Test_4.scala b/test/files/run/macro-def-path-dependent/Test_4.scala index 6562802013..67cb88ee6f 100644 --- a/test/files/run/macro-def-path-dependent/Test_4.scala +++ b/test/files/run/macro-def-path-dependent/Test_4.scala @@ -1,11 +1,11 @@ package test4 import scala.reflect.runtime.universe._ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import scala.reflect.api.Universe object Test { def materializeTypeTag[T](u: Universe)(e: T): u.TypeTag[T] = macro materializeTypeTag_impl[T] - def materializeTypeTag_impl[T: c.WeakTypeTag](c: BlackboxContext)(u: c.Expr[Universe])(e: c.Expr[T]): c.Expr[u.value.TypeTag[T]] = ??? + def materializeTypeTag_impl[T: c.WeakTypeTag](c: Context)(u: c.Expr[Universe])(e: c.Expr[T]): c.Expr[u.value.TypeTag[T]] = ??? }
\ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent/Test_5.scala b/test/files/run/macro-def-path-dependent/Test_5.scala index 22407b850c..b518ce864c 100644 --- a/test/files/run/macro-def-path-dependent/Test_5.scala +++ b/test/files/run/macro-def-path-dependent/Test_5.scala @@ -1,9 +1,9 @@ package test56 import scala.reflect.runtime.universe._ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import scala.reflect.api.Universe object Impls { - def materializeTypeTag_impl[T: c.WeakTypeTag](c: BlackboxContext)(u: c.Expr[Universe])(e: c.Expr[T]): c.Expr[u.value.TypeTag[T]] = ??? + def materializeTypeTag_impl[T: c.WeakTypeTag](c: Context)(u: c.Expr[Universe])(e: c.Expr[T]): c.Expr[u.value.TypeTag[T]] = ??? }
\ No newline at end of file diff --git a/test/files/run/macro-def-path-dependent/Test_6.scala b/test/files/run/macro-def-path-dependent/Test_6.scala index 011e726b3f..a8b50ce7d2 100644 --- a/test/files/run/macro-def-path-dependent/Test_6.scala +++ b/test/files/run/macro-def-path-dependent/Test_6.scala @@ -1,7 +1,7 @@ package test56 import scala.reflect.runtime.universe._ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import scala.reflect.api.Universe object Macros { diff --git a/test/files/run/macro-default-params/Macros_1.scala b/test/files/run/macro-default-params/Macros_1.scala index 47780ea4b8..74588a1cf4 100644 --- a/test/files/run/macro-default-params/Macros_1.scala +++ b/test/files/run/macro-default-params/Macros_1.scala @@ -1,11 +1,11 @@ import scala.language.experimental.macros -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context object Macros { def id[A]: A = null.asInstanceOf[A] def foo: Any = macro impl - def impl(c: WhiteboxContext): c.Tree = { + def impl(c: Context): c.Tree = { import c.universe._ import Flag._ diff --git a/test/files/run/macro-divergence-spurious/Impls_Macros_1.scala b/test/files/run/macro-divergence-spurious/Impls_Macros_1.scala index 4bafa84128..85d0f0bb7e 100644 --- a/test/files/run/macro-divergence-spurious/Impls_Macros_1.scala +++ b/test/files/run/macro-divergence-spurious/Impls_Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros trait Complex[T] @@ -7,7 +7,7 @@ class Foo(val bar: Bar) class Bar(val s: String) object Complex { - def impl[T: c.WeakTypeTag](c: BlackboxContext): c.Expr[Complex[T]] = { + def impl[T: c.WeakTypeTag](c: Context): c.Expr[Complex[T]] = { import c.universe._ val tpe = weakTypeOf[T] for (f <- tpe.declarations.collect{case f: TermSymbol if f.isParamAccessor && !f.isMethod => f}) { diff --git a/test/files/run/macro-duplicate/Impls_Macros_1.scala b/test/files/run/macro-duplicate/Impls_Macros_1.scala index ab852c9e46..84fb2c5b61 100644 --- a/test/files/run/macro-duplicate/Impls_Macros_1.scala +++ b/test/files/run/macro-duplicate/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ val Expr(Block((cdef: ClassDef) :: Nil, _)) = reify { class C { def x = 2 } } val cdef1 = diff --git a/test/files/run/macro-enclosures/Impls_Macros_1.scala b/test/files/run/macro-enclosures/Impls_Macros_1.scala index dfffb48e73..5b04cf29e9 100644 --- a/test/files/run/macro-enclosures/Impls_Macros_1.scala +++ b/test/files/run/macro-enclosures/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ reify { println("enclosingPackage = " + c.Expr[String](Literal(Constant(c.enclosingPackage.toString))).splice) diff --git a/test/files/run/macro-expand-implicit-argument/Macros_1.scala b/test/files/run/macro-expand-implicit-argument/Macros_1.scala index 7ac30e3ff2..465f313ef2 100644 --- a/test/files/run/macro-expand-implicit-argument/Macros_1.scala +++ b/test/files/run/macro-expand-implicit-argument/Macros_1.scala @@ -5,7 +5,7 @@ import scala.{specialized => spec} import language.experimental.macros import scala.reflect.ClassTag -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { def alloc[@spec A:ClassTag](src:Array[A], s1:Int, len:Int) = { @@ -35,7 +35,7 @@ object Macros { * arr * } */ - def arrayMacro[A:c.WeakTypeTag](c:BlackboxContext)(as:c.Expr[A]*)(ct: c.Expr[ClassTag[A]]): c.Expr[Array[A]] = { + def arrayMacro[A:c.WeakTypeTag](c:Context)(as:c.Expr[A]*)(ct: c.Expr[ClassTag[A]]): c.Expr[Array[A]] = { import c.mirror._ import c.universe._ def const(x:Int) = Literal(Constant(x)) diff --git a/test/files/run/macro-expand-implicit-macro-has-implicit/Impls_1.scala b/test/files/run/macro-expand-implicit-macro-has-implicit/Impls_1.scala index c56489e61c..18c97956e4 100644 --- a/test/files/run/macro-expand-implicit-macro-has-implicit/Impls_1.scala +++ b/test/files/run/macro-expand-implicit-macro-has-implicit/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int]) = { + def foo(c: Context)(x: c.Expr[Int]) = { import c.universe._ val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(x.tree)) c.Expr[Unit](body) diff --git a/test/files/run/macro-expand-implicit-macro-is-implicit/Impls_1.scala b/test/files/run/macro-expand-implicit-macro-is-implicit/Impls_1.scala index f93d9100e8..aeceee5a5b 100644 --- a/test/files/run/macro-expand-implicit-macro-is-implicit/Impls_1.scala +++ b/test/files/run/macro-expand-implicit-macro-is-implicit/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[String]): c.Expr[Option[Int]] = { + def foo(c: Context)(x: c.Expr[String]): c.Expr[Option[Int]] = { import c.universe._ val body = Apply(Ident(definitions.SomeModule), List(Select(x.tree, TermName("toInt")))) c.Expr[Option[Int]](body) diff --git a/test/files/run/macro-expand-implicit-macro-is-val/Impls_1.scala b/test/files/run/macro-expand-implicit-macro-is-val/Impls_1.scala index a8b478e9f2..fd267d32c4 100644 --- a/test/files/run/macro-expand-implicit-macro-is-val/Impls_1.scala +++ b/test/files/run/macro-expand-implicit-macro-is-val/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.universe._ val body = Literal(Constant(2)) c.Expr[Int](body) diff --git a/test/files/run/macro-expand-implicit-macro-is-view/Impls_1.scala b/test/files/run/macro-expand-implicit-macro-is-view/Impls_1.scala index f93d9100e8..aeceee5a5b 100644 --- a/test/files/run/macro-expand-implicit-macro-is-view/Impls_1.scala +++ b/test/files/run/macro-expand-implicit-macro-is-view/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[String]): c.Expr[Option[Int]] = { + def foo(c: Context)(x: c.Expr[String]): c.Expr[Option[Int]] = { import c.universe._ val body = Apply(Ident(definitions.SomeModule), List(Select(x.tree, TermName("toInt")))) c.Expr[Option[Int]](body) diff --git a/test/files/run/macro-expand-multiple-arglists/Impls_1.scala b/test/files/run/macro-expand-multiple-arglists/Impls_1.scala index bc3d768a67..9278633c11 100644 --- a/test/files/run/macro-expand-multiple-arglists/Impls_1.scala +++ b/test/files/run/macro-expand-multiple-arglists/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int])(y: c.Expr[Int]) = { + def foo(c: Context)(x: c.Expr[Int])(y: c.Expr[Int]) = { import c.universe._ val sum = Apply(Select(x.tree, TermName("$minus")), List(y.tree)) val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(sum)) diff --git a/test/files/run/macro-expand-nullary-generic/Impls_1.scala b/test/files/run/macro-expand-nullary-generic/Impls_1.scala index e0a048046f..9362d6c17a 100644 --- a/test/files/run/macro-expand-nullary-generic/Impls_1.scala +++ b/test/files/run/macro-expand-nullary-generic/Impls_1.scala @@ -1,15 +1,15 @@ import scala.reflect.runtime.universe._ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def impl[T: c.WeakTypeTag](c: Ctx)(meth: String) = { + def impl[T: c.WeakTypeTag](c: Context)(meth: String) = { import c.universe._ val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant(s"$meth[${c.weakTypeOf[T]}]")))) c.Expr[Unit](body) } - def fooNullary[T: c.WeakTypeTag](c: Ctx) = impl[T](c)("fooNullary") - def fooEmpty[T: c.WeakTypeTag](c: Ctx)() = impl[T](c)("fooEmpty") - def barNullary[T: c.WeakTypeTag](c: Ctx)(x: c.Expr[Int]) = impl[T](c)("barNullary") - def barEmpty[T: c.WeakTypeTag](c: Ctx)(x: c.Expr[Int])() = impl[T](c)("barEmpty") + def fooNullary[T: c.WeakTypeTag](c: Context) = impl[T](c)("fooNullary") + def fooEmpty[T: c.WeakTypeTag](c: Context)() = impl[T](c)("fooEmpty") + def barNullary[T: c.WeakTypeTag](c: Context)(x: c.Expr[Int]) = impl[T](c)("barNullary") + def barEmpty[T: c.WeakTypeTag](c: Context)(x: c.Expr[Int])() = impl[T](c)("barEmpty") }
\ No newline at end of file diff --git a/test/files/run/macro-expand-nullary-nongeneric/Impls_1.scala b/test/files/run/macro-expand-nullary-nongeneric/Impls_1.scala index 5da33babd3..c8c3d255c4 100644 --- a/test/files/run/macro-expand-nullary-nongeneric/Impls_1.scala +++ b/test/files/run/macro-expand-nullary-nongeneric/Impls_1.scala @@ -1,15 +1,15 @@ import scala.reflect.runtime.universe._ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def impl(c: Ctx)(meth: String) = { + def impl(c: Context)(meth: String) = { import c.universe._ val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant(meth)))) c.Expr[Unit](body) } - def fooNullary(c: Ctx) = impl(c)("fooNullary") - def fooEmpty(c: Ctx)() = impl(c)("fooEmpty") - def barNullary(c: Ctx)(x: c.Expr[Int]) = impl(c)("barNullary") - def barEmpty(c: Ctx)(x: c.Expr[Int])() = impl(c)("barEmpty") + def fooNullary(c: Context) = impl(c)("fooNullary") + def fooEmpty(c: Context)() = impl(c)("fooEmpty") + def barNullary(c: Context)(x: c.Expr[Int]) = impl(c)("barNullary") + def barEmpty(c: Context)(x: c.Expr[Int])() = impl(c)("barEmpty") }
\ No newline at end of file diff --git a/test/files/run/macro-expand-overload/Impls_1.scala b/test/files/run/macro-expand-overload/Impls_1.scala index ea68e9eb93..ef9d01d4ed 100644 --- a/test/files/run/macro-expand-overload/Impls_1.scala +++ b/test/files/run/macro-expand-overload/Impls_1.scala @@ -1,15 +1,15 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def impl(c: Ctx)(tag: String, x: c.Expr[_]) = { + def impl(c: Context)(tag: String, x: c.Expr[_]) = { import c.{prefix => prefix} import c.universe._ val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant(tag)), Literal(Constant(prefix.toString)), x.tree)) c.Expr[Unit](body) } - def fooObjectString(c: Ctx)(x: c.Expr[_]) = impl(c)("fooObjectString", x) - def fooObjectInt(c: Ctx)(x: c.Expr[_]) = impl(c)("fooObjectInt", x) - def fooClassString(c: Ctx)(x: c.Expr[_]) = impl(c)("fooClassString", x) - def fooClassInt(c: Ctx)(x: c.Expr[_]) = impl(c)("fooClassInt", x) + def fooObjectString(c: Context)(x: c.Expr[_]) = impl(c)("fooObjectString", x) + def fooObjectInt(c: Context)(x: c.Expr[_]) = impl(c)("fooObjectInt", x) + def fooClassString(c: Context)(x: c.Expr[_]) = impl(c)("fooClassString", x) + def fooClassInt(c: Context)(x: c.Expr[_]) = impl(c)("fooClassInt", x) }
\ No newline at end of file diff --git a/test/files/run/macro-expand-override/Impls_1.scala b/test/files/run/macro-expand-override/Impls_1.scala index 648641f578..e6ce18f172 100644 --- a/test/files/run/macro-expand-override/Impls_1.scala +++ b/test/files/run/macro-expand-override/Impls_1.scala @@ -1,15 +1,15 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def impl(c: Ctx)(tag: String, x: c.Expr[_]) = { + def impl(c: Context)(tag: String, x: c.Expr[_]) = { import c.{prefix => prefix} import c.universe._ val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant(tag)), Literal(Constant(prefix.toString)), x.tree)) c.Expr[Unit](body) } - def fooBString(c: Ctx)(x: c.Expr[_]) = impl(c)("fooBString", x) - def fooBInt(c: Ctx)(x: c.Expr[_]) = impl(c)("fooBInt", x) - def fooDInt(c: Ctx)(x: c.Expr[_]) = impl(c)("fooDInt", x) - def fooZString(c: Ctx)(x: c.Expr[_]) = impl(c)("fooZString", x) + def fooBString(c: Context)(x: c.Expr[_]) = impl(c)("fooBString", x) + def fooBInt(c: Context)(x: c.Expr[_]) = impl(c)("fooBInt", x) + def fooDInt(c: Context)(x: c.Expr[_]) = impl(c)("fooDInt", x) + def fooZString(c: Context)(x: c.Expr[_]) = impl(c)("fooZString", x) }
\ No newline at end of file diff --git a/test/files/run/macro-expand-recursive/Impls_1.scala b/test/files/run/macro-expand-recursive/Impls_1.scala index 8ba1a24540..3def2d2fbe 100644 --- a/test/files/run/macro-expand-recursive/Impls_1.scala +++ b/test/files/run/macro-expand-recursive/Impls_1.scala @@ -1,13 +1,13 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.universe._ val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("it works")))) c.Expr[Unit](body) } - def fooFoo(c: Ctx) = { + def fooFoo(c: Context) = { import c.universe._ val body = Select(Ident(TermName("Macros")), TermName("foo")) c.Expr[Unit](body) diff --git a/test/files/run/macro-expand-tparams-bounds/Impls_1.scala b/test/files/run/macro-expand-tparams-bounds/Impls_1.scala index a255072774..95aaa1c3d7 100644 --- a/test/files/run/macro-expand-tparams-bounds/Impls_1.scala +++ b/test/files/run/macro-expand-tparams-bounds/Impls_1.scala @@ -1,12 +1,12 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Impls1 { - def foo[U <: String](c: BlackboxContext): c.Expr[Unit] = { import c.universe._; c.Expr[Unit](q"""println("hello")""") } + def foo[U <: String](c: Context): c.Expr[Unit] = { import c.universe._; c.Expr[Unit](q"""println("hello")""") } } class C class D extends C object Impls2 { - def foo[U <: C](c: BlackboxContext): c.Expr[Unit] = { import c.universe._; c.Expr[Unit](q"""println("hello")""") } + def foo[U <: C](c: Context): c.Expr[Unit] = { import c.universe._; c.Expr[Unit](q"""println("hello")""") } } diff --git a/test/files/run/macro-expand-tparams-explicit/Impls_1.scala b/test/files/run/macro-expand-tparams-explicit/Impls_1.scala index e95d61a36a..c33ac6d1b7 100644 --- a/test/files/run/macro-expand-tparams-explicit/Impls_1.scala +++ b/test/files/run/macro-expand-tparams-explicit/Impls_1.scala @@ -1,8 +1,8 @@ import scala.reflect.runtime.universe._ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo[U: c.WeakTypeTag](c: Ctx) = { + def foo[U: c.WeakTypeTag](c: Context) = { import c.universe._ val U = implicitly[c.WeakTypeTag[U]] val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant(U.toString)))) diff --git a/test/files/run/macro-expand-tparams-implicit/Impls_1.scala b/test/files/run/macro-expand-tparams-implicit/Impls_1.scala index 37cf785c0d..32cee0d5fb 100644 --- a/test/files/run/macro-expand-tparams-implicit/Impls_1.scala +++ b/test/files/run/macro-expand-tparams-implicit/Impls_1.scala @@ -1,8 +1,8 @@ import scala.reflect.runtime.universe._ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo[U: c.WeakTypeTag](c: Ctx)(x: c.Expr[U]) = { + def foo[U: c.WeakTypeTag](c: Context)(x: c.Expr[U]) = { import c.universe._ val U = implicitly[c.WeakTypeTag[U]] val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant(U.toString)))) diff --git a/test/files/run/macro-expand-tparams-prefix/Impls_1.scala b/test/files/run/macro-expand-tparams-prefix/Impls_1.scala index 8f85ffff4a..289f07162b 100644 --- a/test/files/run/macro-expand-tparams-prefix/Impls_1.scala +++ b/test/files/run/macro-expand-tparams-prefix/Impls_1.scala @@ -1,8 +1,8 @@ import scala.reflect.runtime.universe._ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Impls1 { - def foo[U: c.WeakTypeTag](c: BlackboxContext)(x: c.Expr[U]) = { + def foo[U: c.WeakTypeTag](c: Context)(x: c.Expr[U]) = { import c.universe._ val U = implicitly[c.WeakTypeTag[U]] c.Expr[Unit](q"println(${U.toString})") @@ -10,7 +10,7 @@ object Impls1 { } object Impls2 { - def foo[T: c.WeakTypeTag, U: c.WeakTypeTag](c: BlackboxContext)(x: c.Expr[U]) = { + def foo[T: c.WeakTypeTag, U: c.WeakTypeTag](c: Context)(x: c.Expr[U]) = { import c.universe._ val T = implicitly[c.WeakTypeTag[T]] val U = implicitly[c.WeakTypeTag[U]] @@ -20,7 +20,7 @@ object Impls2 { } object Impls345 { - def foo[T, U: c.WeakTypeTag, V](c: BlackboxContext)(implicit T: c.WeakTypeTag[T], V: c.WeakTypeTag[V]): c.Expr[Unit] = { + def foo[T, U: c.WeakTypeTag, V](c: Context)(implicit T: c.WeakTypeTag[T], V: c.WeakTypeTag[V]): c.Expr[Unit] = { import c.universe._ c.Expr(q""" println(${T.toString}) diff --git a/test/files/run/macro-expand-unapply-a/Impls_Macros_1.scala b/test/files/run/macro-expand-unapply-a/Impls_Macros_1.scala index 7bfff374e2..64f16c6a89 100644 --- a/test/files/run/macro-expand-unapply-a/Impls_Macros_1.scala +++ b/test/files/run/macro-expand-unapply-a/Impls_Macros_1.scala @@ -1,11 +1,11 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context object Helper { def unapplySeq[T](x: List[T]): Option[Seq[T]] = List.unapplySeq[T](x) } object Macros { - def impl[T: c.WeakTypeTag](c: WhiteboxContext)(x: c.Expr[List[T]]) = { + def impl[T: c.WeakTypeTag](c: Context)(x: c.Expr[List[T]]) = { c.universe.reify(Helper.unapplySeq(x.splice)) } diff --git a/test/files/run/macro-expand-varargs-explicit-over-nonvarargs-bad/Impls_1.scala b/test/files/run/macro-expand-varargs-explicit-over-nonvarargs-bad/Impls_1.scala index 2480af61ad..18af84583a 100644 --- a/test/files/run/macro-expand-varargs-explicit-over-nonvarargs-bad/Impls_1.scala +++ b/test/files/run/macro-expand-varargs-explicit-over-nonvarargs-bad/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(xs: c.Expr[Int]*) = { + def foo(c: Context)(xs: c.Expr[Int]*) = { import c.universe._ val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), xs.map(_.tree).toList) c.Expr[Unit](body) diff --git a/test/files/run/macro-expand-varargs-explicit-over-nonvarargs-good/Impls_1.scala b/test/files/run/macro-expand-varargs-explicit-over-nonvarargs-good/Impls_1.scala index a31c92a01c..4bdc5bec00 100644 --- a/test/files/run/macro-expand-varargs-explicit-over-nonvarargs-good/Impls_1.scala +++ b/test/files/run/macro-expand-varargs-explicit-over-nonvarargs-good/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(xs: c.Expr[Int]*) = { + def foo(c: Context)(xs: c.Expr[Int]*) = { import c.universe._ val stripped_xs = xs map (_.tree) toList match { case List(Typed(stripped, Ident(wildstar))) if wildstar == tpnme.WILDCARD_STAR => List(stripped) diff --git a/test/files/run/macro-expand-varargs-explicit-over-varargs/Impls_1.scala b/test/files/run/macro-expand-varargs-explicit-over-varargs/Impls_1.scala index 889240d628..64ab7de02a 100644 --- a/test/files/run/macro-expand-varargs-explicit-over-varargs/Impls_1.scala +++ b/test/files/run/macro-expand-varargs-explicit-over-varargs/Impls_1.scala @@ -1,11 +1,11 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { def myprintln(xs: Int*) = { println(xs) } - def foo(c: Ctx)(xs: c.Expr[Int]*) = { + def foo(c: Context)(xs: c.Expr[Int]*) = { import c.universe._ val body = Apply(Select(Ident(TermName("Impls")), TermName("myprintln")), xs.map(_.tree).toList) c.Expr[Unit](body) diff --git a/test/files/run/macro-expand-varargs-implicit-over-nonvarargs/Impls_1.scala b/test/files/run/macro-expand-varargs-implicit-over-nonvarargs/Impls_1.scala index 2480af61ad..18af84583a 100644 --- a/test/files/run/macro-expand-varargs-implicit-over-nonvarargs/Impls_1.scala +++ b/test/files/run/macro-expand-varargs-implicit-over-nonvarargs/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(xs: c.Expr[Int]*) = { + def foo(c: Context)(xs: c.Expr[Int]*) = { import c.universe._ val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), xs.map(_.tree).toList) c.Expr[Unit](body) diff --git a/test/files/run/macro-expand-varargs-implicit-over-varargs/Impls_1.scala b/test/files/run/macro-expand-varargs-implicit-over-varargs/Impls_1.scala index 889240d628..64ab7de02a 100644 --- a/test/files/run/macro-expand-varargs-implicit-over-varargs/Impls_1.scala +++ b/test/files/run/macro-expand-varargs-implicit-over-varargs/Impls_1.scala @@ -1,11 +1,11 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { def myprintln(xs: Int*) = { println(xs) } - def foo(c: Ctx)(xs: c.Expr[Int]*) = { + def foo(c: Context)(xs: c.Expr[Int]*) = { import c.universe._ val body = Apply(Select(Ident(TermName("Impls")), TermName("myprintln")), xs.map(_.tree).toList) c.Expr[Unit](body) diff --git a/test/files/run/macro-impl-default-params/Impls_Macros_1.scala b/test/files/run/macro-impl-default-params/Impls_Macros_1.scala index aa76a410ea..9b1d0eed35 100644 --- a/test/files/run/macro-impl-default-params/Impls_Macros_1.scala +++ b/test/files/run/macro-impl-default-params/Impls_Macros_1.scala @@ -1,8 +1,8 @@ import scala.reflect.runtime.universe._ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo_targs[T, U: c.WeakTypeTag](c: Ctx = null)(x: c.Expr[Int] = null) = { + def foo_targs[T, U: c.WeakTypeTag](c: Context = null)(x: c.Expr[Int] = null) = { import c.{prefix => prefix} import c.universe._ val U = implicitly[c.WeakTypeTag[U]] diff --git a/test/files/run/macro-impl-relaxed/Macros_1.scala b/test/files/run/macro-impl-relaxed/Macros_1.scala index 3cf5090ec8..420eb2a399 100644 --- a/test/files/run/macro-impl-relaxed/Macros_1.scala +++ b/test/files/run/macro-impl-relaxed/Macros_1.scala @@ -1,11 +1,11 @@ import language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def implUU(c: BlackboxContext)(x: c.Tree): c.Tree = x - def implTU(c: BlackboxContext)(x: c.Expr[Int]): c.Tree = x.tree - def implUT(c: BlackboxContext)(x: c.Tree): c.Expr[Int] = c.Expr[Int](x) - def implTT(c: BlackboxContext)(x: c.Expr[Int]): c.Expr[Int] = x + def implUU(c: Context)(x: c.Tree): c.Tree = x + def implTU(c: Context)(x: c.Expr[Int]): c.Tree = x.tree + def implUT(c: Context)(x: c.Tree): c.Expr[Int] = c.Expr[Int](x) + def implTT(c: Context)(x: c.Expr[Int]): c.Expr[Int] = x def fooUU(x: Int): Int = macro implUU def fooTU(x: Int): Int = macro implTU diff --git a/test/files/run/macro-impl-rename-context/Impls_Macros_1.scala b/test/files/run/macro-impl-rename-context/Impls_Macros_1.scala index c79fc30628..acc47fcde6 100644 --- a/test/files/run/macro-impl-rename-context/Impls_Macros_1.scala +++ b/test/files/run/macro-impl-rename-context/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(unconventionalName: Ctx)(x: unconventionalName.Expr[Int]) = { + def foo(unconventionalName: Context)(x: unconventionalName.Expr[Int]) = { import unconventionalName.universe._ unconventionalName.Expr[Unit](q"""println("invoking foo...")""") } diff --git a/test/files/run/macro-impl-tparam-only-in-impl/Impls_1.scala b/test/files/run/macro-impl-tparam-only-in-impl/Impls_1.scala index 55cf0dcafa..705defb18f 100644 --- a/test/files/run/macro-impl-tparam-only-in-impl/Impls_1.scala +++ b/test/files/run/macro-impl-tparam-only-in-impl/Impls_1.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo[U <: String](c: Ctx): c.Expr[Unit] = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } + def foo[U <: String](c: Context): c.Expr[Unit] = { import c.universe._; c.Expr[Unit](q"""println("hello world")""") } } diff --git a/test/files/run/macro-impl-tparam-typetag-is-optional/Impls_1.scala b/test/files/run/macro-impl-tparam-typetag-is-optional/Impls_1.scala index bcc746e39a..fc72e7a979 100644 --- a/test/files/run/macro-impl-tparam-typetag-is-optional/Impls_1.scala +++ b/test/files/run/macro-impl-tparam-typetag-is-optional/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo[U](c: Ctx) = { + def foo[U](c: Context) = { import c.universe._ val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("don't know U")))) c.Expr[Unit](body) diff --git a/test/files/run/macro-invalidret-doesnt-conform-to-def-rettype/Impls_Macros_1.scala b/test/files/run/macro-invalidret-doesnt-conform-to-def-rettype/Impls_Macros_1.scala index 5a51d27b24..603500b597 100644 --- a/test/files/run/macro-invalidret-doesnt-conform-to-def-rettype/Impls_Macros_1.scala +++ b/test/files/run/macro-invalidret-doesnt-conform-to-def-rettype/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx): c.Expr[Int] = { + def foo(c: Context): c.Expr[Int] = { import c.universe._ c.Expr(Literal(Constant("42"))) } diff --git a/test/files/run/macro-invalidret-nontypeable/Impls_Macros_1.scala b/test/files/run/macro-invalidret-nontypeable/Impls_Macros_1.scala index 44e508a1c6..b6b9611743 100644 --- a/test/files/run/macro-invalidret-nontypeable/Impls_Macros_1.scala +++ b/test/files/run/macro-invalidret-nontypeable/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.universe._ val body = Ident(TermName("IDoNotExist")) c.Expr[Int](body) diff --git a/test/files/run/macro-invalidusage-badret/Impls_Macros_1.scala b/test/files/run/macro-invalidusage-badret/Impls_Macros_1.scala index a54eaa4001..0d4c5755f0 100644 --- a/test/files/run/macro-invalidusage-badret/Impls_Macros_1.scala +++ b/test/files/run/macro-invalidusage-badret/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int]) = x + def foo(c: Context)(x: c.Expr[Int]) = x } object Macros { diff --git a/test/files/run/macro-invalidusage-partialapplication-with-tparams/Impls_Macros_1.scala b/test/files/run/macro-invalidusage-partialapplication-with-tparams/Impls_Macros_1.scala index a67a296335..8b5c59bde8 100644 --- a/test/files/run/macro-invalidusage-partialapplication-with-tparams/Impls_Macros_1.scala +++ b/test/files/run/macro-invalidusage-partialapplication-with-tparams/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo[T: c.WeakTypeTag](c: Ctx)(x: c.Expr[T]) = { + def foo[T: c.WeakTypeTag](c: Context)(x: c.Expr[T]) = { import c.universe._ val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant(x.tree.toString)))) c.Expr[Unit](body) diff --git a/test/files/run/macro-invalidusage-partialapplication/Impls_Macros_1.scala b/test/files/run/macro-invalidusage-partialapplication/Impls_Macros_1.scala index 88929df27a..6970b4dd7e 100644 --- a/test/files/run/macro-invalidusage-partialapplication/Impls_Macros_1.scala +++ b/test/files/run/macro-invalidusage-partialapplication/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int])(y: c.Expr[Int]) = { + def foo(c: Context)(x: c.Expr[Int])(y: c.Expr[Int]) = { import c.universe._ val sum = Apply(Select(x.tree, TermName("$plus")), List(y.tree)) val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(sum)) diff --git a/test/files/run/macro-openmacros/Impls_Macros_1.scala b/test/files/run/macro-openmacros/Impls_Macros_1.scala index 22e94f32cd..b60ca90d91 100644 --- a/test/files/run/macro-openmacros/Impls_Macros_1.scala +++ b/test/files/run/macro-openmacros/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext): c.Expr[Unit] = { + def impl(c: Context): c.Expr[Unit] = { // we're macros, so we can reflect against our source path // so we don't need any partests to clean up after us! val dir = c.enclosingUnit.source.file.file.getCanonicalFile.getParentFile diff --git a/test/files/run/macro-parse-position-malformed/Impls_Macros_1.scala b/test/files/run/macro-parse-position-malformed/Impls_Macros_1.scala index 2417eb6897..b623d8820a 100644 --- a/test/files/run/macro-parse-position-malformed/Impls_Macros_1.scala +++ b/test/files/run/macro-parse-position-malformed/Impls_Macros_1.scala @@ -1,8 +1,9 @@ import scala.language.experimental.macros -import scala.reflect.macros.{Context => Ctx, ParseException} +import scala.reflect.macros.blackbox.Context +import scala.reflect.macros.ParseException object Macros { - def impl(c: Ctx)() = { + def impl(c: Context)() = { import c.universe._ val out = try { c.parse("foo(bar") diff --git a/test/files/run/macro-parse-position/Impls_Macros_1.scala b/test/files/run/macro-parse-position/Impls_Macros_1.scala index 92f64a8e70..dd20fd291b 100644 --- a/test/files/run/macro-parse-position/Impls_Macros_1.scala +++ b/test/files/run/macro-parse-position/Impls_Macros_1.scala @@ -1,8 +1,8 @@ import scala.language.experimental.macros -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: Ctx)() = { + def impl(c: Context)() = { import c.universe._ val t = c.parse("foo bar") val out = s"${t.pos == NoPosition}\n${t.pos}\n${t.pos.source.content.length}\n${new String(t.pos.source.content)}" diff --git a/test/files/run/macro-quasiinvalidbody-c/Impls_Macros_1.scala b/test/files/run/macro-quasiinvalidbody-c/Impls_Macros_1.scala index 04aa11b8fe..df189b70d3 100644 --- a/test/files/run/macro-quasiinvalidbody-c/Impls_Macros_1.scala +++ b/test/files/run/macro-quasiinvalidbody-c/Impls_Macros_1.scala @@ -1,8 +1,8 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Macros { object Impls { - def foo(c: Ctx)(x: c.Expr[Any]) = x + def foo(c: Context)(x: c.Expr[Any]) = x } def foo(x: Any) = macro Impls.foo diff --git a/test/files/run/macro-quasiquotes/Macros_1.scala b/test/files/run/macro-quasiquotes/Macros_1.scala index 81775d98e8..764542a870 100644 --- a/test/files/run/macro-quasiquotes/Macros_1.scala +++ b/test/files/run/macro-quasiquotes/Macros_1.scala @@ -1,7 +1,7 @@ import language.experimental.macros -import scala.reflect.macros.BlackboxMacro +import scala.reflect.macros.blackbox.Context -trait Impls extends BlackboxMacro { +class Impls(val c: Context) { import c.universe._ def impl1 = q"println(1)" def impl2 = q"{ println(2); println(3) }" diff --git a/test/files/run/macro-range/Common_1.scala b/test/files/run/macro-range/Common_1.scala index 1ad2a6c6eb..0e66815f15 100644 --- a/test/files/run/macro-range/Common_1.scala +++ b/test/files/run/macro-range/Common_1.scala @@ -1,4 +1,4 @@ -import reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context abstract class RangeDefault { val from, to: Int @@ -10,7 +10,7 @@ abstract class RangeDefault { /** This class should go into reflect.macro once it is a bit more stable. */ abstract class Utils { - val context: BlackboxContext + val context: Context import context.universe._ class TreeSubstituter(from: List[Symbol], to: List[Tree]) extends Transformer { diff --git a/test/files/run/macro-range/Expansion_Impossible_2.scala b/test/files/run/macro-range/Expansion_Impossible_2.scala index fa869a2569..514de6864a 100644 --- a/test/files/run/macro-range/Expansion_Impossible_2.scala +++ b/test/files/run/macro-range/Expansion_Impossible_2.scala @@ -1,7 +1,7 @@ -import reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Impls { - def foreach(c: BlackboxContext)(f: c.Expr[Int => Unit]): c.Expr[Unit] = { + def foreach(c: Context)(f: c.Expr[Int => Unit]): c.Expr[Unit] = { // todo. read the compiler config and print if -Ydebug is set //println("macro-expand, _this = "+ _this) object utils extends Utils { val context: c.type = c } diff --git a/test/files/run/macro-reflective-ma-normal-mdmi/Impls_Macros_1.scala b/test/files/run/macro-reflective-ma-normal-mdmi/Impls_Macros_1.scala index 53b96691e9..e964da2106 100644 --- a/test/files/run/macro-reflective-ma-normal-mdmi/Impls_Macros_1.scala +++ b/test/files/run/macro-reflective-ma-normal-mdmi/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int]) = { + def foo(c: Context)(x: c.Expr[Int]) = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(1)))) c.Expr[Int](body) diff --git a/test/files/run/macro-reflective-mamd-normal-mi/Impls_1.scala b/test/files/run/macro-reflective-mamd-normal-mi/Impls_1.scala index 81ad5cae0b..89a818d99c 100644 --- a/test/files/run/macro-reflective-mamd-normal-mi/Impls_1.scala +++ b/test/files/run/macro-reflective-mamd-normal-mi/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int]) = { + def foo(c: Context)(x: c.Expr[Int]) = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(1)))) c.Expr[Int](body) diff --git a/test/files/run/macro-reify-basic/Macros_1.scala b/test/files/run/macro-reify-basic/Macros_1.scala index e1a6d8abfb..1cf2a8a406 100644 --- a/test/files/run/macro-reify-basic/Macros_1.scala +++ b/test/files/run/macro-reify-basic/Macros_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Macros { def foo(s: String) = macro Impls.foo object Impls { - def foo(c: Ctx)(s: c.Expr[String]) = c.universe.reify { + def foo(c: Context)(s: c.Expr[String]) = c.universe.reify { println("hello " + s.splice) } } diff --git a/test/files/run/macro-reify-freevars/Macros_1.scala b/test/files/run/macro-reify-freevars/Macros_1.scala index 2cd94f600a..912f602c6c 100644 --- a/test/files/run/macro-reify-freevars/Macros_1.scala +++ b/test/files/run/macro-reify-freevars/Macros_1.scala @@ -2,7 +2,7 @@ package scala.collection.slick object QueryableMacros{ def map[T:c.WeakTypeTag, S:c.WeakTypeTag] - (c: scala.reflect.macros.BlackboxContext) + (c: scala.reflect.macros.blackbox.Context) (projection: c.Expr[T => S]) : c.Expr[scala.collection.slick.Queryable[S]] = { import c.universe._ diff --git a/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala b/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala index 8f7a34a10a..8d2aa1e70a 100644 --- a/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala +++ b/test/files/run/macro-reify-nested-a/Impls_Macros_1.scala @@ -1,8 +1,8 @@ import scala.reflect.runtime.universe._ import scala.reflect.runtime.{universe => ru} -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context -case class Utils[C <: BlackboxContext]( c:C ) { +case class Utils[C <: Context]( c:C ) { import c.universe._ import c.{Tree=>_} object removeDoubleReify extends c.universe.Transformer { @@ -21,7 +21,7 @@ case class Utils[C <: BlackboxContext]( c:C ) { } } object QueryableMacros{ - def _helper[C <: BlackboxContext,S:c.WeakTypeTag]( c:C )( name:String, projection:c.Expr[_] ) = { + def _helper[C <: Context,S:c.WeakTypeTag]( c:C )( name:String, projection:c.Expr[_] ) = { import c.universe._ import treeBuild._ val element_type = implicitly[c.WeakTypeTag[S]].tpe @@ -34,7 +34,7 @@ object QueryableMacros{ c.universe.reify{ Queryable.factory[S]( foo.splice )} } def map[T:c.WeakTypeTag, S:c.WeakTypeTag] - (c: scala.reflect.macros.BlackboxContext) + (c: scala.reflect.macros.blackbox.Context) (projection: c.Expr[T => S]): c.Expr[Queryable[S]] = _helper[c.type,S]( c )( "_map", projection ) } class Queryable[T]{ diff --git a/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala b/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala index 8f7a34a10a..8d2aa1e70a 100644 --- a/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala +++ b/test/files/run/macro-reify-nested-b/Impls_Macros_1.scala @@ -1,8 +1,8 @@ import scala.reflect.runtime.universe._ import scala.reflect.runtime.{universe => ru} -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context -case class Utils[C <: BlackboxContext]( c:C ) { +case class Utils[C <: Context]( c:C ) { import c.universe._ import c.{Tree=>_} object removeDoubleReify extends c.universe.Transformer { @@ -21,7 +21,7 @@ case class Utils[C <: BlackboxContext]( c:C ) { } } object QueryableMacros{ - def _helper[C <: BlackboxContext,S:c.WeakTypeTag]( c:C )( name:String, projection:c.Expr[_] ) = { + def _helper[C <: Context,S:c.WeakTypeTag]( c:C )( name:String, projection:c.Expr[_] ) = { import c.universe._ import treeBuild._ val element_type = implicitly[c.WeakTypeTag[S]].tpe @@ -34,7 +34,7 @@ object QueryableMacros{ c.universe.reify{ Queryable.factory[S]( foo.splice )} } def map[T:c.WeakTypeTag, S:c.WeakTypeTag] - (c: scala.reflect.macros.BlackboxContext) + (c: scala.reflect.macros.blackbox.Context) (projection: c.Expr[T => S]): c.Expr[Queryable[S]] = _helper[c.type,S]( c )( "_map", projection ) } class Queryable[T]{ diff --git a/test/files/run/macro-reify-ref-to-packageless/Impls_1.scala b/test/files/run/macro-reify-ref-to-packageless/Impls_1.scala index bc0015774e..38ec6f022e 100644 --- a/test/files/run/macro-reify-ref-to-packageless/Impls_1.scala +++ b/test/files/run/macro-reify-ref-to-packageless/Impls_1.scala @@ -1,6 +1,6 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { val `Answer to the Ultimate Question of Life, the Universe, and Everything` = 42 - def foo(c: Ctx) = c.universe.reify { `Answer to the Ultimate Question of Life, the Universe, and Everything` } + def foo(c: Context) = c.universe.reify { `Answer to the Ultimate Question of Life, the Universe, and Everything` } } diff --git a/test/files/run/macro-reify-splice-outside-reify/Impls_Macros_1.scala b/test/files/run/macro-reify-splice-outside-reify/Impls_Macros_1.scala index d89a5e380d..f038d8714f 100644 --- a/test/files/run/macro-reify-splice-outside-reify/Impls_Macros_1.scala +++ b/test/files/run/macro-reify-splice-outside-reify/Impls_Macros_1.scala @@ -1,9 +1,9 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int]) = { + def foo(c: Context)(x: c.Expr[Int]) = { import c.universe._ - val x1 = c.Expr[Int](c.resetAllAttrs(x.tree)) + val x1 = c.Expr[Int](c.untypecheck(x.tree)) c.Expr[Int](Literal(Constant(c.eval(x1)))) } } diff --git a/test/files/run/macro-reify-staticXXX/Macros_1.scala b/test/files/run/macro-reify-staticXXX/Macros_1.scala index 077271d582..2993218bb4 100644 --- a/test/files/run/macro-reify-staticXXX/Macros_1.scala +++ b/test/files/run/macro-reify-staticXXX/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object B { override def toString = "object" } class C { override def toString = "class" } @@ -14,7 +14,7 @@ object foo { } object packageless { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ reify { println(B) @@ -31,7 +31,7 @@ object packageless { package packageful { object Test { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ reify { println(B) diff --git a/test/files/run/macro-reify-tagful-a/Macros_1.scala b/test/files/run/macro-reify-tagful-a/Macros_1.scala index 56d43c1c53..6f061fd26a 100644 --- a/test/files/run/macro-reify-tagful-a/Macros_1.scala +++ b/test/files/run/macro-reify-tagful-a/Macros_1.scala @@ -1,11 +1,11 @@ import scala.reflect.runtime.universe._ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Macros { def foo[T](s: T) = macro Impls.foo[T] object Impls { - def foo[T: c.WeakTypeTag](c: Ctx)(s: c.Expr[T]) = c.universe.reify { + def foo[T: c.WeakTypeTag](c: Context)(s: c.Expr[T]) = c.universe.reify { List(s.splice) } } diff --git a/test/files/run/macro-reify-tagless-a/Impls_Macros_1.scala b/test/files/run/macro-reify-tagless-a/Impls_Macros_1.scala index 27acaa1626..faac3e3a31 100644 --- a/test/files/run/macro-reify-tagless-a/Impls_Macros_1.scala +++ b/test/files/run/macro-reify-tagless-a/Impls_Macros_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Macros { def foo[T](s: T) = macro Impls.foo[T] object Impls { - def foo[T](c: Ctx)(s: c.Expr[T]) = c.universe.reify { + def foo[T](c: Context)(s: c.Expr[T]) = c.universe.reify { List[T](s.splice) } } diff --git a/test/files/run/macro-reify-type/Macros_1.scala b/test/files/run/macro-reify-type/Macros_1.scala index 04634b649a..bac1744c50 100644 --- a/test/files/run/macro-reify-type/Macros_1.scala +++ b/test/files/run/macro-reify-type/Macros_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import scala.reflect.runtime.{universe => ru} object StaticReflect { def method[A](name: String): ru.Type = macro methodImpl[A] - def methodImpl[A: c.WeakTypeTag](c: BlackboxContext)(name: c.Expr[String]): c.Expr[ru.Type] = { + def methodImpl[A: c.WeakTypeTag](c: Context)(name: c.Expr[String]): c.Expr[ru.Type] = { import c.universe._ val nameName: TermName = name.tree match { diff --git a/test/files/run/macro-reify-unreify/Macros_1.scala b/test/files/run/macro-reify-unreify/Macros_1.scala index 055959018a..6e358eb72d 100644 --- a/test/files/run/macro-reify-unreify/Macros_1.scala +++ b/test/files/run/macro-reify-unreify/Macros_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Macros { def foo(s: String) = macro Impls.foo object Impls { - def foo(c: Ctx)(s: c.Expr[String]) = { + def foo(c: Context)(s: c.Expr[String]) = { import c.universe._ import treeBuild._ diff --git a/test/files/run/macro-repl-basic.check b/test/files/run/macro-repl-basic.check index cc974897f2..86b4d472ed 100644 --- a/test/files/run/macro-repl-basic.check +++ b/test/files/run/macro-repl-basic.check @@ -4,25 +4,25 @@ Type :help for more information. scala> import language.experimental.macros import language.experimental.macros -scala> import scala.reflect.macros.{BlackboxContext => Ctx} -import scala.reflect.macros.{BlackboxContext=>Ctx} +scala> import scala.reflect.macros.blackbox.Context +import scala.reflect.macros.blackbox.Context scala> scala> object Impls { - def foo(c: Ctx)(x: c.Expr[Int]) = { + def foo(c: Context)(x: c.Expr[Int]) = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(1)))) c.Expr[Int](body) } - def bar(c: Ctx)(x: c.Expr[Int]) = { + def bar(c: Context)(x: c.Expr[Int]) = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(2)))) c.Expr[Int](body) } - def quux(c: Ctx)(x: c.Expr[Int]) = { + def quux(c: Context)(x: c.Expr[Int]) = { import c.universe._ val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(3)))) c.Expr[Int](body) diff --git a/test/files/run/macro-repl-basic.scala b/test/files/run/macro-repl-basic.scala index dea36c481c..217f3bc0eb 100644 --- a/test/files/run/macro-repl-basic.scala +++ b/test/files/run/macro-repl-basic.scala @@ -3,22 +3,22 @@ import scala.tools.partest.ReplTest object Test extends ReplTest { def code = """ |import language.experimental.macros - |import scala.reflect.macros.{BlackboxContext => Ctx} + |import scala.reflect.macros.blackbox.Context | |object Impls { - | def foo(c: Ctx)(x: c.Expr[Int]) = { + | def foo(c: Context)(x: c.Expr[Int]) = { | import c.universe._ | val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(1)))) | c.Expr[Int](body) | } | - | def bar(c: Ctx)(x: c.Expr[Int]) = { + | def bar(c: Context)(x: c.Expr[Int]) = { | import c.universe._ | val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(2)))) | c.Expr[Int](body) | } | - | def quux(c: Ctx)(x: c.Expr[Int]) = { + | def quux(c: Context)(x: c.Expr[Int]) = { | import c.universe._ | val body = Apply(Select(x.tree, TermName("$plus")), List(Literal(Constant(3)))) | c.Expr[Int](body) diff --git a/test/files/run/macro-repl-dontexpand.check b/test/files/run/macro-repl-dontexpand.check index 9f538c04b6..20d3b2d702 100644 --- a/test/files/run/macro-repl-dontexpand.check +++ b/test/files/run/macro-repl-dontexpand.check @@ -1,14 +1,14 @@ Type in expressions to have them evaluated. Type :help for more information. -scala> def bar1(c: scala.reflect.macros.BlackboxContext) = ??? -bar1: (c: scala.reflect.macros.BlackboxContext)Nothing +scala> def bar1(c: scala.reflect.macros.blackbox.Context) = ??? +bar1: (c: scala.reflect.macros.blackbox.Context)Nothing scala> def foo1 = macro bar1 defined term macro foo1: Nothing -scala> def bar2(c: scala.reflect.macros.WhiteboxContext) = ??? -bar2: (c: scala.reflect.macros.WhiteboxContext)Nothing +scala> def bar2(c: scala.reflect.macros.whitebox.Context) = ??? +bar2: (c: scala.reflect.macros.whitebox.Context)Nothing scala> def foo2 = macro bar2 defined term macro foo2: Nothing diff --git a/test/files/run/macro-repl-dontexpand.scala b/test/files/run/macro-repl-dontexpand.scala index 733288e513..920f40084f 100644 --- a/test/files/run/macro-repl-dontexpand.scala +++ b/test/files/run/macro-repl-dontexpand.scala @@ -3,9 +3,9 @@ import scala.tools.partest.ReplTest object Test extends ReplTest { override def extraSettings = "-language:experimental.macros" def code = """ - |def bar1(c: scala.reflect.macros.BlackboxContext) = ??? + |def bar1(c: scala.reflect.macros.blackbox.Context) = ??? |def foo1 = macro bar1 - |def bar2(c: scala.reflect.macros.WhiteboxContext) = ??? + |def bar2(c: scala.reflect.macros.whitebox.Context) = ??? |def foo2 = macro bar2 |""".stripMargin } diff --git a/test/files/run/macro-settings/Impls_Macros_1.scala b/test/files/run/macro-settings/Impls_Macros_1.scala index c9cecfa99f..851a987206 100644 --- a/test/files/run/macro-settings/Impls_Macros_1.scala +++ b/test/files/run/macro-settings/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Impls { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ reify { println(c.Expr[String](Literal(Constant(c.settings.toString))).splice) diff --git a/test/files/run/macro-sip19-revised/Impls_Macros_1.scala b/test/files/run/macro-sip19-revised/Impls_Macros_1.scala index 3acc52dbe0..ded4d85cfc 100644 --- a/test/files/run/macro-sip19-revised/Impls_Macros_1.scala +++ b/test/files/run/macro-sip19-revised/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context object Macros { - def impl(c: WhiteboxContext) = { + def impl(c: Context) = { import c.universe._ val inscope = c.inferImplicitValue(c.mirror.staticClass("SourceLocation").toType) diff --git a/test/files/run/macro-sip19/Impls_Macros_1.scala b/test/files/run/macro-sip19/Impls_Macros_1.scala index f830d2af0d..f66ab71479 100644 --- a/test/files/run/macro-sip19/Impls_Macros_1.scala +++ b/test/files/run/macro-sip19/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context object Macros { - def impl(c: WhiteboxContext) = { + def impl(c: Context) = { import c.universe._ val Apply(fun, args) = c.enclosingImplicits(0).tree val fileName = fun.pos.source.file.file.getName diff --git a/test/files/run/macro-subpatterns/Macro_1.scala b/test/files/run/macro-subpatterns/Macro_1.scala index d8e86e27c6..2de6b4da9d 100644 --- a/test/files/run/macro-subpatterns/Macro_1.scala +++ b/test/files/run/macro-subpatterns/Macro_1.scala @@ -1,9 +1,9 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import language.experimental.macros object Extractor { def unapply(x: Any): Any = macro unapplyImpl - def unapplyImpl(c: WhiteboxContext)(x: c.Tree) = { + def unapplyImpl(c: Context)(x: c.Tree) = { val st = c.universe.asInstanceOf[reflect.internal.SymbolTable] import st._ val subpatterns = x.attachments.get[SubpatternsAttachment].get.patterns diff --git a/test/files/run/macro-system-properties.check b/test/files/run/macro-system-properties.check index ceed1079b2..ffbd5a8aa8 100644 --- a/test/files/run/macro-system-properties.check +++ b/test/files/run/macro-system-properties.check @@ -1,14 +1,14 @@ Type in expressions to have them evaluated. Type :help for more information. -scala> import language.experimental._, reflect.macros.BlackboxContext -import language.experimental._ -import reflect.macros.BlackboxContext +scala> import scala.language.experimental._, scala.reflect.macros.blackbox.Context +import scala.language.experimental._ +import scala.reflect.macros.blackbox.Context scala> object GrabContext { def lastContext = Option(System.getProperties.get("lastContext").asInstanceOf[reflect.macros.runtime.Context]) // System.properties lets you stash true globals (unlike statics which are classloader scoped) - def impl(c: BlackboxContext)() = { import c.universe._; System.getProperties.put("lastContext", c); c.Expr[Unit](q"()") } + def impl(c: Context)() = { import c.universe._; System.getProperties.put("lastContext", c); c.Expr[Unit](q"()") } def grab(): Unit = macro impl } defined object GrabContext diff --git a/test/files/run/macro-system-properties.scala b/test/files/run/macro-system-properties.scala index 3325c1747a..db88eb7df6 100644 --- a/test/files/run/macro-system-properties.scala +++ b/test/files/run/macro-system-properties.scala @@ -3,11 +3,11 @@ import scala.tools.partest.ReplTest object Test extends ReplTest { def code = """ - import language.experimental._, reflect.macros.BlackboxContext + import scala.language.experimental._, scala.reflect.macros.blackbox.Context object GrabContext { def lastContext = Option(System.getProperties.get("lastContext").asInstanceOf[reflect.macros.runtime.Context]) // System.properties lets you stash true globals (unlike statics which are classloader scoped) - def impl(c: BlackboxContext)() = { import c.universe._; System.getProperties.put("lastContext", c); c.Expr[Unit](q"()") } + def impl(c: Context)() = { import c.universe._; System.getProperties.put("lastContext", c); c.Expr[Unit](q"()") } def grab(): Unit = macro impl } object Test { class C(implicit a: Any) { GrabContext.grab } } diff --git a/test/files/run/macro-term-declared-in-annotation/Impls_1.scala b/test/files/run/macro-term-declared-in-annotation/Impls_1.scala index df3509731b..c4bcfbc1ba 100644 --- a/test/files/run/macro-term-declared-in-annotation/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-annotation/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-anonymous/Impls_1.scala b/test/files/run/macro-term-declared-in-anonymous/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-anonymous/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-anonymous/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-block/Impls_1.scala b/test/files/run/macro-term-declared-in-block/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-block/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-block/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-class-class/Impls_1.scala b/test/files/run/macro-term-declared-in-class-class/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-class-class/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-class-class/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-class-object/Impls_1.scala b/test/files/run/macro-term-declared-in-class-object/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-class-object/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-class-object/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-class/Impls_1.scala b/test/files/run/macro-term-declared-in-class/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-class/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-class/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-default-param/Impls_1.scala b/test/files/run/macro-term-declared-in-default-param/Impls_1.scala index 4fae9b200f..ef0f136139 100644 --- a/test/files/run/macro-term-declared-in-default-param/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-default-param/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-implicit-class/Impls_Macros_1.scala b/test/files/run/macro-term-declared-in-implicit-class/Impls_Macros_1.scala index 053af625a2..ef00f6ff32 100644 --- a/test/files/run/macro-term-declared-in-implicit-class/Impls_Macros_1.scala +++ b/test/files/run/macro-term-declared-in-implicit-class/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def toOptionOfInt(c: Ctx) = { + def toOptionOfInt(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-method/Impls_1.scala b/test/files/run/macro-term-declared-in-method/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-method/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-method/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-object-class/Impls_1.scala b/test/files/run/macro-term-declared-in-object-class/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-object-class/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-object-class/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-object-object/Impls_1.scala b/test/files/run/macro-term-declared-in-object-object/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-object-object/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-object-object/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-object/Impls_1.scala b/test/files/run/macro-term-declared-in-object/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-object/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-object/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-package-object/Impls_1.scala b/test/files/run/macro-term-declared-in-package-object/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-package-object/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-package-object/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-refinement/Impls_1.scala b/test/files/run/macro-term-declared-in-refinement/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-refinement/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-refinement/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-term-declared-in-trait/Impls_1.scala b/test/files/run/macro-term-declared-in-trait/Impls_1.scala index d69422872b..c43f5f3f53 100644 --- a/test/files/run/macro-term-declared-in-trait/Impls_1.scala +++ b/test/files/run/macro-term-declared-in-trait/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/files/run/macro-typecheck-implicitsdisabled/Impls_Macros_1.scala b/test/files/run/macro-typecheck-implicitsdisabled/Impls_Macros_1.scala index ce937671cc..956331cfae 100644 --- a/test/files/run/macro-typecheck-implicitsdisabled/Impls_Macros_1.scala +++ b/test/files/run/macro-typecheck-implicitsdisabled/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl_with_implicits_enabled(c: BlackboxContext) = { + def impl_with_implicits_enabled(c: Context) = { import c.universe._ val tree1 = Apply(Select(Literal(Constant(1)), TermName("$minus$greater")), List(Literal(Constant(2)))) @@ -11,7 +11,7 @@ object Macros { def foo_with_implicits_enabled = macro impl_with_implicits_enabled - def impl_with_implicits_disabled(c: BlackboxContext) = { + def impl_with_implicits_disabled(c: Context) = { import c.universe._ try { diff --git a/test/files/run/macro-typecheck-macrosdisabled/Impls_Macros_1.scala b/test/files/run/macro-typecheck-macrosdisabled/Impls_Macros_1.scala index 45b9a4fcc8..eb558f49b5 100644 --- a/test/files/run/macro-typecheck-macrosdisabled/Impls_Macros_1.scala +++ b/test/files/run/macro-typecheck-macrosdisabled/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl_with_macros_enabled(c: BlackboxContext) = { + def impl_with_macros_enabled(c: Context) = { import c.universe._ val ru = Select(Select(Select(Select(Ident(TermName("scala")), TermName("reflect")), TermName("runtime")), TermName("package")), TermName("universe")) @@ -12,7 +12,7 @@ object Macros { def foo_with_macros_enabled = macro impl_with_macros_enabled - def impl_with_macros_disabled(c: BlackboxContext) = { + def impl_with_macros_disabled(c: Context) = { import c.universe._ val rupkg = c.mirror.staticModule("scala.reflect.runtime.package") diff --git a/test/files/run/macro-typecheck-macrosdisabled2/Impls_Macros_1.scala b/test/files/run/macro-typecheck-macrosdisabled2/Impls_Macros_1.scala index d37a654957..3412f5c88f 100644 --- a/test/files/run/macro-typecheck-macrosdisabled2/Impls_Macros_1.scala +++ b/test/files/run/macro-typecheck-macrosdisabled2/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl_with_macros_enabled(c: BlackboxContext) = { + def impl_with_macros_enabled(c: Context) = { import c.universe._ val ru = Select(Select(Select(Select(Ident(TermName("scala")), TermName("reflect")), TermName("runtime")), TermName("package")), TermName("universe")) @@ -12,7 +12,7 @@ object Macros { def foo_with_macros_enabled = macro impl_with_macros_enabled - def impl_with_macros_disabled(c: BlackboxContext) = { + def impl_with_macros_disabled(c: Context) = { import c.universe._ val rupkg = c.mirror.staticModule("scala.reflect.runtime.package") diff --git a/test/files/run/macro-undetparams-consfromsls/Impls_Macros_1.scala b/test/files/run/macro-undetparams-consfromsls/Impls_Macros_1.scala index 1af0579abc..5df5f96aa8 100644 --- a/test/files/run/macro-undetparams-consfromsls/Impls_Macros_1.scala +++ b/test/files/run/macro-undetparams-consfromsls/Impls_Macros_1.scala @@ -1,8 +1,8 @@ import scala.reflect.runtime.universe._ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def cons_impl[A: c.WeakTypeTag](c: BlackboxContext)(x: c.Expr[A], xs: c.Expr[List[A]]): c.Expr[List[A]] = { + def cons_impl[A: c.WeakTypeTag](c: Context)(x: c.Expr[A], xs: c.Expr[List[A]]): c.Expr[List[A]] = { import c.universe._ reify { println("A = " + c.Expr[String](Literal(Constant(implicitly[c.WeakTypeTag[A]].toString))).splice) @@ -10,7 +10,7 @@ object Macros { } } - def nil_impl[B: c.WeakTypeTag](c: BlackboxContext): c.Expr[List[B]] = { + def nil_impl[B: c.WeakTypeTag](c: Context): c.Expr[List[B]] = { import c.universe._ reify { println("B = " + c.Expr[String](Literal(Constant(implicitly[c.WeakTypeTag[B]].toString))).splice) diff --git a/test/files/run/macro-undetparams-macroitself/Impls_Macros_1.scala b/test/files/run/macro-undetparams-macroitself/Impls_Macros_1.scala index f698320579..1eb257e1d9 100644 --- a/test/files/run/macro-undetparams-macroitself/Impls_Macros_1.scala +++ b/test/files/run/macro-undetparams-macroitself/Impls_Macros_1.scala @@ -1,8 +1,8 @@ import scala.reflect.runtime.universe._ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl[T: c.WeakTypeTag](c: BlackboxContext)(foo: c.Expr[T]): c.Expr[Unit] = { + def impl[T: c.WeakTypeTag](c: Context)(foo: c.Expr[T]): c.Expr[Unit] = { import c.universe._ reify { println(c.Expr[String](Literal(Constant(implicitly[c.WeakTypeTag[T]].toString))).splice) } } diff --git a/test/files/run/macro-vampire-false-warning/Macros_1.scala b/test/files/run/macro-vampire-false-warning/Macros_1.scala index bf75e924e8..0912bfba0c 100644 --- a/test/files/run/macro-vampire-false-warning/Macros_1.scala +++ b/test/files/run/macro-vampire-false-warning/Macros_1.scala @@ -1,20 +1,20 @@ // As per http://meta.plasm.us/posts/2013/08/31/feeding-our-vampires/ import scala.annotation.StaticAnnotation -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import scala.language.experimental.macros class body(tree: Any) extends StaticAnnotation object Macros { - def selFieldImpl(c: WhiteboxContext) = { + def selFieldImpl(c: Context) = { import c.universe._ val field = c.macroApplication.symbol val bodyAnn = field.annotations.filter(_.tpe <:< typeOf[body]).head c.Expr[Any](bodyAnn.scalaArgs.head) } - def mkObjectImpl(c: WhiteboxContext)(xs: c.Expr[Any]*) = { + def mkObjectImpl(c: Context)(xs: c.Expr[Any]*) = { import c.universe._ import Flag._ // val kvps = xs.toList map { case q"${_}(${Literal(Constant(name: String))}).->[${_}]($value)" => name -> value } diff --git a/test/files/run/macro-whitebox-dynamic-materialization/Macros_1.scala b/test/files/run/macro-whitebox-dynamic-materialization/Macros_1.scala index 87cd310b09..60a8d011f1 100644 --- a/test/files/run/macro-whitebox-dynamic-materialization/Macros_1.scala +++ b/test/files/run/macro-whitebox-dynamic-materialization/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import scala.language.experimental.macros trait Foo[T] @@ -15,7 +15,7 @@ object Foo extends LowPriority { } object Macros { - def impl[T: c.WeakTypeTag](c: WhiteboxContext) = { + def impl[T: c.WeakTypeTag](c: Context) = { import c.universe._ val tpe = weakTypeOf[T] if (tpe.members.exists(_.typeSignature =:= typeOf[Int])) diff --git a/test/files/run/macro-whitebox-extractor/Macros_1.scala b/test/files/run/macro-whitebox-extractor/Macros_1.scala index 64053b8a24..d394c0241a 100644 --- a/test/files/run/macro-whitebox-extractor/Macros_1.scala +++ b/test/files/run/macro-whitebox-extractor/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import language.experimental.macros object Extractor { @@ -6,7 +6,7 @@ object Extractor { } object Macros { - def unapplyImpl(c: WhiteboxContext)(x: c.Tree) = { + def unapplyImpl(c: Context)(x: c.Tree) = { import c.universe._ q""" new { diff --git a/test/files/run/macro-whitebox-fundep-materialization/Macros_1.scala b/test/files/run/macro-whitebox-fundep-materialization/Macros_1.scala index 671a4fff4e..a8309e35b0 100644 --- a/test/files/run/macro-whitebox-fundep-materialization/Macros_1.scala +++ b/test/files/run/macro-whitebox-fundep-materialization/Macros_1.scala @@ -1,5 +1,5 @@ import scala.language.experimental.macros -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context trait Iso[T, U] { def to(t : T) : U @@ -8,7 +8,7 @@ trait Iso[T, U] { object Iso { implicit def materializeIso[T, U]: Iso[T, U] = macro impl[T, U] - def impl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: WhiteboxContext): c.Expr[Iso[T, U]] = { + def impl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: Context): c.Expr[Iso[T, U]] = { import c.universe._ import definitions._ import Flag._ diff --git a/test/files/run/macro-whitebox-structural/Impls_Macros_1.scala b/test/files/run/macro-whitebox-structural/Impls_Macros_1.scala index b8d0c042be..45fdb79c30 100644 --- a/test/files/run/macro-whitebox-structural/Impls_Macros_1.scala +++ b/test/files/run/macro-whitebox-structural/Impls_Macros_1.scala @@ -1,8 +1,8 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import scala.language.experimental.macros object Macros { - def impl(c: WhiteboxContext) = { + def impl(c: Context) = { import c.universe._ q""" trait Foo { diff --git a/test/files/run/macroPlugins-macroArgs/Macros_2.scala b/test/files/run/macroPlugins-macroArgs/Macros_2.scala index d6521dfbcb..b19b8f18dc 100644 --- a/test/files/run/macroPlugins-macroArgs/Macros_2.scala +++ b/test/files/run/macroPlugins-macroArgs/Macros_2.scala @@ -1,8 +1,8 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext)(arg: c.Tree) = { + def impl(c: Context)(arg: c.Tree) = { import c.universe._ q"""println($arg)""" } diff --git a/test/files/run/macroPlugins-macroExpand/Macros_2.scala b/test/files/run/macroPlugins-macroExpand/Macros_2.scala index f16503b415..c9c88ad2fd 100644 --- a/test/files/run/macroPlugins-macroExpand/Macros_2.scala +++ b/test/files/run/macroPlugins-macroExpand/Macros_2.scala @@ -1,13 +1,13 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl1(c: BlackboxContext) = { + def impl1(c: Context) = { import c.universe._ q"""println("impl1")""" } - def impl2(c: BlackboxContext) = { + def impl2(c: Context) = { import c.universe._ q"""println("impl2")""" } diff --git a/test/files/run/macroPlugins-macroRuntime/Macros_2.scala b/test/files/run/macroPlugins-macroRuntime/Macros_2.scala index d6521dfbcb..b19b8f18dc 100644 --- a/test/files/run/macroPlugins-macroRuntime/Macros_2.scala +++ b/test/files/run/macroPlugins-macroRuntime/Macros_2.scala @@ -1,8 +1,8 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext)(arg: c.Tree) = { + def impl(c: Context)(arg: c.Tree) = { import c.universe._ q"""println($arg)""" } diff --git a/test/files/run/macroPlugins-namerHooks.scala b/test/files/run/macroPlugins-namerHooks.scala index a71d685f7f..302429b19e 100644 --- a/test/files/run/macroPlugins-namerHooks.scala +++ b/test/files/run/macroPlugins-namerHooks.scala @@ -14,19 +14,20 @@ object Test extends DirectTest { import analyzer._ val output = collection.mutable.ListBuffer[String]() + def log(what: String) = output += what.replace(String.format("%n"), " ") object macroPlugin extends MacroPlugin { override def pluginsEnterSym(namer: Namer, tree: Tree): Boolean = { - output += s"enterSym(${tree.toString.replace('\n', ' ')})" + log(s"enterSym($tree)") namer.standardEnterSym(tree) true } override def pluginsEnsureCompanionObject(namer: Namer, cdef: ClassDef, creator: ClassDef => Tree = companionModuleDef(_)): Option[Symbol] = { - output += s"ensureCompanionObject(${cdef.toString.replace('\n', ' ')}, ...)" + log(s"ensureCompanionObject($cdef, ...)") Some(namer.standardEnsureCompanionObject(cdef, creator)) } override def pluginsEnterStats(typer: Typer, stats: List[Tree]): List[Tree] = { - stats.foreach(stat => output += s"enterStat(${stat.toString.replace('\n', ' ')})") + stats.foreach(stat => log(s"enterStat($stat)")) stats } } diff --git a/test/files/run/macroPlugins-typedMacroBody/Macros_2.scala b/test/files/run/macroPlugins-typedMacroBody/Macros_2.scala index fa8522e729..80acfec659 100644 --- a/test/files/run/macroPlugins-typedMacroBody/Macros_2.scala +++ b/test/files/run/macroPlugins-typedMacroBody/Macros_2.scala @@ -1,13 +1,13 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl1(c: BlackboxContext) = { + def impl1(c: Context) = { import c.universe._ q"""println("impl1")""" } - def impl2(c: BlackboxContext) = { + def impl2(c: Context) = { import c.universe._ q"""println("impl2")""" } diff --git a/test/files/run/name-based-patmat.check b/test/files/run/name-based-patmat.check index 1cc605ea3d..3d5fc40ed7 100644 --- a/test/files/run/name-based-patmat.check +++ b/test/files/run/name-based-patmat.check @@ -1,3 +1,5 @@ +`catdog only` has 11 chars +`catdog only, no product` has 23 chars catdog 2 catdogs! A ha ha! 3 catdogs! A ha ha! diff --git a/test/files/run/name-based-patmat.scala b/test/files/run/name-based-patmat.scala index 2c429c141f..8e20940100 100644 --- a/test/files/run/name-based-patmat.scala +++ b/test/files/run/name-based-patmat.scala @@ -1,5 +1,33 @@ final class MiniSome[T](val get: T) extends AnyVal { def isEmpty = false } +package p0 { + class Single(val x: Any) extends AnyRef with Product1[String] { + private def s = "" + x + override def canEqual(x: Any) = this eq x.asInstanceOf[AnyRef] + def isEmpty = false + def get = this + def _1 = s + " only" + + override def toString = s"Single(${_1})" + } + + object Single { + def unapply(x: Any): Single = new Single(x) + } + + class SingleNoProduct(val x: Any) extends AnyRef { + private def s = "" + x + def isEmpty = false + def get = s + " only, no product" + + override def toString = s"SingleNoProduct($get)" + } + + object SingleNoProduct { + def unapply(x: Any): SingleNoProduct = new SingleNoProduct(x) + } +} + package p1 { class Triple(val x: Any) extends AnyRef with Product3[String, String, String] { private def s = "" + x @@ -49,14 +77,16 @@ package p3 { } object Test { - - // def f(x: Any) = x match { - // case p1.Foo(x, y, z) => println((x, y, z)) - // case x => println(x) - // } - def main(args: Array[String]): Unit = { "catdog" match { + case p0.Single(x) => println(s"`${x._1}` has ${x._1.length} chars") + case x => println("fail: " + x) + } + "catdog" match { + case p0.SingleNoProduct(x) => println(s"`$x` has ${x.length} chars") + case x => println("fail: " + x) + } + "catdog" match { case p1.Triple(x, y, z) => List(x, y, z) foreach println case x => println("fail: " + x) } diff --git a/test/files/run/numbereq.scala b/test/files/run/numbereq.scala index d50db6d049..7ce4b23cf8 100644 --- a/test/files/run/numbereq.scala +++ b/test/files/run/numbereq.scala @@ -31,6 +31,24 @@ object Test { ).flatten } + // Don't necessarily expect BigDecimal created from BigInt to agree with Double here. + def isIffy(x: Any, y: Any, canSwap: Boolean = true): Boolean = x match { + case bd: BigDecimal => y match { + case _: Float | _: Double => bd.toString.length > 15 + case _ => false + } + case _ => canSwap && isIffy(y, x, false) + } + + // Don't necessarily expect BigInt to agree with Float/Double beyond a Long + def isIffyB(x: Any, y: Any, canSwap: Boolean = true): Boolean = x match { + case bi: BigInt => y match { + case _: Float | _: Double => bi < Long.MinValue || bi > Long.MaxValue + case _ => false + } + case _ => canSwap && isIffyB(y, x, false) + } + def main(args: Array[String]): Unit = { val ints = (0 to 15).toList map (Short.MinValue >> _) val ints2 = ints map (x => -x) @@ -46,7 +64,6 @@ object Test { val sets = setneg1 ++ setneg2 ++ List(zero) ++ setpos1 ++ setpos2 for (set <- sets ; x <- set ; y <- set) { - // println("'%s' == '%s' (%s == %s) (%s == %s)".format(x, y, x.hashCode, y.hashCode, x.##, y.##)) assert(x == y, "%s/%s != %s/%s".format(x, x.getClass, y, y.getClass)) assert(x.## == y.##, "%s != %s".format(x.getClass, y.getClass)) } @@ -64,9 +81,11 @@ object Test { val sets2 = setneg1 ++ setneg1b ++ setneg2 ++ setneg2b ++ List(zero) ++ setpos1 ++ setpos1b ++ setpos2 ++ setpos2b for (set <- sets2 ; x <- set ; y <- set) { -// println("'%s' == '%s' (%s == %s) (%s == %s)".format(x, y, x.hashCode, y.hashCode, x.##, y.##)) - assert(x == y, "%s/%s != %s/%s".format(x, x.getClass, y, y.getClass)) -// assert(x.## == y.##, "%s != %s".format(x.getClass, y.getClass)) Disable until Double.## is fixed (SI-5640) + if (!isIffy(x,y)) { + assert(x == y, "%s/%s != %s/%s".format(x, x.getClass, y, y.getClass)) + // The following is blocked by SI-8150 + // if (!isIffyB(x,y)) assert(x.## == y.##, "%x/%s != %x/%s from %s.## and %s.##".format(x.##, x.getClass, y.##, y.getClass, x, y)) + } } } } diff --git a/test/files/run/partialfun.scala b/test/files/run/partialfun.scala index f3c53b94ae..71c7d3e61c 100644 --- a/test/files/run/partialfun.scala +++ b/test/files/run/partialfun.scala @@ -76,7 +76,7 @@ object Test { } val chained = pf0 orElse pf1 orElse pf2 - chained() + chained(()) } def main(args: Array[String]): Unit = { diff --git a/test/files/run/patmat-mix-case-extractor.check b/test/files/run/patmat-mix-case-extractor.check new file mode 100644 index 0000000000..a6e1bd23df --- /dev/null +++ b/test/files/run/patmat-mix-case-extractor.check @@ -0,0 +1,8 @@ +-1 +6 +4 +18 +-1 +1006 +1004 +1018 diff --git a/test/files/run/patmat-mix-case-extractor.scala b/test/files/run/patmat-mix-case-extractor.scala new file mode 100644 index 0000000000..964e6f743c --- /dev/null +++ b/test/files/run/patmat-mix-case-extractor.scala @@ -0,0 +1,110 @@ +trait CaseClass +trait ProdCaseClass extends CaseClass { def x: Int } +trait SeqCaseClass extends CaseClass { def xs: Seq[Int] } + +case class CaseClass1() extends CaseClass +case class CaseClass2(xs: Int*) extends SeqCaseClass +case class CaseClass3(x: Int) extends ProdCaseClass +case class CaseClass4(x: Int, xs: Int*) extends ProdCaseClass with SeqCaseClass + +object Extractor1 { def unapply(x: CaseClass): Boolean = false } +object Extractor2 { def unapplySeq(x: SeqCaseClass): Option[Seq[Int]] = Some(x.xs) } +object Extractor3 { def unapply(x: ProdCaseClass): Option[Int] = Some(x.x) } +object Extractor4 { def unapplySeq(x: ProdCaseClass with SeqCaseClass): Option[(Int, Seq[Int])] = Some(x.x, x.xs) } + +class A { + def f1(x: Any) = x match { + case CaseClass1() => -1 + case CaseClass2(xs @ _*) => xs.sum + case CaseClass3(x) => x + case CaseClass4(x, xs @ _*) => x + xs.sum + case Extractor4(x, xs @ _*) => 1000 + x + xs.sum + case Extractor3(x) => 1000 + x + case Extractor2(xs @ _*) => 1000 + xs.sum + case Extractor1() => -3 + case _ => -2 + } + def f2(x: Any) = x match { + case Extractor4(x, xs @ _*) => 1000 + x + xs.sum + case Extractor3(x) => 1000 + x + case Extractor2(xs @ _*) => 1000 + xs.sum + case Extractor1() => -3 + case CaseClass1() => -1 + case CaseClass2(xs @ _*) => xs.sum + case CaseClass3(x) => x + case CaseClass4(x, xs @ _*) => x + xs.sum + case _ => -2 + } + def run() { + List( + f1(CaseClass1()), + f1(CaseClass2(1, 2, 3)), + f1(CaseClass3(4)), + f1(CaseClass4(5, 6, 7)), + f2(CaseClass1()), + f2(CaseClass2(1, 2, 3)), + f2(CaseClass3(4)), + f2(CaseClass4(5, 6, 7)) + ) foreach println + } +} + +object Test { + def main(args: Array[String]): Unit = { + (new A).run + } +} + + +class B { + case class CaseClass0() + case class CaseClass0v(xs: Int*) + + case class CaseClass(x: Int, y: Int) + object Extractor { def unapply(x: Any): Option[(Int, Int)] = Some((1, 1)) } + + case class CaseSeq(x: Char, y: Double, zs: Int*) + object ExtractorSeq { def unapplySeq(x: Any): Option[(Int, Int, Seq[Int])] = Some((1, 1, List(1))) } + + def f1(x: CaseClass) = x match { case CaseClass(y, z) => y } + def f2(x: Any) = x match { case Extractor(y, z) => y } + + def f3(x: CaseSeq) = x match { + case CaseSeq(x, y) => y + case CaseSeq(x, y, z) => z + } + def f4(x: CaseSeq) = x match { + case CaseSeq(x, y, z) => z :: Nil + case CaseSeq(x, y, z @ _*) => z + } + + def f5(x: Any) = x match { case ExtractorSeq(x, y, z) => z } + def f6(x: Any) = x match { case ExtractorSeq(x, y, z @ _*) => z } + + def g1(x: CaseClass0) = x match { + case CaseClass0() => true + } + def g2(x: CaseClass0v) = x match { + case CaseClass0v() => true + case CaseClass0v(5) => true + case CaseClass0v(x) => true + case CaseClass0v(xs @ _*) => false + } +} + +package p1 { + trait _X { + case class _Foo(); + object _Bar { + def unapply(foo: _Foo): Boolean = true; + } + } + + object Y extends _X { + val foo = _Foo() + foo match { + case _Bar() => + case _ => assert(false) + } + } +} diff --git a/test/files/run/private-override.scala b/test/files/run/private-override.scala deleted file mode 100644 index 0a3f57f97c..0000000000 --- a/test/files/run/private-override.scala +++ /dev/null @@ -1,17 +0,0 @@ -package test.p1.p2 { - abstract class A { - private[p2] def f2(): Int = 1 - } - abstract class Other extends A { - // It's a private method - not a private[p2] method. Not a failed - // "weaker access privileges" override, a different namespace. - private def f2(): Int = super.f2() + 2 - def go() = f2() - } -} - -object Test extends test.p1.p2.Other { - def main(args: Array[String]): Unit = { - println(go()) - } -} diff --git a/test/files/run/reflection-magicsymbols-invoke.check b/test/files/run/reflection-magicsymbols-invoke.check index 352aefaf25..b153ae0470 100644 --- a/test/files/run/reflection-magicsymbols-invoke.check +++ b/test/files/run/reflection-magicsymbols-invoke.check @@ -28,7 +28,7 @@ it's important to print the list of AnyVal's members if some of them change (possibly, adding and/or removing magic symbols), we must update this test constructor AnyVal: ()AnyVal method getClass: ()Class[_ <: AnyVal] -testing AnyVal.<init>: class java.lang.InstantiationException: null +testing AnyVal.<init>: class scala.ScalaReflectionException: unsupported symbol constructor AnyVal when invoking bytecodeless method mirror for scala.AnyVal.<init>(): AnyVal (bound to null) testing AnyVal.getClass: class scala.ScalaReflectionException: expected a member of class Integer, you provided method scala.AnyVal.getClass ============ AnyRef @@ -36,12 +36,10 @@ it's important to print the list of AnyRef's members if some of them change (possibly, adding and/or removing magic symbols), we must update this test constructor Object: ()java.lang.Object method !=: (x$1: Any)Boolean -method !=: (x$1: AnyRef)Boolean method ##: ()Int method $asInstanceOf: [T0]()T0 method $isInstanceOf: [T0]()Boolean method ==: (x$1: Any)Boolean -method ==: (x$1: AnyRef)Boolean method asInstanceOf: [T0]=> T0 method clone: ()java.lang.Object method eq: (x$1: AnyRef)Boolean @@ -82,14 +80,11 @@ Array it's important to print the list of Array's members if some of them change (possibly, adding and/or removing magic symbols), we must update this test constructor Array: (_length: Int)Array[T] -constructor Cloneable: ()java.lang.Cloneable method !=: (x$1: Any)Boolean -method !=: (x$1: AnyRef)Boolean method ##: ()Int method $asInstanceOf: [T0]()T0 method $isInstanceOf: [T0]()Boolean method ==: (x$1: Any)Boolean -method ==: (x$1: AnyRef)Boolean method apply: (i: Int)T method asInstanceOf: [T0]=> T0 method clone: ()Array[T] diff --git a/test/files/run/reflection-sorted-members.check b/test/files/run/reflection-sorted-members.check index c148e19e69..415e073149 100644 --- a/test/files/run/reflection-sorted-members.check +++ b/test/files/run/reflection-sorted-members.check @@ -1,4 +1,3 @@ value a value b value c -value x diff --git a/test/files/run/reflection-sync-potpourri.scala b/test/files/run/reflection-sync-potpourri.scala index 0ad5f2ab66..0c96974df7 100644 --- a/test/files/run/reflection-sync-potpourri.scala +++ b/test/files/run/reflection-sync-potpourri.scala @@ -24,7 +24,7 @@ object Test extends App { override def run(): Unit = { val s1 = foo("42") val s2 = perms(diceRolls(i - 1)).map(x => force(x)).sorted.mkString(", ") - assert(s1 == "java.lang.String") + assert(s1 == "String" || s1 == "java.lang.String") assert(s2 == "java.lang.annotation.Annotation, java.lang.reflect.Method, scala.io.BufferedSource, scala.io.Codec") } }) diff --git a/test/files/run/reify_ann3.check b/test/files/run/reify_ann3.check index d4cf660758..4f1c61cf0e 100644 --- a/test/files/run/reify_ann3.check +++ b/test/files/run/reify_ann3.check @@ -1,5 +1,5 @@ { - class Tree[A, B] extends AnyRef { + class Tree[A, +B] extends AnyRef { @new inline @getter() final <paramaccessor> val key: A = _; def <init>(key: A) = { super.<init>(); @@ -9,7 +9,7 @@ () } { - class Tree[A, B] extends AnyRef { + class Tree[A, +B] extends AnyRef { final <paramaccessor> private[this] val key: A = _; @inline @scala.annotation.meta.getter final <stable> <accessor> <paramaccessor> def key: A = Tree.this.key; def <init>(key: A): Tree[A,B] = { diff --git a/test/files/run/repl-term-macros.check b/test/files/run/repl-term-macros.check index f73abb5dc3..3580bfe1f1 100644 --- a/test/files/run/repl-term-macros.check +++ b/test/files/run/repl-term-macros.check @@ -1,16 +1,16 @@ Type in expressions to have them evaluated. Type :help for more information. -scala> import scala.reflect.macros.BlackboxContext -import scala.reflect.macros.BlackboxContext +scala> import scala.reflect.macros.blackbox.Context +import scala.reflect.macros.blackbox.Context scala> import language.experimental.macros import language.experimental.macros scala> -scala> def impl1(c: BlackboxContext) = { import c.universe._; c.Expr[Unit](q"()") } -impl1: (c: scala.reflect.macros.BlackboxContext)c.Expr[Unit] +scala> def impl1(c: Context) = { import c.universe._; c.Expr[Unit](q"()") } +impl1: (c: scala.reflect.macros.blackbox.Context)c.Expr[Unit] scala> def foo1: Unit = macro impl1 defined term macro foo1: Unit @@ -19,8 +19,8 @@ scala> foo1 scala> -scala> def impl2(c: BlackboxContext)() = { import c.universe._; c.Expr[Unit](q"()") } -impl2: (c: scala.reflect.macros.BlackboxContext)()c.Expr[Unit] +scala> def impl2(c: Context)() = { import c.universe._; c.Expr[Unit](q"()") } +impl2: (c: scala.reflect.macros.blackbox.Context)()c.Expr[Unit] scala> def foo2(): Unit = macro impl2 defined term macro foo2: ()Unit @@ -29,8 +29,8 @@ scala> foo2() scala> -scala> def impl3(c: BlackboxContext)(x: c.Expr[Int])(y: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"()") } -impl3: (c: scala.reflect.macros.BlackboxContext)(x: c.Expr[Int])(y: c.Expr[Int])c.Expr[Unit] +scala> def impl3(c: Context)(x: c.Expr[Int])(y: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"()") } +impl3: (c: scala.reflect.macros.blackbox.Context)(x: c.Expr[Int])(y: c.Expr[Int])c.Expr[Unit] scala> def foo3(x: Int)(y: Int): Unit = macro impl3 defined term macro foo3: (x: Int)(y: Int)Unit diff --git a/test/files/run/repl-term-macros.scala b/test/files/run/repl-term-macros.scala index b4660e258e..32892b7314 100644 --- a/test/files/run/repl-term-macros.scala +++ b/test/files/run/repl-term-macros.scala @@ -2,18 +2,18 @@ import scala.tools.partest.ReplTest object Test extends ReplTest { def code = """ - import scala.reflect.macros.BlackboxContext + import scala.reflect.macros.blackbox.Context import language.experimental.macros -def impl1(c: BlackboxContext) = { import c.universe._; c.Expr[Unit](q"()") } +def impl1(c: Context) = { import c.universe._; c.Expr[Unit](q"()") } def foo1: Unit = macro impl1 foo1 -def impl2(c: BlackboxContext)() = { import c.universe._; c.Expr[Unit](q"()") } +def impl2(c: Context)() = { import c.universe._; c.Expr[Unit](q"()") } def foo2(): Unit = macro impl2 foo2() -def impl3(c: BlackboxContext)(x: c.Expr[Int])(y: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"()") } +def impl3(c: Context)(x: c.Expr[Int])(y: c.Expr[Int]) = { import c.universe._; c.Expr[Unit](q"()") } def foo3(x: Int)(y: Int): Unit = macro impl3 foo3(2)(3) """ diff --git a/test/files/run/resetattrs-this.scala b/test/files/run/resetattrs-this.scala index 6150a4e265..ff45d61dfe 100644 --- a/test/files/run/resetattrs-this.scala +++ b/test/files/run/resetattrs-this.scala @@ -6,6 +6,6 @@ object Test extends App { val tb = cm.mkToolBox() val tree = Select(This(cm.staticPackage("scala").moduleClass), TermName("Predef")) val ttree = tb.typecheck(tree) - val rttree = tb.resetAllAttrs(ttree) + val rttree = tb.untypecheck(ttree) println(tb.eval(rttree) == Predef) } diff --git a/test/files/run/stringinterpolation_macro-run.check b/test/files/run/stringinterpolation_macro-run.check index be62c5780b..ead61e76ac 100644 --- a/test/files/run/stringinterpolation_macro-run.check +++ b/test/files/run/stringinterpolation_macro-run.check @@ -46,6 +46,8 @@ S 120 120 120 + 0X4 +She is 4 feet tall. 120 42 3.400000e+00 @@ -60,3 +62,6 @@ S 05/26/12 05/26/12 05/26/12 +% +7 7 9 +7 9 9 diff --git a/test/files/run/stringinterpolation_macro-run.scala b/test/files/run/stringinterpolation_macro-run.scala index 1138cd0860..ff779dd1d3 100644 --- a/test/files/run/stringinterpolation_macro-run.scala +++ b/test/files/run/stringinterpolation_macro-run.scala @@ -72,6 +72,14 @@ println(f"${120 : java.lang.Integer}%d") println(f"${120 : java.lang.Long}%d") println(f"${BigInt(120)}%d") println(f"${new java.math.BigInteger("120")}%d") +println(f"${4}%#10X") + +locally { + val fff = new java.util.Formattable { + def formatTo(f: java.util.Formatter, g: Int, w: Int, p: Int) = f.format("4") + } + println(f"She is ${fff}%#s feet tall.") +} { implicit val strToShort = (s: String) => java.lang.Short.parseShort(s) @@ -103,4 +111,11 @@ println(f"${c.getTime.getTime}%TD") implicit val strToDate = (x: String) => c println(f"""${"1234"}%TD""") + + +// literals and arg indexes +println(f"%%") +println(f"${7}%d %<d ${9}%d") +println(f"${7}%d %2$$d ${9}%d") + } diff --git a/test/files/run/t261.check b/test/files/run/t261.check new file mode 100644 index 0000000000..35d242ba79 --- /dev/null +++ b/test/files/run/t261.check @@ -0,0 +1,2 @@ +A +B diff --git a/test/files/run/t261.scala b/test/files/run/t261.scala new file mode 100644 index 0000000000..d8ddb28c00 --- /dev/null +++ b/test/files/run/t261.scala @@ -0,0 +1,11 @@ +trait A { val foo: String = "A" } +trait B { + private val foo: String = "B" + def f = println(foo) +} +object Test extends A with B { + def main(args: Array[String]) = { + println(foo) + f + } +}
\ No newline at end of file diff --git a/test/files/run/t5256h.check b/test/files/run/t5256h.check index 1a4a92a684..dc3e919897 100644 --- a/test/files/run/t5256h.check +++ b/test/files/run/t5256h.check @@ -3,5 +3,5 @@ Test.$anon$1 java.lang.Object { final private val x: Int def x(): Int - def <init>(): java.lang.Object{def x(): Int} + def <init>(): $anon$1 } diff --git a/test/files/run/t5629b.check b/test/files/run/t5629b.check index 1bc0248c3d..e0f25f0b05 100644 --- a/test/files/run/t5629b.check +++ b/test/files/run/t5629b.check @@ -2,7 +2,7 @@ MySmartPF.apply entered... newPF.applyOrElse entered... default -scala.MatchError: () (of class scala.runtime.BoxedUnit) +scala.MatchError: 1 (of class java.lang.Integer) === pf(42): MySmartPF.apply entered... newPF.applyOrElse entered... diff --git a/test/files/run/t5629b.scala b/test/files/run/t5629b.scala index 9ff29c8d89..5d402201ae 100644 --- a/test/files/run/t5629b.scala +++ b/test/files/run/t5629b.scala @@ -1,8 +1,3 @@ - - - - - object Test extends App { trait MyPF[@specialized(Int) -A] extends (A => Unit) { @@ -16,7 +11,7 @@ object Test extends App { trait MySmartPF[@specialized(Int) -A] extends MyPF[A] { def apply(x: A): Unit = { println("MySmartPF.apply entered...") - applyOrElse(x, { _: Any => throw new MatchError }) + applyOrElse(x, { default: Any => throw new MatchError(default) }) } } diff --git a/test/files/run/t5713/Impls_Macros_1.scala b/test/files/run/t5713/Impls_Macros_1.scala index bfe2fc4efd..7b04197cfa 100644 --- a/test/files/run/t5713/Impls_Macros_1.scala +++ b/test/files/run/t5713/Impls_Macros_1.scala @@ -1,7 +1,7 @@ package m import language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Level extends Enumeration { val Error = Value(5) @@ -13,7 +13,7 @@ object Logger { private object LoggerMacros { - type LoggerContext = BlackboxContext { type PrefixType = Logger.type } + type LoggerContext = Context { type PrefixType = Logger.type } def error(c: LoggerContext)(message: c.Expr[String]): c.Expr[Unit] = log(c)(c.universe.reify(Level.Error), message) diff --git a/test/files/run/t5753_1/Impls_Macros_1.scala b/test/files/run/t5753_1/Impls_Macros_1.scala index 3ddff56c38..ce07138852 100644 --- a/test/files/run/t5753_1/Impls_Macros_1.scala +++ b/test/files/run/t5753_1/Impls_Macros_1.scala @@ -1,8 +1,8 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros trait Impls { - def impl(c: BlackboxContext)(x: c.Expr[Any]) = x + def impl(c: Context)(x: c.Expr[Any]) = x } object Macros extends Impls { diff --git a/test/files/run/t5753_2/Impls_Macros_1.scala b/test/files/run/t5753_2/Impls_Macros_1.scala index c95c9a41b3..d446d37bdf 100644 --- a/test/files/run/t5753_2/Impls_Macros_1.scala +++ b/test/files/run/t5753_2/Impls_Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{BlackboxContext => Ctx} +import scala.reflect.macros.blackbox.Context trait Macro_T { - def foo[T](c: Ctx)(s: c.Expr[T]) = s + def foo[T](c: Context)(s: c.Expr[T]) = s } object Macros { diff --git a/test/files/run/t576.check b/test/files/run/t576.check index 8a1218a102..6458d5d743 100644 --- a/test/files/run/t576.check +++ b/test/files/run/t576.check @@ -1,3 +1,4 @@ +warning: there were 1 deprecation warning(s); re-run with -deprecation for details 1 2 3 diff --git a/test/files/run/t5894.scala b/test/files/run/t5894.scala index 5d482333f5..6e118fd396 100644 --- a/test/files/run/t5894.scala +++ b/test/files/run/t5894.scala @@ -1,10 +1,11 @@ -import language.experimental.macros +import scala.reflect.macros.blackbox.Context +import scala.language.experimental.macros class Test object Test { def foo: Unit = macro fooImpl - def fooImpl(c: reflect.macros.BlackboxContext) = { import c.universe._; c.Expr[Unit](q"()") } + def fooImpl(c: Context) = { import c.universe._; c.Expr[Unit](q"()") } def main(args: Array[String]) { try { diff --git a/test/files/run/t5903a/Macros_1.scala b/test/files/run/t5903a/Macros_1.scala index ce1b035260..5d084ceed5 100644 --- a/test/files/run/t5903a/Macros_1.scala +++ b/test/files/run/t5903a/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import language.experimental.macros trait Tree @@ -13,7 +13,7 @@ object NewQuasiquotes { } object QuasiquoteMacros { - def unapplyImpl(c: WhiteboxContext)(t: c.Tree) = { + def unapplyImpl(c: Context)(t: c.Tree) = { import c.universe._ q""" new { diff --git a/test/files/run/t5903b/Macros_1.scala b/test/files/run/t5903b/Macros_1.scala index 97f15cec3b..29a05f7fec 100644 --- a/test/files/run/t5903b/Macros_1.scala +++ b/test/files/run/t5903b/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import language.experimental.macros object Interpolation { @@ -10,7 +10,7 @@ object Interpolation { } object Macros { - def unapplyImpl[T: c.WeakTypeTag](c: WhiteboxContext)(x: c.Tree) = { + def unapplyImpl[T: c.WeakTypeTag](c: Context)(x: c.Tree) = { import c.universe._ q""" new { diff --git a/test/files/run/t5903c/Macros_1.scala b/test/files/run/t5903c/Macros_1.scala index 979284a263..34fe1d8808 100644 --- a/test/files/run/t5903c/Macros_1.scala +++ b/test/files/run/t5903c/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import language.experimental.macros object Interpolation { @@ -10,7 +10,7 @@ object Interpolation { } object Macros { - def unapplyImpl[T: c.WeakTypeTag](c: WhiteboxContext)(x: c.Tree) = { + def unapplyImpl[T: c.WeakTypeTag](c: Context)(x: c.Tree) = { import c.universe._ q""" new { diff --git a/test/files/run/t5903d/Macros_1.scala b/test/files/run/t5903d/Macros_1.scala index dc1989462b..f1f8dc1fde 100644 --- a/test/files/run/t5903d/Macros_1.scala +++ b/test/files/run/t5903d/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import language.experimental.macros object Interpolation { @@ -10,7 +10,7 @@ object Interpolation { } object Macros { - def unapplyImpl(c: WhiteboxContext)(x: c.Tree) = { + def unapplyImpl(c: Context)(x: c.Tree) = { import c.universe._ q""" new { diff --git a/test/files/run/t5923a/Macros_1.scala b/test/files/run/t5923a/Macros_1.scala index 445392ff95..9aa7a02708 100644 --- a/test/files/run/t5923a/Macros_1.scala +++ b/test/files/run/t5923a/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import language.experimental.macros case class C[T](t: String) @@ -7,7 +7,7 @@ object C { } object Macros { - def impl[T](c: WhiteboxContext)(ttag: c.WeakTypeTag[T]) = { + def impl[T](c: Context)(ttag: c.WeakTypeTag[T]) = { import c.universe._ val ttag0 = ttag; { diff --git a/test/files/run/t5923d/Macros_1.scala b/test/files/run/t5923d/Macros_1.scala index b6e7134b95..1400674d4b 100644 --- a/test/files/run/t5923d/Macros_1.scala +++ b/test/files/run/t5923d/Macros_1.scala @@ -1,9 +1,9 @@ import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context trait MappedRow trait RowMapper[T <: MappedRow] object RowMapper { implicit def mapper[T <: MappedRow]: RowMapper[T] = macro impl[T] - def impl[T <: MappedRow : c.WeakTypeTag](c: BlackboxContext) = c.universe.reify(new RowMapper[T]{}) + def impl[T <: MappedRow : c.WeakTypeTag](c: Context) = c.universe.reify(new RowMapper[T]{}) }
\ No newline at end of file diff --git a/test/files/run/t5940.scala b/test/files/run/t5940.scala index 062f11c467..7b025b43af 100644 --- a/test/files/run/t5940.scala +++ b/test/files/run/t5940.scala @@ -4,15 +4,15 @@ object Test extends DirectTest { def code = ??? def macros_1 = """ - import scala.reflect.macros.BlackboxContext + import scala.reflect.macros.blackbox.Context object Impls { - def impl(c: BlackboxContext) = { import c.universe._; c.Expr[Unit](q"()") } + def impl(c: Context) = { import c.universe._; c.Expr[Unit](q"()") } } object Macros { //import Impls._ - def impl(c: BlackboxContext) = { import c.universe._; c.Expr[Unit](q"()") } + def impl(c: Context) = { import c.universe._; c.Expr[Unit](q"()") } def foo: Unit = macro impl } """ diff --git a/test/files/run/t6187.check b/test/files/run/t6187.check index c833b45443..0180125809 100644 --- a/test/files/run/t6187.check +++ b/test/files/run/t6187.check @@ -1,15 +1,15 @@ Type in expressions to have them evaluated. Type :help for more information. -scala> import language.experimental.macros, reflect.macros.BlackboxContext -import language.experimental.macros -import reflect.macros.BlackboxContext +scala> import scala.language.experimental.macros, scala.reflect.macros.blackbox.Context +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.Context -scala> def macroImpl[T: c.WeakTypeTag](c: BlackboxContext)(t: c.Expr[T]): c.Expr[List[T]] = { +scala> def macroImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[List[T]] = { val r = c.universe.reify { List(t.splice) } - c.Expr[List[T]]( c.resetLocalAttrs(r.tree) ) + c.Expr[List[T]]( c.untypecheck(r.tree) ) } -macroImpl: [T](c: scala.reflect.macros.BlackboxContext)(t: c.Expr[T])(implicit evidence$1: c.WeakTypeTag[T])c.Expr[List[T]] +macroImpl: [T](c: scala.reflect.macros.blackbox.Context)(t: c.Expr[T])(implicit evidence$1: c.WeakTypeTag[T])c.Expr[List[T]] scala> def demo[T](t: T): List[T] = macro macroImpl[T] defined term macro demo: [T](t: T)List[T] diff --git a/test/files/run/t6187.scala b/test/files/run/t6187.scala index fc6fa6e9a7..7a39cfd9e7 100644 --- a/test/files/run/t6187.scala +++ b/test/files/run/t6187.scala @@ -2,10 +2,10 @@ import scala.tools.partest.ReplTest object Test extends ReplTest { override def code = """ -import language.experimental.macros, reflect.macros.BlackboxContext -def macroImpl[T: c.WeakTypeTag](c: BlackboxContext)(t: c.Expr[T]): c.Expr[List[T]] = { +import scala.language.experimental.macros, scala.reflect.macros.blackbox.Context +def macroImpl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[List[T]] = { val r = c.universe.reify { List(t.splice) } - c.Expr[List[T]]( c.resetLocalAttrs(r.tree) ) + c.Expr[List[T]]( c.untypecheck(r.tree) ) } def demo[T](t: T): List[T] = macro macroImpl[T] def m[T](t: T): List[List[T]] = diff --git a/test/files/run/t6196.scala b/test/files/run/t6196.scala new file mode 100644 index 0000000000..16c2c7409d --- /dev/null +++ b/test/files/run/t6196.scala @@ -0,0 +1,68 @@ +import scala.collection.immutable.HashSet + +object Test extends App { + + case class Collision(value: Int) extends Ordered[Collision] { + def compare(that:Collision) = value compare that.value + + override def hashCode = value / 5 + } + + def testCorrectness[T : Ordering](n: Int, mkKey: Int => T) { + val o = implicitly[Ordering[T]] + val s = HashSet.empty[T] ++ (0 until n).map(mkKey) + for (i <- 0 until n) { + val ki = mkKey(i) + val a = s.filter(o.lt(_,ki)) + val b = s.filterNot(o.lt(_,ki)) + require(a.size == i && (0 until i).forall(i => a.contains(mkKey(i)))) + require(b.size == n - i && (i until n).forall(i => b.contains(mkKey(i)))) + } + } + + // this tests the structural sharing of the new filter + // I could not come up with a simple test that tests structural sharing when only parts are reused, but + // at least this fails with the old and passes with the new implementation + def testSharing() { + val s = HashSet.empty[Int] ++ (0 until 100) + require(s.filter(_ => true) eq s) + require(s.filterNot(_ => false) eq s) + } + + // this tests that neither hashCode nor equals are called during filter + def testNoHashing() { + var hashCount = 0 + var equalsCount = 0 + case class HashCounter(value:Int) extends Ordered[HashCounter] { + def compare(that:HashCounter) = value compare that.value + + override def hashCode = { + hashCount += 1 + value + } + + override def equals(that:Any) = { + equalsCount += 1 + this match { + case HashCounter(value) => this.value == value + case _ => false + } + } + } + + val s = HashSet.empty[HashCounter] ++ (0 until 100).map(HashCounter) + val hashCount0 = hashCount + val equalsCount0 = equalsCount + val t = s.filter(_<HashCounter(50)) + require(hashCount == hashCount0) + require(equalsCount == equalsCount0) + } + + // this tests correctness of filter and filterNot for integer keys + testCorrectness[Int](100, identity _) + // this tests correctness of filter and filterNot for keys with lots of collisions + // this is necessary because usually collisions are rare so the collision-related code is not thoroughly tested + testCorrectness[Collision](100, Collision.apply _) + testSharing() + testNoHashing() +} diff --git a/test/files/run/t6200.scala b/test/files/run/t6200.scala new file mode 100644 index 0000000000..9a5d91e042 --- /dev/null +++ b/test/files/run/t6200.scala @@ -0,0 +1,68 @@ +import scala.collection.immutable.HashMap + +object Test extends App { + + case class Collision(value: Int) extends Ordered[Collision] { + def compare(that: Collision) = value compare that.value + + override def hashCode = value / 5 + } + + def testCorrectness[T: Ordering](n: Int, mkKey: Int => T) { + val o = implicitly[Ordering[T]] + val s = HashMap.empty[T, Unit] ++ (0 until n).map(x => mkKey(x) -> (())) + for (i <- 0 until n) { + val ki = mkKey(i) + val a = s.filter(kv => o.lt(kv._1, ki)) + val b = s.filterNot(kv => o.lt(kv._1, ki)) + require(a.size == i && (0 until i).forall(i => a.contains(mkKey(i)))) + require(b.size == n - i && (i until n).forall(i => b.contains(mkKey(i)))) + } + } + + // this tests the structural sharing of the new filter + // I could not come up with a simple test that tests structural sharing when only parts are reused, but + // at least this fails with the old and passes with the new implementation + def testSharing() { + val s = HashMap.empty[Int, Unit] ++ (0 until 100).map(_ -> (())) + require(s.filter(_ => true) eq s) + require(s.filterNot(_ => false) eq s) + } + + // this tests that neither hashCode nor equals are called during filter + def testNoHashing() { + var hashCount = 0 + var equalsCount = 0 + case class HashCounter(value: Int) extends Ordered[HashCounter] { + def compare(that: HashCounter) = value compare that.value + + override def hashCode = { + hashCount += 1 + value + } + + override def equals(that: Any) = { + equalsCount += 1 + this match { + case HashCounter(value) => this.value == value + case _ => false + } + } + } + + val s = HashMap.empty[HashCounter, Unit] ++ (0 until 100).map(k => HashCounter(k) -> (())) + val hashCount0 = hashCount + val equalsCount0 = equalsCount + val t = s.filter(_._1 < HashCounter(50)) + require(hashCount == hashCount0) + require(equalsCount == equalsCount0) + } + + // this tests correctness of filter and filterNot for integer keys + testCorrectness[Int](100, identity _) + // this tests correctness of filter and filterNot for keys with lots of collisions + // this is necessary because usually collisions are rare so the collision-related code is not thoroughly tested + testCorrectness[Collision](100, Collision.apply _) + testSharing() + testNoHashing() +} diff --git a/test/files/run/t6221/Macros_1.scala b/test/files/run/t6221/Macros_1.scala index 60ed0aa3e3..b5c28360fa 100644 --- a/test/files/run/t6221/Macros_1.scala +++ b/test/files/run/t6221/Macros_1.scala @@ -1,6 +1,6 @@ import language.experimental.macros import language.implicitConversions -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import scala.reflect.runtime.universe.Tree class ReflectiveClosure[A, B](val tree: Tree, fn: A => B) extends (A => B) { @@ -12,7 +12,7 @@ object ReflectiveClosure { } object Macros { - def reflectiveClosureImpl[A, B](c: BlackboxContext)(f: c.Expr[A => B]): c.Expr[ReflectiveClosure[A, B]] = { + def reflectiveClosureImpl[A, B](c: Context)(f: c.Expr[A => B]): c.Expr[ReflectiveClosure[A, B]] = { import c.universe._ val u = treeBuild.mkRuntimeUniverseRef val m = EmptyTree diff --git a/test/files/run/t6253a.scala b/test/files/run/t6253a.scala new file mode 100644 index 0000000000..efa3230df6 --- /dev/null +++ b/test/files/run/t6253a.scala @@ -0,0 +1,64 @@ +import scala.collection.immutable.HashSet + +object Test extends App { + + var hashCount = 0 + + /** + * A key that produces lots of hash collisions, to exercise the part of the code that deals with those + */ + case class Collision(value: Int) { + + override def hashCode = { + // we do not check hash counts for Collision keys because ListSet.++ uses a mutable hashset internally, + // so when we have hash collisions, union will call key.hashCode. + // hashCount += 1 + value / 5 + } + } + + /** + * A key that is identical to int other than that it counts hashCode invocations + */ + case class HashCounter(value: Int) { + + override def hashCode = { + hashCount += 1 + value + } + } + + def testUnion[T](sizes: Seq[Int], offsets: Seq[Double], keyType: String, mkKey: Int => T) { + for { + i <- sizes + o <- offsets + } { + val e = HashSet.empty[T] + val j = (i * o).toInt + // create two sets of size i with overlap o + val a = e ++ (0 until i).map(mkKey) + require(a.size == i, s"Building HashSet of size $i failed. Key type $keyType.") + val b = e ++ (j until (i + j)).map(mkKey) + require(b.size == i, s"Building HashSet of size $i failed. Key type $keyType.") + val as = e ++ (0 until j).map(mkKey) + require(as.size == j, s"Building HashSet of size $j failed. Key type $keyType.") + val hashCount0 = hashCount + val u = a union b + require(hashCount == hashCount0, s"key.hashCode should not be called, but has been called ${hashCount - hashCount0} times. Key type $keyType.") + require(u == (a union scala.collection.mutable.HashSet(b.toSeq: _*)), s"Operation must still work for other sets!") + require(u.size == i + j, s"Expected size ${i+j}. Real size ${u.size}. Key type $keyType.") + for (x <- 0 until i + j) + require(u.contains(mkKey(x)), s"Key type $keyType. Set (0 until ${i + j}) should contain $x but does not.") + val a_as = a union as + val as_a = as union a + require((a_as eq a) || (a_as eq as), s"No structural sharing in a union as. Key type $keyType, a=(0 until $i) as=(0 until $j)") + require((as_a eq a) || (as_a eq as), s"No structural sharing in as union a. Key type $keyType, a=(0 until $i) as=(0 until $j)") + } + } + + val sizes = Seq(1, 10, 100, 1000, 10000, 100000) + val offsets = Seq(0.0, 0.25, 0.5, 0.75, 1.0) + testUnion(sizes, offsets, "int", identity[Int]) + testUnion(sizes, offsets, "hashcounter", HashCounter.apply) + testUnion(sizes, offsets, "collision", Collision.apply) +} diff --git a/test/files/run/t6253b.scala b/test/files/run/t6253b.scala new file mode 100644 index 0000000000..9cbfefd49e --- /dev/null +++ b/test/files/run/t6253b.scala @@ -0,0 +1,62 @@ +import scala.collection.immutable.HashSet + +object Test extends App { + + var hashCount = 0 + + /** + * A key that produces lots of hash collisions, to exercise the part of the code that deals with those + */ + case class Collision(value: Int) { + + override def hashCode = { + hashCount += 1 + value / 5 + } + } + + /** + * A key that is identical to int other than that it counts hashCode invocations + */ + case class HashCounter(value: Int) { + + override def hashCode = { + hashCount += 1 + value + } + } + + def testIntersect[T](sizes: Seq[Int], offsets: Seq[Double], keyType: String, mkKey: Int => T) { + for { + i <- sizes + o <- offsets + } { + val e = HashSet.empty[T] + val j = (i * o).toInt + // create two sets of size i with overlap o + val a = e ++ (0 until i).map(mkKey) + require(a.size == i, s"Building HashSet of size $i failed. Key type $keyType.") + val b = e ++ (j until (i + j)).map(mkKey) + require(b.size == i, s"Building HashSet of size $i failed. Key type $keyType.") + val as = e ++ (0 until j).map(mkKey) + require(as.size == j, s"Building HashSet of size $j failed. Key type $keyType.") + val hashCount0 = hashCount + val u = a intersect b + require(hashCount == hashCount0, s"key.hashCode should not be called, but has been called ${hashCount - hashCount0} times. Key type $keyType.") + require(u == (a intersect scala.collection.mutable.HashSet(b.toSeq: _*)), s"Operation must still work for other sets!") + require(u.size == i - j, s"Expected size ${i + j}. Real size ${u.size}. Key type $keyType.") + for (x <- j until i) + require(u.contains(mkKey(x)), s"Key type $keyType. Set (0 until ${i + j}) should contain $x but does not.") + val a_as = a intersect as + val as_a = as intersect a + require((a_as eq as) || (a_as eq a), s"No structural sharing in a intersect as. Key type $keyType, a=(0 until $i) as=(0 until $j)") + require((as_a eq as) || (as_a eq a), s"No structural sharing in as intersect a. Key type $keyType, a=(0 until $i) as=(0 until $j)") + } + } + + val sizes = Seq(1, 10, 100, 1000, 10000, 100000) + val offsets = Seq(0.0, 0.25, 0.5, 0.75, 1.0) + testIntersect(sizes, offsets, "int", identity[Int]) + testIntersect(sizes, offsets, "hashcounter", HashCounter.apply) + testIntersect(sizes, offsets, "collision", Collision.apply) +} diff --git a/test/files/run/t6253c.scala b/test/files/run/t6253c.scala new file mode 100644 index 0000000000..71dfe1473e --- /dev/null +++ b/test/files/run/t6253c.scala @@ -0,0 +1,63 @@ +import scala.collection.immutable.HashSet + +object Test extends App { + + var hashCount = 0 + + /** + * A key that produces lots of hash collisions, to exercise the part of the code that deals with those + */ + case class Collision(value: Int) { + + override def hashCode = { + hashCount += 1 + value / 5 + } + } + + /** + * A key that is identical to int other than that it counts hashCode invocations + */ + case class HashCounter(value: Int) { + + override def hashCode = { + hashCount += 1 + value + } + } + + def testDiff[T](sizes: Seq[Int], offsets: Seq[Double], keyType: String, mkKey: Int => T) { + for { + i <- sizes + o <- offsets + } { + val e = HashSet.empty[T] + val j = (i * o).toInt + // create two sets of size i with overlap o + val a = e ++ (0 until i).map(mkKey) + require(a.size == i, s"Building HashSet of size $i failed. Key type $keyType.") + val b = e ++ (j until (i + j)).map(mkKey) + require(b.size == i, s"Building HashSet of size $i failed. Key type $keyType.") + val as = e ++ (0 until j).map(mkKey) + require(as.size == j, s"Building HashSet of size $j failed. Key type $keyType.") + val hashCount0 = hashCount + val u = a diff b + require(hashCount == hashCount0, s"key.hashCode should not be called, but has been called ${hashCount - hashCount0} times. Key type $keyType.") + require(u == (a diff scala.collection.mutable.HashSet(b.toSeq: _*)), s"Operation must still work for other sets!") + require(u.size == j, s"Expected size $j. Real size ${u.size}. Key type $keyType.") + for (x <- 0 until j) + require(u.contains(mkKey(x)), s"Key type $keyType. Set (0 until ${i + j}) should contain $x but does not.") + require((as intersect b).isEmpty) + val b_as = b diff as + val as_b = as diff b + require((b_as eq b) || (b_as eq as), s"No structural sharing in b diff as. Key type $keyType, b=($j until ${i + j}) as=(0 until $j)") + require((as_b eq b) || (as_b eq as), s"No structural sharing in as diff b. Key type $keyType, b=($j until ${i + j}) as=(0 until $j)") + } + } + + val sizes = Seq(1, 10, 100, 1000, 10000, 100000) + val offsets = Seq(0.0, 0.25, 0.5, 0.75, 1.0) + testDiff(sizes, offsets, "int", identity[Int]) + testDiff(sizes, offsets, "hashCounter", HashCounter.apply) + testDiff(sizes, offsets, "collision", Collision.apply) +} diff --git a/test/files/run/t6260-delambdafy.check b/test/files/run/t6260-delambdafy.check new file mode 100644 index 0000000000..b2a7bed988 --- /dev/null +++ b/test/files/run/t6260-delambdafy.check @@ -0,0 +1,4 @@ +f(C@2e) + +Test$lambda$1$$apply +apply diff --git a/test/files/run/t6260-delambdafy.flags b/test/files/run/t6260-delambdafy.flags new file mode 100644 index 0000000000..48b438ddf8 --- /dev/null +++ b/test/files/run/t6260-delambdafy.flags @@ -0,0 +1 @@ +-Ydelambdafy:method diff --git a/test/files/run/t6260-delambdafy.scala b/test/files/run/t6260-delambdafy.scala new file mode 100644 index 0000000000..056b1edd4e --- /dev/null +++ b/test/files/run/t6260-delambdafy.scala @@ -0,0 +1,12 @@ +class C[A](private val a: Any) extends AnyVal + +object Test { + val f = (x: C[Any]) => {println(s"f($x)"); x} + def main(args: Array[String]) { + f(new C(".")) + val methods = f.getClass.getDeclaredMethods.map(_.getName).sorted + println("") + println(methods.mkString("\n")) + } +} + diff --git a/test/files/run/t6260c.check b/test/files/run/t6260c.check new file mode 100644 index 0000000000..1a57f2d741 --- /dev/null +++ b/test/files/run/t6260c.check @@ -0,0 +1,5 @@ +f(C@2e) + +Test$$anonfun$$apply +apply +g(C@2e) diff --git a/test/files/run/t6260c.scala b/test/files/run/t6260c.scala new file mode 100644 index 0000000000..845dc157b7 --- /dev/null +++ b/test/files/run/t6260c.scala @@ -0,0 +1,17 @@ +class C[A](private val a: Any) extends AnyVal + +object Test { + val f = (x: C[Any]) => {println(s"f($x)"); x} + trait T[A] { + def apply(a: A): A + } + val g = new T[C[Any]] { def apply(a: C[Any]) = { println(s"g($a)"); a } } + def main(args: Array[String]) { + f(new C(".")) + val methods = f.getClass.getDeclaredMethods.map(_.getName).sorted + println("") + println(methods.mkString("\n")) + g.apply(new C(".")) + } +} + diff --git a/test/files/run/t6261.scala b/test/files/run/t6261.scala index b4463256c9..bf6d640de3 100644 --- a/test/files/run/t6261.scala +++ b/test/files/run/t6261.scala @@ -2,12 +2,6 @@ import scala.collection.immutable._ object Test extends App { - def test0() { - val m=ListMap(1->2,3->4) - if(m.tail ne m.tail) - println("ListMap.tail uses a builder, so it is not O(1)") - } - def test1() { // test that a HashTrieMap with one leaf element is not created! val x = HashMap.empty + (1->1) + (2->2) @@ -92,7 +86,6 @@ object Test extends App { // StructureTests.printStructure(z) require(z.size == 2 && z.contains(a._1) && z.contains(c._1)) } - test0() test1() test2() test3() diff --git a/test/files/run/t6381.check b/test/files/run/t6381.check index ef08d0da09..4ed11d59ff 100644 --- a/test/files/run/t6381.check +++ b/test/files/run/t6381.check @@ -1,14 +1,14 @@ Type in expressions to have them evaluated. Type :help for more information. -scala> import language.experimental.macros -import language.experimental.macros +scala> import scala.language.experimental.macros +import scala.language.experimental.macros -scala> def pos_impl(c: reflect.macros.BlackboxContext): c.Expr[String] = { +scala> def pos_impl(c: scala.reflect.macros.blackbox.Context): c.Expr[String] = { import c.universe._ c.Expr[String](Literal(Constant(c.enclosingPosition.getClass.toString))) } -pos_impl: (c: scala.reflect.macros.BlackboxContext)c.Expr[String] +pos_impl: (c: scala.reflect.macros.blackbox.Context)c.Expr[String] scala> def pos: String = macro pos_impl defined term macro pos: String diff --git a/test/files/run/t6381.scala b/test/files/run/t6381.scala index c78dc13ed7..5a687c10c1 100644 --- a/test/files/run/t6381.scala +++ b/test/files/run/t6381.scala @@ -2,8 +2,8 @@ import scala.tools.partest.ReplTest object Test extends ReplTest { def code = """ - |import language.experimental.macros - |def pos_impl(c: reflect.macros.BlackboxContext): c.Expr[String] = { + |import scala.language.experimental.macros + |def pos_impl(c: scala.reflect.macros.blackbox.Context): c.Expr[String] = { | import c.universe._ | c.Expr[String](Literal(Constant(c.enclosingPosition.getClass.toString))) |} diff --git a/test/files/run/t6394a/Macros_1.scala b/test/files/run/t6394a/Macros_1.scala index b934b5ebb1..376d85ba67 100644 --- a/test/files/run/t6394a/Macros_1.scala +++ b/test/files/run/t6394a/Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c:BlackboxContext): c.Expr[Any] = { + def impl(c:Context): c.Expr[Any] = { import c.universe._ val selfTree = This(c.enclosingImpl.symbol.asModule.moduleClass) diff --git a/test/files/run/t6394b/Macros_1.scala b/test/files/run/t6394b/Macros_1.scala index 01fbc4f09e..53215e63aa 100644 --- a/test/files/run/t6394b/Macros_1.scala +++ b/test/files/run/t6394b/Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c:BlackboxContext): c.Expr[Any] = { + def impl(c:Context): c.Expr[Any] = { import c.universe._ val selfTree = This(tpnme.EMPTY) diff --git a/test/files/run/t6411a.check b/test/files/run/t6411a.check new file mode 100644 index 0000000000..9226146195 --- /dev/null +++ b/test/files/run/t6411a.check @@ -0,0 +1,96 @@ +meth = method yg_1 +as seen by Scala reflection: def yg_1[T](y: Y[T]): T +as seen by Java reflection: public java.lang.Object a$.yg_1(java.lang.Object) +result = 1 +meth = method yg_1 +as seen by Scala reflection: def yg_1[T](y: Y[T]): T +as seen by Java reflection: public java.lang.Object a$.yg_1(java.lang.Object) +result = 1 +meth = method yi_2 +as seen by Scala reflection: def yi_2(y: Y[Int]): Int +as seen by Java reflection: public int a$.yi_2(java.lang.Integer) +result = 2 +meth = method yi_2 +as seen by Scala reflection: def yi_2(y: Y[Int]): Int +as seen by Java reflection: public int a$.yi_2(java.lang.Integer) +result = class java.lang.IllegalArgumentException: argument type mismatch +meth = method ys_3 +as seen by Scala reflection: def ys_3(y: Y[String]): String +as seen by Java reflection: public java.lang.String a$.ys_3(java.lang.String) +result = class java.lang.IllegalArgumentException: argument type mismatch +meth = method ys_3 +as seen by Scala reflection: def ys_3(y: Y[String]): String +as seen by Java reflection: public java.lang.String a$.ys_3(java.lang.String) +result = 3 +meth = method ya_4 +as seen by Scala reflection: def ya_4(ys: Array[Y[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.ya_4(Y[]) +result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String +meth = method ya_4 +as seen by Scala reflection: def ya_4(ys: Array[Y[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.ya_4(Y[]) +result = List(4) +meth = method yl_5 +as seen by Scala reflection: def yl_5(ys: List[Y[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.yl_5(scala.collection.immutable.List) +result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String +meth = method yl_5 +as seen by Scala reflection: def yl_5(ys: List[Y[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.yl_5(scala.collection.immutable.List) +result = List(5) +meth = method yni_7 +as seen by Scala reflection: def yni_7(y: => Y[Int]): Int +as seen by Java reflection: public int a$.yni_7(scala.Function0) +result = 7 +meth = method yns_8 +as seen by Scala reflection: def yns_8(y: => Y[String]): String +as seen by Java reflection: public java.lang.String a$.yns_8(scala.Function0) +result = 8 +meth = method zg_1 +as seen by Scala reflection: def zg_1[T](z: Z[T]): T +as seen by Java reflection: public java.lang.Object a$.zg_1(Z) +result = 1 +meth = method zg_1 +as seen by Scala reflection: def zg_1[T](z: Z[T]): T +as seen by Java reflection: public java.lang.Object a$.zg_1(Z) +result = 1 +meth = method zi_2 +as seen by Scala reflection: def zi_2(z: Z[Int]): Int +as seen by Java reflection: public int a$.zi_2(Z) +result = 2 +meth = method zi_2 +as seen by Scala reflection: def zi_2(z: Z[Int]): Int +as seen by Java reflection: public int a$.zi_2(Z) +result = class java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer +meth = method zs_3 +as seen by Scala reflection: def zs_3(z: Z[String]): String +as seen by Java reflection: public java.lang.String a$.zs_3(Z) +result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String +meth = method zs_3 +as seen by Scala reflection: def zs_3(z: Z[String]): String +as seen by Java reflection: public java.lang.String a$.zs_3(Z) +result = 3 +meth = method za_4 +as seen by Scala reflection: def za_4(zs: Array[Z[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.za_4(Z[]) +result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String +meth = method za_4 +as seen by Scala reflection: def za_4(zs: Array[Z[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.za_4(Z[]) +result = List(4) +meth = method zl_5 +as seen by Scala reflection: def zl_5(zs: List[Z[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.zl_5(scala.collection.immutable.List) +result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String +meth = method zl_5 +as seen by Scala reflection: def zl_5(zs: List[Z[String]]): List[String] +as seen by Java reflection: public scala.collection.immutable.List a$.zl_5(scala.collection.immutable.List) +result = List(5) +meth = method zni_7 +as seen by Scala reflection: def zni_7(z: => Z[Int]): Int +as seen by Java reflection: public int a$.zni_7(scala.Function0) +result = 7 +meth = method zns_8 +as seen by Scala reflection: def zns_8(z: => Z[String]): String +as seen by Java reflection: public java.lang.String a$.zns_8(scala.Function0) +result = 8 diff --git a/test/files/run/t6411a.scala b/test/files/run/t6411a.scala new file mode 100644 index 0000000000..3bfeac2890 --- /dev/null +++ b/test/files/run/t6411a.scala @@ -0,0 +1,81 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.language.reflectiveCalls + +class Y[T](val i: T) extends AnyVal { + override def toString = s"Y($i)" +} +class Z[T](val i: T) extends AnyRef { + override def toString = s"Z($i)" +} + +object a { + def yg_1[T](y: Y[T]) = y.i + def yi_2(y: Y[Int]) = y.i + def ys_3(y: Y[String]) = y.i + def ya_4(ys: Array[Y[String]]) = ys.toList.map(_.i) + def yl_5(ys: List[Y[String]]) = ys.map(_.i) + def yv_6(ys: Y[String]*) = ys.toList.map(_.i) + def yni_7(y: => Y[Int]) = y.i + def yns_8(y: => Y[String]) = y.i + + def zg_1[T](z: Z[T]) = z.i + def zi_2(z: Z[Int]) = z.i + def zs_3(z: Z[String]) = z.i + def za_4(zs: Array[Z[String]]) = zs.toList.map(_.i) + def zl_5(zs: List[Z[String]]) = zs.map(_.i) + def zv_6(zs: Z[String]*) = zs.toList.map(_.i) + def zni_7(z: => Z[Int]) = z.i + def zns_8(z: => Z[String]) = z.i +} + +object Test extends App { + def test(methName: String, arg: Any) = { + val moduleA = cm.reflect(a) + val msym = moduleA.symbol.typeSignature.declaration(TermName(methName)).asMethod + println(s"meth = $msym") + val mmirror = moduleA.reflectMethod(msym) + val mresult = + try { mmirror(arg) } + catch { + case ex: Exception => + val ex1 = scala.reflect.runtime.ReflectionUtils.unwrapThrowable(ex) + s"${ex1.getClass}: ${ex1.getMessage}" + } + println(s"as seen by Scala reflection: ${msym.asInstanceOf[scala.reflect.internal.Symbols#Symbol].defString}") + println(s"as seen by Java reflection: ${mmirror.asInstanceOf[{val jmeth: java.lang.reflect.Method}].jmeth}") + println(s"result = $mresult") + } + + test("yg_1", new Y(1)) + test("yg_1", new Y("1")) + test("yi_2", new Y(2)) + test("yi_2", new Y("2")) + test("ys_3", new Y(3)) + test("ys_3", new Y("3")) + test("ya_4", Array(new Y(4))) + test("ya_4", Array(new Y("4"))) + test("yl_5", List(new Y(5))) + test("yl_5", List(new Y("5"))) + // FIXME: disabled because of SI-7056 + // test("yv_6", new Y(6)) + // test("yv_6", new Y("6")) + test("yni_7", new Y(7)) + test("yns_8", new Y("8")) + + test("zg_1", new Z(1)) + test("zg_1", new Z("1")) + test("zi_2", new Z(2)) + test("zi_2", new Z("2")) + test("zs_3", new Z(3)) + test("zs_3", new Z("3")) + test("za_4", Array(new Z(4))) + test("za_4", Array(new Z("4"))) + test("zl_5", List(new Z(5))) + test("zl_5", List(new Z("5"))) + // FIXME: disabled because of SI-7056 + // test("zv_6", new Z(6)) + // test("zv_6", new Z("6")) + test("zni_7", new Z(7)) + test("zns_8", new Z("8")) +}
\ No newline at end of file diff --git a/test/files/run/t6411b.check b/test/files/run/t6411b.check new file mode 100644 index 0000000000..e20bed6d8d --- /dev/null +++ b/test/files/run/t6411b.check @@ -0,0 +1 @@ +Bar(Foo(3)) diff --git a/test/files/run/t6411b.scala b/test/files/run/t6411b.scala new file mode 100644 index 0000000000..af30108826 --- /dev/null +++ b/test/files/run/t6411b.scala @@ -0,0 +1,12 @@ +import scala.reflect.runtime.universe._ + +case class Foo(n: Int) extends AnyVal +case class Bar(foo: Foo) + +object Test extends App { + val mirror = runtimeMirror(getClass.getClassLoader) + val cm = mirror.reflectClass(typeOf[Bar].typeSymbol.asClass) + val ctor = typeOf[Bar].declaration(nme.CONSTRUCTOR).asMethod + val ctorm = cm.reflectConstructor(ctor) + println(ctorm(Foo(3))) +}
\ No newline at end of file diff --git a/test/files/run/t6662/Macro_1.scala b/test/files/run/t6662/Macro_1.scala index cecf242f66..419859772d 100644 --- a/test/files/run/t6662/Macro_1.scala +++ b/test/files/run/t6662/Macro_1.scala @@ -1,8 +1,8 @@ import language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Demo { def id[T](a: T): T = macro idImpl[T] - def idImpl[T: c.WeakTypeTag](c: BlackboxContext)(a: c.Expr[T]): c.Expr[T] = a + def idImpl[T: c.WeakTypeTag](c: Context)(a: c.Expr[T]): c.Expr[T] = a } diff --git a/test/files/run/t6662/Test_2.scala b/test/files/run/t6662/Test_2.scala index 03a80b655a..82ac54cb46 100644 --- a/test/files/run/t6662/Test_2.scala +++ b/test/files/run/t6662/Test_2.scala @@ -2,7 +2,7 @@ object Test { def main(args: Array[String]) { - val s = Demo id () + val s = Demo id (()) println(s) } } diff --git a/test/files/run/t6863.check b/test/files/run/t6863.check index 030cb8b265..fea22b582f 100644 --- a/test/files/run/t6863.check +++ b/test/files/run/t6863.check @@ -10,3 +10,4 @@ t6863.scala:46: warning: comparing values of types Unit and Unit using `==' will t6863.scala:59: warning: comparing values of types Unit and Unit using `==' will always yield true assert({ () => x }.apply == ()) ^ +warning: there were 4 deprecation warning(s); re-run with -deprecation for details diff --git a/test/files/run/t6935.check b/test/files/run/t6935.check new file mode 100644 index 0000000000..844ca54682 --- /dev/null +++ b/test/files/run/t6935.check @@ -0,0 +1 @@ +warning: there were 1 deprecation warning(s); re-run with -deprecation for details diff --git a/test/files/run/t6935.scala b/test/files/run/t6935.scala index dea2d7f2e2..fdaf02e5ce 100644 --- a/test/files/run/t6935.scala +++ b/test/files/run/t6935.scala @@ -1,14 +1,14 @@ object Test { def main(args: Array[String]): Unit = { - import java.io._ - val bytes = new ByteArrayOutputStream() - val out = new ObjectOutputStream(bytes) - out.writeObject(()) - out.close() - val buf = bytes.toByteArray - val in = new ObjectInputStream(new ByteArrayInputStream(buf)) - val unit = in.readObject() - assert(unit == ()) + import java.io._ + val bytes = new ByteArrayOutputStream() + val out = new ObjectOutputStream(bytes) + out.writeObject(()) + out.close() + val buf = bytes.toByteArray + val in = new ObjectInputStream(new ByteArrayInputStream(buf)) + val unit = in.readObject() + assert(unit == ()) } } diff --git a/test/files/run/t6992/Macros_1.scala b/test/files/run/t6992/Macros_1.scala index 25566dddbf..d101efdda3 100644 --- a/test/files/run/t6992/Macros_1.scala +++ b/test/files/run/t6992/Macros_1.scala @@ -1,5 +1,5 @@ import scala.language.experimental.macros -import scala.reflect.macros.Context +import scala.reflect.macros.whitebox.Context object Macros { def foo(name: String): Any = macro foo_impl diff --git a/test/files/run/t7008-scala-defined/Impls_Macros_2.scala b/test/files/run/t7008-scala-defined/Impls_Macros_2.scala index 0ce5daf0d0..7049ed6490 100644 --- a/test/files/run/t7008-scala-defined/Impls_Macros_2.scala +++ b/test/files/run/t7008-scala-defined/Impls_Macros_2.scala @@ -1,8 +1,8 @@ import language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ val decls = c.typeOf[ScalaClassWithCheckedExceptions_1[_]].declarations.toList val s = decls.sortBy(_.name.toString).map(decl => (s"${decl.name}: ${decl.annotations}")).mkString(scala.compat.Platform.EOL) diff --git a/test/files/run/t7008/Impls_Macros_2.scala b/test/files/run/t7008/Impls_Macros_2.scala index 6da9dca913..9dfa66a20a 100644 --- a/test/files/run/t7008/Impls_Macros_2.scala +++ b/test/files/run/t7008/Impls_Macros_2.scala @@ -1,8 +1,8 @@ import language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ val decls = c.typeOf[JavaClassWithCheckedExceptions_1[_]].declarations.toList val s = decls.sortBy(_.name.toString).map(decl => (s"${decl.name}: ${decl.annotations}")).mkString(scala.compat.Platform.EOL) diff --git a/test/files/run/t7047/Impls_Macros_1.scala b/test/files/run/t7047/Impls_Macros_1.scala index 0d64729791..787ea6cfe8 100644 --- a/test/files/run/t7047/Impls_Macros_1.scala +++ b/test/files/run/t7047/Impls_Macros_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros class Foo object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ try { c.inferImplicitValue(typeOf[Foo], silent = false) diff --git a/test/files/run/t7157/Impls_Macros_1.scala b/test/files/run/t7157/Impls_Macros_1.scala index e48fbcaed3..cc258b016a 100644 --- a/test/files/run/t7157/Impls_Macros_1.scala +++ b/test/files/run/t7157/Impls_Macros_1.scala @@ -1,9 +1,9 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros object Macros { object AImpl { - def a(ctx: BlackboxContext)(args: ctx.Expr[Any]*): ctx.Expr[Unit] = { + def a(ctx: Context)(args: ctx.Expr[Any]*): ctx.Expr[Unit] = { import ctx.universe._ ctx.Expr[Unit](Apply(Ident(TermName("println")), List(Literal(Constant(1))))) } diff --git a/test/files/run/t7240/Macros_1.scala b/test/files/run/t7240/Macros_1.scala index 84ad231043..c6e976038d 100644 --- a/test/files/run/t7240/Macros_1.scala +++ b/test/files/run/t7240/Macros_1.scala @@ -1,7 +1,7 @@ package bakery import scala.language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context trait FailureCake { implicit def liftAnyFails[T: Manifest]: Any = ??? @@ -13,7 +13,7 @@ trait FailureCake { object Bakery { def failure: Any = macro failureImpl - def failureImpl(c: BlackboxContext): c.Expr[Any] = { + def failureImpl(c: Context): c.Expr[Any] = { import c.universe._ def dslTrait(dslName: String) = { @@ -41,7 +41,7 @@ object Bakery { def constructor = Apply(Select(New(Ident(newTypeName("eval"))), nme.CONSTRUCTOR), List()) c.eval(c.Expr[Any]( - c.resetAllAttrs(Block(composeDSL(Literal(Constant(1))), constructor)))) + c.untypecheck(Block(composeDSL(Literal(Constant(1))), constructor)))) c.Expr[Any](Literal(Constant(1))) } diff --git a/test/files/run/t7319.check b/test/files/run/t7319.check index d03ee3a6cf..b7443aa0c4 100644 --- a/test/files/run/t7319.check +++ b/test/files/run/t7319.check @@ -21,7 +21,7 @@ scala> convert(Some[Int](0)) --- because --- argument expression's type is not compatible with formal parameter type; found : Some[Int] - required: ?F forSome { type _$1 <: ?F forSome { type _$2 } } + required: ?F[_$1] forSome { type _$1 <: ?F[_$2] forSome { type _$2 } } convert(Some[Int](0)) ^ <console>:12: error: type mismatch; diff --git a/test/files/run/t7326.scala b/test/files/run/t7326.scala new file mode 100644 index 0000000000..ed9471ea8e --- /dev/null +++ b/test/files/run/t7326.scala @@ -0,0 +1,64 @@ +import scala.collection.immutable.ListSet +import scala.collection.immutable.HashSet + +object Test extends App { + + def testCorrectness() { + // a key that has many hashCode collisions + case class Collision(i: Int) { override def hashCode = i / 5 } + + def subsetTest[T](emptyA:Set[T], emptyB:Set[T], mkKey:Int => T, n:Int) { + val outside = mkKey(n + 1) + for(i <- 0 to n) { + val a = emptyA ++ (0 until i).map(mkKey) + // every set must be a subset of itself + require(a.subsetOf(a), "A set must be the subset of itself") + for(k <- 0 to i) { + // k <= i, so b is definitely a subset + val b = emptyB ++ (0 until k).map(mkKey) + // c has less elements than a, but contains a value that is not in a + // so it is not a subset, but that is not immediately obvious due to size + val c = b + outside + require(b.subsetOf(a), s"$b must be a subset of $a") + require(!c.subsetOf(a), s"$c must not be a subset of $a") + } + } + } + + // test the HashSet/HashSet case + subsetTest(HashSet.empty[Int], HashSet.empty[Int], identity, 100) + + // test the HashSet/other set case + subsetTest(HashSet.empty[Int], ListSet.empty[Int], identity, 100) + + // test the HashSet/HashSet case for Collision keys + subsetTest(HashSet.empty[Collision], HashSet.empty[Collision], Collision, 100) + + // test the HashSet/other set case for Collision keys + subsetTest(HashSet.empty[Collision], ListSet.empty[Collision], Collision, 100) + } + + /** + * A main performance benefit of the new subsetOf is that we do not have to call hashCode during subsetOf + * since we already have the hash codes in the HashSet1 nodes. + */ + def testNoHashCodeInvocationsDuringSubsetOf() = { + var count = 0 + + case class HashCodeCounter(i:Int) { + override def hashCode = { + count += 1 + i + } + } + + val a = HashSet.empty ++ (0 until 100).map(HashCodeCounter) + val b = HashSet.empty ++ (0 until 50).map(HashCodeCounter) + val count0 = count + val result = b.subsetOf(a) + require(count == count0, "key.hashCode must not be called during subsetOf of two HashSets") + result + } + testCorrectness() + testNoHashCodeInvocationsDuringSubsetOf() +} diff --git a/test/files/run/t7328.check b/test/files/run/t7328.check new file mode 100644 index 0000000000..e386fe70d9 --- /dev/null +++ b/test/files/run/t7328.check @@ -0,0 +1,4 @@ +Foo +Foo(3) +Foo(3) +Foo(5) diff --git a/test/files/run/t7328.scala b/test/files/run/t7328.scala new file mode 100644 index 0000000000..8816fa2347 --- /dev/null +++ b/test/files/run/t7328.scala @@ -0,0 +1,18 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} + +case class Foo(x: Int) extends AnyVal +case class Bar(foo: Foo) + +object Test extends App { + val foo = typeOf[Bar].declaration(TermName("foo")).asMethod + println(foo.returnType) // Foo + + val bar = Bar(Foo(3)) + println(bar.foo) // Foo(3) + + val im = cm.reflect(bar) + println(im.reflectField(foo).get) // incorrectly gives java.lang.Integer(3) not Foo(3) + im.reflectField(foo).set(Foo(5)) // java.lang.IllegalArgumentException: Can not set int field Bar.foo to Foo + println(im.reflectMethod(foo)()) // incorrectly gives java.lang.Integer(3) not Foo(3) +}
\ No newline at end of file diff --git a/test/files/run/t7375b/Macros_1.scala b/test/files/run/t7375b/Macros_1.scala index bcd8e52172..b6090e730b 100644 --- a/test/files/run/t7375b/Macros_1.scala +++ b/test/files/run/t7375b/Macros_1.scala @@ -1,5 +1,5 @@ import language.experimental.macros -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context class C1(val n: Int) extends AnyVal class C2(val n: Int) extends AnyRef @@ -9,7 +9,7 @@ object Macros { type F2 = C2 def foo = macro impl - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ def test[T: c.TypeTag] = reify(println(c.Expr[String](Literal(Constant(c.reifyRuntimeClass(c.typeOf[T]).toString))).splice)).tree def tests = Block(List(test[C1], test[C2], test[F1], test[F2]), Literal(Constant(()))) diff --git a/test/files/run/t7445.scala b/test/files/run/t7445.scala new file mode 100644 index 0000000000..e4ffeb8e1a --- /dev/null +++ b/test/files/run/t7445.scala @@ -0,0 +1,6 @@ +import scala.collection.immutable.ListMap + +object Test extends App { + val a = ListMap(1 -> 1, 2 -> 2, 3 -> 3, 4 -> 4, 5 -> 5); + require(a.tail == ListMap(2 -> 2, 3 -> 3, 4 -> 4, 5 -> 5)); +} diff --git a/test/files/run/t7475b.check b/test/files/run/t7475b.check new file mode 100644 index 0000000000..51993f072d --- /dev/null +++ b/test/files/run/t7475b.check @@ -0,0 +1,2 @@ +2 +2 diff --git a/test/files/run/t7475b.scala b/test/files/run/t7475b.scala new file mode 100644 index 0000000000..a205602b6d --- /dev/null +++ b/test/files/run/t7475b.scala @@ -0,0 +1,11 @@ +trait A { private val x = 1 } +trait B { val x = 2 } +trait C1 extends B with A { println(x) } +trait C2 extends A with B { println(x) } + +object Test { + def main(args: Array[String]): Unit = { + new C1 { } + new C2 { } + } +} diff --git a/test/files/run/t7507.scala b/test/files/run/t7507.scala index 6c1959ddac..a5eab6248f 100644 --- a/test/files/run/t7507.scala +++ b/test/files/run/t7507.scala @@ -4,6 +4,10 @@ trait Cake extends Slice trait Slice { self: Cake => // must have self type that extends `Slice` private[this] val bippy = () // must be private[this] locally(bippy) + class C1 { + locally(bippy) + locally(self.bippy) + } } // Originally reported bug: diff --git a/test/files/run/t7570a.check b/test/files/run/t7570a.check new file mode 100644 index 0000000000..3cc58df837 --- /dev/null +++ b/test/files/run/t7570a.check @@ -0,0 +1 @@ +C diff --git a/test/files/run/t7570a.scala b/test/files/run/t7570a.scala new file mode 100644 index 0000000000..b8b4ddeaf2 --- /dev/null +++ b/test/files/run/t7570a.scala @@ -0,0 +1,11 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.ToolBox +import definitions._ +import Flag._ + +object Test extends App { + val tb = cm.mkToolBox() + val csym = tb.define(q"""class C { override def toString = "C" }""") + println(tb.eval(q"new $csym")) +}
\ No newline at end of file diff --git a/test/files/run/t7570b.check b/test/files/run/t7570b.check new file mode 100644 index 0000000000..0c28247025 --- /dev/null +++ b/test/files/run/t7570b.check @@ -0,0 +1 @@ +compilation failed: reflective toolbox has failed: cannot have free terms in a top-level definition diff --git a/test/files/run/t7570b.scala b/test/files/run/t7570b.scala new file mode 100644 index 0000000000..f1db193186 --- /dev/null +++ b/test/files/run/t7570b.scala @@ -0,0 +1,17 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.{ToolBox, ToolBoxError} +import definitions._ +import Flag._ + +object Test extends App { + val tb = cm.mkToolBox() + val msg = build.newFreeTerm("msg", "C") + build.setTypeSignature(msg, typeOf[String]) + try { + val csym = tb.define(q"""class C { override def toString = $msg }""") + println(tb.eval(q"new $csym")) + } catch { + case ToolBoxError(message, _) => println(s"compilation failed: $message") + } +}
\ No newline at end of file diff --git a/test/files/run/t7570c.check b/test/files/run/t7570c.check new file mode 100644 index 0000000000..61e659d9e0 --- /dev/null +++ b/test/files/run/t7570c.check @@ -0,0 +1,2 @@ +(class C,true,false,false) +(object D,false,true,false) diff --git a/test/files/run/t7570c.scala b/test/files/run/t7570c.scala new file mode 100644 index 0000000000..a5bdbffe18 --- /dev/null +++ b/test/files/run/t7570c.scala @@ -0,0 +1,13 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.{ToolBox, ToolBoxError} +import definitions._ +import Flag._ + +object Test extends App { + val tb = cm.mkToolBox() + val csym = tb.define(q"""class C { override def toString = "C" }""") + println((csym, csym.isClass, csym.isModule, csym.isModuleClass)) + val dsym = tb.define(q"""object D { override def toString = "D" }""".asInstanceOf[ModuleDef]) + println((dsym, dsym.isClass, dsym.isModule, dsym.isModuleClass)) +}
\ No newline at end of file diff --git a/test/files/run/t7617a/Macros_1.scala b/test/files/run/t7617a/Macros_1.scala index d19f112bf4..77b18c20e2 100644 --- a/test/files/run/t7617a/Macros_1.scala +++ b/test/files/run/t7617a/Macros_1.scala @@ -1,12 +1,12 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros object Macros { - def getValueImpl[T](c: BlackboxContext): c.Expr[T] = { + def getValueImpl[T](c: Context): c.Expr[T] = { import c.universe._ c.Expr[T](Apply(Select(c.prefix.tree, newTermName("getVal")), Nil)) } - def setValueImpl[T](c: BlackboxContext)(value: c.Expr[T]): c.Expr[Unit] = { + def setValueImpl[T](c: Context)(value: c.Expr[T]): c.Expr[Unit] = { import c.universe._ c.Expr[Unit](Apply(Select(c.prefix.tree, newTermName("setVal")), List(value.tree))) } diff --git a/test/files/run/t7617b/Macros_1.scala b/test/files/run/t7617b/Macros_1.scala index b1406f30bb..90fcfda47d 100644 --- a/test/files/run/t7617b/Macros_1.scala +++ b/test/files/run/t7617b/Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context object Macros { - def impl(c: BlackboxContext)(name: c.Expr[String])(value: c.Expr[Any]) = { + def impl(c: Context)(name: c.Expr[String])(value: c.Expr[Any]) = { import c.universe._ reify(println(s"${name.splice} = ${value.splice}")) } diff --git a/test/files/run/t7657/Macros_1.scala b/test/files/run/t7657/Macros_1.scala index 9aac02031d..a883f76bc3 100644 --- a/test/files/run/t7657/Macros_1.scala +++ b/test/files/run/t7657/Macros_1.scala @@ -1,8 +1,8 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros trait T { def t(): Unit } abstract class A extends T { override def t(): Unit = () } -object Macro { def t(c: BlackboxContext)(): c.Expr[Unit] = c.universe.reify(()) } +object Macro { def t(c: Context)(): c.Expr[Unit] = c.universe.reify(()) } class C extends A { override def t(): Unit = macro Macro.t } diff --git a/test/files/run/t7700.check b/test/files/run/t7700.check new file mode 100644 index 0000000000..ca8e686984 --- /dev/null +++ b/test/files/run/t7700.check @@ -0,0 +1,2 @@ +public abstract java.lang.Object C.bar(java.lang.Object) +public abstract java.lang.Object C.foo(java.lang.Object) diff --git a/test/files/run/t7700.scala b/test/files/run/t7700.scala new file mode 100644 index 0000000000..76d16b808c --- /dev/null +++ b/test/files/run/t7700.scala @@ -0,0 +1,17 @@ +import scala.annotation._ + +trait C[@specialized U] { + @unspecialized + def foo(u: U): U + @unspecialized + def bar[A](u: U) = u +} + +object Test extends App { + val declared = classOf[C[_]].getDeclaredMethods.sortBy(_.getName) + println(declared.mkString("\n")) + object CInt extends C[Int] { def foo(i: Int) = i } + object CAny extends C[Any] { def foo(a: Any) = a } + assert(CInt.foo(1) == 1) + assert(CAny.foo("") == "") +} diff --git a/test/files/run/t7777/Macros_1.scala b/test/files/run/t7777/Macros_1.scala index 459ab3edbb..1dc6d6740c 100644 --- a/test/files/run/t7777/Macros_1.scala +++ b/test/files/run/t7777/Macros_1.scala @@ -1,6 +1,6 @@ import scala.language.experimental.macros import scala.language.dynamics -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context class DynMacro extends Dynamic { def applyDynamic(s: String)(xs: Any*): DynMacro = @@ -8,7 +8,7 @@ class DynMacro extends Dynamic { } object DynMacro extends DynMacro { - def applyDynamicMacro(c: WhiteboxContext)(s: c.Expr[String])(xs: c.Expr[Any]*): c.Expr[DynMacro] = { + def applyDynamicMacro(c: Context)(s: c.Expr[String])(xs: c.Expr[Any]*): c.Expr[DynMacro] = { import c.universe._ val Literal(Constant(n: String)) = s.tree val args = xs.map(_.tree.toString).mkString("(", ", ", ")") diff --git a/test/disabled/run/t7843-jsr223-service.check b/test/files/run/t7843-jsr223-service.check index a668df3567..a668df3567 100644 --- a/test/disabled/run/t7843-jsr223-service.check +++ b/test/files/run/t7843-jsr223-service.check diff --git a/test/files/run/t7843-jsr223-service.scala b/test/files/run/t7843-jsr223-service.scala new file mode 100644 index 0000000000..31112212ea --- /dev/null +++ b/test/files/run/t7843-jsr223-service.scala @@ -0,0 +1,8 @@ +import scala.tools.nsc.interpreter.IMain + +object Test extends App { + val engine = new IMain.Factory getScriptEngine() + engine.asInstanceOf[IMain].settings.usejavacp.value = true + engine put ("n", 10) + engine eval "1 to n.asInstanceOf[Int] foreach print" +} diff --git a/test/files/run/t7871/Macros_1.scala b/test/files/run/t7871/Macros_1.scala index 801a6af4e7..dca2508128 100644 --- a/test/files/run/t7871/Macros_1.scala +++ b/test/files/run/t7871/Macros_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.Context +import scala.reflect.macros.whitebox.Context import language.experimental.macros trait Tree diff --git a/test/files/run/t7933.check b/test/files/run/t7933.check new file mode 100644 index 0000000000..317e9677c3 --- /dev/null +++ b/test/files/run/t7933.check @@ -0,0 +1,2 @@ +hello +hello diff --git a/test/files/run/t7933.scala b/test/files/run/t7933.scala new file mode 100644 index 0000000000..b06dffcd80 --- /dev/null +++ b/test/files/run/t7933.scala @@ -0,0 +1,11 @@ +import scala.tools.nsc.interpreter.IMain + +object Test extends App { + val engine = new IMain.Factory getScriptEngine() + engine.asInstanceOf[IMain].settings.usejavacp.value = true + val res2 = engine.asInstanceOf[javax.script.Compilable] + res2 compile "8" eval() + val res5 = res2 compile """println("hello") ; 8""" + res5 eval() + res5 eval() +} diff --git a/test/files/run/t8015-ffc.scala b/test/files/run/t8015-ffc.scala new file mode 100644 index 0000000000..fe6781be42 --- /dev/null +++ b/test/files/run/t8015-ffc.scala @@ -0,0 +1,7 @@ + +object Test extends App { + val ms = """This is a long multiline string + with \u000d\u000a CRLF embedded.""" + assert(ms.lines.size == 3, s"lines.size ${ms.lines.size}") + assert(ms contains "\r\n CRLF", "no CRLF") +} diff --git a/test/files/run/t8046.check b/test/files/run/t8046.check new file mode 100644 index 0000000000..905b0b35ca --- /dev/null +++ b/test/files/run/t8046.check @@ -0,0 +1,2 @@ +List(trait Op, trait Function1, class Object, class Any) +BTS(T,Three.this.Op[Int],Int => Int,Object,Any) diff --git a/test/files/run/t8046/Test.scala b/test/files/run/t8046/Test.scala new file mode 100644 index 0000000000..f6b525d1b5 --- /dev/null +++ b/test/files/run/t8046/Test.scala @@ -0,0 +1,18 @@ +import scala.tools.partest._ + +object Test extends DirectTest { + override def code = "" + override def extraSettings: String = "-usejavacp" + + override def show() { + val c = newCompiler() + new c.Run + import c._ + + val f4 = typeOf[Three].member(newTermName("f4")) + val f4ParamInfo = f4.paramss.head.head.info + println(f4ParamInfo.baseClasses) + println(f4ParamInfo.baseTypeSeq) + } +} + diff --git a/test/files/run/t8046/t8046c.scala b/test/files/run/t8046/t8046c.scala new file mode 100644 index 0000000000..0b484da530 --- /dev/null +++ b/test/files/run/t8046/t8046c.scala @@ -0,0 +1,13 @@ +import language._ + +trait One { + type Op[A] + type Alias[A] = Op[A] +} + +trait Three extends One { + trait Op[A] extends (A => A) + + def f4[T <: Alias[Int]](f: T) = 0 +} + diff --git a/test/files/run/t8048a/Macros_1.scala b/test/files/run/t8048a/Macros_1.scala index f48e84f1de..d13e851d90 100644 --- a/test/files/run/t8048a/Macros_1.scala +++ b/test/files/run/t8048a/Macros_1.scala @@ -1,8 +1,8 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context import scala.language.experimental.macros object Macros { - def impl(c: WhiteboxContext) = { + def impl(c: Context) = { import c.universe._ q"if (true) Some(2) else None" } diff --git a/test/files/run/t8048b/Macros_1.scala b/test/files/run/t8048b/Macros_1.scala index b113af86ea..520a6fac06 100644 --- a/test/files/run/t8048b/Macros_1.scala +++ b/test/files/run/t8048b/Macros_1.scala @@ -6,10 +6,10 @@ // * https://groups.google.com/forum/#!topic/scala-internals/eXQt-BPm4i8 import scala.language.experimental.macros -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context object Macros { - def impl1(c: WhiteboxContext) = { + def impl1(c: Context) = { import c.universe._ q""" trait Foo { def x = 2 } @@ -18,7 +18,7 @@ object Macros { } def foo1: Any = macro impl1 - def impl2(c: WhiteboxContext) = { + def impl2(c: Context) = { import c.universe._ q""" class Foo { def x = 2 } @@ -27,7 +27,7 @@ object Macros { } def foo2: Any = macro impl2 - def impl3(c: WhiteboxContext) = { + def impl3(c: Context) = { import c.universe._ q""" new { def x = 2 } diff --git a/test/files/run/t8100.check b/test/files/run/t8100.check new file mode 100644 index 0000000000..cdd927fd88 --- /dev/null +++ b/test/files/run/t8100.check @@ -0,0 +1 @@ +Success(0) diff --git a/test/files/run/t8100.scala b/test/files/run/t8100.scala new file mode 100644 index 0000000000..b9d0fe5003 --- /dev/null +++ b/test/files/run/t8100.scala @@ -0,0 +1,8 @@ +object Test { + import scala.util.Try + + def main(args: Array[String]): Unit = { + def stream = Stream.from(0).take(100000).map(n => None) + println(Try(stream.flatten.length)) + } +} diff --git a/test/files/run/t8104/Macros_1.scala b/test/files/run/t8104/Macros_1.scala index 21d81a3687..2ad4bc5a99 100644 --- a/test/files/run/t8104/Macros_1.scala +++ b/test/files/run/t8104/Macros_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.WhiteboxContext +import scala.reflect.macros.whitebox.Context object Macros { - def impl[T](c: WhiteboxContext)(implicit T: c.WeakTypeTag[T]) = { + def impl[T](c: Context)(implicit T: c.WeakTypeTag[T]) = { import c.universe._ import definitions._ val fields = T.tpe.declarations.toList.collect{ case x: TermSymbol if x.isVal && x.isCaseAccessor => x } diff --git a/test/files/run/t8133/A_1.scala b/test/files/run/t8133/A_1.scala new file mode 100644 index 0000000000..a2836cdb3a --- /dev/null +++ b/test/files/run/t8133/A_1.scala @@ -0,0 +1,5 @@ +// a.scala +package object pkg { + class AnyOps(val x: Any) extends AnyVal + def AnyOps(x: Any) = new AnyOps(x) +} diff --git a/test/files/run/t8133/B_2.scala b/test/files/run/t8133/B_2.scala new file mode 100644 index 0000000000..b80e10952d --- /dev/null +++ b/test/files/run/t8133/B_2.scala @@ -0,0 +1,15 @@ +package pkg { + package object other + package other { + class Crash { + AnyOps(0) + () + } + } +} + +object Test { + def main(args: Array[String]): Unit = { + new pkg.other.Crash + } +} diff --git a/test/files/run/t8133b/A_1.scala b/test/files/run/t8133b/A_1.scala new file mode 100644 index 0000000000..24bbfc118d --- /dev/null +++ b/test/files/run/t8133b/A_1.scala @@ -0,0 +1,4 @@ +package object pkg { + def foo(x: Int): String = "a" + def foo(x: String): String = "b" +} diff --git a/test/files/run/t8133b/B_2.scala b/test/files/run/t8133b/B_2.scala new file mode 100644 index 0000000000..865ca0c0b0 --- /dev/null +++ b/test/files/run/t8133b/B_2.scala @@ -0,0 +1,9 @@ +// b.scala +package pkg { + package object other + package other { class Crash { foo("") } } +} + +object Test { + def main(args: Array[String]): Unit = new pkg.other.Crash +} diff --git a/test/files/run/t8177f.scala b/test/files/run/t8177f.scala new file mode 100644 index 0000000000..f50a5d98d6 --- /dev/null +++ b/test/files/run/t8177f.scala @@ -0,0 +1,20 @@ +trait Thing { type A; var p: A = _ } +class A[T](final val x: Thing { type A = T }) { + type Q = T + + def x1: T = x.p + def x2: Q = x.p + def x3: x.A = x.p +} +// all result types should be inferred as Int +class B extends A[Int](null) { + def y1 = x1 + def y2 = x2 + val y3 = x3 // before SI-8177, this lead to a signature that erased to java.lang.Object +} + + +object Test extends App { + val methods = classOf[B].getDeclaredMethods.sortBy(_.getName) + assert(methods.forall(_.toGenericString.startsWith("public int"))) +} diff --git a/test/files/run/t8199.scala b/test/files/run/t8199.scala new file mode 100644 index 0000000000..50994159ed --- /dev/null +++ b/test/files/run/t8199.scala @@ -0,0 +1,105 @@ +class reallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongname { +object obj0 +object obj01 +object obj012 +object obj0123 +object obj01234 +object obj012345 +object obj0123456 +object obj01234567 +object obj012345678 +object obj0123456789 +object obj01234567890 +class cls0 +class cls01 +class cls012 +class cls0123 +class cls01234 +class cls012345 +class cls0123456 +class cls01234567 +class cls012345678 +class cls0123456789 +class cls01234567890 +trait trt0 { def x = Test.checkCallerImplClassName() } +trait trt01 { def x = Test.checkCallerImplClassName() } +trait trt012 { def x = Test.checkCallerImplClassName() } +trait trt0123 { def x = Test.checkCallerImplClassName() } +trait trt01234 { def x = Test.checkCallerImplClassName() } +trait trt012345 { def x = Test.checkCallerImplClassName() } +trait trt0123456 { def x = Test.checkCallerImplClassName() } +trait trt01234567 { def x = Test.checkCallerImplClassName() } +trait trt012345678 { def x = Test.checkCallerImplClassName() } +trait trt0123456789 { def x = Test.checkCallerImplClassName() } +trait trt01234567890 { def x = Test.checkCallerImplClassName() } +} + +object Test extends App { + def check(c: Class[_]) { + checkClassName(c.getName) + } + def checkClassName(name: String) { + val defaultMaxClassFileLength = 255 + assert((name + ".class").length <= defaultMaxClassFileLength, name) + } + def checkCallerImplClassName() { + val name = Thread.currentThread.getStackTrace.apply(2).getClassName + assert(name.contains("$class")) + Test.checkClassName(name) + } + + val c = new reallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongname + import c._ + + check(obj0.getClass) + check(obj01.getClass) + check(obj012.getClass) + check(obj0123.getClass) + check(obj01234.getClass) + check(obj012345.getClass) + check(obj0123456.getClass) + check(obj01234567.getClass) + check(obj012345678.getClass) + check(obj0123456789.getClass) + check(obj01234567890.getClass) + + check(classOf[cls0]) + check(classOf[cls01]) + check(classOf[cls012]) + check(classOf[cls0123]) + check(classOf[cls01234]) + check(classOf[cls012345]) + check(classOf[cls0123456]) + check(classOf[cls01234567]) + check(classOf[cls012345678]) + check(classOf[cls0123456789]) + check(classOf[cls01234567890]) + + // interface facets + check(classOf[trt0]) + check(classOf[trt01]) + check(classOf[trt012]) + check(classOf[trt0123]) + check(classOf[trt01234]) + check(classOf[trt012345]) + check(classOf[trt0123456]) + check(classOf[trt01234567]) + check(classOf[trt012345678]) + check(classOf[trt0123456789]) + check(classOf[trt01234567890]) + + // impl classes are harder to find the names of to test! + (new trt0 {}).x + (new trt01 {}).x + (new trt012 {}).x + (new trt0123 {}).x + (new trt01234 {}).x + (new trt012345 {}).x + (new trt0123456 {}).x + (new trt01234567 {}).x + (new trt012345678 {}).x + (new trt0123456789 {}).x + (new trt01234567890 {}).x +} + +// filename too long: reallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongnamereallylongname$obj012345$.class diff --git a/test/files/run/t8233-bcode.flags b/test/files/run/t8233-bcode.flags new file mode 100644 index 0000000000..c30091d3de --- /dev/null +++ b/test/files/run/t8233-bcode.flags @@ -0,0 +1 @@ +-Ybackend:GenBCode diff --git a/test/files/run/t8233-bcode.scala b/test/files/run/t8233-bcode.scala new file mode 100644 index 0000000000..fae1c2b702 --- /dev/null +++ b/test/files/run/t8233-bcode.scala @@ -0,0 +1,18 @@ +object Test { + def bar(s: String) = s; + val o: Option[Null] = None + def nullReference { + val a: Null = o.get + bar(a) // Was: VerifyError under GenICode + } + + def literal { + val a: Null = null + bar(a) + } + + def main(args: Array[String]) = { + try { nullReference } catch { case _: NoSuchElementException => } + literal + } +} diff --git a/test/files/run/t8233.scala b/test/files/run/t8233.scala new file mode 100644 index 0000000000..fae1c2b702 --- /dev/null +++ b/test/files/run/t8233.scala @@ -0,0 +1,18 @@ +object Test { + def bar(s: String) = s; + val o: Option[Null] = None + def nullReference { + val a: Null = o.get + bar(a) // Was: VerifyError under GenICode + } + + def literal { + val a: Null = null + bar(a) + } + + def main(args: Array[String]) = { + try { nullReference } catch { case _: NoSuchElementException => } + literal + } +} diff --git a/test/files/run/t8245.scala b/test/files/run/t8245.scala new file mode 100644 index 0000000000..d44defbb9e --- /dev/null +++ b/test/files/run/t8245.scala @@ -0,0 +1,14 @@ +object Test { + def foo(o: Option[Int]): Int = { + lazy val i: Int = { + def local: Int = {if ("".isEmpty) return 42; -42} + assert(local == 42) + o.getOrElse(return -1) + } + i + 1 + } + + def main(args: Array[String]) { + assert(foo(None) == -1) + } +} diff --git a/test/files/run/toolbox_current_run_compiles.scala b/test/files/run/toolbox_current_run_compiles.scala index 31e0a45eea..6ec7074643 100644 --- a/test/files/run/toolbox_current_run_compiles.scala +++ b/test/files/run/toolbox_current_run_compiles.scala @@ -1,9 +1,9 @@ package pkg { - import scala.reflect.macros.BlackboxContext + import scala.reflect.macros.blackbox.Context import scala.language.experimental.macros object Macros { - def impl[T: c.WeakTypeTag](c: BlackboxContext) = { + def impl[T: c.WeakTypeTag](c: Context) = { import c.universe._ val sym = c.weakTypeOf[T].typeSymbol val g = c.universe.asInstanceOf[scala.tools.nsc.Global] diff --git a/test/files/run/typed-annotated/Macros_1.scala b/test/files/run/typed-annotated/Macros_1.scala index 42478cb988..d805d82f39 100644 --- a/test/files/run/typed-annotated/Macros_1.scala +++ b/test/files/run/typed-annotated/Macros_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.BlackboxContext +import scala.reflect.macros.blackbox.Context import language.experimental.macros class ann extends scala.annotation.StaticAnnotation object Macros { - def impl(c: BlackboxContext) = { + def impl(c: Context) = { import c.universe._ // val tpt = Annotated(Apply(Select(New(Ident(newTypeName("ann"))), nme.CONSTRUCTOR), List()), Ident(newTypeName("Int"))) val tpt = Annotated(Apply(Select(New(Ident(newTypeName("ann"))), nme.CONSTRUCTOR), List()), TypeTree(weakTypeOf[Int])) diff --git a/test/files/run/var-arity-class-symbol.scala b/test/files/run/var-arity-class-symbol.scala new file mode 100644 index 0000000000..29fe960eb3 --- /dev/null +++ b/test/files/run/var-arity-class-symbol.scala @@ -0,0 +1,19 @@ +import scala.reflect.runtime.universe._, definitions._ +object Test extends App { + // Tuples + assert(TupleClass.seq.size == 22) + assert(TupleClass(0) == NoSymbol) + assert(TupleClass(23) == NoSymbol) + assert((1 to 22).forall { i => TupleClass(i).name.toString == s"Tuple$i" }) + // Functions + assert(FunctionClass.seq.size == 23) + assert(FunctionClass(-1) == NoSymbol) + assert(FunctionClass(23) == NoSymbol) + assert((0 to 22).forall { i => FunctionClass(i).name.toString == s"Function$i" }) + // Products + assert(ProductClass.seq.size == 23) + assert(ProductClass(-1) == NoSymbol) + assert(ProductClass(0) == UnitClass) + assert(ProductClass(23) == NoSymbol) + assert((1 to 22).forall { i => ProductClass(i).name.toString == s"Product$i" }) +} diff --git a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala index 2af656c7c9..dcd4f63a4d 100644 --- a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala @@ -7,7 +7,9 @@ object DefinitionConstructionProps with TraitConstruction with TypeDefConstruction with ValDefConstruction - with PackageConstruction { + with DefConstruction + with PackageConstruction + with ImportConstruction { property("SI-6842") = test { val x: Tree = q"val x: Int" assertEqAst(q"def f($x) = 0", "def f(x: Int) = 0") @@ -228,13 +230,13 @@ trait MethodConstruction { self: QuasiquoteProperties => property("splice type name into annotation") = test { val name = TypeName("annot") - assertSameAnnots(q"@$name def foo", List(annot(name))) + assertSameAnnots(q"@$name def foo", List(q"new $name")) } property("splice ident into annotation") = test { val name = TypeName("annot") val ident = Ident(name) - assertSameAnnots(q"@$ident def foo", List(annot(name))) + assertSameAnnots(q"@$ident def foo", List(q"new $name")) } property("splice idents into annotation") = test { @@ -244,36 +246,36 @@ trait MethodConstruction { self: QuasiquoteProperties => } property("splice constructor calls into annotation") = test { - val ctorcalls = List(annot("a1"), annot("a2")) + val ctorcalls = List(q"new a1", q"new a2") assertSameAnnots(q"@..$ctorcalls def foo", ctorcalls) } property("splice multiple annotations (1)") = test { - val annot1 = annot("a1") - val annot2 = annot("a2") + val annot1 = q"new a1" + val annot2 = q"new a2" val res = q"@$annot1 @$annot2 def foo" assertSameAnnots(res, List(annot1, annot2)) } property("splice multiple annotations (2)") = test { - val annot1 = annot("a1") - val annots = List(annot("a2"), annot("a3")) + val annot1 = q"new a1" + val annots = List(q"new a2", q"new a3") val res = q"@$annot1 @..$annots def foo" assertSameAnnots(res, annot1 :: annots) } property("splice annotations with arguments (1)") = test { - val a = annot("a", List(q"x")) + val a = q"new a(x)" assertSameAnnots(q"@$a def foo", q"@a(x) def foo") } property("splice annotations with arguments (2)") = test { - val a = newTypeName("a") + val a = TypeName("a") assertSameAnnots(q"@$a(x) def foo", q"@a(x) def foo") } property("splice annotations with arguments (3") = test { - val a = Ident(newTypeName("a")) + val a = Ident(TypeName("a")) assertSameAnnots(q"@$a(x) def foo", q"@a(x) def foo") } @@ -285,7 +287,7 @@ trait MethodConstruction { self: QuasiquoteProperties => } property("can't splice annotations with arguments specificed twice") = test { - val a = annot("a", List(q"x")) + val a = q"new a(x)" assertThrows[IllegalArgumentException] { q"@$a(y) def foo" } @@ -349,4 +351,43 @@ trait PackageConstruction { self: QuasiquoteProperties => assertEqAst(q"package object foo extends { ..$edefs } with Any", "package object foo extends { val x = 1; type I = Int } with Any") } -}
\ No newline at end of file +} + +trait DefConstruction { self: QuasiquoteProperties => + property("construct implicit args (1)") = test { + val x = q"val x: Int" + assertEqAst(q"def foo(implicit $x) = x", "def foo(implicit x: Int) = x") + } + + property("construct implicit args (2)") = test { + val xs = q"val x1: Int" :: q"val x2: Long" :: Nil + assertEqAst(q"def foo(implicit ..$xs) = x1 + x2", "def foo(implicit x1: Int, x2: Long) = x1 + x2") + } +} + +trait ImportConstruction { self: QuasiquoteProperties => + property("construct wildcard import") = test { + val sel = pq"_" + assert(q"import foo.$sel" ≈ q"import foo._") + } + + property("construct named import") = test { + val sel = pq"bar" + assert(q"import foo.$sel" ≈ q"import foo.bar") + } + + property("construct renaming import") = test { + val sel = pq"bar -> baz" + assert(q"import foo.$sel" ≈ q"import foo.{bar => baz}") + } + + property("construct unimport import") = test { + val sels = pq"poison -> _" :: pq"_" :: Nil + assert(q"import foo.{..$sels}" ≈ q"import foo.{poison => _, _}") + } + + property("construct mixed import") = test { + val sels = pq"a -> b" :: pq"c -> _" :: pq"_" :: Nil + assert(q"import foo.{..$sels}" ≈ q"import foo.{a => b, c => _, _}") + } +} diff --git a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala index 94465930ed..e2d1757d48 100644 --- a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala @@ -8,7 +8,9 @@ object DefinitionDeconstructionProps with ObjectDeconstruction with ModsDeconstruction with ValVarDeconstruction + with DefDeconstruction with PackageDeconstruction + with ImportDeconstruction trait TraitDeconstruction { self: QuasiquoteProperties => property("exhaustive trait matcher") = test { @@ -124,18 +126,28 @@ trait ModsDeconstruction { self: QuasiquoteProperties => } property("@..$annots def foo") = test { - val a = annot("a") - val b = annot("b") + val a = q"new a" + val b = q"new b" val q"@..$annots def foo" = q"@$a @$b def foo" annots ≈ List(a, b) } property("@$annot @..$annots def foo") = test { - val a = annot("a") - val b = annot("b") - val c = annot("c") + val a = q"new a" + val b = q"new b" + val c = q"new c" val q"@$first @..$rest def foo" = q"@$a @$b @$c def foo" - first ≈ a && rest ≈ List(b, c) + assert(first ≈ a) + assert(rest ≈ List(b, c)) + } + + property("@..$anots @$annot def foo") = test { + val a = q"new a" + val b = q"new b" + val c = q"new c" + val q"@..$init @$last def foo" = q"@$a @$b @$c def foo" + assert(init ≈ List(a, b)) + assert(last ≈ c) } } @@ -179,4 +191,84 @@ trait PackageDeconstruction { self: QuasiquoteProperties => matches("package object foo extends { val early = 1 } with daddy") assertThrows[MatchError] { matches("object foo") } } -}
\ No newline at end of file +} + +trait DefDeconstruction { self: QuasiquoteProperties => + property("exhaustive def matcher") = test { + def matches(line: String) = { + val t = parse(line) + val q"$mods0 def $name0[..$targs0](...$argss0): $restpe0 = $body0" = t + val q"$mods1 def $name1[..$targs1](...$argss1)(implicit ..$impl1): $restpe1 = $body1" = t + } + matches("def foo = foo") + matches("implicit def foo: Int = 2") + matches("def foo[T](x: T): T = x") + matches("def foo[A: B] = implicitly[B[A]]") + matches("private def foo = 0") + matches("def foo[A <% B] = null") + matches("def foo(one: One)(two: Two) = (one, two)") + matches("def foo[T](args: T*) = args.toList") + } + + property("extract implicit arg list (1)") = test { + val q"def foo(...$argss)(implicit ..$impl)" = q"def foo(x: Int)(implicit y: Int)" + assert(impl ≈ List(q"${Modifiers(IMPLICIT | PARAM)} val y: Int")) + } + + property("extract implicit arg list (2)") = test { + val q"def foo(...$argss)(implicit ..$impl)" = q"def foo(x: Int)" + assert(impl.isEmpty) + } +} + +trait ImportDeconstruction { self: QuasiquoteProperties => + property("exhaustive import matcher") = test { + def matches(line: String) = { + val q"import $ref.{..$sels}" = parse(line) + } + matches("import foo.bar") + matches("import foo.{bar, baz}") + matches("import foo.{a => b, c => d}") + matches("import foo.{poision => _, _}") + matches("import foo.bar.baz._") + } + + property("extract import binding") = test { + val q"import $_.$sel" = q"import foo.bar" + val pq"bar" = sel + } + + property("extract import wildcard") = test { + val q"import $_.$sel" = q"import foo._" + val pq"_" = sel + } + + property("extract import rename") = test { + val q"import $_.$sel" = q"import foo.{bar => baz}" + val pq"bar -> baz" = sel + val pq"$left -> $right" = sel + val pq"bar" = left + val pq"baz" = right + } + + property("extract import unimport") = test { + val q"import $_.$sel" = q"import foo.{bar => _}" + val pq"bar -> _" = sel + val pq"$left -> $right" = sel + val pq"bar" = left + val pq"_" = right + } + + property("splice names into import selector") = forAll { + (expr: Tree, plain: TermName, oldname: TermName, newname: TermName, discard: TermName) => + + val Import(expr1, List( + ImportSelector(plain11, _, plain12, _), + ImportSelector(oldname1, _, newname1, _), + ImportSelector(discard1, _, wildcard, _))) = + q"import $expr.{$plain, $oldname => $newname, $discard => _}" + + expr1 ≈ expr && plain11 == plain12 && plain12 == plain && + oldname1 == oldname && newname1 == newname && discard1 == discard && wildcard == nme.WILDCARD + } +} diff --git a/test/files/scalacheck/quasiquotes/ErrorProps.scala b/test/files/scalacheck/quasiquotes/ErrorProps.scala index 92d299bede..1ba9bba381 100644 --- a/test/files/scalacheck/quasiquotes/ErrorProps.scala +++ b/test/files/scalacheck/quasiquotes/ErrorProps.scala @@ -32,12 +32,6 @@ object ErrorProps extends QuasiquoteProperties("errors") { q"@...$annots def foo" """) - property("@..$first @$rest def foo") = fails( - "Can't extract with .. here", - """ - q"@a @b @c def foo" match { case q"@..$first @$rest def foo" => } - """) - property("only literal string arguments") = fails( "Quasiquotes can only be used with literal strings", """ @@ -52,13 +46,6 @@ object ErrorProps extends QuasiquoteProperties("errors") { StringContext("\"", "\"").q(x) """) - property("expected different cardinality") = fails( - "Can't splice List[reflect.runtime.universe.Tree] with ..., consider using ..", - """ - val args: List[Tree] = Nil - q"f(...$args)" - """) - property("non-liftable type ..") = fails( "Can't splice List[StringBuilder] with .., consider omitting the dots or providing an implicit instance of Liftable[StringBuilder]", """ @@ -90,13 +77,6 @@ object ErrorProps extends QuasiquoteProperties("errors") { q"$xs" """) - property("use zero card") = fails( - "Can't splice reflect.runtime.universe.Tree with .., consider omitting the dots", - """ - val t = EmptyTree - q"f(..$t)" - """) - property("not liftable or natively supported") = fails( "Can't splice StringBuilder, consider providing an implicit instance of Liftable[StringBuilder]", """ @@ -154,12 +134,6 @@ object ErrorProps extends QuasiquoteProperties("errors") { q"$m1 $m2 def foo" """) - property("can't extract with .. card here") = fails( - "Can't extract with .. here", - """ - val q"f(..$xs, $y)" = EmptyTree - """) - property("can't extract mods with annots") = fails( "Can't extract modifiers together with annotations, consider extracting just modifiers", """ @@ -188,4 +162,4 @@ object ErrorProps extends QuasiquoteProperties("errors") { // // Make sure a nice error is reported in this case // { import Flag._; val mods = NoMods; q"lazy $mods val x: Int" } -}
\ No newline at end of file +} diff --git a/test/files/scalacheck/quasiquotes/LiftableProps.scala b/test/files/scalacheck/quasiquotes/LiftableProps.scala index 539375d905..bd631b8734 100644 --- a/test/files/scalacheck/quasiquotes/LiftableProps.scala +++ b/test/files/scalacheck/quasiquotes/LiftableProps.scala @@ -5,51 +5,62 @@ object LiftableProps extends QuasiquoteProperties("liftable") { property("splice byte") = test { val c: Byte = 0 assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0: Byte}" ≈ Literal(Constant(c))) } property("splice short") = test { val c: Short = 0 assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0: Short}" ≈ Literal(Constant(c))) } property("splice char") = test { val c: Char = 'c' assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${'c'}" ≈ Literal(Constant(c))) } property("splice int") = test { val c: Int = 0 assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0: Int}" ≈ Literal(Constant(c))) } property("splice long") = test { val c: Long = 0 assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0: Long}" ≈ Literal(Constant(c))) } property("splice float") = test { val c: Float = 0.0f assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0.0f: Float}" ≈ Literal(Constant(c))) } property("splice double") = test { val c: Double = 0.0 assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${0.0: Double}" ≈ Literal(Constant(c))) } property("splice boolean") = test { val c: Boolean = false assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${true}" ≈ Literal(Constant(true))) + assert(q"${false}" ≈ Literal(Constant(false))) } property("splice string") = test { val c: String = "s" assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${"s"}" ≈ Literal(Constant(c))) } property("splice unit") = test { val c: Unit = () assert(q"$c" ≈ Literal(Constant(c))) + assert(q"${()}" ≈ Literal(Constant(c))) } property("lift symbol") = test { @@ -111,4 +122,41 @@ object LiftableProps extends QuasiquoteProperties("liftable") { assert(q"${(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)}" ≈ q"(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)") assert(q"${(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22)}" ≈ q"(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22)") } -}
\ No newline at end of file + + property("lift nil") = test { + val nil = Nil + assert(q"$nil" ≈ q"scala.collection.immutable.Nil") + } + + property("lift some") = test { + val some1 = Some(1) + assert(q"$some1" ≈ q"scala.Some(1)") + val some2: Option[Int] = Some(1) + assert(q"$some2" ≈ q"scala.Some(1)") + } + + property("lift none") = test { + val none1 = None + assert(q"$none1" ≈ q"scala.None") + val none2: Option[Int] = None + assert(q"$none2" ≈ q"scala.None") + } + + property("lift left") = test { + val left1 = Left(1) + assert(q"$left1" ≈ q"scala.util.Left(1)") + val left2: Left[Int, Int] = Left(1) + assert(q"$left2" ≈ q"scala.util.Left(1)") + val left3: Either[Int, Int] = Left(1) + assert(q"$left3" ≈ q"scala.util.Left(1)") + } + + property("lift right") = test { + val right1 = Right(1) + assert(q"$right1" ≈ q"scala.util.Right(1)") + val right2: Right[Int, Int] = Right(1) + assert(q"$right2" ≈ q"scala.util.Right(1)") + val right3: Either[Int, Int] = Right(1) + assert(q"$right3" ≈ q"scala.util.Right(1)") + } +} diff --git a/test/files/scalacheck/quasiquotes/PatternConstructionProps.scala b/test/files/scalacheck/quasiquotes/PatternConstructionProps.scala index 582e915258..ca4c8609ac 100644 --- a/test/files/scalacheck/quasiquotes/PatternConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/PatternConstructionProps.scala @@ -29,4 +29,8 @@ object PatternConstructionProps extends QuasiquoteProperties("pattern constructi property("splice into casedef") = forAll { (pat: Tree, cond: Tree, body: Tree) => cq"$pat if $cond => $body" ≈ CaseDef(pat, cond, body) } -}
\ No newline at end of file + + property("splice into alternative") = forAll { (first: Tree, rest: List[Tree]) => + pq"$first | ..$rest" ≈ Alternative(first :: rest) + } +} diff --git a/test/files/scalacheck/quasiquotes/PatternDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/PatternDeconstructionProps.scala index cccf8095db..ad3266bcec 100644 --- a/test/files/scalacheck/quasiquotes/PatternDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/PatternDeconstructionProps.scala @@ -22,8 +22,23 @@ object PatternDeconstructionProps extends QuasiquoteProperties("pattern deconstr pat0 ≈ pat && subpat0 ≈ subpat } + property("extract apply many") = forAll { (pat: Tree, subpats: List[Tree]) => + val pq"$pat0(..$subpats0)" = pq"$pat(..$subpats)" + pat0 ≈ pat && subpats0 ≈ subpats + } + + property("extract apply last") = forAll { (pat: Tree, subpats: List[Tree], subpatlast: Tree) => + val pq"$pat0(..$subpats0, $subpatlast0)" = pq"$pat(..$subpats, $subpatlast)" + pat0 ≈ pat && subpats0 ≈ subpats && subpatlast0 ≈ subpatlast + } + property("extract casedef") = forAll { (pat: Tree, cond: Tree, body: Tree) => val cq"$pat0 if $cond0 => $body0" = cq"$pat if $cond => $body" pat0 ≈ pat && cond0 ≈ cond && body0 ≈ body } -}
\ No newline at end of file + + property("extract alternative") = forAll { (first: Tree, rest: List[Tree]) => + val pq"$first1 | ..$rest1" = pq"$first | ..$rest" + first1 ≈ first && rest1 ≈ rest + } +} diff --git a/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala b/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala index e4ee5dfcae..589b8d4d72 100644 --- a/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala +++ b/test/files/scalacheck/quasiquotes/QuasiquoteProperties.scala @@ -116,10 +116,5 @@ trait Helpers { } } - def annot(name: String): Tree = annot(TypeName(name), Nil) - def annot(name: TypeName): Tree = annot(name, Nil) - def annot(name: String, args: List[Tree]): Tree = annot(TypeName(name), args) - def annot(name: TypeName, args: List[Tree]): Tree = q"new $name(..$args)" - val scalapkg = build.setSymbol(Ident(TermName("scala")), definitions.ScalaPackage) } diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala index 6fb05ff9a4..058880a25c 100644 --- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala @@ -85,19 +85,6 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { q"$fun[..$types]" ≈ (if (types.nonEmpty) TypeApply(fun, types) else fun) } - property("splice names into import selector") = forAll { - (expr: Tree, plain: Name, oldname: Name, newname: Name, discard: Name) => - - val Import(expr1, List( - ImportSelector(plain11, _, plain12, _), - ImportSelector(oldname1, _, newname1, _), - ImportSelector(discard1, _, wildcard, _))) = - q"import $expr.{$plain, $oldname => $newname, $discard => _}" - - expr1 ≈ expr && plain11 == plain12 && plain12 == plain && - oldname1 == oldname && newname1 == newname && discard1 == discard && wildcard == nme.WILDCARD - } - property("splice trees into while loop") = forAll { (cond: Tree, body: Tree) => val LabelDef(_, List(), If(cond1, Block(List(body1), Apply(_, List())), Literal(Constant(())))) = q"while($cond) $body" body1 ≈ body && cond1 ≈ cond @@ -116,7 +103,7 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { def blockInvariant(quote: Tree, trees: List[Tree]) = quote ≈ (trees match { - case Nil => q"()" + case Nil => q"" case _ :+ last if !last.isTerm => Block(trees, q"()") case head :: Nil => head case init :+ last => Block(init, last) @@ -224,4 +211,76 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { property("SI-8009") = test { q"`foo`".asInstanceOf[reflect.internal.SymbolTable#Ident].isBackquoted } + + property("SI-8148") = test { + val q"($a, $b) => $_" = q"_ + _" + assert(a.name != b.name) + } + + property("SI-7275 a") = test { + val t = q"stat1; stat2" + assertEqAst(q"..$t", "{stat1; stat2}") + } + + property("SI-7275 b") = test { + def f(t: Tree) = q"..$t" + assertEqAst(f(q"stat1; stat2"), "{stat1; stat2}") + } + + property("SI-7275 c1") = test { + object O + implicit val liftO = Liftable[O.type] { _ => q"foo; bar" } + assertEqAst(q"f(..$O)", "f(foo, bar)") + } + + property("SI-7275 c2") = test { + object O + implicit val liftO = Liftable[O.type] { _ => q"{ foo; bar }; { baz; bax }" } + assertEqAst(q"f(...$O)", "f(foo, bar)(baz, bax)") + } + + property("SI-7275 d") = test { + val l = q"a; b" :: q"c; d" :: Nil + assertEqAst(q"f(...$l)", "f(a, b)(c, d)") + val l2: Iterable[Tree] = l + assertEqAst(q"f(...$l2)", "f(a, b)(c, d)") + } + + property("SI-7275 e") = test { + val t = q"{ a; b }; { c; d }" + assertEqAst(q"f(...$t)", "f(a, b)(c, d)") + } + + property("SI-7275 e2") = test { + val t = q"{ a; b }; c; d" + assertEqAst(q"f(...$t)", "f(a, b)(c)(d)") + } + + property("remove synthetic unit") = test { + val q"{ ..$stats1 }" = q"{ def x = 2 }" + assert(stats1 ≈ List(q"def x = 2")) + val q"{ ..$stats2 }" = q"{ class X }" + assert(stats2 ≈ List(q"class X")) + val q"{ ..$stats3 }" = q"{ type X = Int }" + assert(stats3 ≈ List(q"type X = Int")) + val q"{ ..$stats4 }" = q"{ val x = 2 }" + assert(stats4 ≈ List(q"val x = 2")) + } + + property("don't remove user-defined unit") = test { + val q"{ ..$stats }" = q"{ def x = 2; () }" + assert(stats ≈ List(q"def x = 2", q"()")) + } + + property("empty-tree as block") = test { + val q"{ ..$stats1 }" = q" " + assert(stats1.isEmpty) + val stats2 = List.empty[Tree] + assert(q"{ ..$stats2 }" ≈ q"") + } + + property("consistent variable order") = test { + val q"$a = $b = $c = $d = $e = $f = $g = $h = $k = $l" = q"a = b = c = d = e = f = g = h = k = l" + assert(a ≈ q"a" && b ≈ q"b" && c ≈ q"c" && d ≈ q"d" && e ≈ q"e" && g ≈ q"g" && h ≈ q"h" && k ≈ q"k" && l ≈ q"l") + } } diff --git a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala index 8d1ada342a..148bb383b0 100644 --- a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala @@ -29,14 +29,34 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction y1 ≈ x1 && y2 ≈ x2 && ys ≈ List(x3) } + property("f(y1, ..ys, yn)") = forAll { (x1: Tree, x2: Tree, x3: Tree, x4: Tree) => + val q"f($y1, ..$ys, $yn)" = q"f($x1, $x2, $x3, $x4)" + y1 ≈ x1 && ys ≈ List(x2, x3) && yn ≈ x4 + } + + property("f(..ys, y_{n-1}, y_n)") = forAll { (x1: Tree, x2: Tree, x3: Tree, x4: Tree) => + val q"f(..$ys, $yn1, $yn)" = q"f($x1, $x2, $x3, $x4)" + ys ≈ List(x1, x2) && yn1 ≈ x3 && yn ≈ x4 + } + property("f(...xss)") = forAll { (x1: Tree, x2: Tree) => - val q"f(...$argss)" = q"f($x1)($x2)" - argss ≈ List(List(x1), List(x2)) + val q"f(...$xss)" = q"f($x1)($x2)" + xss ≈ List(List(x1), List(x2)) + } + + property("f(...$xss)(..$last)") = forAll { (x1: Tree, x2: Tree, x3: Tree) => + val q"f(...$xss)(..$last)" = q"f($x1)($x2)($x3)" + xss ≈ List(List(x1), List(x2)) && last ≈ List(x3) + } + + property("f(...$xss)(..$lastinit, $lastlast)") = forAll { (x1: Tree, x2: Tree, x3: Tree, x4: Tree) => + val q"f(...$xss)(..$lastinit, $lastlast)" = q"f($x1)($x2, $x3, $x4)" + xss ≈ List(List(x1)) && lastinit ≈ List(x2, x3) && lastlast ≈ x4 } property("f(...xss) = f") = forAll { (x1: Tree, x2: Tree) => - val q"f(...$argss)" = q"f" - argss ≈ List() + val q"f(...$xss)" = q"f" + xss ≈ List() } property("deconstruct unit as tuple") = test { @@ -51,12 +71,27 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction property("deconstruct tuple mixed") = test { val q"($first, ..$rest)" = q"(a, b, c)" - assert(first ≈ q"a" && rest ≈ List(q"b", q"c")) + assert(first ≈ q"a") + assert(rest ≈ List(q"b", q"c")) + } + + property("deconstruct tuple last element") = test { + val q"($first, ..$rest, $last)" = q"(a, b, c, d)" + assert(first ≈ q"a") + assert(rest ≈ List(q"b", q"c")) + assert(last ≈ q"d") } property("deconstruct cases") = test { val q"$x match { case ..$cases }" = q"x match { case 1 => case 2 => }" - x ≈ q"x" && cases ≈ List(cq"1 =>", cq"2 =>") + assert(x ≈ q"x") + assert(cases ≈ List(cq"1 =>", cq"2 =>")) + } + + property("deconstruct splitting last case") = test { + val q"$_ match { case ..$cases case $last }" = q"x match { case 1 => case 2 => case 3 => }" + assert(cases ≈ List(cq"1 =>", cq"2 =>")) + assert(last ≈ cq"3 =>") } property("deconstruct block") = test { @@ -64,6 +99,12 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction assert(xs ≈ List(q"x1", q"x2", q"x3")) } + property("deconstruct last element of a block") = test { + val q"{ ..$xs; $x }" = q"x1; x2; x3; x4" + assert(xs ≈ List(q"x1", q"x2", q"x3")) + assert(x ≈ q"x4") + } + property("exhaustive function matcher") = test { def matches(line: String) { val q"(..$args) => $body" = parse(line) } matches("() => bippy") diff --git a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala index be7a96d91e..78b54a4e49 100644 --- a/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TypeConstructionProps.scala @@ -28,4 +28,10 @@ object TypeConstructionProps extends QuasiquoteProperties("type construction") val restpe = tq"C" assert(tq"..$argtpes => $restpe" ≈ tq"(A, B) => C") } -}
\ No newline at end of file + + property("empty tq") = test { + val tt: TypeTree = tq"" + assert(tt.tpe == null) + assert(tt.original == null) + } +} diff --git a/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala index 499f5d6d8e..0fdcc19052 100644 --- a/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TypeDeconstructionProps.scala @@ -13,23 +13,49 @@ object TypeDeconstructionProps extends QuasiquoteProperties("type deconstruction a ≈ Ident(name1) && b ≈ Ident(name2) } - property("tuple type") = test { + property("tuple type (1)") = test { val tq"(..$empty)" = tq"_root_.scala.Unit" assert(empty.isEmpty) + } + + property("tuple type (2)") = test { val tq"(..$ts)" = tq"(t1, t2)" assert(ts ≈ List(tq"t1", tq"t2")) + } + + property("tuple type (3)") = test { val tq"($head, ..$tail)" = tq"(t0, t1, t2)" - assert(head ≈ tq"t0" && tail ≈ List(tq"t1", tq"t2")) + assert(head ≈ tq"t0") + assert(tail ≈ List(tq"t1", tq"t2")) + } + + property("tuple type (4)") = test { + val tq"(..$init, $last)" = tq"(t0, t1, t2)" + assert(init ≈ List(tq"t0", tq"t1")) + assert(last ≈ tq"t2") } property("refined type") = test { val tq"T { ..$stats }" = tq"T { def foo; val x: Int; type Y = String }" - assert(stats ≈ (q"def foo" :: q"val x: Int" :: q"type Y = String" :: Nil)) + assert(stats ≈ List(q"def foo", q"val x: Int", q"type Y = String")) } - property("function type") = test { + property("function type (1)") = test { val tq"..$argtpes => $restpe" = tq"(A, B) => C" - assert(argtpes ≈ (tq"A" :: tq"B" :: Nil)) + assert(argtpes ≈ List(tq"A", tq"B")) assert(restpe ≈ tq"C") } -}
\ No newline at end of file + + property("function type (2)") = test { + val tq"(..$argtpes, $arglast) => $restpe" = tq"(A, B, C) => D" + assert(argtpes ≈ List(tq"A", tq"B")) + assert(arglast ≈ tq"C") + assert(restpe ≈ tq"D") + } + + property("match empty type tree") = test { + val tq"" = TypeTree() + // matches because type tree isn't syntactic without original + val tq"" = tq"${typeOf[Int]}" + } +} diff --git a/test/files/scalacheck/quasiquotes/TypecheckedProps.scala b/test/files/scalacheck/quasiquotes/TypecheckedProps.scala index 2f501435e3..3afb47952c 100644 --- a/test/files/scalacheck/quasiquotes/TypecheckedProps.scala +++ b/test/files/scalacheck/quasiquotes/TypecheckedProps.scala @@ -75,4 +75,11 @@ object TypecheckedProps extends QuasiquoteProperties("typechecked") { assert(f.original ≈ pq"Test.this.Cell") assert(args ≈ List(pq"v")) } -}
\ No newline at end of file + + property("extract inferred val type") = test { + val typechecked = typecheck(q"val x = 42") + val q"val x = 42" = typechecked + val q"val x: ${tq""} = 42" = typechecked + val q"val x: ${t: Type} = 42" = typechecked + } +} diff --git a/test/files/scalacheck/range.scala b/test/files/scalacheck/range.scala index 6c7c32bfdf..493083a51f 100644 --- a/test/files/scalacheck/range.scala +++ b/test/files/scalacheck/range.scala @@ -127,6 +127,47 @@ abstract class RangeTest(kind: String) extends Properties("Range "+kind) { (visited == expectedSize(r)) :| str(r) } + property("sum") = forAll(myGen) { r => +// println("----------") +// println("sum "+str(r)) + val rSum = r.sum + val expected = r.length match { + case 0 => 0 + case 1 => r.head + case _ => ((r.head + r.last).toLong * r.length / 2).toInt + } +// println("size: " + r.length) +// println("expected: " + expected) +// println("obtained: " + rSum) + + (rSum == expected) :| str(r) + } + +/* checks that sum respects custom Numeric */ + property("sumCustomNumeric") = forAll(myGen) { r => + val mod = 65536 + object mynum extends Numeric[Int] { + def plus(x: Int, y: Int): Int = (x + y) % mod + override def zero = 0 + + def fromInt(x: Int): Int = ??? + def minus(x: Int, y: Int): Int = ??? + def negate(x: Int): Int = ??? + def times(x: Int, y: Int): Int = ??? + def toDouble(x: Int): Double = ??? + def toFloat(x: Int): Float = ??? + def toInt(x: Int): Int = ((x % mod) + mod * 2) % mod + def toLong(x: Int): Long = ??? + def compare(x: Int, y: Int): Int = ??? + } + + val rSum = r.sum(mynum) + val expected = mynum.toInt(r.sum) + + (rSum == expected) :| str(r) + } + + property("length") = forAll(myGen suchThat (r => expectedSize(r).toInt == expectedSize(r))) { r => // println("length "+str(r)) (r.length == expectedSize(r)) :| str(r) @@ -224,7 +265,8 @@ object TooLargeRange extends Properties("Too Large Range") { property("Too large range throws exception") = forAll(genTooLargeStart) { start => try { val r = Range.inclusive(start, Int.MaxValue, 1) - println("how here? r = " + r.toString) + val l = r.length + println("how here? length = " + l + ", r = " + r.toString) false } catch { case _: IllegalArgumentException => true } diff --git a/test/junit/scala/collection/NumericRangeTest.scala b/test/junit/scala/collection/NumericRangeTest.scala new file mode 100644 index 0000000000..3980c31577 --- /dev/null +++ b/test/junit/scala/collection/NumericRangeTest.scala @@ -0,0 +1,140 @@ +package scala.collection.immutable + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import scala.math._ +import scala.util._ + +/* Tests various ranges by making sure they all agree on the same answers. */ +@RunWith(classOf[JUnit4]) +class RangeConsistencyTest { + def r2nr[T: Integral]( + r: Range, puff: T, stride: T, check: (T,T) => Boolean, bi: T => BigInt + ): List[(BigInt,Try[Int])] = { + val num = implicitly[Integral[T]] + import num._ + val one = num.one + + if (!check(puff, fromInt(r.start))) return Nil + val start = puff * fromInt(r.start) + val sp1 = start + one + val sn1 = start - one + + if (!check(puff, fromInt(r.end))) return Nil + val end = puff * fromInt(r.end) + val ep1 = end + one + val en1 = end - one + + if (!check(stride, fromInt(r.step))) return Nil + val step = stride * fromInt(r.step) + + def NR(s: T, e: T, i: T) = { + val delta = (bi(e) - bi(s)).abs - (if (r.isInclusive) 0 else 1) + val n = if (r.length == 0) BigInt(0) else delta / bi(i).abs + 1 + if (r.isInclusive) { + (n, Try(NumericRange.inclusive(s,e,i).length)) + } + else { + (n, Try(NumericRange(s,e,i).length)) + } + } + + List(NR(start, end, step)) ::: + (if (sn1 < start) List(NR(sn1, end, step)) else Nil) ::: + (if (start < sp1) List(NR(sp1, end, step)) else Nil) ::: + (if (en1 < end) List(NR(start, en1, step)) else Nil) ::: + (if (end < ep1) List(NR(start, ep1, step)) else Nil) + } + + // Motivated by SI-4370: Wrong result for Long.MinValue to Long.MaxValue by Int.MaxValue + @Test + def rangeChurnTest() { + val rn = new Random(4370) + for (i <- 0 to 10000) { control.Breaks.breakable { + val start = rn.nextInt + val end = rn.nextInt + val step = rn.nextInt(4) match { + case 0 => 1 + case 1 => -1 + case 2 => (rn.nextInt(11)+2)*(2*rn.nextInt(2)+1) + case 3 => var x = rn.nextInt; while (x==0) x = rn.nextInt; x + } + val r = if (rn.nextBoolean) Range.inclusive(start, end, step) else Range(start, end, step) + + try { r.length } + catch { case iae: IllegalArgumentException => control.Breaks.break } + + val lpuff = rn.nextInt(4) match { + case 0 => 1L + case 1 => rn.nextInt(11)+2L + case 2 => 1L << rn.nextInt(60) + case 3 => math.max(1L, math.abs(rn.nextLong)) + } + val lstride = rn.nextInt(4) match { + case 0 => lpuff + case 1 => 1L + case 2 => 1L << rn.nextInt(60) + case 3 => math.max(1L, math.abs(rn.nextLong)) + } + val lr = r2nr[Long]( + r, lpuff, lstride, + (a,b) => { val x = BigInt(a)*BigInt(b); x.isValidLong }, + x => BigInt(x) + ) + + lr.foreach{ case (n,t) => assert( + t match { + case Failure(_) => n > Int.MaxValue + case Success(m) => n == m + }, + (r.start, r.end, r.step, r.isInclusive, lpuff, lstride, n, t) + )} + + val bipuff = rn.nextInt(3) match { + case 0 => BigInt(1) + case 1 => BigInt(rn.nextLong) + Long.MaxValue + 2 + case 2 => BigInt("1" + "0"*(rn.nextInt(100)+1)) + } + val bistride = rn.nextInt(3) match { + case 0 => bipuff + case 1 => BigInt(1) + case 2 => BigInt("1" + "0"*(rn.nextInt(100)+1)) + } + val bir = r2nr[BigInt](r, bipuff, bistride, (a,b) => true, identity) + + bir.foreach{ case (n,t) => assert( + t match { + case Failure(_) => n > Int.MaxValue + case Success(m) => n == m + }, + (r.start, r.end, r.step, r.isInclusive, bipuff, bistride, n, t) + )} + }} + } + + @Test + def testSI4370() { assert{ + Try((Long.MinValue to Long.MaxValue by Int.MaxValue).length) match { + case Failure(iae: IllegalArgumentException) => true + case _ => false + } + }} + + @Test + def testSI6736() { + // These operations on overfull ranges should all succeed. + assert( (0 to Int.MaxValue).contains(4) ) + assert( !((Int.MinValue to 0).contains(4)) ) + assert( (Int.MinValue to 0).last == 0 ) + assert( (Int.MinValue until 5).last == 4 ) + assert( (-7 to -99 by -4).last == -99 && (-7 until -99 by -4).last == -95 ) + assert( (Int.MinValue to 5) == (Int.MinValue until 6) ) + assert( (-3 to Int.MaxValue).drop(4).length == Int.MaxValue ) + assert( (-3 to Int.MaxValue).take(1234) == (-3 to 1230) ) + assert( (-3 to Int.MaxValue).dropRight(4).length == Int.MaxValue ) + assert( (-3 to Int.MaxValue).takeRight(1234).length == 1234 ) + assert( (-3 to Int.MaxValue).dropWhile(_ <= 0).length == Int.MaxValue ) + assert( (-3 to Int.MaxValue).span(_ <= 0) match { case (a,b) => a.length == 4 && b.length == Int.MaxValue } ) + } +} diff --git a/test/junit/scala/collection/PagedSeq.scala b/test/junit/scala/collection/PagedSeq.scala new file mode 100644 index 0000000000..5f83cf6f31 --- /dev/null +++ b/test/junit/scala/collection/PagedSeq.scala @@ -0,0 +1,16 @@ +package scala.collection.immutable + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import org.junit.Assert._ + +/* Test for SI-6615 */ +@RunWith(classOf[JUnit4]) +class PagedSeqTest { + @Test + def rovingDoesNotNPE(): Unit = { + // should not NPE, and should equal the given Seq + assertEquals(Seq('a'), PagedSeq.fromStrings(List.fill(5000)("a")).slice(4096, 4097)) + } +} diff --git a/test/junit/scala/collection/SetMapConsistencyTest.scala b/test/junit/scala/collection/SetMapConsistencyTest.scala index c62b074483..0d6f43db06 100644 --- a/test/junit/scala/collection/SetMapConsistencyTest.scala +++ b/test/junit/scala/collection/SetMapConsistencyTest.scala @@ -476,4 +476,35 @@ class SetMapConsistencyTest { } assert(test) } + + @Test + def testSI8213() { + val am = new scala.collection.mutable.AnyRefMap[String, Int] + for (i <- 0 until 1024) am += i.toString -> i + am.getOrElseUpdate("1024", { am.clear; -1 }) + assert(am == scala.collection.mutable.AnyRefMap("1024" -> -1)) + val lm = new scala.collection.mutable.LongMap[Int] + for (i <- 0 until 1024) lm += i.toLong -> i + lm.getOrElseUpdate(1024, { lm.clear; -1 }) + assert(lm == scala.collection.mutable.LongMap(1024L -> -1)) + } + + // Mutating when an iterator is in the wild shouldn't produce random junk in the iterator + // Todo: test all sets/maps this way + @Test + def testSI8154() { + def f() = { + val xs = scala.collection.mutable.AnyRefMap[String, Int]("a" -> 1) + val it = xs.iterator + it.hasNext + xs.clear() + + if (it.hasNext) Some(it.next) + else None + } + assert(f() match { + case Some((a,b)) if (a==null || b==null) => false + case _ => true + }) + } } diff --git a/test/junit/scala/math/BigDecimalTest.scala b/test/junit/scala/math/BigDecimalTest.scala new file mode 100644 index 0000000000..d1ba96fcc8 --- /dev/null +++ b/test/junit/scala/math/BigDecimalTest.scala @@ -0,0 +1,225 @@ +package scala.math + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import java.math.{BigDecimal => BD, MathContext => MC} + +/* Tests various maps by making sure they all agree on the same answers. */ +@RunWith(classOf[JUnit4]) +class BigDecimalTest { + + // Motivated by SI-6173: BigDecimal#isWhole implementation is very heap intensive + @Test + def isWholeTest() { + val wholes = List( + BigDecimal(1), + BigDecimal(10L), + BigDecimal(14.000), + BigDecimal(new BD("19127981892347012385719827340123471923850195")), + BigDecimal("1e1000000000"), + BigDecimal(14.1928857191985e22), + BigDecimal(14.12519823759817, new MC(2)) + ) + val fracs = List( + BigDecimal(0.1), + BigDecimal(new BD("1.000000000000000000000000000000000001")), + BigDecimal(new BD("275712375971892375127591745810580123751.99999")), + BigDecimal("14.19238571927581e6"), + BigDecimal("912834718237510238591285")/2 + ) + assert(wholes.forall(_.isWhole) && fracs.forall(! _.isWhole)) + } + + // Motivated by SI-6699: BigDecimal.isValidDouble behaves unexpectedly + @Test + def isValidDoubleTest() { + val valids = List( + BigDecimal(1), + BigDecimal(19571.125), + BigDecimal.decimal(0.1), + BigDecimal(1e15) + ) + val invalids = List( + BigDecimal(new BD("1.0000000000000000000000000000000000000000001")), + BigDecimal("10e1000000"), + BigDecimal("10e-1000000") + ) + assert( + valids.forall(_.isDecimalDouble) && + invalids.forall(! _.isDecimalDouble) + ) + } + + // Motivated by SI-6173: BigDecimal#isWhole implementation is very heap intensive + @Test + def doesNotExplodeTest() { + val troublemaker = BigDecimal("1e1000000000") + val reasonable = BigDecimal("1e1000") + val reasonableInt = reasonable.toBigInt + assert( + reasonable.hashCode == reasonableInt.hashCode && + reasonable == reasonableInt && + reasonableInt == reasonable && + troublemaker.hashCode != reasonable.hashCode && + !(troublemaker == reasonableInt) && + !(reasonableInt == troublemaker) + ) + } + + // Motivated by SI-6456: scala.math.BigDecimal should not accept a null value + @Test + def refusesNullTest() { + def isIAE[A](a: => A) = try { a; false } catch { case iae: IllegalArgumentException => true } + def isNPE[A](a: => A) = try { a; false } catch { case npe: NullPointerException => true } + assert( + isIAE(new BigDecimal(null: BD, new MC(2))) && + isIAE(new BigDecimal(new BD("5.7"), null: MC)) && + isNPE(BigDecimal(null: BigInt)) && + isNPE(BigDecimal(null: String)) && + isNPE(BigDecimal(null: Array[Char])) + ) + } + + // Motivated by SI-6153: BigDecimal.hashCode() has high collision rate + @Test + def hashCodesAgreeTest() { + val bi: BigInt = 100000 + val bd: BigDecimal = 100000 + val l: Long = 100000 + val d: Double = 100000 + assert( + d.## == l.## && + l.## == bd.## && + bd.## == bi.## && + (bd pow 4).hashCode == (bi pow 4).hashCode && + BigDecimal("1e150000").hashCode != BigDecimal("1e150000").toBigInt.hashCode + ) + } + + // Motivated by noticing BigDecimal(0.1f) != BigDecimal(0.1) + @Test + def consistentTenthsTest() { + def tenths = List[Any]( + BigDecimal("0.1"), + 0.1, + BigDecimal.decimal(0.1f), + BigDecimal.decimal(0.1), + BigDecimal(0.1), + BigDecimal(BigInt(1), 1), + BigDecimal(new BD("0.1")), + BigDecimal(1L, 1), + BigDecimal(1) / BigDecimal(10), + BigDecimal(10).pow(-1) + ) + for (a <- tenths; b <- tenths) assert(a == b, s"$a != $b but both should be 0.1") + } + + // Motivated by noticing BigDecimal(123456789, mc6) != BigDecimal(123456789L, mc6) + // where mc6 is a MathContext that rounds to six digits + @Test + def consistentRoundingTest() { + val mc6 = new MC(6) + val sameRounding = List( + List( + 123457000, + 123457000L, + 123457e3, + BigDecimal(123456789, mc6), + BigDecimal(123456789L, mc6), + BigDecimal(123456789d, mc6), + BigDecimal("123456789", mc6), + BigDecimal(Array('1','2','3','4','5','6','7','8','9'), mc6), + BigDecimal(BigInt(123456789), mc6), + BigDecimal(BigInt(1234567890), 1, mc6), + BigDecimal.decimal(123456789, mc6), + BigDecimal.decimal(123456789d, mc6), + BigDecimal.decimal(new BD("123456789"), mc6) + ), + List( + 123456789, + 123456789L, + 123456789d, + new BigDecimal(new BD("123456789"), mc6), + new BigDecimal(new BD("123456789")), + BigDecimal(123456789), + BigDecimal(123456789L), + BigDecimal(123456789d), + BigDecimal("123456789"), + BigDecimal(Array('1','2','3','4','5','6','7','8','9')), + BigDecimal(BigInt(123456789)), + BigDecimal(BigInt(1234567890), 1), + BigDecimal.decimal(123456789), + BigDecimal.decimal(123456789d), + BigDecimal.valueOf(123456789d, mc6) + ) + ) + sameRounding.map(_.zipWithIndex).foreach{ case xs => + for ((a,i) <- xs; (b,j) <- xs) { + assert(a == b, s"$a != $b (#$i != #$j) but should be the same") + assert(a.## == b.##, s"Hash code mismatch in equal BigDecimals: #$i != #$j") + } + } + val List(xs, ys) = sameRounding.map(_.zipWithIndex) + for ((a,i) <- xs; (b,j) <- ys) assert(a != b, s"$a == $b (#$i == #$j) but should be different") + } + + // This was unexpectedly truncated in 2.10 + @Test + def noPrematureRoundingTest() { + val text = "9791375983750284059237954823745923845928547807345082378340572986452364" + val same = List[Any]( + BigInt(text), BigDecimal(text), BigDecimal(new BD(text)) + ) + for (a <- same; b <- same) assert(a == b, s"$a != $b but should be the same") + } + + // Tests attempts to make sane the representation of IEEE binary32 and binary64 + // (i.e. Float and Double) with Scala's text-is-King BigDecimal policy + @Test + def churnRepresentationTest() { + val rn = new scala.util.Random(42) + for (i <- 1 to 1000) { + val d = rn.nextDouble + assert({ + BigDecimal.decimal(d).isDecimalDouble && + BigDecimal.binary(d).isBinaryDouble && + BigDecimal.exact(d).isExactDouble + }, s"At least one wrong BigDecimal representation for $d") + } + for (i <- 1 to 1000) { + val f = rn.nextFloat + assert({ + BigDecimal.decimal(f).isDecimalFloat && + BigDecimal.binary(f).isBinaryFloat && + BigDecimal.exact(f).isExactFloat + }, s"At least one wrong BigDecimal representation for $f") + } + for (i <- 1 to 1000) { + val ndig = 15+rn.nextInt(5) + val s = Array.fill(ndig)((rn.nextInt(10)+'0').toChar).mkString + val bi = BigInt(s) + val l = bi.toLong + val d = bi.toDouble + val bd = BigDecimal(bi) + val bd2 = BigDecimal.decimal(d) + assert(!bi.isValidLong || bi == l, s"Should be invalid or equal: $bi $l") + assert(!bi.isValidDouble || bi == d, s"Should be invalid or equal: $bi $d") + assert(bd == bi, s"Should be equal $bi $bd") + assert(bd.## == bi.##, s"Hash codes for $bi, $bd should be equal") + assert(bd == bd2 || bd2 != BigDecimal.exact(d) || !bi.isValidDouble, + s"$bd != $bd2 should only be when inexact or invalid") + assert(d == bd2 && bd2 == d, s"$d != $bd2 but they should equal") + } + val different = List( + BigDecimal.decimal(0.1), + BigDecimal.binary(0.1), + BigDecimal.binary(0.1, new MC(25)), + BigDecimal.exact(0.1), + BigDecimal.exact(0.1f), + BigDecimal.decimal((0.1f).toDouble) + ) + for (a <- different; b <- different if (a ne b)) + assert(a != b, "BigDecimal representations of Double mistakenly conflated") + } +} diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala new file mode 100644 index 0000000000..a08a29a9d1 --- /dev/null +++ b/test/junit/scala/reflect/internal/PrintersTest.scala @@ -0,0 +1,820 @@ +package scala.reflect.internal + +import org.junit.Test +import org.junit.Assert._ +import scala.tools.reflect._ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror=>cm} +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(classOf[JUnit4]) +class PrintersTest extends BasePrintTests + with ClassPrintTests + with TraitPrintTests + with ValAndDefPrintTests + with QuasiTreesPrintTests + with PackagePrintTests + +object PrinterHelper { + val toolbox = cm.mkToolBox() + def assertPrintedCode(code: String, tree: Tree = EmptyTree) = { + def processEOL(resultCode: String) = { + import scala.reflect.internal.Chars._ + resultCode.replaceAll(s"$CR$LF", s"$LF").replace(CR, LF) + } + + val toolboxTree = + try{ + toolbox.parse(code) + } catch { + case e:scala.tools.reflect.ToolBoxError => throw new Exception(e.getMessage + ": " + code) + } + if (tree ne EmptyTree) assertEquals("using quasiquote or given tree"+"\n", code.trim, processEOL(showCode(tree))) + else assertEquals("using toolbox parser", code.trim, processEOL(showCode(toolboxTree))) + } + + implicit class StrContextStripMarginOps(val stringContext: StringContext) extends util.StripMarginInterpolator +} + +import PrinterHelper._ + +trait BasePrintTests { + @Test def testIdent = assertPrintedCode("*", Ident("*")) + + @Test def testConstant1 = assertPrintedCode("\"*\"", Literal(Constant("*"))) + + @Test def testConstant2 = assertPrintedCode("42", Literal(Constant(42))) + + @Test def testConstantFloat = assertPrintedCode("42.0F", Literal(Constant(42f))) + + @Test def testConstantDouble = assertPrintedCode("42.0", Literal(Constant(42d))) + + @Test def testConstantLong = assertPrintedCode("42L", Literal(Constant(42l))) + + @Test def testOpExpr = assertPrintedCode("(5).+(4)") + + @Test def testName1 = assertPrintedCode("class test") + + @Test def testName2 = assertPrintedCode("class *") + + @Test def testName4 = assertPrintedCode("class `a*`") + + @Test def testName5 = assertPrintedCode("val :::: = 1") + + @Test def testName6 = assertPrintedCode("val `::::t` = 1") + + @Test def testName7 = assertPrintedCode("""class \/""") + + @Test def testName8 = assertPrintedCode("""class \\\\""") + + @Test def testName9 = assertPrintedCode("""class test_\/""") + + @Test def testName10 = assertPrintedCode("""class `*_*`""") + + @Test def testName11 = assertPrintedCode("""class `a_*`""") + + @Test def testName12 = assertPrintedCode("""class `*_a`""") + + @Test def testName13 = assertPrintedCode("""class a_a""") + + @Test def testName14 = assertPrintedCode("val x$11 = 5") + + @Test def testName15 = assertPrintedCode("class `[]`") + + @Test def testName16 = assertPrintedCode("class `()`") + + @Test def testName17 = assertPrintedCode("class `{}`") + + @Test def testName18 = assertPrintedCode("class <>") + + @Test def testName19 = assertPrintedCode("""class `class`""") + + @Test def testName20 = assertPrintedCode("""class `test name`""") + + @Test def testIfExpr1 = assertPrintedCode(sm""" + |if (a) + | ((expr1): Int) + |else + | ((expr2): Int)""") + + @Test def testIfExpr2 = assertPrintedCode(sm""" + |(if (a) + | { + | expr1; + | () + | } + |else + | { + | expr2; + | () + | }).toString""") + + @Test def testIfExpr3 = assertPrintedCode(sm""" + |(if (a) + | { + | expr1; + | () + | } + |else + | { + | expr2; + | () + | }).method1().method2()""") + + //val x = true && true && false.! + @Test def testBooleanExpr1 = assertPrintedCode("val x = true.&&(true).&&(false.!)") + + //val x = true && !(true && false) + @Test def testBooleanExpr2 = assertPrintedCode("val x = true.&&(true.&&(false).`unary_!`)") + + @Test def testNewExpr1 = assertPrintedCode("new foo()") + + //new foo { test } + @Test def testNewExpr2 = assertPrintedCode(sm""" + |{ + | final class $$anon extends foo { + | test + | }; + | new $$anon() + |}""") + + @Test def testNewExpr3 = assertPrintedCode("new foo[t]()") + + @Test def testNewExpr4 = assertPrintedCode("new foo(x)") + + @Test def testNewExpr5 = assertPrintedCode("new foo[t](x)") + + //new foo[t](x) { () } + @Test def testNewExpr6 = assertPrintedCode(sm""" + |{ + | final class $$anon extends foo[t](x) { + | () + | }; + | new $$anon() + |}""") + + //new foo with bar + @Test def testNewExpr7 = assertPrintedCode(sm""" + |{ + | final class $$anon extends foo with bar; + | new $$anon() + |}""") + + //new { anonymous } + @Test def testNewExpr8 = assertPrintedCode(sm""" + |{ + | final class $$anon { + | anonymous + | }; + | new $$anon() + |}""") + + //new { val early = 1 } with Parent[Int] { body } + @Test def testNewExpr9 = assertPrintedCode(sm""" + |{ + | final class $$anon extends { + | val early = 1 + | } with Parent[Int] { + | body + | }; + | new $$anon() + |}""") + + //new Foo { self => } + @Test def testNewExpr10 = assertPrintedCode(sm""" + |{ + | final class $$anon extends Foo { self => + | + | }; + | new $$anon() + |}""") + + @Test def testReturn = assertPrintedCode("def test: Int = return 42") + + @Test def testFunc1 = assertPrintedCode("List(1, 2, 3).map(((i: Int) => i.-(1)))") + + //val sum: Seq[Int] => Int = _ reduceLeft (_+_) + @Test def testFunc2 = assertPrintedCode("val sum: _root_.scala.Function1[Seq[Int], Int] = ((x$1) => x$1.reduceLeft(((x$2, x$3) => x$2.+(x$3))))") + + //List(1, 2, 3) map (_ - 1) + @Test def testFunc3 = assertPrintedCode("List(1, 2, 3).map(((x$1) => x$1.-(1)))") + + @Test def testImport1 = assertPrintedCode("import scala.collection.mutable") + + @Test def testImport2 = assertPrintedCode("import java.lang.{String=>Str}") + + @Test def testImport3 = assertPrintedCode("import java.lang.{String=>Str, Object=>_, _}") + + @Test def testImport4 = assertPrintedCode("import scala.collection._") +} + +trait ClassPrintTests { + @Test def testClass = assertPrintedCode("class *") + + @Test def testClassWithBody = assertPrintedCode(sm""" + |class X { + | def y = "test" + |}""") + + @Test def testClassWithPublicParams = assertPrintedCode("class X(val x: Int, val s: String)") + + @Test def testClassWithParams1 = assertPrintedCode("class X(x: Int, s: String)") + + @Test def testClassWithParams2 = assertPrintedCode("class X(@test x: Int, s: String)") + + @Test def testClassWithParams3 = assertPrintedCode("class X(implicit x: Int, s: String)") + + @Test def testClassWithParams4 = assertPrintedCode("class X(implicit @test x: Int, s: String)") + + @Test def testClassWithParams5 = assertPrintedCode("class X(override private[this] val x: Int, s: String) extends Y") + + @Test def testClassWithParams6 = assertPrintedCode("class X(@test1 override private[this] val x: Int, @test2(param1 = 7) s: String) extends Y") + + @Test def testClassWithParams7 = assertPrintedCode("class X protected (val x: Int, val s: String)") + + @Test def testClassWithParams8 = assertPrintedCode("class X(var x: Int)") + + @Test def testClassWithParams9 = assertPrintedCode("class X(var x: Int*)") + + @Test def testClassWithByNameParam = assertPrintedCode("class X(x: => Int)") + + @Test def testClassWithDefault = assertPrintedCode("class X(var x: Int = 5)") + + @Test def testClassWithParams10 = assertPrintedCode("class X(protected[zzz] var x: Int)") + + @Test def testClassWithParams11 = assertPrintedCode("class X(override var x: Int) extends F(x) with E(x)") + + @Test def testClassWithParams12 = assertPrintedCode("class X(val y: Int)()(var z: Double)") + + @Test def testClassWithImplicitParams = assertPrintedCode("class X(var i: Int)(implicit val d: Double, var f: Float)") + + @Test def testClassWithEarly = assertPrintedCode(sm""" + |class X(var i: Int) extends { + | val a: String = i; + | type B + |} with Y""") + + @Test def testClassWithThrow1 = assertPrintedCode(sm""" + |class Throw1 { + | throw new Exception("exception!") + |}""") + + @Test def testClassWithThrow2 = assertPrintedCode(sm""" + |class Throw2 { + | var msg = " "; + | val e = new Exception(msg); + | throw e + |}""") + + /* + class Test { + val (a, b) = (1, 2) + } + */ + @Test def testClassWithAssignmentWithTuple1 = assertPrintedCode(sm""" + |class Test { + | private[this] val x$$1 = (scala.Tuple2(1, 2): @scala.unchecked) match { + | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2(a, b) + | }; + | val a = x$$1._1; + | val b = x$$1._2 + |}""") + + /* + class Test { + val (a, b) = (1).->(2) + } + */ + @Test def testClassWithAssignmentWithTuple2 = assertPrintedCode(sm""" + |class Test { + | private[this] val x$$1 = ((1).->(2): @scala.unchecked) match { + | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2(a, b) + | }; + | val a = x$$1._1; + | val b = x$$1._2 + |}""") + + /* + class Test { + val List(one, three, five) = List(1,3,5) + } + */ + @Test def testClassWithPatternMatchInAssignment = assertPrintedCode(sm""" + |class Test { + | private[this] val x$$1 = (List(1, 3, 5): @scala.unchecked) match { + | case List((one @ _), (three @ _), (five @ _)) => scala.Tuple3(one, three, five) + | }; + | val one = x$$1._1; + | val three = x$$1._2; + | val five = x$$1._3 + |}""") + + //class A(l: List[_]) + @Test def testClassWithExistentialParameter1 = assertPrintedCode(sm""" + |class Test(l: (List[_$$1] forSome { + | type _$$1 + |}))""") + + @Test def testClassWithExistentialParameter2 = assertPrintedCode(sm""" + |class B(l: (List[T] forSome { + | type T + |}))""") + + @Test def testClassWithCompoundTypeTree = assertPrintedCode(sm""" + |{ + | trait A; + | trait B; + | abstract class C(val a: A with B) { + | def method(x: A with B with C { + | val x: Float + | }): A with B + | }; + | () + |}""") + + @Test def testClassWithSelectFromTypeTree = assertPrintedCode(sm""" + |{ + | trait A { + | type T + | }; + | class B(t: (A)#T); + | () + |}""") + + @Test def testImplicitClass = assertPrintedCode("implicit class X(protected[zzz] var x: Int)") + + @Test def testAbstractClass = assertPrintedCode("abstract class X(protected[zzz] var x: Int)") + + @Test def testCaseClassWithParams1 = assertPrintedCode("case class X(x: Int, s: String)") + + @Test def testCaseClassWithParams2 = assertPrintedCode("case class X(protected val x: Int, s: String)") + + @Test def testCaseClassWithParams3 = assertPrintedCode("case class X(implicit x: Int, s: String)") + + @Test def testCaseClassWithParams4 = assertPrintedCode("case class X(override val x: Int, s: String) extends Y") + + @Test def testCaseClassWithBody = assertPrintedCode(sm""" + |case class X() { + | def y = "test" + |}""") + + @Test def testLocalClass = assertPrintedCode(sm""" + |def test = { + | class X(var a: Int) { + | def y = "test" + | }; + | new X(5) + |}""") + + @Test def testLocalCaseClass = assertPrintedCode(sm""" + |def test = { + | case class X(var a: Int) { + | def y = "test" + | }; + | new X(5) + |}""") + + @Test def testSuperInClass = assertPrintedCode(sm""" + |{ + | trait Root { + | def r = "Root" + | }; + | class X extends Root { + | def superX = super.r + | }; + | class Y extends X with Root { + | class Inner { + | val myY = Y.super.r + | }; + | def fromX = super[X].r; + | def fromRoot = super[Root].r + | }; + | () + |}""") + + @Test def testThisInClass = assertPrintedCode(sm""" + |class Outer { + | class Inner { + | val outer = Root.this + | }; + | val self = this + |}""") + + @Test def testCaseClassWithParamsAndBody = assertPrintedCode(sm""" + |case class X(x: Int, s: String) { + | def y = "test" + |}""") + + @Test def testObject = assertPrintedCode("object *") + + @Test def testObjectWithBody = assertPrintedCode(sm""" + |object X { + | def y = "test" + |}""") + + @Test def testObjectWithEarly1 = assertPrintedCode(sm""" + |object X extends { + | val early: T = v + |} with Bar""") + + @Test def testObjectWithEarly2 = assertPrintedCode(sm""" + |object X extends { + | val early: T = v; + | type EarlyT = String + |} with Bar""") + + @Test def testObjectWithSelf = assertPrintedCode(sm""" + |object Foo extends Foo { self => + | body + |}""") + + @Test def testObjectInh = assertPrintedCode("private[Y] object X extends Bar with Baz") + + @Test def testObjectWithPatternMatch1 = assertPrintedCode(sm""" + |object PM1 { + | List(1, 2) match { + | case (i @ _) => i + | } + |}""") + + @Test def testObjectWithPatternMatch2 = assertPrintedCode(sm""" + |object PM2 { + | List(1, 2).map({ + | case (i @ _) if i.>(5) => i + | }) + |}""") + + //case i: Int => i + @Test def testObjectWithPatternMatch3 = assertPrintedCode(sm""" + |object PM3 { + | List(1, 2).map({ + | case (i @ ((_): Int)) => i + | }) + |}""") + + //case a @ (i: Int) => i + @Test def testObjectWithPatternMatch4 = assertPrintedCode(sm""" + |object PM4 { + | List(1, 2).map({ + | case (a @ (i @ ((_): Int))) => i + | }) + |}""") + + @Test def testObjectWithPatternMatch5 = assertPrintedCode(sm""" + |object PM5 { + | List(1, 2).map({ + | case _ => 42 + | }) + |}""") + + @Test def testObjectWithPatternMatch6 = assertPrintedCode(sm""" + |object PM6 { + | List(1, 2) match { + | case ::((x @ _), (xs @ _)) => x + | } + |}""") + + @Test def testObjectWithPatternMatch7 = assertPrintedCode(sm""" + |object PM7 { + | List(1, 2).map({ + | case (0| 1) => true + | case _ => false + | }) + |}""") + + @Test def testObjectWithPatternMatch8 = assertPrintedCode(sm""" + |object PM8 { + | "abcde".toList match { + | case Seq((car @ _), _*) => car + | } + |}""") + + @Test def testObjectWithPatternMatch9 = assertPrintedCode(sm""" + |{ + | object Extractor { + | def unapply(i: Int) = Some(i) + | }; + | object PM9 { + | 42 match { + | case (a @ Extractor((i @ _))) => i + | } + | }; + | () + |}""") + + @Test def testObjectWithPartialFunc = assertPrintedCode(sm""" + |object Test { + | def partFuncTest[A, B](e: Either[A, B]): scala.Unit = e match { + | case Right(_) => () + | } + |}""") + + @Test def testObjectWithTry = assertPrintedCode(sm""" + |object Test { + | import java.io; + | var file: PrintStream = null; + | try { + | val out = new FileOutputStream("myfile.txt"); + | file = new PrintStream(out) + | } catch { + | case (ioe @ ((_): IOException)) => println("ioe") + | case (e @ ((_): Exception)) => println("e") + | } finally println("finally") + |}""") +} + +trait TraitPrintTests { + @Test def testTrait = assertPrintedCode("trait *") + + @Test def testTraitWithBody = assertPrintedCode(sm""" + |trait X { + | def y = "test" + |}""") + + @Test def testTraitWithSelfTypeAndBody = assertPrintedCode(sm""" + |trait X { self: Order => + | def y = "test" + |}""") + + @Test def testTraitWithSelf1 = assertPrintedCode(sm""" + |trait X { self => + | def y = "test" + |}""") + + @Test def testTraitWithSelf2 = assertPrintedCode(sm""" + |trait X { self: Foo with Bar => + | val x: Int = 1 + |}""") + + @Test def testTraitTypeParams = assertPrintedCode("trait X[A, B]") + + @Test def testTraitWithBody2 = assertPrintedCode(sm""" + |trait X { + | def foo: scala.Unit; + | val bar: Baz + |}""") + + @Test def testTraitWithInh = assertPrintedCode("trait X extends A with B") + + @Test def testTraitWithEarly1 = assertPrintedCode(sm""" + |trait X extends { + | val x: Int = 1 + |} with Any""") + + @Test def testTraitWithEarly2 = assertPrintedCode(sm""" + |trait X extends { + | val x: Int = 0; + | type Foo = Bar + |} with Y""") + + @Test def testTraitWithEarly3 = assertPrintedCode(sm""" + |trait X extends { + | val x: Int = 5; + | val y: Double = 4.0; + | type Foo; + | type XString = String + |} with Y""") + + @Test def testTraitWithEarly4 = assertPrintedCode(sm""" + |trait X extends { + | val x: Int = 5; + | val y: Double = 4.0; + | type Foo; + | type XString = String + |} with Y { + | val z = 7 + |}""") + + @Test def testTraitWithEarly5 = assertPrintedCode(sm""" + |trait X extends { + | override protected[this] val x: Int = 5; + | val y: Double = 4.0; + | private type Foo; + | private[ee] type XString = String + |} with Y { + | val z = 7 + |}""") + + @Test def testTraitWithSingletonTypeTree = assertPrintedCode(sm""" + |trait Test { + | def testReturnSingleton(): this.type + |}""") + + @Test def testTraitWithThis = assertPrintedCode(sm""" + |trait Test { _ : X with Y => + | + |}""", q"trait Test { this: X with Y => }") + + @Test def testTraitWithWhile1 = assertPrintedCode(sm""" + |trait Test { + | while (true.!=(false)) + | println("testing...") + | + |}""") + + @Test def testTraitWithWhile2 = assertPrintedCode(sm""" + |trait Test { + | while (true) + | { + | println("testing..."); + | println("testing...") + | } + | + |}""") + + @Test def testTraitWithDoWhile1 = assertPrintedCode(sm""" + |trait Test { + | do + | println("testing...") + | while (true) + |}""") + + @Test def testTraitWithTypes = assertPrintedCode(sm""" + |trait Test { + | type A = Int; + | type B >: Nothing <: AnyRef; + | protected type C >: Nothing; + | type D <: AnyRef + |}""") +} + +trait ValAndDefPrintTests { + @Test def testVal1 = assertPrintedCode("val a: Unit = null") + + @Test def testVal2 = assertPrintedCode("val * : Unit = null") + + @Test def testVal3 = assertPrintedCode("val a_ : Unit = null") + + @Test def testDef1 = assertPrintedCode("def a: Unit = null") + + @Test def testDef2 = assertPrintedCode("def * : Unit = null") + + @Test def testDef3 = assertPrintedCode("def a_(x: Int): Unit = null") + + @Test def testDef4 = assertPrintedCode("def a_ : Unit = null") + + @Test def testDef5 = assertPrintedCode("def a_(* : Int): Unit = null") + + @Test def testDef6 = assertPrintedCode("def a_(b_ : Int): Unit = null") + + @Test def testDef7 = assertPrintedCode(sm""" + |{ + | def test1 = (); + | def test2() = () + |}""", + Block( + DefDef(NoMods, newTermName("test1"), Nil, Nil, EmptyTree, Literal(Constant(()))), + DefDef(NoMods, newTermName("test2"), Nil, Nil :: Nil, EmptyTree, Literal(Constant(()))) + ) + ) + + @Test def testDef8 = { + val arg = ValDef(Modifiers(Flag.IMPLICIT) , newTermName("a"), + AppliedTypeTree(Ident(newTypeName("R")), List(Ident(newTypeName("X")))), EmptyTree) + + //def m[X](implicit a: R[X]) = () + val tree = DefDef(NoMods, newTermName("test"), TypeDef(NoMods, newTypeName("X"), Nil, EmptyTree) :: Nil, + List(List(arg)), EmptyTree, Literal(Constant(()))) + + assertPrintedCode("def test[X](implicit a: R[X]) = ()", tree) + } + + @Test def testDefWithParams1 = assertPrintedCode("def foo(x: Int*) = null") + + @Test def testDefWithParams2 = assertPrintedCode("def foo(x: Int)(y: Int = 1) = null") + + @Test def testDefWithTypeParams1 = assertPrintedCode("def foo[A, B, C](x: A)(y: Int = 1): C = null") + + @Test def testDefWithTypeParams2 = assertPrintedCode("def foo[A, B <: Bar] = null") + + @Test def testDefWithAnn1 = assertPrintedCode("@annot def foo = null") + + @Test def testDefWithAnn2 = assertPrintedCode("@a(x) def foo = null") + + @Test def testDefWithAnn3 = assertPrintedCode("@Foo[A, B] def foo = null") + + @Test def testDefWithAnn4 = assertPrintedCode("@Foo(a)(b)(x, y) def foo = null") + + @Test def testDefWithAnn5 = assertPrintedCode("@Foo[A, B](a)(b) @Bar def foo(x: Int) = null") + + @Test def testDefWithAnn6 = assertPrintedCode("@test1(new test2()) def foo = 42") + + @Test def testDefWithAnn7 = assertPrintedCode("@`t*` def foo = 42") + + @Test def testDefWithAnn8 = assertPrintedCode("@throws(classOf[Exception]) def foo = throw new Exception()") + + @Test def testAnnotated1 = assertPrintedCode("def foo = 42: @test1") + + @Test def testAnnotated2 = assertPrintedCode("""def foo = 42: @test1(42, z = "5")""") + + @Test def testAnnotated3 = assertPrintedCode("def foo = (42: @test1): @test2(new test1())") + + @Test def testAnnotated4 = assertPrintedCode("""def foo = 42: @test1(4, "testing")(4.2)""") + + @Test def testAnnotated5 = assertPrintedCode("""def foo = (42: @test1(4, "testing")(4.2)): @test2(1, "bar")(3.14)""") + + @Test def testAnnotated6 = assertPrintedCode("def foo = ((42: @test1): @test2(new test1())): @test3(1)(2, 3)(4)") + + @Test def testAnnotated7 = assertPrintedCode(sm""" + |(x: @unchecked) match { + | case ((_): Int) => true + | case _ => false + |}""") + + @Test def testAnnotated8 = assertPrintedCode(sm""" + |((x: @unchecked): @test1(1, "testing")(3.14)) match { + | case _ => true + |}""") +} + +trait PackagePrintTests { + @Test def testPackage1 = assertPrintedCode(sm""" + |package foo.bar { + | + |}""") + + @Test def testPackage2 = assertPrintedCode(sm""" + |package foo { + | class C + | + | object D + |}""") + + //package object foo extends a with b + @Test def testPackage3 = assertPrintedCode(sm""" + |package foo { + | object `package` extends a with b + |}""") + + //package object foo { def foo; val x = 1 } + @Test def testPackage4 = assertPrintedCode(sm""" + |package foo { + | object `package` { + | def foo: scala.Unit; + | val x = 1 + | } + |}""") + + //package object foo extends { val x = 1; type I = Int } with Any + @Test def testPackage5 = assertPrintedCode(sm""" + |package foo { + | object `package` extends { + | val x = 1; + | type I = Int + | } with Any + |}""") +} + +trait QuasiTreesPrintTests { + @Test def testQuasiIdent = assertPrintedCode("*", q"*") + + @Test def testQuasiVal = assertPrintedCode("val * : Unit = null", q"val * : Unit = null") + + @Test def testQuasiDef = assertPrintedCode("def * : Unit = null", q"def * : Unit = null") + + @Test def testQuasiTrait = assertPrintedCode("trait *", q"trait *") + + @Test def testQuasiClass = assertPrintedCode("class *", q"class *") + + @Test def testQuasiClassWithPublicParams = assertPrintedCode( "class X(val x: Int, val s: String)", q"class X(val x: Int, val s:String)" ) + + @Test def testQuasiClassWithParams = assertPrintedCode("class X(x: Int, s: String)", q"class X(x: Int, s:String)") + + @Test def testQuasiObject = assertPrintedCode("object *", q"object *") + + @Test def testQuasiObjectWithBody = assertPrintedCode(sm""" + |object X { + | def y = "test" + |}""", q"""object X{ def y = "test" }""") + + @Test def testQuasiClassWithBody = assertPrintedCode(sm""" + |class X { + | def y = "test" + |}""", q"""class X{ def y = "test" }""") + + @Test def testQuasiTraitWithBody = assertPrintedCode(sm""" + |trait X { + | def y = "test" + |}""", q"""trait X{ def y = "test" }""") + + @Test def testQuasiTraitWithSelfTypeAndBody = assertPrintedCode(sm""" + |trait X { self: Order => + | def y = "test" + |}""", q"""trait X{ self: Order => def y = "test" }""") + + @Test def testQuasiTraitWithSelf = assertPrintedCode(sm""" + |trait X { self => + | def y = "test" + |}""", q"""trait X{ self => def y = "test" }""") + + @Test def testQuasiCaseClassWithBody = assertPrintedCode(sm""" + |case class X() { + | def y = "test" + |}""", q"""case class X() { def y = "test" }""") + + @Test def testQuasiCaseClassWithParamsAndBody = assertPrintedCode(sm""" + |case class X(x: Int, s: String) { + | def y = "test" + |}""", q"""case class X(x: Int, s: String){ def y = "test" }""") +} diff --git a/test/junit/scala/reflect/internal/util/SourceFileTest.scala b/test/junit/scala/reflect/internal/util/SourceFileTest.scala new file mode 100644 index 0000000000..903e705ba2 --- /dev/null +++ b/test/junit/scala/reflect/internal/util/SourceFileTest.scala @@ -0,0 +1,55 @@ +package scala.reflect.internal.util + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(classOf[JUnit4]) +class SourceFileTest { + def lineContentOf(code: String, offset: Int) = + Position.offset(new BatchSourceFile("", code), offset).lineContent + + @Test + def si8205_overflow(): Unit = { + val file = new BatchSourceFile("", "code no newline") + // the bug in lineToString counted until MaxValue, and the AIOOBE came from here + assertFalse(file.isEndOfLine(Int.MaxValue)) + } + + @Test + def si8205_lineToString(): Unit = { + assertEquals("", lineContentOf("", 0)) + assertEquals("abc", lineContentOf("abc", 0)) + assertEquals("abc", lineContentOf("abc", 3)) + assertEquals("code no newline", lineContentOf("code no newline", 1)) + assertEquals("", lineContentOf("\n", 0)) + assertEquals("abc", lineContentOf("abc\ndef", 0)) + assertEquals("abc", lineContentOf("abc\ndef", 3)) + assertEquals("def", lineContentOf("abc\ndef", 4)) + assertEquals("def", lineContentOf("abc\ndef", 6)) + assertEquals("def", lineContentOf("abc\ndef\n", 7)) + } + + @Test + def CRisEOL(): Unit = { + assertEquals("", lineContentOf("\r", 0)) + assertEquals("abc", lineContentOf("abc\rdef", 0)) + assertEquals("abc", lineContentOf("abc\rdef", 3)) + assertEquals("def", lineContentOf("abc\rdef", 4)) + assertEquals("def", lineContentOf("abc\rdef", 6)) + assertEquals("def", lineContentOf("abc\rdef\r", 7)) + } + + @Test + def CRNLisEOL(): Unit = { + assertEquals("", lineContentOf("\r\n", 0)) + assertEquals("abc", lineContentOf("abc\r\ndef", 0)) + assertEquals("abc", lineContentOf("abc\r\ndef", 3)) + assertEquals("abc", lineContentOf("abc\r\ndef", 4)) + assertEquals("def", lineContentOf("abc\r\ndef", 5)) + assertEquals("def", lineContentOf("abc\r\ndef", 7)) + assertEquals("def", lineContentOf("abc\r\ndef", 8)) + assertEquals("def", lineContentOf("abc\r\ndef\r\n", 9)) + } +} diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala index a3699a4eeb..b42e9a07cb 100644 --- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala +++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala @@ -69,6 +69,7 @@ class SymbolTableForUnitTesting extends SymbolTable { // Members declared in scala.reflect.internal.Required def picklerPhase: scala.reflect.internal.Phase = SomePhase + def erasurePhase: scala.reflect.internal.Phase = SomePhase // Members declared in scala.reflect.internal.SymbolTable def currentRunId: Int = 1 diff --git a/test/osgi/src/BasicReflection.scala b/test/osgi/src/BasicReflection.scala index 68fedb7c83..d601f04f89 100644 --- a/test/osgi/src/BasicReflection.scala +++ b/test/osgi/src/BasicReflection.scala @@ -2,6 +2,8 @@ package tools.test.osgi package reflection package basic +import scala.language.higherKinds + import org.junit.Assert._ import org.ops4j.pax.exam.CoreOptions._ diff --git a/test/osgi/src/ScalaOsgiHelper.scala b/test/osgi/src/ScalaOsgiHelper.scala index 7b14cf20e8..084afe8643 100644 --- a/test/osgi/src/ScalaOsgiHelper.scala +++ b/test/osgi/src/ScalaOsgiHelper.scala @@ -1,5 +1,5 @@ package tools.test.osgi - + import org.ops4j.pax.exam.CoreOptions._ import org.ops4j.pax.exam import java.io.File @@ -12,7 +12,7 @@ trait ScalaOsgiHelper { } private def filteredBundleFiles(names: String*): Array[exam.Option] = - for(bundle <- allBundleFiles; if names exists (bundle.getName contains)) + for(bundle <- allBundleFiles; if names exists (bundle.getName contains _)) yield makeBundle(bundle) private def makeBundle(file: File): exam.Option = @@ -34,5 +34,5 @@ trait ScalaOsgiHelper { val bundles = filteredBundleFiles("scala-library") bundles ++ Array[exam.Option](felix(), equinox(), junitBundles()) } - + } diff --git a/test/pending/neg/macro-invalidusage-badbounds-b/Impls_1.scala b/test/pending/neg/macro-invalidusage-badbounds-b/Impls_1.scala index 89020de7dd..be47d5cec4 100644 --- a/test/pending/neg/macro-invalidusage-badbounds-b/Impls_1.scala +++ b/test/pending/neg/macro-invalidusage-badbounds-b/Impls_1.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo[U <: String](c: Ctx) = ??? + def foo[U <: String](c: Context) = ??? } diff --git a/test/files/neg/t7886.scala b/test/pending/neg/t7886.scala index 55d80a0a43..55d80a0a43 100644 --- a/test/files/neg/t7886.scala +++ b/test/pending/neg/t7886.scala diff --git a/test/pending/neg/t7886b.scala b/test/pending/neg/t7886b.scala new file mode 100644 index 0000000000..1db8be9821 --- /dev/null +++ b/test/pending/neg/t7886b.scala @@ -0,0 +1,23 @@ +trait Covariant[+A] +trait Contra[-A] { def accept(p: A): Unit } +trait Invariant[A] extends Covariant[A] with Contra[A] + +trait T +case class Unravel[A](m: Contra[A], msg: A) extends T + +object Test extends Covariant[Any] { + def g(m: Contra[Any]): Unit = m accept 5 + def f(x: T): Unit = x match { + case Unravel(m, msg) => g(m) + case _ => + } + def main(args: Array[String]) { + f(Unravel[String](new Contra[String] { def accept(x: String) = x.length }, "")) + } +} +// java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String +// at Test$$anon$1.accept(a.scala:18) +// at Test$.g(a.scala:13) +// at Test$.f(a.scala:15) +// at Test$.main(a.scala:18) +// at Test.main(a.scala) diff --git a/test/files/pos/pattern-typing.scala b/test/pending/pos/pattern-typing.scala index 7286cc38af..7286cc38af 100644 --- a/test/files/pos/pattern-typing.scala +++ b/test/pending/pos/pattern-typing.scala diff --git a/test/files/pos/t1786.scala b/test/pending/pos/t1786.scala index 32d6c06f6e..6299eb9eae 100644 --- a/test/files/pos/t1786.scala +++ b/test/pending/pos/t1786.scala @@ -1,3 +1,11 @@ +/** This a consequence of the current type checking algorithm, where bounds are checked only after variables are instantiated. + * I believe this will change once we go to contraint-based type inference. + * Alternatively, we can pursue a more extensive fix to SI-6169 + * + * The below code shows a compiler flaw in that the wildcard "_" as value for a bounded type parameter either + * breaks the boundary - as it result in Any - or doesn't evaluate to the boundary (as I'd hoped it to be). +*/ + class SomeClass(val intValue:Int) class MyClass[T <: SomeClass](val myValue:T) class Flooz[A >: Null <: SomeClass, T >: Null <: A](var value: T) diff --git a/test/files/pos/t5459.scala b/test/pending/pos/t5459.scala index 971e6f896d..971e6f896d 100644 --- a/test/files/pos/t5459.scala +++ b/test/pending/pos/t5459.scala diff --git a/test/pending/pos/t6161.scala b/test/pending/pos/t6161.scala new file mode 100644 index 0000000000..5783cc85f2 --- /dev/null +++ b/test/pending/pos/t6161.scala @@ -0,0 +1,22 @@ +object t6161 { + trait N { + type Name + } + + trait N1 extends N { + class Name { + type ThisNameType <: Name + def encode: ThisNameType = ??? + } + } + + trait S { + self: N => // change to N1 and it compiles + type NameType <: Name + } + + object g extends S with N1 + + val n1: g.NameType = ??? + val n2: g.Name = n1.encode +} diff --git a/test/pending/pos/t8128b.scala b/test/pending/pos/t8128b.scala new file mode 100644 index 0000000000..dd44a25a90 --- /dev/null +++ b/test/pending/pos/t8128b.scala @@ -0,0 +1,18 @@ +class Optiony[X] { def isEmpty = true; def get: X = ??? } +class Seqy[X] { def head: X = ???; def length = 0; def apply(i: Int): X = ??? } + +object G { + def unapply(m: Any): Optiony[_] = ??? +} + +object H { + def unapplySeq(m: Any): Optiony[Seqy[_]] = ??? +} + +object Test { + (0: Any) match { + case G(v) => v + case H(v) => v + case _ => + } +} diff --git a/test/files/presentation/context-bounds1.check b/test/pending/presentation/context-bounds1.check index b444de59a4..b444de59a4 100644 --- a/test/files/presentation/context-bounds1.check +++ b/test/pending/presentation/context-bounds1.check diff --git a/test/files/presentation/context-bounds1/Test.scala b/test/pending/presentation/context-bounds1/Test.scala index bec1131c4c..bec1131c4c 100644 --- a/test/files/presentation/context-bounds1/Test.scala +++ b/test/pending/presentation/context-bounds1/Test.scala diff --git a/test/files/presentation/context-bounds1/src/ContextBounds.scala b/test/pending/presentation/context-bounds1/src/ContextBounds.scala index 72a8f694a3..72a8f694a3 100644 --- a/test/files/presentation/context-bounds1/src/ContextBounds.scala +++ b/test/pending/presentation/context-bounds1/src/ContextBounds.scala diff --git a/test/pending/run/idempotency-partial-functions.scala b/test/pending/run/idempotency-partial-functions.scala index e673da5a29..b26c442599 100644 --- a/test/pending/run/idempotency-partial-functions.scala +++ b/test/pending/run/idempotency-partial-functions.scala @@ -22,7 +22,7 @@ object Test extends App { val tb = cm.mkToolBox() val tpartials = tb.typecheck(partials.tree) println(tpartials) - val rtpartials = tb.resetAllAttrs(tpartials) + val rtpartials = tb.untypecheck(tpartials) println(tb.eval(rtpartials)) } Test.main(null)
\ No newline at end of file diff --git a/test/pending/run/macro-expand-default/Impls_1.scala b/test/pending/run/macro-expand-default/Impls_1.scala index bb55f02ab2..fd5d8d7f18 100644 --- a/test/pending/run/macro-expand-default/Impls_1.scala +++ b/test/pending/run/macro-expand-default/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int], y: c.Expr[Int]) = { + def foo(c: Context)(x: c.Expr[Int], y: c.Expr[Int]) = { import c.universe._ val sum = Apply(Select(x.tree, TermName("$minus")), List(y.tree)) val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(sum)) diff --git a/test/pending/run/macro-expand-implicit-macro-defeats-type-inference/Impls_1.scala b/test/pending/run/macro-expand-implicit-macro-defeats-type-inference/Impls_1.scala index 15bcb581c8..e8170fda07 100644 --- a/test/pending/run/macro-expand-implicit-macro-defeats-type-inference/Impls_1.scala +++ b/test/pending/run/macro-expand-implicit-macro-defeats-type-inference/Impls_1.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.Context +import scala.reflect.macros.whitebox.Context object Impls { def foo[T: c.WeakTypeTag](c: Context): c.Expr[List[T]] = c.universe.reify { diff --git a/test/pending/run/macro-expand-macro-has-context-bound/Impls_1.scala b/test/pending/run/macro-expand-macro-has-context-bound/Impls_1.scala index eed68280cd..34182b7968 100644 --- a/test/pending/run/macro-expand-macro-has-context-bound/Impls_1.scala +++ b/test/pending/run/macro-expand-macro-has-context-bound/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo[U](c: Ctx)(x: c.Expr[U])(evidence: c.Expr[Numeric[U]]) = { + def foo[U](c: Context)(x: c.Expr[U])(evidence: c.Expr[Numeric[U]]) = { import c.universe._ val plusOne = Apply(Select(evidence.tree, TermName("plus")), List(x.tree, Literal(Constant(1)))) val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(plusOne)) diff --git a/test/pending/run/macro-expand-named/Impls_1.scala b/test/pending/run/macro-expand-named/Impls_1.scala index bb55f02ab2..fd5d8d7f18 100644 --- a/test/pending/run/macro-expand-named/Impls_1.scala +++ b/test/pending/run/macro-expand-named/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx)(x: c.Expr[Int], y: c.Expr[Int]) = { + def foo(c: Context)(x: c.Expr[Int], y: c.Expr[Int]) = { import c.universe._ val sum = Apply(Select(x.tree, TermName("$minus")), List(y.tree)) val body = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(sum)) diff --git a/test/pending/run/macro-expand-tparams-prefix-e1/Impls_1.scala b/test/pending/run/macro-expand-tparams-prefix-e1/Impls_1.scala index 487ac79673..683622b29d 100644 --- a/test/pending/run/macro-expand-tparams-prefix-e1/Impls_1.scala +++ b/test/pending/run/macro-expand-tparams-prefix-e1/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo[T, U: c.WeakTypeTag, V](c: Ctx)(implicit T: c.WeakTypeTag[T], V: c.WeakTypeTag[V]): c.Expr[Unit] = { + def foo[T, U: c.WeakTypeTag, V](c: Context)(implicit T: c.WeakTypeTag[T], V: c.WeakTypeTag[V]): c.Expr[Unit] = { import c.universe._ Block(List( Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant(T.toString)))), diff --git a/test/pending/run/macro-expand-tparams-prefix-f1/Impls_1.scala b/test/pending/run/macro-expand-tparams-prefix-f1/Impls_1.scala index 487ac79673..683622b29d 100644 --- a/test/pending/run/macro-expand-tparams-prefix-f1/Impls_1.scala +++ b/test/pending/run/macro-expand-tparams-prefix-f1/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo[T, U: c.WeakTypeTag, V](c: Ctx)(implicit T: c.WeakTypeTag[T], V: c.WeakTypeTag[V]): c.Expr[Unit] = { + def foo[T, U: c.WeakTypeTag, V](c: Context)(implicit T: c.WeakTypeTag[T], V: c.WeakTypeTag[V]): c.Expr[Unit] = { import c.universe._ Block(List( Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant(T.toString)))), diff --git a/test/pending/run/macro-quasiinvalidbody-a/Impls_1.scala b/test/pending/run/macro-quasiinvalidbody-a/Impls_1.scala index daedde4021..741a921b72 100644 --- a/test/pending/run/macro-quasiinvalidbody-a/Impls_1.scala +++ b/test/pending/run/macro-quasiinvalidbody-a/Impls_1.scala @@ -1,5 +1,5 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context trait Impls { - def impl(c: Ctx)(x: c.Expr[Any]) = x + def impl(c: Context)(x: c.Expr[Any]) = x }
\ No newline at end of file diff --git a/test/pending/run/macro-quasiinvalidbody-a/Macros_Test_2.scala b/test/pending/run/macro-quasiinvalidbody-a/Macros_Test_2.scala index 27140a77ad..2735321eae 100644 --- a/test/pending/run/macro-quasiinvalidbody-a/Macros_Test_2.scala +++ b/test/pending/run/macro-quasiinvalidbody-a/Macros_Test_2.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Macros extends Impls { def foo(x: Any) = macro impl diff --git a/test/pending/run/macro-quasiinvalidbody-b/Impls_1.scala b/test/pending/run/macro-quasiinvalidbody-b/Impls_1.scala index 246fc9f904..b023d31f05 100644 --- a/test/pending/run/macro-quasiinvalidbody-b/Impls_1.scala +++ b/test/pending/run/macro-quasiinvalidbody-b/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context trait ImplContainer { object Impls { - def foo(c: Ctx)(x: c.Expr[Any]) = x + def foo(c: Context)(x: c.Expr[Any]) = x } }
\ No newline at end of file diff --git a/test/pending/run/macro-quasiinvalidbody-b/Macros_Test_2.scala b/test/pending/run/macro-quasiinvalidbody-b/Macros_Test_2.scala index da9445ac52..639d93fb5f 100644 --- a/test/pending/run/macro-quasiinvalidbody-b/Macros_Test_2.scala +++ b/test/pending/run/macro-quasiinvalidbody-b/Macros_Test_2.scala @@ -1,4 +1,4 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Macros extends ImplContainer { def foo(x: Any) = macro Impls.foo diff --git a/test/pending/run/macro-reify-array/Macros_1.scala b/test/pending/run/macro-reify-array/Macros_1.scala index f970be5caa..eea0133feb 100644 --- a/test/pending/run/macro-reify-array/Macros_1.scala +++ b/test/pending/run/macro-reify-array/Macros_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Macros { def foo[T](s: String) = macro Impls.foo[T] object Impls { - def foo[T: c.WeakTypeTag](c: Ctx)(s: c.Expr[T]) = c.universe.reify { + def foo[T: c.WeakTypeTag](c: Context)(s: c.Expr[T]) = c.universe.reify { Array(s.splice) } } diff --git a/test/pending/run/macro-reify-tagful-b/Macros_1.scala b/test/pending/run/macro-reify-tagful-b/Macros_1.scala index 59dbe7157b..f4d8062a14 100644 --- a/test/pending/run/macro-reify-tagful-b/Macros_1.scala +++ b/test/pending/run/macro-reify-tagful-b/Macros_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Macros { def foo[T](s: T) = macro Impls.foo[List[T]] object Impls { - def foo[T: c.WeakTypeTag](c: Ctx)(s: c.Expr[T]) = c.universe.reify { + def foo[T: c.WeakTypeTag](c: Context)(s: c.Expr[T]) = c.universe.reify { List(s.splice) } } diff --git a/test/pending/run/macro-reify-tagless-b/Impls_Macros_1.scala b/test/pending/run/macro-reify-tagless-b/Impls_Macros_1.scala index a581c47026..1307052394 100644 --- a/test/pending/run/macro-reify-tagless-b/Impls_Macros_1.scala +++ b/test/pending/run/macro-reify-tagless-b/Impls_Macros_1.scala @@ -1,10 +1,10 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Macros { def foo[T](s: T) = macro Impls.foo[List[T]] object Impls { - def foo[T](c: Ctx)(s: c.Expr[T]) = c.universe.reify { + def foo[T](c: Context)(s: c.Expr[T]) = c.universe.reify { List(s.splice) } } diff --git a/test/pending/run/macro-term-declared-in-anonymous-explicit-import/Impls_1.scala b/test/pending/run/macro-term-declared-in-anonymous-explicit-import/Impls_1.scala index 348f3420f2..c43f5f3f53 100644 --- a/test/pending/run/macro-term-declared-in-anonymous-explicit-import/Impls_1.scala +++ b/test/pending/run/macro-term-declared-in-anonymous-explicit-import/Impls_1.scala @@ -1,7 +1,7 @@ -import scala.reflect.macros.{Context => Ctx} +import scala.reflect.macros.blackbox.Context object Impls { - def foo(c: Ctx) = { + def foo(c: Context) = { import c.{prefix => prefix} import c.universe._ val printPrefix = Apply(Select(Ident(definitions.PredefModule), TermName("println")), List(Literal(Constant("prefix = " + prefix)))) diff --git a/test/scaladoc/resources/SI-4014_0.scala b/test/scaladoc/resources/SI-4014_0.scala new file mode 100644 index 0000000000..c398fcc1e0 --- /dev/null +++ b/test/scaladoc/resources/SI-4014_0.scala @@ -0,0 +1,4 @@ +/** A template without authors. + * + */ +trait Foo
\ No newline at end of file diff --git a/test/scaladoc/resources/SI-4014_1.scala b/test/scaladoc/resources/SI-4014_1.scala new file mode 100644 index 0000000000..34386b515e --- /dev/null +++ b/test/scaladoc/resources/SI-4014_1.scala @@ -0,0 +1,5 @@ +/** A template with one author. + * + * @author The Only Author + */ +trait Foo
\ No newline at end of file diff --git a/test/scaladoc/resources/SI-4014_2.scala b/test/scaladoc/resources/SI-4014_2.scala new file mode 100644 index 0000000000..514f7a1e4c --- /dev/null +++ b/test/scaladoc/resources/SI-4014_2.scala @@ -0,0 +1,6 @@ +/** A template with more than one author. + * + * @author The First Author + * @author The Second Author + */ +trait Foo
\ No newline at end of file diff --git a/test/scaladoc/run/SI-6812.scala b/test/scaladoc/run/SI-6812.scala index 6893e816d0..90005b8db4 100644 --- a/test/scaladoc/run/SI-6812.scala +++ b/test/scaladoc/run/SI-6812.scala @@ -5,11 +5,11 @@ import language._ object Test extends ScaladocModelTest { override def code = """ - import scala.reflect.macros.BlackboxContext + import scala.reflect.macros.blackbox.Context import language.experimental.macros object Macros { - def impl(c: BlackboxContext) = c.literalUnit + def impl(c: Context) = c.literalUnit def foo: Unit = macro impl } diff --git a/test/scaladoc/run/SI-6812b.scala b/test/scaladoc/run/SI-6812b.scala index b8a8140357..74dbd130a3 100644 --- a/test/scaladoc/run/SI-6812b.scala +++ b/test/scaladoc/run/SI-6812b.scala @@ -5,11 +5,11 @@ import language._ object Test extends ScaladocModelTest { override def code = """ - import scala.reflect.macros.BlackboxContext + import scala.reflect.macros.blackbox.Context import language.experimental.macros object Macros { - def impl(c: BlackboxContext) = c.literalUnit + def impl(c: Context) = c.literalUnit def foo: Unit = macro impl } diff --git a/test/scaladoc/run/t7124.check b/test/scaladoc/run/t7124.check new file mode 100644 index 0000000000..96b627a322 --- /dev/null +++ b/test/scaladoc/run/t7124.check @@ -0,0 +1,3 @@ +List() +List(Paragraph(Text(macro))) +Done. diff --git a/test/scaladoc/run/t7124.scala b/test/scaladoc/run/t7124.scala new file mode 100644 index 0000000000..e8272000d2 --- /dev/null +++ b/test/scaladoc/run/t7124.scala @@ -0,0 +1,22 @@ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + + override def code = """ + import scala.language.experimental.macros + class Test { + def print(): Unit = macro ??? + } + """ + + def scaladocSettings = "" + + def testModel(root: Package) = { + import access._ + val p = root._class("Test")._method("print") + + println(p.annotations) // no annotations + println(p.flags) // a 'macro' flag + } +} diff --git a/test/scaladoc/scalacheck/HtmlFactoryTest.scala b/test/scaladoc/scalacheck/HtmlFactoryTest.scala index 03348b81d2..56328ea875 100644 --- a/test/scaladoc/scalacheck/HtmlFactoryTest.scala +++ b/test/scaladoc/scalacheck/HtmlFactoryTest.scala @@ -47,6 +47,7 @@ object Test extends Properties("HtmlFactory") { settings.scaladocQuietRun = true settings.nowarn.value = true settings.classpath.value = getClasspath + settings.docAuthor.value = true val reporter = new scala.tools.nsc.reporters.ConsoleReporter(settings) new DocFactory(reporter, settings) @@ -563,12 +564,13 @@ object Test extends Properties("HtmlFactory") { property("Comment inheritance: Correct explicit inheritance for override") = checkText("explicit-inheritance-override.scala")( (Some("InheritDocDerived"), - """def function[T](arg1: T, arg2: String): Double + """def function[T](arg1: T, arg2: String): Double Starting line Starting line The base comment. And another sentence... The base comment. And another sentence... Ending line + Author: StartAuthor a Scala developer EndAuthor T StartT the type of the first argument EndT arg1 Start1 The T term comment End1 arg2 Start2 The string comment End2 @@ -589,12 +591,13 @@ object Test extends Properties("HtmlFactory") { property("Comment inheritance: Correct explicit inheritance for usecase") = checkText("explicit-inheritance-usecase.scala")( (Some("UseCaseInheritDoc"), - """def function[T](arg1: T, arg2: String): Double + """def function[T](arg1: T, arg2: String): Double [use case] Starting line [use case] Starting line The base comment. And another sentence... The base comment. And another sentence... Ending line + Author: StartAuthor a Scala developer EndAuthor T StartT the type of the first argument EndT arg1 Start1 The T term comment End1 arg2 Start2 The string comment End2 @@ -663,6 +666,45 @@ object Test extends Properties("HtmlFactory") { } } + property("SI-4014: Scaladoc omits @author: no authors") = { + val noAuthors = createTemplates("SI-4014_0.scala")("Foo.html") + + noAuthors match { + case node: scala.xml.Node => { + val s = node.toString + ! s.contains("Author") + } + case _ => false + } + } + + property("SI-4014: Scaladoc omits @author: one author") = { + val oneAuthor = createTemplates("SI-4014_1.scala")("Foo.html") + + oneAuthor match { + case node: scala.xml.Node => { + val s = node.toString + s.contains("<h6>Author:</h6>") + s.contains("<p>The Only Author\n</p>") + } + case _ => false + } + } + + property("SI-4014: Scaladoc omits @author: two authors") = { + val twoAuthors = createTemplates("SI-4014_2.scala")("Foo.html") + + twoAuthors match { + case node: scala.xml.Node => { + val s = node.toString + s.contains("<h6>Authors:</h6>") + s.contains("<p>The First Author\n</p>") + s.contains("<p>The Second Author\n</p>") + } + case _ => false + } + } + { val files = createTemplates("basic.scala") //println(files) diff --git a/versions.properties b/versions.properties index 90448dc49a..2ea8e713f1 100644 --- a/versions.properties +++ b/versions.properties @@ -1,20 +1,25 @@ -starr.version=2.11.0-M7 +#Sun, 19 Jan 2014 23:57:57 +0100 +starr.version=2.11.0-M8 starr.use.released=1 # These are the versions of the modules that go with this release. # These properties are used during PR validation and in dbuild builds. -scala.binary.version=2.11.0-M7 +scala.binary.version=2.11.0-M8 # external modules shipped with distribution: scala-xml.version.number=1.0.0-RC7 scala-parser-combinators.version.number=1.0.0-RC5 -scala-continuations-plugin.version.number=1.0.0-RC2 -scala-continuations-library.version.number=1.0.0-RC2 +scala-continuations-plugin.version.number=1.0.0-RC3 +scala-continuations-library.version.number=1.0.0-RC3 scala-swing.version.number=1.0.0-RC2 +# these ship with distribution (and scala-library-all depends on them) +akka-actor.version.number=2.2.3 +actors-migration.version.number=1.0.0 + # external modules, used internally (not shipped) partest.version.number=1.0.0-RC8 -scalacheck.version.number=1.11.1 +scalacheck.version.number=1.11.3 # TODO: modularize the compiler #scala-compiler-doc.version.number=1.0.0-RC1 |