diff --git a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala index 45364481a319..9178478c399b 100644 --- a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala +++ b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala @@ -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 @@ -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)), @@ -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 diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 24aa48213f31..80b2d6f13718 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -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) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 8aeb68cbe984..5bcc32de158f 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -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, "") + // ------------ Flags following this one are not pickled ---------------------------------- /** Symbol is not a member of its owner */ @@ -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 @@ -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 | diff --git a/compiler/src/dotty/tools/dotc/core/NamerOps.scala b/compiler/src/dotty/tools/dotc/core/NamerOps.scala index c45e820c0e90..ce525fc5d827 100644 --- a/compiler/src/dotty/tools/dotc/core/NamerOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NamerOps.scala @@ -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 diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index fee5f1f0be87..38b3dc174a72 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -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? */ @@ -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 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 10af44c76169..43cb9bda3b29 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -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) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index d2b9b607a391..52b97fcba891 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -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 @@ -670,6 +668,7 @@ class TreeUnpickler(reader: TastyReader, case PARAMalias => addFlag(SuperParamAlias) case EXPORTED => addFlag(Exported) case OPEN => addFlag(Open) + case INVISIBLE => addFlag(Invisible) case TRANSPARENT => addFlag(Transparent) case INFIX => addFlag(Infix) case PRIVATEqualified => diff --git a/compiler/src/dotty/tools/dotc/transform/BeanProperties.scala b/compiler/src/dotty/tools/dotc/transform/BeanProperties.scala index baeb9cdbea98..91ec94590284 100644 --- a/compiler/src/dotty/tools/dotc/transform/BeanProperties.scala +++ b/compiler/src/dotty/tools/dotc/transform/BeanProperties.scala @@ -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 @@ -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 diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 746ea78e0ba9..60f4ee415897 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -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 diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 53fd04c04136..989efadb9239 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -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() } diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 31c840e49578..08254e1b1113 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -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 diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index f5969169353a..f0f5739e9c92 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -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 @@ -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`. @@ -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 + final val EMPTYCLAUSE = 45 + final val SPLITCLAUSE = 46 // Cat. 2: tag Nat @@ -636,6 +638,7 @@ object TastyFormat { | PARAMalias | EXPORTED | OPEN + | INVISIBLE | ANNOTATION | PRIVATEqualified | PROTECTEDqualified => true @@ -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" diff --git a/tests/neg-custom-args/fatal-warnings/i10137.scala b/tests/neg-custom-args/fatal-warnings/i10137.scala deleted file mode 100644 index 3272c3434e07..000000000000 --- a/tests/neg-custom-args/fatal-warnings/i10137.scala +++ /dev/null @@ -1,4 +0,0 @@ -package foo: - @main def main(): Unit = println("Hello, World!") // error - -@main def List(): Unit = println("List") // error diff --git a/tests/pos/main.scala b/tests/pos/main.scala new file mode 100644 index 000000000000..4f3fd4681e47 --- /dev/null +++ b/tests/pos/main.scala @@ -0,0 +1,4 @@ +package foo: + @main def main(): Unit = println("Hello, World!") + +@main def List(): Unit = println("List")