Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import config.Printers.refcheck
import reporting.*
import Constants.Constant
import cc.stripCapturing
import dotty.tools.dotc.printing.Formatting.hl

object RefChecks {
import tpd.*
Expand Down Expand Up @@ -1274,6 +1275,18 @@ object RefChecks {
case tp: NamedType if tp.prefix.typeSymbol != ctx.owner.enclosingClass =>
report.warning(UnqualifiedCallToAnyRefMethod(tree, tree.symbol), tree)
case _ => ()

def checkJavaStaticProtected(tree: tpd.Apply | tpd.Select | tpd.Assign)(using Context): Unit =
val sym = tree.symbol
if sym.isAllOf(StaticProtected) then
val definedPackage = sym.enclosingPackageClass
val definedClass = sym.owner.companionClass //it's _not_ sym.enclosingClass because it's static, therefore enclosed in a companion object, not a class
val enclosingPackage = ctx.owner.enclosingPackageClass

if definedPackage != enclosingPackage && !ctx.owner.ownersIterator.exists(_.derivesFrom(definedClass)) then
report.error(em"${StaticProtected} $sym which is defined in $definedPackage is inaccessible at runtime from $enclosingPackage", tree.srcPos)
end checkJavaStaticProtected

}
import RefChecks.*

Expand Down Expand Up @@ -1363,6 +1376,15 @@ class RefChecks extends MiniPhase { thisPhase =>
override def transformSelect(tree: tpd.Select)(using Context): tpd.Tree =
if defn.ScalaBoxedClasses().contains(tree.qualifier.tpe.typeSymbol) && tree.name == nme.synchronized_ then
report.warning(SynchronizedCallOnBoxedClass(tree), tree.srcPos)
checkJavaStaticProtected(tree)
tree

override def transformApply(tree: tpd.Apply)(using Context): tpd.Apply =
checkJavaStaticProtected(tree)
tree

override def transformAssign(tree: tpd.Assign)(using Context): tpd.Assign =
checkJavaStaticProtected(tree)
tree
}

Expand Down
4 changes: 4 additions & 0 deletions tests/neg/i18446.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- Error: tests/neg/i18446/Test.scala:1:17 -----------------------------------------------------------------------------
1 |val _ = foo.Task.poll() // error
| ^^^^^^^^^^^^^
|protected <java> <static> method poll which is defined in package foo is inaccessible at runtime from package <empty>
5 changes: 5 additions & 0 deletions tests/neg/i18446/Task.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package foo;

public abstract class Task{
protected static void poll(){ System.out.println("Task"); }
}
1 change: 1 addition & 0 deletions tests/neg/i18446/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
val _ = foo.Task.poll() // error
2 changes: 2 additions & 0 deletions tests/run/i18446.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Task
Task
7 changes: 7 additions & 0 deletions tests/run/i18446/Client.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// scalajs: --skip

package bar;

object Client extends foo.Task {
def run = foo.Task.poll()
}
5 changes: 5 additions & 0 deletions tests/run/i18446/Task.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package foo;

public abstract class Task{
protected static void poll(){ System.out.println("Task"); }
}
5 changes: 5 additions & 0 deletions tests/run/i18446/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// scalajs: --skip

@main def Test =
foo.run
bar.Client.run
7 changes: 7 additions & 0 deletions tests/run/i18446/i18446.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// scalajs: --skip

package foo

def run = {
foo.Task.poll()
}
Loading