@@ -323,7 +323,6 @@ class JSCodeGen()(using genCtx: Context) {
323
323
// Generate members (constructor + methods)
324
324
325
325
val generatedNonFieldMembers = new mutable.ListBuffer [js.MemberDef ]
326
- val exportedSymbols = new mutable.ListBuffer [Symbol ]
327
326
328
327
val tpl = td.rhs.asInstanceOf [Template ]
329
328
for (tree <- tpl.constr :: tpl.body) {
@@ -336,19 +335,11 @@ class JSCodeGen()(using genCtx: Context) {
336
335
case dd : DefDef =>
337
336
val sym = dd.symbol
338
337
339
- val isExport = false // jsInterop.isExport(sym)
340
-
341
338
if (sym.hasAnnotation(jsdefn.JSNativeAnnot ))
342
339
generatedNonFieldMembers += genJSNativeMemberDef(dd)
343
340
else
344
341
generatedNonFieldMembers ++= genMethod(dd)
345
342
346
- if (isExport) {
347
- // We add symbols that we have to export here. This way we also
348
- // get inherited stuff that is implemented in this class.
349
- exportedSymbols += sym
350
- }
351
-
352
343
case _ =>
353
344
throw new FatalError (" Illegal tree in body of genScalaClass(): " + tree)
354
345
}
@@ -357,21 +348,11 @@ class JSCodeGen()(using genCtx: Context) {
357
348
// Generate fields and add to methods + ctors
358
349
val generatedMembers = genClassFields(td) ++ generatedNonFieldMembers.toList
359
350
360
- // Generate the exported members, constructors and accessors
361
- val exports = {
362
- /*
363
- // Generate the exported members
364
- val memberExports = genMemberExports(sym, exportedSymbols.toList)
351
+ // Generate member exports
352
+ val memberExports = jsExportsGen.genMemberExports(sym)
365
353
366
- // Generate exported constructors or accessors
367
- val exportedConstructorsOrAccessors =
368
- if (isStaticModule(sym)) genModuleAccessorExports(sym)
369
- else genConstructorExports(sym)
370
-
371
- memberExports ++ exportedConstructorsOrAccessors
372
- */
373
- Nil
374
- }
354
+ // Generate top-level export definitions
355
+ val topLevelExportDefs = jsExportsGen.genTopLevelExports(sym)
375
356
376
357
// Static initializer
377
358
val optStaticInitializer = {
@@ -383,20 +364,27 @@ class JSCodeGen()(using genCtx: Context) {
383
364
}
384
365
}
385
366
if (enableReflectiveInstantiation)
386
- genRegisterReflectiveInstantiation(sym)
367
+ genRegisterReflectiveInstantiation(sym).toList
387
368
else
388
- None
369
+ Nil
389
370
}
390
371
391
- val staticInitializerStats = reflectInit.toList
372
+ // Initialization of the module because of field exports
373
+ val needsStaticModuleInit =
374
+ topLevelExportDefs.exists(_.isInstanceOf [js.TopLevelFieldExportDef ])
375
+ val staticModuleInit =
376
+ if (! needsStaticModuleInit) Nil
377
+ else List (genLoadModule(sym))
378
+
379
+ val staticInitializerStats = reflectInit ::: staticModuleInit
392
380
if (staticInitializerStats.nonEmpty)
393
- List (genStaticInitializerWithStats( js.Block (staticInitializerStats)))
381
+ List (genStaticConstructorWithStats(ir. Names . StaticInitializerName , js.Block (staticInitializerStats)))
394
382
else
395
383
Nil
396
384
}
397
385
398
386
val allMemberDefsExceptStaticForwarders =
399
- generatedMembers ::: exports ::: optStaticInitializer
387
+ generatedMembers ::: memberExports ::: optStaticInitializer
400
388
401
389
// Add static forwarders
402
390
val allMemberDefs = if (! isCandidateForForwarders(sym)) {
@@ -452,7 +440,7 @@ class JSCodeGen()(using genCtx: Context) {
452
440
None ,
453
441
None ,
454
442
hashedDefs,
455
- Nil )(
443
+ topLevelExportDefs )(
456
444
optimizerHints)
457
445
458
446
classDefinition
@@ -511,6 +499,28 @@ class JSCodeGen()(using genCtx: Context) {
511
499
}
512
500
}
513
501
502
+ // Static members (exported from the companion object)
503
+ val staticMembers = {
504
+ val module = sym.companionModule
505
+ if (! module.exists) {
506
+ Nil
507
+ } else {
508
+ val companionModuleClass = module.moduleClass
509
+ val exports = withScopedVars(currentClassSym := companionModuleClass) {
510
+ jsExportsGen.genStaticExports(companionModuleClass)
511
+ }
512
+ if (exports.exists(_.isInstanceOf [js.JSFieldDef ])) {
513
+ val classInitializer =
514
+ genStaticConstructorWithStats(ir.Names .ClassInitializerName , genLoadModule(companionModuleClass))
515
+ exports :+ classInitializer
516
+ } else {
517
+ exports
518
+ }
519
+ }
520
+ }
521
+
522
+ val topLevelExports = jsExportsGen.genTopLevelExports(sym)
523
+
514
524
val (jsClassCaptures, generatedConstructor) =
515
525
genJSClassCapturesAndConstructor(sym, constructorTrees.toList)
516
526
@@ -525,7 +535,8 @@ class JSCodeGen()(using genCtx: Context) {
525
535
genClassFields(td) :::
526
536
generatedConstructor ::
527
537
jsExportsGen.genJSClassDispatchers(sym, dispatchMethodNames.result().distinct) :::
528
- generatedMethods.toList
538
+ generatedMethods.toList :::
539
+ staticMembers
529
540
}
530
541
531
542
// Hashed definitions of the class
@@ -546,7 +557,7 @@ class JSCodeGen()(using genCtx: Context) {
546
557
jsSuperClass,
547
558
None ,
548
559
hashedMemberDefs,
549
- Nil )(
560
+ topLevelExports )(
550
561
OptimizerHints .empty)
551
562
552
563
classDefinition
@@ -785,10 +796,15 @@ class JSCodeGen()(using genCtx: Context) {
785
796
! f.isOneOf(Method | Module ) && f.isTerm
786
797
&& ! f.hasAnnotation(jsdefn.JSNativeAnnot )
787
798
&& ! f.hasAnnotation(jsdefn.JSOptionalAnnot )
799
+ && ! f.hasAnnotation(jsdefn.JSExportStaticAnnot )
788
800
}.flatMap({ f =>
789
801
implicit val pos = f.span
790
802
791
- val isStaticField = f.is(JavaStatic ).ensuring(isStatic => ! (isStatic && isJSClass))
803
+ val isTopLevelExport = f.hasAnnotation(jsdefn.JSExportTopLevelAnnot )
804
+ val isJavaStatic = f.is(JavaStatic )
805
+ assert(! (isTopLevelExport && isJavaStatic),
806
+ em " found ${f.fullName} which is both a top-level export and a Java static " )
807
+ val isStaticField = isTopLevelExport || isJavaStatic
792
808
793
809
val namespace = if isStaticField then js.MemberNamespace .PublicStatic else js.MemberNamespace .Public
794
810
val mutable = isStaticField || f.is(Mutable )
@@ -797,6 +813,7 @@ class JSCodeGen()(using genCtx: Context) {
797
813
798
814
val irTpe =
799
815
if (isJSClass) genExposedFieldIRType(f)
816
+ else if (isTopLevelExport) jstpe.AnyType
800
817
else toIRType(f.info)
801
818
802
819
if (isJSClass && f.isJSExposed)
@@ -806,7 +823,7 @@ class JSCodeGen()(using genCtx: Context) {
806
823
val originalName = originalNameOfField(f)
807
824
val fieldDef = js.FieldDef (flags, fieldIdent, originalName, irTpe)
808
825
val optionalStaticFieldGetter =
809
- if isStaticField then
826
+ if isJavaStatic then
810
827
// Here we are generating a public static getter for the static field,
811
828
// this is its API for other units. This is necessary for singleton
812
829
// enum values, which are backed by static fields.
@@ -824,7 +841,7 @@ class JSCodeGen()(using genCtx: Context) {
824
841
}).toList
825
842
}
826
843
827
- private def genExposedFieldIRType (f : Symbol ): jstpe.Type = {
844
+ def genExposedFieldIRType (f : Symbol ): jstpe.Type = {
828
845
val tpeEnteringPosterasure = atPhase(elimErasedValueTypePhase)(f.info)
829
846
tpeEnteringPosterasure match {
830
847
case tpe : ErasedValueType =>
@@ -850,11 +867,11 @@ class JSCodeGen()(using genCtx: Context) {
850
867
851
868
// Static initializers -----------------------------------------------------
852
869
853
- private def genStaticInitializerWithStats ( stats : js.Tree )(
870
+ private def genStaticConstructorWithStats ( name : MethodName , stats : js.Tree )(
854
871
implicit pos : Position ): js.MethodDef = {
855
872
js.MethodDef (
856
873
js.MemberFlags .empty.withNamespace(js.MemberNamespace .StaticConstructor ),
857
- js.MethodIdent (ir. Names . StaticInitializerName ),
874
+ js.MethodIdent (name ),
858
875
NoOriginalName ,
859
876
Nil ,
860
877
jstpe.NoType ,
@@ -3916,19 +3933,17 @@ class JSCodeGen()(using genCtx: Context) {
3916
3933
}
3917
3934
3918
3935
(f, true )
3919
- } else /* if (jsInterop.topLevelExportsOf(sym).nonEmpty) {
3920
- val f = js.SelectStatic(encodeClassName(sym.owner),
3921
- encodeFieldSym(sym))(jstpe.AnyType)
3936
+ } else if (sym.hasAnnotation(jsdefn.JSExportTopLevelAnnot )) {
3937
+ val f = js.SelectStatic (encodeClassName(sym.owner), encodeFieldSym(sym))(jstpe.AnyType )
3922
3938
(f, true )
3923
- } else if (jsInterop.staticExportsOf(sym).nonEmpty) {
3924
- val exportInfo = jsInterop.staticExportsOf(sym).head
3925
- val companionClass = patchedLinkedClassOfClass(sym.owner)
3926
- val f = js.JSSelect(
3927
- genLoadJSConstructor(companionClass),
3928
- js.StringLiteral(exportInfo.jsName))
3929
-
3939
+ } else if (sym.hasAnnotation(jsdefn.JSExportStaticAnnot )) {
3940
+ val jsName = sym.getAnnotation(jsdefn.JSExportStaticAnnot ).get.argumentConstantString(0 ).getOrElse {
3941
+ sym.defaultJSName
3942
+ }
3943
+ val companionClass = sym.owner.linkedClass
3944
+ val f = js.JSSelect (genLoadJSConstructor(companionClass), js.StringLiteral (jsName))
3930
3945
(f, true )
3931
- } else*/ {
3946
+ } else {
3932
3947
val f =
3933
3948
val className = encodeClassName(sym.owner)
3934
3949
val fieldIdent = encodeFieldSym(sym)
0 commit comments