@@ -54,12 +54,12 @@ object PrepJSExports {
54
54
55
55
private final case class ExportInfo (jsName : String , destination : ExportDestination )(val pos : SrcPos )
56
56
57
- /** Checks a class or module for export.
57
+ /** Checks a class or module class for export.
58
58
*
59
- * Note that Scala classes are never actually exported; their constructors are.
59
+ * Note that non-module Scala classes are never actually exported; their constructors are.
60
60
* However, the checks are performed on the class when the class is annotated.
61
61
*/
62
- def checkClassExports (sym : Symbol )(using Context ): Unit = {
62
+ def checkClassOrModuleExports (sym : Symbol )(using Context ): Unit = {
63
63
val exports = exportsOf(sym)
64
64
if (exports.nonEmpty)
65
65
checkClassOrModuleExports(sym, exports.head.pos)
@@ -129,6 +129,8 @@ object PrepJSExports {
129
129
err(" You may not export a native JS " + (if (isMod) " object" else " class" ))
130
130
} else if (! hasLegalExportVisibility(sym)) {
131
131
err(" You may only export public and protected " + (if (isMod) " objects" else " classes" ))
132
+ } else if (isJSAny(sym.owner)) {
133
+ err(" You may not export a " + (if (isMod) " object" else " class" ) + " in a subclass of js.Any" )
132
134
} else if (sym.isLocalToBlock) {
133
135
err(" You may not export a local " + (if (isMod) " object" else " class" ))
134
136
} else if (! sym.isStatic) {
@@ -187,8 +189,10 @@ object PrepJSExports {
187
189
val isStaticExport = annot.symbol == JSExportStaticAnnot
188
190
val hasExplicitName = annot.arguments.nonEmpty
189
191
192
+ val exportPos : SrcPos = if (isExportAll) sym else annot.tree
193
+
190
194
assert(! isTopLevelExport || hasExplicitName,
191
- em " Found a top-level export without an explicit name at ${annot.tree .sourcePos}" )
195
+ em " Found a top-level export without an explicit name at ${exportPos .sourcePos}" )
192
196
193
197
val name = {
194
198
if (hasExplicitName) {
@@ -224,14 +228,11 @@ object PrepJSExports {
224
228
225
229
// Enforce proper setter signature
226
230
if (sym.isJSSetter)
227
- checkSetterSignature(sym, annot.tree , exported = true )
231
+ checkSetterSignature(sym, exportPos , exported = true )
228
232
229
233
// Enforce no __ in name
230
- if (! isTopLevelExport && name.contains(" __" )) {
231
- // Get position for error message
232
- val pos : SrcPos = if (hasExplicitName) annot.arguments.head else trgSym
233
- report.error(" An exported name may not contain a double underscore (`__`)" , pos)
234
- }
234
+ if (! isTopLevelExport && name.contains(" __" ))
235
+ report.error(" An exported name may not contain a double underscore (`__`)" , exportPos)
235
236
236
237
/* Illegal function application exports, i.e., method named 'apply'
237
238
* without an explicit export name.
@@ -249,24 +250,21 @@ object PrepJSExports {
249
250
250
251
// Don't allow apply without explicit name
251
252
if (! shouldBeTolerated) {
252
- // Get position for error message
253
- val pos : SrcPos = if (isExportAll) trgSym else annot.tree
254
-
255
253
report.error(
256
254
" A member cannot be exported to function application. " +
257
255
" Add @JSExport(\" apply\" ) to export under the name apply." ,
258
- pos )
256
+ exportPos )
259
257
}
260
258
261
259
case _ : ExportDestination .TopLevel =>
262
260
throw new AssertionError (
263
- em " Found a top-level export without an explicit name at ${annot.tree .sourcePos}" )
261
+ em " Found a top-level export without an explicit name at ${exportPos .sourcePos}" )
264
262
265
263
case ExportDestination .Static =>
266
264
report.error(
267
265
" A member cannot be exported to function application as static. " +
268
266
" Use @JSExportStatic(\" apply\" ) to export it under the name 'apply'." ,
269
- annot.tree )
267
+ exportPos )
270
268
}
271
269
}
272
270
@@ -285,42 +283,33 @@ object PrepJSExports {
285
283
if (isIllegalToString) {
286
284
report.error(
287
285
" You may not export a zero-argument method named other than 'toString' under the name 'toString'" ,
288
- annot.tree )
286
+ exportPos )
289
287
}
290
288
291
- // Disallow @JSExport on non-members.
292
- if (! isMember && ! sym.is(Trait )) {
289
+ // Disallow @JSExport at the top-level, as well as on objects and classes
290
+ if (symOwner.is(Package ) || symOwner.isPackageObject) {
291
+ report.error(" @JSExport is forbidden on top-level definitions. Use @JSExportTopLevel instead." , exportPos)
292
+ } else if (! isMember && ! sym.is(Trait )) {
293
293
report.error(
294
- " @JSExport is forbidden on objects and classes. Use @JSExportTopLevel instead." ,
295
- annot.tree )
294
+ " @JSExport is forbidden on objects and classes. Use @JSExport'ed factory methods instead." ,
295
+ exportPos )
296
296
}
297
297
298
298
case _ : ExportDestination .TopLevel =>
299
- if (sym.is(Lazy )) {
300
- report.error(
301
- " You may not export a lazy val to the top level" ,
302
- annot.tree)
303
- } else if (! sym.isOneOf(Accessor | Module ) && sym.isJSProperty) {
304
- report.error(
305
- " You may not export a getter or a setter to the top level" ,
306
- annot.tree)
307
- }
299
+ if (sym.is(Lazy ))
300
+ report.error(" You may not export a lazy val to the top level" , exportPos)
301
+ else if (! sym.is(Accessor ) && sym.isTerm && sym.isJSProperty)
302
+ report.error(" You may not export a getter or a setter to the top level" , exportPos)
308
303
309
304
/* Disallow non-static methods.
310
305
* Note: Non-static classes have more specific error messages in checkClassOrModuleExports.
311
306
*/
312
- if (sym.is(Method ) && (! symOwner.isStatic || ! symOwner.is(ModuleClass ))) {
313
- report.error(
314
- " Only static objects may export their members to the top level" ,
315
- annot.tree)
316
- }
307
+ if (sym.isTerm && (! symOwner.isStatic || ! symOwner.is(ModuleClass )))
308
+ report.error(" Only static objects may export their members to the top level" , exportPos)
317
309
318
310
// The top-level name must be a valid JS identifier
319
- if (! isValidTopLevelExportName(name)) {
320
- report.error(
321
- " The top-level export name must be a valid JavaScript identifier name" ,
322
- annot.tree)
323
- }
311
+ if (! isValidTopLevelExportName(name))
312
+ report.error(" The top-level export name must be a valid JavaScript identifier name" , exportPos)
324
313
325
314
case ExportDestination .Static =>
326
315
def companionIsNonNativeJSClass : Boolean = {
@@ -334,21 +323,21 @@ object PrepJSExports {
334
323
if (! symOwner.isStatic || ! symOwner.is(ModuleClass ) || ! companionIsNonNativeJSClass) {
335
324
report.error(
336
325
" Only a static object whose companion class is a non-native JS class may export its members as static." ,
337
- annot.tree )
326
+ exportPos )
338
327
}
339
328
340
329
if (isMember) {
341
330
if (sym.is(Lazy ))
342
- report.error(" You may not export a lazy val as static" , annot.tree )
331
+ report.error(" You may not export a lazy val as static" , exportPos )
343
332
} else {
344
333
if (sym.is(Trait ))
345
- report.error(" You may not export a trait as static." , annot.tree )
334
+ report.error(" You may not export a trait as static." , exportPos )
346
335
else
347
- report.error(" Implementation restriction: cannot export a class or object as static" , annot.tree )
336
+ report.error(" Implementation restriction: cannot export a class or object as static" , exportPos )
348
337
}
349
338
}
350
339
351
- ExportInfo (name, destination)(annot.tree )
340
+ ExportInfo (name, destination)(exportPos )
352
341
}
353
342
354
343
allExportInfos.filter(_.destination == ExportDestination .Normal )
@@ -481,9 +470,7 @@ object PrepJSExports {
481
470
482
471
/** Checks whether there are default parameters not at the end of the flattened parameter list. */
483
472
private def hasIllegalDefaultParam (sym : Symbol )(using Context ): Boolean = {
484
- // TODO
485
- // val isDefParam = (_: Symbol).hasFlag(Flags.DEFAULTPARAM)
486
- // sym.paramss.flatten.reverse.dropWhile(isDefParam).exists(isDefParam)
487
- false
473
+ sym.hasDefaultParams
474
+ && sym.paramSymss.flatten.reverse.dropWhile(_.is(HasDefault )).exists(_.is(HasDefault ))
488
475
}
489
476
}
0 commit comments