From 42101109eae04a91d8d9e72f6cbe93cebf594c75 Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Tue, 10 Dec 2024 15:38:45 -0500 Subject: [PATCH 1/5] fix: update `scala-cli.jar` path Signed-off-by: Rui Chen [Cherry-picked 70cc1a19da85f502fc58c8f0ed4fbe6ff9444e7d] --- dist/libexec/cli-common-platform | 2 +- dist/libexec/cli-common-platform.bat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/libexec/cli-common-platform b/dist/libexec/cli-common-platform index a5906e882bb4..e56f5221dbf2 100644 --- a/dist/libexec/cli-common-platform +++ b/dist/libexec/cli-common-platform @@ -1,3 +1,3 @@ #!/usr/bin/env bash -SCALA_CLI_CMD_BASH=("\"$JAVACMD\"" "-jar \"$PROG_HOME/bin/scala-cli.jar\"") +SCALA_CLI_CMD_BASH=("\"$JAVACMD\"" "-jar \"$PROG_HOME/libexec/scala-cli.jar\"") diff --git a/dist/libexec/cli-common-platform.bat b/dist/libexec/cli-common-platform.bat index 99103266c1d9..45b09f3460e6 100644 --- a/dist/libexec/cli-common-platform.bat +++ b/dist/libexec/cli-common-platform.bat @@ -2,4 +2,4 @@ @rem we need to escape % in the java command path, for some reason this doesnt work in common.bat set "_JAVACMD=!_JAVACMD:%%=%%%%!" -set SCALA_CLI_CMD_WIN="%_JAVACMD%" "-jar" "%_PROG_HOME%\bin\scala-cli.jar" \ No newline at end of file +set SCALA_CLI_CMD_WIN="%_JAVACMD%" "-jar" "%_PROG_HOME%\libexec\scala-cli.jar" From ff78d080612b0f816d68e2b88d481cb6825e5daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreira?= Date: Tue, 10 Dec 2024 11:24:02 +0000 Subject: [PATCH 2/5] Limit exposure to ConcurrentModificationException when sys props are replaced or mutated port of https://github.com/scala/scala/commit/f6859f28bb49193fde83e6020a6a89ce926a91e8 [Cherry-picked 705c33ca9ca4ed01e8b11c7928468fbd2a267aa7] --- .../src/dotty/tools/dotc/config/PathResolver.scala | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/PathResolver.scala b/compiler/src/dotty/tools/dotc/config/PathResolver.scala index 29e6e35855c8..67be0e3587cb 100644 --- a/compiler/src/dotty/tools/dotc/config/PathResolver.scala +++ b/compiler/src/dotty/tools/dotc/config/PathResolver.scala @@ -36,9 +36,16 @@ object PathResolver { /** Values found solely by inspecting environment or property variables. */ object Environment { - private def searchForBootClasspath = ( - systemProperties find (_._1 endsWith ".boot.class.path") map (_._2) getOrElse "" - ) + private def searchForBootClasspath = { + import scala.jdk.CollectionConverters.* + val props = System.getProperties + // This formulation should be immune to ConcurrentModificationExceptions when system properties + // we're unlucky enough to witness a partially published result of System.setProperty or direct + // mutation of the System property map. stringPropertyNames internally uses the Enumeration interface, + // rather than Iterator, and this disables the fail-fast ConcurrentModificationException. + val propNames = props.stringPropertyNames() + propNames.asScala collectFirst { case k if k endsWith ".boot.class.path" => props.getProperty(k) } getOrElse "" + } /** Environment variables which java pays attention to so it * seems we do as well. From 87d6ed9e30e0e94eac97758ed47a36a72a86c554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreira?= Date: Tue, 10 Dec 2024 13:32:39 +0000 Subject: [PATCH 3/5] improve javaBootClassPath lazy evaluation [Cherry-picked 31690d45237fb6aab7e0474ee115d7bdfe8a0892] --- compiler/src/dotty/tools/dotc/config/PathResolver.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/config/PathResolver.scala b/compiler/src/dotty/tools/dotc/config/PathResolver.scala index 67be0e3587cb..f60727e6bba2 100644 --- a/compiler/src/dotty/tools/dotc/config/PathResolver.scala +++ b/compiler/src/dotty/tools/dotc/config/PathResolver.scala @@ -53,7 +53,8 @@ object PathResolver { def classPathEnv: String = envOrElse("CLASSPATH", "") def sourcePathEnv: String = envOrElse("SOURCEPATH", "") - def javaBootClassPath: String = propOrElse("sun.boot.class.path", searchForBootClasspath) + //using propOrNone/getOrElse instead of propOrElse so that searchForBootClasspath is lazy evaluated + def javaBootClassPath: String = propOrNone("sun.boot.class.path") getOrElse searchForBootClasspath def javaExtDirs: String = propOrEmpty("java.ext.dirs") def scalaHome: String = propOrEmpty("scala.home") From 09a8ff1bb3e59ed32b0bf9bad4f6ba9bd7ca7268 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 22 Oct 2024 03:00:58 -0700 Subject: [PATCH 4/5] Nowarn extension matching nonpublic member [Cherry-picked d0fdbfb4cace1bba61fcffc95fba4de1c236e3eb] --- .../dotty/tools/dotc/typer/RefChecks.scala | 23 +++++++++++-------- tests/warn/i21816.scala | 17 ++++++++++++++ 2 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 tests/warn/i21816.scala diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 0a0356707048..6945dffbe2f2 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -1169,16 +1169,19 @@ object RefChecks { target.nonPrivateMember(sym.name) .filterWithPredicate: member => - val memberIsImplicit = member.info.hasImplicitParams - val paramTps = - if memberIsImplicit then methTp.stripPoly.firstParamTypes - else methTp.firstExplicitParamTypes - - paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || { - val memberParamTps = member.info.stripPoly.firstParamTypes - !memberParamTps.isEmpty - && memberParamTps.lengthCompare(paramTps) == 0 - && memberParamTps.lazyZip(paramTps).forall((m, x) => x frozen_<:< m) + val memberIsPublic = (member.symbol.flags & AccessFlags).isEmpty && !member.symbol.privateWithin.exists + memberIsPublic && { + val memberIsImplicit = member.info.hasImplicitParams + val paramTps = + if memberIsImplicit then methTp.stripPoly.firstParamTypes + else methTp.firstExplicitParamTypes + + paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || { + val memberParamTps = member.info.stripPoly.firstParamTypes + !memberParamTps.isEmpty + && memberParamTps.lengthCompare(paramTps) == 0 + && memberParamTps.lazyZip(paramTps).forall((m, x) => x frozen_<:< m) + } } .exists if !target.typeSymbol.denot.isAliasType && !target.typeSymbol.denot.isOpaqueAlias && hidden diff --git a/tests/warn/i21816.scala b/tests/warn/i21816.scala new file mode 100644 index 000000000000..9153b8b0ee2f --- /dev/null +++ b/tests/warn/i21816.scala @@ -0,0 +1,17 @@ + +case class CC(a: String, b: String) extends Iterable[String] { + override def iterator: Iterator[String] = Iterator(a, b) +} + +trait T { + extension (cc: CC) def className: String = "foo" +} + +object O extends T { + def foo = { + val cc = CC("a", "b") + println(cc.className) + } +} + +@main def main() = O.foo From b6bc62c8acbd1f38a2ff1799be32ca3c311a4f0c Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 22 Oct 2024 08:04:10 -0700 Subject: [PATCH 5/5] Prefer isPublic in RefChecks [Cherry-picked ae1b583325a160ed980808be7915c1adb66ac22a] --- compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 6945dffbe2f2..0ec9458cac5c 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -525,7 +525,6 @@ object RefChecks { // todo: align accessibility implication checking with isAccessible in Contexts def isOverrideAccessOK = - val memberIsPublic = (member.flags & AccessFlags).isEmpty && !member.privateWithin.exists def protectedOK = !other.is(Protected) || member.is(Protected) // if o is protected, so is m def accessBoundaryOK = val ob = other.accessBoundary(member.owner) @@ -534,7 +533,7 @@ object RefChecks { def companionBoundaryOK = ob.isClass && !ob.isLocalToBlock && mb.is(Module) && (ob.companionModule eq mb.companionModule) ob.isContainedIn(mb) || companionBoundaryOK // m relaxes o's access boundary, def otherIsJavaProtected = other.isAllOf(JavaProtected) // or o is Java defined and protected (see #3946) - memberIsPublic || protectedOK && (accessBoundaryOK || otherIsJavaProtected) + member.isPublic || protectedOK && (accessBoundaryOK || otherIsJavaProtected) end isOverrideAccessOK if !member.hasTargetName(other.targetName) then @@ -1169,8 +1168,7 @@ object RefChecks { target.nonPrivateMember(sym.name) .filterWithPredicate: member => - val memberIsPublic = (member.symbol.flags & AccessFlags).isEmpty && !member.symbol.privateWithin.exists - memberIsPublic && { + member.symbol.isPublic && { val memberIsImplicit = member.info.hasImplicitParams val paramTps = if memberIsImplicit then methTp.stripPoly.firstParamTypes