@@ -26,6 +26,7 @@ import StdNames._
26
26
import TypeErasure .ErasedValueType
27
27
28
28
import dotty .tools .dotc .transform .{Erasure , ValueClasses }
29
+ import dotty .tools .dotc .transform .SymUtils ._
29
30
import dotty .tools .dotc .util .SourcePosition
30
31
import dotty .tools .dotc .util .Spans .Span
31
32
import dotty .tools .dotc .report
@@ -283,7 +284,7 @@ class JSCodeGen()(using genCtx: Context) {
283
284
284
285
// Generate members (constructor + methods)
285
286
286
- val generatedMethods = new mutable.ListBuffer [js.MethodDef ]
287
+ val generatedNonFieldMembers = new mutable.ListBuffer [js.MemberDef ]
287
288
val exportedSymbols = new mutable.ListBuffer [Symbol ]
288
289
289
290
val tpl = td.rhs.asInstanceOf [Template ]
@@ -298,13 +299,11 @@ class JSCodeGen()(using genCtx: Context) {
298
299
val sym = dd.symbol
299
300
300
301
val isExport = false // jsInterop.isExport(sym)
301
- val isNamedExport = false /* isExport && sym.annotations.exists(
302
- _.symbol == JSExportNamedAnnotation)*/
303
302
304
- /* if (isNamedExport )
305
- generatedMethods += genNamedExporterDef (dd)
306
- else*/
307
- generatedMethods ++= genMethod(dd)
303
+ if (sym.hasAnnotation(jsdefn. JSNativeAnnot ) )
304
+ generatedNonFieldMembers += genJSNativeMemberDef (dd)
305
+ else
306
+ generatedNonFieldMembers ++= genMethod(dd)
308
307
309
308
if (isExport) {
310
309
// We add symbols that we have to export here. This way we also
@@ -318,7 +317,7 @@ class JSCodeGen()(using genCtx: Context) {
318
317
}
319
318
320
319
// Generate fields and add to methods + ctors
321
- val generatedMembers = genClassFields(td) ++ generatedMethods .toList
320
+ val generatedMembers = genClassFields(td) ++ generatedNonFieldMembers .toList
322
321
323
322
// Generate the exported members, constructors and accessors
324
323
val exports = {
@@ -530,7 +529,6 @@ class JSCodeGen()(using genCtx: Context) {
530
529
531
530
private def genClassInterfaces (sym : ClassSymbol )(
532
531
implicit pos : Position ): List [js.ClassIdent ] = {
533
- import dotty .tools .dotc .transform .SymUtils ._
534
532
for {
535
533
intf <- sym.directlyInheritedTraits
536
534
} yield {
@@ -678,7 +676,10 @@ class JSCodeGen()(using genCtx: Context) {
678
676
" genClassFields called with a ClassDef other than the current one" )
679
677
680
678
// Term members that are neither methods nor modules are fields
681
- classSym.info.decls.filter(f => ! f.isOneOf(Method | Module ) && f.isTerm).map({ f =>
679
+ classSym.info.decls.filter { f =>
680
+ ! f.isOneOf(Method | Module ) && f.isTerm
681
+ && ! f.hasAnnotation(jsdefn.JSNativeAnnot )
682
+ }.map({ f =>
682
683
implicit val pos = f.span
683
684
684
685
val name =
@@ -816,6 +817,17 @@ class JSCodeGen()(using genCtx: Context) {
816
817
817
818
// Generate a method -------------------------------------------------------
818
819
820
+ /** Generates the JSNativeMemberDef. */
821
+ def genJSNativeMemberDef (tree : DefDef ): js.JSNativeMemberDef = {
822
+ implicit val pos = tree.span
823
+
824
+ val sym = tree.symbol
825
+ val flags = js.MemberFlags .empty.withNamespace(js.MemberNamespace .PublicStatic )
826
+ val methodName = encodeMethodSym(sym)
827
+ val jsNativeLoadSpec = computeJSNativeLoadSpecOfValDef(sym)
828
+ js.JSNativeMemberDef (flags, methodName, jsNativeLoadSpec)
829
+ }
830
+
819
831
private def genMethod (dd : DefDef ): Option [js.MethodDef ] = {
820
832
withScopedVars(
821
833
localNames := new LocalNameGenerator
@@ -1228,7 +1240,7 @@ class JSCodeGen()(using genCtx: Context) {
1228
1240
val sym = lhs0.symbol
1229
1241
if (sym.is(JavaStaticTerm ))
1230
1242
throw new FatalError (s " Assignment to static member ${sym.fullName} not supported " )
1231
- val genRhs = genExpr(rhs)
1243
+ def genRhs = genExpr(rhs)
1232
1244
val lhs = lhs0 match {
1233
1245
case lhs : Ident => desugarIdent(lhs).getOrElse(lhs)
1234
1246
case lhs => lhs
@@ -1248,7 +1260,15 @@ class JSCodeGen()(using genCtx: Context) {
1248
1260
1249
1261
val genQual = genExpr(qualifier)
1250
1262
1251
- /* if (isScalaJSDefinedJSClass(sym.owner)) {
1263
+ if (sym.hasAnnotation(jsdefn.JSNativeAnnot )) {
1264
+ /* This is an assignment to a @js.native field. Since we reject
1265
+ * `@js.native var`s as compile errors, this can only happen in
1266
+ * the constructor of the enclosing object.
1267
+ * We simply ignore the assignment, since the field will not be
1268
+ * emitted at all.
1269
+ */
1270
+ js.Skip ()
1271
+ } else /* if (isScalaJSDefinedJSClass(sym.owner)) {
1252
1272
val genLhs = if (isExposed(sym))
1253
1273
js.JSBracketSelect(genQual, js.StringLiteral(jsNameOf(sym)))
1254
1274
else
@@ -1257,12 +1277,12 @@ class JSCodeGen()(using genCtx: Context) {
1257
1277
ensureBoxed(genRhs,
1258
1278
enteringPhase(currentRun.posterasurePhase)(rhs.tpe))
1259
1279
js.Assign(genLhs, boxedRhs)
1260
- } else { */
1280
+ } else*/ {
1261
1281
js.Assign (
1262
1282
js.Select (genQual, encodeClassName(sym.owner),
1263
1283
encodeFieldSym(sym))(toIRType(sym.info)),
1264
1284
genRhs)
1265
- // }
1285
+ }
1266
1286
case _ =>
1267
1287
js.Assign (
1268
1288
js.VarRef (encodeLocalSym(sym))(toIRType(sym.info)),
@@ -2120,6 +2140,8 @@ class JSCodeGen()(using genCtx: Context) {
2120
2140
genApplyJSMethodGeneric(sym, genExprOrGlobalScope(receiver), genActualJSArgs(sym, args), isStat)(tree.sourcePos)
2121
2141
/* else
2122
2142
genApplyJSClassMethod(genExpr(receiver), sym, genActualArgs(sym, args))*/
2143
+ } else if (sym.hasAnnotation(jsdefn.JSNativeAnnot )) {
2144
+ genJSNativeMemberCall(tree, isStat)
2123
2145
} else {
2124
2146
genApplyMethodMaybeStatically(genExpr(receiver), sym, genActualArgs(sym, args))
2125
2147
}
@@ -2287,6 +2309,26 @@ class JSCodeGen()(using genCtx: Context) {
2287
2309
(firstArg.asInstanceOf [js.Tree ], args.tail)
2288
2310
}
2289
2311
2312
+ /** Gen JS code for a call to a native JS def or val. */
2313
+ private def genJSNativeMemberCall (tree : Apply , isStat : Boolean ): js.Tree = {
2314
+ val sym = tree.symbol
2315
+ val Apply (_, args) = tree
2316
+
2317
+ implicit val pos = tree.span
2318
+
2319
+ val jsNativeMemberValue =
2320
+ js.SelectJSNativeMember (encodeClassName(sym.owner), encodeMethodSym(sym))
2321
+
2322
+ val boxedResult =
2323
+ if (sym.isJSGetter) jsNativeMemberValue
2324
+ else js.JSFunctionApply (jsNativeMemberValue, genActualJSArgs(sym, args))
2325
+
2326
+ unbox(boxedResult, atPhase(elimErasedValueTypePhase) {
2327
+ sym.info.resultType
2328
+ })
2329
+ }
2330
+
2331
+
2290
2332
/** Gen JS code for a call to a polymorphic method.
2291
2333
*
2292
2334
* The only methods that reach the back-end as polymorphic are
@@ -3498,6 +3540,12 @@ class JSCodeGen()(using genCtx: Context) {
3498
3540
}
3499
3541
}
3500
3542
3543
+ private def computeJSNativeLoadSpecOfValDef (sym : Symbol ): js.JSNativeLoadSpec = {
3544
+ atPhase(picklerPhase.next) {
3545
+ computeJSNativeLoadSpecOfInPhase(sym)
3546
+ }
3547
+ }
3548
+
3501
3549
private def computeJSNativeLoadSpecOfClass (sym : Symbol ): Option [js.JSNativeLoadSpec ] = {
3502
3550
if (sym.is(Trait ) || sym.hasAnnotation(jsdefn.JSGlobalScopeAnnot )) {
3503
3551
None
0 commit comments