Skip to content

Commit 09b7746

Browse files
committed
Make main methods invisible
Add a new flag Invisible that gets set for compiler-generated main methods. Invisible symbols are skipped when resolving members during typechecking. They become visible after typechecking. With that mechanism, we can accept main methods that are themselves called `main`.
1 parent ce30a1c commit 09b7746

File tree

10 files changed

+27
-23
lines changed

10 files changed

+27
-23
lines changed

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

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,6 @@ object MainProxies {
3939
mainMethods(stats).flatMap(mainProxy)
4040
}
4141

42-
private def checkNoShadowing(mainFun: Symbol)(using Context) =
43-
val cls = ctx.typer.findRef(mainFun.name.toTypeName, WildcardType, EmptyFlags, EmptyFlags, mainFun).typeSymbol
44-
if cls.exists && cls.owner != ctx.owner then
45-
report.warning(
46-
i"""The class `${ctx.printer.fullNameString(mainFun)}` generated from `@main` will shadow the existing ${cls.showLocated}.
47-
|The existing definition might no longer be found on recompile.""", mainFun)
48-
4942
import untpd._
5043
def mainProxy(mainFun: Symbol)(using Context): List[TypeDef] = {
5144
val mainAnnotSpan = mainFun.getAnnotation(defn.MainAnnot).get.tree.span
@@ -93,7 +86,6 @@ object MainProxies {
9386
case _ =>
9487
report.error(s"@main can only annotate a method", pos)
9588
}
96-
checkNoShadowing(mainFun)
9789
val errVar = Ident(nme.error)
9890
val handler = CaseDef(
9991
Typed(errVar, TypeTree(defn.CLP_ParseError.typeRef)),
@@ -106,7 +98,7 @@ object MainProxies {
10698
.withFlags(JavaStatic)
10799
val mainTempl = Template(emptyConstructor, Nil, Nil, EmptyValDef, mainMeth :: Nil)
108100
val mainCls = TypeDef(mainFun.name.toTypeName, mainTempl)
109-
.withFlags(Final)
101+
.withFlags(Final | Invisible)
110102
if (!ctx.reporter.hasErrors) result = mainCls.withSpan(mainAnnotSpan.toSynthetic) :: Nil
111103
}
112104
result

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,11 +1061,12 @@ object Denotations {
10611061
def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation =
10621062
if (denots.exists && denots.matches(this)) NoDenotation else this
10631063
def filterWithFlags(required: FlagSet, excluded: FlagSet)(using Context): SingleDenotation =
1064+
val realExcluded = if ctx.isAfterTyper then excluded else excluded | Invisible
10641065
def symd: SymDenotation = this match
10651066
case symd: SymDenotation => symd
10661067
case _ => symbol.denot
10671068
if !required.isEmpty && !symd.isAllOf(required)
1068-
|| !excluded.isEmpty && symd.isOneOf(excluded) then NoDenotation
1069+
|| symd.isOneOf(realExcluded) then NoDenotation
10691070
else this
10701071
def aggregate[T](f: SingleDenotation => T, g: (T, T) => T): T = f(this)
10711072

compiler/src/dotty/tools/dotc/core/Flags.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,9 @@ object Flags {
369369
/** An infix method or type */
370370
val (Infix @ _, _, _) = newFlags(44, "infix")
371371

372+
/** Symbol cannot be found as a member during typer */
373+
val (Invisible @ _, _, _) = newFlags(45, "<invisible>")
374+
372375
// ------------ Flags following this one are not pickled ----------------------------------
373376

374377
/** Symbol is not a member of its owner */
@@ -458,7 +461,7 @@ object Flags {
458461
Scala2SpecialFlags, MutableOrOpen, Opaque, Touched, JavaStatic,
459462
OuterOrCovariant, LabelOrContravariant, CaseAccessor,
460463
Extension, NonMember, Implicit, Given, Permanent, Synthetic,
461-
SuperParamAliasOrScala2x, Inline, Macro, ConstructorProxy)
464+
SuperParamAliasOrScala2x, Inline, Macro, ConstructorProxy, Invisible)
462465

463466
/** Flags that are not (re)set when completing the denotation, or, if symbol is
464467
* a top-level class or object, when completing the denotation once the class
@@ -512,7 +515,7 @@ object Flags {
512515
val RetainedModuleValAndClassFlags: FlagSet =
513516
AccessFlags | Package | Case |
514517
Synthetic | JavaDefined | JavaStatic | Artifact |
515-
Lifted | MixedIn | Specialized | ConstructorProxy
518+
Lifted | MixedIn | Specialized | ConstructorProxy | Invisible
516519

517520
/** Flags that can apply to a module val */
518521
val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags |

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,9 @@ object SymDenotations {
572572
isAbsent(canForce)
573573
case _ =>
574574
// Otherwise, no completion is necessary, see the preconditions of `markAbsent()`.
575-
(myInfo `eq` NoType) ||
576-
is(ModuleVal, butNot = Package) && moduleClass.isAbsent(canForce)
575+
(myInfo `eq` NoType)
576+
|| is(Invisible) && !ctx.isAfterTyper
577+
|| is(ModuleVal, butNot = Package) && moduleClass.isAbsent(canForce)
577578
}
578579

579580
/** Is this symbol the root class or its companion object? */
@@ -2209,8 +2210,8 @@ object SymDenotations {
22092210
ensureCompleted()
22102211
myCompanion
22112212

2212-
override def registeredCompanion_=(c: Symbol) =
2213-
myCompanion = c
2213+
override def registeredCompanion_=(c: Symbol) =
2214+
myCompanion = c
22142215

22152216
private var myNestingLevel = -1
22162217

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ class TreePickler(pickler: TastyPickler) {
724724
if (flags.is(Artifact)) writeModTag(ARTIFACT)
725725
if flags.is(Transparent) then writeModTag(TRANSPARENT)
726726
if flags.is(Infix) then writeModTag(INFIX)
727+
if flags.is(Invisible) then writeModTag(INVISIBLE)
727728
if (isTerm) {
728729
if (flags.is(Implicit)) writeModTag(IMPLICIT)
729730
if (flags.is(Given)) writeModTag(GIVEN)

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,7 @@ class TreeUnpickler(reader: TastyReader,
670670
case PARAMalias => addFlag(SuperParamAlias)
671671
case EXPORTED => addFlag(Exported)
672672
case OPEN => addFlag(Open)
673+
case INVISIBLE => addFlag(Invisible)
673674
case TRANSPARENT => addFlag(Transparent)
674675
case INFIX => addFlag(Infix)
675676
case PRIVATEqualified =>

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ class CompilationTests {
109109
compileFile("tests/pos/i0239.scala", defaultOptions),
110110
compileFile("tests/pos/anonClassSubtyping.scala", defaultOptions),
111111
compileFile("tests/pos/extmethods.scala", defaultOptions),
112-
compileFile("tests/pos/companions.scala", defaultOptions)
112+
compileFile("tests/pos/companions.scala", defaultOptions),
113+
compileFile("tests/pos/main.scala", defaultOptions)
113114
).times(2).checkCompile()
114115
}
115116

tasty/src/dotty/tools/tasty/TastyFormat.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,8 @@ Standard-Section: "ASTs" TopLevelStat*
211211
PARAMsetter -- The setter part `x_=` of a var parameter `x` which itself is pickled as a PARAM
212212
PARAMalias -- Parameter is alias of a superclass parameter
213213
EXPORTED -- An export forwarder
214-
OPEN -- an open class
214+
OPEN
215+
INVISIBLE -- an open class
215216
Annotation
216217
217218
Variance = STABLE -- invariant
@@ -284,7 +285,7 @@ object TastyFormat {
284285
* compatibility, but remains backwards compatible, with all
285286
* preceeding `MinorVersion`.
286287
*/
287-
final val MinorVersion: Int = 0
288+
final val MinorVersion: Int = 1
288289

289290
/**Natural Number. The `ExperimentalVersion` allows for
290291
* experimentation with changes to TASTy without committing
@@ -474,6 +475,7 @@ object TastyFormat {
474475
final val INFIX = 43
475476
final val EMPTYCLAUSE = 44
476477
final val SPLITCLAUSE = 45
478+
final val INVISIBLE = 46
477479

478480
// Cat. 2: tag Nat
479481

@@ -636,6 +638,7 @@ object TastyFormat {
636638
| PARAMalias
637639
| EXPORTED
638640
| OPEN
641+
| INVISIBLE
639642
| ANNOTATION
640643
| PRIVATEqualified
641644
| PROTECTEDqualified => true
@@ -698,6 +701,7 @@ object TastyFormat {
698701
case PARAMsetter => "PARAMsetter"
699702
case EXPORTED => "EXPORTED"
700703
case OPEN => "OPEN"
704+
case INVISIBLE => "INVISIBLE"
701705
case PARAMalias => "PARAMalias"
702706
case EMPTYCLAUSE => "EMPTYCLAUSE"
703707
case SPLITCLAUSE => "SPLITCLAUSE"

tests/neg-custom-args/fatal-warnings/i10137.scala

Lines changed: 0 additions & 4 deletions
This file was deleted.

tests/pos/main.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package foo:
2+
@main def main(): Unit = println("Hello, World!")
3+
4+
@main def List(): Unit = println("List")

0 commit comments

Comments
 (0)