diff --git a/compiler/src/dotty/tools/dotc/config/PathResolver.scala b/compiler/src/dotty/tools/dotc/config/PathResolver.scala index 29e6e35855c8..f60727e6bba2 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. @@ -46,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") diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 0a0356707048..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,16 +1168,18 @@ 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) + member.symbol.isPublic && { + 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/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" 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