diff options
222 files changed, 3621 insertions, 599 deletions
diff --git a/build.number b/build.number index dc85ecb777..5f8ed6d6b6 100644 --- a/build.number +++ b/build.number @@ -1,9 +1,9 @@ #Tue Sep 11 19:21:09 CEST 2007 version.major=2 version.minor=11 -version.patch=5 +version.patch=6 # This is the -N part of a version. if it's 0, it's dropped from maven versions. version.bnum=0 -# Note: To build a release run ant with -Dbuild.release=true -# To build an RC, run ant with -Dmaven.version.suffix=-RCN +# To build a release, see scripts/jobs/scala-release-2.11.x-build +# (normally run by the eponymous job on scala-ci.typesafe.com).
\ No newline at end of file @@ -280,7 +280,7 @@ TODO: <!-- Pax runner --> <property name="pax.exam.version" value="3.5.0"/><!-- Last version which supports Java 6 --> - <property name="osgi.felix.version" value="4.0.3"/> + <property name="osgi.felix.version" value="4.4.0"/> <property name="osgi.equinox.version" value="3.7.1"/> <artifact:dependencies pathId="pax.exam.classpath" filesetId="pax.exam.fileset"> <dependency groupId="org.ops4j.pax.exam" artifactId="pax-exam-container-native" version="${pax.exam.version}"> @@ -294,6 +294,7 @@ TODO: <dependency groupId="ch.qos.logback" artifactId="logback-classic" version="1.1.2"/> <dependency groupId="junit" artifactId="junit" version="${junit.version}"/> </artifact:dependencies> + <copy-deps project="pax.exam"/> <artifact:dependencies pathId="osgi.framework.felix"> <dependency groupId="org.apache.felix" artifactId="org.apache.felix.framework" version="${osgi.felix.version}"/> @@ -1375,8 +1376,8 @@ TODO: </target> <target name="test.osgi" depends="test.osgi.comp"> - <if><isset property="has.java8"/><then> - <echo message="Skipping OSGi JUnit tests on Java 8. See SI-8642"/> + <if><isset property="test.osgi.skip"/><then> + <echo message="Skipping OSGi JUnit tests"/> </then><else> <echo message="Running OSGi JUnit tests. Output in ${build-osgi.dir}"/> <stopwatch name="test.osgi.timer"/> diff --git a/scripts/common b/scripts/common new file mode 100644 index 0000000000..b075469379 --- /dev/null +++ b/scripts/common @@ -0,0 +1,153 @@ +# This is for forcibly stopping the job from a subshell (see test +# below). +trap "exit 1" TERM +export TOP_PID=$$ +set -e + +# Known problems : does not fare well with interrupted, partial +# compilations. We should perhaps have a multi-dependency version +# of do_i_have below + +LOGGINGDIR="$WORKSPACE/logs" +mkdir -p $LOGGINGDIR + +unset SBT_HOME +SBT_HOME="$WORKSPACE/.sbt" +mkdir -p $SBT_HOME +IVY_CACHE="$WORKSPACE/.ivy2" +mkdir -p $IVY_CACHE +rm -rf $IVY_CACHE/cache/org.scala-lang + +# temp dir where all 'non-build' operation are performed +TMP_ROOT_DIR=$(mktemp -d -t pr-scala.XXXX) +TMP_DIR="${TMP_ROOT_DIR}/tmp" +mkdir "${TMP_DIR}" + + +# detect sed version and how to enable extended regexes +SEDARGS="-n$(if (echo "a" | sed -nE "s/a/b/" &> /dev/null); then echo E; else echo r; fi)" + + + +# :docstring test: +# Usage: test <argument ..> +# Executes <argument ..>, logging the launch of the command to the +# main log file, and kills global script execution with the TERM +# signal if the commands ends up failing. +# DO NOT USE ON FUNCTIONS THAT DECLARE VARIABLES, +# AS YOU'LL BE RUNNING IN A SUBSHELL AND VARIABLE DECLARATIONS WILL BE LOST +# :end docstring: + +function test() { + echo "### $@" + "$@" + status=$? + if [ $status -ne 0 ]; then + say "### ERROR with $1" + kill -s TERM $TOP_PID + fi +} + +# :docstring say: +# Usage: say <argument ..> +# Prints <argument ..> to both console and the main log file. +# :end docstring: + +function say(){ + (echo "$@") | tee -a $LOGGINGDIR/compilation-$SCALADATE-$SCALAHASH.log +} + +# General debug logging +# $* - message +function debug () { + echo "----- $*" +} + +function parseScalaProperties(){ + propFile="$baseDir/$1" + if [ ! -f $propFile ]; then + echo "Property file $propFile not found." + exit 1 + else + awk -f "$scriptsDir/readproperties.awk" "$propFile" > "$propFile.sh" + . "$propFile.sh" # yeah yeah, not that secure, improvements welcome (I tried, but bash made me cry again) + fi +} + + +## TAKEN FROM UBER-BUILD, except that it "returns" (via $RES) true/false +# Check if an artifact is available +# $1 - groupId +# $2 - artifacId +# $3 - version +# $4 - extra repository to look in (optional) +# return value in $RES +function checkAvailability () { + pushd "${TMP_DIR}" + rm -rf * + +# pom file for the test project + cat > pom.xml << EOF +<project xmlns="http://maven.apache.org/POM/4.0.0" 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>com.typesafe</groupId> + <artifactId>typesafeDummy</artifactId> + <packaging>war</packaging> + <version>1.0-SNAPSHOT</version> + <name>Dummy</name> + <url>http://127.0.0.1</url> + <dependencies> + <dependency> + <groupId>$1</groupId> + <artifactId>$2</artifactId> + <version>$3</version> + </dependency> + </dependencies> + <repositories> + <repository> + <id>sonatype.snapshot</id> + <name>Sonatype maven snapshot repository</name> + <url>https://oss.sonatype.org/content/repositories/snapshots</url> + <snapshots> + <updatePolicy>daily</updatePolicy> + </snapshots> + </repository> +EOF + + if [ -n "$4" ] + then +# adds the extra repository + cat >> pom.xml << EOF + <repository> + <id>extrarepo</id> + <name>extra repository</name> + <url>$4</url> + </repository> +EOF + fi + + cat >> pom.xml << EOF + </repositories> +</project> +EOF + + set +e + mvn "${MAVEN_ARGS[@]}" compile &> "${TMP_DIR}/mvn.log" + RES=$? + # Quiet the maven, but allow diagnosing problems. + grep -i downloading "${TMP_DIR}/mvn.log" + grep -i exception "${TMP_DIR}/mvn.log" + grep -i error "${TMP_DIR}/mvn.log" + set -e + +# log the result + if [ ${RES} == 0 ] + then + debug "$1:$2:jar:$3 found !" + RES=true + else + debug "$1:$2:jar:$3 not found !" + RES=false + fi + popd +} diff --git a/scripts/jobs/integrate/bootstrap b/scripts/jobs/integrate/bootstrap new file mode 100755 index 0000000000..46d610018c --- /dev/null +++ b/scripts/jobs/integrate/bootstrap @@ -0,0 +1,563 @@ +#!/bin/bash -e +# TODO: different scripts for the different phases -- usually we don't need to bootstrap the modules, +# since we can use the previous version of scala for STARR as well as for compiling the modules (assuming it's binary compatible) +# We should move away from the complicated bootstrap and set up our release schedule so we always have a previous build that satisfies these criteria. +# (Potentially trivially, by splitting up this script, and publishing locker as if it were a real release.) + +# requirements: +# sbtCmd must point to sbt from sbt-extras (this is the standard on the Scala jenkins, so we only support that one) +# - ~/.sonatype-curl that consists of user = USER:PASS +# - ~/.m2/settings.xml with credentials for sonatype + # <server> + # <id>private-repo</id> + # <username>jenkinside</username> + # <password></password> + # </server> +# - ~/.credentials (for sonatype) + # realm=Sonatype Nexus Repository Manager + # host=oss.sonatype.org + # user=lamp + # password= +# - ~/.credentials-private-repo for private-repo.typesafe.com, as follows: + # realm=Artifactory Realm + # host=private-repo.typesafe.com + # user=jenkinside + # password= +# - ~/.sbt/0.13/plugins/gpg.sbt with: +# addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.1") + +# Modus operandi: +# +# Determine Scala version as: +# +# $SCALA_VER_BASE$SCALA_VER_SUFFIX (if former variable is set) +# By parsing the tag (if HEAD is tagged as v$base$suffix) +# By parsing build.number for the base version, suffixing with -$sha-nightly +# Serialize these versions to jenkins.properties, which are passed downstream to scala-release-2.11.x-dist. +# This also removes the need to tag scala/scala-dist (not possible for nightlies, still encouraged for releases, but not a hard requirement). +# +# Determine Module Versions +# +# When running in "versions.properties" mode (the default), derive tags from these versions and build, publishing only those modules that are not available yet. +# Otherwise, build HEAD for all modules, derive a -nightly version for them. +# Bootstrap: +# +# Build minimal core of Scala as this version (aka locker), publish to private-repo +# Build modules required to bootstrap, publish to private-repo +# Build Scala using the previously built core and bootstrap modules, publish to private-repo This overwrites the minimal core on private-repo +# Stage to sonatype (unless building a -nightly release): +# +# Stage this Scala build on sonatype +# Rebuild modules with this Scala build, and stage them on sonatype as well +# This script can be run in multiple modes. It is design to work without any input, +# so that it could be run in Travis CI. In that mode, it'll build a release when +# the current HEAD of the checkout in $WORKSPACE is tagged, and stage to sonatype. Otherwise, +# it'll build a nightly. +# +# Since the nightlies are intended to be a drop in replacement, all modules are built with the +# full Scala version as their binary version, so that you can just set scalaVersion to the +# nightly's sha-derived version and be good to go. +# +# The other way to trigger a release is by setting the SCALA_VER_BASE env var. +# +# By default, we build the versions of the modules as specified by versions.properties +# (as specified in the HEAD commit). Set moduleVersioning to something random +# to trigger building HEAD of each module, generating a fresh -$(git describe)-nightly version for each. +# +# PS: set publishToSonatype to anything but "yes" to avoid publishing to sonatype +# (publishing only done when $WORKSPACE checkout's HEAD is tagged / SCALA_VER_BASE is set.) + + +# set to something besides the default to build nightly snapshots of the modules instead of some tagged version +moduleVersioning=${moduleVersioning-"versions.properties"} + +publishPrivateTask=${publishPrivateTask-"publish"} +publishSonatypeTaskCore=${publishSonatypeTaskCore-"publish-signed"} +publishSonatypeTaskModules=${publishSonatypeTaskModules-"publish-signed"} +publishLockerPrivateTask=${publishLockerPrivateTask-$publishPrivateTask} # set to "init" to speed up testing of the script (if you already built locker before) + +sbtCmd=${sbtCmd-sbt} # TESTING (this is a marker for defaults to change when testing locally: should be sbtx on my mac) + +# 0.13.5 does not respect "set every scalaVersion", see +# https://github.com/scala/scala-parser-combinators/pull/27 +sbtCmd="$sbtCmd -sbt-version 0.13.2" + +forceRebuild=${forceRebuild-no} + +# publishToSonatype +# set to anything but "yes" to avoid publishing to sonatype +# overridden to "no" when no SCALA_VER_BASE is passed and HEAD is not tagged with a valid version tag +# + +antBuildTask="${antBuildTask-nightly}" # TESTING leave empty to avoid the sanity check (don't set it to "init" because ant will croak) +clean="clean" # TESTING leave empty to speed up testing + + + +baseDir=${WORKSPACE-`pwd`} +scriptsDir="$baseDir/scripts" +. $scriptsDir/common + +# we must change ivy home to get a fresh ivy cache, otherwise we get half-bootstrapped scala +# rm it in case it existed (and there's no ivy2-shadow, which indicates we're running in a TESTING environment)... +# we don't nuke the whole ws since that clobbers the git clones needlessly +[[ -d $baseDir/ivy2-shadow ]] || rm -rf $baseDir/ivy2 +mkdir -p $baseDir/ivy2 + +rm -rf $baseDir/resolutionScratch_ +mkdir -p $baseDir/resolutionScratch_ + +# repo used to publish "locker" scala to (to start the bootstrap) +privateCred="private-repo" +privateRepo="http://private-repo.typesafe.com/typesafe/scala-release-temp/" + +##### git +gfxd() { + git clean -fxd # TESTING +} + +update() { + [[ -d $baseDir ]] || mkdir -p $baseDir + cd $baseDir + + if [ ! -d $baseDir/$2 ]; then git clone "https://github.com/$1/$2.git"; fi + + cd $2 + + git fetch --tags "https://github.com/$1/$2.git" + (git fetch "https://github.com/$1/$2.git" $3 && git checkout -q FETCH_HEAD) #|| git checkout -q $3 # || fallback is for local testing on tag + git reset --hard +} + +##### sonatype interface + +stApi="https://oss.sonatype.org/service/local" + +function st_curl(){ + curl -H "Content-Type: application/json" -H "accept: application/json,application/vnd.siesta-error-v1+json,application/vnd.siesta-validation-errors-v1+json" -K ~/.sonatype-curl -s -o - $@ +} + +function st_stagingReposOpen() { + st_curl "$stApi/staging/profile_repositories" | jq '.data[] | select(.profileName == "org.scala-lang") | select(.type == "open")' +} + +function st_stagingRepoDrop() { + repo=$1 + message=$2 + echo "{\"data\":{\"description\":\"$message\",\"stagedRepositoryIds\":[\"$repo\"]}}" | st_curl -X POST -d @- "$stApi/staging/bulk/drop" +} + +function st_stagingRepoClose() { + repo=$1 + message=$2 + echo "{\"data\":{\"description\":\"$message\",\"stagedRepositoryIds\":[\"$repo\"]}}" | st_curl -X POST -d @- "$stApi/staging/bulk/close" +} + + +# ARGH trying to get this to work on multiple versions of sbt-extras... +# the old version (on jenkins, and I don't want to upgrade for risk of breaking other builds) honors -sbt-dir +# the new version of sbt-extras ignores sbt-dir, so we pass it in as -Dsbt.global.base +# need to set sbt-dir to one that has the gpg.sbt plugin config +sbtArgs="-no-colors -ivy $baseDir/ivy2 -Dsbt.override.build.repos=true -Dsbt.repository.config=$scriptsDir/repositories-scala-release -Dsbt.global.base=$HOME/.sbt/0.13 -sbt-dir $HOME/.sbt/0.13" + +sbtBuild() { + echo "### sbtBuild: "$sbtCmd $sbtArgs "${scalaVersionTasks[@]}" "${publishTasks[@]}" "$@" + $sbtCmd $sbtArgs "${scalaVersionTasks[@]}" "${publishTasks[@]}" "$@" >> $baseDir/logs/builds 2>&1 +} + +sbtResolve() { + cd $baseDir/resolutionScratch_ + touch build.sbt + cross=${4-binary} # Disabled / binary / full + echo "### sbtResolve: $sbtCmd $sbtArgs " "${scalaVersionTasks[@]}" "\"$1\" % \"$2\" % \"$3\" cross CrossVersion.$cross" + $sbtCmd $sbtArgs "${scalaVersionTasks[@]}" \ + "set libraryDependencies := Seq(\"$1\" % \"$2\" % \"$3\" cross CrossVersion.$cross)" \ + 'show update' >> $baseDir/logs/resolution 2>&1 +} + +# Oh boy... can't use scaladoc to document scala-xml/scala-parser-combinators +# if scaladoc depends on the same version of scala-xml/scala-parser-combinators. +# Even if that version is available through the project's resolvers, sbt won't look past this project. +# SOOOOO, we set the version to a dummy (-DOC), generate documentation, +# then set the version to the right one and publish (which won't re-gen the docs). +# Also tried publish-local without docs using 'set publishArtifact in (Compile, packageDoc) := false' and republishing, no dice. + +# Each buildModule() function is invoked twice: first to build against locker and publish to private-repo, then +# to build against the release and publish to sonatype (or publish-local if publishToSonatype is not "yes"). +# In the second round, sbtResolve is always true: the module will be found in the private-repo! +# Therefore, if MODULE_BUILT is "yes" (in the second round), we know that we need to build (and publish) the +# module again. +# +# Note: we tried an alternative solution in which sbtResolve would not look at private-repo, but that fails. For example, +# scala-xml depends on scala-library, so sbt tries to find the scala-library of the version that we are currently building, +# which exists only in private-repo. + +buildXML() { + if [ "$XML_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-xml" $XML_VER ) + then echo "Found scala-xml $XML_VER; not building." + else + update scala scala-xml "$XML_REF" && gfxd + sbtBuild 'set version := "'$XML_VER'-DOC"' $clean doc 'set version := "'$XML_VER'"' test "${buildTasks[@]}" + XML_BUILT="yes" # ensure the module is built and published when buildXML is invoked for the second time, see comment above + fi +} + +buildParsers() { + if [ "$PARSERS_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-parser-combinators" $PARSERS_VER ) + then echo "Found scala-parser-combinators $PARSERS_VER; not building." + else + update scala scala-parser-combinators "$PARSERS_REF" && gfxd + sbtBuild 'set version := "'$PARSERS_VER'-DOC"' $clean doc 'set version := "'$PARSERS_VER'"' test "${buildTasks[@]}" + PARSERS_BUILT="yes" + fi +} + +buildPartest() { + if [ "$PARTEST_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-partest" $PARTEST_VER ) + then echo "Found scala-partest $PARTEST_VER; not building." + else + update scala scala-partest "$PARTEST_REF" && gfxd + sbtBuild 'set version :="'$PARTEST_VER'"' 'set VersionKeys.scalaXmlVersion := "'$XML_VER'"' 'set VersionKeys.scalaCheckVersion := "'$SCALACHECK_VER'"' $clean test "${buildTasks[@]}" + PARTEST_BUILT="yes" + fi +} + +# buildPartestIface() { +# if [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-partest-interface" $PARTEST_IFACE_VER ) +# then echo "Found scala-partest-interface $PARTEST_IFACE_VER; not building." +# else +# update scala scala-partest-interface "$PARTEST_IFACE_REF" && gfxd +# sbtBuild 'set version :="'$PARTEST_IFACE_VER'"' $clean "${buildTasks[@]}" +# fi +# } + +buildContinuations() { + if [ "$CONT_PLUG_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.plugins" "scala-continuations-plugin" $CONTINUATIONS_VER full ) + then echo "Found scala-continuations-plugin $CONTINUATIONS_VER; not building." + else + update scala scala-continuations $CONTINUATIONS_REF && gfxd + + $sbtCmd $sbtArgs 'project plugin' "${scalaVersionTasks[@]}" "${publishTasks[@]}" \ + 'set version := "'$CONTINUATIONS_VER'"' $clean "compile:package" test "${buildTasks[@]}" # https://github.com/scala/scala-continuations/pull/4 + CONT_PLUG_BUILT="yes" + fi + + if [ "$CONT_LIB_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.plugins" "scala-continuations-library" $CONTINUATIONS_VER ) + then echo "Found scala-continuations-library $CONTINUATIONS_VER; not building." + else + update scala scala-continuations $CONTINUATIONS_REF && gfxd + $sbtCmd $sbtArgs 'project library' "${scalaVersionTasks[@]}" "${publishTasks[@]}" \ + 'set version := "'$CONTINUATIONS_VER'"' $clean test "${buildTasks[@]}" + CONT_LIB_BUILT="yes" + fi +} + +buildSwing() { + if [ "$SWING_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-swing" $SWING_VER ) + then echo "Found scala-swing $SWING_VER; not building." + else + update scala scala-swing "$SWING_REF" && gfxd + sbtBuild 'set version := "'$SWING_VER'"' $clean test "${buildTasks[@]}" + SWING_BUILT="yes" + fi +} + +buildActorsMigration(){ + if [ "$ACTORS_MIGRATION_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang" "scala-actors-migration" $ACTORS_MIGRATION_VER ) + then echo "Found scala-actors-migration $ACTORS_MIGRATION_VER; not building." + else + update scala actors-migration "$ACTORS_MIGRATION_REF" && gfxd + # not running tests because + # [error] Test scala.actors.migration.NestedReact.testNestedReactAkka failed: java.util.concurrent.TimeoutException: Futures timed out after [20 seconds] + sbtBuild 'set version := "'$ACTORS_MIGRATION_VER'"' 'set VersionKeys.continuationsVersion := "'$CONTINUATIONS_VER'"' $clean "${buildTasks[@]}" + ACTORS_MIGRATION_BUILT="yes" + fi +} + +buildScalacheck(){ + if [ "$SCALACHECK_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scalacheck" "scalacheck" $SCALACHECK_VER ) + then echo "Found scalacheck $SCALACHECK_VER; not building." + else + update rickynils scalacheck $SCALACHECK_REF && gfxd + sbtBuild 'set version := "'$SCALACHECK_VER'"' 'set VersionKeys.scalaParserCombinatorsVersion := "'$PARSERS_VER'"' $clean $publishPrivateTask # test times out NOTE: never published to sonatype + SCALACHECK_BUILT="yes" + fi +} + +# build modules, using ${buildTasks[@]} (except for Scalacheck, which is hard-coded to publish to private-repo) +buildModules() { + buildXML + buildParsers + buildContinuations + buildSwing + buildActorsMigration + buildScalacheck + buildPartest + # buildPartestIface +} + + +## BUILD STEPS: + +determineScalaVersion() { + cd $WORKSPACE + parseScalaProperties "versions.properties" + + if [ -z "$SCALA_VER_BASE" ]; then + echo "No SCALA_VER_BASE specified." + + scalaTag=$(git describe --exact-match ||:) + + SCALA_BINARY_VER=${SCALA_BINARY_VER-"$scala_binary_version"} + + if [ -z "$scalaTag" ] + then + echo "No tag found, building nightly snapshot." + parseScalaProperties "build.number" + SCALA_VER_BASE="$version_major.$version_minor.$version_patch" + SCALA_VER_SUFFIX="-$(git rev-parse --short HEAD)-nightly" + SCALADOC_SOURCE_LINKS_VER=$(git rev-parse HEAD) + + # TODO: publish nightly snapshot using this script + publishToSonatype="no" + echo "repo_ref=2.11.x" >> $baseDir/jenkins.properties # for the -dist downstream jobs that build the actual archives + else + echo "HEAD is tagged as $scalaTag." + # borrowed from https://github.com/cloudflare/semver_bash/blob/master/semver.sh + local RE='v*\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\([0-9A-Za-z-]*\)' # don't change this to make it more accurate, it's not worth it + SCALA_VER_BASE="$(echo $scalaTag | sed -e "s#$RE#\1.\2.\3#")" + SCALA_VER_SUFFIX="$(echo $scalaTag | sed -e "s#$RE#\4#")" + SCALADOC_SOURCE_LINKS_VER=$scalaTag + + if [ "$SCALA_VER_BASE" == "$scalaTag" ]; then + echo "Could not parse version $scalaTag" + exit 1 + fi + publishToSonatype=${publishToSonatype-"yes"} # unless forced previously, publish + fi + else + publishToSonatype=${publishToSonatype-"yes"} # unless forced previously, publish + # if version base/suffix are provided, we assume a corresponding tag exists for the scaladoc source links + SCALADOC_SOURCE_LINKS_VER="v$SCALA_VER_BASE$SCALA_VER_SUFFIX" + fi + + SCALA_VER="$SCALA_VER_BASE$SCALA_VER_SUFFIX" + echo "version=$SCALA_VER" >> $baseDir/jenkins.properties + echo "sbtDistVersionOverride=-Dproject.version=$SCALA_VER" >> $baseDir/jenkins.properties + + # We don't override the scala binary version: when running in -nightly + versions.properties versioning mode, + # we intend to be a drop-in replacement -- all you need to do is change the Scala version + # In order to override this, add 'set every scalaBinaryVersion := "'$SCALA_BINARY_VER'"', + # which, when used with pre-release Scala version numbers, will require tweaking at the sbt usage site as well. + scalaVersionTasks=('set every scalaVersion := "'$SCALA_VER'"') + + echo "Building Scala $SCALA_VER." +} + +deriveVersion() { + update $1 $2 $3 &> /dev/null + echo "$(git describe --match=v* | cut -dv -f2)-nightly" +} + +deriveVersionAnyTag() { + update $1 $2 $3 &> /dev/null + echo "$(git describe | cut -dv -f2)-nightly" +} + +# determineScalaVersion must have been called +deriveModuleVersions() { + if [ "$moduleVersioning" == "versions.properties" ] + then + # use versions.properties as defaults when no version specified on command line + XML_VER=${XML_VER-$scala_xml_version_number} + PARSERS_VER=${PARSERS_VER-$scala_parser_combinators_version_number} + CONTINUATIONS_VER=${CONTINUATIONS_VER-$scala_continuations_plugin_version_number} + SWING_VER=${SWING_VER-$scala_swing_version_number} + ACTORS_MIGRATION_VER=${ACTORS_MIGRATION_VER-$actors_migration_version_number} + PARTEST_VER=${PARTEST_VER-$partest_version_number} + SCALACHECK_VER=${SCALACHECK_VER-$scalacheck_version_number} + + # If a _VER was not specified, the corresponding _REF will be non-empty by now (as specified, or HEAD) + XML_REF=${XML_REF-"v$XML_VER"} + PARSERS_REF=${PARSERS_REF-"v$PARSERS_VER"} + CONTINUATIONS_REF=${CONTINUATIONS_REF-"v$CONTINUATIONS_VER"} + SWING_REF=${SWING_REF-"v$SWING_VER"} + ACTORS_MIGRATION_REF=${ACTORS_MIGRATION_REF-"v$ACTORS_MIGRATION_VER"} + PARTEST_REF=${PARTEST_REF-"v$PARTEST_VER"} + # PARTEST_IFACE_REF=${PARTEST_IFACE_REF-"v$PARTEST_IFACE_VER"} + SCALACHECK_REF=${SCALACHECK_REF-"$SCALACHECK_VER"} + else + XML_VER=${XML_VER-$(deriveVersion scala scala-xml "$XML_REF")} + PARSERS_VER=${PARSERS_VER-$(deriveVersion scala scala-parser-combinators "$PARSERS_REF")} + CONTINUATIONS_VER=${CONTINUATIONS_VER-$(deriveVersion scala scala-continuations "$CONTINUATIONS_REF")} + SWING_VER=${SWING_VER-$(deriveVersion scala scala-swing "$SWING_REF")} + ACTORS_MIGRATION_VER=${ACTORS_MIGRATION_VER-$(deriveVersion scala actors-migration "$ACTORS_MIGRATION_REF")} + PARTEST_VER=${PARTEST_VER-$(deriveVersion scala scala-partest "$PARTEST_REF")} + SCALACHECK_VER=${SCALACHECK_VER-$(deriveVersionAnyTag rickynils scalacheck "$SCALACHECK_REF")} + + XML_REF=${XML_REF-"HEAD"} + PARSERS_REF=${PARSERS_REF-"HEAD"} + CONTINUATIONS_REF=${CONTINUATIONS_REF-"HEAD"} + SWING_REF=${SWING_REF-"HEAD"} + ACTORS_MIGRATION_REF=${ACTORS_MIGRATION_REF-"HEAD"} + PARTEST_REF=${PARTEST_REF-"HEAD"} + # PARTEST_IFACE_REF=${PARTEST_IFACE_REF-"HEAD"} + SCALACHECK_REF=${SCALACHECK_REF-"HEAD"} + fi + + echo "Module versions (versioning strategy: $moduleVersioning):" + echo "ACTORS_MIGRATION = $ACTORS_MIGRATION_VER at $ACTORS_MIGRATION_REF" + echo "CONTINUATIONS = $CONTINUATIONS_VER at $CONTINUATIONS_REF" + echo "PARSERS = $PARSERS_VER at $PARSERS_REF" + echo "PARTEST = $PARTEST_VER at $PARTEST_REF" + echo "SCALACHECK = $SCALACHECK_VER at $SCALACHECK_REF" + echo "SWING = $SWING_VER at $SWING_REF" + echo "XML = $XML_VER at $XML_REF" + + # PARTEST_IFACE_VER=${PARTEST_IFACE_VER-$(deriveVersion scala scala-partest-interface "$PARTEST_IFACE_REF")} +} + +constructUpdatedModuleVersions() { + updatedModuleVersions=() + + # force the new module versions for building the core. these may be different from the values in versions.properties, + # either because the variables (XML_VER) were provided, or because we're building the modules from HEAD. + # in the common case, the values are the same as in versions.properties. + updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dactors-migration.version.number=$ACTORS_MIGRATION_VER") + updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-continuations-library.version.number=$CONTINUATIONS_VER") + updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-continuations-plugin.version.number=$CONTINUATIONS_VER") + updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-parser-combinators.version.number=$PARSERS_VER") + updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-swing.version.number=$SWING_VER") + updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-xml.version.number=$XML_VER") + + updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dpartest.version.number=$PARTEST_VER") + updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscalacheck.version.number=$SCALACHECK_VER") + + # allow overriding the akka-actors and jline version using a jenkins build parameter + if [ ! -z "$AKKA_ACTOR_VER" ]; then updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dakka-actor.version.number=$AKKA_ACTOR_VER"); fi + if [ ! -z "$JLINE_VER" ] ; then updatedModuleVersions=("${updatedModuleVersions[@]}" "-Djline.version=$JLINE_VER"); fi + + if [ ! -z "$SCALA_BINARY_VER" ]; then updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala.binary.version=$SCALA_BINARY_VER"); fi + if [ ! -z "$SCALA_FULL_VER" ] ; then updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala.full.version=$SCALA_FULL_VER"); fi +} + +# build locker (scala + modules) and quick, publishing everything to private-repo +bootstrap() { + echo "### Bootstrapping" + + cd $WORKSPACE + + #### LOCKER + + echo "### Building locker" + + # for bootstrapping, publish core (or at least smallest subset we can get away with) + # so that we can build modules with this version of Scala and publish them locally + # must publish under $SCALA_VER so that the modules will depend on this (binary) version of Scala + # publish more than just core: partest needs scalap + # in sabbus lingo, the resulting Scala build will be used as starr to build the released Scala compiler + ant -Dmaven.version.number=$SCALA_VER\ + -Dremote.snapshot.repository=NOPE\ + -Dremote.release.repository=$privateRepo\ + -Drepository.credentials.id=$privateCred\ + -Dscalac.args.optimise=-optimise\ + -Ddocs.skip=1\ + -Dlocker.skip=1\ + $publishLockerPrivateTask >> $baseDir/logs/builds 2>&1 + + + echo "### Building modules using locker" + + # build, test and publish modules with this core + # publish to our internal repo (so we can resolve the modules in the scala build below) + # we only need to build the modules necessary to build Scala itself + # since the version of locker and quick are the same + publishTasks=('set credentials += Credentials(Path.userHome / ".credentials-private-repo")' "set every publishTo := Some(\"private-repo\" at \"$privateRepo\")") + buildTasks=($publishPrivateTask) + buildModules + + constructUpdatedModuleVersions + + #### QUICK + + echo "### Bootstrapping Scala using locker" + + # # TODO: close all open staging repos so that we can be reaonably sure the only open one we see after publishing below is ours + # # the ant call will create a new one + # + # Rebuild Scala with these modules so that all binary versions are consistent. + # Update versions.properties to new modules. + # Sanity check: make sure the Scala test suite passes / docs can be generated with these modules. + # don't skip locker (-Dlocker.skip=1), or stability will fail + # overwrite "locker" version of scala at private-repo with bootstrapped version + cd $baseDir + rm -rf build/ # must leave everything else in $baseDir for downstream jobs + + ant -Dstarr.version=$SCALA_VER\ + -Dextra.repo.url=$privateRepo\ + -Dmaven.version.suffix=$SCALA_VER_SUFFIX\ + ${updatedModuleVersions[@]} \ + -Dupdate.versions=1\ + -Dscaladoc.git.commit=$SCALADOC_SOURCE_LINKS_VER\ + -Dremote.snapshot.repository=NOPE\ + -Dremote.release.repository=$privateRepo\ + -Drepository.credentials.id=$privateCred\ + -Dscalac.args.optimise=-optimise\ + $antBuildTask $publishPrivateTask + + # clear ivy cache (and to be sure, local as well), so the next round of sbt builds sees the fresh scala + rm -rf $baseDir/ivy2 + + # TODO: create PR with following commit (note that release will have been tagged already) + # git commit versions.properties -m"Bump versions.properties for $SCALA_VER." +} + +# assumes we just bootstrapped, and current directory is $baseDir +# publishes locker to sonatype, then builds modules again (those for which version numbers were provided), +# and publishes those to sonatype as well +# finally, the staging repos are closed +publishSonatype() { + # stage to sonatype, along with all modules -Dmaven.version.suffix/-Dbuild.release not necessary, + # since we're just publishing an existing build + echo "### Publishing core to sonatype" + ant -Dmaven.version.number=$SCALA_VER $publishSonatypeTaskCore + + echo "### Publishing modules to sonatype" + # build/test/publish scala core modules to sonatype (this will start a new staging repo) + # (was hoping we could make everything go to the same staging repo, but it's not timing that causes two staging repos to be opened) + # NOTE: only publish those for which versions are set + # test and publish to sonatype, assuming you have ~/.sbt/0.13/sonatype.sbt and ~/.sbt/0.13/plugin/gpg.sbt + publishTasks=('set credentials += Credentials(Path.userHome / ".credentials-sonatype")' "set pgpPassphrase := Some(Array.empty)") + buildTasks=($publishSonatypeTaskModules) + buildModules + + open=$(st_stagingReposOpen) + allOpenUrls=$(echo $open | jq '.repositoryURI' | tr -d \") + allOpen=$(echo $open | jq '.repositoryId' | tr -d \") + + echo "Closing open repos: $allOpen" + + for repo in $allOpen; do st_stagingRepoClose $repo; done + + echo "Closed sonatype staging repos: $allOpenUrls." +} + + +#### MAIN + +determineScalaVersion + +deriveModuleVersions + +bootstrap + +if [ "$publishToSonatype" == "yes" ] + then publishSonatype + else # build modules one more time, just to mimic the regular build as much when running as nightly + echo "### Rebuilding modules with quick, publishing to $baseDir/ivy/local" + buildTasks=(publish-local) + # buildScalacheck always uses publishPrivateTask (not buildTasks). we override it to avoid publishing to private-repo. + publishPrivateTask="publish-local" + forceRebuild="yes" + buildModules +fi diff --git a/scripts/jobs/integrate/ide b/scripts/jobs/integrate/ide new file mode 100755 index 0000000000..5c1e6199e3 --- /dev/null +++ b/scripts/jobs/integrate/ide @@ -0,0 +1,32 @@ +#!/bin/bash -e +# requires checkout: root is a scala checkout with which to integrate (actually, only required file is versions.properties, as documented below) +# requires env: scalaVersion (specifies binary already built from above checkout), WORKSPACE (provided by jenkins), repo_ref (HEAD of the scala checkout), +# requires files: $baseDir/versions.properties (from checkout -- defines version numbers for modules used to build scala for dbuild...) + +# TODO: remove when integration is up and running +if [ "woele$_scabot_last" != "woele1" ]; then echo "Scabot didn't mark this as last commit -- skipping."; exit 0; fi + +baseDir=${WORKSPACE-`pwd`} +uberBuildUrl=${uberBuildUrl-"https://github.com/scala-ide/uber-build.git"} +uberBuildConfig=${uberBuildConfig-"validator.conf"} # TODO: backport to 2.10.x: uberBuildConfig="validator-2.10.conf" + +uberBuildDir="$baseDir/uber-build/" + +cd $baseDir +if [[ -d $uberBuildDir ]]; then + ( cd $uberBuildDir && git fetch $uberBuildUrl HEAD && git checkout -f FETCH_HEAD && git clean -fxd ) +else + git clone $uberBuildUrl +fi + +echo "maven.version.number=$scalaVersion" >> versions.properties + +# pass prRepoUrl in, which uber-build passes along to dbuild (in sbt-builds-for-ide) +# the "-P pr-scala" maven arg accomplishes the same thing for maven (directly used in uber-build) +BASEDIR="$baseDir" prRepoUrl="$prRepoUrl" MAVEN_ARGS="-P pr-scala"\ + $uberBuildDir/uber-build.sh $uberBuildDir/config/$uberBuildConfig $repo_ref $scalaVersion + +# uber-build puts its local repo under target/m2repo +# wipe the org/scala-lang part, which otherwise just keeps +# growing and growing due to the -$sha-SNAPSHOT approach +[[ -d $baseDir/target/m2repo/org/scala-lang ]] && rm -rf $baseDir/target/m2repo/org/scala-lang diff --git a/scripts/jobs/validate/publish-core b/scripts/jobs/validate/publish-core new file mode 100755 index 0000000000..9dff5a34b0 --- /dev/null +++ b/scripts/jobs/validate/publish-core @@ -0,0 +1,44 @@ +#!/bin/bash -e +# This script publishes the core of Scala to maven for use as locker downstream, +# and saves the relevant properties used in its build artifacts, versions.properties. +# (This means we'll use locker instead of quick downstream in dbuild. +# The only downside is that backend improvements don't improve compiler performance itself until they are in STARR). +# The version is suffixed with "-${sha:0:7}-SNAPSHOT" + +baseDir=${WORKSPACE-`pwd`} +scriptsDir="$baseDir/scripts" +. $scriptsDir/common + +case $prDryRun in + yep) + echo "DRY RUN" + mkdir -p build/pack ; mkdir -p dists/maven/latest + ;; + *) + sha=$(git rev-parse HEAD) # TODO: warn if $repo_ref != $sha (we shouldn't do PR validation using symbolic gitrefs) + echo "sha/repo_ref == $sha/$repo_ref ?" + + parseScalaProperties build.number + + ./pull-binary-libs.sh + # "noyoudont" is there juuuust in case + antDeployArgs="-Dmaven.version.suffix=\"-${sha:0:7}-SNAPSHOT\" -Dremote.snapshot.repository=$prRepoUrl -Drepository.credentials.id=pr-scala -Dremote.release.repository=noyoudont" + + echo ">>> Getting Scala version number." + ant -q $antDeployArgs init + parseScalaProperties buildcharacter.properties # produce maven_version_number + + echo ">>> Checking availability of Scala ${maven_version_number} in $prRepoUrl." + checkAvailability "org.scala-lang" "scala-library" "${maven_version_number}" $prRepoUrl; libraryAvailable=$RES + checkAvailability "org.scala-lang" "scala-reflect" "${maven_version_number}" $prRepoUrl; reflectAvailable=$RES + checkAvailability "org.scala-lang" "scala-compiler" "${maven_version_number}" $prRepoUrl; compilerAvailable=$RES + + if $libraryAvailable && $reflectAvailable && $compilerAvailable; then + echo "Scala core already built!" + else + ant $antDeployArgs $antBuildArgs publish-opt-nodocs + fi + + mv buildcharacter.properties jenkins.properties # parsed by the jenkins job + ;; +esac diff --git a/scripts/jobs/validate/test b/scripts/jobs/validate/test new file mode 100755 index 0000000000..c1c02c80cb --- /dev/null +++ b/scripts/jobs/validate/test @@ -0,0 +1,17 @@ +#!/bin/bash -e + +case $prDryRun in + yep) + echo "DRY RUN" + ;; + *) + ./pull-binary-libs.sh + + # build quick using STARR built upstream, as specified by scalaVersion + # (in that sense it's locker, since it was built with starr by that upstream job) + ant -Dstarr.version=$scalaVersion \ + -Dscalac.args.optimise=-optimise \ + -Dlocker.skip=1 -Dstarr.use.released=1 -Dextra.repo.url=$prRepoUrl \ + $testExtraArgs ${testTarget-test.core docs.done} + ;; +esac
\ No newline at end of file diff --git a/scripts/readproperties.awk b/scripts/readproperties.awk new file mode 100644 index 0000000000..96da94775b --- /dev/null +++ b/scripts/readproperties.awk @@ -0,0 +1,39 @@ +# Adapted from http://stackoverflow.com/questions/1682442/reading-java-properties-file-from-bash/2318840#2318840 +BEGIN { + FS="="; + n=""; + v=""; + c=0; # Not a line continuation. +} +/^\#/ { # The line is a comment. Breaks line continuation. + c=0; + next; +} +/\\$/ && (c==0) && (NF>=2) { # Name value pair with a line continuation... + e=index($0,"="); + n=substr($0,1,e-1); + v=substr($0,e+1,length($0) - e - 1); # Trim off the backslash. + c=1; # Line continuation mode. + next; +} +/^[^\\]+\\$/ && (c==1) { # Line continuation. Accumulate the value. + v= "" v substr($0,1,length($0)-1); + next; +} +((c==1) || (NF>=2)) && !/^[^\\]+\\$/ { # End of line continuation, or a single line name/value pair + if (c==0) { # Single line name/value pair + e=index($0,"="); + n=substr($0,1,e-1); + v=substr($0,e+1,length($0) - e); + } else { # Line continuation mode - last line of the value. + c=0; # Turn off line continuation mode. + v= "" v $0; + } + # Make sure the name is a legal shell variable name + gsub(/[^A-Za-z0-9_]/,"_",n); + # Silently drop everything that might confuse bash. + gsub(/[\n\r\\\t'"\$!]/,"",v); + print "export " n "=\"" v "\" || echo \"Failed to set " n "\""; # don't make bash crap out when a property could not be parsed + n = ""; + v = ""; +} diff --git a/scripts/repositories-scala-release b/scripts/repositories-scala-release new file mode 100644 index 0000000000..00538a08ff --- /dev/null +++ b/scripts/repositories-scala-release @@ -0,0 +1,7 @@ +[repositories] + plugins: http://dl.bintray.com/sbt/sbt-plugin-releases/, [organisation]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext] + private-repo: http://private-repo.typesafe.com/typesafe/scala-release-temp/ + typesafe-ivy-releases: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext], bootOnly + sbt-plugin-releases: http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext] + maven-central + local
\ No newline at end of file diff --git a/spec/03-types.md b/spec/03-types.md index d067d45ab2..5658e15f44 100644 --- a/spec/03-types.md +++ b/spec/03-types.md @@ -167,8 +167,8 @@ SimpleType ::= SimpleType TypeArgs TypeArgs ::= ‘[’ Types ‘]’ ``` -A parameterized type $T[ U_1 , \ldots , U_n ]$ consists of a type -designator $T$ and type parameters $U_1 , \ldots , U_n$ where +A parameterized type $T[ T_1 , \ldots , T_n ]$ consists of a type +designator $T$ and type parameters $T_1 , \ldots , T_n$ where $n \geq 1$. $T$ must refer to a type constructor which takes $n$ type parameters $a_1 , \ldots , a_n$. diff --git a/spec/04-basic-declarations-and-definitions.md b/spec/04-basic-declarations-and-definitions.md index aca1c63d22..65d79dd5f4 100644 --- a/spec/04-basic-declarations-and-definitions.md +++ b/spec/04-basic-declarations-and-definitions.md @@ -631,7 +631,7 @@ For every parameter $p_{i,j}$ with a default argument a method named expression. Here, $n$ denotes the parameter's position in the method declaration. These methods are parametrized by the type parameter clause `[$\mathit{tps}\,$]` and all value parameter clauses -`($\mathit{ps}_1$)$\ldots$($\mathit{ps}_{i-1}$)` preceeding $p_{i,j}$. +`($\mathit{ps}_1$)$\ldots$($\mathit{ps}_{i-1}$)` preceding $p_{i,j}$. The `$f\$$default$\$$n` methods are inaccessible for user programs. diff --git a/spec/05-classes-and-objects.md b/spec/05-classes-and-objects.md index ef854b2abb..fd20d6ae2c 100644 --- a/spec/05-classes-and-objects.md +++ b/spec/05-classes-and-objects.md @@ -128,7 +128,7 @@ consists of the following steps. occurrence in the linearization. - Finally the statement sequence $\mathit{stats}\,$ is evaluated. -###### Delayed Initializaton +###### Delayed Initialization The initialization code of an object or class (but not a trait) that follows the superclass constructor invocation and the mixin-evaluation of the template's base diff --git a/spec/06-expressions.md b/spec/06-expressions.md index afd1492744..133ec3c8e5 100644 --- a/spec/06-expressions.md +++ b/spec/06-expressions.md @@ -410,6 +410,19 @@ The final result of the transformation is a block of the form } ``` +### Signature Polymorphic Methods + +For invocations of signature polymorphic methods of the target platform `$f$($e_1 , \ldots , e_m$)`, +the invoked function has a different method type `($p_1$:$T_1 , \ldots , p_n$:$T_n$)$U$` at each call +site. The parameter types `$T_ , \ldots , T_n$` are the types of the argument expressions +`$e_1 , \ldots , e_m$` and `$U$` is the expected type at the call site. If the expected type is +undefined then `$U$` is `scala.AnyRef`. The parameter names `$p_1 , \ldots , p_n$` are fresh. + +###### Note + +On the Java platform version 7 and later, the methods `invoke` and `invokeExact` in class +`java.lang.invoke.MethodHandle` are signature polymorphic. + ## Method Values ```ebnf @@ -666,7 +679,7 @@ followed by operators starting with ``|`', etc. There's one exception to this rule, which concerns [_assignment operators_](#assignment-operators). -The precedence of an assigment operator is the same as the one +The precedence of an assignment operator is the same as the one of simple assignment `(=)`. That is, it is lower than the precedence of any other operator. @@ -1109,7 +1122,7 @@ is `scala.Nothing`. ## Try Expressions ```ebnf -Expr1 ::= `try' `{' Block `}' [`catch' `{' CaseClauses `}'] +Expr1 ::= `try' (`{' Block `}' | Expr) [`catch' `{' CaseClauses `}'] [`finally' Expr] ``` @@ -1761,7 +1774,7 @@ trait Dynamic { ``` Assume a selection of the form $e.x$ where the type of $e$ conforms to `scala.Dynamic`. -Further assuming the selection is not followed by any function arguments, such an expression can be rewitten under the conditions given [here](#implicit-conversions) to: +Further assuming the selection is not followed by any function arguments, such an expression can be rewritten under the conditions given [here](#implicit-conversions) to: ```scala $e$.applyDynamic("$x$") diff --git a/spec/08-pattern-matching.md b/spec/08-pattern-matching.md index 3538457b5c..e75bddc096 100644 --- a/spec/08-pattern-matching.md +++ b/spec/08-pattern-matching.md @@ -609,7 +609,7 @@ case class If[T](c: Term[Boolean], There are terms to represent numeric literals, incrementation, a zero test, and a conditional. Every term carries as a type parameter the -type of the expression it representes (either `Int` or `Boolean`). +type of the expression it represents (either `Int` or `Boolean`). A type-safe evaluator for such terms can be written as follows. diff --git a/spec/09-top-level-definitions.md b/spec/09-top-level-definitions.md index 847fab548d..e3185d8b7d 100644 --- a/spec/09-top-level-definitions.md +++ b/spec/09-top-level-definitions.md @@ -159,7 +159,7 @@ The `main` method of a program can be directly defined in the object, or it can be inherited. The scala library defines a special class `scala.App` whose body acts as a `main` method. An objects $m$ inheriting from this class is thus a program, -which executes the initializaton code of the object $m$. +which executes the initialization code of the object $m$. ###### Example The following example will create a hello world program by defining diff --git a/src/actors/scala/actors/Actor.scala b/src/actors/scala/actors/Actor.scala index 75160fa18f..293335f720 100644 --- a/src/actors/scala/actors/Actor.scala +++ b/src/actors/scala/actors/Actor.scala @@ -205,7 +205,7 @@ object Actor extends Combinators { * Actions in `f` have to contain the rest of the computation of `self`, * as this method will never return. * - * A common method of continuting the computation is to send a message + * A common method of continuing the computation is to send a message * to another actor: * {{{ * react { diff --git a/src/actors/scala/actors/LinkedQueue.java b/src/actors/scala/actors/LinkedQueue.java index 796f428cf5..3f7b93c386 100644 --- a/src/actors/scala/actors/LinkedQueue.java +++ b/src/actors/scala/actors/LinkedQueue.java @@ -22,7 +22,7 @@ package scala.actors; * and takes when the queue is not empty. * Normally a put and a take can proceed simultaneously. * (Although it does not allow multiple concurrent puts or takes.) - * This class tends to perform more efficently than + * This class tends to perform more efficiently than * other Channel implementations in producer/consumer * applications. * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>] diff --git a/src/actors/scala/actors/remote/Proxy.scala b/src/actors/scala/actors/remote/Proxy.scala index 9949b36181..2cb03544f2 100644 --- a/src/actors/scala/actors/remote/Proxy.scala +++ b/src/actors/scala/actors/remote/Proxy.scala @@ -84,7 +84,7 @@ private[remote] class Proxy(node: Node, name: Symbol, @transient var kernel: Net } // Proxy is private[remote], but these classes are public and use it in a public -// method signature. That makes the only method they have non-overriddable. +// method signature. That makes the only method they have non-overridable. // So I made them final, which seems appropriate anyway. final class LinkToFun extends Function2[AbstractActor, Proxy, Unit] with Serializable { diff --git a/src/actors/scala/actors/threadpool/AbstractCollection.java b/src/actors/scala/actors/threadpool/AbstractCollection.java index f3dc1e1292..195a0064ab 100644 --- a/src/actors/scala/actors/threadpool/AbstractCollection.java +++ b/src/actors/scala/actors/threadpool/AbstractCollection.java @@ -1,6 +1,6 @@ /* * Written by Dawid Kurzyniec, based on public domain code written by Doug Lea - * and publictly available documentation, and released to the public domain, as + * and publicly available documentation, and released to the public domain, as * explained at http://creativecommons.org/licenses/publicdomain */ diff --git a/src/actors/scala/actors/threadpool/ExecutorCompletionService.java b/src/actors/scala/actors/threadpool/ExecutorCompletionService.java index 9a4a4fb71c..02e9bbe297 100644 --- a/src/actors/scala/actors/threadpool/ExecutorCompletionService.java +++ b/src/actors/scala/actors/threadpool/ExecutorCompletionService.java @@ -135,7 +135,7 @@ public class ExecutorCompletionService implements CompletionService { * @param completionQueue the queue to use as the completion queue * normally one dedicated for use by this service. This queue is * treated as unbounded -- failed attempted <tt>Queue.add</tt> - * operations for completed taskes cause them not to be + * operations for completed tasks cause them not to be * retrievable. * @throws NullPointerException if executor or completionQueue are <tt>null</tt> */ diff --git a/src/actors/scala/actors/threadpool/locks/ReentrantReadWriteLock.java b/src/actors/scala/actors/threadpool/locks/ReentrantReadWriteLock.java index 437af77c7a..914d242100 100644 --- a/src/actors/scala/actors/threadpool/locks/ReentrantReadWriteLock.java +++ b/src/actors/scala/actors/threadpool/locks/ReentrantReadWriteLock.java @@ -20,13 +20,13 @@ import scala.actors.threadpool.helpers.*; * * <p>The order of entry * to the read and write lock is unspecified, subject to reentrancy - * constraints. A nonfair lock that is continously contended may + * constraints. A nonfair lock that is continuously contended may * indefinitely postpone one or more reader or writer threads, but * will normally have higher throughput than a fair lock. * <p> * * DEPARTURE FROM java.util.concurrent: this implementation impose - * a writer-preferrence and thus its acquisition order may be different + * a writer-preference and thus its acquisition order may be different * than in java.util.concurrent. * * <li><b>Reentrancy</b> diff --git a/src/asm/scala/tools/asm/Label.java b/src/asm/scala/tools/asm/Label.java index 5d5529ce74..c094eba408 100644 --- a/src/asm/scala/tools/asm/Label.java +++ b/src/asm/scala/tools/asm/Label.java @@ -545,7 +545,7 @@ public class Label { } // ------------------------------------------------------------------------ - // Overriden Object methods + // Overridden Object methods // ------------------------------------------------------------------------ /** diff --git a/src/asm/scala/tools/asm/tree/analysis/Analyzer.java b/src/asm/scala/tools/asm/tree/analysis/Analyzer.java index 0134555f10..ff840aabde 100644 --- a/src/asm/scala/tools/asm/tree/analysis/Analyzer.java +++ b/src/asm/scala/tools/asm/tree/analysis/Analyzer.java @@ -375,7 +375,7 @@ public class Analyzer<V extends Value> implements Opcodes { * instruction of the method. The size of the returned array is * equal to the number of instructions (and labels) of the method. A * given frame is <tt>null</tt> if the corresponding instruction - * cannot be reached, or if an error occured during the analysis of + * cannot be reached, or if an error occurred during the analysis of * the method. */ public Frame<V>[] getFrames() { @@ -435,7 +435,7 @@ public class Analyzer<V extends Value> implements Opcodes { /** * Creates a control flow graph edge. The default implementation of this - * method does nothing. It can be overriden in order to construct the + * method does nothing. It can be overridden in order to construct the * control flow graph of a method (this method is called by the * {@link #analyze analyze} method during its visit of the method's code). * diff --git a/src/asm/scala/tools/asm/tree/analysis/Interpreter.java b/src/asm/scala/tools/asm/tree/analysis/Interpreter.java index 56f4bedc00..00fe6c8bff 100644 --- a/src/asm/scala/tools/asm/tree/analysis/Interpreter.java +++ b/src/asm/scala/tools/asm/tree/analysis/Interpreter.java @@ -82,7 +82,7 @@ public abstract class Interpreter<V extends Value> { * the bytecode instruction to be interpreted. * @return the result of the interpretation of the given instruction. * @throws AnalyzerException - * if an error occured during the interpretation. + * if an error occurred during the interpretation. */ public abstract V newOperation(AbstractInsnNode insn) throws AnalyzerException; @@ -101,7 +101,7 @@ public abstract class Interpreter<V extends Value> { * @return the result of the interpretation of the given instruction. The * returned value must be <tt>equal</tt> to the given value. * @throws AnalyzerException - * if an error occured during the interpretation. + * if an error occurred during the interpretation. */ public abstract V copyOperation(AbstractInsnNode insn, V value) throws AnalyzerException; @@ -122,7 +122,7 @@ public abstract class Interpreter<V extends Value> { * the argument of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. * @throws AnalyzerException - * if an error occured during the interpretation. + * if an error occurred during the interpretation. */ public abstract V unaryOperation(AbstractInsnNode insn, V value) throws AnalyzerException; @@ -146,7 +146,7 @@ public abstract class Interpreter<V extends Value> { * the second argument of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. * @throws AnalyzerException - * if an error occured during the interpretation. + * if an error occurred during the interpretation. */ public abstract V binaryOperation(AbstractInsnNode insn, V value1, V value2) throws AnalyzerException; @@ -167,7 +167,7 @@ public abstract class Interpreter<V extends Value> { * the third argument of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. * @throws AnalyzerException - * if an error occured during the interpretation. + * if an error occurred during the interpretation. */ public abstract V ternaryOperation(AbstractInsnNode insn, V value1, V value2, V value3) throws AnalyzerException; @@ -185,7 +185,7 @@ public abstract class Interpreter<V extends Value> { * the arguments of the instruction to be interpreted. * @return the result of the interpretation of the given instruction. * @throws AnalyzerException - * if an error occured during the interpretation. + * if an error occurred during the interpretation. */ public abstract V naryOperation(AbstractInsnNode insn, List<? extends V> values) throws AnalyzerException; @@ -203,7 +203,7 @@ public abstract class Interpreter<V extends Value> { * @param expected * the expected return type of the analyzed method. * @throws AnalyzerException - * if an error occured during the interpretation. + * if an error occurred during the interpretation. */ public abstract void returnOperation(AbstractInsnNode insn, V value, V expected) throws AnalyzerException; diff --git a/src/asm/scala/tools/asm/util/Printer.java b/src/asm/scala/tools/asm/util/Printer.java index 4135672c6b..773f129ad9 100644 --- a/src/asm/scala/tools/asm/util/Printer.java +++ b/src/asm/scala/tools/asm/util/Printer.java @@ -181,7 +181,7 @@ public abstract class Printer { */ public Printer visitClassTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { - throw new RuntimeException("Must be overriden"); + throw new RuntimeException("Must be overridden"); } /** @@ -264,7 +264,7 @@ public abstract class Printer { */ public Printer visitFieldTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { - throw new RuntimeException("Must be overriden"); + throw new RuntimeException("Must be overridden"); } /** @@ -287,7 +287,7 @@ public abstract class Printer { * {@link scala.tools.asm.MethodVisitor#visitParameter(String, int)}. */ public void visitParameter(String name, int access) { - throw new RuntimeException("Must be overriden"); + throw new RuntimeException("Must be overridden"); } /** @@ -309,7 +309,7 @@ public abstract class Printer { */ public Printer visitMethodTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { - throw new RuntimeException("Must be overriden"); + throw new RuntimeException("Must be overridden"); } /** @@ -380,7 +380,7 @@ public abstract class Printer { visitMethodInsn(opcode, owner, name, desc, itf); return; } - throw new RuntimeException("Must be overriden"); + throw new RuntimeException("Must be overridden"); } /** @@ -397,7 +397,7 @@ public abstract class Printer { visitMethodInsn(opcode, owner, name, desc); return; } - throw new RuntimeException("Must be overriden"); + throw new RuntimeException("Must be overridden"); } /** @@ -457,7 +457,7 @@ public abstract class Printer { */ public Printer visitInsnAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { - throw new RuntimeException("Must be overriden"); + throw new RuntimeException("Must be overridden"); } /** @@ -473,7 +473,7 @@ public abstract class Printer { */ public Printer visitTryCatchAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { - throw new RuntimeException("Must be overriden"); + throw new RuntimeException("Must be overridden"); } /** @@ -491,7 +491,7 @@ public abstract class Printer { public Printer visitLocalVariableAnnotation(final int typeRef, final TypePath typePath, final Label[] start, final Label[] end, final int[] index, final String desc, final boolean visible) { - throw new RuntimeException("Must be overriden"); + throw new RuntimeException("Must be overridden"); } /** diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala index 8905c94eeb..13bf0ef4c6 100644 --- a/src/compiler/scala/tools/ant/Scalac.scala +++ b/src/compiler/scala/tools/ant/Scalac.scala @@ -479,7 +479,7 @@ class Scalac extends ScalaMatchingTask with ScalacShared { /** Tests if a file exists and prints a warning in case it doesn't. Always * returns the file, even if it doesn't exist. - * @param file A file to test for existance. + * @param file A file to test for existence. * @return The same file. */ protected def existing(file: File): File = { if (!file.exists) diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 733664c30a..1c9dbad4dd 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -234,7 +234,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Called by ScalaDocAnalyzer when a doc comment has been parsed. */ def signalParsedDocComment(comment: String, pos: Position) = { - // TODO: this is all very borken (only works for scaladoc comments, not regular ones) + // TODO: this is all very broken (only works for scaladoc comments, not regular ones) // --> add hooks to parser and refactor Interactive global to handle comments directly // in any case don't use reporter for parser hooks reporter.comment(pos, comment) @@ -1461,7 +1461,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } - /** Caching member symbols that are def-s in Defintions because they might change from Run to Run. */ + /** Caching member symbols that are def-s in Definitions because they might change from Run to Run. */ val runDefinitions: definitions.RunDefinitions = new definitions.RunDefinitions /** Compile list of source files, diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala index 1eb6c9da2c..e1cfa63960 100644 --- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala +++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala @@ -18,7 +18,7 @@ trait PhaseAssembly { /** * Aux datastructure for solving the constraint system - * The depency graph container with helper methods for node and edge creation + * The dependency graph container with helper methods for node and edge creation */ private class DependencyGraph { diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala index f1517e56a0..96939e616c 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala @@ -425,11 +425,10 @@ trait MarkupParsers { if (ch != '/') ts append xPattern // child else return false // terminate - case '{' => // embedded Scala patterns - while (ch == '{') { - nextch() + case '{' if xCheckEmbeddedBlock => // embedded Scala patterns, if not double brace + do { ts ++= xScalaPatterns - } + } while (xCheckEmbeddedBlock) assert(!xEmbeddedBlock, "problem with embedded block") case SU => diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index d9f56b47fa..cf52ad6636 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1077,7 +1077,7 @@ abstract class GenICode extends SubComponent { () case (_, UNIT) => ctx.bb.emit(DROP(from), pos) - // otherwise we'd better be doing a primtive -> primitive coercion or there's a problem + // otherwise we'd better be doing a primitive -> primitive coercion or there's a problem case _ if !from.isRefOrArrayType && !to.isRefOrArrayType => coerce(from, to) case _ => @@ -1495,7 +1495,7 @@ abstract class GenICode extends SubComponent { if (!settings.optimise) { if (l.tpe <:< BoxedNumberClass.tpe) { if (r.tpe <:< BoxedNumberClass.tpe) platform.externalEqualsNumNum - else if (r.tpe <:< BoxedCharacterClass.tpe) platform.externalEqualsNumChar + else if (r.tpe <:< BoxedCharacterClass.tpe) platform.externalEqualsNumObject // will be externalEqualsNumChar in 2.12, SI-9030 else platform.externalEqualsNumObject } else platform.externalEquals } else { diff --git a/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala b/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala index f81c42d836..27bf836484 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Primitives.scala @@ -60,7 +60,7 @@ trait Primitives { self: ICodes => // type : (buf,el) => buf // range: lf,rg <- { BOOL, Ix, Ux, Rx, REF, STR } - // jvm : It should call the appropiate 'append' method on StringBuffer + // jvm : It should call the appropriate 'append' method on StringBuffer case class StringConcat(el: TypeKind) extends Primitive /** Signals the beginning of a series of concatenations. diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala index 676ee12683..b0ad5bdaf9 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala @@ -332,13 +332,13 @@ abstract class TypeFlowAnalysis { `remainingCALLs` also caches info about the typestack just before the callsite, so as to spare computing them again at inlining time. Besides caching, a further optimization involves skipping those basic blocks whose in-flow and out-flow isn't needed anyway (as explained next). - A basic block lacking a callsite in `remainingCALLs`, when visisted by the standard algorithm, won't cause any inlining. + A basic block lacking a callsite in `remainingCALLs`, when visited by the standard algorithm, won't cause any inlining. But as we know from the way type-flows are computed, computing the in- and out-flow for a basic block relies in general on those of other basic blocks. In detail, we want to focus on that sub-graph of the CFG such that control flow may reach a remaining candidate callsite. Those basic blocks not in that subgraph can be skipped altogether. That's why: - `forwardAnalysis()` in `MTFAGrowable` now checks for inclusion of a basic block in `relevantBBs` - same check is performed before adding a block to the worklist, and as part of choosing successors. - The bookkeeping supporting on-the-fly pruning of irrelevant blocks requires overridding most methods of the dataflow-analysis. + The bookkeeping supporting on-the-fly pruning of irrelevant blocks requires overriding most methods of the dataflow-analysis. The rest of the story takes place in Inliner, which does not visit all of the method's basic blocks but only on those represented in `remainingCALLs`. diff --git a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala index 7269910af6..75aa0fc984 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala @@ -5,10 +5,11 @@ package scala.tools.nsc.backend.jvm -import scala.tools.asm.tree.{AbstractInsnNode, ClassNode, MethodNode} -import java.io.PrintWriter +import scala.tools.asm.tree.{InsnList, AbstractInsnNode, ClassNode, MethodNode} +import java.io.{StringWriter, PrintWriter} import scala.tools.asm.util.{TraceClassVisitor, TraceMethodVisitor, Textifier} import scala.tools.asm.ClassReader +import scala.collection.convert.decorateAsScala._ object AsmUtils { @@ -36,19 +37,12 @@ object AsmUtils { def traceMethod(mnode: MethodNode): Unit = { println(s"Bytecode for method ${mnode.name}") - val p = new Textifier - val tracer = new TraceMethodVisitor(p) - mnode.accept(tracer) - val w = new PrintWriter(System.out) - p.print(w) - w.flush() + println(textify(mnode)) } def traceClass(cnode: ClassNode): Unit = { println(s"Bytecode for class ${cnode.name}") - val w = new PrintWriter(System.out) - cnode.accept(new TraceClassVisitor(w)) - w.flush() + println(textify(cnode)) } def traceClass(bytes: Array[Byte]): Unit = traceClass(readClass(bytes)) @@ -59,8 +53,56 @@ object AsmUtils { node } - def instructionString(instruction: AbstractInsnNode): String = instruction.getOpcode match { - case -1 => instruction.toString - case op => scala.tools.asm.util.Printer.OPCODES(op) + /** + * Returns a human-readable representation of the cnode ClassNode. + */ + def textify(cnode: ClassNode): String = { + val trace = new TraceClassVisitor(new PrintWriter(new StringWriter)) + cnode.accept(trace) + val sw = new StringWriter + val pw = new PrintWriter(sw) + trace.p.print(pw) + sw.toString } + + /** + * Returns a human-readable representation of the code in the mnode MethodNode. + */ + def textify(mnode: MethodNode): String = { + val trace = new TraceClassVisitor(new PrintWriter(new StringWriter)) + mnode.accept(trace) + val sw = new StringWriter + val pw = new PrintWriter(sw) + trace.p.print(pw) + sw.toString + } + + /** + * Returns a human-readable representation of the given instruction. + */ + def textify(insn: AbstractInsnNode): String = { + val trace = new TraceMethodVisitor(new Textifier) + insn.accept(trace) + val sw = new StringWriter + val pw = new PrintWriter(sw) + trace.p.print(pw) + sw.toString.trim + } + + /** + * Returns a human-readable representation of the given instruction sequence. + */ + def textify(insns: Iterator[AbstractInsnNode]): String = { + val trace = new TraceMethodVisitor(new Textifier) + insns.foreach(_.accept(trace)) + val sw: StringWriter = new StringWriter + val pw: PrintWriter = new PrintWriter(sw) + trace.p.print(pw) + sw.toString.trim + } + + /** + * Returns a human-readable representation of the given instruction sequence. + */ + def textify(insns: InsnList): String = textify(insns.iterator().asScala) } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala index 328ec8a033..a5f33aa786 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala @@ -162,4 +162,32 @@ final class BCodeAsmCommon[G <: Global](val global: G) { assoc.collectFirst { case (`nme`.value, LiteralAnnotArg(Constant(value: Symbol))) => value }).flatten.getOrElse(AnnotationRetentionPolicyClassValue) + + def implementedInterfaces(classSym: Symbol): List[Symbol] = { + // Additional interface parents based on annotations and other cues + def newParentForAnnotation(ann: AnnotationInfo): Option[Type] = ann.symbol match { + case RemoteAttr => Some(RemoteInterfaceClass.tpe) + case _ => None + } + + def isInterfaceOrTrait(sym: Symbol) = sym.isInterface || sym.isTrait + + val allParents = classSym.info.parents ++ classSym.annotations.flatMap(newParentForAnnotation) + + // We keep the superClass when computing minimizeParents to eliminate more interfaces. + // Example: T can be eliminated from D + // trait T + // class C extends T + // class D extends C with T + val interfaces = erasure.minimizeParents(allParents) match { + case superClass :: ifs if !isInterfaceOrTrait(superClass.typeSymbol) => + ifs + case ifs => + // minimizeParents removes the superclass if it's redundant, for example: + // trait A + // class C extends Object with A // minimizeParents removes Object + ifs + } + interfaces.map(_.typeSymbol) + } } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index daf36ce374..062daa4eac 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -1225,7 +1225,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { val equalsMethod: Symbol = { if (l.tpe <:< BoxedNumberClass.tpe) { if (r.tpe <:< BoxedNumberClass.tpe) platform.externalEqualsNumNum - else if (r.tpe <:< BoxedCharacterClass.tpe) platform.externalEqualsNumChar + else if (r.tpe <:< BoxedCharacterClass.tpe) platform.externalEqualsNumObject // will be externalEqualsNumChar in 2.12, SI-9030 else platform.externalEqualsNumObject } else platform.externalEquals } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 806d4b277c..8d1c37532e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -791,32 +791,28 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { assert(moduleClass.companionClass == NoSymbol, moduleClass) innerClassBufferASM.clear() this.cunit = cunit - val moduleName = internalName(moduleClass) // + "$" - val mirrorName = moduleName.substring(0, moduleName.length() - 1) - val flags = (asm.Opcodes.ACC_SUPER | asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_FINAL) + val bType = mirrorClassClassBType(moduleClass) val mirrorClass = new asm.tree.ClassNode mirrorClass.visit( classfileVersion, - flags, - mirrorName, + bType.info.flags, + bType.internalName, null /* no java-generic-signature */, ObjectReference.internalName, EMPTY_STRING_ARRAY ) - if (emitSource) { - mirrorClass.visitSource("" + cunit.source, - null /* SourceDebugExtension */) - } + if (emitSource) + mirrorClass.visitSource("" + cunit.source, null /* SourceDebugExtension */) - val ssa = getAnnotPickle(mirrorName, moduleClass.companionSymbol) + val ssa = getAnnotPickle(bType.internalName, moduleClass.companionSymbol) mirrorClass.visitAttribute(if (ssa.isDefined) pickleMarkerLocal else pickleMarkerForeign) emitAnnotations(mirrorClass, moduleClass.annotations ++ ssa) - addForwarders(isRemote(moduleClass), mirrorClass, mirrorName, moduleClass) + addForwarders(isRemote(moduleClass), mirrorClass, bType.internalName, moduleClass) - innerClassBufferASM ++= classBTypeFromSymbol(moduleClass).info.memberClasses + innerClassBufferASM ++= bType.info.nestedClasses addInnerClassesASM(mirrorClass, innerClassBufferASM.toList) mirrorClass.visitEnd() @@ -932,7 +928,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { constructor.visitMaxs(0, 0) // just to follow protocol, dummy arguments constructor.visitEnd() - innerClassBufferASM ++= classBTypeFromSymbol(cls).info.memberClasses + innerClassBufferASM ++= classBTypeFromSymbol(cls).info.nestedClasses addInnerClassesASM(beanInfoClass, innerClassBufferASM.toList) beanInfoClass.visitEnd() diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala index d58368b19d..c3db28151b 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala @@ -271,7 +271,7 @@ abstract class BCodeIdiomatic extends SubComponent { assert(from != BOOL && to != BOOL, s"inconvertible types : $from -> $to") // We're done with BOOL already - from match { + (from: @unchecked) match { // using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match" @@ -361,7 +361,7 @@ abstract class BCodeIdiomatic extends SubComponent { assert(elem.isNonVoidPrimitiveType) val rand = { // using `asm.Type.SHORT` instead of `BType.SHORT` because otherwise "warning: could not emit switch for @switch annotated match" - elem match { + (elem: @unchecked) match { case BOOL => Opcodes.T_BOOLEAN case BYTE => Opcodes.T_BYTE case SHORT => Opcodes.T_SHORT diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala index 03bc32061b..142c901c21 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala @@ -118,7 +118,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { addClassFields() - innerClassBufferASM ++= classBTypeFromSymbol(claszSymbol).info.memberClasses + innerClassBufferASM ++= classBTypeFromSymbol(claszSymbol).info.nestedClasses gen(cd.impl) addInnerClassesASM(cnode, innerClassBufferASM.toList) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala index 7c95b7fc3b..b94208c1a5 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala @@ -284,7 +284,7 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder { * ------ */ - // a note on terminology: this is not "postHandlers", despite appearences. + // a note on terminology: this is not "postHandlers", despite appearances. // "postHandlers" as in the source-code view. And from that perspective, both (3.A) and (3.B) are invisible implementation artifacts. if (hasFinally) { nopIfNeeded(startTryBody) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala index 53ac5bfdc7..a9bce82acd 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala @@ -8,16 +8,35 @@ package backend.jvm import scala.tools.asm import asm.Opcodes +import scala.tools.asm.tree.{InnerClassNode, ClassNode} +import opt.ByteCodeRepository +import scala.collection.convert.decorateAsScala._ /** - * The BTypes component defines The BType class hierarchy. BTypes encapsulates all type information - * that is required after building the ASM nodes. This includes optimizations, geneartion of + * The BTypes component defines The BType class hierarchy. BTypes encapsulate all type information + * that is required after building the ASM nodes. This includes optimizations, generation of * InnerClass attributes and generation of stack map frames. * * This representation is immutable and independent of the compiler data structures, hence it can * be queried by concurrent threads. */ abstract class BTypes { + import BTypes.InternalName + + // Some core BTypes are required here, in class BType, where no Global instance is available. + // The Global is only available in the subclass BTypesFromSymbols. We cannot depend on the actual + // implementation (CoreBTypesProxy) here because it has members that refer to global.Symbol. + val coreBTypes: CoreBTypesProxyGlobalIndependent[this.type] + import coreBTypes._ + + /** + * Tools for parsing classfiles, used by the inliner. + */ + val byteCodeRepository: ByteCodeRepository + + // Allows to define per-run caches here and in the CallGraph component, which don't have a global + def recordPerRunCache[T <: collection.generic.Clearable](cache: T): T + /** * A map from internal names to ClassBTypes. Every ClassBType is added to this map on its * construction. @@ -29,30 +48,83 @@ abstract class BTypes { * Concurrent because stack map frames are computed when in the class writer, which might run * on multiple classes concurrently. */ - protected val classBTypeFromInternalNameMap: collection.concurrent.Map[String, ClassBType] + val classBTypeFromInternalName: collection.concurrent.Map[InternalName, ClassBType] = recordPerRunCache(collection.concurrent.TrieMap.empty[InternalName, ClassBType]) /** - * The string represented by the `offset` / `length` values of a ClassBType, see comment of that - * class. + * Parse the classfile for `internalName` and construct the [[ClassBType]]. */ - protected def internalNameString(offset: Int, lenght: Int): String + def classBTypeFromParsedClassfile(internalName: InternalName): ClassBType = { + classBTypeFromClassNode(byteCodeRepository.classNode(internalName)) + } /** - * Obtain a previously constructed ClassBType for a given internal name. + * Construct the [[ClassBType]] for a parsed classfile. */ - def classBTypeFromInternalName(internalName: String) = classBTypeFromInternalNameMap(internalName) + def classBTypeFromClassNode(classNode: ClassNode): ClassBType = { + classBTypeFromInternalName.getOrElse(classNode.name, { + setClassInfo(classNode, ClassBType(classNode.name)) + }) + } - // Some core BTypes are required here, in class BType, where no Global instance is available. - // The Global is only available in the subclass BTypesFromSymbols. We cannot depend on the actual - // implementation (CoreBTypesProxy) here because it has members that refer to global.Symbol. - val coreBTypes: CoreBTypesProxyGlobalIndependent[this.type] - import coreBTypes._ + private def setClassInfo(classNode: ClassNode, classBType: ClassBType): ClassBType = { + val superClass = classNode.superName match { + case null => + assert(classNode.name == ObjectReference.internalName, s"class with missing super type: ${classNode.name}") + None + case superName => + Some(classBTypeFromParsedClassfile(superName)) + } + + val interfaces: List[ClassBType] = classNode.interfaces.asScala.map(classBTypeFromParsedClassfile)(collection.breakOut) + + val flags = classNode.access + + /** + * Find all nested classes of classNode. The innerClasses attribute contains all nested classes + * that are declared inside classNode or used in the bytecode of classNode. So some of them are + * nested in some other class than classNode, and we need to filter them. + * + * For member classes, innerClassNode.outerName is defined, so we compare that to classNode.name. + * + * For local and anonymous classes, innerClassNode.outerName is null. Such classes are required + * to have an EnclosingMethod attribute declaring the outer class. So we keep those local and + * anonymous classes whose outerClass is classNode.name. + * + */ + def nestedInCurrentClass(innerClassNode: InnerClassNode): Boolean = { + (innerClassNode.outerName != null && innerClassNode.outerName == classNode.name) || + (innerClassNode.outerName == null && byteCodeRepository.classNode(innerClassNode.name).outerClass == classNode.name) + } + + val nestedClasses: List[ClassBType] = classNode.innerClasses.asScala.collect({ + case i if nestedInCurrentClass(i) => classBTypeFromParsedClassfile(i.name) + })(collection.breakOut) + + // if classNode is a nested class, it has an innerClass attribute for itself. in this + // case we build the NestedInfo. + val nestedInfo = classNode.innerClasses.asScala.find(_.name == classNode.name) map { + case innerEntry => + val enclosingClass = + if (innerEntry.outerName != null) { + // if classNode is a member class, the outerName is non-null + classBTypeFromParsedClassfile(innerEntry.outerName) + } else { + // for anonymous or local classes, the outerName is null, but the enclosing class is + // stored in the EnclosingMethod attribute (which ASM encodes in classNode.outerClass). + classBTypeFromParsedClassfile(classNode.outerClass) + } + val staticFlag = (innerEntry.access & Opcodes.ACC_STATIC) != 0 + NestedInfo(enclosingClass, Option(innerEntry.outerName), Option(innerEntry.innerName), staticFlag) + } + classBType.info = ClassInfo(superClass, interfaces, flags, nestedClasses, nestedInfo) + classBType + } /** - * A BType is either a primitve type, a ClassBType, an ArrayBType of one of these, or a MethodType + * A BType is either a primitive type, a ClassBType, an ArrayBType of one of these, or a MethodType * referring to BTypes. */ - /*sealed*/ trait BType { // Not sealed for now due to SI-8546 + sealed trait BType { final override def toString: String = this match { case UNIT => "V" case BOOL => "Z" @@ -171,6 +243,9 @@ abstract class BTypes { assert(other.isRef, s"Cannot compute maxType: $this, $other") // Approximate `lub`. The common type of two references is always ObjectReference. ObjectReference + + case _: MethodBType => + throw new AssertionError(s"unexpected method type when computing maxType: $this") } /** @@ -369,7 +444,7 @@ abstract class BTypes { * * - Initializer block (JLS 8.6 / 8.7): block of statements in a java class * - static initializer: executed before constructor body - * - instance initializer: exectued when class is initialized (instance creation, static + * - instance initializer: executed when class is initialized (instance creation, static * field access, ...) * * - A static nested class can be defined as @@ -540,7 +615,7 @@ abstract class BTypes { * * class A { * void f() { class B {} } - * static void g() { calss C {} } + * static void g() { class C {} } * } * * B has an outer pointer, C doesn't. Both B and C are NOT marked static in the InnerClass table. @@ -568,28 +643,14 @@ abstract class BTypes { /** * A ClassBType represents a class or interface type. The necessary information to build a * ClassBType is extracted from compiler symbols and types, see BTypesFromSymbols. - * - * The `offset` and `length` fields are used to represent the internal name of the class. They - * are indices into some character array. The internal name can be obtained through the method - * `internalNameString`, which is abstract in this component. Name creation is assumed to be - * hash-consed, so if two ClassBTypes have the same internal name, they NEED to have the same - * `offset` and `length`. - * - * The actual implementation in subclass BTypesFromSymbols uses the global `chrs` array from the - * name table. This representation is efficient because the JVM class name is obtained through - * `classSymbol.javaBinaryName`. This already adds the necessary string to the `chrs` array, - * so it makes sense to reuse the same name table in the backend. - * - * ClassBType is not a case class because we want a custom equals method, and because the - * extractor extracts the internalName, which is what you typically need. */ - final class ClassBType(val offset: Int, val length: Int) extends RefBType { + final case class ClassBType(internalName: InternalName) extends RefBType { /** * Write-once variable allows initializing a cyclic graph of infos. This is required for * nested classes. Example: for the definition `class A { class B }` we have * * B.info.nestedInfo.outerClass == A - * A.info.memberClasses contains B + * A.info.nestedClasses contains B */ private var _info: ClassInfo = null @@ -604,7 +665,7 @@ abstract class BTypes { checkInfoConsistency() } - classBTypeFromInternalNameMap(internalName) = this + classBTypeFromInternalName(internalName) = this private def checkInfoConsistency(): Unit = { // we assert some properties. however, some of the linked ClassBType (members, superClass, @@ -612,7 +673,7 @@ abstract class BTypes { // best-effort verification. def ifInit(c: ClassBType)(p: ClassBType => Boolean): Boolean = c._info == null || p(c) - def isJLO(t: ClassBType) = t.internalName == "java/lang/Object" + def isJLO(t: ClassBType) = t.internalName == ObjectReference.internalName assert(!ClassBType.isInternalPhantomType(internalName), s"Cannot create ClassBType for phantom type $this") @@ -627,16 +688,10 @@ abstract class BTypes { s"Invalid interfaces in $this: ${info.interfaces}" ) - assert(info.memberClasses.forall(c => ifInit(c)(_.isNestedClass)), info.memberClasses) + assert(info.nestedClasses.forall(c => ifInit(c)(_.isNestedClass)), info.nestedClasses) } /** - * The internal name of a class is the string returned by java.lang.Class.getName, with all '.' - * replaced by '/'. For example "java/lang/String". - */ - def internalName: String = internalNameString(offset, length) - - /** * @return The class name without the package prefix */ def simpleName: String = internalName.split("/").last @@ -661,8 +716,9 @@ abstract class BTypes { outerName.orNull, innerName.orNull, GenBCode.mkFlags( - info.flags, - if (isStaticNestedClass) asm.Opcodes.ACC_STATIC else 0 + // the static flag in the InnerClass table has a special meaning, see InnerClass comment + info.flags & ~Opcodes.ACC_STATIC, + if (isStaticNestedClass) Opcodes.ACC_STATIC else 0 ) & ClassBType.INNER_CLASSES_FLAGS ) } @@ -736,33 +792,10 @@ abstract class BTypes { } while (fcs == null) fcs } - - /** - * Custom equals / hashCode: we only compare the name (offset / length) - */ - override def equals(o: Any): Boolean = (this eq o.asInstanceOf[Object]) || (o match { - case c: ClassBType => c.offset == this.offset && c.length == this.length - case _ => false - }) - - override def hashCode: Int = { - import scala.runtime.Statics - var acc: Int = -889275714 - acc = Statics.mix(acc, offset) - acc = Statics.mix(acc, length) - Statics.finalizeHash(acc, 2) - } } object ClassBType { /** - * Pattern matching on a ClassBType extracts the `internalName` of the class. - */ - def unapply(c: ClassBType): Option[String] = - if (c == null) None - else Some(c.internalName) - - /** * Valid flags for InnerClass attribute entry. * See http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.6 */ @@ -801,12 +834,12 @@ abstract class BTypes { * through the superclass. * @param flags The java flags, obtained through `javaFlags`. Used also to derive * the flags for InnerClass entries. - * @param memberClasses Classes nested in this class. Those need to be added to the + * @param nestedClasses Classes nested in this class. Those need to be added to the * InnerClass table, see the InnerClass spec summary above. * @param nestedInfo If this describes a nested class, information for the InnerClass table. */ - case class ClassInfo(superClass: Option[ClassBType], interfaces: List[ClassBType], flags: Int, - memberClasses: List[ClassBType], nestedInfo: Option[NestedInfo]) + final case class ClassInfo(superClass: Option[ClassBType], interfaces: List[ClassBType], flags: Int, + nestedClasses: List[ClassBType], nestedInfo: Option[NestedInfo]) /** * Information required to add a class to an InnerClass table. @@ -820,13 +853,13 @@ abstract class BTypes { * * (*) Note that the STATIC flag in ClassInfo.flags, obtained through javaFlags(classSym), is not * correct for the InnerClass entry, see javaFlags. The static flag in the InnerClass describes - * a source-level propety: if the class is in a static context (does not have an outer pointer). + * a source-level property: if the class is in a static context (does not have an outer pointer). * This is checked when building the NestedInfo. */ - case class NestedInfo(enclosingClass: ClassBType, - outerName: Option[String], - innerName: Option[String], - isStaticNestedClass: Boolean) + final case class NestedInfo(enclosingClass: ClassBType, + outerName: Option[String], + innerName: Option[String], + isStaticNestedClass: Boolean) /** * This class holds the data for an entry in the InnerClass table. See the InnerClass summary @@ -839,9 +872,9 @@ abstract class BTypes { * @param innerName The simple name of the inner class, may be null. * @param flags The flags for this class in the InnerClass entry. */ - case class InnerClassEntry(name: String, outerName: String, innerName: String, flags: Int) + final case class InnerClassEntry(name: String, outerName: String, innerName: String, flags: Int) - case class ArrayBType(componentType: BType) extends RefBType { + final case class ArrayBType(componentType: BType) extends RefBType { def dimension: Int = componentType match { case a: ArrayBType => 1 + a.dimension case _ => 1 @@ -853,7 +886,7 @@ abstract class BTypes { } } - case class MethodBType(argumentTypes: List[BType], returnType: BType) extends BType + final case class MethodBType(argumentTypes: List[BType], returnType: BType) extends BType /* Some definitions that are required for the implementation of BTypes. They are abstract because * initializing them requires information from types / symbols, which is not accessible here in @@ -873,3 +906,12 @@ abstract class BTypes { */ def isCompilingPrimitive: Boolean } + +object BTypes { + /** + * A marker for strings that represent class internal names. + * Ideally the type would be incompatible with String, for example by making it a value class. + * But that would create overhead in a Collection[InternalName]. + */ + type InternalName = String +}
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala index 3b7cbd6392..94f9b585d9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala @@ -7,10 +7,14 @@ package scala.tools.nsc package backend.jvm import scala.tools.asm +import opt.ByteCodeRepository +import scala.tools.asm.tree.ClassNode +import scala.tools.nsc.backend.jvm.opt.ByteCodeRepository.Source +import BTypes.InternalName /** * This class mainly contains the method classBTypeFromSymbol, which extracts the necessary - * information from a symbol and its type to create the correpsonding ClassBType. It requires + * information from a symbol and its type to create the corresponding ClassBType. It requires * access to the compiler (global parameter). * * The mixin CoreBTypes defines core BTypes that are used in the backend. Building these BTypes @@ -32,20 +36,13 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { val coreBTypes = new CoreBTypesProxy[this.type](this) import coreBTypes._ - final def intializeCoreBTypes(): Unit = { - coreBTypes.setBTypes(new CoreBTypes[this.type](this)) - } + val byteCodeRepository = new ByteCodeRepository(global.classPath, recordPerRunCache(collection.concurrent.TrieMap.empty[InternalName, (ClassNode, Source)])) - def internalNameString(offset: Int, length: Int) = new String(global.chrs, offset, length) - - protected val classBTypeFromInternalNameMap = { - global.perRunCaches.recordCache(collection.concurrent.TrieMap.empty[String, ClassBType]) + final def initializeCoreBTypes(): Unit = { + coreBTypes.setBTypes(new CoreBTypes[this.type](this)) } - /** - * Cache for the method classBTypeFromSymbol. - */ - private val convertedClasses = perRunCaches.newMap[Symbol, ClassBType]() + def recordPerRunCache[T <: collection.generic.Clearable](cache: T): T = perRunCaches.recordCache(cache) // helpers that need access to global. // TODO @lry create a separate component, they don't belong to BTypesFromSymbols @@ -89,13 +86,11 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { (classSym != NothingClass && classSym != NullClass), s"Cannot create ClassBType for special class symbol ${classSym.fullName}") - convertedClasses.getOrElse(classSym, { - val internalName = classSym.javaBinaryName.toTypeName - // We first create and add the ClassBType to the hash map before computing its info. This - // allows initializing cylic dependencies, see the comment on variable ClassBType._info. - val classBType = new ClassBType(internalName.start, internalName.length) - convertedClasses(classSym) = classBType - setClassInfo(classSym, classBType) + val internalName = classSym.javaBinaryName.toString + classBTypeFromInternalName.getOrElse(internalName, { + // The new ClassBType is added to the map in its constructor, before we set its info. This + // allows initializing cyclic dependencies, see the comment on variable ClassBType._info. + setClassInfo(classSym, ClassBType(internalName)) }) } @@ -114,7 +109,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { val superClass = if (superClassSym == NoSymbol) None else Some(classBTypeFromSymbol(superClassSym)) - val interfaces = getSuperInterfaces(classSym).map(classBTypeFromSymbol) + val interfaces = implementedInterfaces(classSym).map(classBTypeFromSymbol) val flags = javaFlags(classSym) @@ -126,25 +121,35 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { * code generation, but those duplicates will be eliminated when emitting the InnerClass * attribute. * - * Why doe we need to collect classes into innerClassBufferASM at all? To collect references to + * Why do we need to collect classes into innerClassBufferASM at all? To collect references to * nested classes, but NOT nested in C, that are used within C. */ val nestedClassSymbols = { // The lambdalift phase lifts all nested classes to the enclosing class, so if we collect // member classes right after lambdalift, we obtain all nested classes, including local and // anonymous ones. - val nestedClasses = exitingPhase(currentRun.lambdaliftPhase)(memberClassesOf(classSym)) + val nestedClasses = { + val nested = exitingPhase(currentRun.lambdaliftPhase)(memberClassesOf(classSym)) + if (isTopLevelModuleClass(classSym)) { + // For Java compatibility, member classes of top-level objects are treated as members of + // the top-level companion class, see comment below. + val members = exitingPickler(memberClassesOf(classSym)) + nested diff members + } else { + nested + } + } - // If this is a top-level class, and it has a companion object, the member classes of the - // companion are added as members of the class. For example: + // If this is a top-level class, the member classes of the companion object are added as + // members of the class. For example: // class C { } // object C { // class D // def f = { class E } // } - // The class D is added as a member of class C. The reason is that the InnerClass attribute - // for D will containt class "C" and NOT the module class "C$" as the outer class of D. - // This is done by buildNestedInfo, the reason is Java compatibility, see comment in BTypes. + // The class D is added as a member of class C. The reason is: for Java compatibility, the + // InnerClass attribute for D has "C" (NOT the module class "C$") as the outer class of D + // (done by buildNestedInfo). See comment in BTypes. // For consistency, the InnerClass entry for D needs to be present in C - to Java it looks // like D is a member of C, not C$. val linkedClass = exitingPickler(classSym.linkedClassOfClass) // linkedCoC does not work properly in late phases @@ -174,75 +179,51 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { } else true }) - val memberClasses = nestedClassSymbolsNoJavaModuleClasses.map(classBTypeFromSymbol) + val nestedClasses = nestedClassSymbolsNoJavaModuleClasses.map(classBTypeFromSymbol) val nestedInfo = buildNestedInfo(classSym) - classBType.info = ClassInfo(superClass, interfaces, flags, memberClasses, nestedInfo) + classBType.info = ClassInfo(superClass, interfaces, flags, nestedClasses, nestedInfo) classBType } - /** - * All interfaces implemented by a class, except for those inherited through the superclass. - * - * TODO @lry share code with GenASM - */ - private def getSuperInterfaces(classSym: Symbol): List[Symbol] = { - - // Additional interface parents based on annotations and other cues - def newParentForAnnotation(ann: AnnotationInfo): Symbol = ann.symbol match { - case RemoteAttr => RemoteInterfaceClass - case _ => NoSymbol - } - - val superInterfaces0: List[Symbol] = classSym.mixinClasses - val superInterfaces = existingSymbols(superInterfaces0 ++ classSym.annotations.map(newParentForAnnotation)).distinct - - assert(!superInterfaces.contains(NoSymbol), s"found NoSymbol among: ${superInterfaces.mkString(", ")}") - assert(superInterfaces.forall(s => s.isInterface || s.isTrait), s"found non-interface among: ${superInterfaces.mkString(", ")}") - - erasure.minimizeInterfaces(superInterfaces.map(_.info)).map(_.typeSymbol) - } - private def buildNestedInfo(innerClassSym: Symbol): Option[NestedInfo] = { assert(innerClassSym.isClass, s"Cannot build NestedInfo for non-class symbol $innerClassSym") - val isNested = !innerClassSym.rawowner.isPackageClass - if (!isNested) None + val isTopLevel = innerClassSym.rawowner.isPackageClass + if (isTopLevel) None else { // See comment in BTypes, when is a class marked static in the InnerClass table. val isStaticNestedClass = isOriginallyStaticOwner(innerClassSym.originalOwner) // After lambdalift (which is where we are), the rawowoner field contains the enclosing class. - val enclosingClassSym = { - if (innerClassSym.isJavaDefined && innerClassSym.rawowner.isModuleClass) { - // Example java source: class C { static class D { } } - // The Scala compiler creates a class and a module symbol for C. Because D is a static - // nested class, the symbol for D is nested in the module class C (not in the class C). - // For the InnerClass attribute, we use the class symbol C, which represents the situation - // in the source code. - - // Cannot use innerClassSym.isStatic: this method looks at the owner, which is a package - // at this pahse (after lambdalift, flatten). - assert(isOriginallyStaticOwner(innerClassSym.originalOwner), innerClassSym.originalOwner) - + val enclosingClass = { + // (1) Example java source: class C { static class D { } } + // The Scala compiler creates a class and a module symbol for C. Because D is a static + // nested class, the symbol for D is nested in the module class C (not in the class C). + // For the InnerClass attribute, we use the class symbol C, which represents the situation + // in the source code. + + // (2) Java compatibility. See the big comment in BTypes that summarizes the InnerClass spec. + if ((innerClassSym.isJavaDefined && innerClassSym.rawowner.isModuleClass) || // (1) + (!isAnonymousOrLocalClass(innerClassSym) && isTopLevelModuleClass(innerClassSym.rawowner))) { // (2) // phase travel for linkedCoC - does not always work in late phases - exitingPickler(innerClassSym.rawowner.linkedClassOfClass) + exitingPickler(innerClassSym.rawowner.linkedClassOfClass) match { + case NoSymbol => + // For top-level modules without a companion class, see doc of mirrorClassClassBType. + mirrorClassClassBType(exitingPickler(innerClassSym.rawowner)) + + case companionClass => + classBTypeFromSymbol(companionClass) + } + } else { + classBTypeFromSymbol(innerClassSym.rawowner) } - else innerClassSym.rawowner } - val enclosingClass: ClassBType = classBTypeFromSymbol(enclosingClassSym) val outerName: Option[String] = { - if (isAnonymousOrLocalClass(innerClassSym)) { - None - } else { - val outerName = innerClassSym.rawowner.javaBinaryName - // Java compatibility. See the big comment in BTypes that summarizes the InnerClass spec. - val outerNameModule = if (isTopLevelModuleClass(innerClassSym.rawowner)) outerName.dropModule - else outerName - Some(outerNameModule.toString) - } + if (isAnonymousOrLocalClass(innerClassSym)) None + else Some(enclosingClass.internalName) } val innerName: Option[String] = { @@ -255,6 +236,29 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { } /** + * For top-level objects without a companion class, the compilere generates a mirror class with + * static forwarders (Java compat). There's no symbol for the mirror class, but we still need a + * ClassBType (its info.nestedClasses will hold the InnerClass entries, see comment in BTypes). + */ + def mirrorClassClassBType(moduleClassSym: Symbol): ClassBType = { + assert(isTopLevelModuleClass(moduleClassSym), s"not a top-level module class: $moduleClassSym") + val internalName = moduleClassSym.javaBinaryName.dropModule.toString + classBTypeFromInternalName.getOrElse(internalName, { + val c = ClassBType(internalName) + // class info consistent with BCodeHelpers.genMirrorClass + val nested = exitingPickler(memberClassesOf(moduleClassSym)) map classBTypeFromSymbol + c.info = ClassInfo( + superClass = Some(ObjectReference), + interfaces = Nil, + flags = asm.Opcodes.ACC_SUPER | asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_FINAL, + nestedClasses = nested, + nestedInfo = None + ) + c + }) + } + + /** * True for module classes of package level objects. The backend will generate a mirror class for * such objects. */ diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala index fac3c93be2..246235f395 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala @@ -4,7 +4,7 @@ package backend.jvm import scala.annotation.switch /** - * Core BTypes and some other definitions. The initialization of these definitions requies access + * Core BTypes and some other definitions. The initialization of these definitions requires access * to symbols / types (global). * * The symbols used to initialize the ClassBTypes may change from one compiler run to the next. To @@ -18,11 +18,11 @@ import scala.annotation.switch * * The definitions in `CoreBTypes` need to be lazy vals to break an initialization cycle. When * creating a new instance to assign to the proxy, the `classBTypeFromSymbol` invoked in the - * constructor will actucally go through the proxy. The lazy vals make sure the instance is assigned + * constructor will actually go through the proxy. The lazy vals make sure the instance is assigned * in the proxy before the fields are initialized. * * Note: if we did not re-create the core BTypes on each compiler run, BType.classBTypeFromInternalNameMap - * could not be a perRunCache anymore: the classes defeined here need to be in that map, they are + * could not be a perRunCache anymore: the classes defined here need to be in that map, they are * added when the ClassBTypes are created. The per run cache removes them, so they would be missing * in the second run. */ @@ -192,7 +192,7 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) { } /** - * This trait make some core BTypes availalbe that don't depend on a Global instance. Some core + * This trait make some core BTypes available that don't depend on a Global instance. Some core * BTypes are required to be accessible in the BTypes trait, which does not have access to Global. * * BTypes cannot refer to CoreBTypesProxy because some of its members depend on global, for example diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index e56a20c2e7..abe3bc512c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -677,7 +677,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => def isDeprecated(sym: Symbol): Boolean = { sym.annotations exists (_ matches definitions.DeprecatedAttr) } - def addInnerClasses(csym: Symbol, jclass: asm.ClassVisitor) { + def addInnerClasses(csym: Symbol, jclass: asm.ClassVisitor, isMirror: Boolean = false) { /* The outer name for this inner class. Note that it returns null * when the inner class should not get an index in the constant pool. * That means non-member classes (anonymous). See Section 4.7.5 in the JVMS. @@ -698,11 +698,19 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => else innerSym.rawname + innerSym.moduleSuffix - // This collects all inner classes of csym, including local and anonymous: lambdalift makes - // them members of their enclosing class. - innerClassBuffer ++= exitingPhase(currentRun.lambdaliftPhase)(memberClassesOf(csym)) + innerClassBuffer ++= { + val members = exitingPickler(memberClassesOf(csym)) + // lambdalift makes all classes (also local, anonymous) members of their enclosing class + val allNested = exitingPhase(currentRun.lambdaliftPhase)(memberClassesOf(csym)) - // Add members of the companion object (if top-level). why, see comment in BTypes.scala. + // for the mirror class, we take the members of the companion module class (Java compat, + // see doc in BTypes.scala). for module classes, we filter out those members. + if (isMirror) members + else if (isTopLevelModule(csym)) allNested diff members + else allNested + } + + // If this is a top-level class, add members of the companion object. val linkedClass = exitingPickler(csym.linkedClassOfClass) // linkedCoC does not work properly in late phases if (isTopLevelModule(linkedClass)) { // phase travel to exitingPickler: this makes sure that memberClassesOf only sees member classes, @@ -1206,22 +1214,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => def serialVUID: Option[Long] = genBCode.serialVUID(clasz.symbol) - private def getSuperInterfaces(c: IClass): Array[String] = { - - // Additional interface parents based on annotations and other cues - def newParentForAttr(ann: AnnotationInfo): Symbol = ann.symbol match { - case RemoteAttr => RemoteInterfaceClass - case _ => NoSymbol - } - - val ps = c.symbol.info.parents - val superInterfaces0: List[Symbol] = if(ps.isEmpty) Nil else c.symbol.mixinClasses - val superInterfaces = existingSymbols(superInterfaces0 ++ c.symbol.annotations.map(newParentForAttr)).distinct - - if(superInterfaces.isEmpty) EMPTY_STRING_ARRAY - else mkArray(erasure.minimizeInterfaces(superInterfaces.map(_.info)).map(t => javaName(t.typeSymbol))) - } - var clasz: IClass = _ // this var must be assigned only by genClass() var jclass: asm.ClassWriter = _ // the classfile being emitted var thisName: String = _ // the internal name of jclass @@ -1242,7 +1234,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => val ps = c.symbol.info.parents val superClass: String = if(ps.isEmpty) JAVA_LANG_OBJECT.getInternalName else javaName(ps.head.typeSymbol) - val ifaces = getSuperInterfaces(c) + val ifaces: Array[String] = implementedInterfaces(c.symbol).map(javaName)(collection.breakOut) val thisSignature = getGenericSignature(c.symbol, c.symbol.owner) val flags = mkFlags( @@ -2812,7 +2804,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => addForwarders(isRemote(modsym), mirrorClass, mirrorName, modsym) - addInnerClasses(modsym, mirrorClass) + addInnerClasses(modsym, mirrorClass, isMirror = true) mirrorClass.visitEnd() writeIfNotTooBig("" + modsym.name, mirrorName, mirrorClass, modsym) } @@ -2947,7 +2939,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => } // end of class JBeanInfoBuilder /** A namespace for utilities to normalize the code of an IMethod, over and beyond what IMethod.normalize() strives for. - * In particualr, IMethod.normalize() doesn't collapseJumpChains(). + * In particular, IMethod.normalize() doesn't collapseJumpChains(). * * TODO Eventually, these utilities should be moved to IMethod and reused from normalize() (there's nothing JVM-specific about them). */ @@ -3162,7 +3154,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => } } - // remove the unusued exception handler references + // remove the unused exception handler references if (settings.debug) for (exh <- unusedExceptionHandlers) debuglog(s"eliding exception handler $exh because it does not cover any reachable blocks") m.exh = m.exh filterNot unusedExceptionHandlers diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala index a45f586666..d5e95c47cf 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala @@ -286,7 +286,7 @@ abstract class GenBCode extends BCodeSyncAndTry { val initStart = Statistics.startTimer(BackendStats.bcodeInitTimer) arrivalPos = 0 // just in case scalaPrimitives.init() - bTypes.intializeCoreBTypes() + bTypes.initializeCoreBTypes() Statistics.stopTimer(BackendStats.bcodeInitTimer, initStart) // initBytecodeWriter invokes fullName, thus we have to run it before the typer-dependent thread is activated. diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala new file mode 100644 index 0000000000..7b424d2107 --- /dev/null +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala @@ -0,0 +1,112 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2014 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.tools.nsc +package backend.jvm +package opt + +import scala.tools.asm +import asm.tree._ +import scala.collection.convert.decorateAsScala._ +import scala.tools.nsc.io.AbstractFile +import scala.tools.nsc.util.ClassFileLookup +import OptimizerReporting._ +import ByteCodeRepository._ +import BTypes.InternalName + +/** + * The ByteCodeRepository provides utilities to read the bytecode of classfiles from the compilation + * classpath. Parsed classes are cached in the `classes` map. + * + * @param classPath The compiler classpath where classfiles are searched and read from. + * @param classes Cache for parsed ClassNodes. Also stores the source of the bytecode: + * [[Classfile]] if read from `classPath`, [[CompilationUnit]] if the bytecode + * corresponds to a class being compiled. + */ +class ByteCodeRepository(val classPath: ClassFileLookup[AbstractFile], val classes: collection.concurrent.Map[InternalName, (ClassNode, Source)]) { + /** + * The class node and source for an internal name. If the class node is not yet available, it is + * parsed from the classfile on the compile classpath. + */ + def classNodeAndSource(internalName: InternalName): (ClassNode, Source) = { + classes.getOrElseUpdate(internalName, (parseClass(internalName), Classfile)) + } + + /** + * The class node for an internal name. If the class node is not yet available, it is parsed from + * the classfile on the compile classpath. + */ + def classNode(internalName: InternalName) = classNodeAndSource(internalName)._1 + + /** + * The field node for a field matching `name` and `descriptor`, accessed in class `classInternalName`. + * The declaration of the field may be in one of the superclasses. + * + * @return The [[FieldNode]] of the requested field and the [[InternalName]] of its declaring class. + */ + def fieldNode(classInternalName: InternalName, name: String, descriptor: String): Option[(FieldNode, InternalName)] = { + val c = classNode(classInternalName) + c.fields.asScala.find(f => f.name == name && f.desc == descriptor).map((_, classInternalName)) orElse { + Option(c.superName).flatMap(n => fieldNode(n, name, descriptor)) + } + } + + /** + * The method node for a method matching `name` and `descriptor`, accessed in class `classInternalName`. + * The declaration of the method may be in one of the parents. + * + * @return The [[MethodNode]] of the requested method and the [[InternalName]] of its declaring class. + */ + def methodNode(classInternalName: InternalName, name: String, descriptor: String): Option[(MethodNode, InternalName)] = { + val c = classNode(classInternalName) + c.methods.asScala.find(m => m.name == name && m.desc == descriptor).map((_, classInternalName)) orElse { + val parents = Option(c.superName) ++ c.interfaces.asScala + // `view` to stop at the first result + parents.view.flatMap(methodNode(_, name, descriptor)).headOption + } + } + + private def parseClass(internalName: InternalName): ClassNode = { + val fullName = internalName.replace('/', '.') + classPath.findClassFile(fullName) map { classFile => + val classNode = new asm.tree.ClassNode() + val classReader = new asm.ClassReader(classFile.toByteArray) + // We don't need frames when inlining, but we want to keep the local variable table, so we + // don't use SKIP_DEBUG. + classReader.accept(classNode, asm.ClassReader.SKIP_FRAMES) + // SKIP_FRAMES leaves line number nodes. Remove them because they are not correct after + // inlining. + // TODO: we need to remove them also for classes that are not parsed from classfiles, why not simplify and do it once when inlining? + // OR: instead of skipping line numbers for inlined code, use write a SourceDebugExtension + // attribute that contains JSR-45 data that encodes debugging info. + // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.11 + // https://jcp.org/aboutJava/communityprocess/final/jsr045/index.html + removeLineNumberNodes(classNode) + classNode + } getOrElse { + inlineFailure(s"Class file for class $fullName not found.") + } + } + + private def removeLineNumberNodes(classNode: ClassNode): Unit = { + for (method <- classNode.methods.asScala) { + val iter = method.instructions.iterator() + while (iter.hasNext) iter.next() match { + case _: LineNumberNode => iter.remove() + case _ => + } + } + } +} + +object ByteCodeRepository { + /** + * The source of a ClassNode in the ByteCodeRepository. Can be either [[CompilationUnit]] if the + * class is being compiled or [[Classfile]] if the class was parsed from the compilation classpath. + */ + sealed trait Source + object CompilationUnit extends Source + object Classfile extends Source +} diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala index 273112b93c..87ad715e4d 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala @@ -19,16 +19,16 @@ import scala.tools.nsc.settings.ScalaSettings * Optimizations within a single method. * * unreachable code - * - removes instrucions of basic blocks to which no branch instruction points + * - removes instructions of basic blocks to which no branch instruction points * + enables eliminating some exception handlers and local variable descriptors * > eliminating them is required for correctness, as explained in `removeUnreachableCode` * * empty exception handlers * - removes exception handlers whose try block is empty * + eliminating a handler where the try block is empty and reachable will turn the catch block - * unreachble. in this case "unreachable code" is invoked recursively until reaching a fixpiont. + * unreachable. in this case "unreachable code" is invoked recursively until reaching a fixpoint. * > for try blocks that are unreachable, "unreachable code" removes also the instructions of the - * catch block, and the recrusive invocation is not necessary. + * catch block, and the recursive invocation is not necessary. * * simplify jumps * - various simplifications, see doc domments of individual optimizations @@ -52,10 +52,10 @@ class LocalOpt(settings: ScalaSettings) { * cleanups to the bytecode. * * @param clazz The class whose methods are optimized - * @return `true` if unreachable code was elminated in some method, `false` otherwise. + * @return `true` if unreachable code was eliminated in some method, `false` otherwise. */ def methodOptimizations(clazz: ClassNode): Boolean = { - settings.Yopt.value.nonEmpty && clazz.methods.asScala.foldLeft(false) { + !settings.YoptNone && clazz.methods.asScala.foldLeft(false) { case (changed, method) => methodOptimizations(method, clazz.name) || changed } } @@ -66,7 +66,7 @@ class LocalOpt(settings: ScalaSettings) { * We rely on dead code elimination provided by the ASM framework, as described in the ASM User * Guide (http://asm.ow2.org/index.html), Section 8.2.1. It runs a data flow analysis, which only * computes Frame information for reachable instructions. Instructions for which no Frame data is - * available after the analyis are unreachable. + * available after the analysis are unreachable. * * Also simplifies branching instructions, removes unused local variable descriptors, empty * exception handlers, unnecessary label declarations and empty line number nodes. @@ -240,7 +240,7 @@ class LocalOpt(settings: ScalaSettings) { } /** - * The number of local varialbe slots used for parameters and for the `this` reference. + * The number of local variable slots used for parameters and for the `this` reference. */ private def parametersSize(method: MethodNode): Int = { // Double / long fields occupy two slots, so we sum up the sizes. Since getSize returns 0 for @@ -322,7 +322,7 @@ class LocalOpt(settings: ScalaSettings) { * In order to run an Analyzer, the maxLocals / maxStack fields need to be available. The ASM * framework only computes these values during bytecode generation. * - * Sicne there's currently no better way, we run a bytecode generator on the method and extract + * Since there's currently no better way, we run a bytecode generator on the method and extract * the computed values. This required changes to the ASM codebase: * - the [[MethodWriter]] class was made public * - accessors for maxLocals / maxStack were added to the MethodWriter class @@ -345,7 +345,7 @@ class LocalOpt(settings: ScalaSettings) { * Removes LineNumberNodes that don't describe any executable instructions. * * This method expects (and asserts) that the `start` label of each LineNumberNode is the - * lexically preceeding label declaration. + * lexically preceding label declaration. */ def removeEmptyLineNumbers(method: MethodNode): Boolean = { def isEmpty(node: AbstractInsnNode): Boolean = node.getNext match { @@ -510,7 +510,7 @@ class LocalOpt(settings: ScalaSettings) { * CondJump l; [nops, no labels]; GOTO m; [nops]; l: [...] * => NegatedCondJump m; [nops, no labels]; [nops]; l: [...] * - * Note that no label definitions are allowed in the first [nops] section. Otherwsie, there could + * Note that no label definitions are allowed in the first [nops] section. Otherwise, there could * be some other jump to the GOTO, and eliminating it would change behavior. * * For technical reasons, we cannot remove the GOTO here (*).Instead this method returns an Option @@ -542,7 +542,7 @@ class LocalOpt(settings: ScalaSettings) { * => xRETURN/ATHROW; [any ops]; l: xRETURN/ATHROW * * inlining is only done if the GOTO instruction is not part of a try block, otherwise the - * rewrite might change the behavior. For xRETURN, the reason is that return insructions may throw + * rewrite might change the behavior. For xRETURN, the reason is that return instructions may throw * an IllegalMonitorStateException, as described here: * http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.return */ diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/OptimizerReporting.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/OptimizerReporting.scala new file mode 100644 index 0000000000..7002e43d98 --- /dev/null +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/OptimizerReporting.scala @@ -0,0 +1,24 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2014 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.tools.nsc +package backend.jvm + +import scala.tools.asm +import asm.tree._ + +/** + * Reporting utilities used in the optimizer. + */ +object OptimizerReporting { + def methodSignature(className: String, methodName: String, methodDescriptor: String): String = { + className + "::" + methodName + methodDescriptor + } + + def methodSignature(className: String, method: MethodNode): String = methodSignature(className, method.name, method.desc) + + def inlineFailure(reason: String): Nothing = MissingRequirementError.signal(reason) + def assertionError(message: String): Nothing = throw new AssertionError(message) +} diff --git a/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala b/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala index c6e699373b..0e6ee76eb2 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala @@ -18,7 +18,7 @@ import scala.annotation.tailrec * * With some more work it could be extended to * - cache stable values (final fields, modules) in locals - * - replace the copy propagation in ClosureElilmination + * - replace the copy propagation in ClosureElimination * - fold constants * - eliminate unnecessary stores and loads * - propagate knowledge gathered from conditionals for further optimization @@ -437,7 +437,7 @@ abstract class ConstantOptimization extends SubComponent { // TODO if we do all that we need to be careful in the // case that success and failure are the same target block // because we're using a Map and don't want one possible state to clobber the other - // alternative mayb we should just replace the conditional with a jump if both targets are the same + // alternative maybe we should just replace the conditional with a jump if both targets are the same def mightEqual = val1 mightEqual val2 def mightNotEqual = val1 mightNotEqual val2 diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index 4b419b210c..3704acb055 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -223,7 +223,7 @@ abstract class DeadCodeElimination extends SubComponent { debuglog("Marking instr: \tBB_" + bb + ": " + idx + " " + bb(idx)) val instr = bb(idx) - // adds the instrutions that define the stack values about to be consumed to the work list to + // adds the instructions that define the stack values about to be consumed to the work list to // be marked useful def addDefs() = for ((bb1, idx1) <- rdef.findDefs(bb, idx, instr.consumed) if !useful(bb1)(idx1)) { debuglog(s"\t${bb1(idx1)} is consumed by $instr") diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index aa18b26d93..8f6fc65706 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -290,7 +290,7 @@ abstract class Inliners extends SubComponent { /** * A transformation local to the body of the IMethod received as argument. - * An linining decision consists in replacing a callsite with the body of the callee. + * An inlining decision consists in replacing a callsite with the body of the callee. * Please notice that, because `analyzeMethod()` itself may modify a method body, * the particular callee bodies that end up being inlined depend on the particular order in which methods are visited * (no topological sorting over the call-graph is attempted). diff --git a/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala b/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala index 26b5429e23..cb201617d2 100644 --- a/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala +++ b/src/compiler/scala/tools/nsc/classpath/FlatClassPath.scala @@ -23,8 +23,8 @@ trait FlatClassPath extends ClassFileLookup[AbstractFile] { /** Allows to get entries for packages and classes merged with sources possibly in one pass. */ private[nsc] def list(inPackage: String): FlatClassPathEntries - // A default implementation which should be overriden, if we can create more efficient - // solution for given type of FlatClassPath + // A default implementation which should be overridden, if we can create the more efficient + // solution for a given type of FlatClassPath override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = { val (pkg, simpleClassName) = PackageNameUtils.separatePkgAndClassNames(className) diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 18e639b81c..a5b722612d 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -168,7 +168,7 @@ trait ScalaSettings extends AbsScalaSettings val termConflict = ChoiceSetting ("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error") val inline = BooleanSetting ("-Yinline", "Perform inlining when possible.") val inlineHandlers = BooleanSetting ("-Yinline-handlers", "Perform exception handler inlining when possible.") - val YinlinerWarnings= BooleanSetting ("-Yinline-warnings", "Emit inlining warnings. (Normally surpressed due to high volume)") + val YinlinerWarnings= BooleanSetting ("-Yinline-warnings", "Emit inlining warnings. (Normally suppressed due to high volume)") val Xlinearizer = ChoiceSetting ("-Ylinearizer", "which", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo") val log = PhasesSetting ("-Ylog", "Log operations during") val Ylogcp = BooleanSetting ("-Ylog-classpath", "Output information about what classpath is being applied.") @@ -199,7 +199,7 @@ trait ScalaSettings extends AbsScalaSettings val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup") val Yreplclassbased = BooleanSetting ("-Yrepl-class-based", "Use classes to wrap REPL snippets instead of objects") val Yreploutdir = StringSetting ("-Yrepl-outdir", "path", "Write repl-generated classfiles to given output directory (use \"\" to generate a temporary dir)" , "") - val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.") + val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overridden methods.") val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.").withDeprecationMessage(removalIn212) val inferByName = BooleanSetting ("-Yinfer-by-name", "Allow inference of by-name types. This is a temporary option to ease transition. See SI-7899.").withDeprecationMessage(removalIn212) val YclasspathImpl = ChoiceSetting ("-YclasspathImpl", "implementation", "Choose classpath scanning method.", List(ClassPathRepresentationType.Recursive, ClassPathRepresentationType.Flat), ClassPathRepresentationType.Recursive) @@ -215,7 +215,7 @@ trait ScalaSettings extends AbsScalaSettings object YoptChoices extends MultiChoiceEnumeration { val unreachableCode = Choice("unreachable-code", "Eliminate unreachable code, exception handlers protecting no instructions, debug information of eliminated variables.") - val simplifyJumps = Choice("simplify-jumps", "Simplify branching instructions, eliminate unnecessery ones.") + val simplifyJumps = Choice("simplify-jumps", "Simplify branching instructions, eliminate unnecessary ones.") val recurseUnreachableJumps = Choice("recurse-unreachable-jumps", "Recursively apply unreachable-code and simplify-jumps (if enabled) until reaching a fixpoint.") val emptyLineNumbers = Choice("empty-line-numbers", "Eliminate unnecessary line number information.") val emptyLabels = Choice("empty-labels", "Eliminate and collapse redundant labels in the bytecode.") @@ -242,6 +242,7 @@ trait ScalaSettings extends AbsScalaSettings descr = "Enable optimizations", domain = YoptChoices) + def YoptNone = Yopt.isSetByUser && Yopt.value.isEmpty def YoptUnreachableCode = !Yopt.isSetByUser || Yopt.contains(YoptChoices.unreachableCode) def YoptSimplifyJumps = Yopt.contains(YoptChoices.simplifyJumps) def YoptRecurseUnreachableJumps = Yopt.contains(YoptChoices.recurseUnreachableJumps) diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index c400e8c29c..41ce0837cb 100644 --- a/src/compiler/scala/tools/nsc/settings/Warnings.scala +++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala @@ -28,10 +28,11 @@ trait Warnings { val warnUnusedImport = BooleanSetting("-Ywarn-unused-import", "Warn when imports are unused.") // Experimental lint warnings that are turned off, but which could be turned on programmatically. - // These warnings are said to blind those who dare enable them. - // They are not activated by -Xlint and can't be enabled on the command line. - val warnValueOverrides = { // currently turned off as experimental. creaded using constructor (new BS), so not available on the command line. - val flag = new BooleanSetting("value-overrides", "Generated value class method overrides an implementation") + // They are not activated by -Xlint and can't be enabled on the command line because they are not + // created using the standard factory methods. + + val warnValueOverrides = { + val flag = new BooleanSetting("value-overrides", "Generated value class method overrides an implementation.") flag.value = false flag } @@ -53,10 +54,11 @@ trait Warnings { val TypeParameterShadow = LintWarning("type-parameter-shadow", "A local type parameter shadows a type already in scope.") val PolyImplicitOverload = LintWarning("poly-implicit-overload", "Parameterized overloaded implicit methods are not visible as view bounds.") val OptionImplicit = LintWarning("option-implicit", "Option.apply used implicit view.") - val DelayedInitSelect = LintWarning("delayedinit-select", "Selecting member of DelayedInit") + val DelayedInitSelect = LintWarning("delayedinit-select", "Selecting member of DelayedInit.") val ByNameRightAssociative = LintWarning("by-name-right-associative", "By-name parameter of right associative operator.") val PackageObjectClasses = LintWarning("package-object-classes", "Class or object defined in package object.") val UnsoundMatch = LintWarning("unsound-match", "Pattern match may not be typesafe.") + val StarsAlign = LintWarning("stars-align", "Pattern sequence wildcard must align with sequence component.") def allLintWarnings = values.toSeq.asInstanceOf[Seq[LintWarning]] } @@ -77,6 +79,7 @@ trait Warnings { def warnByNameRightAssociative = lint contains ByNameRightAssociative def warnPackageObjectClasses = lint contains PackageObjectClasses def warnUnsoundMatch = lint contains UnsoundMatch + def warnStarsAlign = lint contains StarsAlign // Lint warnings that are currently -Y, but deprecated in that usage @deprecated("Use warnAdaptedArgs", since="2.11.2") diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 9af3efbece..8fd2ea45e4 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -170,7 +170,7 @@ abstract class SymbolLoaders { } /** Create a new loader from a binary classfile. - * This is intented as a hook allowing to support loading symbols from + * This is intended as a hook allowing to support loading symbols from * files other than .class files. */ protected def newClassLoader(bin: AbstractFile): SymbolLoader = diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 1abbdb50b0..4d08be3c24 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -587,7 +587,7 @@ abstract class ClassfileParser { info = MethodType(newParams, clazz.tpe) } - // 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 info propagatePackageBoundary(jflags, sym) @@ -768,7 +768,7 @@ abstract class ClassfileParser { classTParams = tparams val parents = new ListBuffer[Type]() while (index < end) { - parents += sig2type(tparams, skiptvs = false) // here the variance doesnt'matter + parents += sig2type(tparams, skiptvs = false) // here the variance doesn't matter } ClassInfoType(parents.toList, instanceScope, sym) } diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index f471440293..362cbde04f 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -535,7 +535,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { * whether `sym` denotes a param-accessor (ie a field) that fulfills all of: * (a) has stationary value, ie the same value provided via the corresponding ctor-arg; and * (b) isn't subject to specialization. We might be processing statements for: - * (b.1) the constructur in the generic (super-)class; or + * (b.1) the constructor in the generic (super-)class; or * (b.2) the constructor in the specialized (sub-)class. * (c) isn't part of a DelayedInit subclass. */ diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala index f7b1021ea2..d2c511a2d1 100644 --- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala +++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala @@ -9,7 +9,7 @@ import scala.reflect.internal.Symbols import scala.collection.mutable.LinkedHashMap /** - * This transformer is responisble for turning lambdas into anonymous classes. + * This transformer is responsible for turning lambdas into anonymous classes. * The main assumption it makes is that a lambda {args => body} has been turned into * {args => liftedBody()} where lifted body is a top level method that implements the body of the lambda. * Currently Uncurry is responsible for that transformation. @@ -17,7 +17,7 @@ import scala.collection.mutable.LinkedHashMap * From a lambda, Delambdafy will create * 1) a static forwarder at the top level of the class that contained the lambda * 2) a new top level class that - a) has fields and a constructor taking the captured environment (including possbily the "this" + a) has fields and a constructor taking the captured environment (including possibly the "this" * reference) * b) an apply method that calls the static forwarder * c) if needed a bridge method for the apply method @@ -99,7 +99,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre super.transform(newExpr) // when we encounter a template (basically the thing that holds body of a class/trait) - // we need to updated it to include newly created accesor methods after transforming it + // we need to updated it to include newly created accessor methods after transforming it case Template(_, _, _) => try { // during this call accessorMethods will be populated from the Function case @@ -249,7 +249,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre else "$" + funOwner.name + "$" ) val oldClassPart = oldClass.name.decode - // make sure the class name doesn't contain $anon, otherwsie isAnonymousClass/Function may be true + // make sure the class name doesn't contain $anon, otherwise isAnonymousClass/Function may be true val name = unit.freshTypeName(s"$oldClassPart$suffix".replace("$anon", "$nestedInAnon")) val lambdaClass = pkg newClassSymbol(name, originalFunction.pos, FINAL | SYNTHETIC) addAnnotation SerialVersionUIDAnnotation @@ -434,7 +434,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre } /** - * Get the symbol of the target lifted lambad body method from a function. I.e. if + * Get the symbol of the target lifted lambda body method from a function. I.e. if * the function is {args => anonfun(args)} then this method returns anonfun's symbol */ private def targetMethod(fun: Function): Symbol = fun match { diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index b6af19250e..5c72bb3258 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -185,22 +185,22 @@ abstract class Erasure extends AddInterfaces private def isErasedValueType(tpe: Type) = tpe.isInstanceOf[ErasedValueType] - /* Drop redundant interfaces (ones which are implemented by some other parent) from the immediate parents. + /* Drop redundant types (ones which are implemented by some other parent) from the immediate parents. * This is important on Android because there is otherwise an interface explosion. */ - def minimizeInterfaces(lstIfaces: List[Type]): List[Type] = { - var rest = lstIfaces - var leaves = List.empty[Type] - while(!rest.isEmpty) { + def minimizeParents(parents: List[Type]): List[Type] = { + var rest = parents + var leaves = collection.mutable.ListBuffer.empty[Type] + while(rest.nonEmpty) { val candidate = rest.head val nonLeaf = leaves exists { t => t.typeSymbol isSubClass candidate.typeSymbol } if(!nonLeaf) { - leaves = candidate :: (leaves filterNot { t => candidate.typeSymbol isSubClass t.typeSymbol }) + leaves = leaves filterNot { t => candidate.typeSymbol isSubClass t.typeSymbol } + leaves += candidate } rest = rest.tail } - - leaves.reverse + leaves.toList } @@ -220,7 +220,7 @@ abstract class Erasure extends AddInterfaces case _ => tps } - val minParents = minimizeInterfaces(parents) + val minParents = minimizeParents(parents) val validParents = if (isTraitSignature) // java is unthrilled about seeing interfaces inherit from classes @@ -430,7 +430,7 @@ abstract class Erasure extends AddInterfaces * a name clash. The present method guards against these name clashes. * * @param member The original member - * @param other The overidden symbol for which the bridge was generated + * @param other The overridden symbol for which the bridge was generated * @param bridge The bridge */ def checkBridgeOverrides(member: Symbol, other: Symbol, bridge: Symbol): Seq[(Position, String)] = { @@ -1153,7 +1153,7 @@ abstract class Erasure extends AddInterfaces } } - /** The main transform function: Pretransfom the tree, and then + /** The main transform function: Pretransform the tree, and then * re-type it at phase erasure.next. */ override def transform(tree: Tree): Tree = { diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index c291961447..6225b486c2 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -441,7 +441,7 @@ abstract class ExplicitOuter extends InfoTransform else atPos(tree.pos)(outerPath(outerValue, currentClass.outerClass, sym)) // (5) case Select(qual, name) => - // make not private symbol acessed from inner classes, as well as + // make not private symbol accessed from inner classes, as well as // symbols accessed from @inline methods // // See SI-6552 for an example of why `sym.owner.enclMethod hasAnnotation ScalaInlineClass` diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index 4662ef6224..6149e40fa7 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -77,7 +77,7 @@ abstract class Flatten extends InfoTransform { if (sym.isTerm && !sym.isStaticModule) { decls1 enter sym if (sym.isModule) { - // In theory, we could assert(sym.isMethod), because nested, non-static moduls are + // In theory, we could assert(sym.isMethod), because nested, non-static modules are // transformed to methods (lateMETHOD flag added in RefChecks). But this requires // forcing sym.info (see comment on isModuleNotMethod), which forces stub symbols // too eagerly (SI-8907). diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index d69c9d9a65..fa0c1f797b 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -402,7 +402,7 @@ abstract class LambdaLift extends InfoTransform { } /* SI-6231: Something like this will be necessary to eliminate the implementation - * restiction from paramGetter above: + * restriction from paramGetter above: * We need to pass getters to the interface of an implementation class. private def fixTraitGetters(lifted: List[Tree]): List[Tree] = for (stat <- lifted) yield stat match { diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala index c1c025ad48..e4082eb376 100644 --- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala +++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala @@ -35,7 +35,7 @@ abstract class OverridingPairs extends SymbolPairs { */ 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 + && !high.isPrivate // private or private[this] members never are overridden && !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/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 9c81e31ad9..1691b01e3e 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -894,7 +894,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } val specMember = subst(outerEnv)(specializedOverload(owner, sym, spec)) - owner.info.decls.enter(specMember) typeEnv(specMember) = typeEnv(sym) ++ outerEnv ++ spec wasSpecializedForTypeVars(specMember) ++= spec collect { case (s, tp) if s.tpe == tp => s } @@ -1291,7 +1290,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * // even in the specialized variant, the local X class * // doesn't extend Parent$mcI$sp, since its symbol has * // been created after specialization and was not seen - * // by specialzation's info transformer. + * // by specialization's info transformer. * ... * } * } diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala index 75d2cfe0f2..0b53dc37de 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala @@ -122,9 +122,20 @@ trait Logic extends Debugging { // symbols are propositions final class Sym private[PropositionalLogic] (val variable: Var, val const: Const) extends Prop { + + override def equals(other: scala.Any): Boolean = other match { + case that: Sym => this.variable == that.variable && + this.const == that.const + case _ => false + } + + override def hashCode(): Int = { + variable.hashCode * 41 + const.hashCode + } + private val id: Int = Sym.nextSymId - override def toString = variable + "=" + const + "#" + id + override def toString = s"$variable=$const#$id" } object Sym { @@ -370,9 +381,11 @@ trait Logic extends Debugging { val EmptyModel: Model val NoModel: Model + final case class Solution(model: Model, unassigned: List[Sym]) + def findModelFor(solvable: Solvable): Model - def findAllModelsFor(solvable: Solvable): List[Model] + def findAllModelsFor(solvable: Solvable): List[Solution] } } @@ -622,7 +635,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { if (!t.symbol.isStable) { // Create a fresh type for each unstable value, since we can never correlate it to another value. - // For example `case X => case X =>` should not complaing about the second case being unreachable, + // For example `case X => case X =>` should not complain about the second case being unreachable, // if X is mutable. freshExistentialSubtype(t.tpe) } diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala index 8650f6ef90..34ebbc7463 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala @@ -6,6 +6,8 @@ package scala.tools.nsc.transform.patmat +import scala.annotation.tailrec +import scala.collection.immutable.{IndexedSeq, Iterable} import scala.language.postfixOps import scala.collection.mutable import scala.reflect.internal.util.Statistics @@ -266,7 +268,7 @@ trait MatchApproximation extends TreeAndTypeAnalysis with ScalaLogic with MatchT // the type of the binder passed to the first invocation // determines the type of the tree that'll be returned for that binder as of then final def binderToUniqueTree(b: Symbol) = - unique(accumSubst(normalize(CODE.REF(b))), b.tpe) + unique(accumSubst(normalize(gen.mkAttributedStableRef(b))), b.tpe) // note that the sequencing of operations is important: must visit in same order as match execution // binderToUniqueTree uses the type of the first symbol that was encountered as the type for all future binders @@ -363,7 +365,7 @@ trait MatchApproximation extends TreeAndTypeAnalysis with ScalaLogic with MatchT def handleUnknown(tm: TreeMaker) = handler(tm) } - // used for CSE -- rewrite all unknowns to False (the most conserative option) + // used for CSE -- rewrite all unknowns to False (the most conservative option) object conservative extends TreeMakerToProp { def handleUnknown(tm: TreeMaker) = False } @@ -514,8 +516,16 @@ trait MatchAnalysis extends MatchApproximation { // find the models (under which the match fails) val matchFailModels = findAllModelsFor(propToSolvable(matchFails)) + val scrutVar = Var(prevBinderTree) - val counterExamples = matchFailModels.flatMap(modelToCounterExample(scrutVar)) + val counterExamples = { + matchFailModels.flatMap { + model => + val varAssignments = expandModel(model) + varAssignments.flatMap(modelToCounterExample(scrutVar) _) + } + } + // sorting before pruning is important here in order to // keep neg/t7020.scala stable // since e.g. List(_, _) would cover List(1, _) @@ -587,6 +597,8 @@ trait MatchAnalysis extends MatchApproximation { case object WildcardExample extends CounterExample { override def toString = "_" } case object NoExample extends CounterExample { override def toString = "??" } + // returns a mapping from variable to + // equal and notEqual symbols def modelToVarAssignment(model: Model): Map[Var, (Seq[Const], Seq[Const])] = model.toSeq.groupBy{f => f match {case (sym, value) => sym.variable} }.mapValues{ xs => val (trues, falses) = xs.partition(_._2) @@ -600,20 +612,110 @@ trait MatchAnalysis extends MatchApproximation { v +"(="+ v.path +": "+ v.staticTpCheckable +") "+ assignment }.mkString("\n") - // return constructor call when the model is a true counter example - // (the variables don't take into account type information derived from other variables, - // so, naively, you might try to construct a counter example like _ :: Nil(_ :: _, _ :: _), - // since we didn't realize the tail of the outer cons was a Nil) - def modelToCounterExample(scrutVar: Var)(model: Model): Option[CounterExample] = { + /** + * The models we get from the DPLL solver need to be mapped back to counter examples. + * However there's no precalculated mapping model -> counter example. Even worse, + * not every valid model corresponds to a valid counter example. + * The reason is that restricting the valid models further would for example require + * a quadratic number of additional clauses. So to keep the optimistic case fast + * (i.e., all cases are covered in a pattern match), the infeasible counter examples + * are filtered later. + * + * The DPLL procedure keeps the literals that do not contribute to the solution + * unassigned, e.g., for `(a \/ b)` + * only {a = true} or {b = true} is required and the other variable can have any value. + * + * This function does a smart expansion of the model and avoids models that + * have conflicting mappings. + * + * For example for in case of the given set of symbols (taken from `t7020.scala`): + * "V2=2#16" + * "V2=6#19" + * "V2=5#18" + * "V2=4#17" + * "V2=7#20" + * + * One possibility would be to group the symbols by domain but + * this would only work for equality tests and would not be compatible + * with type tests. + * Another observation leads to a much simpler algorithm: + * Only one of these symbols can be set to true, + * since `V2` can at most be equal to one of {2,6,5,4,7}. + */ + def expandModel(solution: Solution): List[Map[Var, (Seq[Const], Seq[Const])]] = { + + val model = solution.model + // x1 = ... // x1.hd = ... // x1.tl = ... // x1.hd.hd = ... // ... val varAssignment = modelToVarAssignment(model) + debug.patmat("var assignment for model " + model + ":\n" + varAssignmentString(varAssignment)) + + // group symbols that assign values to the same variables (i.e., symbols are mutually exclusive) + // (thus the groups are sets of disjoint assignments to variables) + val groupedByVar: Map[Var, List[Sym]] = solution.unassigned.groupBy(_.variable) + + val expanded = for { + (variable, syms) <- groupedByVar.toList + } yield { + + val (equal, notEqual) = varAssignment.getOrElse(variable, Nil -> Nil) + + def addVarAssignment(equalTo: List[Const], notEqualTo: List[Const]) = { + Map(variable ->(equal ++ equalTo, notEqual ++ notEqualTo)) + } + + // this assignment is needed in case that + // there exists already an assign + val allNotEqual = addVarAssignment(Nil, syms.map(_.const)) - debug.patmat("var assignment for model "+ model +":\n"+ varAssignmentString(varAssignment)) + // this assignment is conflicting on purpose: + // a list counter example could contain wildcards: e.g. `List(_,_)` + val allEqual = addVarAssignment(syms.map(_.const), Nil) + if(equal.isEmpty) { + val oneHot = for { + s <- syms + } yield { + addVarAssignment(List(s.const), syms.filterNot(_ == s).map(_.const)) + } + allEqual :: allNotEqual :: oneHot + } else { + allEqual :: allNotEqual :: Nil + } + } + + if (expanded.isEmpty) { + List(varAssignment) + } else { + // we need the cartesian product here, + // since we want to report all missing cases + // (i.e., combinations) + val cartesianProd = expanded.reduceLeft((xs, ys) => + for {map1 <- xs + map2 <- ys} yield { + map1 ++ map2 + }) + + // add expanded variables + // note that we can just use `++` + // since the Maps have disjoint keySets + for { + m <- cartesianProd + } yield { + varAssignment ++ m + } + } + } + + // return constructor call when the model is a true counter example + // (the variables don't take into account type information derived from other variables, + // so, naively, you might try to construct a counter example like _ :: Nil(_ :: _, _ :: _), + // since we didn't realize the tail of the outer cons was a Nil) + def modelToCounterExample(scrutVar: Var)(varAssignment: Map[Var, (Seq[Const], Seq[Const])]): Option[CounterExample] = { // chop a path into a list of symbols def chop(path: Tree): List[Symbol] = path match { case Ident(_) => List(path.symbol) @@ -742,7 +844,7 @@ trait MatchAnalysis extends MatchApproximation { // then we can safely ignore these counter examples since we will eventually encounter // both counter examples separately case _ if inSameDomain => None - + // not a valid counter-example, possibly since we have a definite type but there was a field mismatch // TODO: improve reasoning -- in the mean time, a false negative is better than an annoying false positive case _ => Some(NoExample) @@ -761,12 +863,12 @@ trait MatchAnalysis extends MatchApproximation { } def analyzeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type, suppression: Suppression): Unit = { - if (!suppression.unreachable) { + if (!suppression.suppressUnreachable) { unreachableCase(prevBinder, cases, pt) foreach { caseIndex => reportUnreachable(cases(caseIndex).last.pos) } } - if (!suppression.exhaustive) { + if (!suppression.suppressExhaustive) { val counterExamples = exhaustive(prevBinder, cases, pt) if (counterExamples.nonEmpty) reportMissingCases(prevBinder.pos, counterExamples) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala index 22661d6ccf..6302e34ac9 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala @@ -208,7 +208,7 @@ trait MatchTranslation { case _ => (cases, None) } - checkMatchVariablePatterns(nonSyntheticCases) + if (!settings.XnoPatmatAnalysis) checkMatchVariablePatterns(nonSyntheticCases) // we don't transform after uncurry // (that would require more sophistication when generating trees, @@ -248,7 +248,10 @@ trait MatchTranslation { if (caseDefs forall treeInfo.isCatchCase) caseDefs else { val swatches = { // switch-catches - val bindersAndCases = caseDefs map { caseDef => + // SI-7459 must duplicate here as we haven't commited to switch emission, and just figuring out + // if we can ends up mutating `caseDefs` down in the use of `substituteSymbols` in + // `TypedSubstitution#Substitution`. That is called indirectly by `emitTypeSwitch`. + val bindersAndCases = caseDefs.map(_.duplicate) map { caseDef => // generate a fresh symbol for each case, hoping we'll end up emitting a type-switch (we don't have a global scrut there) // if we fail to emit a fine-grained switch, have to do translateCase again with a single scrutSym (TODO: uniformize substitution on treemakers so we can avoid this) val caseScrutSym = freshSym(pos, pureType(ThrowableTpe)) @@ -518,7 +521,7 @@ trait MatchTranslation { // reference the (i-1)th case accessor if it exists, otherwise the (i-1)th tuple component override protected def tupleSel(binder: Symbol)(i: Int): Tree = { val accessors = binder.caseFieldAccessors - if (accessors isDefinedAt (i-1)) REF(binder) DOT accessors(i-1) + if (accessors isDefinedAt (i-1)) gen.mkAttributedStableRef(binder) DOT accessors(i-1) else codegen.tupleSel(binder)(i) // this won't type check for case classes, as they do not inherit ProductN } } @@ -580,7 +583,7 @@ trait MatchTranslation { // duplicated with the extractor Unapplied case Apply(x, List(i @ Ident(nme.SELECTOR_DUMMY))) => treeCopy.Apply(t, x, binderRef(i.pos) :: Nil) - // SI-7868 Account for numeric widening, e.g. <unappplySelector>.toInt + // SI-7868 Account for numeric widening, e.g. <unapplySelector>.toInt case Apply(x, List(i @ (sel @ Select(Ident(nme.SELECTOR_DUMMY), name)))) => treeCopy.Apply(t, x, treeCopy.Select(sel, binderRef(i.pos), name) :: Nil) case _ => diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala index 3fd9ce76f8..b703b5bc6d 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala @@ -21,9 +21,10 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { import global._ import definitions._ - final case class Suppression(exhaustive: Boolean, unreachable: Boolean) + final case class Suppression(suppressExhaustive: Boolean, suppressUnreachable: Boolean) object Suppression { val NoSuppression = Suppression(false, false) + val FullSuppression = Suppression(true, true) } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -166,8 +167,17 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { val usedBinders = new mutable.HashSet[Symbol]() // all potentially stored subpat binders val potentiallyStoredBinders = stored.unzip._1.toSet + def ref(sym: Symbol) = + if (potentiallyStoredBinders(sym)) usedBinders += sym // compute intersection of all symbols in the tree `in` and all potentially stored subpat binders - in.foreach(t => if (potentiallyStoredBinders(t.symbol)) usedBinders += t.symbol) + in.foreach { + case tt: TypeTree => + tt.tpe foreach { // SI-7459 e.g. case Prod(t) => new t.u.Foo + case SingleType(_, sym) => ref(sym) + case _ => + } + case t => ref(t.symbol) + } if (usedBinders.isEmpty) in else { @@ -517,7 +527,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { def removeSubstOnly(makers: List[TreeMaker]) = makers filterNot (_.isInstanceOf[SubstOnlyTreeMaker]) // a foldLeft to accumulate the localSubstitution left-to-right - // it drops SubstOnly tree makers, since their only goal in life is to propagate substitutions to the next tree maker, which is fullfilled by propagateSubstitution + // it drops SubstOnly tree makers, since their only goal in life is to propagate substitutions to the next tree maker, which is fulfilled by propagateSubstitution def propagateSubstitution(treeMakers: List[TreeMaker], initial: Substitution): List[TreeMaker] = { var accumSubst: Substitution = initial treeMakers foreach { maker => @@ -542,7 +552,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { debug.patmat("combining cases: "+ (casesNoSubstOnly.map(_.mkString(" >> ")).mkString("{", "\n", "}"))) val (suppression, requireSwitch): (Suppression, Boolean) = - if (settings.XnoPatmatAnalysis) (Suppression.NoSuppression, false) + if (settings.XnoPatmatAnalysis) (Suppression.FullSuppression, false) else scrut match { case Typed(tree, tpt) => val suppressExhaustive = tpt.tpe hasAnnotation UncheckedClass @@ -574,7 +584,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { (Suppression.NoSuppression, false) } - emitSwitch(scrut, scrutSym, casesNoSubstOnly, pt, matchFailGenOverride, suppression.exhaustive).getOrElse{ + emitSwitch(scrut, scrutSym, casesNoSubstOnly, pt, matchFailGenOverride, unchecked = suppression.suppressExhaustive).getOrElse{ if (requireSwitch) reporter.warning(scrut.pos, "could not emit switch for @switch annotated match") if (casesNoSubstOnly nonEmpty) { diff --git a/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala b/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala index ef50e083a1..d35aad964d 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala @@ -12,7 +12,7 @@ import scala.language.postfixOps import scala.tools.nsc.transform.TypingTransformers import scala.tools.nsc.transform.Transform import scala.reflect.internal.util.Statistics -import scala.reflect.internal.Types +import scala.reflect.internal.{Mode, Types} import scala.reflect.internal.util.Position /** Translate pattern matching. @@ -198,33 +198,57 @@ trait Interface extends ast.TreeDSL { } class Substitution(val from: List[Symbol], val to: List[Tree]) { - import global.{Transformer, Ident, NoType} + import global.{Transformer, Ident, NoType, TypeTree, SingleType} // We must explicitly type the trees that we replace inside some other tree, since the latter may already have been typed, // and will thus not be retyped. This means we might end up with untyped subtrees inside bigger, typed trees. def apply(tree: Tree): Tree = { // according to -Ystatistics 10% of translateMatch's time is spent in this method... // since about half of the typedSubst's end up being no-ops, the check below shaves off 5% of the time spent in typedSubst - if (!tree.exists { case i@Ident(_) => from contains i.symbol case _ => false}) tree - else (new Transformer { + val toIdents = to.forall(_.isInstanceOf[Ident]) + val containsSym = tree.exists { + case i@Ident(_) => from contains i.symbol + case tt: TypeTree => tt.tpe.exists { + case SingleType(_, sym) => + (from contains sym) && { + if (!toIdents) global.devWarning(s"Unexpected substitution of non-Ident into TypeTree `$tt`, subst= $this") + true + } + case _ => false + } + case _ => false + } + val toSyms = to.map(_.symbol) + object substIdentsForTrees extends Transformer { private def typedIfOrigTyped(to: Tree, origTp: Type): Tree = if (origTp == null || origTp == NoType) to // important: only type when actually substing and when original tree was typed // (don't need to use origTp as the expected type, though, and can't always do this anyway due to unknown type params stemming from polymorphic extractors) else typer.typed(to) + def typedStable(t: Tree) = typer.typed(t.shallowDuplicate, Mode.MonoQualifierModes | Mode.TYPEPATmode) + lazy val toTypes: List[Type] = to map (tree => typedStable(tree).tpe) + override def transform(tree: Tree): Tree = { def subst(from: List[Symbol], to: List[Tree]): Tree = if (from.isEmpty) tree - else if (tree.symbol == from.head) typedIfOrigTyped(to.head.shallowDuplicate.setPos(tree.pos), tree.tpe) + else if (tree.symbol == from.head) typedIfOrigTyped(typedStable(to.head).setPos(tree.pos), tree.tpe) else subst(from.tail, to.tail) - tree match { + val tree1 = tree match { case Ident(_) => subst(from, to) case _ => super.transform(tree) } + tree1.modifyType(_.substituteTypes(from, toTypes)) } - }).transform(tree) + } + if (containsSym) { + if (to.forall(_.isInstanceOf[Ident])) + tree.duplicate.substituteSymbols(from, to.map(_.symbol)) // SI-7459 catches `case t => new t.Foo` + else + substIdentsForTrees.transform(tree) + } + else tree } diff --git a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala index 8924394b72..2753baa51d 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala @@ -110,8 +110,10 @@ trait ScalacPatternExpanders { err("Star pattern must correspond with varargs or unapplySeq") else if (elementArity < 0) arityError("not enough") - else if (elementArity > 0 && !extractor.hasSeq) + else if (elementArity > 0 && !isSeq) arityError("too many") + else if (settings.warnStarsAlign && isSeq && productArity > 0 && (elementArity > 0 || !isStar)) + warn("A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*).") aligned } diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala index 1ba13c0617..27217f0dc2 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala @@ -288,7 +288,7 @@ trait Solving extends Logic { val NoTseitinModel: TseitinModel = null // returns all solutions, if any (TODO: better infinite recursion backstop -- detect fixpoint??) - def findAllModelsFor(solvable: Solvable): List[Model] = { + def findAllModelsFor(solvable: Solvable): List[Solution] = { debug.patmat("find all models for\n"+ cnfString(solvable.cnf)) // we must take all vars from non simplified formula @@ -305,54 +305,12 @@ trait Solving extends Logic { relevantLits.map(lit => -lit) } - /** - * The DPLL procedure only returns a minimal mapping from literal to value - * such that the CNF formula is satisfied. - * E.g. for: - * `(a \/ b)` - * The DPLL procedure will find either {a = true} or {b = true} - * as solution. - * - * The expansion step will amend both solutions with the unassigned variable - * i.e., {a = true} will be expanded to {a = true, b = true} and {a = true, b = false}. - */ - def expandUnassigned(unassigned: List[Int], model: TseitinModel): List[TseitinModel] = { - // the number of solutions is doubled for every unassigned variable - val expandedModels = 1 << unassigned.size - var current = mutable.ArrayBuffer[TseitinModel]() - var next = mutable.ArrayBuffer[TseitinModel]() - current.sizeHint(expandedModels) - next.sizeHint(expandedModels) - - current += model - - // we use double buffering: - // read from `current` and create a two models for each model in `next` - for { - s <- unassigned - } { - for { - model <- current - } { - def force(l: Lit) = model + l - - next += force(Lit(s)) - next += force(Lit(-s)) - } - - val tmp = current - current = next - next = tmp - - next.clear() - } - - current.toList + final case class TseitinSolution(model: TseitinModel, unassigned: List[Int]) { + def projectToSolution(symForVar: Map[Int, Sym]) = Solution(projectToModel(model, symForVar), unassigned map symForVar) } - def findAllModels(clauses: Array[Clause], - models: List[TseitinModel], - recursionDepthAllowed: Int = global.settings.YpatmatExhaustdepth.value): List[TseitinModel]= + models: List[TseitinSolution], + recursionDepthAllowed: Int = global.settings.YpatmatExhaustdepth.value): List[TseitinSolution]= if (recursionDepthAllowed == 0) { val maxDPLLdepth = global.settings.YpatmatExhaustdepth.value reportWarning("(Exhaustivity analysis reached max recursion depth, not all missing cases are reported. " + @@ -368,17 +326,15 @@ trait Solving extends Logic { val unassigned: List[Int] = (relevantVars -- model.map(lit => lit.variable)).toList debug.patmat("unassigned "+ unassigned +" in "+ model) - val forced = expandUnassigned(unassigned, model) - debug.patmat("forced "+ forced) + val solution = TseitinSolution(model, unassigned) val negated = negateModel(model) - findAllModels(clauses :+ negated, forced ++ models, recursionDepthAllowed - 1) + findAllModels(clauses :+ negated, solution :: models, recursionDepthAllowed - 1) } else models } - val tseitinModels: List[TseitinModel] = findAllModels(solvable.cnf, Nil) - val models: List[Model] = tseitinModels.map(projectToModel(_, solvable.symbolMapping.symForVar)) - models + val tseitinSolutions = findAllModels(solvable.cnf, Nil) + tseitinSolutions.map(_.projectToSolution(solvable.symbolMapping.symForVar)) } private def withLit(res: TseitinModel, l: Lit): TseitinModel = { diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 866ca37303..5c36bd9d28 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -73,7 +73,7 @@ trait ContextErrors { // 2) provide the type of the implicit parameter for which we got diverging expansion // (pt at the point of divergence gives less information to the user) // Note: it is safe to delay error message generation in this case - // becasue we don't modify implicits' infos. + // because we don't modify implicits' infos. case class DivergentImplicitTypeError(underlyingTree: Tree, pt0: Type, sym: Symbol) extends TreeTypeError { def errMsg: String = errMsgForPt(pt0) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index a7d0d32c6f..ca25e59c4b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -145,7 +145,7 @@ trait Contexts { self: Analyzer => * - A variety of bits that track the current error reporting policy (more on this later); * whether or not implicits/macros are enabled, whether we are in a self or super call or * in a constructor suffix. These are represented as bits in the mask `contextMode`. - * - Some odds and ends: undetermined type pararameters of the current line of type inference; + * - Some odds and ends: undetermined type parameters of the current line of type inference; * contextual augmentation for error messages, tracking of the nesting depth. * * And behaviour: @@ -154,19 +154,19 @@ trait Contexts { self: Analyzer => * to buffer these for use in 'silent' type checking, when some recovery might be possible. * - `Context` is something of a Zipper for the tree were are typechecking: it `enclosingContextChain` * is the path back to the root. This is exactly what we need to resolve names (`lookupSymbol`) - * and to collect in-scope implicit defintions (`implicitss`) + * and to collect in-scope implicit definitions (`implicitss`) * Supporting these are `imports`, which represents all `Import` trees in in the enclosing context chain. - * - In a similar vein, we can assess accessiblity (`isAccessible`.) + * - In a similar vein, we can assess accessibility (`isAccessible`.) * * More on error buffering: * When are type errors recoverable? In quite a few places, it turns out. Some examples: * trying to type an application with/without the expected type, or with/without implicit views * enabled. This is usually mediated by `Typer.silent`, `Inferencer#tryTwice`. * - * Intially, starting from the `typer` phase, the contexts either buffer or report errors; + * Initially, starting from the `typer` phase, the contexts either buffer or report errors; * afterwards errors are thrown. This is configured in `rootContext`. Additionally, more * fine grained control is needed based on the kind of error; ambiguity errors are often - * suppressed during exploraratory typing, such as determining whether `a == b` in an argument + * suppressed during exploratory typing, such as determining whether `a == b` in an argument * position is an assignment or a named argument, when `Infererencer#isApplicableSafe` type checks * applications with and without an expected type, or whtn `Typer#tryTypedApply` tries to fit arguments to * a function type with/without implicit views. diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 74c28122a1..71558273a6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -3,7 +3,7 @@ * @author Martin Odersky */ -//todo: rewrite or disllow new T where T is a mixin (currently: <init> not a member of T) +//todo: rewrite or disallow new T where T is a mixin (currently: <init> not a member of T) //todo: use inherited type info also for vars and values //todo: disallow C#D in superclass //todo: treat :::= correctly @@ -159,7 +159,7 @@ trait Implicits { * @param tree The tree representing the implicit * @param subst A substituter that represents the undetermined type parameters * that were instantiated by the winning implicit. - * @param undetparams undeterminted type parameters + * @param undetparams undetermined type parameters */ class SearchResult(val tree: Tree, val subst: TreeTypeSubstituter, val undetparams: List[Symbol]) { override def toString = "SearchResult(%s, %s)".format(tree, diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 8979b26719..cf97474d9a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1017,7 +1017,7 @@ trait Infer extends Checkable { /** Substitute free type variables `undetparams` of type constructor * `tree` in pattern, given prototype `pt`. * - * @param tree the constuctor that needs to be instantiated + * @param tree the constructor that needs to be instantiated * @param undetparams the undetermined type parameters * @param pt0 the expected result type of the instance */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 0bb94be636..711cfba24d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -171,7 +171,7 @@ trait Namers extends MethodSynthesis { val newFlags = (sym.flags & LOCKED) | flags sym.rawInfo match { case tr: TypeRef => - // !!! needed for: pos/t5954d; the uniques type cache will happilly serve up the same TypeRef + // !!! needed for: pos/t5954d; the uniques type cache will happily serve up the same TypeRef // over this mutated symbol, and we witness a stale cache for `parents`. tr.invalidateCaches() case _ => diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index b6387fd56b..50f658f68d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -384,7 +384,7 @@ trait NamesDefaults { self: Analyzer => * of arguments. * * @param args The list of arguments - * @param params The list of parameter sybols of the invoked method + * @param params The list of parameter symbols of the invoked method * @param argName A function that extracts the name of an argument expression, if it is a named argument. */ def missingParams[T](args: List[T], params: List[Symbol], argName: T => Option[Name]): (List[Symbol], Boolean) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala index bb8c3c3c6d..fa4a764f1b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala @@ -336,7 +336,7 @@ trait PatternTypers { val app = atPos(uncheckedPattern.pos)(Apply(classTagExtractor, args)) // must call doTypedUnapply directly, as otherwise we get undesirable rewrites // and re-typechecks of the target of the unapply call in PATTERNmode, - // this breaks down when the classTagExtractor (which defineds the unapply member) is not a simple reference to an object, + // this breaks down when the classTagExtractor (which defines the unapply member) is not a simple reference to an object, // but an arbitrary tree as is the case here val res = doTypedUnapply(app, classTagExtractor, classTagExtractor, args, PATTERNmode, pt) diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 1daff02c23..d2046a158c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -171,7 +171,7 @@ trait SyntheticMethods extends ast.TreeDSL { def thatCast(eqmeth: Symbol): Tree = gen.mkCast(Ident(eqmeth.firstParam), clazz.tpe) - /* The equality method core for case classes and inline clases. + /* The equality method core for case classes and inline classes. * 1+ args: * (that.isInstanceOf[this.C]) && { * val x$1 = that.asInstanceOf[this.C] diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index aaa75b5ee1..9773028b76 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -946,7 +946,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // Ignore type errors raised in later phases that are due to mismatching types with existential skolems // We have lift crashing in 2.9 with an adapt failure in the pattern matcher. - // Here's my hypothsis why this happens. The pattern matcher defines a variable of type + // Here's my hypothesis why this happens. The pattern matcher defines a variable of type // // val x: T = expr // @@ -1177,7 +1177,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } def instantiatePossiblyExpectingUnit(tree: Tree, mode: Mode, pt: Type): Tree = { - if (mode.typingExprNotFun && pt.typeSymbol == UnitClass) + if (mode.typingExprNotFun && pt.typeSymbol == UnitClass && !tree.tpe.isInstanceOf[MethodType]) instantiateExpectingUnit(tree, mode) else instantiate(tree, mode, pt) @@ -3281,6 +3281,22 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } handleOverloaded + case _ if isPolymorphicSignature(fun.symbol) => + // Mimic's Java's treatment of polymorphic signatures as described in + // https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.3 + // + // One can think of these methods as being infinitely overloaded. We create + // a ficticious new cloned method symbol for each call site that takes on a signature + // governed by a) the argument types and b) the expected type + val args1 = typedArgs(args, forArgMode(fun, mode)) + val pts = args1.map(_.tpe.deconst) + val clone = fun.symbol.cloneSymbol + val cloneParams = pts map (pt => clone.newValueParameter(currentUnit.freshTermName()).setInfo(pt)) + val resultType = if (isFullyDefined(pt)) pt else ObjectTpe + clone.modifyInfo(mt => copyMethodType(mt, cloneParams, resultType)) + val fun1 = fun.setSymbol(clone).setType(clone.info) + doTypedApply(tree, fun1, args1, mode, resultType).setType(resultType) + case mt @ MethodType(params, _) => val paramTypes = mt.paramTypes // repeat vararg as often as needed, remove by-name @@ -3776,8 +3792,12 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case TypeRef(pre, sym, args) => if (sym.isAliasType && containsLocal(tp) && (tp.dealias ne tp)) apply(tp.dealias) else { - if (pre.isVolatile) - InferTypeWithVolatileTypeSelectionError(tree, pre) + if (pre.isVolatile) pre match { + case SingleType(_, sym) if sym.isSynthetic && isPastTyper => + debuglog(s"ignoring volatility of prefix in pattern matcher generated inferred type: $tp") // See pos/t7459c.scala + case _ => + InferTypeWithVolatileTypeSelectionError(tree, pre) + } mapOver(tp) } case _ => diff --git a/src/compiler/scala/tools/nsc/util/DocStrings.scala b/src/compiler/scala/tools/nsc/util/DocStrings.scala index ba44126df2..352816803f 100755 --- a/src/compiler/scala/tools/nsc/util/DocStrings.scala +++ b/src/compiler/scala/tools/nsc/util/DocStrings.scala @@ -8,7 +8,7 @@ package util import scala.reflect.internal.Chars._ -/** Utilitity methods for doc comment strings +/** Utility methods for doc comment strings */ object DocStrings { diff --git a/src/intellij-14/scala.ipr.SAMPLE b/src/intellij-14/scala.ipr.SAMPLE index 7c2022f3a9..1e3d07466d 100644 --- a/src/intellij-14/scala.ipr.SAMPLE +++ b/src/intellij-14/scala.ipr.SAMPLE @@ -233,14 +233,14 @@ <library name="starr" type="Scala"> <properties> <compiler-classpath> - <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-compiler-2.11.2.jar" /> - <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-library-2.11.2.jar" /> - <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-reflect-2.11.2.jar" /> + <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-compiler-#scala-version#.jar" /> + <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-library-#scala-version#.jar" /> + <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-reflect-#scala-version#.jar" /> </compiler-classpath> </properties> <CLASSES> - <root url="jar://$PROJECT_DIR$/../../build/deps/starr/scala-library-2.11.2.jar!/" /> - <root url="jar://$PROJECT_DIR$/../../build/deps/starr/scala-reflect-2.11.2.jar!/" /> + <root url="jar://$PROJECT_DIR$/../../build/deps/starr/scala-library-#scala-version#.jar!/" /> + <root url="jar://$PROJECT_DIR$/../../build/deps/starr/scala-reflect-#scala-version#.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES /> @@ -248,9 +248,9 @@ <library name="starr-no-deps" type="Scala"> <properties> <compiler-classpath> - <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-compiler-2.11.2.jar" /> - <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-library-2.11.2.jar" /> - <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-reflect-2.11.2.jar" /> + <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-compiler-#scala-version#.jar" /> + <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-library-#scala-version#.jar" /> + <root url="file://$PROJECT_DIR$/../../build/deps/starr/scala-reflect-#scala-version#.jar" /> </compiler-classpath> </properties> <CLASSES /> diff --git a/src/intellij-14/setup.sh b/src/intellij-14/setup.sh index ec303778ed..cf08898f24 100755 --- a/src/intellij-14/setup.sh +++ b/src/intellij-14/setup.sh @@ -12,3 +12,6 @@ for f in "$SCRIPT_DIR"/*.SAMPLE; do g=${f%.SAMPLE} cp $f $g done + +SCALA_VERSION="`cat $SCRIPT_DIR/../../versions.properties | grep 'starr.version' | awk '{split($0,a,"="); print a[2]}'`" +sed "s/#scala-version#/$SCALA_VERSION/g" $SCRIPT_DIR/scala.ipr.SAMPLE > $SCRIPT_DIR/scala.ipr
\ No newline at end of file diff --git a/src/intellij/scala-lang.ipr.SAMPLE b/src/intellij/scala-lang.ipr.SAMPLE index c0614c946c..0cd3fdae6a 100644 --- a/src/intellij/scala-lang.ipr.SAMPLE +++ b/src/intellij/scala-lang.ipr.SAMPLE @@ -218,6 +218,7 @@ <module fileurl="file://$PROJECT_DIR$/scalap.iml" filepath="$PROJECT_DIR$/scalap.iml" /> <module fileurl="file://$PROJECT_DIR$/test.iml" filepath="$PROJECT_DIR$/test.iml" /> <module fileurl="file://$PROJECT_DIR$/test-junit.iml" filepath="$PROJECT_DIR$/test-junit.iml" /> + <module fileurl="file://$PROJECT_DIR$/test-osgi.iml" filepath="$PROJECT_DIR$/test-osgi.iml" /> </modules> </component> <component name="ProjectResources"> diff --git a/src/intellij/test-osgi.iml.SAMPLE b/src/intellij/test-osgi.iml.SAMPLE new file mode 100644 index 0000000000..a589aaa0a9 --- /dev/null +++ b/src/intellij/test-osgi.iml.SAMPLE @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$/../../test/osgi"> + <sourceFolder url="file://$MODULE_DIR$/../../test/osgi/src" isTestSource="false" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module" module-name="actors" /> + <orderEntry type="module" module-name="asm" /> + <orderEntry type="module" module-name="compiler" /> + <orderEntry type="module" module-name="library" /> + <orderEntry type="module" module-name="reflect" /> + <orderEntry type="module" module-name="repl" /> + <orderEntry type="module" module-name="partest-extras" /> + <orderEntry type="module" module-name="forkjoin" /> + <orderEntry type="library" name="junit" level="project" /> + <orderEntry type="library" name="scaladoc-deps" level="project" /> + <orderEntry type="library" name="scala-sdk" level="project" /> + <orderEntry type="library" scope="PROVIDED" name="pax.exam-deps" level="project" /> + </component> +</module>
\ No newline at end of file diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index 5d00141e6a..9b34a39e02 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -78,7 +78,11 @@ trait InteractiveAnalyzer extends Analyzer { val owningInfo = sym.owner.info val existingDerivedSym = owningInfo.decl(sym.name.toTermName).filter(sym => sym.isSynthetic && sym.isMethod) existingDerivedSym.alternatives foreach (owningInfo.decls.unlink) - enterImplicitWrapper(tree.asInstanceOf[ClassDef]) + val defTree = tree match { + case dd: DocDef => dd.definition // See SI-9011, Scala IDE's presentation compiler incorporates ScalaDocGlobal with InterativeGlobal, so we have to unwrap DocDefs. + case _ => tree + } + enterImplicitWrapper(defTree.asInstanceOf[ClassDef]) } super.enterExistingSym(sym, tree) } @@ -522,7 +526,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") /** The current presentation compiler runner */ @volatile private[interactive] var compileRunner: Thread = newRunnerThread() - /** Check that the currenyly executing thread is the presentation compiler thread. + /** Check that the currently executing thread is the presentation compiler thread. * * Compiler initialization may happen on a different thread (signalled by globalPhase being NoPhase) */ @@ -1188,7 +1192,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } } - /** Parses and enters given source file, stroring parse tree in response */ + /** Parses and enters given source file, storing parse tree in response */ private def getParsedEnteredNow(source: SourceFile, response: Response[Tree]) { respond(response) { onUnitOf(source) { unit => diff --git a/src/interactive/scala/tools/nsc/interactive/Pickler.scala b/src/interactive/scala/tools/nsc/interactive/Pickler.scala index 83f3fab925..ddc0c8a068 100644 --- a/src/interactive/scala/tools/nsc/interactive/Pickler.scala +++ b/src/interactive/scala/tools/nsc/interactive/Pickler.scala @@ -6,7 +6,7 @@ import scala.language.implicitConversions import scala.reflect.ClassTag /** An abstract class for writing and reading Scala objects to and - * from a legible representation. The presesentation follows the following grammar: + * from a legible representation. The representation follows the following grammar: * {{{ * Pickled = `true` | `false` | `null` | NumericLit | StringLit | * Labelled | Pickled `,` Pickled @@ -85,7 +85,7 @@ abstract class Pickler[T] { object Pickler { /** A base class representing unpickler result. It has two subclasses: - * `UnpickleSucess` for successful unpicklings and `UnpickleFailure` for failures, + * `UnpickleSuccess` for successful unpicklings and `UnpickleFailure` for failures, * where a value of the given type `T` could not be unpickled from input. * @tparam T the type of unpickled values in case of success. */ @@ -154,7 +154,7 @@ object Pickler { */ def pkl[T: Pickler] = implicitly[Pickler[T]] - /** A class represenenting `~`-pairs */ + /** A class representing `~`-pairs */ case class ~[+S, +T](fst: S, snd: T) /** A wrapper class to be able to use `~` s an infix method */ diff --git a/src/library/scala/Enumeration.scala b/src/library/scala/Enumeration.scala index e11d1b35d7..c4aa511cd7 100644 --- a/src/library/scala/Enumeration.scala +++ b/src/library/scala/Enumeration.scala @@ -121,7 +121,8 @@ abstract class Enumeration (initial: Int) extends Serializable { * @throws NoSuchElementException if no `Value` with a matching * name is in this `Enumeration` */ - final def withName(s: String): Value = values.find(_.toString == s).get + final def withName(s: String): Value = values.find(_.toString == s).getOrElse( + throw new NoSuchElementException(s"No value found for '$s'")) /** Creates a fresh value, part of this enumeration. */ protected final def Value: Value = Value(nextId) diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala index 41224f4c6c..f134f5ce3d 100644 --- a/src/library/scala/Option.scala +++ b/src/library/scala/Option.scala @@ -125,8 +125,8 @@ sealed abstract class Option[+A] extends Product with Serializable { * Although the use of null is discouraged, code written to use * $option must often interface with code that expects and returns nulls. * @example {{{ - * val initalText: Option[String] = getInitialText - * val textField = new JComponent(initalText.orNull,20) + * val initialText: Option[String] = getInitialText + * val textField = new JComponent(initialText.orNull,20) * }}} */ @inline final def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse ev(null) diff --git a/src/library/scala/collection/GenSeqLike.scala b/src/library/scala/collection/GenSeqLike.scala index 1c4f233e22..cf1de0c8e6 100644 --- a/src/library/scala/collection/GenSeqLike.scala +++ b/src/library/scala/collection/GenSeqLike.scala @@ -397,7 +397,7 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal * @inheritdoc * * Another way to express this - * is that `xs union ys` computes the order-presevring multi-set union of `xs` and `ys`. + * is that `xs union ys` computes the order-preserving multi-set union of `xs` and `ys`. * `union` is hence a counter-part of `diff` and `intersect` which also work on multi-sets. * * $willNotTerminateInf diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index 20712f918c..0783beac0f 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -479,7 +479,7 @@ trait Iterator[+A] extends TraversableOnce[A] { } } - /** Produces a collection containing cummulative results of applying the + /** Produces a collection containing cumulative results of applying the * operator going left to right. * * $willNotTerminateInf @@ -502,8 +502,8 @@ trait Iterator[+A] extends TraversableOnce[A] { } else Iterator.empty.next() } - /** Produces a collection containing cummulative results of applying the operator going right to left. - * The head of the collection is the last cummulative result. + /** Produces a collection containing cumulative results of applying the operator going right to left. + * The head of the collection is the last cumulative result. * * $willNotTerminateInf * $orderDependent diff --git a/src/library/scala/collection/LinearSeqOptimized.scala b/src/library/scala/collection/LinearSeqOptimized.scala index 64248aa755..9c336e8e31 100755 --- a/src/library/scala/collection/LinearSeqOptimized.scala +++ b/src/library/scala/collection/LinearSeqOptimized.scala @@ -44,7 +44,7 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea * * $willNotTerminateInf * - * Note: the execution of `length` may take time proportial to the length of the sequence. + * Note: the execution of `length` may take time proportional to the length of the sequence. */ def length: Int = { var these = self @@ -57,7 +57,7 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea } /** Selects an element by its index in the $coll. - * Note: the execution of `apply` may take time proportial to the index value. + * Note: the execution of `apply` may take time proportional to the index value. * @throws IndexOutOfBoundsException if `idx` does not satisfy `0 <= idx < length`. */ def apply(n: Int): A = { diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index e4b7371ed4..f548eac88d 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -406,7 +406,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { // 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 + // create a new HashSetCollision with the hash we already know and the new keys new HashSetCollision1(hash, ks1) } } @@ -426,7 +426,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { // 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 + // create a new HashSetCollision with the hash we already know and the new keys new HashSetCollision1(hash, ks1) } } @@ -445,7 +445,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { // Should only have HSC1 if size > 1 this case _ => - // create a new HashSetCollison with the hash we already know and the new keys + // create a new HashSetCollision with the hash we already know and the new keys new HashSetCollision1(hash, ks1) } } else this diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 09a69b8096..9ed5162061 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -944,7 +944,7 @@ self => * * @param p the test predicate. * @return A new `Stream` representing the results of applying `p` to the - * oringal `Stream`. + * original `Stream`. * * @example {{{ * // Assume we have a Stream that takes the first 20 natural numbers diff --git a/src/library/scala/collection/immutable/Vector.scala b/src/library/scala/collection/immutable/Vector.scala index c7da447f72..47a623a616 100644 --- a/src/library/scala/collection/immutable/Vector.scala +++ b/src/library/scala/collection/immutable/Vector.scala @@ -215,7 +215,7 @@ override def companion: GenericCompanion[Vector] = Vector import Vector.{Log2ConcatFaster, TinyAppendFaster} if (that.isEmpty) this.asInstanceOf[That] else { - val again = if (!that.isTraversableAgain) that.toVector else that + val again = if (!that.isTraversableAgain) that.toVector else that.seq again.size match { // Often it's better to append small numbers of elements (or prepend if RHS is a vector) case n if n <= TinyAppendFaster || n < (this.size >> Log2ConcatFaster) => diff --git a/src/library/scala/collection/mutable/DoubleLinkedList.scala b/src/library/scala/collection/mutable/DoubleLinkedList.scala index 671b79f8c2..fd95e74fbc 100644 --- a/src/library/scala/collection/mutable/DoubleLinkedList.scala +++ b/src/library/scala/collection/mutable/DoubleLinkedList.scala @@ -41,7 +41,7 @@ import generic._ * @define mayNotTerminateInf * @define willNotTerminateInf */ -@deprecated("Low-level linked lists are deprecated due to idiosyncracies in interface and incomplete features.", "2.11.0") +@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") @SerialVersionUID(-8144992287952814767L) class DoubleLinkedList[A]() extends AbstractSeq[A] with LinearSeq[A] diff --git a/src/library/scala/collection/mutable/DoubleLinkedListLike.scala b/src/library/scala/collection/mutable/DoubleLinkedListLike.scala index a43fe34c99..aafe34f50a 100644 --- a/src/library/scala/collection/mutable/DoubleLinkedListLike.scala +++ b/src/library/scala/collection/mutable/DoubleLinkedListLike.scala @@ -56,10 +56,10 @@ import scala.annotation.migration * @define Coll `DoubleLinkedList` * @define coll double linked list */ -@deprecated("Low-level linked lists are deprecated due to idiosyncracies in interface and incomplete features.", "2.11.0") +@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") trait DoubleLinkedListLike[A, This <: Seq[A] with DoubleLinkedListLike[A, This]] extends SeqLike[A, This] with LinkedListLike[A, This] { self => - /** A reference to the node in the linked list preceeding the current node. */ + /** A reference to the node in the linked list preceding the current node. */ var prev: This = _ // returns that list if this list is empty diff --git a/src/library/scala/collection/mutable/LinkedList.scala b/src/library/scala/collection/mutable/LinkedList.scala index 092698ac0b..b3500367af 100644 --- a/src/library/scala/collection/mutable/LinkedList.scala +++ b/src/library/scala/collection/mutable/LinkedList.scala @@ -76,7 +76,7 @@ import generic._ * }}} */ @SerialVersionUID(-7308240733518833071L) -@deprecated("Low-level linked lists are deprecated due to idiosyncracies in interface and incomplete features.", "2.11.0") +@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") class LinkedList[A]() extends AbstractSeq[A] with LinearSeq[A] with GenericTraversableTemplate[A, LinkedList] diff --git a/src/library/scala/collection/mutable/LinkedListLike.scala b/src/library/scala/collection/mutable/LinkedListLike.scala index 987b83d23b..a9d385bc5b 100644 --- a/src/library/scala/collection/mutable/LinkedListLike.scala +++ b/src/library/scala/collection/mutable/LinkedListLike.scala @@ -55,7 +55,7 @@ import scala.annotation.tailrec * * }}} */ -@deprecated("Low-level linked lists are deprecated due to idiosyncracies in interface and incomplete features.", "2.11.0") +@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") trait LinkedListLike[A, This <: Seq[A] with LinkedListLike[A, This]] extends SeqLike[A, This] { self => var elem: A = _ diff --git a/src/library/scala/collection/mutable/LongMap.scala b/src/library/scala/collection/mutable/LongMap.scala index 5fafe23d9f..c124f35cd7 100644 --- a/src/library/scala/collection/mutable/LongMap.scala +++ b/src/library/scala/collection/mutable/LongMap.scala @@ -19,7 +19,7 @@ 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 + * 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. * diff --git a/src/library/scala/collection/mutable/MapLike.scala b/src/library/scala/collection/mutable/MapLike.scala index 471cd1cdde..af28df1b88 100644 --- a/src/library/scala/collection/mutable/MapLike.scala +++ b/src/library/scala/collection/mutable/MapLike.scala @@ -133,7 +133,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] /** Creates a new map containing the key/value mappings provided by the specified traversable object * and all the key/value mappings of this map. * - * Note that existing mappings from this map with the same key as those in `xs` will be overriden. + * Note that existing mappings from this map with the same key as those in `xs` will be overridden. * * @param xs the traversable object. * @return a new map containing mappings of this map and those provided by `xs`. diff --git a/src/library/scala/collection/mutable/OpenHashMap.scala b/src/library/scala/collection/mutable/OpenHashMap.scala index aade2ed6fb..24f5761cf5 100644 --- a/src/library/scala/collection/mutable/OpenHashMap.scala +++ b/src/library/scala/collection/mutable/OpenHashMap.scala @@ -31,7 +31,7 @@ object OpenHashMap { /** A mutable hash map based on an open hashing scheme. The precise scheme is * undefined, but it should make a reasonable effort to ensure that an insert - * with consecutive hash codes is not unneccessarily penalised. In particular, + * with consecutive hash codes is not unnecessarily penalised. In particular, * mappings of consecutive integer keys should work without significant * performance loss. * diff --git a/src/library/scala/collection/package.scala b/src/library/scala/collection/package.scala index 26b061b2a5..6a2b6de75a 100644 --- a/src/library/scala/collection/package.scala +++ b/src/library/scala/collection/package.scala @@ -18,7 +18,7 @@ package scala * * == Using Collections == * - * It is convienient to treat all collections as either + * It is convenient to treat all collections as either * a [[scala.collection.Traversable]] or [[scala.collection.Iterable]], as * these traits define the vast majority of operations * on a collection. diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index 2b54e05841..016255dca4 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -744,7 +744,7 @@ self: ParIterableLike[T, Repr, Sequential] => * The index flag is initially set to maximum integer value. * * @param pred the predicate used to test the elements - * @return the longest prefix of this $coll of elements that satisy the predicate `pred` + * @return the longest prefix of this $coll of elements that satisfy the predicate `pred` */ def takeWhile(pred: T => Boolean): Repr = { val cbf = combinerFactory diff --git a/src/library/scala/collection/parallel/package.scala b/src/library/scala/collection/parallel/package.scala index 91c54fa8f1..d77dcb0658 100644 --- a/src/library/scala/collection/parallel/package.scala +++ b/src/library/scala/collection/parallel/package.scala @@ -206,7 +206,7 @@ package parallel { * Methods `beforeCombine` and `afterCombine` are called before and after * combining the buckets, respectively, given that the argument to `combine` * is not `this` (as required by the `combine` contract). - * They can be overriden in subclasses to provide custom behaviour by modifying + * They can be overridden in subclasses to provide custom behaviour by modifying * the receiver (which will be the return value). */ private[parallel] abstract class BucketCombiner[-Elem, +To, Buck, +CombinerType <: BucketCombiner[Elem, To, Buck, CombinerType]] diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index e93a3284dc..914646320c 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -485,7 +485,7 @@ object Future { * The result becomes available once the asynchronous computation is completed. * * @tparam T the type of the result - * @param body the asychronous computation + * @param body the asynchronous computation * @param executor the execution context on which the future is run * @return the `Future` holding the result of the computation */ diff --git a/src/library/scala/concurrent/SyncVar.scala b/src/library/scala/concurrent/SyncVar.scala index 494c955833..9634f6d900 100644 --- a/src/library/scala/concurrent/SyncVar.scala +++ b/src/library/scala/concurrent/SyncVar.scala @@ -93,7 +93,7 @@ class SyncVar[A] { // [Heather] the reason why: it doesn't take into consideration // whether or not the SyncVar is already defined. So, set has been // deprecated in order to eventually be able to make "setting" private - @deprecated("Use `put` instead, as `set` is potentionally error-prone", "2.10.0") + @deprecated("Use `put` instead, as `set` is potentially error-prone", "2.10.0") // NOTE: Used by SBT 0.13.0-M2 and below def set(x: A): Unit = setVal(x) @@ -113,7 +113,7 @@ class SyncVar[A] { // [Heather] the reason why: it doesn't take into consideration // whether or not the SyncVar is already defined. So, unset has been // deprecated in order to eventually be able to make "unsetting" private - @deprecated("Use `take` instead, as `unset` is potentionally error-prone", "2.10.0") + @deprecated("Use `take` instead, as `unset` is potentially error-prone", "2.10.0") // NOTE: Used by SBT 0.13.0-M2 and below def unset(): Unit = synchronized { isDefined = false diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala index 4843d28679..d159dda414 100644 --- a/src/library/scala/concurrent/package.scala +++ b/src/library/scala/concurrent/package.scala @@ -12,6 +12,75 @@ import scala.concurrent.duration.Duration import scala.annotation.implicitNotFound /** This package object contains primitives for concurrent and parallel programming. + * + * == Guide == + * + * A more detailed guide to Futures and Promises, including discussion and examples + * can be found at + * [[http://docs.scala-lang.org/overviews/core/futures.html]]. + * + * == Common Imports == + * + * When working with Futures, you will often find that importing the whole concurrent + * package is convenient, furthermore you are likely to need an implicit ExecutionContext + * in scope for many operations involving Futures and Promises: + * + * {{{ + * import scala.concurrent._ + * import ExecutionContext.Implicits.global + * }}} + * + * == Specifying Durations == + * + * Operations often require a duration to be specified. A duration DSL is available + * to make defining these easier: + * + * {{{ + * import scala.concurrent.duration._ + * val d: Duration = 10.seconds + * }}} + * + * == Using Futures For Non-blocking Computation == + * + * Basic use of futures is easy with the factory method on Future, which executes a + * provided function asynchronously, handing you back a future result of that function + * without blocking the current thread. In order to create the Future you will need + * either an implicit or explicit ExecutionContext to be provided: + * + * {{{ + * import scala.concurrent._ + * import ExecutionContext.Implicits.global // implicit execution context + * + * val firstZebra: Future[Int] = Future { + * val source = scala.io.Source.fromFile("/etc/dictionaries-common/words") + * source.toSeq.indexOfSlice("zebra") + * } + * }}} + * + * == Avoid Blocking == + * + * Although blocking is possible in order to await results (with a mandatory timeout duration): + * + * {{{ + * import scala.concurrent.duration._ + * Await.result(firstZebra, 10.seconds) + * }}} + * + * and although this is sometimes necessary to do, in particular for testing purposes, blocking + * in general is discouraged when working with Futures and concurrency in order to avoid + * potential deadlocks and improve performance. Instead, use callbacks or combinators to + * remain in the future domain: + * + * {{{ + * val animalRange: Future[Int] = for { + * aardvark <- firstAardvark + * zebra <- firstZebra + * } yield zebra - aardvark + * + * animalRange.onSuccess { + * case x if x > 500000 => println("It's a long way from Aardvark to Zebra") + * } + * }}} */ package object concurrent { type ExecutionException = java.util.concurrent.ExecutionException @@ -70,6 +139,11 @@ package concurrent { /** * `Await` is what is used to ensure proper handling of blocking for `Awaitable` instances. + * + * While occasionally useful, e.g. for testing, it is recommended that you avoid Await + * when possible in favor of callbacks and combinators like onComplete and use in + * for comprehensions. Await will block the thread on which it runs, and could cause + * performance and deadlock issues. */ object Await { /** diff --git a/src/library/scala/io/Source.scala b/src/library/scala/io/Source.scala index 74c3e06839..9f0b56b4fe 100644 --- a/src/library/scala/io/Source.scala +++ b/src/library/scala/io/Source.scala @@ -169,9 +169,20 @@ object Source { createBufferedSource(is, reset = () => fromInputStream(is)(codec), close = () => is.close())(codec) } -/** The class `Source` implements an iterable representation of source data. - * Calling method `reset` returns an identical, resetted source, where - * possible. +/** An iterable representation of source data. + * It may be reset with the optional `reset` method. + * + * Subclasses must supply [[scala.io.Source@iter the underlying iterator]]. + * + * Error handling may be customized by overriding the [[scala.io.Source@report report]] method. + * + * The [[scala.io.Source@ch current input]] and [[scala.io.Source@pos position]], + * as well as the [[scala.io.Source@next next character]] methods delegate to + * [[scala.io.Source$Positioner the positioner]]. + * + * The default positioner encodes line and column numbers in the position passed to `report`. + * This behavior can be changed by supplying a + * [[scala.io.Source@withPositioning(pos:Source.this.Positioner):Source.this.type custom positioner]]. * * @author Burak Emir * @version 1.0 diff --git a/src/library/scala/io/StdIn.scala b/src/library/scala/io/StdIn.scala index 64836ecd6e..0f9656436b 100644 --- a/src/library/scala/io/StdIn.scala +++ b/src/library/scala/io/StdIn.scala @@ -4,7 +4,7 @@ package io import java.text.MessageFormat /** private[scala] because this is not functionality we should be providing - * in the standard library, at least not in this idiosyncractic form. + * in the standard library, at least not in this idiosyncratic form. * Factored into trait because it is better code structure regardless. */ private[scala] trait StdIn { diff --git a/src/library/scala/language.scala b/src/library/scala/language.scala index c638f531bb..2eb5514a18 100644 --- a/src/library/scala/language.scala +++ b/src/library/scala/language.scala @@ -1,3 +1,13 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2015, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + + + package scala /** diff --git a/src/library/scala/languageFeature.scala b/src/library/scala/languageFeature.scala index 1f411c412a..51118b43be 100644 --- a/src/library/scala/languageFeature.scala +++ b/src/library/scala/languageFeature.scala @@ -1,3 +1,13 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2015, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + + + package scala import scala.annotation.meta diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index 74a174ea74..cf95f945ba 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -364,7 +364,7 @@ object BigDecimal { * 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 + * full number of digits, thus producing the exact decimal value corresponding 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, diff --git a/src/library/scala/math/Ordering.scala b/src/library/scala/math/Ordering.scala index 0d7ea8bce2..827cccc77e 100644 --- a/src/library/scala/math/Ordering.scala +++ b/src/library/scala/math/Ordering.scala @@ -284,6 +284,9 @@ object Ordering extends LowPriorityOrderingImplicits { override def gteq(x: Float, y: Float): Boolean = outer.gteq(y, x) override def lt(x: Float, y: Float): Boolean = outer.lt(y, x) override def gt(x: Float, y: Float): Boolean = outer.gt(y, x) + override def min(x: Float, y: Float): Float = outer.max(x, y) + override def max(x: Float, y: Float): Float = outer.min(x, y) + } } implicit object Float extends FloatOrdering @@ -309,6 +312,8 @@ object Ordering extends LowPriorityOrderingImplicits { override def gteq(x: Double, y: Double): Boolean = outer.gteq(y, x) override def lt(x: Double, y: Double): Boolean = outer.lt(y, x) override def gt(x: Double, y: Double): Boolean = outer.gt(y, x) + override def min(x: Double, y: Double): Double = outer.max(x, y) + override def max(x: Double, y: Double): Double = outer.min(x, y) } } implicit object Double extends DoubleOrdering diff --git a/src/library/scala/runtime/MethodCache.scala b/src/library/scala/runtime/MethodCache.scala index 2d5f832e1f..a8fdfc1059 100644 --- a/src/library/scala/runtime/MethodCache.scala +++ b/src/library/scala/runtime/MethodCache.scala @@ -16,7 +16,7 @@ import java.lang.{ Class => JClass } import scala.annotation.tailrec /** An element of a polymorphic object cache. - * This class is refered to by the `CleanUp` phase. Each `PolyMethodCache` chain + * This class is referred to by the `CleanUp` phase. Each `PolyMethodCache` chain * must only relate to one method as `PolyMethodCache` does not identify * the method name and argument types. In practice, one variable will be * generated per call point, and will uniquely relate to the method called diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index f50059ce54..18fcbf8276 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -251,7 +251,7 @@ object ScalaRunTime { * * The primary motivation for this method is to provide a means for * correctly obtaining a String representation of a value, while - * avoiding the pitfalls of naïvely calling toString on said value. + * avoiding the pitfalls of naively calling toString on said value. * In particular, it addresses the fact that (a) toString cannot be * called on null and (b) depending on the apparent type of an * array, toString may or may not print it in a human-readable form. diff --git a/src/library/scala/sys/process/package.scala b/src/library/scala/sys/process/package.scala index 1340a6c415..b1976ad4b6 100644 --- a/src/library/scala/sys/process/package.scala +++ b/src/library/scala/sys/process/package.scala @@ -119,7 +119,7 @@ package scala.sys { * ==Handling Input and Output== * * In the underlying Java model, once a `Process` has been started, one can - * get `java.io.InputStream` and `java.io.OutpuStream` representing its + * get `java.io.InputStream` and `java.io.OutputStream` representing its * output and input respectively. That is, what one writes to an * `OutputStream` is turned into input to the process, and the output of a * process can be read from an `InputStream` -- of which there are two, one diff --git a/src/manual/scala/man1/Command.scala b/src/manual/scala/man1/Command.scala index 1cf55cb28d..8f811f950e 100644 --- a/src/manual/scala/man1/Command.scala +++ b/src/manual/scala/man1/Command.scala @@ -47,7 +47,7 @@ trait Command { def copyright = Section("COPYRIGHT", "This is open-source software, available to you under a BSD-like license. " & - "See accomponying \"copyright\" or \"LICENSE\" file for copying conditions. " & + "See accompanying \"copyright\" or \"LICENSE\" file for copying conditions. " & "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A " & "PARTICULAR PURPOSE.") diff --git a/src/manual/scala/man1/scalac.scala b/src/manual/scala/man1/scalac.scala index 31d25d4801..3954ed588e 100644 --- a/src/manual/scala/man1/scalac.scala +++ b/src/manual/scala/man1/scalac.scala @@ -360,7 +360,7 @@ object scalac extends Command { "ANF pre-transform for " & MItalic("@cps") & " (CPS plugin)"), Definition( MItalic("selectivecps"), - MItalic("@cps") & "-driven transform of selectiveanf assignements (CPS plugin)"), + MItalic("@cps") & "-driven transform of selectiveanf assignments (CPS plugin)"), Definition( MItalic("uncurry"), "uncurry, translate function values to anonymous classes"), diff --git a/src/partest-extras/scala/tools/partest/BytecodeTest.scala b/src/partest-extras/scala/tools/partest/BytecodeTest.scala index 37ef4684ef..8459419fa5 100644 --- a/src/partest-extras/scala/tools/partest/BytecodeTest.scala +++ b/src/partest-extras/scala/tools/partest/BytecodeTest.scala @@ -136,7 +136,7 @@ abstract class BytecodeTest { object BytecodeTest { /** Parse `file` as a class file, transforms the ASM representation with `f`, - * and overwrites the orginal file. + * and overwrites the original file. */ def modifyClassFile(file: JFile)(f: ClassNode => ClassNode) { val rfile = new reflect.io.File(file) diff --git a/src/partest-extras/scala/tools/partest/instrumented/Profiler.java b/src/partest-extras/scala/tools/partest/instrumented/Profiler.java index d6b62e1d9e..848103f5cc 100644 --- a/src/partest-extras/scala/tools/partest/instrumented/Profiler.java +++ b/src/partest-extras/scala/tools/partest/instrumented/Profiler.java @@ -12,7 +12,7 @@ import java.util.Map; * A simple profiler class that counts method invocations. It is being used in byte-code instrumentation by inserting * call to {@link Profiler#methodCalled(String, String, String)} at the beginning of every instrumented class. * - * WARANING: This class is INTERNAL implementation detail and should never be used directly. It's made public only + * WARNING: This class is INTERNAL implementation detail and should never be used directly. It's made public only * because it must be universally accessible for instrumentation needs. If you want to profile your test use * {@link Instrumentation} instead. */ diff --git a/src/reflect/scala/reflect/api/Liftables.scala b/src/reflect/scala/reflect/api/Liftables.scala index 673dbce6f5..c6352905d1 100644 --- a/src/reflect/scala/reflect/api/Liftables.scala +++ b/src/reflect/scala/reflect/api/Liftables.scala @@ -52,7 +52,7 @@ trait Liftables { self: Universe => object Unliftable extends StandardUnliftableInstances { /** A helper method that simplifies creation of `Unliftable` instances. * Takes a partial function which is defined on correct representations of `T` - * and returns corresponing instances. + * and returns corresponding instances. * * For example to extract a reference to an object as object itself: * diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala index 773c6b6fb4..adaf829b32 100644 --- a/src/reflect/scala/reflect/api/Mirrors.scala +++ b/src/reflect/scala/reflect/api/Mirrors.scala @@ -338,7 +338,7 @@ trait Mirrors { self: Universe => * with getting a field or invoking a getter method of the field. * * If `symbol` represents a field of a base class with respect to the class of the receiver, - * and this base field is overriden in the class of the receiver, then this method will retrieve + * and this base field is overridden in the class of the receiver, then this method will retrieve * the value of the base field. To achieve overriding behavior, use reflectMethod on an accessor. */ def get: Any @@ -352,7 +352,7 @@ trait Mirrors { self: Universe => * with setting a field or invoking a setter method of the field. * * If `symbol` represents a field of a base class with respect to the class of the receiver, - * and this base field is overriden in the class of the receiver, then this method will set + * and this base field is overridden in the class of the receiver, then this method will set * the value of the base field. To achieve overriding behavior, use reflectMethod on an accessor. */ def set(value: Any): Unit diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala index 03f7b2d218..472da60338 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -72,10 +72,10 @@ trait Names { * @group API */ abstract class NameApi { - /** Checks wether the name is a term name */ + /** Checks whether the name is a term name */ def isTermName: Boolean - /** Checks wether the name is a type name */ + /** Checks whether the name is a type name */ def isTypeName: Boolean /** Returns a term name that wraps the same string as `this` */ diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index 18d185067e..c01029d067 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -339,7 +339,7 @@ trait Symbols { self: Universe => @deprecated("Use `overrides` instead", "2.11.0") def allOverriddenSymbols: List[Symbol] - /** Returns all symbols overriden by this symbol. + /** Returns all symbols overridden by this symbol. * * @group Basics */ diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index aeaa38c317..9ecd87c17e 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -158,7 +158,7 @@ trait Trees { self: Universe => /** Do all parts of this tree satisfy predicate `p`? */ def forAll(p: Tree => Boolean): Boolean - /** Tests whether two trees are structurall equal. + /** Tests whether two trees are structurally equal. * Note that `==` on trees is reference equality. */ def equalsStructure(that : Tree): Boolean diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala index 0ca8611719..54f64153c1 100644 --- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala +++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala @@ -144,7 +144,7 @@ trait BaseTypeSeqs { "\n --- because ---\n"+msg) } - /** A merker object for a base type sequence that's no yet computed. + /** A marker object for a base type sequence that's no yet computed. * used to catch inheritance cycles */ val undetBaseTypeSeq: BaseTypeSeq = newBaseTypeSeq(List(), Array()) @@ -152,7 +152,7 @@ trait BaseTypeSeqs { /** Create a base type sequence consisting of a single type */ def baseTypeSingletonSeq(tp: Type): BaseTypeSeq = newBaseTypeSeq(List(), Array(tp)) - /** Create the base type sequence of a compound type wuth given tp.parents */ + /** Create the base type sequence of a compound type with given tp.parents */ def compoundBaseTypeSeq(tp: Type): BaseTypeSeq = { val tsym = tp.typeSymbol val parents = tp.parents diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 7e2d124486..9f4ec3e6d1 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -514,6 +514,8 @@ trait Definitions extends api.StandardDefinitions { lazy val ScalaSignatureAnnotation = requiredClass[scala.reflect.ScalaSignature] lazy val ScalaLongSignatureAnnotation = requiredClass[scala.reflect.ScalaLongSignature] + lazy val MethodHandle = getClassIfDefined("java.lang.invoke.MethodHandle") + // Option classes lazy val OptionClass: ClassSymbol = requiredClass[Option[_]] lazy val OptionModule: ModuleSymbol = requiredModule[scala.Option.type] @@ -931,7 +933,7 @@ trait Definitions extends api.StandardDefinitions { // members of class scala.Any - // TODO these aren't final! They are now overriden in AnyRef/Object. Prior to the fix + // TODO these aren't final! They are now overridden 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. @@ -1508,6 +1510,9 @@ trait Definitions extends api.StandardDefinitions { lazy val PartialManifestClass = getTypeMember(ReflectPackage, tpnme.ClassManifest) lazy val ManifestSymbols = Set[Symbol](PartialManifestClass, FullManifestClass, OptManifestClass) + + def isPolymorphicSignature(sym: Symbol) = PolySigMethods(sym) + private lazy val PolySigMethods: Set[Symbol] = Set[Symbol](MethodHandle.info.decl(sn.Invoke), MethodHandle.info.decl(sn.InvokeExact)).filter(_.exists) } } } diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 4a35e024de..0cbb976a98 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -277,7 +277,7 @@ trait Mirrors extends api.Mirrors { // TODO - having these as objects means they elude the attempt to // add synchronization in SynchronizedSymbols. But we should either - // flip on object overrides or find some other accomodation, because + // flip on object overrides or find some other accommodation, because // lazy vals are unnecessarily expensive relative to objects and it // is very beneficial for a handful of bootstrap symbols to have // first class identities diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index b50f324074..32d12d305e 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -131,11 +131,11 @@ trait Names extends api.Names { newTermName(cs, offset, len, cachedString).toTypeName /** Create a term name from string. */ - @deprecatedOverriding("To synchronize, use `override def synchronizeNames = true`", "2.11.0") // overriden in https://github.com/scala-ide/scala-ide/blob/master/org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaPresentationCompiler.scala + @deprecatedOverriding("To synchronize, use `override def synchronizeNames = true`", "2.11.0") // overridden in https://github.com/scala-ide/scala-ide/blob/master/org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaPresentationCompiler.scala def newTermName(s: String): TermName = newTermName(s.toCharArray(), 0, s.length(), null) /** Create a type name from string. */ - @deprecatedOverriding("To synchronize, use `override def synchronizeNames = true`", "2.11.0") // overriden in https://github.com/scala-ide/scala-ide/blob/master/org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaPresentationCompiler.scala + @deprecatedOverriding("To synchronize, use `override def synchronizeNames = true`", "2.11.0") // overridden in https://github.com/scala-ide/scala-ide/blob/master/org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaPresentationCompiler.scala def newTypeName(s: String): TypeName = newTermName(s).toTypeName /** Create a term name from the UTF8 encoded bytes in bs[offset..offset+len-1]. */ diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala index c16d8778d9..4d0e31b037 100644 --- a/src/reflect/scala/reflect/internal/Positions.scala +++ b/src/reflect/scala/reflect/internal/Positions.scala @@ -204,7 +204,7 @@ trait Positions extends api.Positions { self: SymbolTable => /** Set position of all children of a node * @param pos A target position. * Uses the point of the position as the point of all positions it assigns. - * Uses the start of this position as an Offset position for unpositioed trees + * Uses the start of this position as an Offset position for unpositioned trees * without children. * @param trees The children to position. All children must be positionable. */ diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index c4953b2c1f..98b2c48379 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -546,10 +546,11 @@ trait Printers extends api.Printers { self: SymbolTable => import Chars._ val decName = name.decoded val bslash = '\\' + val isDot = (x: Char) => x == '.' val brackets = List('[',']','(',')','{','}') def addBackquotes(s: String) = - if (decoded && (decName.exists(ch => brackets.contains(ch) || isWhitespace(ch)) || + if (decoded && (decName.exists(ch => brackets.contains(ch) || isWhitespace(ch) || isDot(ch)) || (name.isOperatorName && decName.exists(isOperatorPart) && decName.exists(isScalaLetter) && !decName.contains(bslash)))) s"`$s`" else s diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala index 614e71b597..cca33253be 100644 --- a/src/reflect/scala/reflect/internal/StdAttachments.scala +++ b/src/reflect/scala/reflect/internal/StdAttachments.scala @@ -27,7 +27,7 @@ trait StdAttachments { def importAttachment(importer: Importer): this.type } - /** Attachment that doesn't contain any reflection artificats and can be imported as-is. */ + /** Attachment that doesn't contain any reflection artifacts and can be imported as-is. */ trait PlainAttachment extends ImportableAttachment { def importAttachment(importer: Importer): this.type = this } @@ -42,7 +42,7 @@ trait StdAttachments { */ case object BackquotedIdentifierAttachment extends PlainAttachment - /** Identifies trees are either result or intermidiate value of for loop desugaring. + /** Identifies trees are either result or intermediate value of for loop desugaring. */ case object ForAttachment extends PlainAttachment diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 667ff7c4b4..c94ee996e4 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -1147,6 +1147,7 @@ trait StdNames { final val GetClassLoader: TermName = newTermName("getClassLoader") final val GetMethod: TermName = newTermName("getMethod") final val Invoke: TermName = newTermName("invoke") + final val InvokeExact: TermName = newTermName("invokeExact") val Boxed = immutable.Map[TypeName, TypeName]( tpnme.Boolean -> BoxedBoolean, diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 8e86e6fad9..d5fc52abbf 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -682,7 +682,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * 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 + * However we do need to fix this for runtime reflection, since this idiosyncrasy 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. */ @@ -740,7 +740,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * * Note: the lateMETHOD flag is added lazily in the info transformer of the RefChecks phase. * This means that forcing the `sym.info` may change the value of `sym.isMethod`. Forcing the - * info is in the responsability of the caller. Doing it eagerly here was tried (0ccdb151f) but + * info is in the responsibility of the caller. Doing it eagerly here was tried (0ccdb151f) but * has proven to lead to bugs (SI-8907). * * Here's an example where one can see all four of FF FT TF TT for (isStatic, isMethod) at @@ -2054,7 +2054,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => * where it is the outer class of the enclosing class. */ final def outerClass: Symbol = - if (owner.isClass) owner + if (this == NoSymbol) { + // ideally we shouldn't get here, but its better to harden against this than suffer the infinite loop in SI-9133 + devWarningDumpStack("NoSymbol.outerClass", 15) + NoSymbol + } else if (owner.isClass) owner else if (isClassLocalToConstructor) owner.enclClass.outerClass else owner.outerClass @@ -2812,7 +2816,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def outerSource: Symbol = // SI-6888 Approximate the name to workaround the deficiencies in `nme.originalName` - // in the face of clases named '$'. SI-2806 remains open to address the deeper problem. + // in the face of classes named '$'. SI-2806 remains open to address the deeper problem. if (originalName endsWith (nme.OUTER)) initialize.referenced else NoSymbol @@ -3570,7 +3574,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * @param syms the prototypical symbols * @param symFn the function to create new symbols * @param tpe the prototypical type - * @return the new symbol-subsituted type + * @return the new symbol-substituted type */ def deriveType(syms: List[Symbol], symFn: Symbol => Symbol)(tpe: Type): Type = { val syms1 = deriveSymbols(syms, symFn) @@ -3585,7 +3589,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * @param as arguments to be passed to symFn together with symbols from syms (must be same length) * @param symFn the function to create new symbols based on `as` * @param tpe the prototypical type - * @return the new symbol-subsituted type + * @return the new symbol-substituted type */ def deriveType2[A](syms: List[Symbol], as: List[A], symFn: (Symbol, A) => Symbol)(tpe: Type): Type = { val syms1 = deriveSymbols2(syms, as, symFn) diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index 6e8e992d16..b3e11a826e 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -713,7 +713,7 @@ abstract class TreeGen { val rhsUnchecked = mkUnchecked(rhs) - // TODO: clean this up -- there is too much information packked into mkPatDef's `pat` argument + // TODO: clean this up -- there is too much information packed into mkPatDef's `pat` argument // when it's a simple identifier (case Some((name, tpt)) -- above), // pat should have the type ascription that was specified by the user // however, in `case None` (here), we must be careful not to generate illegal pattern trees (such as `(a, b): Tuple2[Int, String]`) diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index c521277f69..4657fa0000 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -588,7 +588,7 @@ abstract class TreeInfo { private def hasNoSymbol(t: Tree) = t.symbol == null || t.symbol == NoSymbol - /** Is this pattern node a synthetic catch-all case, added during PartialFuction synthesis before we know + /** Is this pattern node a synthetic catch-all case, added during PartialFunction synthesis before we know * whether the user provided cases are exhaustive. */ def isSyntheticDefaultCase(cdef: CaseDef) = cdef match { case CaseDef(Bind(nme.DEFAULT_CASE, _), EmptyTree, _) => true @@ -815,7 +815,7 @@ abstract class TreeInfo { object Unapplied { // Duplicated with `spliceApply` def unapply(tree: Tree): Option[Tree] = tree match { - // SI-7868 Admit Select() to account for numeric widening, e.g. <unappplySelector>.toInt + // SI-7868 Admit Select() to account for numeric widening, e.g. <unapplySelector>.toInt case Apply(fun, (Ident(nme.SELECTOR_DUMMY)| Select(Ident(nme.SELECTOR_DUMMY), _)) :: Nil) => Some(fun) case Apply(fun, _) => unapply(fun) diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 35de3adff6..ccf907e05d 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -1576,6 +1576,7 @@ trait Trees extends api.Trees { */ class TreeSymSubstituter(from: List[Symbol], to: List[Symbol]) extends Transformer { val symSubst = new SubstSymMap(from, to) + private var mutatedSymbols: List[Symbol] = Nil override def transform(tree: Tree): Tree = { def subst(from: List[Symbol], to: List[Symbol]) { if (!from.isEmpty) @@ -1594,6 +1595,7 @@ trait Trees extends api.Trees { |TreeSymSubstituter: updated info of symbol ${tree.symbol} | Old: ${showRaw(tree.symbol.info, printTypes = true, printIds = true)} | New: ${showRaw(newInfo, printTypes = true, printIds = true)}""") + mutatedSymbols ::= tree.symbol tree.symbol updateInfo newInfo } case _ => @@ -1613,7 +1615,23 @@ trait Trees extends api.Trees { } else super.transform(tree) } - def apply[T <: Tree](tree: T): T = transform(tree).asInstanceOf[T] + def apply[T <: Tree](tree: T): T = { + val tree1 = transform(tree) + invalidateSingleTypeCaches(tree1) + tree1.asInstanceOf[T] + } + private def invalidateSingleTypeCaches(tree: Tree): Unit = { + if (mutatedSymbols.nonEmpty) + for (t <- tree) + for (tp <- t.tpe) { + tp match { + case s: SingleType if mutatedSymbols contains s.sym => + s.underlyingPeriod = NoPeriod + s.underlyingCache = NoType + case _ => + } + } + } override def toString() = "TreeSymSubstituter/" + substituterString("Symbol", "Symbol", from, to) } diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index a95f626a0b..ce36f7efa3 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -731,7 +731,7 @@ trait Types * `substThis(from, to).substSym(symsFrom, symsTo)`. * * `SubstThisAndSymMap` performs a breadth-first map over this type, which meant that - * symbol substitution occured before `ThisType` substitution. Consequently, in substitution + * symbol substitution occurred before `ThisType` substitution. Consequently, in substitution * of a `SingleType(ThisType(`from`), sym), symbols were rebound to `from` rather than `to`. */ def substThisAndSym(from: Symbol, to: Type, symsFrom: List[Symbol], symsTo: List[Symbol]): Type = @@ -1687,7 +1687,7 @@ trait Types */ private var refs: Array[RefMap] = _ - /** The initialization state of the class: UnInialized --> Initializing --> Initialized + /** The initialization state of the class: UnInitialized --> Initializing --> Initialized * Syncnote: This var need not be protected with synchronized, because * it is accessed only from expansiveRefs, which is called only from * Typer. @@ -1972,7 +1972,7 @@ trait Types require(sym.isNonClassType, sym) /* Syncnote: These are pure caches for performance; no problem to evaluate these - * several times. Hence, no need to protected with synchronzied in a mutli-threaded + * several times. Hence, no need to protected with synchronized in a multi-threaded * usage scenario. */ private var relativeInfoCache: Type = _ @@ -2643,7 +2643,7 @@ trait Types * nowhere inside a type argument * - no quantified type argument contains a quantified variable in its bound * - the typeref's symbol is not itself quantified - * - the prefix is not quanitified + * - the prefix is not quantified */ def isRepresentableWithWildcards = { val qset = quantified.toSet @@ -3101,7 +3101,7 @@ trait Types // addressed here: all lower bounds are retained and their intersection calculated when the // bounds are solved. // - // In a side-effect free universe, checking tp and tp.parents beofre checking tp.baseTypeSeq + // In a side-effect free universe, checking tp and tp.parents before checking tp.baseTypeSeq // would be pointless. In this case, each check we perform causes us to lose specificity: in // the end the best we'll do is the least specific type we tested against, since the typevar // does not see these checks as "probes" but as requirements to fulfill. @@ -3332,7 +3332,7 @@ trait Types * * SI-6385 Erasure's creation of bridges considers method signatures `exitingErasure`, * which contain `ErasedValueType`-s. In order to correctly consider the overriding - * and overriden signatures as equivalent in `run/t6385.scala`, it is critical that + * and overridden signatures as equivalent in `run/t6385.scala`, it is critical that * this type contains the erasure of the wrapped type, rather than the unerased type * of the value class itself, as was originally done. * diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala index 12b765b7a6..ef22df3f2e 100644 --- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -32,7 +32,7 @@ trait Variances { /** Is every symbol in the owner chain between `site` and the owner of `sym` * either a term symbol or private[this]? If not, add `sym` to the set of - * esacped locals. + * escaped locals. * @pre sym.isLocalToThis */ @tailrec final def checkForEscape(sym: Symbol, site: Symbol) { diff --git a/src/reflect/scala/reflect/internal/annotations/uncheckedBounds.scala b/src/reflect/scala/reflect/internal/annotations/uncheckedBounds.scala index a44bb54734..662d841c91 100644 --- a/src/reflect/scala/reflect/internal/annotations/uncheckedBounds.scala +++ b/src/reflect/scala/reflect/internal/annotations/uncheckedBounds.scala @@ -5,7 +5,7 @@ package annotations /** * An annotation that designates the annotated type should not be checked for violations of * type parameter bounds in the `refchecks` phase of the compiler. This can be used by synthesized - * code the uses an inferred type of an expression as the type of an artifict val/def (for example, + * code the uses an inferred type of an expression as the type of an artifact val/def (for example, * a temporary value introduced by an ANF transform). See [[https://issues.scala-lang.org/browse/SI-7694]]. * * @since 2.10.3 diff --git a/src/reflect/scala/reflect/internal/tpe/FindMembers.scala b/src/reflect/scala/reflect/internal/tpe/FindMembers.scala index de54f3768e..42b13944f6 100644 --- a/src/reflect/scala/reflect/internal/tpe/FindMembers.scala +++ b/src/reflect/scala/reflect/internal/tpe/FindMembers.scala @@ -12,7 +12,7 @@ import TypesStats._ trait FindMembers { this: SymbolTable => - /** Implementatation of `Type#{findMember, findMembers}` */ + /** Implementation 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 diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala index c1c43178e5..f79099213a 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala @@ -75,7 +75,7 @@ private[internal] trait TypeConstraints { /* Syncnote: Type constraints are assumed to be used from only one * thread. They are not exposed in api.Types and are used only locally * in operations that are exposed from types. Hence, no syncing of any - * variables should be ncessesary. + * variables should be necessary. */ /** Guard these lists against AnyClass and NothingClass appearing, diff --git a/src/reflect/scala/reflect/internal/util/WeakHashSet.scala b/src/reflect/scala/reflect/internal/util/WeakHashSet.scala index a9a7c7780d..3a7a7626fb 100644 --- a/src/reflect/scala/reflect/internal/util/WeakHashSet.scala +++ b/src/reflect/scala/reflect/internal/util/WeakHashSet.scala @@ -7,13 +7,13 @@ import scala.collection.generic.Clearable import scala.collection.mutable.{Set => MSet} /** - * A HashSet where the elements are stored weakly. Elements in this set are elligible for GC if no other + * A HashSet where the elements are stored weakly. Elements in this set are eligible for GC if no other * hard references are associated with them. Its primary use case is as a canonical reference * identity holder (aka "hash-consing") via findEntryOrUpdate * * This Set implementation cannot hold null. Any attempt to put a null in it will result in a NullPointerException * - * This set implmeentation is not in general thread safe without external concurrency control. However it behaves + * This set implementation is not in general thread safe without external concurrency control. However it behaves * properly when GC concurrently collects elements in this set. */ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: Double) extends Set[A] with Function1[A, Boolean] with MSet[A] { @@ -26,7 +26,7 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D /** * queue of Entries that hold elements scheduled for GC - * the removeStaleEntries() method works through the queue to remeove + * the removeStaleEntries() method works through the queue to remove * stale entries from the table */ private[this] val queue = new ReferenceQueue[A] @@ -62,7 +62,7 @@ final class WeakHashSet[A <: AnyRef](val initialCapacity: Int, val loadFactor: D private[this] def computeThreshHold: Int = (table.size * loadFactor).ceil.toInt /** - * find the bucket associated with an elements's hash code + * find the bucket associated with an element's hash code */ private[this] def bucketFor(hash: Int): Int = { // spread the bits around to try to avoid accidental collisions using the diff --git a/src/reflect/scala/reflect/macros/Enclosures.scala b/src/reflect/scala/reflect/macros/Enclosures.scala index 69ede42cc7..1eb6832b5b 100644 --- a/src/reflect/scala/reflect/macros/Enclosures.scala +++ b/src/reflect/scala/reflect/macros/Enclosures.scala @@ -47,7 +47,7 @@ trait Enclosures { /** Tries to guess a position for the enclosing application. * But that is simple, right? Just dereference `pos` of `macroApplication`? Not really. - * If we're in a synthetic macro expansion (no positions), we must do our best to infer the position of something that triggerd this expansion. + * If we're in a synthetic macro expansion (no positions), we must do our best to infer the position of something that triggered this expansion. * Surprisingly, quite often we can do this by navigation the `enclosingMacros` stack. */ def enclosingPosition: Position diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index 1eb67215bb..3b57169565 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -44,7 +44,7 @@ abstract class Universe extends scala.reflect.api.Universe { * it is imperative that you either call `untypecheck` or do `changeOwner(tree, x, y)`. * * Since at the moment `untypecheck` has fundamental problem that can sometimes lead to tree corruption, - * `changeOwner` becomes an indispensible tool in building 100% robust macros. + * `changeOwner` becomes an indispensable tool in building 100% robust macros. * Future versions of the reflection API might obviate the need in taking care of * these low-level details, but at the moment this is what we've got. */ diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index a0da3f3bbf..1c751fb93b 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -38,7 +38,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive override lazy val rootMirror: Mirror = createMirror(NoSymbol, rootClassLoader) - // overriden by ReflectGlobal + // overridden by ReflectGlobal def rootClassLoader: ClassLoader = this.getClass.getClassLoader trait JavaClassCompleter diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index c87b810bdd..1c0aa7cf6d 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -310,6 +310,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.QuasiquoteClass_api_unapply definitions.ScalaSignatureAnnotation definitions.ScalaLongSignatureAnnotation + definitions.MethodHandle definitions.OptionClass definitions.OptionModule definitions.SomeClass diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 6d0cb0df45..4f0c0253e9 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -39,7 +39,7 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb * 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 + * initialization 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, @@ -102,10 +102,10 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb * * 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. + * that effectively 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. + * is going to spuriously call `initialize`, which is either a gil-protected operation (if the symbol isn't initialized yet) + * or a no-op (if the symbol is already initialized), 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). diff --git a/src/repl/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala b/src/repl/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala index e66e4eff29..df49e6a2e4 100644 --- a/src/repl/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala +++ b/src/repl/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala @@ -30,7 +30,7 @@ class AbstractOrMissingHandler[T](onError: String => Unit, value: T) extends Par |Failed to initialize compiler: %s not found. |** Note that as of 2.8 scala does not assume use of the java classpath. |** For the old behavior pass -usejavacp to scala, or if using a Settings - |** object programatically, settings.usejavacp.value = true.""".stripMargin.format(x.req) + |** object programmatically, settings.usejavacp.value = true.""".stripMargin.format(x.req) ) value } diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index f9f7388363..0347622cf4 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -45,7 +45,7 @@ import java.io.File * all variables defined by that code. To extract the result of an * interpreted line to show the user, a second "result object" is created * which imports the variables exported by the above object and then - * exports members called "$eval" and "$print". To accomodate user expressions + * exports members called "$eval" and "$print". To accommodate user expressions * that read from variables or methods defined in previous statements, "import" * statements are used. * diff --git a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala index ebca3e7e62..c80b94bf89 100644 --- a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala +++ b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala @@ -656,7 +656,7 @@ object JavapClass { // FunFinder.funs(ks) finds anonfuns class FunFinder(loader: ScalaClassLoader, intp: Option[IMain]) { - // manglese for closure: typename, $anonfun or lamba, opt method, digits + // manglese for closure: typename, $anonfun or lambda, opt method, digits val closure = """(.*)\$(\$anonfun|lambda)(?:\$+([^$]+))?\$(\d+)""".r // manglese for closure @@ -743,7 +743,7 @@ object JavapClass { case _ => Nil } val res = fs map (_.to[Seq]) getOrElse Seq() - // on second thought, we don't care about lamba method classes, just the impl methods + // on second thought, we don't care about lambda method classes, just the impl methods val rev = res flatMap { case x @ closure(_, "lambda", _, _) => labdaMethod(x, target) @@ -787,7 +787,7 @@ object JavapClass { } } /** Translate the supplied targets to patterns for anonfuns. - * Pattern is typename $ label [[$]$func] $n where label is $anonfun or lamba, + * Pattern is typename $ label [[$]$func] $n where label is $anonfun or lambda, * and lambda includes the extra dollar, func is a method name, and n is an int. * The typename for a nested class is dollar notation, Betty$Bippy. * diff --git a/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala b/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala index f177816b30..9f555aee14 100644 --- a/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala +++ b/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala @@ -80,7 +80,7 @@ trait LoopCommands { def recording(line: String) = Result(keepRunning = true, Option(line)) // most commands do not want to micromanage the Result, but they might want - // to print something to the console, so we accomodate Unit and String returns. + // to print something to the console, so we accommodate Unit and String returns. implicit def resultFromUnit(x: Unit): Result = default implicit def resultFromString(msg: String): Result = { echoCommandMessage(msg) diff --git a/src/repl/scala/tools/nsc/interpreter/Power.scala b/src/repl/scala/tools/nsc/interpreter/Power.scala index f69a5b487d..8d8140b638 100644 --- a/src/repl/scala/tools/nsc/interpreter/Power.scala +++ b/src/repl/scala/tools/nsc/interpreter/Power.scala @@ -155,7 +155,7 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re } object InternalInfo extends LowPriorityInternalInfo { } - /** Now dealing with the problem of acidentally calling a method on Type + /** Now dealing with the problem of accidentally calling a method on Type * when you're holding a Symbol and seeing the Symbol converted to the * type of Symbol rather than the type of the thing represented by the * symbol, by only implicitly installing one method, "?", and the rest diff --git a/src/scaladoc/scala/tools/ant/Scaladoc.scala b/src/scaladoc/scala/tools/ant/Scaladoc.scala index 36a1405b11..034416e844 100644 --- a/src/scaladoc/scala/tools/ant/Scaladoc.scala +++ b/src/scaladoc/scala/tools/ant/Scaladoc.scala @@ -543,7 +543,7 @@ class Scaladoc extends ScalaMatchingTask { /** Tests if a file exists and prints a warning in case it doesn't. Always * returns the file, even if it doesn't exist. * - * @param file A file to test for existance. + * @param file A file to test for existence. * @return The same file. */ private def existing(file: File): File = { diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.js index 478f2e38ac..680ead7a59 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.js +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.js @@ -25,7 +25,7 @@ $(document).ready(function() $(".diagram-container").css("display", "block"); $(".diagram").each(function() { - // store inital dimensions + // store initial dimensions $(this).data("width", $("svg", $(this)).width()); $(this).data("height", $("svg", $(this)).height()); // store unscaled clone of SVG element diff --git a/src/scaladoc/scala/tools/nsc/doc/model/Entity.scala b/src/scaladoc/scala/tools/nsc/doc/model/Entity.scala index 6932f01e9a..7fe8903c76 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/Entity.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/Entity.scala @@ -117,7 +117,7 @@ trait MemberEntity extends Entity { def toRoot: List[MemberEntity] /** The templates in which this member has been declared. The first element of the list is the template that contains - * the currently active declaration of this member, subsequent elements are declarations that have been overriden. If + * the currently active declaration of this member, subsequent elements are declarations that have been overridden. If * the first element is equal to `inTemplate`, the member is declared locally, if not, it has been inherited. All * elements of this list are in the linearization of `inTemplate`. */ def inDefinitionTemplates: List[TemplateEntity] diff --git a/test/benchmarks/src/scala/collection/parallel/benchmarks/Bench.scala b/test/benchmarks/src/scala/collection/parallel/benchmarks/Bench.scala index e8dfe0ac50..c20bbaeef1 100644 --- a/test/benchmarks/src/scala/collection/parallel/benchmarks/Bench.scala +++ b/test/benchmarks/src/scala/collection/parallel/benchmarks/Bench.scala @@ -78,7 +78,7 @@ trait Bench extends Benchmark { } /** - * Prints results of the benchmark. May be overidden in benchmarks. + * Prints results of the benchmark. May be overridden in benchmarks. */ def printResults {} diff --git a/test/files/jvm/innerClassAttribute/Test.scala b/test/files/jvm/innerClassAttribute/Test.scala index 1c1a0522e4..3820048cb4 100644 --- a/test/files/jvm/innerClassAttribute/Test.scala +++ b/test/files/jvm/innerClassAttribute/Test.scala @@ -84,17 +84,15 @@ object Test extends BytecodeTest { } def testA3() = { - def t(c: String) = { - val List(b1, b2) = innerClassNodes(c) - // the outer class for classes nested inside top-level modules is not the module class, but the mirror class. - // this is a hack for java interop, handled in the backend. see BTypes.scala, comment on "Java Compatibility". - assertMember(b1, "A3", "B1", flags = publicStatic) - assertMember(b2, "A3", "B2$", flags = publicStatic) - } - t("A3$") - // the mirror class has the same inner class attributes as the module - // class (added when the mirror is created in the backend) - t("A3") + // the inner class entries for top-level object members are in the companion class, so nothing in the module class + val List() = innerClassNodes("A3$") + + // inner class entries in the companion class (a backend-generated mirror class in this case) + val List(b1, b2) = innerClassNodes("A3") + // the outer class for classes nested inside top-level modules is not the module class, but the mirror class. + // this is a hack for java interop, handled in the backend. see BTypes.scala, comment on "Java Compatibility". + assertMember(b1, "A3", "B1", flags = publicStatic) + assertMember(b2, "A3", "B2$", flags = publicStatic) } def testA4() = { @@ -164,7 +162,10 @@ object Test extends BytecodeTest { } def testA15() = { - val List(b) = innerClassNodes("A15") + // no member classes, only anonymous / local. these are nested in the module class, not the companion. + val List() = innerClassNodes("A15") + + val List(b) = innerClassNodes("A15$") assertLocal(b, "A15$B$3", "B$3") val List(_, c) = innerClassNodes("A15$B$3") @@ -283,9 +284,7 @@ object Test extends BytecodeTest { assertMember(i3c, "A21", "I3$", flags = publicStatic) assertLocal(j1, "A21$J1$1", "J1$1") - val List(i2m, i3m, j3, j4, j5) = innerClassNodes("A21$") - assertMember(i2m, "A21", "I2", flags = publicStatic) - assertMember(i3m, "A21", "I3$", flags = publicStatic) + val List(j3, j4, j5) = innerClassNodes("A21$") assertLocal(j3, "A21$J3$1", "J3$1") assertLocal(j4, "A21$J4$1", "J4$1") assertLocal(j5, "A21$J5$1", "J5$1") // non-static! diff --git a/test/files/jvm/t8582.check b/test/files/jvm/t8582.check index 564f482ff8..e388366270 100644 --- a/test/files/jvm/t8582.check +++ b/test/files/jvm/t8582.check @@ -14,10 +14,10 @@ Reflection can find direct nested classes (A2-B2-C2) A2$B2: List(class A2$B2$C2) A2$B2$C2: List() -Mirror classes have the same InnerClass attributes as the corresponding module class: - className[p1/p2/Singleton$Singleton$] outerClassName[p1/p2/Singleton] innerName[Singleton$] access[9] -Module class +The InnerClass attribute of a mirror class contains the members of the module class: className[p1/p2/Singleton$Singleton$] outerClassName[p1/p2/Singleton] innerName[Singleton$] access[9] +The module members are not in the InnerClass table of the module class (unless referenced): + An outer class has a InnerClass attribute for direct nested classes className[A1$B1] outerClassName[A1] innerName[B1] access[1] diff --git a/test/files/jvm/t8582.scala b/test/files/jvm/t8582.scala index 8a57ef7952..e9a01f9016 100644 --- a/test/files/jvm/t8582.scala +++ b/test/files/jvm/t8582.scala @@ -55,9 +55,9 @@ object Test extends BytecodeTest { println(nested(classOf[A2#B2])) println(nested(classOf[A2#B2#C2])) - nprintln("Mirror classes have the same InnerClass attributes as the corresponding module class:") + nprintln("The InnerClass attribute of a mirror class contains the members of the module class:") printInner("p1.p2.Singleton") // mirror class - println("Module class") + println("The module members are not in the InnerClass table of the module class (unless referenced):") printInner("p1.p2.Singleton$") nprintln("An outer class has a InnerClass attribute for direct nested classes") diff --git a/test/files/jvm/t9044.scala b/test/files/jvm/t9044.scala new file mode 100644 index 0000000000..b1073325e8 --- /dev/null +++ b/test/files/jvm/t9044.scala @@ -0,0 +1,6 @@ +trait A +trait B +object Test extends A with B with App { + val is = Test.getClass.getInterfaces.mkString(", ") + assert(is == "interface A, interface B, interface scala.App", is) +} diff --git a/test/files/neg/literate_existentials.scala b/test/files/neg/literate_existentials.scala index 8580347bf9..5537c50b3a 100644 --- a/test/files/neg/literate_existentials.scala +++ b/test/files/neg/literate_existentials.scala @@ -187,7 +187,7 @@ object LiterateExistentials { // implicitly[Int <:< (M forSome { type M >: Nothing <: String })] // fails -// The preceeding line causes the compiler to generate an error message. +// The preceding line causes the compiler to generate an error message. diff --git a/test/files/neg/structural.scala b/test/files/neg/structural.scala index d783399317..00459676a9 100644 --- a/test/files/neg/structural.scala +++ b/test/files/neg/structural.scala @@ -11,13 +11,13 @@ object Test extends App { def f2[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: B): Object; val x: B }) = x.m[Tata](x.x) //fail def f3[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: C): Object; val x: C }) = x.m[Tata](x.x) //fail def f4[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: D): Object; val x: D }) = x.m[Tata](x.x) //fail - def f5[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: E): Object; val x: Tata }) = x.m[Tata](x.x) //suceed + def f5[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: E): Object; val x: Tata }) = x.m[Tata](x.x) //succeeds - def f6[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): A }) = x.m[Tata](null) //suceed - def f7[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): B }) = x.m[Tata](null) //suceed - def f8[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): C }) = x.m[Tata](null) //suceed + def f6[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): A }) = x.m[Tata](null) //succeeds + def f7[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): B }) = x.m[Tata](null) //succeeds + def f8[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): C }) = x.m[Tata](null) //succeeds def f9[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): D }) = x.m[Tata](null) //fail - def f0[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): E }) = x.m[Tata](null) //suceed + def f0[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): E }) = x.m[Tata](null) //succeeds } diff --git a/test/files/neg/t7623.check b/test/files/neg/t7623.check new file mode 100644 index 0000000000..db368dd369 --- /dev/null +++ b/test/files/neg/t7623.check @@ -0,0 +1,21 @@ +t7623.scala:19: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def f = "" match { case X(s) => } + ^ +t7623.scala:21: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def g = "" match { case X(s, t) => } + ^ +t7623.scala:23: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def h = "" match { case X(s, t, u @ _*) => } + ^ +t7623.scala:9: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def f = C("") match { case C(s) => } + ^ +t7623.scala:11: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def g = C("") match { case C(s, t) => } + ^ +t7623.scala:13: warning: A repeated case parameter or extracted sequence should be matched only by a sequence wildcard (_*). + def h = C("") match { case C(s, t, u @ _*) => } + ^ +error: No warnings can be incurred under -Xfatal-warnings. +6 warnings found +one error found diff --git a/test/files/neg/t7623.flags b/test/files/neg/t7623.flags new file mode 100644 index 0000000000..74c9e38323 --- /dev/null +++ b/test/files/neg/t7623.flags @@ -0,0 +1 @@ +-Xlint:stars-align -Xfatal-warnings diff --git a/test/files/neg/t7623.scala b/test/files/neg/t7623.scala new file mode 100644 index 0000000000..5c40f37bc1 --- /dev/null +++ b/test/files/neg/t7623.scala @@ -0,0 +1,38 @@ + + +case class C(s: String, xs: Int*) + +object X { def unapplySeq(a: Any): Option[(String, Seq[Int])] = Some("", List(1,2,3)) } + +// for case classes with varargs, avoid misaligned patterns +trait Ctest { + def f = C("") match { case C(s) => } + + def g = C("") match { case C(s, t) => } + + def h = C("") match { case C(s, t, u @ _*) => } + + def ok = C("") match { case C(s, u @ _*) => } +} +// for extractors that unapplySeq: Option[(Something, Seq[_])], avoid misaligned patterns +trait Xtest { + def f = "" match { case X(s) => } + + def g = "" match { case X(s, t) => } + + def h = "" match { case X(s, t, u @ _*) => } + + def ok = "" match { case X(s, u @ _*) => } +} +// for extractors that unapplySeq: Option[Seq[_]], anything goes +trait Rtest { + val r = "(a+)".r + + def f = "" match { case r(s) => } + + def g = "" match { case r(s, t) => } + + def h = "" match { case r(s, t, u @ _*) => } + + def whatever = "" match { case r(u @ _*) => } +} diff --git a/test/files/neg/t9093.check b/test/files/neg/t9093.check new file mode 100644 index 0000000000..085a433f0b --- /dev/null +++ b/test/files/neg/t9093.check @@ -0,0 +1,6 @@ +t9093.scala:3: error: polymorphic expression cannot be instantiated to expected type; + found : [C](f: C)Null + required: Unit + val x: Unit = apply2(0)/*(0)*/ + ^ +one error found diff --git a/test/files/neg/t9093.scala b/test/files/neg/t9093.scala new file mode 100644 index 0000000000..d9922ad70e --- /dev/null +++ b/test/files/neg/t9093.scala @@ -0,0 +1,5 @@ +object Main { + def apply2[C](fa: Any)(f: C) = null + val x: Unit = apply2(0)/*(0)*/ +} + diff --git a/test/files/pos/patmat-suppress.flags b/test/files/pos/patmat-suppress.flags new file mode 100644 index 0000000000..a988a5b807 --- /dev/null +++ b/test/files/pos/patmat-suppress.flags @@ -0,0 +1 @@ +-Xfatal-warnings -Xno-patmat-analysis
\ No newline at end of file diff --git a/test/files/pos/patmat-suppress.scala b/test/files/pos/patmat-suppress.scala new file mode 100644 index 0000000000..7c8aded690 --- /dev/null +++ b/test/files/pos/patmat-suppress.scala @@ -0,0 +1,159 @@ +// test that none of these warn due to -Xno-patmat-analysis +// tests taken from test/files/neg/patmatexhaust.scala, test/files/neg/pat_unreachable.scala +class TestSealedExhaustive { // compile only + sealed abstract class Foo + + case class Bar(x:Int) extends Foo + case object Baz extends Foo + + def ma1(x:Foo) = x match { + case Bar(_) => // not exhaustive + } + + def ma2(x:Foo) = x match { + case Baz => // not exhaustive + } + + sealed abstract class Mult + case class Kult(s:Mult) extends Mult + case class Qult() extends Mult + + def ma33(x:Kult) = x match { // exhaustive + case Kult(_) => // exhaustive + } + + def ma3(x:Mult) = (x,x) match { // not exhaustive + case (Kult(_), Qult()) => // Kult missing + //case (Kult(_), Kult(_)) => + case (Qult(), Kult(_)) => // Qult missing + //case (Qult(), Qult()) => + } + + def ma3u(x:Mult) = ((x,x) : @unchecked) match { // not exhaustive, but not checked! + case (Kult(_), Qult()) => + case (Qult(), Kult(_)) => + } + + sealed abstract class Deep + + case object Ga extends Deep + sealed class Gp extends Deep + case object Gu extends Gp + + def zma3(x:Deep) = x match { // exhaustive! + case _ => + } + def zma4(x:Deep) = x match { // exhaustive! + case Ga => + case _ => + } + + def ma4(x:Deep) = x match { // missing cases: Gu, Gp which is not abstract so must be included + case Ga => + } + + def ma5(x:Deep) = x match { + case Gu => + case _ if 1 == 0 => + case Ga => + } + + def ma6() = List(1,2) match { // give up + case List(1,2) => + case x :: xs => + } + + def ma7() = List(1,2) match { //exhaustive + case 1::2::Nil => + case _ => + } + + sealed class B + case class B1() extends B + case object B2 extends B + def ma8(x: B) = x match { + case _: B => true + } + def ma9(x: B) = x match { + case B1() => true // missing B, which is not abstract so must be included + case B2 => true + } + + object ob1 { + sealed abstract class C + sealed abstract class C1 extends C + object C2 extends C + case class C3() extends C + case object C4 extends C + + def ma10(x: C) = x match { // exhaustive: abstract sealed C1 is dead end. + case C3() => true + case C2 | C4 => true + } + } + + object ob2 { + sealed abstract class C + abstract class C1 extends C + object C2 extends C + case class C3() extends C + case object C4 extends C + + def ma10(x: C) = x match { // not exhaustive: C1 is not sealed. + case C3() => true + case C2 | C4 => true + } + } + object ob3 { + sealed abstract class C + sealed abstract class C1 extends C + object D1 extends C1 + case class D2() extends C1 + object C2 extends C + case class C3() extends C + case object C4 extends C + + def ma10(x: C) = x match { // not exhaustive: C1 has subclasses. + case C3() => true + case C2 | C4 => true + } + } + object ob4 { + sealed abstract class C + sealed class C1 extends C + object C2 extends C + case class C3() extends C + case object C4 extends C + + def ma10(x: C) = x match { // not exhaustive: C1 is not abstract. + case C3() => true + case C2 | C4 => true + } + } +} + +object TestUnreachable extends App { + def unreachable1(xs:Seq[Char]) = xs match { + case Seq(x, y, _*) => x::y::Nil + case Seq(x, y, z, w) => List(z,w) // redundant! + } + def unreachable2(xs:Seq[Char]) = xs match { + case Seq(x, y, _*) => x::y::Nil + case Seq(x, y) => List(x, y) + } + + def not_unreachable(xs:Seq[Char]) = xs match { + case Seq(x, y, _*) => x::y::Nil + case Seq(x) => List(x) + } + def not_unreachable2(xs:Seq[Char]) = xs match { + case Seq(x, y) => x::y::Nil + case Seq(x, y, z, _*) => List(x,y) + } + + def contrivedExample[A, B, C](a: A, b: B, c: C): Unit = a match { + case b => println("matched b") + case c => println("matched c") + case _ => println("matched neither") + } +} diff --git a/test/files/pos/t4070.scala b/test/files/pos/t4070.scala index a9777f02ed..11af67a529 100644 --- a/test/files/pos/t4070.scala +++ b/test/files/pos/t4070.scala @@ -20,7 +20,7 @@ package b { /* -// With crash below the clasess: +// With crash below the classes: % scalac -Dscalac.debug.tvar ./a.scala [ create] ?_$1 ( In Foo#crash ) [ setInst] tv[Int] ( In Foo#crash, _$1=tv[Int] ) diff --git a/test/files/pos/t5154.scala b/test/files/pos/t5154.scala new file mode 100644 index 0000000000..2629308f00 --- /dev/null +++ b/test/files/pos/t5154.scala @@ -0,0 +1,9 @@ + +trait Z { + // extra space made the pattern OK + def f = <z> {{3}}</z> match { case <z> {{3}}</z> => } + + // lack of space: error: illegal start of simple pattern + def g = <z>{{3}}</z> match { case <z>{{3}}</z> => } +} + diff --git a/test/files/pos/t7459a.scala b/test/files/pos/t7459a.scala new file mode 100644 index 0000000000..5107715e06 --- /dev/null +++ b/test/files/pos/t7459a.scala @@ -0,0 +1,18 @@ +trait SpecialException extends Throwable + +object Test { + def run() { + try { + ??? + } catch { + case e: SpecialException => e.isInstanceOf[SpecialException] + case e => + } + + // OKAY + // (null: Throwable) match { + // case e: SpecialException => e.isInstanceOf[SpecialException] + // case e => + // } + } +}
\ No newline at end of file diff --git a/test/files/pos/t7459b.scala b/test/files/pos/t7459b.scala new file mode 100644 index 0000000000..a4b4fd07a9 --- /dev/null +++ b/test/files/pos/t7459b.scala @@ -0,0 +1,12 @@ +import scala.concurrent._ +import scala.util._ + + +class Test { + (null: Any) match { + case s @ Some(_) => ??? + case f @ _ => + () => f + ??? + } +}
\ No newline at end of file diff --git a/test/files/pos/t7459c.scala b/test/files/pos/t7459c.scala new file mode 100644 index 0000000000..dc2605abe6 --- /dev/null +++ b/test/files/pos/t7459c.scala @@ -0,0 +1,18 @@ +object Test { + trait Universe { + type Type + type TypeTag[A] >: Null <: TypeTagApi[A] + trait TypeTagApi[A] { def tpe: Type } + } + trait JavaUniverse extends Universe + + trait Mirror[U <: Universe] { + def universe: U + } + (null: Mirror[_]).universe match { + case ju: JavaUniverse => + val ju1 = ju + val f = {() => (null: ju.TypeTag[Nothing]).tpe } + } + trait M[A] +} diff --git a/test/files/pos/t7459d.scala b/test/files/pos/t7459d.scala new file mode 100644 index 0000000000..7843156885 --- /dev/null +++ b/test/files/pos/t7459d.scala @@ -0,0 +1,8 @@ +class Test { + (null: Any) match { + case s @ Some(_) => ??? + case f @ _ => + () => f + ??? + } +} diff --git a/test/files/pos/t7704.scala b/test/files/pos/t7704.scala new file mode 100644 index 0000000000..cae88d3324 --- /dev/null +++ b/test/files/pos/t7704.scala @@ -0,0 +1,10 @@ +class Attr { type V ; class Val } +class StrAttr extends Attr { type V = String } +class BoolAttr extends Attr { type V = Boolean } + +object Main { + def f(x: Attr) = x match { + case v: StrAttr => new v.Val + case v: BoolAttr => new v.Val + } +} diff --git a/test/files/pos/t8828.scala b/test/files/pos/t8828.scala index 92092b4dd4..182aba54c0 100644 --- a/test/files/pos/t8828.scala +++ b/test/files/pos/t8828.scala @@ -11,7 +11,7 @@ package inner { } // the trait is sealed and doWork is not - // and cannot be overriden: no warning + // and cannot be overridden: no warning private[outer] sealed trait C { def doWork(a: A): A = a } diff --git a/test/files/pos/t8999.flags b/test/files/pos/t8999.flags new file mode 100644 index 0000000000..0f96f1f872 --- /dev/null +++ b/test/files/pos/t8999.flags @@ -0,0 +1 @@ +-nowarn
\ No newline at end of file diff --git a/test/files/pos/t8999.scala b/test/files/pos/t8999.scala new file mode 100644 index 0000000000..99c4b2ad84 --- /dev/null +++ b/test/files/pos/t8999.scala @@ -0,0 +1,271 @@ +object Types { + + abstract sealed class Type + + case object AnyType extends Type + + case object NothingType extends Type + + case object UndefType extends Type + + case object BooleanType extends Type + + case object IntType extends Type + + case object LongType extends Type + + case object FloatType extends Type + + case object DoubleType extends Type + + case object StringType extends Type + + case object NullType extends Type + + sealed abstract class ReferenceType extends Type + + final case class ClassType(className: String) extends ReferenceType + + final case class ArrayType(baseClassName: String, dimensions: Int) extends ReferenceType + + final case class RecordType(fields: List[RecordType.Field]) extends Type + + object RecordType { + final case class Field(name: String, originalName: Option[String], + tpe: Type, mutable: Boolean) + } + + case object NoType extends Type + +} + + +sealed abstract class ClassKind + +object ClassKind { + + case object Class extends ClassKind + + case object ModuleClass extends ClassKind + + case object Interface extends ClassKind + + case object RawJSType extends ClassKind + + case object HijackedClass extends ClassKind + + case object TraitImpl extends ClassKind + +} + +object Trees { + + import Types._ + + abstract sealed class Tree + + case object EmptyTree extends Tree + + sealed trait PropertyName + case class Ident(name: String, originalName: Option[String]) extends PropertyName + object Ident { + def apply(name: String): Ident = + new Ident(name, Some(name)) + } + + case class VarDef(name: Ident, vtpe: Type, mutable: Boolean, rhs: Tree) extends Tree + + case class ParamDef(name: Ident, ptpe: Type, mutable: Boolean) extends Tree + + case class Skip() extends Tree + + class Block private(val stats: List[Tree]) extends Tree + + object Block { + def unapply(block: Block): Some[List[Tree]] = Some(block.stats) + } + + case class Labeled(label: Ident, tpe: Type, body: Tree) extends Tree + + case class Assign(lhs: Tree, rhs: Tree) extends Tree + + case class Return(expr: Tree, label: Option[Ident] = None) extends Tree + + case class If(cond: Tree, thenp: Tree, elsep: Tree) extends Tree + + case class While(cond: Tree, body: Tree, label: Option[Ident] = None) extends Tree + + case class DoWhile(body: Tree, cond: Tree, label: Option[Ident] = None) extends Tree + + case class Try(block: Tree, errVar: Ident, handler: Tree, finalizer: Tree) extends Tree + + case class Throw(expr: Tree) extends Tree + + case class Continue(label: Option[Ident] = None) extends Tree + + case class Match(selector: Tree, cases: List[(List[Literal], Tree)], default: Tree) extends Tree + + case class Debugger() extends Tree + + case class New(cls: ClassType, ctor: Ident, args: List[Tree]) extends Tree + + case class LoadModule(cls: ClassType) extends Tree + + case class StoreModule(cls: ClassType, value: Tree) extends Tree + + case class Select(qualifier: Tree, item: Ident, mutable: Boolean) extends Tree + + case class Apply(receiver: Tree, method: Ident, args: List[Tree]) extends Tree + + case class StaticApply(receiver: Tree, cls: ClassType, method: Ident, args: List[Tree]) extends Tree + + case class TraitImplApply(impl: ClassType, method: Ident, args: List[Tree]) extends Tree + + case class UnaryOp(op: Int, lhs: Tree) extends Tree + + case class BinaryOp(op: Int, lhs: Tree, rhs: Tree) extends Tree + + case class NewArray(tpe: ArrayType, lengths: List[Tree]) extends Tree + + case class ArrayValue(tpe: ArrayType, elems: List[Tree]) extends Tree + + case class ArrayLength(array: Tree) extends Tree + + case class ArraySelect(array: Tree, index: Tree) extends Tree + + case class RecordValue(tpe: RecordType, elems: List[Tree]) extends Tree + + case class IsInstanceOf(expr: Tree, cls: ReferenceType) extends Tree + + case class AsInstanceOf(expr: Tree, cls: ReferenceType) extends Tree + + case class Unbox(expr: Tree, charCode: Char) extends Tree + + case class GetClass(expr: Tree) extends Tree + + case class CallHelper(helper: String, args: List[Tree]) extends Tree + + case class JSNew(ctor: Tree, args: List[Tree]) extends Tree + + case class JSDotSelect(qualifier: Tree, item: Ident) extends Tree + + case class JSBracketSelect(qualifier: Tree, item: Tree) extends Tree + + case class JSFunctionApply(fun: Tree, args: List[Tree]) extends Tree + + case class JSDotMethodApply(receiver: Tree, method: Ident, args: List[Tree]) extends Tree + + case class JSBracketMethodApply(receiver: Tree, method: Tree, args: List[Tree]) extends Tree + + case class JSDelete(prop: Tree) extends Tree + + case class JSUnaryOp(op: String, lhs: Tree) extends Tree + + case class JSBinaryOp(op: String, lhs: Tree, rhs: Tree) extends Tree + + case class JSArrayConstr(items: List[Tree]) extends Tree + + case class JSObjectConstr(fields: List[(PropertyName, Tree)]) extends Tree + + case class JSEnvInfo() extends Tree + + sealed trait Literal extends Tree + + case class Undefined() extends Literal + + case class UndefinedParam() extends Literal + + case class Null() extends Literal + + case class BooleanLiteral(value: Boolean) extends Literal + + case class IntLiteral(value: Int) extends Literal + + case class LongLiteral(value: Long) extends Literal + + case class FloatLiteral(value: Float) extends Literal + + case class DoubleLiteral(value: Double) extends Literal + + case class StringLiteral(value: String) extends Literal with PropertyName + + case class ClassOf(cls: ReferenceType) extends Literal + + case class VarRef(ident: Ident, mutable: Boolean) extends Tree + + case class This() extends Tree + + case class Closure(captureParams: List[ParamDef], params: List[ParamDef], + body: Tree, captureValues: List[Tree]) extends Tree + + case class ClassDef(name: Ident, kind: ClassKind, parent: Option[Ident], ancestors: List[Ident], defs: List[Tree]) extends Tree + + case class MethodDef(name: PropertyName, args: List[ParamDef], resultType: Type, body: Tree) extends Tree + + case class PropertyDef(name: PropertyName, getterBody: Tree, setterArg: ParamDef, setterBody: Tree) extends Tree + + case class ConstructorExportDef(name: String, args: List[ParamDef], body: Tree) extends Tree + + case class ModuleExportDef(fullName: String) extends Tree + + final class TreeHash(val treeHash: Array[Byte], val posHash: Array[Byte]) +} + +object Main { + import Trees._ + import Types._ + + private def transform(tree: Tree) = { + val ObjectClass = "O" + tree match { + case VarDef(_, _, _, rhs) => + case tree: Block => + case Labeled(ident@Ident(label, _), tpe, body) => + case Assign(lhs, rhs) => + case Return(expr, optLabel) => + case If(cond, thenp, elsep) => + case While(cond, body, optLabel) => + case DoWhile(body, cond, None) => + case Try(block, errVar, EmptyTree, finalizer) => + case Try(block, errVar@Ident(name, originalName), handler, finalizer) => + case Throw(expr) => + case Continue(optLabel) => + case Match(selector, cases, default) => + case New(cls, ctor, args) => + case StoreModule(cls, value) => + case tree: Select => + case tree: Apply => + case tree: StaticApply => + case tree: TraitImplApply => + case tree@UnaryOp(_, arg) => + case tree@BinaryOp(op, lhs, rhs) => + case NewArray(tpe, lengths) => + case ArrayValue(tpe, elems) => + case ArrayLength(array) => + case ArraySelect(array, index) => + case RecordValue(tpe, elems) => + case IsInstanceOf(expr, ClassType(ObjectClass)) => + case IsInstanceOf(expr, tpe) => + case AsInstanceOf(expr, ClassType(ObjectClass)) => + case AsInstanceOf(expr, cls) => + case Unbox(arg, charCode) => + case GetClass(expr) => + case JSNew(ctor, args) => + case JSDotSelect(qualifier, item) => + case JSBracketSelect(qualifier, item) => + case tree: JSFunctionApply => + case JSDotMethodApply(receiver, method, args) => + case JSBracketMethodApply(receiver, method, args) => + case JSDelete(JSDotSelect(obj, prop)) => + case JSDelete(JSBracketSelect(obj, prop)) => + case JSUnaryOp(op, lhs) => + case JSBinaryOp(op, lhs, rhs) => + case JSArrayConstr(items) => + case JSObjectConstr(fields) => + case _: VarRef | _: This => + case Closure(captureParams, params, body, captureValues) => + case _: Skip | _: Debugger | _: LoadModule | + _: JSEnvInfo | _: Literal | EmptyTree => + } + } +}
\ No newline at end of file diff --git a/test/files/pos/t9050.scala b/test/files/pos/t9050.scala new file mode 100644 index 0000000000..b1ab09f901 --- /dev/null +++ b/test/files/pos/t9050.scala @@ -0,0 +1,13 @@ +final class Mu[F](val value: Any) extends AnyVal { + def cata(f: F) { + // crash + ((y: Mu[F]) => y.cata(f)) + // crash + def foo(x : Mu[F]) = x.cata(f) + + // // okay + def x: Mu[F] = ??? + (() => x.cata(f)) + assert(true, cata(f)) + } +} diff --git a/test/files/presentation/visibility/src/Completions.scala b/test/files/presentation/visibility/src/Completions.scala index 8c07934915..69ec3959ad 100644 --- a/test/files/presentation/visibility/src/Completions.scala +++ b/test/files/presentation/visibility/src/Completions.scala @@ -11,7 +11,7 @@ package accessibility { def secretPublic(): Unit def someTests(other: Foo) { - other./*!*/secretPrivate // should be all but scretThis + other./*!*/secretPrivate // should be all but secretThis this./*!*/secretProtected // should hit five completions } @@ -25,7 +25,7 @@ package accessibility { class UnrelatedClass { def someTests(foo: Foo) { - foo./*!*/ // should list public and protected[accessiblity] + foo./*!*/ // should list public and protected[accessibility] } } diff --git a/test/files/res/t9089.check b/test/files/res/t9089.check new file mode 100644 index 0000000000..6cf64f734b --- /dev/null +++ b/test/files/res/t9089.check @@ -0,0 +1,4 @@ + +nsc> +nsc> +nsc> diff --git a/test/files/res/t9089.res b/test/files/res/t9089.res new file mode 100644 index 0000000000..ab5cc8534d --- /dev/null +++ b/test/files/res/t9089.res @@ -0,0 +1,2 @@ +t9089/A.scala +t9089/A.scala diff --git a/test/files/res/t9089/A.scala b/test/files/res/t9089/A.scala new file mode 100644 index 0000000000..bccf269639 --- /dev/null +++ b/test/files/res/t9089/A.scala @@ -0,0 +1 @@ +object O { def f(x: => Int): Int = x } diff --git a/test/files/run/applydynamic_sip.scala b/test/files/run/applydynamic_sip.scala index cf918a82ed..47d0c6a303 100644 --- a/test/files/run/applydynamic_sip.scala +++ b/test/files/run/applydynamic_sip.scala @@ -40,7 +40,7 @@ object Test extends App { // qual.sel(arg = a, a2: _*) // qual.sel(arg, arg2 = "a2", a2: _*) - // If qual.sel appears immediately on the left-hand side of an assigment + // If qual.sel appears immediately on the left-hand side of an assignment // qual.updateDynamic(“sel”)(expr) qual.sel = expr diff --git a/test/files/run/icode-reader-dead-code.check b/test/files/run/icode-reader-dead-code.check index d1739fed3b..c9de93283e 100644 --- a/test/files/run/icode-reader-dead-code.check +++ b/test/files/run/icode-reader-dead-code.check @@ -1,4 +1,7 @@ Bytecode for method f + + // access flags 0x11 + public final f()I L0 LINENUMBER 4 L0 ICONST_1 @@ -7,7 +10,11 @@ Bytecode for method f LOCALVARIABLE this Lp/A; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 + Bytecode for method f + + // access flags 0x11 + public final f()I L0 LINENUMBER 4 L0 ICONST_1 @@ -17,3 +24,4 @@ Bytecode for method f LOCALVARIABLE this Lp/A; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 + diff --git a/test/files/run/t5313.scala b/test/files/run/t5313.scala index 0d7168fa89..7f5af74c3f 100644 --- a/test/files/run/t5313.scala +++ b/test/files/run/t5313.scala @@ -11,7 +11,7 @@ object Test extends IcodeComparison { def bar = { var kept1 = new Object val result = new java.lang.ref.WeakReference(kept1) - kept1 = null // we can't eliminate this assigment because result can observe + kept1 = null // we can't eliminate this assignment because result can observe // when the object has no more references. See SI-5313 kept1 = new Object // but we can eliminate this one because kept1 has already been clobbered var erased2 = null // we can eliminate this store because it's never used diff --git a/test/files/run/t6114.scala b/test/files/run/t6114.scala index cb880ece00..8ad02d5bb2 100644 --- a/test/files/run/t6114.scala +++ b/test/files/run/t6114.scala @@ -51,7 +51,7 @@ object Test extends App { val next = list.asScala ++ List(4,5,6) assert(next != list.asScala) - // Note: Clone is hidden at this level, so no overriden cloning. + // Note: Clone is hidden at this level, so no overridden cloning. } testList diff --git a/test/files/run/t7459a.scala b/test/files/run/t7459a.scala new file mode 100644 index 0000000000..e9653c6e79 --- /dev/null +++ b/test/files/run/t7459a.scala @@ -0,0 +1,14 @@ +class LM { + class Node[B1] + case class CC(n: LM) + + // crash + val f: (LM => Any) = { + case tttt => + new tttt.Node[Any]() + } +} + +object Test extends App { + new LM().f(new LM()) +} diff --git a/test/files/run/t7459b-optimize.flags b/test/files/run/t7459b-optimize.flags new file mode 100644 index 0000000000..49d036a887 --- /dev/null +++ b/test/files/run/t7459b-optimize.flags @@ -0,0 +1 @@ +-optimize diff --git a/test/files/run/t7459b-optimize.scala b/test/files/run/t7459b-optimize.scala new file mode 100644 index 0000000000..605890962c --- /dev/null +++ b/test/files/run/t7459b-optimize.scala @@ -0,0 +1,21 @@ +class LM { + class Node[B1] + + // crash + val g: (CC => Any) = { + case CC(tttt) => + new tttt.Node[Any]() + } + + val h: (Some[CC] => Any) = { + case Some(CC(tttt)) => + new tttt.Node[Any]() + } +} + +object Test extends App { + new LM().g(new CC(new LM())) + new LM().h(Some(new CC(new LM()))) +} +case class CC(n: LM) + diff --git a/test/files/run/t7459b.scala b/test/files/run/t7459b.scala new file mode 100644 index 0000000000..605890962c --- /dev/null +++ b/test/files/run/t7459b.scala @@ -0,0 +1,21 @@ +class LM { + class Node[B1] + + // crash + val g: (CC => Any) = { + case CC(tttt) => + new tttt.Node[Any]() + } + + val h: (Some[CC] => Any) = { + case Some(CC(tttt)) => + new tttt.Node[Any]() + } +} + +object Test extends App { + new LM().g(new CC(new LM())) + new LM().h(Some(new CC(new LM()))) +} +case class CC(n: LM) + diff --git a/test/files/run/t7459c.scala b/test/files/run/t7459c.scala new file mode 100644 index 0000000000..144c5d793b --- /dev/null +++ b/test/files/run/t7459c.scala @@ -0,0 +1,16 @@ +class LM { + class Node[B1] + + // crash + val g: (CC => Any) = { + case CC(tttt) => + tttt.## // no crash + new tttt.Node[Any]() + } +} + +object Test extends App { + new LM().g(new CC(new LM())) +} +case class CC(n: LM) + diff --git a/test/files/run/t7459d.scala b/test/files/run/t7459d.scala new file mode 100644 index 0000000000..3263701f9d --- /dev/null +++ b/test/files/run/t7459d.scala @@ -0,0 +1,15 @@ +class LM { + class Node[B1] + case class CC(n: LM) + + // crash + val f: (LM => Any) = { + case tttt => + val uuuu: (tttt.type, Any) = (tttt, 0) + new uuuu._1.Node[Any]() + } +} + +object Test extends App { + new LM().f(new LM()) +} diff --git a/test/files/run/t7459f.scala b/test/files/run/t7459f.scala new file mode 100644 index 0000000000..63e2109560 --- /dev/null +++ b/test/files/run/t7459f.scala @@ -0,0 +1,12 @@ +object Test extends App { + class C + + case class FooSeq(x: Int, y: String, z: C*) + + FooSeq(1, "a", new C()) match { + case FooSeq(1, "a", x@_* ) => + //println(x.toList) + x.asInstanceOf[x.type] + assert(x.isInstanceOf[x.type]) + } +} diff --git a/test/files/run/t7965.scala b/test/files/run/t7965.scala new file mode 100644 index 0000000000..df80d4b5bb --- /dev/null +++ b/test/files/run/t7965.scala @@ -0,0 +1,54 @@ +// Test that scala doesn't apply boxing or varargs conversions to the +// @PolymorphicSignature magical methods, MethodHandle#{invoke, invokeExact} +object Test { + val code = """ + +object O { + private def foo = "foo" + private def bar(x: Int): Int = -x + private def baz(x: Box): Unit = x.a = "present" + val lookup = java.lang.invoke.MethodHandles.lookup +} + +import java.lang.invoke._ +class Box(var a: Any) + +object Test { + def main(args: Array[String]): Unit = { + def lookup(name: String, params: Array[Class[_]], ret: Class[_]) = { + val mt = MethodType.methodType(ret, params) + O.lookup.findVirtual(O.getClass, name, mt) + } + val fooResult = (lookup("foo", Array(), classOf[String]).invokeExact(O): Int) + assert(fooResult == "foo") + + val barResult = (lookup("bar", Array(classOf[Int]), classOf[Int]).invokeExact(O, 42): Int) + assert(barResult == -42) + + val box = new Box(null) + (lookup("baz", Array(classOf[Box]), Void.TYPE).invokeExact(O, box) : Unit) + assert(box.a == "present") + + // Note: Application in statement position in a block in Java also infers return type of Unit, + // but we don't support that, ascribe the type to Unit as above. + // as done in Java. + // lookup("baz", Array(classOf[Box]), Void.TYPE).invokeExact(O, box) + () + } +} + +""" + def main(args: Array[String]): Unit = { + if (util.Properties.isJavaAtLeast("1.7")) test() + } + + def test() { + import scala.reflect.runtime._ + import scala.tools.reflect.ToolBox + + val m = currentMirror + val tb = m.mkToolBox() + import tb._ + eval(parse(code)) + } +} diff --git a/test/files/run/t8253.scala b/test/files/run/t8253.scala index c4800b4491..a00d8b91a4 100644 --- a/test/files/run/t8253.scala +++ b/test/files/run/t8253.scala @@ -10,5 +10,5 @@ object Test extends App { show("<sample xmlns:foo={identity(ns1)}/>", q"<sample xmlns:foo={ns1}/>") // `identity(foo)` used to match the overly permissive match in SymbolXMLBuilder - // which was intented to more specifically match `_root_.scala.xml.Text(...)` + // which was intended to more specifically match `_root_.scala.xml.Text(...)` } diff --git a/test/files/run/t9030.scala b/test/files/run/t9030.scala new file mode 100644 index 0000000000..48d24e5b54 --- /dev/null +++ b/test/files/run/t9030.scala @@ -0,0 +1,19 @@ +object Test extends App { + + // For these methods, the compiler emits calls to BoxesRuntime.equalsNumNum/equalsNumChar/equalsNumObject directly + + def numNum(a: java.lang.Number, b: java.lang.Number) = assert(a == b) + def numChar(a: java.lang.Number, b: java.lang.Character) = assert(a == b) + def numObject(a: java.lang.Number, b: java.lang.Object) = assert(a == b) + + // The compiler doesn't use equalsCharObject directly, but still adding an example for completeness + + def charObject(a: java.lang.Character, b: java.lang.Object) = assert(a == b) + + numNum(new Integer(1), new Integer(1)) + numChar(new Integer(97), new Character('a')) + numObject(new Integer(1), new Integer(1)) + numObject(new Integer(97), new Character('a')) + + charObject(new Character('a'), new Integer(97)) +} diff --git a/test/files/scalacheck/nan-ordering.scala b/test/files/scalacheck/nan-ordering.scala index 2094a46e37..05e97a13c9 100644 --- a/test/files/scalacheck/nan-ordering.scala +++ b/test/files/scalacheck/nan-ordering.scala @@ -42,16 +42,16 @@ object Test extends Properties("NaN-Ordering") { property("Float equiv") = forAll(specFloats, specFloats) { (d1, d2) => numFloat.equiv(d1, d2) == (d1 == d2) } property("Float reverse.min") = forAll(specFloats, specFloats) { (d1, d2) => { - val mathmin = math.min(d1, d2) + val mathmax = math.max(d1, d2) val numericmin = numFloat.reverse.min(d1, d2) - mathmin == numericmin || mathmin.isNaN && numericmin.isNaN + mathmax == numericmin || mathmax.isNaN && numericmin.isNaN } } property("Float reverse.max") = forAll(specFloats, specFloats) { (d1, d2) => { - val mathmax = math.max(d1, d2) + val mathmin = math.min(d1, d2) val numericmax = numFloat.reverse.max(d1, d2) - mathmax == numericmax || mathmax.isNaN && numericmax.isNaN + mathmin == numericmax || mathmin.isNaN && numericmax.isNaN } } @@ -105,16 +105,16 @@ object Test extends Properties("NaN-Ordering") { property("Double equiv") = forAll(specDoubles, specDoubles) { (d1, d2) => numDouble.equiv(d1, d2) == (d1 == d2) } property("Double reverse.min") = forAll(specDoubles, specDoubles) { (d1, d2) => { - val mathmin = math.min(d1, d2) + val mathmax = math.max(d1, d2) val numericmin = numDouble.reverse.min(d1, d2) - mathmin == numericmin || mathmin.isNaN && numericmin.isNaN + mathmax == numericmin || mathmax.isNaN && numericmin.isNaN } } property("Double reverse.max") = forAll(specDoubles, specDoubles) { (d1, d2) => { - val mathmax = math.max(d1, d2) + val mathmin = math.min(d1, d2) val numericmax = numDouble.reverse.max(d1, d2) - mathmax == numericmax || mathmax.isNaN && numericmax.isNaN + mathmin == numericmax || mathmin.isNaN && numericmax.isNaN } } diff --git a/test/files/scalacheck/parallel-collections/ParallelIterableCheck.scala b/test/files/scalacheck/parallel-collections/ParallelIterableCheck.scala index 774d6f428b..468bcb6dd1 100644 --- a/test/files/scalacheck/parallel-collections/ParallelIterableCheck.scala +++ b/test/files/scalacheck/parallel-collections/ParallelIterableCheck.scala @@ -36,7 +36,7 @@ abstract class ParallelIterableCheck[T](collName: String) extends Properties(col // used to check if constructed collection is valid def checkDataStructureInvariants(orig: Traversable[T], cf: AnyRef) = { - // can be overriden in subclasses + // can be overridden in subclasses true } diff --git a/test/instrumented/library/scala/runtime/ScalaRunTime.scala b/test/instrumented/library/scala/runtime/ScalaRunTime.scala index e474ae737c..6b45a4e9f3 100644 --- a/test/instrumented/library/scala/runtime/ScalaRunTime.scala +++ b/test/instrumented/library/scala/runtime/ScalaRunTime.scala @@ -261,7 +261,7 @@ object ScalaRunTime { * * The primary motivation for this method is to provide a means for * correctly obtaining a String representation of a value, while - * avoiding the pitfalls of naïvely calling toString on said value. + * avoiding the pitfalls of naively calling toString on said value. * In particular, it addresses the fact that (a) toString cannot be * called on null and (b) depending on the apparent type of an * array, toString may or may not print it in a human-readable form. diff --git a/test/junit/scala/collection/IterableViewLikeTest.scala b/test/junit/scala/collection/IterableViewLikeTest.scala index 55da02744b..ab09c4930b 100644 --- a/test/junit/scala/collection/IterableViewLikeTest.scala +++ b/test/junit/scala/collection/IterableViewLikeTest.scala @@ -4,6 +4,7 @@ import org.junit.Assert._ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import language.postfixOps @RunWith(classOf[JUnit4]) class IterableViewLikeTest { diff --git a/test/junit/scala/collection/TraversableOnceTest.scala b/test/junit/scala/collection/TraversableOnceTest.scala index 56d8312336..196174c199 100644 --- a/test/junit/scala/collection/TraversableOnceTest.scala +++ b/test/junit/scala/collection/TraversableOnceTest.scala @@ -43,8 +43,8 @@ class TraversableOnceTest { def testReturnTheFirstMatch() = { val d = List(1, 2, 3, 4, 5, 6, 7, 8) def f(x: Int) = x % 3; - assert(d.maxBy(f) == 2, "If multiple elements evaluted to the largest value, maxBy should return the first one.") - assert(d.minBy(f) == 3, "If multiple elements evaluted to the largest value, minBy should return the first one.") + assert(d.maxBy(f) == 2, "If multiple elements evaluated to the largest value, maxBy should return the first one.") + assert(d.minBy(f) == 3, "If multiple elements evaluated to the largest value, minBy should return the first one.") } // Make sure it evaluates f no more than list.length times. @@ -56,7 +56,7 @@ class TraversableOnceTest { evaluatedCountOfMaxBy += 1 x * 10 }) - assert(evaluatedCountOfMaxBy == list.length, s"maxBy: should evaluate f only ${list.length} times, but it evaluted $evaluatedCountOfMaxBy times.") + assert(evaluatedCountOfMaxBy == list.length, s"maxBy: should evaluate f only ${list.length} times, but it evaluated $evaluatedCountOfMaxBy times.") var evaluatedCountOfMinBy = 0 @@ -64,7 +64,7 @@ class TraversableOnceTest { evaluatedCountOfMinBy += 1 x * 10 }) - assert(evaluatedCountOfMinBy == list.length, s"minBy: should evaluate f only ${list.length} times, but it evaluted $evaluatedCountOfMinBy times.") + assert(evaluatedCountOfMinBy == list.length, s"minBy: should evaluate f only ${list.length} times, but it evaluated $evaluatedCountOfMinBy times.") } } diff --git a/test/junit/scala/collection/immutable/VectorTest.scala b/test/junit/scala/collection/immutable/VectorTest.scala new file mode 100644 index 0000000000..e7edba3e43 --- /dev/null +++ b/test/junit/scala/collection/immutable/VectorTest.scala @@ -0,0 +1,20 @@ +package scala.collection.immutable + +import org.junit.{Assert, Test} +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(classOf[JUnit4]) +class VectorTest { + /** + * Test Vector ++ with a small parallel collection concatenation (SI-9072). + * + */ + @Test + def testPlusPlus(): Unit = { + val smallVec = (0 to 1) + val smallParVec = smallVec.par + val testElementsSize = (0 to 1000).map( _ => Vector.empty ++ smallParVec ) + Assert.assertTrue(testElementsSize.forall( v => v.size == 2 )) + } +} diff --git a/test/junit/scala/io/SourceTest.scala b/test/junit/scala/io/SourceTest.scala new file mode 100644 index 0000000000..3138a4589c --- /dev/null +++ b/test/junit/scala/io/SourceTest.scala @@ -0,0 +1,86 @@ + +package scala.io + +import org.junit.Test +import org.junit.Assert._ +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.tools.testing.AssertUtil._ + +import java.io.{ Console => _, _ } + +@RunWith(classOf[JUnit4]) +class SourceTest { + + private implicit val `our codec` = Codec.UTF8 + private val charSet = Codec.UTF8.charSet.name + + private def sampler = """ + |Big-endian and little-endian approaches aren't + |readily interchangeable in general, because the + |laws of arithmetic send signals leftward from + |the bits that are "least significant." + |""".stripMargin.trim + + private def in = new ByteArrayInputStream(sampler.getBytes) + + @Test def canIterateLines() = { + assertEquals(sampler.lines.size, (Source fromString sampler).getLines.size) + } + @Test def canCustomizeReporting() = { + class CapitalReporting(is: InputStream) extends BufferedSource(is) { + override def report(pos: Int, msg: String, out: PrintStream): Unit = { + out print f"$pos%04x: ${msg.toUpperCase}" + } + class OffsetPositioner extends Positioner(null) { + override def next(): Char = { + ch = iter.next() + pos = pos + 1 + ch + } + } + withPositioning(new OffsetPositioner) + } + val s = new CapitalReporting(in) + // skip to next line and report an error + do { + val c = s.next() + } while (s.ch != '\n') + s.next() + val out = new ByteArrayOutputStream + val ps = new PrintStream(out, true, charSet) + s.reportError(s.pos, "That doesn't sound right.", ps) + assertEquals("0030: THAT DOESN'T SOUND RIGHT.", out.toString(charSet)) + } + @Test def canAltCustomizeReporting() = { + class CapitalReporting(is: InputStream)(implicit codec: Codec) extends Source { + override val iter = { + val r = new InputStreamReader(is, codec.decoder) + Iterator continually (codec wrap r.read()) takeWhile (_ != -1) map (_.toChar) + } + override def report(pos: Int, msg: String, out: PrintStream): Unit = { + out print f"$pos%04x: ${msg.toUpperCase}" + } + private[this] var _pos: Int = _ + override def pos = _pos + private[this] var _ch: Char = _ + override def ch = _ch + override def next = { + _ch = iter.next() + _pos += 1 + _ch + } + } + val s = new CapitalReporting(in) + // skip to next line and report an error + do { + val c = s.next() + } while (s.ch != '\n') + s.next() + val out = new ByteArrayOutputStream + val ps = new PrintStream(out, true, charSet) + s.reportError(s.pos, "That doesn't sound right.", ps) + assertEquals("0030: THAT DOESN'T SOUND RIGHT.", out.toString(charSet)) + } +} diff --git a/test/junit/scala/math/OrderingTest.scala b/test/junit/scala/math/OrderingTest.scala new file mode 100644 index 0000000000..218622b8b4 --- /dev/null +++ b/test/junit/scala/math/OrderingTest.scala @@ -0,0 +1,61 @@ +package scala.math + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(classOf[JUnit4]) +class OrderingTest { + + /* Test for SI-9077 */ + @Test + def testReverseOrdering { + def check[T: Ordering](t1: T, t2: T): Unit = { + val O = Ordering[T] + val R = O.reverse + assertEquals(O.min(t1, t2), R.max(t1, t2)) + assertEquals(O.max(t1, t2), R.min(t1, t2)) + + assertEquals(O.lteq(t1, t2), R.lteq(t2, t1)) + assertEquals(O.lt(t1, t2), R.lt(t2, t1)) + assertEquals(O.gteq(t1, t2), R.gteq(t2, t1)) + assertEquals(O.gt(t1, t2), R.gt(t2, t1)) + assertEquals(O.compare(t1, t2), R.compare(t2, t1)) + + assertEquals(O.equiv(t1, t2), R.equiv(t1, t2)) + + assertEquals(O.on((x: T) => x).min(t1, t2), R.on((x: T) => x).max(t1, t2)) + + assertEquals(O.tryCompare(t1, t2), R.tryCompare(t2, t1)) + + assertEquals(O.mkOrderingOps(t1).<(t2), R.mkOrderingOps(t2).<(t1)) + assertEquals(O.mkOrderingOps(t1).<=(t2), R.mkOrderingOps(t2).<=(t1)) + assertEquals(O.mkOrderingOps(t1).>(t2), R.mkOrderingOps(t2).>(t1)) + assertEquals(O.mkOrderingOps(t1).>=(t2), R.mkOrderingOps(t2).>=(t1)) + + assertEquals(O.mkOrderingOps(t1).min(t2), R.mkOrderingOps(t1).max(t2)) + assertEquals(O.mkOrderingOps(t1).max(t2), R.mkOrderingOps(t1).min(t2)) + } + def checkAll[T: Ordering](ts: T*): Unit = { + for (t1 <- ts; t2 <- ts) check(t1, t2) + } + checkAll[Unit](()) + checkAll[Boolean](true, false) + checkAll[Byte](Byte.MinValue, -1.toByte, 0.toByte, 1.toByte, Byte.MaxValue) + checkAll[Char](Char.MinValue, -1.toChar, 0.toChar, 1.toChar, Char.MaxValue) + checkAll[Short](Short.MinValue, -1, 0, 1, Short.MaxValue) + checkAll[Int](Int.MinValue, -1, 0, 1, Int.MaxValue) + checkAll[Double](Double.MinValue, -1, -0, 0, 1, Double.MaxValue) + checkAll[Float](Float.MinValue, -1, -0, 0, 1, Float.MaxValue) + + checkAll[BigInt](Int.MinValue, -1, 0, 1, Int.MaxValue) + checkAll[BigDecimal](Int.MinValue, -1, -0, 1, Int.MaxValue) + checkAll[String]("", "a", "b", "bb") + checkAll[String]("", "a", "b", "bb") + checkAll[Option[Int]](None, Some(1), Some(2)) + checkAll[Iterable[Int]](Nil, List(1), List(1, 2)) + checkAll[(Int, Int)]((1, 2), (1, 3), (4, 5)) + } +} + diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala index 7043c26d5e..9bfe6eecb8 100644 --- a/test/junit/scala/reflect/internal/PrintersTest.scala +++ b/test/junit/scala/reflect/internal/PrintersTest.scala @@ -125,6 +125,8 @@ trait BasePrintTests { @Test def testName19 = assertPrintedCode("""class `class`""") @Test def testName20 = assertPrintedCode("""class `test name`""") + + @Test def testName21 = assertPrintedCode("""class `test.name`""") @Test def testIfExpr1 = assertResultCode(code = sm""" |val a = 1 diff --git a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala index 221aad6536..2347e8288e 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala @@ -19,7 +19,7 @@ class BTypesTest { val btypes = new BTypesFromSymbols[g.type](g) import btypes._ - duringBackend(btypes.intializeCoreBTypes()) + duringBackend(btypes.initializeCoreBTypes()) def classBTypeFromSymbol(sym: Symbol) = duringBackend(btypes.classBTypeFromSymbol(sym)) diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala new file mode 100644 index 0000000000..2975bd060d --- /dev/null +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/BTypesFromClassfileTest.scala @@ -0,0 +1,95 @@ +package scala.tools.nsc +package backend.jvm +package opt + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import scala.tools.asm.Opcodes._ +import org.junit.Assert._ + +import scala.tools.nsc.backend.jvm.BTypes.InternalName +import scala.tools.testing.AssertUtil._ + +import CodeGenTools._ +import scala.tools.partest.ASMConverters +import ASMConverters._ + +import scala.collection.convert.decorateAsScala._ + +@RunWith(classOf[JUnit4]) +class BTypesFromClassfileTest { + val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode") + + import compiler._ + import definitions._ + import genBCode.bTypes + import bTypes._ + + def duringBackend[T](f: => T) = compiler.exitingDelambdafy(f) + + val run = new compiler.Run() // initializes some of the compiler + duringBackend(bTypes.initializeCoreBTypes()) + + def clearCache() = bTypes.classBTypeFromInternalName.clear() + + def sameBType(fromSym: ClassBType, fromClassfile: ClassBType, checked: Set[InternalName] = Set.empty): Set[InternalName] = { + if (checked(fromSym.internalName)) checked + else { + assert(fromSym == fromClassfile, s"$fromSym != $fromClassfile") + sameInfo(fromSym.info, fromClassfile.info, checked + fromSym.internalName) + } + } + + def sameBTypes(fromSyms: Iterable[ClassBType], fromClassfiles: Iterable[ClassBType], checked: Set[InternalName]): Set[InternalName] = { + assert(fromSyms.size == fromClassfiles.size, s"\n$fromSyms\n$fromClassfiles") + (fromSyms, fromClassfiles).zipped.foldLeft(checked) { + case (chk, (fromSym, fromClassfile)) => sameBType(fromSym, fromClassfile, chk) + } + } + + def sameInfo(fromSym: ClassInfo, fromClassfile: ClassInfo, checked: Set[InternalName]): Set[InternalName] = { + assert({ + // Nested class symbols can undergo makeNotPrivate (ExplicitOuter). But this is only applied + // for symbols of class symbols that are being compiled, not those read from a pickle. + // So a class may be public in bytecode, but the symbol still says private. + if (fromSym.nestedInfo.isEmpty) fromSym.flags == fromClassfile.flags + else (fromSym.flags | ACC_PRIVATE | ACC_PUBLIC) == (fromClassfile.flags | ACC_PRIVATE | ACC_PUBLIC) + }, s"class flags differ\n$fromSym\n$fromClassfile") + + val chk1 = sameBTypes(fromSym.superClass, fromClassfile.superClass, checked) + + val chk2 = sameBTypes(fromSym.interfaces, fromClassfile.interfaces, chk1) + + // The fromSym info has only member classes, no local or anonymous. The symbol is read from the + // Scala pickle data and only member classes are created / entered. + // (This is different for symbols that are being compiled, there flatten will enter all local + // and anonymous classes as members of the outer class. But not for unpickled symbols). + // The fromClassfile info has all nested classes, including anonymous and local. So we filter + // them out: member classes are identified by having the `outerName` defined. + val memberClassesFromClassfile = fromClassfile.nestedClasses.filter(_.info.nestedInfo.get.outerName.isDefined) + // Sorting is required: the backend sorts all InnerClass entries by internalName before writing + // them to the classfile (to make it deterministic: the entries are collected in a Set during + // code generation). + val chk3 = sameBTypes(fromSym.nestedClasses.sortBy(_.internalName), memberClassesFromClassfile.sortBy(_.internalName), chk2) + sameBTypes(fromSym.nestedInfo.map(_.enclosingClass), fromClassfile.nestedInfo.map(_.enclosingClass), chk3) + } + + def check(classSym: Symbol): Unit = duringBackend { + clearCache() + val fromSymbol = classBTypeFromSymbol(classSym) + clearCache() + val fromClassfile = bTypes.classBTypeFromParsedClassfile(fromSymbol.internalName) + sameBType(fromSymbol, fromClassfile) + } + + @Test + def compareClassBTypes(): Unit = { + // Note that not only these classes are tested, but also all their parents and all nested + // classes in their InnerClass attributes. + check(ObjectClass) + check(JavaNumberClass) + check(ConsClass) + check(ListModule.moduleClass) + } +} diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala index 5b0f0f238a..5430e33d6c 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/MethodLevelOpts.scala @@ -74,7 +74,7 @@ class MethodLevelOpts { """.stripMargin val m = singleMethod(methodOptCompiler)(code) assertTrue(m.handlers.length == 2) - assertSameCode(m.instructions.dropNonOp, // drop line numbers and lables that are only used by line numbers + assertSameCode(m.instructions.dropNonOp, // drop line numbers and labels that are only used by line numbers // one single label left :-) List(Op(ICONST_1), VarOp(ISTORE, 2), Jump(GOTO, Label(20)), Op(POP), Op(ICONST_2), VarOp(ISTORE, 2), Jump(GOTO, Label(20)), VarOp(ASTORE, 3), Op(ICONST_2), Op(IRETURN), Label(20), Op(ICONST_2), Op(IRETURN)) diff --git a/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala b/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala index 524d2e45e0..91f94e09b6 100644 --- a/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala +++ b/test/junit/scala/tools/nsc/symtab/StdNamesTest.scala @@ -19,7 +19,7 @@ class StdNamesTest { } @Test - def testNewTermNameNegativeLenght(): Unit = { + def testNewTermNameNegativeLength(): Unit = { assertEquals(nme.EMPTY, newTermName("foo".toCharArray, 0, -1)) assertEquals(nme.EMPTY, newTermName("foo".toCharArray, 0, 0)) } diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableTest.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableTest.scala index 11e955a4bb..895ad9d683 100644 --- a/test/junit/scala/tools/nsc/symtab/SymbolTableTest.scala +++ b/test/junit/scala/tools/nsc/symtab/SymbolTableTest.scala @@ -44,4 +44,9 @@ class SymbolTableTest { assertFalse("Foo should be a superclass of Foo", fooSymbol.tpe <:< barSymbol.tpe) } + @Test + def noSymbolOuterClass_t9133: Unit = { + import symbolTable._ + assert(NoSymbol.outerClass == NoSymbol) + } } diff --git a/test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala b/test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala new file mode 100644 index 0000000000..1fff9c9a32 --- /dev/null +++ b/test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala @@ -0,0 +1,555 @@ +package scala.tools.nsc.transform.patmat + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.collection.mutable +import scala.tools.nsc.{Global, Settings} + +object TestSolver extends Logic with Solving { + + val global: Global = new Global(new Settings()) + + // disable max recursion depth in order to get all solutions + global.settings.YpatmatExhaustdepth.tryToSet("off" :: Nil) + + object TestSolver extends Solver { + + class Const { + override def toString: String = "Const" + } + + val NullConst = new Const + type Type = Int + + case class TypeConst(i: Int) extends Const + + object TypeConst extends TypeConstExtractor + + case class ValueConst(i: Int) extends Const + + object ValueConst extends ValueConstExtractor { + def apply(t: Tree): Const = ??? + } + + case class Tree(name: String) + + class Var(val x: Tree) extends AbsVar { + + override def equals(other: scala.Any): Boolean = other match { + case that: Var => this.x == that.x + case _ => false + } + + override def hashCode(): Int = x.hashCode() + + override def toString: String = { + s"Var($x)" + } + + def domainSyms = None + + def implications = Nil + + def mayBeNull = false + + def propForEqualsTo(c: Const): Prop = ??? + + def registerEquality(c: Const) = () + + def registerNull() = () + + def symForStaticTp = None + } + + object Var extends VarExtractor { + def apply(x: Tree): Var = new Var(x) + + def unapply(v: Var): Some[Tree] = Some(v.x) + } + + def prepareNewAnalysis() = {} + + def reportWarning(msg: String) = sys.error(msg) + + /** + * The DPLL procedure only returns a minimal mapping from literal to value + * such that the CNF formula is satisfied. + * E.g. for: + * `(a \/ b)` + * The DPLL procedure will find either {a = true} or {b = true} + * as solution. + * + * The expansion step will amend both solutions with the unassigned variable + * i.e., {a = true} will be expanded to {a = true, b = true} and + * {a = true, b = false}. + */ + def expandUnassigned(solution: Solution): List[Model] = { + import solution._ + + // the number of solutions is doubled for every unassigned variable + val expandedModels = 1 << unassigned.size + var current = mutable.ArrayBuffer[Model]() + var next = mutable.ArrayBuffer[Model]() + current.sizeHint(expandedModels) + next.sizeHint(expandedModels) + + current += model + + // we use double buffering: + // read from `current` and create a two models for each model in `next` + for { + s <- unassigned + } { + for { + model <- current + } { + def force(s: Sym, pol: Boolean) = model + (s -> pol) + + next += force(s, pol = true) + next += force(s, pol = false) + } + + val tmp = current + current = next + next = tmp + + next.clear() + } + + current.toList + } + + /** + * Old CNF conversion code, used for reference: + * - convert formula into NNF + * (i.e., no negated terms, only negated variables) + * - use distributive laws to convert into CNF + */ + def eqFreePropToSolvableViaDistribution(p: Prop) = { + val symbolMapping = new SymbolMapping(gatherSymbols(p)) + + type Formula = Array[TestSolver.Clause] + + def formula(c: Clause*): Formula = c.toArray + + def merge(a: Clause, b: Clause) = a ++ b + + def negationNormalFormNot(p: Prop): Prop = p match { + case And(ps) => Or(ps map negationNormalFormNot) + case Or(ps) => And(ps map negationNormalFormNot) + case Not(p) => negationNormalForm(p) + case True => False + case False => True + case s: Sym => Not(s) + } + + def negationNormalForm(p: Prop): Prop = p match { + case Or(ps) => Or(ps map negationNormalForm) + case And(ps) => And(ps map negationNormalForm) + case Not(negated) => negationNormalFormNot(negated) + case True + | False + | (_: Sym) => p + } + + val TrueF: Formula = Array() + val FalseF = Array(clause()) + def lit(sym: Sym) = Array(clause(symbolMapping.lit(sym))) + def negLit(sym: Sym) = Array(clause(-symbolMapping.lit(sym))) + + def conjunctiveNormalForm(p: Prop): Formula = { + def distribute(a: Formula, b: Formula): Formula = + (a, b) match { + // true \/ _ = true + // _ \/ true = true + case (trueA, trueB) if trueA.size == 0 || trueB.size == 0 => TrueF + // lit \/ lit + case (a, b) if a.size == 1 && b.size == 1 => formula(merge(a(0), b(0))) + // (c1 /\ ... /\ cn) \/ d = ((c1 \/ d) /\ ... /\ (cn \/ d)) + // d \/ (c1 /\ ... /\ cn) = ((d \/ c1) /\ ... /\ (d \/ cn)) + case (cs, ds) => + val (big, small) = if (cs.size > ds.size) (cs, ds) else (ds, cs) + big flatMap (c => distribute(formula(c), small)) + } + + p match { + case True => TrueF + case False => FalseF + case s: Sym => lit(s) + case Not(s: Sym) => negLit(s) + case And(ps) => + ps.toArray flatMap conjunctiveNormalForm + case Or(ps) => + ps map conjunctiveNormalForm reduceLeft { (a, b) => + distribute(a, b) + } + } + } + val cnf = conjunctiveNormalForm(negationNormalForm(p)) + Solvable(cnf, symbolMapping) + } + + } + +} + +/** + * Testing CNF conversion via Tseitin vs NNF & expansion. + */ +@RunWith(classOf[JUnit4]) +class SolvingTest { + + import scala.tools.nsc.transform.patmat.TestSolver.TestSolver._ + + implicit val Ord: Ordering[TestSolver.TestSolver.Model] = Ordering.by { + _.toSeq.sortBy(_.toString()).toIterable + } + + private def sym(name: String) = Sym(Var(Tree(name)), NullConst) + + @Test + def testSymCreation() { + val s1 = sym("hello") + val s2 = sym("hello") + assertEquals(s1, s2) + } + + /** + * Simplest possible test: solve a formula and check the solution(s) + */ + @Test + def testUnassigned() { + val pSym = sym("p") + val solvable = propToSolvable(Or(pSym, Not(pSym))) + val solutions = TestSolver.TestSolver.findAllModelsFor(solvable) + val expected = List(Solution(Map(), List(pSym))) + assertEquals(expected, solutions) + } + + /** + * Unassigned variables must be expanded + * for stable results + */ + @Test + def testNoUnassigned() { + val pSym = sym("p") + val qSym = sym("q") + val solvable = propToSolvable(Or(pSym, Not(qSym))) + val solutions = findAllModelsFor(solvable) + val expanded = solutions.flatMap(expandUnassigned).sorted + val expected = Seq( + Map(pSym -> false, qSym -> false), + Map(pSym -> true, qSym -> false), + Map(pSym -> true, qSym -> true) + ).sorted + + assertEquals(expected, expanded) + } + + @Test + def testTseitinVsExpansionFrom_t7020() { + val formulas = Seq( + And(And(And(Not(sym("V1=null")), + sym("V1=scala.collection.immutable.::[?]")), And(Not(sym("V1=null")), + And(Or(sym("V2=4"), Or(sym("V2=5"), sym("V2=6"))), sym("V3=Nil")))), + And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")), + Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"), + Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")), + Not(sym("V3=null"))), + And(Or(Not(sym("V3=scala.collection.immutable.::[?]")), + Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"), + sym("V1=null")))))))), And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))))), + + And(And(And(Not(sym("V1=null")), + sym("V1=scala.collection.immutable.::[?]")), And(Not(sym("V1=null")), + And(sym("V2=7"), sym("V3=Nil")))), + And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")), + Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"), + Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")), + Not(sym("V3=null"))), + And(Or(Not(sym("V3=scala.collection.immutable.::[?]")), + Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"), + sym("V1=null")))))))), And(And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil")))))))), + + And(And(Not(sym("V1=null")), + sym("V1=scala.collection.immutable.::[?]")), And(Not(sym("V1=null")), + And(Or(sym("V2=4"), Or(sym("V2=5"), sym("V2=6"))), sym("V3=Nil")))), + + And(And(Not(sym("V1=null")), sym("V1=scala.collection.immutable.::[?]")), + And(Not(sym("V1=null")), And(sym("V2=7"), sym("V3=Nil")))), + + And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")), + Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"), + Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")), + Not(sym("V3=null"))), + And(Or(Not(sym("V3=scala.collection.immutable.::[?]")), + Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"), + sym("V1=null")))))))), And(And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil"))))))), + + And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")), + Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"), + Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")), + Not(sym("V3=null"))), + And(Or(Not(sym("V3=scala.collection.immutable.::[?]")), + Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"), + sym("V1=null")))))))), And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=2")), Not(sym("V3=Nil"))))))), + + And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")), + Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"), + Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")), + Not(sym("V3=null"))), + And(Or(Not(sym("V3=scala.collection.immutable.::[?]")), + Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"), + sym("V1=null")))))))), And(sym("V1=Nil"), And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil"))))), And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=2")), Not(sym("V3=Nil"))))))))), + + And(And(Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), And(Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil"))))), And(Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(Not(sym("V2=7")), Not(sym("V3=Nil"))))), Not(sym("V1=Nil"))))), + + And(And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil")))))), + + And(And(Or(sym("V3=scala.collection.immutable.::[?]"), sym("V3=Nil")), + Or(sym("V1=scala.collection.immutable.::[?]"), sym("V1=Nil"))), + And(And(Or(Or(False, Not(sym("V1=scala.collection.immutable.::[?]"))), + Or(False, Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), And(Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil"))))), And(Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(Not(sym("V2=7")), Not(sym("V3=Nil"))))), Not(sym("V1=Nil")))))), + + And(Not(sym("V1=null")), And(Or(sym("V2=4"), Or(sym("V2=5"), sym("V2=6"))), + sym("V3=Nil"))), + + And(Not(sym("V1=null")), And(sym("V2=7"), sym("V3=Nil"))), + + And(Not(sym("V1=null")), sym("V1=scala.collection.immutable.::[?]")), + + And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + + And(Not(sym("V2=5")), Not(sym("V2=6"))), + + And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"), + sym("V1=null")))), + + And(Or(Not(sym("V1=scala.collection.immutable.::[?]")), + Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"), + Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")), + Not(sym("V3=null"))), + And(Or(Not(sym("V3=scala.collection.immutable.::[?]")), + Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"), + sym("V1=null")))))))), + + And(Or(Not(sym("V3=Nil")), Not(sym("V3=null"))), + And(Or(Not(sym("V3=scala.collection.immutable.::[?]")), + Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"), + sym("V1=null")))))), + + And(Or(Not(sym("V3=scala.collection.immutable.::[?]")), + Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"), + sym("V1=null"))))), + + And(Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil"))))), And(Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(Not(sym("V2=7")), Not(sym("V3=Nil"))))), Not(sym("V1=Nil")))), + + And(Or(Or(False, Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), + + And(Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(Not(sym("V2=7")), Not(sym("V3=Nil"))))), Not(sym("V1=Nil"))), + + And(Or(Or(sym("V1=null"), Not(sym("V1=scala.collection.immutable.::[?]"))), + Or(sym("V1=null"), Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), + Not(sym("V2=6")))), Not(sym("V3=Nil"))))), And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=2")), Not(sym("V3=Nil"))))))), + + And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))), + + And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=7")), Not(sym("V3=Nil"))))), + And(And(Or(Not(sym("V1=scala.collection.immutable.::[?]")), + Not(sym("V1=null"))), And(Or(sym("V3=scala.collection.immutable.::[?]"), + Or(sym("V3=Nil"), sym("V3=null"))), And(Or(Not(sym("V3=Nil")), + Not(sym("V3=null"))), + And(Or(Not(sym("V3=scala.collection.immutable.::[?]")), + Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"), + sym("V1=null")))))))), And(sym("V1=Nil"), And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil"))))), And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))))))), + + And(Or(sym("V2=4"), Or(sym("V2=5"), sym("V2=6"))), sym("V3=Nil")), + + And(Or(sym("V3=scala.collection.immutable.::[?]"), Or(sym("V3=Nil"), + sym("V3=null"))), And(Or(Not(sym("V3=Nil")), Not(sym("V3=null"))), + And(Or(Not(sym("V3=scala.collection.immutable.::[?]")), + Not(sym("V3=null"))), And(Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + Or(sym("V1=scala.collection.immutable.::[?]"), Or(sym("V1=Nil"), + sym("V1=null"))))))), + + And(Or(sym("V3=scala.collection.immutable.::[?]"), + sym("V3=Nil")), Or(sym("V1=scala.collection.immutable.::[?]"), + sym("V1=Nil"))), + + And(sym("V1=Nil"), And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil"))))), And(Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=2")), Not(sym("V3=Nil")))))))), + + And(sym("V2=7"), sym("V3=Nil")), + + False, + + Not(sym("V1=Nil")), + + Or(And(Not(sym("V2=4")), + And(Not(sym("V2=5")), Not(sym("V2=6")))), Not(sym("V3=Nil"))), + + Or(False, Not(sym("V1=scala.collection.immutable.::[?]"))), + + Or(False, + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil")))), + + Or(False, Or(Not(sym("V2=1")), Not(sym("V3=Nil")))), + + Or(Not(sym("V1=Nil")), Not(sym("V1=null"))), + + Or(Not(sym("V3=scala.collection.immutable.::[?]")), Not(sym("V3=null"))), + + Or(Or(False, Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil"))))), + + Or(Or(False, + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(False, + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), + + Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil"))))), + + Or(Or(sym("V1=null"), + Not(sym("V1=scala.collection.immutable.::[?]"))), Or(sym("V1=null"), + Or(Not(sym("V2=1")), Not(sym("V3=Nil"))))), + + Or(sym("V1=null"), Not(sym("V1=scala.collection.immutable.::[?]"))), + + Or(sym("V1=null"), + Or(And(Not(sym("V2=4")), And(Not(sym("V2=5")), Not(sym("V2=6")))), + Not(sym("V3=Nil")))), + + Or(sym("V1=null"), Or(Not(sym("V2=1")), Not(sym("V3=Nil")))), + + Or(sym("V1=scala.collection.immutable.::[?]"), + Or(sym("V1=Nil"), sym("V1=null"))), + + Or(sym("V1=scala.collection.immutable.::[?]"), sym("V1=Nil")), + + Or(sym("V2=4"), Or(sym("V2=5"), sym("V2=6"))), + + sym("V3=scala.collection.immutable.::[?]") + ) + + formulas foreach { + f => + // build CNF + val tseitinCnf = propToSolvable(f) + val expansionCnf = eqFreePropToSolvableViaDistribution(f) + + // ALL-SAT + val tseitinSolutions = findAllModelsFor(tseitinCnf) + val expansionSolutins = findAllModelsFor(expansionCnf) + + // expand unassigned variables + // (otherwise solutions can not be compared) + val tseitinNoUnassigned = tseitinSolutions.flatMap(expandUnassigned).sorted + val expansionNoUnassigned = expansionSolutins.flatMap(expandUnassigned).sorted + assertEquals(tseitinNoUnassigned, expansionNoUnassigned) + } + } +} + + diff --git a/test/pending/jvm/cf-attributes.scala b/test/pending/jvm/cf-attributes.scala index f4964b63b1..2d08f22d8b 100644 --- a/test/pending/jvm/cf-attributes.scala +++ b/test/pending/jvm/cf-attributes.scala @@ -62,7 +62,7 @@ object anonymousClasses { //InnerClass: // public final #_; //class anonymousClasses$$anon$1 of class anonymousClasses$ val x = new Foo() { - override def foo() { println("foo (overriden)"); } + override def foo() { println("foo (overridden)"); } def dummy = 0 } } diff --git a/test/pending/jvm/timeout.scala b/test/pending/jvm/timeout.scala index 22b3647dce..8f29f8ddbe 100644 --- a/test/pending/jvm/timeout.scala +++ b/test/pending/jvm/timeout.scala @@ -1,4 +1,4 @@ -// Test is in pending because although it suceeds locally, +// Test is in pending because although it succeeds locally, // it takes too long on the machine which runs nightly tests. // // [partest] EXPECTED: 100 < x < 900 diff --git a/test/scaladoc/resources/SI-3314-diagrams.scala b/test/scaladoc/resources/SI-3314-diagrams.scala index b80a97b522..7d2cc9447c 100644 --- a/test/scaladoc/resources/SI-3314-diagrams.scala +++ b/test/scaladoc/resources/SI-3314-diagrams.scala @@ -7,7 +7,7 @@ package scala.test.scaladoc { * / / / | \ \ \ * Mon Tue Wed Thu Fri Sat Sun * - * - each member should receive an inhertiance diagram: + * - each member should receive an inheritance diagram: * Value * | * | diff --git a/test/scaladoc/resources/implicit-inheritance-override.scala b/test/scaladoc/resources/implicit-inheritance-override.scala index 5d692f59ad..b59d2f410d 100644 --- a/test/scaladoc/resources/implicit-inheritance-override.scala +++ b/test/scaladoc/resources/implicit-inheritance-override.scala @@ -35,7 +35,7 @@ class DerivedC extends Base { class DerivedD extends Base { /** - * @tparam T The overriden type parameter comment + * @tparam T The overridden type parameter comment */ override def function[T](arg1: T, arg2: String): Double = 3.0d }
\ No newline at end of file diff --git a/test/scaladoc/resources/implicits-ambiguating-res.scala b/test/scaladoc/resources/implicits-ambiguating-res.scala index 6ed51366cb..90e43ac2ed 100644 --- a/test/scaladoc/resources/implicits-ambiguating-res.scala +++ b/test/scaladoc/resources/implicits-ambiguating-res.scala @@ -1,5 +1,5 @@ /** - * Test scaladoc implicits distinguishing -- supress all members by implicit conversion that are shadowed by the + * Test scaladoc implicits distinguishing -- suppress all members by implicit conversion that are shadowed by the * class' own members * * {{{ diff --git a/test/scaladoc/resources/implicits-shadowing-res.scala b/test/scaladoc/resources/implicits-shadowing-res.scala index c5e9493bf3..b7f3ceb895 100644 --- a/test/scaladoc/resources/implicits-shadowing-res.scala +++ b/test/scaladoc/resources/implicits-shadowing-res.scala @@ -1,5 +1,5 @@ /** - * Test scaladoc implicits distinguishing -- supress all members by implicit conversion that are shadowed by the + * Test scaladoc implicits distinguishing -- suppress all members by implicit conversion that are shadowed by the * class' own members * * {{{ diff --git a/test/scaladoc/scalacheck/HtmlFactoryTest.scala b/test/scaladoc/scalacheck/HtmlFactoryTest.scala index da0f253a37..51633be440 100644 --- a/test/scaladoc/scalacheck/HtmlFactoryTest.scala +++ b/test/scaladoc/scalacheck/HtmlFactoryTest.scala @@ -485,7 +485,7 @@ object Test extends Properties("HtmlFactory") { """, true), (Some("DerivedD"), """def function[T](arg1: T, arg2: String): Double - T The overriden type parameter comment + T The overridden type parameter comment arg1 The T term comment arg2 The string comment returns The return comment diff --git a/versions.properties b/versions.properties index d24a3bb952..9e2e6cea79 100644 --- a/versions.properties +++ b/versions.properties @@ -4,7 +4,7 @@ # when adding new properties that influence a release, # also add them to the update.versions mechanism in build.xml, # which is used by scala-release-2.11.x in scala/jenkins-scripts -starr.version=2.11.2 +starr.version=2.11.5 starr.use.released=1 # These are the versions of the modules that go with this release. @@ -14,11 +14,11 @@ starr.use.released=1 scala.binary.version=2.11 # e.g. 2.11.0-RC1, 2.11.0, 2.11.1-RC1, 2.11.1 # this defines the dependency on scala-continuations-plugin in scala-dist's pom -scala.full.version=2.11.2 +scala.full.version=2.11.5 # external modules shipped with distribution, as specified by scala-library-all's pom scala-xml.version.number=1.0.3 -scala-parser-combinators.version.number=1.0.2 +scala-parser-combinators.version.number=1.0.3 scala-continuations-plugin.version.number=1.0.2 scala-continuations-library.version.number=1.0.2 scala-swing.version.number=1.0.1 |