From a1cdfe92af2f0794902069ffec5697b8e6794cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Tue, 23 Mar 2021 10:52:08 +0100 Subject: [PATCH] Fix #11592: Scala.js: Handle default params of native JS classes. They must not be emitted, just like regular methods inside native JS classes are not emitted. This ensures that if the default value is `= js.native`, it is not emitted, and therefore does not report an error tha calling `js.native` is illegal in non-native code. --- .../dotty/tools/backend/sjs/JSCodeGen.scala | 22 +++++++++---------- .../tools/dotc/transform/sjs/JSSymUtils.scala | 7 ++++++ .../compiler/RegressionTestScala3.scala | 12 ++++++++++ 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index f5643cc44ddd..38641cea93e4 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -290,12 +290,12 @@ class JSCodeGen()(using genCtx: Context) { "genScalaClass() must be called only for normal classes: "+sym) assert(sym.superClass != NoSymbol, sym) - /*if (hasDefaultCtorArgsAndRawJSModule(sym)) { - reporter.error(pos, - "Implementation restriction: constructors of " + - "Scala classes cannot have default parameters " + - "if their companion module is JS native.") - }*/ + if (hasDefaultCtorArgsAndJSModule(sym)) { + report.error( + "Implementation restriction: " + + "constructors of Scala classes cannot have default parameters if their companion module is JS native.", + td) + } val classIdent = encodeClassNameIdent(sym) val originalName = originalNameOfClass(sym) @@ -965,9 +965,8 @@ class JSCodeGen()(using genCtx: Context) { if (hasDefaultCtorArgsAndJSModule(classSym)) { report.error( - "Implementation restriction: constructors of " + - "non-native JS classes cannot have default parameters " + - "if their companion module is JS native.", + "Implementation restriction: " + + "constructors of non-native JS classes cannot have default parameters if their companion module is JS native.", classSym.srcPos) val ctorDef = js.JSMethodDef(js.MemberFlags.empty, js.StringLiteral("constructor"), Nil, None, js.Skip())( @@ -1067,9 +1066,10 @@ class JSCodeGen()(using genCtx: Context) { Some(js.MethodDef(js.MemberFlags.empty, methodName, originalName, jsParams, toIRType(patchedResultType(sym)), None)( OptimizerHints.empty, None)) - } else /*if (isJSNativeCtorDefaultParam(sym)) { + } else if (sym.isJSNativeCtorDefaultParam) { + // #11592 None - } else if (sym.isClassConstructor && isHijackedBoxedClass(sym.owner)) { + } else /*if (sym.isClassConstructor && isHijackedBoxedClass(sym.owner)) { None } else*/ { /*def isTraitImplForwarder = dd.rhs match { diff --git a/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala b/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala index c11bc16d85cf..0651e33c4d7d 100644 --- a/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala @@ -158,6 +158,13 @@ object JSSymUtils { } } + /** Is this symbol a default param accessor for the constructor of a native JS class? */ + def isJSNativeCtorDefaultParam(using Context): Boolean = { + sym.name.is(DefaultGetterName) + && sym.name.exclude(DefaultGetterName) == nme.CONSTRUCTOR + && sym.owner.linkedClass.hasAnnotation(jsdefn.JSNativeAnnot) + } + def jsCallingConvention(using Context): JSCallingConvention = JSCallingConvention.of(sym) diff --git a/tests/sjs-junit/test/org/scalajs/testsuite/compiler/RegressionTestScala3.scala b/tests/sjs-junit/test/org/scalajs/testsuite/compiler/RegressionTestScala3.scala index 24c80e18bddb..4a7ccad3cc5a 100644 --- a/tests/sjs-junit/test/org/scalajs/testsuite/compiler/RegressionTestScala3.scala +++ b/tests/sjs-junit/test/org/scalajs/testsuite/compiler/RegressionTestScala3.scala @@ -4,6 +4,7 @@ import org.junit.Assert.* import org.junit.Test import scala.scalajs.js +import scala.scalajs.js.annotation._ class RegressionTestScala3 { import RegressionTestScala3.* @@ -21,6 +22,11 @@ class RegressionTestScala3 { assertEquals(-1, obj2.y) assertEquals(4, obj2.foo(5)) } + + @Test def testJSNativeDefaultCtorParamIssue11592(): Unit = { + assertEquals("foo", new RangeErrorIssue11592("foo").message) + assertEquals("", new RangeErrorIssue11592().message) + } } object RegressionTestScala3 { @@ -33,6 +39,12 @@ object RegressionTestScala3 { def foo(x: Int): Int = new ChildClass().concreteMethod(x) } + + @js.native + @JSGlobal("RangeError") + class RangeErrorIssue11592(msg: String = js.native) extends js.Object { + val message: String = js.native + } } // This class needs to be at the top-level, not in an object, to reproduce the issue