Skip to content

Commit e6be077

Browse files
authored
Merge pull request #11546 from dotty-staging/fix-main-shadowing
Make main methods invisible
2 parents 0dbe970 + 54495b6 commit e6be077

File tree

14 files changed

+35
-29
lines changed

14 files changed

+35
-29
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/NamerOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ object NamerOps:
6868
}
6969

7070
/** If a class has one of these flags, it does not get a constructor companion */
71-
private val NoConstructorProxyNeededFlags = Abstract | Trait | Case | Synthetic | Module
71+
private val NoConstructorProxyNeededFlags = Abstract | Trait | Case | Synthetic | Module | Invisible
7272

7373
/** The flags of a constructor companion */
7474
private val ConstructorCompanionFlags = Synthetic | ConstructorProxy

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

Lines changed: 3 additions & 2 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? */

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,7 @@ class TreePickler(pickler: TastyPickler) {
728728
if (flags.is(Artifact)) writeModTag(ARTIFACT)
729729
if flags.is(Transparent) then writeModTag(TRANSPARENT)
730730
if flags.is(Infix) then writeModTag(INFIX)
731+
if flags.is(Invisible) then writeModTag(INVISIBLE)
731732
if (isTerm) {
732733
if (flags.is(Implicit)) writeModTag(IMPLICIT)
733734
if (flags.is(Given)) writeModTag(GIVEN)

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -585,12 +585,10 @@ class TreeUnpickler(reader: TastyReader,
585585
val annots = annotFns.map(_(sym.owner))
586586
sym.annotations = annots
587587
if sym.isOpaqueAlias then sym.setFlag(Deferred)
588-
val isSyntheticBeanAccessor = flags.isAllOf(Method | Synthetic) &&
589-
annots.exists(a => a.matches(defn.BeanPropertyAnnot) || a.matches(defn.BooleanBeanPropertyAnnot))
590588
val isScala2MacroDefinedInScala3 = flags.is(Macro, butNot = Inline) && flags.is(Erased)
591589
ctx.owner match {
592-
case cls: ClassSymbol if (!isScala2MacroDefinedInScala3 || cls == defn.StringContextClass) && !isSyntheticBeanAccessor =>
593-
// Enter all members of classes that are not Scala 2 macros or synthetic bean accessors.
590+
case cls: ClassSymbol if !isScala2MacroDefinedInScala3 || cls == defn.StringContextClass =>
591+
// Enter all members of classes that are not Scala 2 macros.
594592
//
595593
// For `StringContext`, enter `s`, `f` and `raw`
596594
// These definitions will be entered when defined in Scala 2. It is fine to enter them
@@ -670,6 +668,7 @@ class TreeUnpickler(reader: TastyReader,
670668
case PARAMalias => addFlag(SuperParamAlias)
671669
case EXPORTED => addFlag(Exported)
672670
case OPEN => addFlag(Open)
671+
case INVISIBLE => addFlag(Invisible)
673672
case TRANSPARENT => addFlag(Transparent)
674673
case INFIX => addFlag(Infix)
675674
case PRIVATEqualified =>

compiler/src/dotty/tools/dotc/transform/BeanProperties.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class BeanProperties(thisPhase: DenotTransformer):
3131
val meth = newSymbol(
3232
owner = ctx.owner,
3333
name = prefixedName(prefix, valDef.name),
34-
flags = Method | Synthetic,
34+
flags = Method | Synthetic | Invisible,
3535
info = MethodType(Nil, valDef.denot.info),
3636
coord = annot.tree.span
3737
).enteredAfter(thisPhase).asTerm
@@ -45,7 +45,7 @@ class BeanProperties(thisPhase: DenotTransformer):
4545
val meth = newSymbol(
4646
owner,
4747
name = prefixedName("set", valDef.name),
48-
flags = Method | Synthetic,
48+
flags = Method | Synthetic | Invisible,
4949
info = MethodType(valDef.name :: Nil, valDef.denot.info :: Nil, defn.UnitType),
5050
coord = annot.tree.span
5151
).enteredAfter(thisPhase).asTerm

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2658,6 +2658,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26582658
def Implicit: Flags = dotc.core.Flags.Implicit
26592659
def Infix: Flags = dotc.core.Flags.Infix
26602660
def Inline: Flags = dotc.core.Flags.Inline
2661+
def Invisible: Flags = dotc.core.Flags.Invisible
26612662
def JavaDefined: Flags = dotc.core.Flags.JavaDefined
26622663
def JavaStatic: Flags = dotc.core.Flags.JavaStatic
26632664
def Lazy: Flags = dotc.core.Flags.Lazy

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

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

library/src/scala/quoted/Quotes.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3902,6 +3902,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
39023902
/** Is this symbol `inline` */
39033903
def Inline: Flags
39043904

3905+
/** Is this symbol invisible when typechecking? */
3906+
def Invisible: Flags
3907+
39053908
/** Is this symbol defined in a Java class */
39063909
def JavaDefined: Flags
39073910

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ Standard-Section: "ASTs" TopLevelStat*
212212
PARAMalias -- Parameter is alias of a superclass parameter
213213
EXPORTED -- An export forwarder
214214
OPEN -- an open class
215+
INVISIBLE -- invisible during typechecking
215216
Annotation
216217
217218
Variance = STABLE -- invariant
@@ -300,7 +301,7 @@ object TastyFormat {
300301
* is able to read final TASTy documents if the file's
301302
* `MinorVersion` is strictly less than the current value.
302303
*/
303-
final val ExperimentalVersion: Int = 1
304+
final val ExperimentalVersion: Int = 2
304305

305306
/**This method implements a binary relation (`<:<`) between two TASTy versions.
306307
* We label the lhs `file` and rhs `compiler`.
@@ -473,8 +474,9 @@ object TastyFormat {
473474
final val PARAMalias = 41
474475
final val TRANSPARENT = 42
475476
final val INFIX = 43
476-
final val EMPTYCLAUSE = 44
477-
final val SPLITCLAUSE = 45
477+
final val INVISIBLE = 44
478+
final val EMPTYCLAUSE = 45
479+
final val SPLITCLAUSE = 46
478480

479481
// Cat. 2: tag Nat
480482

@@ -637,6 +639,7 @@ object TastyFormat {
637639
| PARAMalias
638640
| EXPORTED
639641
| OPEN
642+
| INVISIBLE
640643
| ANNOTATION
641644
| PRIVATEqualified
642645
| PROTECTEDqualified => true
@@ -699,6 +702,7 @@ object TastyFormat {
699702
case PARAMsetter => "PARAMsetter"
700703
case EXPORTED => "EXPORTED"
701704
case OPEN => "OPEN"
705+
case INVISIBLE => "INVISIBLE"
702706
case PARAMalias => "PARAMalias"
703707
case EMPTYCLAUSE => "EMPTYCLAUSE"
704708
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)