-
Notifications
You must be signed in to change notification settings - Fork 1.1k
use methods to find companion class #436
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
Changes from 8 commits
13a05d5
d01ecb7
25af814
7baead9
880a6f5
5e09d2d
f40c498
0a94d6e
7021570
f2221d0
595c3f6
f9910eb
57027f7
b653007
cdbe81e
042c2f0
84602a3
e907c78
fdc92a6
14e0f72
34f1650
c560648
e5618d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -361,9 +361,11 @@ object desugar { | |
} | ||
companionDefs(parent, applyMeths ::: unapplyMeth :: defaultGetters) | ||
} | ||
else if (defaultGetters.nonEmpty) | ||
companionDefs(anyRef, defaultGetters) | ||
else Nil | ||
else { | ||
if (defaultGetters.nonEmpty) | ||
companionDefs(anyRef, defaultGetters) | ||
else Nil | ||
} | ||
|
||
// For an implicit class C[Ts](p11: T11, ..., p1N: T1N) ... (pM1: TM1, .., pMN: TMN), the method | ||
// synthetic implicit C[Ts](p11: T11, ..., p1N: T1N) ... (pM1: TM1, ..., pMN: TMN): C[Ts] = | ||
|
@@ -409,6 +411,8 @@ object desugar { | |
flatTree(cdef1 :: companions ::: implicitWrappers) | ||
} | ||
|
||
val AccessOrSynthetic = AccessFlags | Synthetic | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rename to SyntheticAccessor. When you set mods, its not an Or. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not setting them, I'm using this value to mask previous mods. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I misread. Consider the comment withdrawn. |
||
|
||
/** Expand | ||
* | ||
* object name extends parents { self => body } | ||
|
@@ -436,7 +440,7 @@ object desugar { | |
.withPos(tmpl.self.pos orElse tmpl.pos.startPos) | ||
val clsTmpl = cpy.Template(tmpl)(self = clsSelf, body = tmpl.body) | ||
val cls = TypeDef(clsName, clsTmpl) | ||
.withMods(mods.toTypeFlags & AccessFlags | ModuleClassCreationFlags) | ||
.withMods(mods.toTypeFlags & AccessOrSynthetic | ModuleClassCreationFlags) | ||
Thicket(modul, classDef(cls)) | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -83,8 +83,8 @@ object StdNames { | |
final val HASHkw: N = kw("#") | ||
final val ATkw: N = kw("@") | ||
|
||
val ANON_CLASS: N = "$anon" | ||
val ANON_FUN: N = "$anonfun" | ||
val ANON_CLASS: N = "$anon" | ||
val ANON_FUN: N = "$anonfun" | ||
val BITMAP_PREFIX: N = "bitmap$" | ||
val BITMAP_NORMAL: N = BITMAP_PREFIX // initialization bitmap for public/protected lazy vals | ||
val BITMAP_TRANSIENT: N = BITMAP_PREFIX + "trans$" // initialization bitmap for transient lazy vals | ||
|
@@ -117,13 +117,15 @@ object StdNames { | |
val PROTECTED_PREFIX: N = "protected$" | ||
val PROTECTED_SET_PREFIX: N = PROTECTED_PREFIX + "set" | ||
val ROOT: N = "<root>" | ||
val SHADOWED: N = "(shadowed)" // tag to be used until we have proper name kinds | ||
val SHADOWED: N = "(shadowed)" // tag to be used until we have proper name kinds | ||
val SINGLETON_SUFFIX: N = ".type" | ||
val SPECIALIZED_SUFFIX: N = "$sp" | ||
val SUPER_PREFIX: N = "super$" | ||
val WHILE_PREFIX: N = "while$" | ||
val DEFAULT_EXCEPTION_NAME: N = "ex$" | ||
val INITIALIZER_PREFIX: N = "initial$" | ||
val COMPANION_MODULE_METHOD: N = "companion$module" | ||
val COMPANION_CLASS_METHOD: N = "compaion$class" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo, should be "companion$class" |
||
|
||
// value types (and AnyRef) are all used as terms as well | ||
// as (at least) arguments to the @specialize annotation. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -773,11 +773,31 @@ object SymDenotations { | |
companionNamed(effectiveName.moduleClassName).sourceModule | ||
|
||
/** The class with the same (type-) name as this module or module class, | ||
* and which is also defined in the same scope and compilation unit. | ||
* NoSymbol if this class does not exist. | ||
*/ | ||
final def companionClass(implicit ctx: Context): Symbol = | ||
companionNamed(effectiveName.toTypeName) | ||
* and which is also defined in the same scope and compilation unit. | ||
* NoSymbol if this class does not exist. | ||
*/ | ||
final def companionClass(implicit ctx: Context): Symbol = { | ||
val companionMethod = info.decls.denotsNamed(nme.COMPANION_CLASS_METHOD, selectPrivate).first | ||
|
||
if (companionMethod.exists) | ||
companionMethod.info.resultType.classSymbol | ||
else { | ||
/* | ||
val scalac = companionNamed(effectiveName.toTypeName) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the commented out code still needed? If not, delete as well as the enclosing {...} |
||
if (scalac.exists) { | ||
println(s"scalac returned companion class for $this to be $scalac") | ||
} | ||
*/ | ||
NoSymbol | ||
} | ||
} | ||
|
||
final def scalacLinkedClass(implicit ctx: Context): Symbol = | ||
if (this is ModuleClass) companionNamed(effectiveName.toTypeName) | ||
else if (this.isClass) companionModule.moduleClass | ||
else NoSymbol | ||
|
||
|
||
/** Find companion class symbol with given name, or NoSymbol if none exists. | ||
* Three alternative strategies: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -161,6 +161,15 @@ trait Symbols { this: Context => | |
owner.thisType, modcls, parents, decls, TermRef.withSymAndName(owner.thisType, module, name)), | ||
privateWithin, coord, assocFile) | ||
|
||
def synthesizeCompanionMethod(name: TermName, ret: SymDenotation, owner: SymDenotation)(implicit ctx: Context) = { | ||
if(owner.exists && ret.exists) ctx.newSymbol( | ||
owner = owner.symbol, | ||
name = name, | ||
flags = Flags.Synthetic | Flags.Private, | ||
info = ExprType(ret.typeRef)) | ||
else NoSymbol | ||
} | ||
|
||
/** Create a package symbol with associated package class | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'd reformulate as follows:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Defining method name based on flags doesn't work here: in order to not force type you will need |
||
* from its non-info fields and a lazy type for loading the package's members. | ||
*/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -118,6 +118,13 @@ object UnPickler { | |
denot.owner.thisType select denot.sourceModule | ||
else selfInfo | ||
if (!(denot.flagsUNSAFE is JavaModule)) ensureConstructor(denot.symbol.asClass, decls) | ||
if (denot.flagsUNSAFE is Module) { | ||
val scalacCompanion = denot.classSymbol.scalacLinkedClass | ||
val companionClassMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, scalacCompanion, denot.classSymbol) | ||
if (companionClassMethod.exists) | ||
companionClassMethod.entered | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a pity that we still need scalacLinkedClass here, because it means we cannot get rid of the associated complexity of isCoDefinedWith. I would much prefer if we got the linked class directly from the unpickling info, instead of looking at |
||
denot.info = ClassInfo(denot.owner.thisType, denot.classSymbol, parentRefs, decls, ost) | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -395,32 +395,64 @@ class Namer { typer: Typer => | |
/** Create top-level symbols for statements and enter them into symbol table */ | ||
def index(stats: List[Tree])(implicit ctx: Context): Context = { | ||
|
||
val classDef = mutable.Map[TypeName, TypeDef]() | ||
val moduleDef = mutable.Map[TypeName, TypeDef]() | ||
|
||
/** Merge the definitions of a synthetic companion generated by a case class | ||
* and the real companion, if both exist. | ||
*/ | ||
def mergeCompanionDefs() = { | ||
val classDef = mutable.Map[TypeName, TypeDef]() | ||
for (cdef @ TypeDef(name, _) <- stats) | ||
if (cdef.isClassDef) classDef(name) = cdef | ||
for (mdef @ ModuleDef(name, _) <- stats) | ||
if (cdef.isClassDef) { | ||
classDef(name) = cdef | ||
cdef.attachmentOrElse(ExpandedTree, cdef) match { | ||
case Thicket(cls :: mval :: (mcls @ TypeDef(_, _: Template)) :: crest) => | ||
moduleDef(name) = mcls | ||
case _ => | ||
} | ||
} | ||
for (mdef @ ModuleDef(name, _) <- stats if !mdef.mods.is(Flags.Package)) { | ||
val typName = name.toTypeName | ||
val Thicket(vdef :: (mcls @ TypeDef(_, impl: Template)) :: Nil) = mdef.attachment(ExpandedTree) | ||
moduleDef(typName) = mcls | ||
classDef get name.toTypeName match { | ||
case Some(cdef) => | ||
val Thicket(vdef :: (mcls @ TypeDef(_, impl: Template)) :: Nil) = mdef.attachment(ExpandedTree) | ||
cdef.attachmentOrElse(ExpandedTree, cdef) match { | ||
case Thicket(cls :: mval :: TypeDef(_, compimpl: Template) :: crest) => | ||
val mcls1 = cpy.TypeDef(mcls)( | ||
rhs = cpy.Template(impl)(body = compimpl.body ++ impl.body)) | ||
mdef.putAttachment(ExpandedTree, Thicket(vdef :: mcls1 :: Nil)) | ||
moduleDef(typName) = mcls1 | ||
cdef.putAttachment(ExpandedTree, Thicket(cls :: crest)) | ||
case _ => | ||
} | ||
case none => | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is a bit on the complex side, in particuar I do not like the repetition of the complicated Thicket pattern matches. Can we experiment with having 4 Maps:
Using these we could streamline the traversal of ModuleDefs. See what I mean? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should those maps be directly updated by desugar or you'll still use attachments? |
||
|
||
def createLinks(classTree: TypeDef, moduleTree: TypeDef)(implicit ctx: Context) = { | ||
val claz = ctx.denotNamed(classTree.name.encode).symbol | ||
val modl = ctx.denotNamed(moduleTree.name.encode).symbol | ||
ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, claz, modl).entered | ||
ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, modl, claz).entered | ||
} | ||
|
||
def createCompanionLinks(implicit ctx: Context): Unit = { | ||
for (cdef @ TypeDef(name, _) <- classDef.values) { | ||
moduleDef.getOrElse(name, EmptyTree) match { | ||
case t: TypeDef => | ||
createLinks(cdef, t) | ||
case EmptyTree => | ||
} | ||
} | ||
} | ||
|
||
stats foreach expand | ||
mergeCompanionDefs() | ||
(ctx /: stats) ((ctx, stat) => indexExpanded(stat)(ctx)) | ||
val ctxWithStats = (ctx /: stats) ((ctx, stat) => indexExpanded(stat)(ctx)) | ||
createCompanionLinks(ctxWithStats) | ||
ctxWithStats | ||
} | ||
|
||
/** The completer of a symbol defined by a member def or import (except ClassSymbols) */ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,7 +149,7 @@ class tests extends CompilerTest { | |
|
||
@Test def dotc_printing = compileDir(dotcDir + "tools/dotc/printing") | ||
|
||
@Test def dotc_reporting = compileDir(dotcDir + "tools/dotc/reporting", twice) | ||
@Test def dotc_reporting = compileDir(dotcDir + "tools/dotc/reporting") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why was the twice removed here? |
||
|
||
@Test def dotc_typer = compileDir(dotcDir + "tools/dotc/typer", failedOther) | ||
// error: error while loading Checking$$anon$2$, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the change in formatting? I liked the old one better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code was rewritten, it used to have more complicated logic between the commits. I have no problem changing it back.