@@ -54,12 +54,12 @@ object PrepJSExports {
5454
5555 private final case class ExportInfo (jsName : String , destination : ExportDestination )(val pos : SrcPos )
5656
57- /** Checks a class or module for export.
57+ /** Checks a class or module class for export.
5858 *
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.
6060 * However, the checks are performed on the class when the class is annotated.
6161 */
62- def checkClassExports (sym : Symbol )(using Context ): Unit = {
62+ def checkClassOrModuleExports (sym : Symbol )(using Context ): Unit = {
6363 val exports = exportsOf(sym)
6464 if (exports.nonEmpty)
6565 checkClassOrModuleExports(sym, exports.head.pos)
@@ -129,6 +129,8 @@ object PrepJSExports {
129129 err(" You may not export a native JS " + (if (isMod) " object" else " class" ))
130130 } else if (! hasLegalExportVisibility(sym)) {
131131 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" )
132134 } else if (sym.isLocalToBlock) {
133135 err(" You may not export a local " + (if (isMod) " object" else " class" ))
134136 } else if (! sym.isStatic) {
@@ -187,8 +189,10 @@ object PrepJSExports {
187189 val isStaticExport = annot.symbol == JSExportStaticAnnot
188190 val hasExplicitName = annot.arguments.nonEmpty
189191
192+ val exportPos : SrcPos = if (isExportAll) sym else annot.tree
193+
190194 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}" )
192196
193197 val name = {
194198 if (hasExplicitName) {
@@ -224,14 +228,11 @@ object PrepJSExports {
224228
225229 // Enforce proper setter signature
226230 if (sym.isJSSetter)
227- checkSetterSignature(sym, annot.tree , exported = true )
231+ checkSetterSignature(sym, exportPos , exported = true )
228232
229233 // 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)
235236
236237 /* Illegal function application exports, i.e., method named 'apply'
237238 * without an explicit export name.
@@ -249,24 +250,21 @@ object PrepJSExports {
249250
250251 // Don't allow apply without explicit name
251252 if (! shouldBeTolerated) {
252- // Get position for error message
253- val pos : SrcPos = if (isExportAll) trgSym else annot.tree
254-
255253 report.error(
256254 " A member cannot be exported to function application. " +
257255 " Add @JSExport(\" apply\" ) to export under the name apply." ,
258- pos )
256+ exportPos )
259257 }
260258
261259 case _ : ExportDestination .TopLevel =>
262260 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}" )
264262
265263 case ExportDestination .Static =>
266264 report.error(
267265 " A member cannot be exported to function application as static. " +
268266 " Use @JSExportStatic(\" apply\" ) to export it under the name 'apply'." ,
269- annot.tree )
267+ exportPos )
270268 }
271269 }
272270
@@ -285,42 +283,33 @@ object PrepJSExports {
285283 if (isIllegalToString) {
286284 report.error(
287285 " You may not export a zero-argument method named other than 'toString' under the name 'toString'" ,
288- annot.tree )
286+ exportPos )
289287 }
290288
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 )) {
293293 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 )
296296 }
297297
298298 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)
308303
309304 /* Disallow non-static methods.
310305 * Note: Non-static classes have more specific error messages in checkClassOrModuleExports.
311306 */
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)
317309
318310 // 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)
324313
325314 case ExportDestination .Static =>
326315 def companionIsNonNativeJSClass : Boolean = {
@@ -334,21 +323,21 @@ object PrepJSExports {
334323 if (! symOwner.isStatic || ! symOwner.is(ModuleClass ) || ! companionIsNonNativeJSClass) {
335324 report.error(
336325 " Only a static object whose companion class is a non-native JS class may export its members as static." ,
337- annot.tree )
326+ exportPos )
338327 }
339328
340329 if (isMember) {
341330 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 )
343332 } else {
344333 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 )
346335 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 )
348337 }
349338 }
350339
351- ExportInfo (name, destination)(annot.tree )
340+ ExportInfo (name, destination)(exportPos )
352341 }
353342
354343 allExportInfos.filter(_.destination == ExportDestination .Normal )
@@ -481,9 +470,7 @@ object PrepJSExports {
481470
482471 /** Checks whether there are default parameters not at the end of the flattened parameter list. */
483472 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 ))
488475 }
489476}
0 commit comments