summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--build.xml2
-rw-r--r--doc/LICENSE.md4
-rw-r--r--doc/License.rtf4
-rw-r--r--project/VersionUtil.scala37
-rw-r--r--scripts/jobs/integrate/bootstrap135
-rw-r--r--spec/05-classes-and-objects.md20
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaVersion.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala95
-rw-r--r--src/library/scala/util/Properties.scala2
-rw-r--r--src/reflect/scala/reflect/internal/tpe/FindMembers.scala14
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala2
-rw-r--r--src/scalap/decoder.properties2
-rw-r--r--test/files/neg/userdefined_apply.check25
-rw-r--r--test/files/neg/userdefined_apply.scala57
-rw-r--r--test/files/pos/userdefined_apply.scala54
16 files changed, 353 insertions, 104 deletions
diff --git a/README.md b/README.md
index bbfe7a797b..c2891390d4 100644
--- a/README.md
+++ b/README.md
@@ -230,7 +230,7 @@ tested version during CI validation.
The Scala CI builds nightly download releases (including all modules) and publishes
them to the following locations:
- [2.12.x](http://www.scala-lang.org/files/archive/nightly/2.12.x/?C=M;O=D)
- - [2.11.x](http://www.scala-lang.org/files/archive/nightly/2.11.x/?C=M;O=A)
+ - [2.11.x](http://www.scala-lang.org/files/archive/nightly/2.11.x/?C=M;O=D)
The CI also publishes nightly API docs:
- [2.12.x](http://www.scala-lang.org/files/archive/nightly/2.12.x/api/?C=M;O=D)
diff --git a/build.xml b/build.xml
index a37cced4cb..f8c0380f41 100644
--- a/build.xml
+++ b/build.xml
@@ -184,7 +184,7 @@ TODO:
<property name="dists.dir" value="${basedir}/dists"/>
- <property name="copyright.string" value="Copyright 2002-2016, LAMP/EPFL"/>
+ <property name="copyright.string" value="Copyright 2002-2017, LAMP/EPFL"/>
<!-- These are NOT the flags used to run SuperSabbus, but the ones written
into the script runners created with scala.tools.ant.ScalaTool -->
diff --git a/doc/LICENSE.md b/doc/LICENSE.md
index c56b38daa2..ce29d7e7d4 100644
--- a/doc/LICENSE.md
+++ b/doc/LICENSE.md
@@ -2,9 +2,9 @@ Scala is licensed under the [BSD 3-Clause License](http://opensource.org/license
## Scala License
-Copyright (c) 2002-2016 EPFL
+Copyright (c) 2002-2017 EPFL
-Copyright (c) 2011-2016 Lightbend, Inc.
+Copyright (c) 2011-2017 Lightbend, Inc.
All rights reserved.
diff --git a/doc/License.rtf b/doc/License.rtf
index c8f24838a2..adc7dfdcb8 100644
--- a/doc/License.rtf
+++ b/doc/License.rtf
@@ -10,8 +10,8 @@
\fs48 Scala License
\fs40 \
-\fs26 Copyright (c) 2002-2016 EPFL\
-Copyright (c) 2011-2016 Lightbend, Inc.\
+\fs26 Copyright (c) 2002-2017 EPFL\
+Copyright (c) 2011-2017 Lightbend, Inc.\
All rights reserved.\
\
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\
diff --git a/project/VersionUtil.scala b/project/VersionUtil.scala
index 4705bbb6ce..3f9b727ef0 100644
--- a/project/VersionUtil.scala
+++ b/project/VersionUtil.scala
@@ -18,7 +18,7 @@ object VersionUtil {
)
lazy val generatePropertiesFileSettings = Seq[Setting[_]](
- copyrightString := "Copyright 2002-2016, LAMP/EPFL",
+ copyrightString := "Copyright 2002-2017, LAMP/EPFL and Lightbend, Inc.",
resourceGenerators in Compile += generateVersionPropertiesFile.map(file => Seq(file)).taskValue,
generateVersionPropertiesFile := generateVersionPropertiesFileImpl.value
)
@@ -45,17 +45,19 @@ object VersionUtil {
/** Compute the canonical, Maven and OSGi version number from `baseVersion` and `baseVersionSuffix`.
* Examples of the generated versions:
*
- * ("2.11.8", "SNAPSHOT" ) -> ("2.11.8-20151215-133023-7559aed3c5", "2.11.8-SNAPSHOT", "2.11.8.v20151215-133023-7559aed3c5")
- * ("2.11.8", "SHA-SNAPSHOT") -> ("2.11.8-20151215-133023-7559aed3c5", "2.11.8-7559aed3c5-SNAPSHOT", "2.11.8.v20151215-133023-7559aed3c5")
- * ("2.11.8", "" ) -> ("2.11.8", "2.11.8", "2.11.8.v20151215-133023-VFINAL-7559aed3c5")
- * ("2.11.8", "M3" ) -> ("2.11.8-M3", "2.11.8-M3", "2.11.8.v20151215-133023-M3-7559aed3c5")
- * ("2.11.8", "RC4" ) -> ("2.11.8-RC4", "2.11.8-RC4", "2.11.8.v20151215-133023-RC4-7559aed3c5")
- * ("2.11.8-RC4", "SPLIT" ) -> ("2.11.8-RC4", "2.11.8-RC4", "2.11.8.v20151215-133023-RC4-7559aed3c5")
+ * ("2.11.8", "SNAPSHOT" ) -> ("2.11.8-20151215-133023-7559aed", "2.11.8-bin-SNAPSHOT", "2.11.8.v20151215-133023-7559aed")
+ * ("2.11.8", "SHA-SNAPSHOT") -> ("2.11.8-20151215-133023-7559aed", "2.11.8-bin-7559aed-SNAPSHOT", "2.11.8.v20151215-133023-7559aed")
+ * ("2.11.8", "SHA" ) -> ("2.11.8-7559aed", "2.11.8-bin-7559aed", "2.11.8.v20151215-133023-7559aed")
+ * ("2.11.0", "SHA" ) -> ("2.11.0-7559aed", "2.11.0-pre-7559aed", "2.11.0.v20151215-133023-7559aed")
+ * ("2.11.8", "" ) -> ("2.11.8", "2.11.8", "2.11.8.v20151215-133023-VFINAL-7559aed")
+ * ("2.11.8", "M3" ) -> ("2.11.8-M3", "2.11.8-M3", "2.11.8.v20151215-133023-M3-7559aed")
+ * ("2.11.8", "RC4" ) -> ("2.11.8-RC4", "2.11.8-RC4", "2.11.8.v20151215-133023-RC4-7559aed")
+ * ("2.11.8-RC4", "SPLIT" ) -> ("2.11.8-RC4", "2.11.8-RC4", "2.11.8.v20151215-133023-RC4-7559aed")
*
* A `baseVersionSuffix` of "SNAPSHOT" is the default, which is used for local snapshot builds. The PR validation
- * job uses "SHA-SNAPSHOT". An empty suffix is used for releases. All other suffix values are treated as RC /
- * milestone builds. The special suffix value "SPLIT" is used to split the real suffix off from `baseVersion`
- * instead and then apply the usual logic. */
+ * job uses "SHA-SNAPSHOT". A proper version number for an integration build can be computed with "SHA". An empty
+ * suffix is used for releases. All other suffix values are treated as RC / milestone builds. The special suffix
+ * value "SPLIT" is used to split the real suffix off from `baseVersion` instead and then apply the usual logic. */
private lazy val versionPropertiesImpl: Def.Initialize[Versions] = Def.setting {
val (base, suffix) = {
@@ -78,11 +80,18 @@ object VersionUtil {
val date = executeTool("get-scala-commit-date")
val sha = executeTool("get-scala-commit-sha").substring(0, 7) // The script produces 10 digits at the moment
+ val Patch = """\d+\.\d+\.(\d+)""".r
+ def cross = base match {
+ case Patch(p) if p.toInt > 0 => "bin"
+ case _ => "pre"
+ }
+
val (canonicalV, mavenV, osgiV, release) = suffix match {
- case "SNAPSHOT" => (s"$base-$date-$sha", s"$base-SNAPSHOT", s"$base.v$date-$sha", false)
- case "SHA-SNAPSHOT" => (s"$base-$date-$sha", s"$base-$sha-SNAPSHOT", s"$base.v$date-$sha", false)
- case "" => (s"$base", s"$base", s"$base.v$date-VFINAL-$sha", true)
- case suffix => (s"$base-$suffix", s"$base-$suffix", s"$base.v$date-$suffix-$sha", true)
+ case "SNAPSHOT" => (s"$base-$date-$sha", s"$base-$cross-SNAPSHOT", s"$base.v$date-$sha", false)
+ case "SHA-SNAPSHOT" => (s"$base-$date-$sha", s"$base-$cross-$sha-SNAPSHOT", s"$base.v$date-$sha", false)
+ case "SHA" => (s"$base-$sha", s"$base-$cross-$sha", s"$base.v$date-$sha", false)
+ case "" => (s"$base", s"$base", s"$base.v$date-VFINAL-$sha", true)
+ case suffix => (s"$base-$suffix", s"$base-$suffix", s"$base.v$date-$suffix-$sha", true)
}
Versions(canonicalV, mavenV, osgiV, sha, date, release)
diff --git a/scripts/jobs/integrate/bootstrap b/scripts/jobs/integrate/bootstrap
index abb5b283c6..85be794276 100644
--- a/scripts/jobs/integrate/bootstrap
+++ b/scripts/jobs/integrate/bootstrap
@@ -3,16 +3,16 @@
# Script Overview
# - determine scala version
# - determine module versions
-# - build minimal core (aka locker) of Scala, use the determined version number, publish to private-repo
-# - build those modules where a binary compatible version doesn't exist, publish to private-repo
-# - build Scala using the previously built core and bootstrap modules, publish to private-repo (overwrites the minimal core version on private-repo)
-# - for releases (not nightlies)
+# - build minimal core (aka locker) of Scala, use the determined version number, publish to scala-integration
+# - build those modules where a binary compatible version doesn't exist, publish to scala-integration
+# - build Scala using the previously built core and bootstrap modules, publish to scala-integration, overwriting
+# the existing artifacts
+# - for releases
# - stage Scala on sonatype
# - rebuild modules that needed a rebuild with this Scala build, and stage them on sonatype
# - for nightlies
# - force rebuild all modules and publish them locally (for testing purposes)
# - the Scala version is serialized to jenkins.properties, which is passed downstream to scala-release jobs
-# - this removes the need to tag scala/scala-dist (it's still encouraged for releases, but not a hard requirement)
# Specifying the Scala version:
@@ -23,8 +23,8 @@
# - Note: After building a release, the jenkins job provides an updated versions.properties file as artifact.
# Put this file in the Scala repo and create a pull request, and also update the file build.number.
#
-# - Otherwise, a nightly release is built:
-# - version number is read from the build.number file, extended with -$sha-nightly
+# - Otherwise, an integration build is performed:
+# - version number is read from the build.number file, extended with -[bin|pre]-$sha
# Specifying module versions: there are two modes
@@ -56,7 +56,7 @@
# to be re-built using the 2.11.1 release, we could not use 2.11.0. We could also not release the modules
# after 2.11.1 was out, because that way the scala-library-all pom of 2.11.1 would depend on the old modules.
#
-# (*) https://github.com/sbt/sbt/blob/0.13.8/util/cross/src/main/input_sources/CrossVersionUtil.scala#L39
+# (*) https://github.com/sbt/sbt/blob/v0.13.13/util/cross/src/main/input_sources/CrossVersionUtil.scala#L41
# Binary incompatible changes in Modules: example with Scala 2.11 / 2.12 and scala-parser-combinators
@@ -107,24 +107,30 @@ mkdir -p $baseDir/ivy2
rm -rf $baseDir/resolutionScratch_
mkdir -p $baseDir/resolutionScratch_
-# repo used to publish "locker" scala to (to start the bootstrap)
-releaseTempRepoCred="private-repo"
-releaseTempRepoUrl=${releaseTempRepoUrl-"https://scala-ci.typesafe.com/artifactory/scala-release-temp/"}
-jcenterCacheUrl=${jcenterCacheUrl-"https://scala-ci.typesafe.com/artifactory/jcenter/"}
-
-# Used below in sbtArgs since we use a dedicated repository to share artifcacts between jobs,
-# so we need to configure SBT to use these rather than its default, Maven Central.
-# See http://www.scala-sbt.org/0.13/docs/Proxy-Repositories.html
-sbtRepositoryConfig="$scriptsDir/repositories-scala-release"
-cat > "$sbtRepositoryConfig" << EOF
+function generateRepositoriesConfig(){
+ # Used below in sbtArgs since we use a dedicated repository to share artifcacts between jobs,
+ # so we need to configure SBT to use these rather than its default, Maven Central.
+ # See http://www.scala-sbt.org/0.13/docs/Proxy-Repositories.html
+ sbtRepositoryConfig="$scriptsDir/repositories-scala-release"
+ jcenterCacheUrl=${jcenterCacheUrl-"https://scala-ci.typesafe.com/artifactory/jcenter/"}
+ cat > "$sbtRepositoryConfig" << EOF
[repositories]
- private-repo: $releaseTempRepoUrl
+ script-repo: $1
jcenter-cache: $jcenterCacheUrl
typesafe-ivy-releases: https://dl.bintray.com/typesafe/ivy-releases/, [organisation]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext], bootOnly
sbt-plugin-releases: https://dl.bintray.com/sbt/sbt-plugin-releases/, [organisation]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]
maven-central
local
EOF
+}
+
+integrationRepoCred="private-repo"
+
+# repo for locker, quick and the modules
+integrationRepoUrl=${integrationRepoUrl-"https://scala-ci.typesafe.com/artifactory/scala-integration/"}
+
+# adding `integrationRepoUrl` to find the locker scala version when building modules
+generateRepositoriesConfig $integrationRepoUrl
##### git
gfxd() {
@@ -198,15 +204,15 @@ sbtResolve() {
# 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
+# Each buildModule() function is invoked twice: first to build against locker and publish to artifactory, 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!
+# In the second round, sbtResolve is always true: the module will be found in the artifactory!
# 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,
+# Note: we tried an alternative solution in which sbtResolve would not look at artifactory, 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.
+# which exists only in artifactory.
buildXML() {
if [ "$XML_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-xml" $XML_VER )
@@ -281,7 +287,7 @@ buildActorsMigration(){
fi
}
-# should only be called with publishTasks publishing to private-repo
+# should only be called with publishTasks publishing to artifactory
buildScalacheck(){
if [ "$SCALACHECK_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scalacheck" "scalacheck" $SCALACHECK_VER )
then echo "Found scalacheck $SCALACHECK_VER; not building."
@@ -292,9 +298,9 @@ buildScalacheck(){
fi
}
-# build modules, using ${buildTasks[@]} (except for Scalacheck, which is hard-coded to publish to private-repo)
+# build modules, using ${buildTasks[@]} (except for Scalacheck, which is hard-coded to publish to artifactory)
buildModules() {
- publishTasks=('set credentials += Credentials(Path.userHome / ".credentials-private-repo")' "set every publishTo := Some(\"private-repo\" at \"$releaseTempRepoUrl\")")
+ publishTasks=('set credentials += Credentials(Path.userHome / ".credentials-private-repo")' "set every publishTo := Some(\"publish-repo\" at \"$integrationRepoUrl\")")
buildTasks=($publishPrivateTask)
buildXML
buildParsers
@@ -329,20 +335,19 @@ scalaVerToBinary() {
local patch="$(echo $2 | sed -e "s#$RE#\3#")"
# The binary version is majMin (e.g. "2.12") if
- # - there's no suffix : 2.12.0, 2.12.1
- # - the suffix starts with "-bin": 2.12.0-bin-M1
- # - the patch version is > 0 : 2.12.1-M1, 1.12.3-RC2, 2.12.1-sha-nightly, 2.12.2-SNAPSHOT
+ # - there's no suffix : 2.12.0, 2.12.1
+ # - the suffix starts with "-bin" : 2.12.1-bin-sha, 2.12.1-bin-sha-custom, 2.12.1-bin-SNAPSHOT
+ # - the suffix is \w+ and patch version is > 0: 2.12.1-M1, 2.12.1-RC2 (also 2.12.1-sha, 2.12.1-SNAPSHOT, which we don't use)
#
- # Otherwise, the binary version is the full version: 2.12.0-M1, 2.12.0-RC2, 2.12.0-sha-nightly, 2.12.0-SNAPSHOT
+ # Otherwise, the binary version is the full version: 2.12.0-M1, 2.12.0-RC2, 2.12.0-pre-sha, 2.12.0-pre-SNAPSHOT
+ # (also 2.12.0-sha, 2.12.0-SNAPSHOT, which we don't use)
#
- # Adapted from sbt: https://github.com/sbt/sbt/blob/0.13.8/util/cross/src/main/input_sources/CrossVersionUtil.scala#L39
+ # Adapted from sbt: https://github.com/sbt/sbt/blob/v0.13.13/util/cross/src/main/input_sources/CrossVersionUtil.scala#L42
#
- # Note: during the pre-release cycle of a major release (e.g. before 2.12.0), the SCALA_BINARY_VER of nightly / SNAPSHOT
- # versions is the full version, e.g. 2.12.0-sha-nightly, so modules are always re-built. This is in line with what sbt
- # does: for example, with scalaVersion := "2.12.0-SNAPSHOT", sbt will resolve scala-xml as scala-xml_2.12.0-SNAPSHOT.
- # Once the 2.12.0 release is out, the binary version is 2.12 for all versions (e.g. for 2.12.1-sha-nightly).
+ # During the pre-release cycle of a major release (e.g. before 2.12.0), the SCALA_BINARY_VER of integration / SNAPSHOT
+ # versions is the full version, e.g. 2.12.0-pre-sha, so modules are always re-built.
- if [[ "$3" == "" || "${3:0:4}" == "-bin" || "$patch" != "0" ]]; then
+ if [[ "$3" == "" || "${3:0:4}" == "-bin" || ("$patch" != "0" && "$3" =~ ^-[a-zA-Z0-9_]+$) ]]; then
echo "$majMin"
else
echo "$1"
@@ -363,10 +368,15 @@ determineScalaVersion() {
if [ -z "$scalaTag" ]
then
- echo "No tag found, building nightly snapshot."
+ echo "No tag found, running an integration build."
parseScalaProperties "build.number"
SCALA_VER_BASE="$version_major.$version_minor.$version_patch"
- SCALA_VER_SUFFIX="-$(git rev-parse --short HEAD)-nightly"
+ local shaSuffix=$(git rev-parse HEAD | cut -c1-7)
+ local cross="bin"
+ if [[ $SCALA_VER_BASE =~ ^.*\.0$ ]]; then
+ cross="pre"
+ fi
+ SCALA_VER_SUFFIX="-$cross-$shaSuffix"
SCALADOC_SOURCE_LINKS_VER=$(git rev-parse HEAD)
# TODO: publish nightly snapshot using this script - currently it's a separate jenkins job still running at EPFL.
@@ -468,20 +478,31 @@ createNetrcFile() {
grep 'password=' $1 | sed 's/password=\(.*\)/password \1/' >> $netrcFile
}
+# deletes existing artifacts (core and modules) matching the $SCALA_VER from the repository passed as argument
removeExistingBuilds() {
- createNetrcFile "$HOME/.credentials-private-repo"
- local netrcFile="$HOME/.credentials-private-repo-netrc"
-
- local storageApiUrl=`echo $releaseTempRepoUrl | sed 's/\(scala-release-temp\)/api\/storage\/\1/'`
- local scalaLangModules=`curl -s $storageApiUrl/org/scala-lang | jq -r '.children | .[] | "org/scala-lang" + .uri'`
-
- for module in "org/scalacheck" $scalaLangModules; do
- local artifacts=`curl -s $storageApiUrl/$module | jq -r ".children | .[] | select(.uri | endswith(\"$SCALA_VER\")) | .uri"`
- for artifact in $artifacts; do
- echo "Deleting $releaseTempRepoUrl$module$artifact"
- curl -s --netrc-file $netrcFile -X DELETE $releaseTempRepoUrl$module$artifact
+ local repoUrl=$1
+ local repoPrefix="https://scala-ci.typesafe.com/artifactory/"
+ if [[ $repoUrl == "$repoPrefix"* ]]; then
+ local repoId=${1#$repoPrefix}
+ local storageApiUrl="${repoPrefix}api/storage/$repoId"
+
+ createNetrcFile "$HOME/.credentials-private-repo"
+ local netrcFile="$HOME/.credentials-private-repo-netrc"
+
+ # "module" is not a scala module (like scala-xml), but an artifact of a boostrap build. the variable
+ # contains: "org/scala-lang/modules", "org/scala-lang/scala-compiler", "org/scala-lang/scala-library", ...
+ local scalaLangModules=`curl -s $storageApiUrl/org/scala-lang | jq -r '.children | .[] | "org/scala-lang" + .uri' | grep -v actors-migration`
+
+ for module in $scalaLangModules; do
+ local artifacts=`curl -s $storageApiUrl/$module | jq -r ".children | .[] | select(.uri | endswith(\"$SCALA_VER\")) | .uri"`
+ for artifact in $artifacts; do
+ echo "Deleting $repoUrl$module$artifact"
+ curl -s --netrc-file $netrcFile -X DELETE $repoUrl$module$artifact
+ done
done
- done
+ else
+ echo "Unknown repo, not deleting anything: $repoUrl"
+ fi
}
constructUpdatedModuleVersions() {
@@ -507,7 +528,7 @@ constructUpdatedModuleVersions() {
if [ ! -z "$SCALA_BINARY_VER" ]; then updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala.binary.version=$SCALA_BINARY_VER"); fi
}
-# build locker (scala + modules) and quick, publishing everything to private-repo
+# build locker (scala + modules) and quick, publishing everything to artifactory
bootstrap() {
echo "### Bootstrapping"
@@ -524,8 +545,8 @@ bootstrap() {
# 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=$releaseTempRepoUrl\
- -Drepository.credentials.id=$releaseTempRepoCred\
+ -Dremote.release.repository=$integrationRepoUrl\
+ -Drepository.credentials.id=$integrationRepoCred\
-Dscalac.args.optimise=-optimise\
-Ddocs.skip=1\
-Dlocker.skip=1\
@@ -561,14 +582,14 @@ bootstrap() {
# which is fully cross-versioned (for $SCALA_VER, the version we're releasing)
ant -Dstarr.version=$SCALA_VER\
-Dscala.full.version=$SCALA_VER\
- -Dextra.repo.url=$releaseTempRepoUrl\
+ -Dextra.repo.url=$integrationRepoUrl\
-Dmaven.version.suffix=$SCALA_VER_SUFFIX\
${updatedModuleVersions[@]} \
-Dupdate.versions=1\
-Dscaladoc.git.commit=$SCALADOC_SOURCE_LINKS_VER\
-Dremote.snapshot.repository=NOPE\
- -Dremote.release.repository=$releaseTempRepoUrl\
- -Drepository.credentials.id=$releaseTempRepoCred\
+ -Dremote.release.repository=$integrationRepoUrl\
+ -Drepository.credentials.id=$integrationRepoCred\
-Dscalac.args.optimise=-optimise\
$antBuildTask $publishPrivateTask
@@ -614,7 +635,7 @@ determineScalaVersion
deriveModuleVersions
-removeExistingBuilds
+removeExistingBuilds $integrationRepoUrl
bootstrap
diff --git a/spec/05-classes-and-objects.md b/spec/05-classes-and-objects.md
index 69828ec7fe..65666e31cb 100644
--- a/spec/05-classes-and-objects.md
+++ b/spec/05-classes-and-objects.md
@@ -851,9 +851,8 @@ already a `val` or `var` modifier. Hence, an accessor
definition for the parameter is [generated](#class-definitions).
A case class definition of `$c$[$\mathit{tps}\,$]($\mathit{ps}_1\,$)$\ldots$($\mathit{ps}_n$)` with type
-parameters $\mathit{tps}$ and value parameters $\mathit{ps}$ implicitly
-generates an [extractor object](08-pattern-matching.html#extractor-patterns) which is
-defined as follows:
+parameters $\mathit{tps}$ and value parameters $\mathit{ps}$ implies
+the definition of a companion object, which serves as an [extractor object](08-pattern-matching.html#extractor-patterns). It has the following shape:
```scala
object $c$ {
@@ -870,11 +869,13 @@ each $\mathit{xs}\_i$ denotes the parameter names of the parameter
section $\mathit{ps}\_i$, and
$\mathit{xs}\_{11}, \ldots , \mathit{xs}\_{1k}$ denote the names of all parameters
in the first parameter section $\mathit{xs}\_1$.
-If a type parameter section is missing in the
-class, it is also missing in the `apply` and
-`unapply` methods.
-The definition of `apply` is omitted if class $c$ is
-`abstract`.
+If a type parameter section is missing in the class, it is also missing in the `apply` and `unapply` methods.
+
+If the companion object $c$ is already defined,
+the `apply` and `unapply` methods are added to the existing object.
+If the object $c$ already has a [matching](#definition-matching)
+`apply` (or `unapply`) member, no new definition is added.
+The definition of `apply` is omitted if class $c$ is `abstract`.
If the case class definition contains an empty value parameter list, the
`unapply` method returns a `Boolean` instead of an `Option` type and
@@ -887,9 +888,6 @@ def unapply[$\mathit{tps}\,$]($x$: $c$[$\mathit{tps}\,$]) = x ne null
The name of the `unapply` method is changed to `unapplySeq` if the first
parameter section $\mathit{ps}_1$ of $c$ ends in a
[repeated parameter](04-basic-declarations-and-definitions.html#repeated-parameters).
-If a companion object $c$ exists already, no new object is created,
-but the `apply` and `unapply` methods are added to the existing
-object instead.
A method named `copy` is implicitly added to every case class unless the
class already has a member (directly defined or inherited) with that name, or the
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala b/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala
index 43bdad5882..d7901730a4 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala
@@ -135,7 +135,7 @@ abstract class ScalaBuild extends Ordered[ScalaBuild] {
def unparse: String
}
/**
- * A development, test, nightly, snapshot or other "unofficial" build
+ * A development, test, integration, snapshot or other "unofficial" build
*/
case class Development(id: String) extends ScalaBuild {
def unparse = s"-${id}"
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index ee64a6646f..69b8cb12e6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -610,7 +610,15 @@ trait Namers extends MethodSynthesis {
noDuplicates(selectors map (_.rename), AppearsTwice)
}
- def enterCopyMethod(copyDef: DefDef): Symbol = {
+ class CompleterWrapper(completer: TypeCompleter) extends TypeCompleter {
+ val tree = completer.tree
+
+ override def complete(sym: Symbol): Unit = {
+ completer.complete(sym)
+ }
+ }
+
+ def copyMethodCompleter(copyDef: DefDef): TypeCompleter = {
val sym = copyDef.symbol
val lazyType = completerOf(copyDef)
@@ -629,13 +637,72 @@ trait Namers extends MethodSynthesis {
)
}
- sym setInfo {
- mkTypeCompleter(copyDef) { sym =>
- assignParamTypes()
- lazyType complete sym
+ mkTypeCompleter(copyDef) { sym =>
+ assignParamTypes()
+ lazyType complete sym
+ }
+ }
+
+ // for apply/unapply, which may need to disappear when they clash with a user-defined method of matching signature
+ def applyUnapplyMethodCompleter(un_applyDef: DefDef, companionContext: Context): TypeCompleter =
+ new CompleterWrapper(completerOf(un_applyDef)) {
+ override def complete(sym: Symbol): Unit = {
+ assert(sym hasAllFlags CASE | SYNTHETIC, sym.defString)
+
+ super.complete(sym)
+
+ // owner won't be locked
+ val ownerInfo = companionContext.owner.info
+
+ // If there's a same-named locked symbol, we're currently completing its signature.
+ // If `scopePartiallyCompleted`, the program is known to have a type error, since
+ // this means a user-defined method is missing a result type while its rhs refers to `sym` or an overload.
+ // This is an error because overloaded/recursive methods must have a result type.
+ // The method would be overloaded if its signature, once completed, would not match the synthetic method's,
+ // or recursive if it turned out we should unlink our synthetic method (matching sig).
+ // In any case, error out. We don't unlink the symbol so that `symWasOverloaded` says yes,
+ // which would be wrong if the method is in fact recursive, but it seems less confusing.
+ val scopePartiallyCompleted = new HasMember(ownerInfo, sym.name, BridgeFlags | SYNTHETIC, LOCKED).apply()
+
+ // Check `scopePartiallyCompleted` first to rule out locked symbols from the owner.info.member call,
+ // as FindMember will call info on a locked symbol (while checking type matching to assemble an overloaded type),
+ // and throw a TypeError, so that we are aborted.
+ // Do not consider deferred symbols, as suppressing our concrete implementation would be an error regardless
+ // of whether the signature matches (if it matches, we omitted a valid implementation, if it doesn't,
+ // we would get an error for the missing implementation it isn't implemented by some overload other than our synthetic one)
+ val suppress = scopePartiallyCompleted || {
+ // can't exclude deferred members using DEFERRED flag here (TODO: why?)
+ val userDefined = ownerInfo.memberBasedOnName(sym.name, BridgeFlags | SYNTHETIC)
+
+ (userDefined != NoSymbol) && {
+ assert(userDefined != sym)
+ val alts = userDefined.alternatives // could be just the one, if this member isn't overloaded
+ // don't compute any further `memberInfo`s if there's an error somewhere
+ alts.exists(_.isErroneous) || {
+ val self = companionContext.owner.thisType
+ val memberInfo = self.memberInfo(sym)
+ alts.exists(alt => !alt.isDeferred && (self.memberInfo(alt) matches memberInfo))
+ }
+ }
+ }
+
+ if (suppress) {
+ sym setInfo ErrorType
+ sym setFlag IS_ERROR
+
+ // Don't unlink in an error situation to generate less confusing error messages.
+ // Ideally, our error reporting would distinguish overloaded from recursive user-defined apply methods without signature,
+ // but this would require some form of partial-completion of method signatures, so that we can
+ // know what the argument types were, even though we can't complete the result type, because
+ // we hit a cycle while trying to compute it (when we get here with locked user-defined symbols, we
+ // are in the complete for that symbol, and thus the locked symbol has not yet received enough info;
+ // I hesitate to provide more info, because it would involve a WildCard or something for its result type,
+ // which could upset other code paths)
+ if (!scopePartiallyCompleted)
+ companionContext.scope.unlink(sym)
+ }
}
}
- }
def completerOf(tree: Tree): TypeCompleter = {
val mono = namerOf(tree.symbol) monoTypeCompleter tree
@@ -697,11 +764,15 @@ trait Namers extends MethodSynthesis {
val bridgeFlag = if (mods hasAnnotationNamed tpnme.bridgeAnnot) BRIDGE | ARTIFACT else 0
val sym = assignAndEnterSymbol(tree) setFlag bridgeFlag
- if (name == nme.copy && sym.isSynthetic)
- enterCopyMethod(tree)
- else
- sym setInfo completerOf(tree)
- }
+ val completer =
+ if (sym hasFlag SYNTHETIC) {
+ if (name == nme.copy) copyMethodCompleter(tree)
+ else if (sym hasFlag CASE) applyUnapplyMethodCompleter(tree, context)
+ else completerOf(tree)
+ } else completerOf(tree)
+
+ sym setInfo completer
+ }
def enterClassDef(tree: ClassDef) {
val ClassDef(mods, _, _, impl) = tree
@@ -1351,7 +1422,7 @@ trait Namers extends MethodSynthesis {
val defTpt =
// don't mess with tpt's of case copy default getters, because assigning something other than TypeTree()
- // will break the carefully orchestrated naming/typing logic that involves enterCopyMethod and caseClassCopyMeth
+ // will break the carefully orchestrated naming/typing logic that involves copyMethodCompleter and caseClassCopyMeth
if (meth.isCaseCopy) TypeTree()
else {
// If the parameter type mentions any type parameter of the method, let the compiler infer the
diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala
index 7ea597eac9..416aeeccb3 100644
--- a/src/library/scala/util/Properties.scala
+++ b/src/library/scala/util/Properties.scala
@@ -105,7 +105,7 @@ private[scala] trait PropertiesTrait {
* or "version (unknown)" if it cannot be determined.
*/
val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
- val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2016, LAMP/EPFL")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2017, LAMP/EPFL and Lightbend, Inc.")
/** This is the encoding to use reading in source files, overridden with -encoding.
* Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
diff --git a/src/reflect/scala/reflect/internal/tpe/FindMembers.scala b/src/reflect/scala/reflect/internal/tpe/FindMembers.scala
index 83a5d23e7c..1b00815bca 100644
--- a/src/reflect/scala/reflect/internal/tpe/FindMembers.scala
+++ b/src/reflect/scala/reflect/internal/tpe/FindMembers.scala
@@ -285,4 +285,18 @@ trait FindMembers {
initBaseClasses.head.newOverloaded(tpe, members)
}
}
+
+ private[scala] final class HasMember(tpe: Type, name: Name, excludedFlags: Long, requiredFlags: Long) extends FindMemberBase[Boolean](tpe, name, excludedFlags, requiredFlags) {
+ private[this] var _result = false
+ override protected def result: Boolean = _result
+
+ protected def shortCircuit(sym: Symbol): Boolean = {
+ _result = true
+ true // prevents call to addMemberIfNew
+ }
+
+ // Not used
+ protected def addMemberIfNew(sym: Symbol): Unit = {}
+ }
+
}
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala
index f70bac8f83..08d3508a78 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala
@@ -280,7 +280,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
{
if (Set("epfl", "EPFL").contains(tpl.universe.settings.docfooter.value))
- <div id="footer">Scala programming documentation. Copyright (c) 2003-2016 <a href="http://www.epfl.ch" target="_top">EPFL</a>, with contributions from <a href="http://www.lightbend.com" target="_top">Lightbend</a>.</div>
+ <div id="footer">Scala programming documentation. Copyright (c) 2003-2017 <a href="http://www.epfl.ch" target="_top">EPFL</a>, with contributions from <a href="http://www.lightbend.com" target="_top">Lightbend</a>.</div>
else
<div id="footer"> { tpl.universe.settings.docfooter.value } </div>
}
diff --git a/src/scalap/decoder.properties b/src/scalap/decoder.properties
index 9bb8d130ea..0bff4c81d4 100644
--- a/src/scalap/decoder.properties
+++ b/src/scalap/decoder.properties
@@ -1,2 +1,2 @@
version.number=2.0.1
-copyright.string=(c) 2002-2016 LAMP/EPFL
+copyright.string=(c) 2002-2017 LAMP/EPFL
diff --git a/test/files/neg/userdefined_apply.check b/test/files/neg/userdefined_apply.check
new file mode 100644
index 0000000000..c8c8976f5f
--- /dev/null
+++ b/test/files/neg/userdefined_apply.check
@@ -0,0 +1,25 @@
+userdefined_apply.scala:3: error: overloaded method apply needs result type
+ private def apply(x: Int) = if (x > 0) new ClashOverloadNoSig(x) else apply("")
+ ^
+userdefined_apply.scala:14: error: overloaded method apply needs result type
+ private def apply(x: Int) = if (x > 0) ClashRecNoSig(1) else ???
+ ^
+userdefined_apply.scala:21: error: overloaded method apply needs result type
+ private def apply(x: Boolean) = if (x) NoClashNoSig(1) else ???
+ ^
+userdefined_apply.scala:28: error: overloaded method apply needs result type
+ private def apply(x: Boolean) = if (x) NoClashOverload(1) else apply("")
+ ^
+userdefined_apply.scala:45: error: recursive method apply needs result type
+case class NoClashNoSigPoly private(x: Int)
+ ^
+userdefined_apply.scala:39: error: NoClashNoSigPoly.type does not take parameters
+ def apply(x: T) = if (???) NoClashNoSigPoly(1) else ???
+ ^
+userdefined_apply.scala:57: error: recursive method apply needs result type
+case class ClashNoSigPoly private(x: Int)
+ ^
+userdefined_apply.scala:51: error: ClashNoSigPoly.type does not take parameters
+ def apply(x: T) = if (???) ClashNoSigPoly(1) else ???
+ ^
+8 errors found
diff --git a/test/files/neg/userdefined_apply.scala b/test/files/neg/userdefined_apply.scala
new file mode 100644
index 0000000000..0a0d960b39
--- /dev/null
+++ b/test/files/neg/userdefined_apply.scala
@@ -0,0 +1,57 @@
+object ClashOverloadNoSig {
+ // error: overloaded method apply needs result type
+ private def apply(x: Int) = if (x > 0) new ClashOverloadNoSig(x) else apply("")
+
+ def apply(x: String): ClashOverloadNoSig = ???
+}
+
+case class ClashOverloadNoSig private(x: Int)
+
+object ClashRecNoSig {
+ // TODO: status quo is that the error refers to an overloaded method, which is actually recursive
+ // (we should have unlinked the symbol in the `if(suppress)` part of `applyUnapplyMethodCompleter`)
+ // error: recursive method apply needs result type
+ private def apply(x: Int) = if (x > 0) ClashRecNoSig(1) else ???
+}
+
+case class ClashRecNoSig private(x: Int)
+
+object NoClashNoSig {
+ // error: overloaded method apply needs result type
+ private def apply(x: Boolean) = if (x) NoClashNoSig(1) else ???
+}
+
+case class NoClashNoSig private(x: Int)
+
+object NoClashOverload {
+ // error: overloaded method apply needs result type
+ private def apply(x: Boolean) = if (x) NoClashOverload(1) else apply("")
+
+ def apply(x: String): NoClashOverload = ???
+}
+
+case class NoClashOverload private(x: Int)
+
+
+class BaseNCNSP[T] {
+ // TODO: suppress the following error
+ // error: NoClashNoSigPoly.type does not take parameters
+ def apply(x: T) = if (???) NoClashNoSigPoly(1) else ???
+}
+
+object NoClashNoSigPoly extends BaseNCNSP[Boolean]
+// TODO: position error at definition of apply in superclass instead of on case clss
+// error: recursive method apply needs result type
+case class NoClashNoSigPoly private(x: Int)
+
+
+class BaseCNSP[T] {
+ // TODO: suppress the following error
+ // error: ClashNoSigPoly.type does not take parameters
+ def apply(x: T) = if (???) ClashNoSigPoly(1) else ???
+}
+
+object ClashNoSigPoly extends BaseCNSP[Int]
+// TODO: position error at definition of apply in superclass instead of on case clss
+// error: recursive method apply needs result type
+case class ClashNoSigPoly private(x: Int)
diff --git a/test/files/pos/userdefined_apply.scala b/test/files/pos/userdefined_apply.scala
new file mode 100644
index 0000000000..e29f9f5141
--- /dev/null
+++ b/test/files/pos/userdefined_apply.scala
@@ -0,0 +1,54 @@
+// NOTE: the companion inherits a public apply method from Function1!
+case class NeedsCompanion private (x: Int)
+
+object ClashNoSig { // ok
+ private def apply(x: Int) = if (x > 0) new ClashNoSig(x) else ???
+}
+case class ClashNoSig private (x: Int)
+
+
+object Clash {
+ private def apply(x: Int) = if (x > 0) new Clash(x) else ???
+}
+case class Clash private (x: Int)
+
+object ClashSig {
+ private def apply(x: Int): ClashSig = if (x > 0) new ClashSig(x) else ???
+}
+case class ClashSig private (x: Int)
+
+object ClashOverload {
+ private def apply(x: Int): ClashOverload = if (x > 0) new ClashOverload(x) else apply("")
+ def apply(x: String): ClashOverload = ???
+}
+case class ClashOverload private (x: Int)
+
+object NoClashSig {
+ private def apply(x: Boolean): NoClashSig = if (x) NoClashSig(1) else ???
+}
+case class NoClashSig private (x: Int)
+
+object NoClashOverload {
+ // needs full sig
+ private def apply(x: Boolean): NoClashOverload = if (x) NoClashOverload(1) else apply("")
+ def apply(x: String): NoClashOverload = ???
+}
+case class NoClashOverload private (x: Int)
+
+
+
+class BaseNCP[T] {
+ // error: overloaded method apply needs result type
+ def apply(x: T): NoClashPoly = if (???) NoClashPoly(1) else ???
+}
+
+object NoClashPoly extends BaseNCP[Boolean]
+case class NoClashPoly private(x: Int)
+
+
+class BaseCP[T] {
+ // error: overloaded method apply needs result type
+ def apply(x: T): ClashPoly = if (???) ClashPoly(1) else ???
+}
+object ClashPoly extends BaseCP[Int]
+case class ClashPoly private(x: Int)