@@ -23,8 +23,10 @@ import Symbols._
23
23
import Denotations ._
24
24
import Phases ._
25
25
import StdNames ._
26
+ import TypeErasure .ErasedValueType
26
27
27
- import dotty .tools .dotc .transform .Erasure
28
+ import dotty .tools .dotc .transform .{Erasure , ValueClasses }
29
+ import dotty .tools .dotc .transform .SymUtils ._
28
30
import dotty .tools .dotc .util .SourcePosition
29
31
import dotty .tools .dotc .util .Spans .Span
30
32
import dotty .tools .dotc .report
@@ -282,7 +284,7 @@ class JSCodeGen()(using genCtx: Context) {
282
284
283
285
// Generate members (constructor + methods)
284
286
285
- val generatedMethods = new mutable.ListBuffer [js.MethodDef ]
287
+ val generatedNonFieldMembers = new mutable.ListBuffer [js.MemberDef ]
286
288
val exportedSymbols = new mutable.ListBuffer [Symbol ]
287
289
288
290
val tpl = td.rhs.asInstanceOf [Template ]
@@ -297,13 +299,11 @@ class JSCodeGen()(using genCtx: Context) {
297
299
val sym = dd.symbol
298
300
299
301
val isExport = false // jsInterop.isExport(sym)
300
- val isNamedExport = false /* isExport && sym.annotations.exists(
301
- _.symbol == JSExportNamedAnnotation)*/
302
302
303
- /* if (isNamedExport )
304
- generatedMethods += genNamedExporterDef (dd)
305
- else*/
306
- generatedMethods ++= genMethod(dd)
303
+ if (sym.hasAnnotation(jsdefn. JSNativeAnnot ) )
304
+ generatedNonFieldMembers += genJSNativeMemberDef (dd)
305
+ else
306
+ generatedNonFieldMembers ++= genMethod(dd)
307
307
308
308
if (isExport) {
309
309
// We add symbols that we have to export here. This way we also
@@ -317,7 +317,7 @@ class JSCodeGen()(using genCtx: Context) {
317
317
}
318
318
319
319
// Generate fields and add to methods + ctors
320
- val generatedMembers = genClassFields(td) ++ generatedMethods .toList
320
+ val generatedMembers = genClassFields(td) ++ generatedNonFieldMembers .toList
321
321
322
322
// Generate the exported members, constructors and accessors
323
323
val exports = {
@@ -529,7 +529,6 @@ class JSCodeGen()(using genCtx: Context) {
529
529
530
530
private def genClassInterfaces (sym : ClassSymbol )(
531
531
implicit pos : Position ): List [js.ClassIdent ] = {
532
- import dotty .tools .dotc .transform .SymUtils ._
533
532
for {
534
533
intf <- sym.directlyInheritedTraits
535
534
} yield {
@@ -677,7 +676,10 @@ class JSCodeGen()(using genCtx: Context) {
677
676
" genClassFields called with a ClassDef other than the current one" )
678
677
679
678
// Term members that are neither methods nor modules are fields
680
- 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 =>
681
683
implicit val pos = f.span
682
684
683
685
val name =
@@ -815,6 +817,17 @@ class JSCodeGen()(using genCtx: Context) {
815
817
816
818
// Generate a method -------------------------------------------------------
817
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
+
818
831
private def genMethod (dd : DefDef ): Option [js.MethodDef ] = {
819
832
withScopedVars(
820
833
localNames := new LocalNameGenerator
@@ -1227,7 +1240,7 @@ class JSCodeGen()(using genCtx: Context) {
1227
1240
val sym = lhs0.symbol
1228
1241
if (sym.is(JavaStaticTerm ))
1229
1242
throw new FatalError (s " Assignment to static member ${sym.fullName} not supported " )
1230
- val genRhs = genExpr(rhs)
1243
+ def genRhs = genExpr(rhs)
1231
1244
val lhs = lhs0 match {
1232
1245
case lhs : Ident => desugarIdent(lhs).getOrElse(lhs)
1233
1246
case lhs => lhs
@@ -1247,7 +1260,15 @@ class JSCodeGen()(using genCtx: Context) {
1247
1260
1248
1261
val genQual = genExpr(qualifier)
1249
1262
1250
- /* 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)) {
1251
1272
val genLhs = if (isExposed(sym))
1252
1273
js.JSBracketSelect(genQual, js.StringLiteral(jsNameOf(sym)))
1253
1274
else
@@ -1256,12 +1277,12 @@ class JSCodeGen()(using genCtx: Context) {
1256
1277
ensureBoxed(genRhs,
1257
1278
enteringPhase(currentRun.posterasurePhase)(rhs.tpe))
1258
1279
js.Assign(genLhs, boxedRhs)
1259
- } else { */
1280
+ } else*/ {
1260
1281
js.Assign (
1261
1282
js.Select (genQual, encodeClassName(sym.owner),
1262
1283
encodeFieldSym(sym))(toIRType(sym.info)),
1263
1284
genRhs)
1264
- // }
1285
+ }
1265
1286
case _ =>
1266
1287
js.Assign (
1267
1288
js.VarRef (encodeLocalSym(sym))(toIRType(sym.info)),
@@ -2119,6 +2140,8 @@ class JSCodeGen()(using genCtx: Context) {
2119
2140
genApplyJSMethodGeneric(sym, genExprOrGlobalScope(receiver), genActualJSArgs(sym, args), isStat)(tree.sourcePos)
2120
2141
/* else
2121
2142
genApplyJSClassMethod(genExpr(receiver), sym, genActualArgs(sym, args))*/
2143
+ } else if (sym.hasAnnotation(jsdefn.JSNativeAnnot )) {
2144
+ genJSNativeMemberCall(tree, isStat)
2122
2145
} else {
2123
2146
genApplyMethodMaybeStatically(genExpr(receiver), sym, genActualArgs(sym, args))
2124
2147
}
@@ -2286,6 +2309,26 @@ class JSCodeGen()(using genCtx: Context) {
2286
2309
(firstArg.asInstanceOf [js.Tree ], args.tail)
2287
2310
}
2288
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
+
2289
2332
/** Gen JS code for a call to a polymorphic method.
2290
2333
*
2291
2334
* The only methods that reach the back-end as polymorphic are
@@ -2599,10 +2642,10 @@ class JSCodeGen()(using genCtx: Context) {
2599
2642
case tpe if isPrimitiveValueType(tpe) =>
2600
2643
makePrimitiveBox(expr, tpe)
2601
2644
2602
- /* case tpe: ErasedValueType =>
2603
- val boxedClass = tpe.valueClazz
2645
+ case tpe : ErasedValueType =>
2646
+ val boxedClass = tpe.tycon.typeSymbol
2604
2647
val ctor = boxedClass.primaryConstructor
2605
- genNew( boxedClass, ctor, List(expr))*/
2648
+ js. New (encodeClassName( boxedClass), encodeMethodSym( ctor) , List (expr))
2606
2649
2607
2650
case _ =>
2608
2651
expr
@@ -2626,15 +2669,15 @@ class JSCodeGen()(using genCtx: Context) {
2626
2669
case tpe if isPrimitiveValueType(tpe) =>
2627
2670
makePrimitiveUnbox(expr, tpe)
2628
2671
2629
- /* case tpe: ErasedValueType =>
2630
- val boxedClass = tpe.valueClazz
2631
- val unboxMethod = boxedClass.derivedValueClassUnbox
2672
+ case tpe : ErasedValueType =>
2673
+ val boxedClass = tpe.tycon.typeSymbol.asClass
2674
+ val unboxMethod = ValueClasses .valueClassUnbox(boxedClass)
2632
2675
val content = genApplyMethod(
2633
- genAsInstanceOf (expr, tpe ), unboxMethod, Nil)
2634
- if (unboxMethod.tpe .resultType <:< tpe.erasedUnderlying)
2676
+ js. AsInstanceOf (expr, encodeClassType(boxedClass) ), unboxMethod, Nil )
2677
+ if (unboxMethod.info .resultType <:< tpe.erasedUnderlying)
2635
2678
content
2636
2679
else
2637
- fromAny (content, tpe.erasedUnderlying)*/
2680
+ unbox (content, tpe.erasedUnderlying)
2638
2681
2639
2682
case tpe =>
2640
2683
genAsInstanceOf(expr, tpe)
@@ -2889,7 +2932,11 @@ class JSCodeGen()(using genCtx: Context) {
2889
2932
case TYPEOF =>
2890
2933
// js.typeOf(arg)
2891
2934
val arg = genArgs1
2892
- genAsInstanceOf(js.JSUnaryOp (js.JSUnaryOp .typeof, arg), defn.StringType )
2935
+ val typeofExpr = arg match {
2936
+ case arg : js.JSGlobalRef => js.JSTypeOfGlobalRef (arg)
2937
+ case _ => js.JSUnaryOp (js.JSUnaryOp .typeof, arg)
2938
+ }
2939
+ js.AsInstanceOf (typeofExpr, jstpe.ClassType (jsNames.BoxedStringClass ))
2893
2940
2894
2941
case STRICT_EQ =>
2895
2942
// js.special.strictEquals(arg1, arg2)
@@ -3497,6 +3544,12 @@ class JSCodeGen()(using genCtx: Context) {
3497
3544
}
3498
3545
}
3499
3546
3547
+ private def computeJSNativeLoadSpecOfValDef (sym : Symbol ): js.JSNativeLoadSpec = {
3548
+ atPhase(picklerPhase.next) {
3549
+ computeJSNativeLoadSpecOfInPhase(sym)
3550
+ }
3551
+ }
3552
+
3500
3553
private def computeJSNativeLoadSpecOfClass (sym : Symbol ): Option [js.JSNativeLoadSpec ] = {
3501
3554
if (sym.is(Trait ) || sym.hasAnnotation(jsdefn.JSGlobalScopeAnnot )) {
3502
3555
None
@@ -3587,8 +3640,9 @@ class JSCodeGen()(using genCtx: Context) {
3587
3640
3588
3641
private def isPrimitiveValueType (tpe : Type ): Boolean = {
3589
3642
tpe.widenDealias match {
3590
- case JavaArrayType (_) => false
3591
- case t => t.typeSymbol.asClass.isPrimitiveValueClass
3643
+ case JavaArrayType (_) => false
3644
+ case _ : ErasedValueType => false
3645
+ case t => t.typeSymbol.asClass.isPrimitiveValueClass
3592
3646
}
3593
3647
}
3594
3648
0 commit comments