Skip to content

Commit 426e828

Browse files
committed
Warn about encoded pkg obj names
1 parent 8601228 commit 426e828

File tree

5 files changed

+58
-20
lines changed

5 files changed

+58
-20
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import annotation.constructorOnly
1919
import printing.Formatting.hl
2020
import config.Printers
2121
import parsing.Parsers
22+
import dotty.tools.dotc.util.chaining.*
2223

2324
import scala.annotation.internal.sharable
2425
import scala.annotation.threadUnsafe
@@ -1268,25 +1269,29 @@ object desugar {
12681269
else tree
12691270
}
12701271

1271-
def checkPackageName(mdef: ModuleDef | PackageDef)(using Context): Unit =
1272-
1273-
def check(name: Name, errSpan: Span): Unit = name match
1274-
case name: SimpleName if !errSpan.isSynthetic && name.exists(Chars.willBeEncoded) =>
1275-
report.warning(em"The package name `$name` will be encoded on the classpath, and can lead to undefined behaviour.", mdef.source.atSpan(errSpan))
1276-
case _ =>
1277-
1278-
def loop(part: RefTree): Unit = part match
1279-
case part @ Ident(name) => check(name, part.span)
1280-
case part @ Select(qual: RefTree, name) =>
1281-
check(name, part.nameSpan)
1282-
loop(qual)
1272+
def checkSimplePackageName(name: Name, errSpan: Span, source: SourceFile, isPackageObject: Boolean)(using Context) =
1273+
if !ctx.isAfterTyper then
1274+
name match
1275+
case name: SimpleName if (isPackageObject || !errSpan.isSynthetic) && name.exists(Chars.willBeEncoded) =>
1276+
report.warning(
1277+
em"The package name `$name` will be encoded on the classpath, and can lead to undefined behaviour.",
1278+
source.atSpan(errSpan))
12831279
case _ =>
12841280

1281+
def checkPackageName(mdef: ModuleDef | PackageDef)(using Context): Unit =
1282+
def check(name: Name, errSpan: Span) = checkSimplePackageName(name, errSpan, mdef.source, isPackageObject = false)
12851283
mdef match
1286-
case pdef: PackageDef => loop(pdef.pid)
1287-
case mdef: ModuleDef if mdef.mods.is(Package) => check(mdef.name, mdef.nameSpan)
1288-
case _ =>
1289-
end checkPackageName
1284+
case pdef: PackageDef =>
1285+
def loop(part: RefTree): Unit = part match
1286+
case part @ Ident(name) => check(name, part.span)
1287+
case part @ Select(qual: RefTree, name) =>
1288+
check(name, part.nameSpan)
1289+
loop(qual)
1290+
case _ =>
1291+
loop(pdef.pid)
1292+
case mdef: ModuleDef if mdef.mods.is(Package) =>
1293+
check(mdef.name, mdef.nameSpan)
1294+
case _ =>
12901295

12911296
/** The normalized name of `mdef`. This means
12921297
* 1. Check that the name does not redefine a Scala core class.
@@ -1795,10 +1800,11 @@ object desugar {
17951800
/** Assuming `src` contains top-level definition, returns the name that should
17961801
* be using for the package object that will wrap them.
17971802
*/
1798-
def packageObjectName(src: SourceFile): TermName =
1803+
def packageObjectName(src: SourceFile, srcPos: SrcPos)(using Context): TermName =
17991804
val fileName = src.file.name
18001805
val sourceName = fileName.take(fileName.lastIndexOf('.'))
18011806
(sourceName ++ str.TOPLEVEL_SUFFIX).toTermName
1807+
.tap(nm => checkSimplePackageName(nm, srcPos.span, src, isPackageObject = true))
18021808

18031809
/** Group all definitions that can't be at the toplevel in
18041810
* an object named `<source>$package` where `<source>` is the name of the source file.
@@ -1826,7 +1832,7 @@ object desugar {
18261832
val (nestedStats, topStats) = pdef.stats.partition(inPackageObject)
18271833
if (nestedStats.isEmpty) pdef
18281834
else {
1829-
val name = packageObjectName(ctx.source)
1835+
val name = packageObjectName(ctx.source, pdef.srcPos)
18301836
val grouped =
18311837
ModuleDef(name, Template(emptyConstructor, Nil, Nil, EmptyValDef, nestedStats))
18321838
.withMods(Modifiers(Synthetic))

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3364,7 +3364,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
33643364
inContext(ctx.packageContext(tree, pkg)) {
33653365
// If it exists, complete the class containing the top-level definitions
33663366
// before typing any statement in the package to avoid cycles as in i13669.scala
3367-
val topLevelClassName = desugar.packageObjectName(ctx.source).moduleClassName
3367+
val topLevelClassName = desugar.packageObjectName(ctx.source, tree.srcPos).moduleClassName
33683368
pkg.moduleClass.info.decls.lookup(topLevelClassName).ensureCompleted()
33693369
var stats1 = typedStats(tree.stats, pkg.moduleClass)._1
33703370
if (!ctx.isAfterTyper)
@@ -3745,8 +3745,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
37453745
def typedStats(stats: List[untpd.Tree], exprOwner: Symbol)(using Context): (List[Tree], Context) = {
37463746
val buf = new mutable.ListBuffer[Tree]
37473747
var enumContexts: SimpleIdentityMap[Symbol, Context] = SimpleIdentityMap.empty
3748-
val initialNotNullInfos = ctx.notNullInfos
37493748
// A map from `enum` symbols to the contexts enclosing their definitions
3749+
val initialNotNullInfos = ctx.notNullInfos
37503750
@tailrec def traverse(stats: List[untpd.Tree])(using Context): (List[Tree], Context) = stats match {
37513751
case (imp: untpd.Import) :: rest =>
37523752
val imp1 = typed(imp)

tests/neg/i22670.check

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-- Warning: tests/neg/i22670/i22670-macro.scala:4:0 --------------------------------------------------------------------
2+
4 |import scala.quoted.*
3+
|^
4+
|The package name `i22670-macro$package` will be encoded on the classpath, and can lead to undefined behaviour.
5+
5 |transparent inline def foo =
6+
6 | ${ fooImpl }
7+
7 |def fooImpl(using Quotes): Expr[Any] =
8+
8 | Expr("hello")
9+
-- Warning: tests/neg/i22670/i22670-usage.scala:4:0 --------------------------------------------------------------------
10+
4 |val x = foo // warn
11+
|^^^^^^^^^^^
12+
|The package name `i22670-usage$package` will be encoded on the classpath, and can lead to undefined behaviour.
13+
Cyclic macro dependencies in tests/neg/i22670/i22670-usage.scala.
14+
Compilation stopped since no further progress can be made.
15+
16+
To fix this, place macros in one set of files and their callers in another.
17+
18+
Compile with -Xprint-suspension for information.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// nopos-error
2+
//package `X-Y` // explicit package name gets a diagnostic
3+
4+
import scala.quoted.*
5+
6+
transparent inline def foo =
7+
${ fooImpl }
8+
9+
def fooImpl(using Quotes): Expr[Any] =
10+
Expr("hello")
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
//import `X-Y`.*
3+
4+
val x = foo // warn

0 commit comments

Comments
 (0)