diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 901355945672..00e36c44e8bc 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -4564,7 +4564,14 @@ class JSCodeGen()(using genCtx: Context) { val module = annot.argumentConstantString(0).getOrElse { unexpected("could not read the module argument as a string literal") } - val path = annot.argumentConstantString(1).fold[List[String]](Nil)(parsePath) + val path = annot.argumentConstantString(1).fold { + if (annot.arguments.sizeIs < 2) + parsePath(sym.defaultJSName) + else + Nil + } { pathName => + parsePath(pathName) + } val importSpec = Import(module, path) annot.argumentConstantString(2).fold[js.JSNativeLoadSpec] { importSpec diff --git a/compiler/src/dotty/tools/dotc/transform/sjs/PrepJSInterop.scala b/compiler/src/dotty/tools/dotc/transform/sjs/PrepJSInterop.scala index e97585735eb7..accc2b45473c 100644 --- a/compiler/src/dotty/tools/dotc/transform/sjs/PrepJSInterop.scala +++ b/compiler/src/dotty/tools/dotc/transform/sjs/PrepJSInterop.scala @@ -14,7 +14,8 @@ import Contexts._ import Decorators._ import DenotTransformers._ import Flags._ -import NameKinds.DefaultGetterName +import NameKinds.{DefaultGetterName, ModuleClassName} +import NameOps._ import StdNames._ import Symbols._ import SymUtils._ @@ -559,9 +560,14 @@ class PrepJSInterop extends MacroTransform with IdentityDenotTransformer { thisP case Some(annot) if annot.symbol == jsdefn.JSGlobalAnnot => checkJSGlobalLiteral(annot) val pathName = annot.argumentConstantString(0).getOrElse { - if ((enclosingOwner is OwnerKind.ScalaMod) && !sym.owner.isPackageObject) { + val symTermName = sym.name.exclude(NameKinds.ModuleClassName).toTermName + if (symTermName == nme.apply) { report.error( - "Native JS members inside non-native objects must have an explicit name in @JSGlobal", + "Native JS definitions named 'apply' must have an explicit name in @JSGlobal", + annot.tree) + } else if (symTermName.isSetterName) { + report.error( + "Native JS definitions with a name ending in '_=' must have an explicit name in @JSGlobal", annot.tree) } sym.defaultJSName @@ -570,6 +576,18 @@ class PrepJSInterop extends MacroTransform with IdentityDenotTransformer { thisP case Some(annot) if annot.symbol == jsdefn.JSImportAnnot => checkJSImportLiteral(annot) + if (annot.arguments.sizeIs < 2) { + val symTermName = sym.name.exclude(NameKinds.ModuleClassName).toTermName + if (symTermName == nme.apply) { + report.error( + "Native JS definitions named 'apply' must have an explicit name in @JSImport", + annot.tree) + } else if (symTermName.isSetterName) { + report.error( + "Native JS definitions with a name ending in '_=' must have an explicit name in @JSImport", + annot.tree) + } + } annot.argumentConstantString(2).foreach { globalPathName => checkGlobalRefPath(globalPathName) } @@ -1107,18 +1125,19 @@ object PrepJSInterop { */ private def checkJSImportLiteral(annot: Annotation)(using Context): Unit = { val args = annot.arguments - assert(args.size == 2 || args.size == 3, - i"@JSImport annotation $annot does not have exactly 2 or 3 arguments") + val argCount = args.size + assert(argCount >= 1 && argCount <= 3, + i"@JSImport annotation $annot does not have between 1 and 3 arguments") val firstArgIsValid = annot.argumentConstantString(0).isDefined if (!firstArgIsValid) report.error("The first argument to @JSImport must be a literal string.", args.head) - val secondArgIsValid = annot.argumentConstantString(1).isDefined || args(1).symbol == jsdefn.JSImportNamespaceModule + val secondArgIsValid = argCount < 2 || annot.argumentConstantString(1).isDefined || args(1).symbol == jsdefn.JSImportNamespaceModule if (!secondArgIsValid) report.error("The second argument to @JSImport must be literal string or the JSImport.Namespace object.", args(1)) - val thirdArgIsValid = args.size < 3 || annot.argumentConstantString(2).isDefined + val thirdArgIsValid = argCount < 3 || annot.argumentConstantString(2).isDefined if (!thirdArgIsValid) report.error("The third argument to @JSImport, when present, must be a literal string.", args(2)) } diff --git a/project/plugins.sbt b/project/plugins.sbt index 1716bb51b7f1..9d743cec8252 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,7 +2,7 @@ // // e.g. addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.1.0") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.7.1") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.9.0") addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.10") diff --git a/tests/neg-scalajs/native-load-spec-need-explicit-name.check b/tests/neg-scalajs/native-load-spec-need-explicit-name.check index 9d91d4897d10..263acca9a2ca 100644 --- a/tests/neg-scalajs/native-load-spec-need-explicit-name.check +++ b/tests/neg-scalajs/native-load-spec-need-explicit-name.check @@ -1,8 +1,48 @@ -- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:6:2 ---------------------------------------------- 6 | @JSGlobal // error | ^^^^^^^^^ - | Native JS members inside non-native objects must have an explicit name in @JSGlobal + | Native JS definitions named 'apply' must have an explicit name in @JSGlobal -- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:10:2 --------------------------------------------- 10 | @JSGlobal // error | ^^^^^^^^^ - | Native JS members inside non-native objects must have an explicit name in @JSGlobal + | Native JS definitions named 'apply' must have an explicit name in @JSGlobal +-- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:14:2 --------------------------------------------- +14 | @JSGlobal // error + | ^^^^^^^^^ + | Native JS definitions with a name ending in '_=' must have an explicit name in @JSGlobal +-- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:20:2 --------------------------------------------- +20 | @JSGlobal // error + | ^^^^^^^^^ + | Native JS definitions with a name ending in '_=' must have an explicit name in @JSGlobal +-- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:19:2 --------------------------------------------- +19 | @js.native // error + | ^^^^^^^^^^ + | @js.native is not allowed on vars, lazy vals and setter defs +-- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:24:2 --------------------------------------------- +24 | @JSGlobal // error + | ^^^^^^^^^ + | Native JS definitions named 'apply' must have an explicit name in @JSGlobal +-- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:30:3 --------------------------------------------- +30 | @JSImport("bar.js") // error + | ^^^^^^^^^^^^^^^^^^^ + | Native JS definitions named 'apply' must have an explicit name in @JSImport +-- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:34:3 --------------------------------------------- +34 | @JSImport("bar.js") // error + | ^^^^^^^^^^^^^^^^^^^ + | Native JS definitions named 'apply' must have an explicit name in @JSImport +-- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:38:3 --------------------------------------------- +38 | @JSImport("bar.js") // error + | ^^^^^^^^^^^^^^^^^^^ + | Native JS definitions with a name ending in '_=' must have an explicit name in @JSImport +-- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:44:3 --------------------------------------------- +44 | @JSImport("bar.js") // error + | ^^^^^^^^^^^^^^^^^^^ + | Native JS definitions with a name ending in '_=' must have an explicit name in @JSImport +-- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:43:2 --------------------------------------------- +43 | @js.native // error + | ^^^^^^^^^^ + | @js.native is not allowed on vars, lazy vals and setter defs +-- Error: tests/neg-scalajs/native-load-spec-need-explicit-name.scala:48:3 --------------------------------------------- +48 | @JSImport("bar.js") // error + | ^^^^^^^^^^^^^^^^^^^ + | Native JS definitions named 'apply' must have an explicit name in @JSImport diff --git a/tests/neg-scalajs/native-load-spec-need-explicit-name.scala b/tests/neg-scalajs/native-load-spec-need-explicit-name.scala index fc08d414dd63..7235fa4e7a36 100644 --- a/tests/neg-scalajs/native-load-spec-need-explicit-name.scala +++ b/tests/neg-scalajs/native-load-spec-need-explicit-name.scala @@ -1,14 +1,52 @@ import scala.scalajs.js import scala.scalajs.js.annotation.* -object A { +object A1 { @js.native @JSGlobal // error - class B extends js.Object + class apply extends js.Object @js.native @JSGlobal // error - object C extends js.Object + object apply extends js.Object + + @js.native + @JSGlobal // error + class foo_= extends js.Object +} + +object A2 { + @js.native // error + @JSGlobal // error + def foo_=(x: Int): Unit = js.native + + @js.native + @JSGlobal // error + def apply(x: Int): Int = js.native +} + +object B1 { + @js.native + @JSImport("bar.js") // error + class apply extends js.Object + + @js.native + @JSImport("bar.js") // error + object apply extends js.Object + + @js.native + @JSImport("bar.js") // error + class foo_= extends js.Object +} + +object B2 { + @js.native // error + @JSImport("bar.js") // error + def foo_=(x: Int): Unit = js.native + + @js.native + @JSImport("bar.js") // error + def apply(x: Int): Int = js.native } // scala-js#2401