Skip to content

Make main methods invisible #11546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 9, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions compiler/src/dotty/tools/dotc/ast/MainProxies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,6 @@ object MainProxies {
mainMethods(stats).flatMap(mainProxy)
}

private def checkNoShadowing(mainFun: Symbol)(using Context) =
val cls = ctx.typer.findRef(mainFun.name.toTypeName, WildcardType, EmptyFlags, EmptyFlags, mainFun).typeSymbol
if cls.exists && cls.owner != ctx.owner then
report.warning(
i"""The class `${ctx.printer.fullNameString(mainFun)}` generated from `@main` will shadow the existing ${cls.showLocated}.
|The existing definition might no longer be found on recompile.""", mainFun)

import untpd._
def mainProxy(mainFun: Symbol)(using Context): List[TypeDef] = {
val mainAnnotSpan = mainFun.getAnnotation(defn.MainAnnot).get.tree.span
Expand Down Expand Up @@ -93,7 +86,6 @@ object MainProxies {
case _ =>
report.error(s"@main can only annotate a method", pos)
}
checkNoShadowing(mainFun)
val errVar = Ident(nme.error)
val handler = CaseDef(
Typed(errVar, TypeTree(defn.CLP_ParseError.typeRef)),
Expand All @@ -106,7 +98,7 @@ object MainProxies {
.withFlags(JavaStatic)
val mainTempl = Template(emptyConstructor, Nil, Nil, EmptyValDef, mainMeth :: Nil)
val mainCls = TypeDef(mainFun.name.toTypeName, mainTempl)
.withFlags(Final)
.withFlags(Final | Invisible)
if (!ctx.reporter.hasErrors) result = mainCls.withSpan(mainAnnotSpan.toSynthetic) :: Nil
}
result
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1061,11 +1061,12 @@ object Denotations {
def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation =
if (denots.exists && denots.matches(this)) NoDenotation else this
def filterWithFlags(required: FlagSet, excluded: FlagSet)(using Context): SingleDenotation =
val realExcluded = if ctx.isAfterTyper then excluded else excluded | Invisible
def symd: SymDenotation = this match
case symd: SymDenotation => symd
case _ => symbol.denot
if !required.isEmpty && !symd.isAllOf(required)
|| !excluded.isEmpty && symd.isOneOf(excluded) then NoDenotation
|| symd.isOneOf(realExcluded) then NoDenotation
else this
def aggregate[T](f: SingleDenotation => T, g: (T, T) => T): T = f(this)

Expand Down
7 changes: 5 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ object Flags {
/** An infix method or type */
val (Infix @ _, _, _) = newFlags(44, "infix")

/** Symbol cannot be found as a member during typer */
val (Invisible @ _, _, _) = newFlags(45, "<invisible>")

// ------------ Flags following this one are not pickled ----------------------------------

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

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

/** Flags that can apply to a module val */
val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags |
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/NamerOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ object NamerOps:
}

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

/** The flags of a constructor companion */
private val ConstructorCompanionFlags = Synthetic | ConstructorProxy
Expand Down
9 changes: 5 additions & 4 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -572,8 +572,9 @@ object SymDenotations {
isAbsent(canForce)
case _ =>
// Otherwise, no completion is necessary, see the preconditions of `markAbsent()`.
(myInfo `eq` NoType) ||
is(ModuleVal, butNot = Package) && moduleClass.isAbsent(canForce)
(myInfo `eq` NoType)
|| is(Invisible) && !ctx.isAfterTyper
|| is(ModuleVal, butNot = Package) && moduleClass.isAbsent(canForce)
}

/** Is this symbol the root class or its companion object? */
Expand Down Expand Up @@ -2209,8 +2210,8 @@ object SymDenotations {
ensureCompleted()
myCompanion

override def registeredCompanion_=(c: Symbol) =
myCompanion = c
override def registeredCompanion_=(c: Symbol) =
myCompanion = c

private var myNestingLevel = -1

Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ class TreePickler(pickler: TastyPickler) {
if (flags.is(Artifact)) writeModTag(ARTIFACT)
if flags.is(Transparent) then writeModTag(TRANSPARENT)
if flags.is(Infix) then writeModTag(INFIX)
if flags.is(Invisible) then writeModTag(INVISIBLE)
if (isTerm) {
if (flags.is(Implicit)) writeModTag(IMPLICIT)
if (flags.is(Given)) writeModTag(GIVEN)
Expand Down
5 changes: 2 additions & 3 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -585,11 +585,9 @@ class TreeUnpickler(reader: TastyReader,
val annots = annotFns.map(_(sym.owner))
sym.annotations = annots
if sym.isOpaqueAlias then sym.setFlag(Deferred)
val isSyntheticBeanAccessor = flags.isAllOf(Method | Synthetic) &&
annots.exists(a => a.matches(defn.BeanPropertyAnnot) || a.matches(defn.BooleanBeanPropertyAnnot))
val isScala2MacroDefinedInScala3 = flags.is(Macro, butNot = Inline) && flags.is(Erased)
ctx.owner match {
case cls: ClassSymbol if (!isScala2MacroDefinedInScala3 || cls == defn.StringContextClass) && !isSyntheticBeanAccessor =>
case cls: ClassSymbol if !isScala2MacroDefinedInScala3 || cls == defn.StringContextClass =>
// Enter all members of classes that are not Scala 2 macros or synthetic bean accessors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Enter all members of classes that are not Scala 2 macros or synthetic bean accessors.
// Enter all members of classes that are not Scala 2 macros

//
// For `StringContext`, enter `s`, `f` and `raw`
Expand Down Expand Up @@ -670,6 +668,7 @@ class TreeUnpickler(reader: TastyReader,
case PARAMalias => addFlag(SuperParamAlias)
case EXPORTED => addFlag(Exported)
case OPEN => addFlag(Open)
case INVISIBLE => addFlag(Invisible)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flag should be visible in tasty-reflect too /cc @nicolasstucki

case TRANSPARENT => addFlag(Transparent)
case INFIX => addFlag(Infix)
case PRIVATEqualified =>
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/BeanProperties.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class BeanProperties(thisPhase: DenotTransformer):
val meth = newSymbol(
owner = ctx.owner,
name = prefixedName(prefix, valDef.name),
flags = Method | Synthetic,
flags = Method | Synthetic | Invisible,
info = MethodType(Nil, valDef.denot.info),
coord = annot.tree.span
).enteredAfter(thisPhase).asTerm
Expand All @@ -45,7 +45,7 @@ class BeanProperties(thisPhase: DenotTransformer):
val meth = newSymbol(
owner,
name = prefixedName("set", valDef.name),
flags = Method | Synthetic,
flags = Method | Synthetic | Invisible,
info = MethodType(valDef.name :: Nil, valDef.denot.info :: Nil, defn.UnitType),
coord = annot.tree.span
).enteredAfter(thisPhase).asTerm
Expand Down
3 changes: 2 additions & 1 deletion compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ class CompilationTests {
compileFile("tests/pos/i0239.scala", defaultOptions),
compileFile("tests/pos/anonClassSubtyping.scala", defaultOptions),
compileFile("tests/pos/extmethods.scala", defaultOptions),
compileFile("tests/pos/companions.scala", defaultOptions)
compileFile("tests/pos/companions.scala", defaultOptions),
compileFile("tests/pos/main.scala", defaultOptions)
).times(2).checkCompile()
}

Expand Down
8 changes: 6 additions & 2 deletions tasty/src/dotty/tools/tasty/TastyFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ Standard-Section: "ASTs" TopLevelStat*
PARAMsetter -- The setter part `x_=` of a var parameter `x` which itself is pickled as a PARAM
PARAMalias -- Parameter is alias of a superclass parameter
EXPORTED -- An export forwarder
OPEN -- an open class
OPEN
INVISIBLE -- an open class
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on wrong line (and inconsistently indented).

Annotation

Variance = STABLE -- invariant
Expand Down Expand Up @@ -284,7 +285,7 @@ object TastyFormat {
* compatibility, but remains backwards compatible, with all
* preceeding `MinorVersion`.
*/
final val MinorVersion: Int = 0
final val MinorVersion: Int = 1

/**Natural Number. The `ExperimentalVersion` allows for
* experimentation with changes to TASTy without committing
Expand Down Expand Up @@ -474,6 +475,7 @@ object TastyFormat {
final val INFIX = 43
final val EMPTYCLAUSE = 44
final val SPLITCLAUSE = 45
final val INVISIBLE = 46
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isLegalTag in this file still says:

firstSimpleTreeTag <= tag && tag <= SPLITCLAUSE ||

presumably that should be replaced with INVISIBLE (we should really add something like final val LAST_SIMPLE_TAG = INVISIBLE to avoid having to update multiple places like this).


// Cat. 2: tag Nat

Expand Down Expand Up @@ -636,6 +638,7 @@ object TastyFormat {
| PARAMalias
| EXPORTED
| OPEN
| INVISIBLE
| ANNOTATION
| PRIVATEqualified
| PROTECTEDqualified => true
Expand Down Expand Up @@ -698,6 +701,7 @@ object TastyFormat {
case PARAMsetter => "PARAMsetter"
case EXPORTED => "EXPORTED"
case OPEN => "OPEN"
case INVISIBLE => "INVISIBLE"
case PARAMalias => "PARAMalias"
case EMPTYCLAUSE => "EMPTYCLAUSE"
case SPLITCLAUSE => "SPLITCLAUSE"
Expand Down
4 changes: 0 additions & 4 deletions tests/neg-custom-args/fatal-warnings/i10137.scala

This file was deleted.

4 changes: 4 additions & 0 deletions tests/pos/main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package foo:
@main def main(): Unit = println("Hello, World!")

@main def List(): Unit = println("List")