diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index e47def78fba1..1b5096640b2b 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -116,6 +116,9 @@ object Denotations { */ def filterWithFlags(required: FlagSet, excluded: FlagSet)(implicit ctx: Context): PreDenotation + /** Map `f` over all single denotations and aggregate the results with `g`. */ + def aggregate[T](f: SingleDenotation => T, g: (T, T) => T): T + private var cachedPrefix: Type = _ private var cachedAsSeenFrom: AsSeenFromResult = _ private var validAsSeenFrom: Period = Nowhere @@ -1132,6 +1135,7 @@ object Denotations { if (denots.exists && denots.matches(this)) NoDenotation else this def filterWithFlags(required: FlagSet, excluded: FlagSet)(implicit ctx: Context): SingleDenotation = if (required.isEmpty && excluded.isEmpty || compatibleWith(required, excluded)) this else NoDenotation + def aggregate[T](f: SingleDenotation => T, g: (T, T) => T): T = f(this) type AsSeenFromResult = SingleDenotation protected def computeAsSeenFrom(pre: Type)(implicit ctx: Context): SingleDenotation = { @@ -1286,6 +1290,8 @@ object Denotations { derivedUnion(denot1 filterDisjoint denot, denot2 filterDisjoint denot) def filterWithFlags(required: FlagSet, excluded: FlagSet)(implicit ctx: Context): PreDenotation = derivedUnion(denot1.filterWithFlags(required, excluded), denot2.filterWithFlags(required, excluded)) + def aggregate[T](f: SingleDenotation => T, g: (T, T) => T): T = + g(denot1.aggregate(f, g), denot2.aggregate(f, g)) protected def derivedUnion(denot1: PreDenotation, denot2: PreDenotation) = if ((denot1 eq this.denot1) && (denot2 eq this.denot2)) this else denot1 union denot2 diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 50b940ec9211..87d448e672f4 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -16,6 +16,7 @@ import annotation.tailrec import util.SimpleIdentityMap import util.Stats import java.util.WeakHashMap +import scala.util.control.NonFatal import config.Config import reporting.diagnostic.Message import reporting.diagnostic.messages.BadSymbolicReference @@ -625,6 +626,10 @@ object SymDenotations { def isPackageObject(implicit ctx: Context): Boolean = name.isPackageObjectName && owner.is(Package) && this.is(Module) + /** Is this symbol a toplevel definition in a package object? */ + def isWrappedToplevelDef(given Context): Boolean = + !isConstructor && owner.isPackageObject + /** Is this symbol an abstract type? */ final def isAbstractType(implicit ctx: Context): Boolean = this.is(DeferredType) @@ -1527,6 +1532,14 @@ object SymDenotations { myBaseTypeCachePeriod = Nowhere } + def invalidateMemberCaches(sym: Symbol)(given Context): Unit = + if myMemberCache != null then myMemberCache.invalidate(sym.name) + if !sym.flagsUNSAFE.is(Private) then + invalidateMemberNamesCache() + if sym.isWrappedToplevelDef then + val outerCache = sym.owner.owner.asClass.classDenot.myMemberCache + if outerCache != null then outerCache.invalidate(sym.name) + override def copyCaches(from: SymDenotation, phase: Phase)(implicit ctx: Context): this.type = { from match { case from: ClassDenotation => @@ -1726,11 +1739,9 @@ object SymDenotations { } /** Enter a symbol in given `scope` without potentially replacing the old copy. */ - def enterNoReplace(sym: Symbol, scope: MutableScope)(implicit ctx: Context): Unit = { + def enterNoReplace(sym: Symbol, scope: MutableScope)(given Context): Unit = scope.enter(sym) - if (myMemberCache != null) myMemberCache.invalidate(sym.name) - if (!sym.flagsUNSAFE.is(Private)) invalidateMemberNamesCache() - } + invalidateMemberCaches(sym) /** Replace symbol `prev` (if defined in current class) by symbol `replacement`. * If `prev` is not defined in current class, do nothing. @@ -2071,6 +2082,7 @@ object SymDenotations { private var packageObjsCache: List[ClassDenotation] = _ private var packageObjsRunId: RunId = NoRunId + private var ambiguityWarningIssued: Boolean = false /** The package objects in this class */ def packageObjs(implicit ctx: Context): List[ClassDenotation] = { @@ -2122,9 +2134,8 @@ object SymDenotations { case pcls :: pobjs1 => if (pcls.isCompleting) recur(pobjs1, acc) else { - // A package object inherits members from `Any` and `Object` which - // should not be accessible from the package prefix. val pmembers = pcls.computeNPMembersNamed(name).filterWithPredicate { d => + // Drop members of `Any` and `Object` val owner = d.symbol.maybeOwner (owner ne defn.AnyClass) && (owner ne defn.ObjectClass) } @@ -2132,9 +2143,52 @@ object SymDenotations { } case nil => val directMembers = super.computeNPMembersNamed(name) - if (acc.exists) acc.union(directMembers.filterWithPredicate(!_.symbol.isAbsent())) - else directMembers + if !acc.exists then directMembers + else acc.union(directMembers.filterWithPredicate(!_.symbol.isAbsent())) match + case d: DenotUnion => dropStale(d) + case d => d } + + def dropStale(multi: DenotUnion): PreDenotation = + val compiledNow = multi.filterWithPredicate(d => + d.symbol.isDefinedInCurrentRun || d.symbol.associatedFile == null + // if a symbol does not have an associated file, assume it is defined + // in the current run anyway. This is true for packages, and also can happen for pickling and + // from-tasty tests that generate a fresh symbol and then re-use it in the next run. + ) + if compiledNow.exists then compiledNow + else + val assocFiles = multi.aggregate(d => Set(d.symbol.associatedFile), _ union _) + if assocFiles.size == 1 then + multi // they are all overloaded variants from the same file + else + // pick the variant(s) from the youngest class file + val lastModDate = assocFiles.map(_.lastModified).max + val youngest = assocFiles.filter(_.lastModified == lastModDate) + val chosen = youngest.head + def ambiguousFilesMsg(f: AbstractFile) = + em"""Toplevel definition $name is defined in + | $chosen + |and also in + | $f""" + if youngest.size > 1 then + throw TypeError(i"""${ambiguousFilesMsg(youngest.tail.head)} + |One of these files should be removed from the classpath.""") + + // Warn if one of the older files comes from a different container. + // In that case picking the youngest file is not necessarily what we want, + // since the older file might have been loaded from a jar earlier in the + // classpath. + def sameContainer(f: AbstractFile): Boolean = + try f.container == chosen.container catch case NonFatal(ex) => true + if !ambiguityWarningIssued then + for conflicting <- assocFiles.find(!sameContainer(_)) do + ctx.warning(i"""${ambiguousFilesMsg(conflicting)} + |Keeping only the definition in $chosen""") + ambiguityWarningIssued = true + multi.filterWithPredicate(_.symbol.associatedFile == chosen) + end dropStale + if (symbol `eq` defn.ScalaPackageClass) { val denots = super.computeNPMembersNamed(name) if (denots.exists) denots @@ -2154,8 +2208,8 @@ object SymDenotations { recur(packageObjs, super.memberNames(keepOnly)) } - /** If another symbol with the same name is entered, unlink it, - * and, if symbol is a package object, invalidate the packageObj cache. + /** If another symbol with the same name is entered, unlink it. + * If symbol is a package object, invalidate the packageObj cache. * @return `sym` is not already entered */ override def proceedWithEnter(sym: Symbol, mscope: MutableScope)(implicit ctx: Context): Boolean = { @@ -2163,8 +2217,8 @@ object SymDenotations { if (entry != null) { if (entry.sym == sym) return false mscope.unlink(entry) - if (sym.name.isPackageObjectName) packageObjsRunId = NoRunId } + if (sym.name.isPackageObjectName) packageObjsRunId = NoRunId true } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 1c5c1941ab25..9a64593c614f 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1908,10 +1908,15 @@ object messages { } case class PackageNameAlreadyDefined(pkg: Symbol)(implicit ctx: Context) extends Message(PackageNameAlreadyDefinedID) { - val msg: String = em"${pkg} is already defined, cannot be a ${hl("package")}" + val (where, or) = + if pkg.associatedFile == null then ("", "") + else (s" in ${pkg.associatedFile}", " or delete the containing class file") + val msg: String = em"""${pkg.name} is the name of $pkg$where. + |It cannot be used at the same time as the name of a package.""" val kind: String = "Naming" val explanation: String = - em"An ${hl("object")} cannot have the same name as an existing ${hl("package")}. Rename either one of them." + em"""An ${hl("object")} or other toplevel definition cannot have the same name as an existing ${hl("package")}. + |Rename either one of them$or.""" } case class UnapplyInvalidNumberOfArguments(qual: untpd.Tree, argTypes: List[Type])(implicit ctx: Context) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index fb70dec6fd04..49cfdcc2af80 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -302,21 +302,48 @@ class Namer { typer: Typer => typr.println(i"creating symbol for $tree in ${ctx.mode}") - def checkNoConflict(name: Name): Name = { - def errorName(msg: => String) = { - ctx.error(msg, tree.sourcePos) - name.freshened - } - def preExisting = ctx.effectiveScope.lookup(name) - if (ctx.owner.is(PackageClass)) - if (preExisting.isDefinedInCurrentRun) - errorName(s"${preExisting.showLocated} has already been compiled once during this run") - else name + /** Check that a new definition with given name and privacy status + * in current context would not conflict with existing currently + * compiled definitions. + * The logic here is very subtle and fragile due to the fact that + * we are not allowed to force anything. + */ + def checkNoConflict(name: Name, isPrivate: Boolean): Name = + val owner = ctx.owner + var conflictsDetected = false + + def conflict(conflicting: Symbol) = + val where: String = + if conflicting.owner == owner then "" + else if conflicting.owner.isPackageObject then i" in ${conflicting.associatedFile}" + else i" in ${conflicting.owner}" + ctx.error(i"$name is already defined as $conflicting$where", tree.sourcePos) + conflictsDetected = true + + def checkNoConflictIn(owner: Symbol) = + val preExisting = owner.unforcedDecls.lookup(name) + if (preExisting.isDefinedInCurrentRun || preExisting.lastKnownDenotation.is(Package)) + && (!preExisting.lastKnownDenotation.is(Private) || preExisting.owner.is(Package)) + then conflict(preExisting) + + def pkgObjs(pkg: Symbol) = + pkg.denot.asInstanceOf[PackageClassDenotation].packageObjs.map(_.symbol) + + if owner.is(PackageClass) then + checkNoConflictIn(owner) + for pkgObj <- pkgObjs(owner) do + checkNoConflictIn(pkgObj) else - if ((!ctx.owner.isClass || name.isTypeName) && preExisting.exists) - errorName(i"$name is already defined as $preExisting") - else name - } + def preExisting = ctx.effectiveScope.lookup(name) + if (!owner.isClass || name.isTypeName) && preExisting.exists then + conflict(preExisting) + else if owner.isPackageObject && !isPrivate && name != nme.CONSTRUCTOR then + checkNoConflictIn(owner.owner) + for pkgObj <- pkgObjs(owner.owner) if pkgObj != owner do + checkNoConflictIn(pkgObj) + + if conflictsDetected then name.freshened else name + end checkNoConflict /** Create new symbol or redefine existing symbol under lateCompile. */ def createOrRefine[S <: Symbol]( @@ -348,8 +375,8 @@ class Namer { typer: Typer => tree match { case tree: TypeDef if tree.isClassDef => - val name = checkNoConflict(tree.name).asTypeName val flags = checkFlags(tree.mods.flags &~ GivenOrImplicit) + val name = checkNoConflict(tree.name, flags.is(Private)).asTypeName val cls = createOrRefine[ClassSymbol](tree, name, flags, ctx.owner, cls => adjustIfModule(new ClassCompleter(cls, tree)(ctx), tree), @@ -357,8 +384,8 @@ class Namer { typer: Typer => cls.completer.asInstanceOf[ClassCompleter].init() cls case tree: MemberDef => - val name = checkNoConflict(tree.name) var flags = checkFlags(tree.mods.flags) + val name = checkNoConflict(tree.name, flags.is(Private)) tree match case tree: ValOrDefDef => if tree.unforcedRhs == EmptyTree diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index b8e262d2d239..c646df6ee279 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1875,12 +1875,11 @@ class Typer extends Namer assignType(cpy.Import(imp)(expr1, selectors1), sym) } - def typedPackageDef(tree: untpd.PackageDef)(implicit ctx: Context): Tree = { + def typedPackageDef(tree: untpd.PackageDef)(implicit ctx: Context): Tree = val pid1 = typedExpr(tree.pid, AnySelectionProto)(ctx.addMode(Mode.InPackageClauseName)) val pkg = pid1.symbol - pid1 match { - case pid1: RefTree if pkg.exists => - if (!pkg.is(Package)) ctx.error(PackageNameAlreadyDefined(pkg), tree.sourcePos) + pid1 match + case pid1: RefTree if pkg.is(Package) => val packageCtx = ctx.packageContext(tree, pkg) var stats1 = typedStats(tree.stats, pkg.moduleClass)(packageCtx)._1 if (!ctx.isAfterTyper) @@ -1888,9 +1887,10 @@ class Typer extends Namer cpy.PackageDef(tree)(pid1, stats1).withType(pkg.termRef) case _ => // Package will not exist if a duplicate type has already been entered, see `tests/neg/1708.scala` - errorTree(tree, i"package ${tree.pid.name} does not exist") - } - } + errorTree(tree, + if pkg.exists then PackageNameAlreadyDefined(pkg) + else i"package ${tree.pid.name} does not exist") + end typedPackageDef def typedAnnotated(tree: untpd.Annotated, pt: Type)(implicit ctx: Context): Tree = { val annot1 = typedExpr(tree.annot, defn.AnnotationClass.typeRef) diff --git a/docs/docs/reference/dropped-features/package-objects.md b/docs/docs/reference/dropped-features/package-objects.md index ee1b1a5d6f24..2e0f51b25fb1 100644 --- a/docs/docs/reference/dropped-features/package-objects.md +++ b/docs/docs/reference/dropped-features/package-objects.md @@ -42,3 +42,6 @@ in a source file `src.scala`, it could be invoked from the command line using a "program name" is mangled it is recommended to always put `main` methods in explicitly named objects. **Note 3:** The notion of `private` is independent of whether a definition is wrapped or not. A `private` toplevel definition is always visible from everywhere in the enclosing package. + +**Note 4:** If several toplevel definitions are overloaded variants with the same name, +they must all come from the same source file. diff --git a/tests/neg/toplevel-doubledef/Test_2.scala b/tests/neg/toplevel-doubledef/Test_2.scala deleted file mode 100644 index 0539a4be38d0..000000000000 --- a/tests/neg/toplevel-doubledef/Test_2.scala +++ /dev/null @@ -1,3 +0,0 @@ -object Test extends App{ - hello("hello") // error: Cannot merge -} \ No newline at end of file diff --git a/tests/neg/toplevel-doubledef/moredefs_1.scala b/tests/neg/toplevel-doubledef/moredefs_1.scala index 6b5c7d12a938..c131b307ebec 100644 --- a/tests/neg/toplevel-doubledef/moredefs_1.scala +++ b/tests/neg/toplevel-doubledef/moredefs_1.scala @@ -1,2 +1,2 @@ -def hello(x: String): Unit = +def hello(x: String): Unit = // error: has already been compiled println(s"hi, $x") \ No newline at end of file diff --git a/tests/neg/toplevel-overload/Test_3.scala b/tests/neg/toplevel-overload/Test_3.scala deleted file mode 100644 index 1d1dd246340e..000000000000 --- a/tests/neg/toplevel-overload/Test_3.scala +++ /dev/null @@ -1,6 +0,0 @@ -class C extends A, B - -val c = new C - -val d = f(c) // error: ambiguous overload - diff --git a/tests/neg/toplevel-overload/defs_1.scala b/tests/neg/toplevel-overload/defs_1.scala index 5c74aaa1249b..dfbba378d07e 100644 --- a/tests/neg/toplevel-overload/defs_1.scala +++ b/tests/neg/toplevel-overload/defs_1.scala @@ -1,3 +1,5 @@ trait A def f(x: A) = s"A" + +def g(): Unit = () \ No newline at end of file diff --git a/tests/neg/toplevel-overload/defs_2.scala b/tests/neg/toplevel-overload/defs_2.scala deleted file mode 100644 index f2ac0f806854..000000000000 --- a/tests/neg/toplevel-overload/defs_2.scala +++ /dev/null @@ -1,3 +0,0 @@ -trait B - -def f(x: B) = s"B" diff --git a/tests/neg/toplevel-overload/moredefs_1.scala b/tests/neg/toplevel-overload/moredefs_1.scala new file mode 100644 index 000000000000..5ba8cfc52078 --- /dev/null +++ b/tests/neg/toplevel-overload/moredefs_1.scala @@ -0,0 +1,5 @@ +trait B + +def f(x: B) = s"B" // error: has already been compiled + +private def g(): Unit = () // OK, since it is private \ No newline at end of file diff --git a/tests/neg/toplevel-package/defs_1.scala b/tests/neg/toplevel-package/defs_1.scala new file mode 100644 index 000000000000..9e9af2d3adbf --- /dev/null +++ b/tests/neg/toplevel-package/defs_1.scala @@ -0,0 +1,6 @@ +package foo +package bar + class C + def hello(x: String): Unit = + println(s"hello: $x") + diff --git a/tests/neg/toplevel-package/moredefs_2.scala b/tests/neg/toplevel-package/moredefs_2.scala new file mode 100644 index 000000000000..32e3583b3633 --- /dev/null +++ b/tests/neg/toplevel-package/moredefs_2.scala @@ -0,0 +1,2 @@ +package foo +def bar = 2 // error: bar is a package diff --git a/tests/pos/i7650/Test_1.scala b/tests/pos/i7650/Test_1.scala new file mode 100644 index 000000000000..01bc62e8e357 --- /dev/null +++ b/tests/pos/i7650/Test_1.scala @@ -0,0 +1 @@ +@main def Test() = println("hi") \ No newline at end of file diff --git a/tests/pos/i7650/Test_2.scala b/tests/pos/i7650/Test_2.scala new file mode 100644 index 000000000000..00174769a0f0 --- /dev/null +++ b/tests/pos/i7650/Test_2.scala @@ -0,0 +1 @@ +object Test diff --git a/tests/run/toplevel-mixed/B_1.scala b/tests/run/toplevel-mixed/B_1.scala index a27e0c8fde37..de59188c0a83 100644 --- a/tests/run/toplevel-mixed/B_1.scala +++ b/tests/run/toplevel-mixed/B_1.scala @@ -1,7 +1,7 @@ class x(val s: String) -object y { +object yy { def foo = 3 } @@ -9,5 +9,5 @@ object X2 { def bar = "hi" } -class X3 +class X4 diff --git a/tests/run/toplevel-mixed/Test_2.scala b/tests/run/toplevel-mixed/Test_2.scala index 01219321807b..45075ef16a7b 100644 --- a/tests/run/toplevel-mixed/Test_2.scala +++ b/tests/run/toplevel-mixed/Test_2.scala @@ -4,7 +4,7 @@ object Test extends App { assert((new x("abc")).s == "abc") assert(y("abc") == 3) - assert(y.foo == 3) + assert(yy.foo == 3) val x2: X2 = "abc" assert(X2.bar == "hi") diff --git a/tests/run/toplevel-overloads.check b/tests/run/toplevel-overloads.check deleted file mode 100644 index cb9ff070ab31..000000000000 --- a/tests/run/toplevel-overloads.check +++ /dev/null @@ -1,4 +0,0 @@ -hello, Bill -3 -yes -hello, Bob diff --git a/tests/run/toplevel-overloads/Test_2.scala b/tests/run/toplevel-overloads/Test_2.scala deleted file mode 100644 index 8a1beba2b2ff..000000000000 --- a/tests/run/toplevel-overloads/Test_2.scala +++ /dev/null @@ -1,7 +0,0 @@ -import top._ -object Test extends App { - println(hello("Bill")) - println(hello(3)) - println(hello(true)) - println(O.hi) -} \ No newline at end of file diff --git a/tests/run/toplevel-overloads/defs_1.scala b/tests/run/toplevel-overloads/defs_1.scala deleted file mode 100644 index 2efcc72c6475..000000000000 --- a/tests/run/toplevel-overloads/defs_1.scala +++ /dev/null @@ -1,12 +0,0 @@ -package top - -def hello(name: String) = s"hello, $name" -def hello(x: Int) = x.toString - -object O { - def hi = hello("Bob") - def gb = hello(true) -} - -val test1 = top.hello(false) -val test2 = hello(false) diff --git a/tests/run/toplevel-overloads/moredefs_1.scala b/tests/run/toplevel-overloads/moredefs_1.scala deleted file mode 100644 index 78e5b21b0240..000000000000 --- a/tests/run/toplevel-overloads/moredefs_1.scala +++ /dev/null @@ -1,4 +0,0 @@ -package top - -def hello(b: Boolean): String = if (b) "yes" else "no" - diff --git a/tests/run/toplevel-stale/A_1.scala b/tests/run/toplevel-stale/A_1.scala new file mode 100644 index 000000000000..ef762c68dcad --- /dev/null +++ b/tests/run/toplevel-stale/A_1.scala @@ -0,0 +1 @@ +def foo234(x: Int): String = "old" \ No newline at end of file diff --git a/tests/run/toplevel-stale/B_2.scala b/tests/run/toplevel-stale/B_2.scala new file mode 100644 index 000000000000..af42be1e4a7d --- /dev/null +++ b/tests/run/toplevel-stale/B_2.scala @@ -0,0 +1,38 @@ +def foo234(x: Long): String = "new" + +// Giving the compiler something to do so that we won't get +// the same modification date as A_1.scala +import math.Ordering + +val y1 = { + val x1 = summon[Ordering[Int]] + val x2 = summon[Ordering[(Int, Int)]] + val x3 = summon[Ordering[(Int, Int, Int)]] + val x4 = summon[Ordering[(Int, Int, Int, Int)]] + val x5 = summon[Ordering[(Int, Int, Int, Int, Int)]] + val x6 = summon[Ordering[(Int, Int, Int, Int, Int, Int)]] + val x7 = summon[Ordering[(Int, Int, Int, Int, Int, Int, Int)]] + val x8 = summon[Ordering[(Int, Int, Int, Int, Int, Int, Int, Int)]] +} + +val y2 = { + val x1 = summon[Ordering[Int]] + val x2 = summon[Ordering[(Int, Int)]] + val x3 = summon[Ordering[(Int, Int, Int)]] + val x4 = summon[Ordering[(Int, Int, Int, Int)]] + val x5 = summon[Ordering[(Int, Int, Int, Int, Int)]] + val x6 = summon[Ordering[(Int, Int, Int, Int, Int, Int)]] + val x7 = summon[Ordering[(Int, Int, Int, Int, Int, Int, Int)]] + val x8 = summon[Ordering[(Int, Int, Int, Int, Int, Int, Int, Int)]] +} + +val y3 = { + val x1 = summon[Ordering[Int]] + val x2 = summon[Ordering[(Int, Int)]] + val x3 = summon[Ordering[(Int, Int, Int)]] + val x4 = summon[Ordering[(Int, Int, Int, Int)]] + val x5 = summon[Ordering[(Int, Int, Int, Int, Int)]] + val x6 = summon[Ordering[(Int, Int, Int, Int, Int, Int)]] + val x7 = summon[Ordering[(Int, Int, Int, Int, Int, Int, Int)]] + val x8 = summon[Ordering[(Int, Int, Int, Int, Int, Int, Int, Int)]] +} \ No newline at end of file diff --git a/tests/run/toplevel-stale/Test_3.scala b/tests/run/toplevel-stale/Test_3.scala new file mode 100644 index 000000000000..3f6118d2946c --- /dev/null +++ b/tests/run/toplevel-stale/Test_3.scala @@ -0,0 +1,2 @@ +@main def Test() = + assert(foo234(1) == "new")