Skip to content

Commit 0fb52be

Browse files
committed
Scala.js: Allow default params of JS native defs to be = js.native.
The default accessors matching that property are not emitted anymore. This is similar to how default accessors for JS native constructors are not emitted. Unfortunately, for backward binary compatibility reasons, we must still emit default accessors of JS native defs that are anything else than `= js.native`. Until Scala.js 1.7.0, those default accessors would actually be referenced by calling code (see scala-js/scala-js#4554), so removing them now would create dangling references. This is a forward port of scala-js/scala-js@e01dc1a
1 parent db67c68 commit 0fb52be

File tree

2 files changed

+54
-8
lines changed

2 files changed

+54
-8
lines changed

compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,53 @@ class JSCodeGen()(using genCtx: Context) {
14021402
val vparamss = dd.termParamss
14031403
val rhs = dd.rhs
14041404

1405+
/* Is this method a default accessor that should be ignored?
1406+
*
1407+
* This is the case iff one of the following applies:
1408+
* - It is a constructor default accessor and the linked class is a
1409+
* native JS class.
1410+
* - It is a default accessor for a native JS def, but with the caveat
1411+
* that its rhs must be `js.native` because of #4553.
1412+
*
1413+
* Both of those conditions can only happen if the default accessor is in
1414+
* a module class, so we use that as a fast way out. (But omitting that
1415+
* condition would not change the result.)
1416+
*
1417+
* This is different than `isJSDefaultParam` in `genApply`: we do not
1418+
* ignore default accessors of *non-native* JS types. Neither for
1419+
* constructor default accessor nor regular default accessors. We also
1420+
* do not need to worry about non-constructor members of native JS types,
1421+
* since for those, the entire member list is ignored in `genJSClassData`.
1422+
*/
1423+
def isIgnorableDefaultParam: Boolean = {
1424+
sym.name.is(DefaultGetterName) && sym.owner.is(ModuleClass) && {
1425+
val info = new DefaultParamInfo(sym)
1426+
if (info.isForConstructor) {
1427+
/* This is a default accessor for a constructor parameter. Check
1428+
* whether the attached constructor is a native JS constructor,
1429+
* which is the case iff the linked class is a native JS type.
1430+
*/
1431+
info.constructorOwner.hasAnnotation(jsdefn.JSNativeAnnot)
1432+
} else {
1433+
/* #4553 We need to ignore default accessors for JS native defs.
1434+
* However, because Scala.js <= 1.7.0 actually emitted code calling
1435+
* those accessors, we must keep default accessors that would
1436+
* compile. The only accessors we can actually get rid of are those
1437+
* that are `= js.native`.
1438+
*/
1439+
!sym.owner.isJSType &&
1440+
info.attachedMethod.hasAnnotation(jsdefn.JSNativeAnnot) && {
1441+
dd.rhs match {
1442+
case MaybeAsInstanceOf(Apply(fun, _)) =>
1443+
fun.symbol == jsdefn.JSPackage_native
1444+
case _ =>
1445+
false
1446+
}
1447+
}
1448+
}
1449+
}
1450+
}
1451+
14051452
withPerMethodBodyState(sym) {
14061453
assert(vparamss.isEmpty || vparamss.tail.isEmpty,
14071454
"Malformed parameter list: " + vparamss)
@@ -1421,7 +1468,7 @@ class JSCodeGen()(using genCtx: Context) {
14211468
Some(js.MethodDef(js.MemberFlags.empty, methodName, originalName,
14221469
jsParams, toIRType(patchedResultType(sym)), None)(
14231470
OptimizerHints.empty, None))
1424-
} else if (sym.isJSNativeCtorDefaultParam) {
1471+
} else if (isIgnorableDefaultParam) {
14251472
// #11592
14261473
None
14271474
} else if (sym.is(Bridge) && sym.name.is(DefaultGetterName) && currentClassSym.isNonNativeJSClass) {
@@ -2016,6 +2063,12 @@ class JSCodeGen()(using genCtx: Context) {
20162063
* - It is a default param of an instance method of a non-native JS type
20172064
* and the attached method is exposed.
20182065
* - It is a default param for a native JS def.
2066+
*
2067+
* This is different than `isIgnorableDefaultParam` in
2068+
* `genMethodWithCurrentLocalNameScope`: we include here the default
2069+
* accessors of *non-native* JS types (unless the corresponding methods are
2070+
* not exposed). We also need to handle non-constructor members of native
2071+
* JS types.
20192072
*/
20202073
def isJSDefaultParam: Boolean = {
20212074
sym.name.is(DefaultGetterName) && {

compiler/src/dotty/tools/dotc/transform/sjs/JSSymUtils.scala

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,6 @@ object JSSymUtils {
156156
def isJSBracketCall(using Context): Boolean =
157157
sym.hasAnnotation(jsdefn.JSBracketCallAnnot)
158158

159-
/** Is this symbol a default param accessor for the constructor of a native JS class? */
160-
def isJSNativeCtorDefaultParam(using Context): Boolean = {
161-
sym.name.is(DefaultGetterName)
162-
&& sym.name.exclude(DefaultGetterName) == nme.CONSTRUCTOR
163-
&& sym.owner.linkedClass.hasAnnotation(jsdefn.JSNativeAnnot)
164-
}
165-
166159
def jsCallingConvention(using Context): JSCallingConvention =
167160
JSCallingConvention.of(sym)
168161

0 commit comments

Comments
 (0)