diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index dab84bb5f69c..47342cb56d33 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -161,12 +161,14 @@ trait Symbols { this: Context => owner.thisType, modcls, parents, decls, TermRef.withSymAndName(owner.thisType, module, name)), privateWithin, coord, assocFile) + val companionMethodFlags = Flags.Synthetic | Flags.Private | Flags.Method + def synthesizeCompanionMethod(name: Name, target: SymDenotation, owner: SymDenotation)(implicit ctx: Context) = if (owner.exists && target.exists && !owner.isAbsent && !target.isAbsent) { val existing = owner.unforcedDecls.lookup(name) existing.orElse{ - ctx.newSymbol(owner.symbol, name, Flags.Synthetic | Flags.Private, ExprType(target.typeRef)) + ctx.newSymbol(owner.symbol, name, companionMethodFlags , ExprType(target.typeRef)) } } else NoSymbol diff --git a/src/dotty/tools/dotc/transform/RestoreScopes.scala b/src/dotty/tools/dotc/transform/RestoreScopes.scala index 3a168b1fe52d..fe24186acc90 100644 --- a/src/dotty/tools/dotc/transform/RestoreScopes.scala +++ b/src/dotty/tools/dotc/transform/RestoreScopes.scala @@ -13,6 +13,7 @@ import ast.Trees._ import NameOps._ import typer.Mode import TreeTransforms.TransformerInfo +import StdNames._ /** The preceding lambda lift and flatten phases move symbols to different scopes * and rename them. This miniphase cleans up afterwards and makes sure that all @@ -33,6 +34,19 @@ class RestoreScopes extends MiniPhaseTransform with IdentityDenotTransformer { t // For top-level classes this does nothing. val cls = tree.symbol.asClass val pkg = cls.owner.asClass + + // Bring back companion links + val companionClass = cls.info.decls.lookup(nme.COMPANION_CLASS_METHOD) + val companionModule = cls.info.decls.lookup(nme.COMPANION_MODULE_METHOD) + + if (companionClass.exists) { + restoredDecls.enter(companionClass) + } + + if (companionModule.exists) { + restoredDecls.enter(companionModule) + } + pkg.enter(cls) val cinfo = cls.classInfo tree.symbol.copySymDenotation( diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index 43e1ce8a6853..1661f7576a55 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -56,6 +56,18 @@ class TreeChecker extends Phase with SymTransformer { registry(name) = sym } + def checkCompanion(symd: SymDenotation)(implicit ctx: Context): Unit = { + val cur = symd.linkedClass + val prev = ctx.atPhase(ctx.phase.prev) { + ct => { + implicit val ctx: Context = ct.withMode(Mode.FutureDefsOK) + symd.symbol.linkedClass + } + } + + if (prev.exists) + assert(cur.exists, i"companion disappeared from $symd") + } def transformSym(symd: SymDenotation)(implicit ctx: Context): SymDenotation = { val sym = symd.symbol @@ -69,6 +81,8 @@ class TreeChecker extends Phase with SymTransformer { testDuplicate(sym, seenClasses, "class") } + checkCompanion(symd) + symd } diff --git a/src/dotty/tools/dotc/transform/ValueClasses.scala b/src/dotty/tools/dotc/transform/ValueClasses.scala index ab4bba94ea53..a7a0db97c5d3 100644 --- a/src/dotty/tools/dotc/transform/ValueClasses.scala +++ b/src/dotty/tools/dotc/transform/ValueClasses.scala @@ -7,6 +7,7 @@ import Symbols._ import SymDenotations._ import Contexts._ import Flags._ +import StdNames._ /** Methods that apply to user-defined value classes */ object ValueClasses { @@ -22,7 +23,8 @@ object ValueClasses { isDerivedValueClass(d.owner) && !d.isConstructor && !d.is(SuperAccessor) && - !d.is(Macro) + !d.is(Macro) && + !(d.name eq nme.COMPANION_MODULE_METHOD) /** The member that of a derived value class that unboxes it. */ def valueClassUnbox(d: ClassDenotation)(implicit ctx: Context): Symbol =