@@ -23,8 +23,10 @@ import Symbols._
2323import Denotations ._
2424import Phases ._
2525import StdNames ._
26+ import TypeErasure .ErasedValueType
2627
27- import dotty .tools .dotc .transform .Erasure
28+ import dotty .tools .dotc .transform .{Erasure , ValueClasses }
29+ import dotty .tools .dotc .transform .SymUtils ._
2830import dotty .tools .dotc .util .SourcePosition
2931import dotty .tools .dotc .util .Spans .Span
3032import dotty .tools .dotc .report
@@ -282,7 +284,7 @@ class JSCodeGen()(using genCtx: Context) {
282284
283285 // Generate members (constructor + methods)
284286
285- val generatedMethods = new mutable.ListBuffer [js.MethodDef ]
287+ val generatedNonFieldMembers = new mutable.ListBuffer [js.MemberDef ]
286288 val exportedSymbols = new mutable.ListBuffer [Symbol ]
287289
288290 val tpl = td.rhs.asInstanceOf [Template ]
@@ -297,13 +299,11 @@ class JSCodeGen()(using genCtx: Context) {
297299 val sym = dd.symbol
298300
299301 val isExport = false // jsInterop.isExport(sym)
300- val isNamedExport = false /* isExport && sym.annotations.exists(
301- _.symbol == JSExportNamedAnnotation)*/
302302
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)
307307
308308 if (isExport) {
309309 // We add symbols that we have to export here. This way we also
@@ -317,7 +317,7 @@ class JSCodeGen()(using genCtx: Context) {
317317 }
318318
319319 // Generate fields and add to methods + ctors
320- val generatedMembers = genClassFields(td) ++ generatedMethods .toList
320+ val generatedMembers = genClassFields(td) ++ generatedNonFieldMembers .toList
321321
322322 // Generate the exported members, constructors and accessors
323323 val exports = {
@@ -529,7 +529,6 @@ class JSCodeGen()(using genCtx: Context) {
529529
530530 private def genClassInterfaces (sym : ClassSymbol )(
531531 implicit pos : Position ): List [js.ClassIdent ] = {
532- import dotty .tools .dotc .transform .SymUtils ._
533532 for {
534533 intf <- sym.directlyInheritedTraits
535534 } yield {
@@ -677,7 +676,10 @@ class JSCodeGen()(using genCtx: Context) {
677676 " genClassFields called with a ClassDef other than the current one" )
678677
679678 // 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 =>
681683 implicit val pos = f.span
682684
683685 val name =
@@ -815,6 +817,17 @@ class JSCodeGen()(using genCtx: Context) {
815817
816818 // Generate a method -------------------------------------------------------
817819
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+
818831 private def genMethod (dd : DefDef ): Option [js.MethodDef ] = {
819832 withScopedVars(
820833 localNames := new LocalNameGenerator
@@ -1227,7 +1240,7 @@ class JSCodeGen()(using genCtx: Context) {
12271240 val sym = lhs0.symbol
12281241 if (sym.is(JavaStaticTerm ))
12291242 throw new FatalError (s " Assignment to static member ${sym.fullName} not supported " )
1230- val genRhs = genExpr(rhs)
1243+ def genRhs = genExpr(rhs)
12311244 val lhs = lhs0 match {
12321245 case lhs : Ident => desugarIdent(lhs).getOrElse(lhs)
12331246 case lhs => lhs
@@ -1247,7 +1260,15 @@ class JSCodeGen()(using genCtx: Context) {
12471260
12481261 val genQual = genExpr(qualifier)
12491262
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)) {
12511272 val genLhs = if (isExposed(sym))
12521273 js.JSBracketSelect(genQual, js.StringLiteral(jsNameOf(sym)))
12531274 else
@@ -1256,12 +1277,12 @@ class JSCodeGen()(using genCtx: Context) {
12561277 ensureBoxed(genRhs,
12571278 enteringPhase(currentRun.posterasurePhase)(rhs.tpe))
12581279 js.Assign(genLhs, boxedRhs)
1259- } else { */
1280+ } else*/ {
12601281 js.Assign (
12611282 js.Select (genQual, encodeClassName(sym.owner),
12621283 encodeFieldSym(sym))(toIRType(sym.info)),
12631284 genRhs)
1264- // }
1285+ }
12651286 case _ =>
12661287 js.Assign (
12671288 js.VarRef (encodeLocalSym(sym))(toIRType(sym.info)),
@@ -2119,6 +2140,8 @@ class JSCodeGen()(using genCtx: Context) {
21192140 genApplyJSMethodGeneric(sym, genExprOrGlobalScope(receiver), genActualJSArgs(sym, args), isStat)(tree.sourcePos)
21202141 /* else
21212142 genApplyJSClassMethod(genExpr(receiver), sym, genActualArgs(sym, args))*/
2143+ } else if (sym.hasAnnotation(jsdefn.JSNativeAnnot )) {
2144+ genJSNativeMemberCall(tree, isStat)
21222145 } else {
21232146 genApplyMethodMaybeStatically(genExpr(receiver), sym, genActualArgs(sym, args))
21242147 }
@@ -2286,6 +2309,26 @@ class JSCodeGen()(using genCtx: Context) {
22862309 (firstArg.asInstanceOf [js.Tree ], args.tail)
22872310 }
22882311
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+
22892332 /** Gen JS code for a call to a polymorphic method.
22902333 *
22912334 * The only methods that reach the back-end as polymorphic are
@@ -2599,10 +2642,10 @@ class JSCodeGen()(using genCtx: Context) {
25992642 case tpe if isPrimitiveValueType(tpe) =>
26002643 makePrimitiveBox(expr, tpe)
26012644
2602- /* case tpe: ErasedValueType =>
2603- val boxedClass = tpe.valueClazz
2645+ case tpe : ErasedValueType =>
2646+ val boxedClass = tpe.tycon.typeSymbol
26042647 val ctor = boxedClass.primaryConstructor
2605- genNew( boxedClass, ctor, List(expr))*/
2648+ js. New (encodeClassName( boxedClass), encodeMethodSym( ctor) , List (expr))
26062649
26072650 case _ =>
26082651 expr
@@ -2626,15 +2669,15 @@ class JSCodeGen()(using genCtx: Context) {
26262669 case tpe if isPrimitiveValueType(tpe) =>
26272670 makePrimitiveUnbox(expr, tpe)
26282671
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)
26322675 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)
26352678 content
26362679 else
2637- fromAny (content, tpe.erasedUnderlying)*/
2680+ unbox (content, tpe.erasedUnderlying)
26382681
26392682 case tpe =>
26402683 genAsInstanceOf(expr, tpe)
@@ -2889,7 +2932,11 @@ class JSCodeGen()(using genCtx: Context) {
28892932 case TYPEOF =>
28902933 // js.typeOf(arg)
28912934 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 ))
28932940
28942941 case STRICT_EQ =>
28952942 // js.special.strictEquals(arg1, arg2)
@@ -3497,6 +3544,12 @@ class JSCodeGen()(using genCtx: Context) {
34973544 }
34983545 }
34993546
3547+ private def computeJSNativeLoadSpecOfValDef (sym : Symbol ): js.JSNativeLoadSpec = {
3548+ atPhase(picklerPhase.next) {
3549+ computeJSNativeLoadSpecOfInPhase(sym)
3550+ }
3551+ }
3552+
35003553 private def computeJSNativeLoadSpecOfClass (sym : Symbol ): Option [js.JSNativeLoadSpec ] = {
35013554 if (sym.is(Trait ) || sym.hasAnnotation(jsdefn.JSGlobalScopeAnnot )) {
35023555 None
@@ -3587,8 +3640,9 @@ class JSCodeGen()(using genCtx: Context) {
35873640
35883641 private def isPrimitiveValueType (tpe : Type ): Boolean = {
35893642 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
35923646 }
35933647 }
35943648
0 commit comments