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 all 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
7 changes: 3 additions & 4 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -585,12 +585,10 @@ 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 =>
// Enter all members of classes that are not Scala 2 macros or synthetic bean accessors.
case cls: ClassSymbol if !isScala2MacroDefinedInScala3 || cls == defn.StringContextClass =>
// Enter all members of classes that are not Scala 2 macros.
//
// For `StringContext`, enter `s`, `f` and `raw`
// These definitions will be entered when defined in Scala 2. It is fine to enter them
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
1 change: 1 addition & 0 deletions compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2664,6 +2664,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
def Implicit: Flags = dotc.core.Flags.Implicit
def Infix: Flags = dotc.core.Flags.Infix
def Inline: Flags = dotc.core.Flags.Inline
def Invisible: Flags = dotc.core.Flags.Invisible
def JavaDefined: Flags = dotc.core.Flags.JavaDefined
def JavaStatic: Flags = dotc.core.Flags.JavaStatic
def Lazy: Flags = dotc.core.Flags.Lazy
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
3 changes: 3 additions & 0 deletions library/src/scala/quoted/Quotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3884,6 +3884,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
/** Is this symbol `inline` */
def Inline: Flags

/** Is this symbol invisible when typechecking? */
def Invisible: Flags

/** Is this symbol defined in a Java class */
def JavaDefined: Flags

Expand Down
10 changes: 7 additions & 3 deletions tasty/src/dotty/tools/tasty/TastyFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ Standard-Section: "ASTs" TopLevelStat*
PARAMalias -- Parameter is alias of a superclass parameter
EXPORTED -- An export forwarder
OPEN -- an open class
INVISIBLE -- invisible during typechecking
Annotation

Variance = STABLE -- invariant
Expand Down Expand Up @@ -300,7 +301,7 @@ object TastyFormat {
* is able to read final TASTy documents if the file's
* `MinorVersion` is strictly less than the current value.
*/
final val ExperimentalVersion: Int = 1
final val ExperimentalVersion: Int = 2

/**This method implements a binary relation (`<:<`) between two TASTy versions.
* We label the lhs `file` and rhs `compiler`.
Expand Down Expand Up @@ -472,8 +473,9 @@ object TastyFormat {
final val PARAMalias = 41
final val TRANSPARENT = 42
final val INFIX = 43
final val EMPTYCLAUSE = 44
final val SPLITCLAUSE = 45
final val INVISIBLE = 44
Copy link
Member

Choose a reason for hiding this comment

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

normally this would require a MajorVersion bump, but as we have not yet had a stable ExperimentalVersion this is fine

final val EMPTYCLAUSE = 45
final val SPLITCLAUSE = 46

// 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")