也许我可以指出代码库中可能相关的几点。
首先,有一种方法可以将 Scala 语言规范 语法直接关联到源代码。比如case classes规则
TmplDef ::= ‘case’ ‘class’ ClassDef
与Parser.tmplDef相关
/** {{{
* TmplDef ::= [case] class ClassDef
* | [case] object ObjectDef
* | [override] trait TraitDef
* }}}
*/
def tmplDef(pos: Offset, mods: Modifiers): Tree = {
...
in.token match {
...
case CASECLASS =>
classDef(pos, (mods | Flags.CASE) withPosition (Flags.CASE, tokenRange(in.prev /*scanner skips on 'case' to 'class', thus take prev*/)))
...
}
}
规范继续
带有类型参数的?[tps](ps1)…(ps?) 的案例类定义
tps 和值参数 ps 暗示了同伴的定义
对象,用作提取器对象。
object ? {
def apply[tps](ps1)…(ps?): ?[tps] = new ?[Ts](xs1)…(xs?)
def unapply[tps](?: ?[tps]) =
if (x eq null) scala.None
else scala.Some(?.xs11,…,?.xs1?)
}
所以让我们试着寻找
的
隐含定义
def apply[tps](ps1)…(ps?): ?[tps] = new ?[Ts](xs1)…(xs?)
这是合成定义的另一种说法。有希望的是,存在MethodSynthesis.scala
/** Logic related to method synthesis which involves cooperation between
* Namer and Typer.
*/
trait MethodSynthesis {
因此我们发现了另外两个潜在的线索Namer 和Typer。我想知道里面有什么?但首先MethodSynthesis.scala 只有大约 300 个 LOC,所以让我们略略看一下。我们偶然发现了promising line
val methDef = factoryMeth(classDef.mods & (AccessFlags | FINAL) | METHOD | IMPLICIT | SYNTHETIC, classDef.name.toTermName, classDef)
"factoryMeth"... 有一个戒指。寻找用途!我们很快被引导到
/** The apply method corresponding to a case class
*/
def caseModuleApplyMeth(cdef: ClassDef): DefDef = {
val inheritedMods = constrMods(cdef)
val mods =
if (applyShouldInheritAccess(inheritedMods))
(caseMods | (inheritedMods.flags & PRIVATE)).copy(privateWithin = inheritedMods.privateWithin)
else
caseMods
factoryMeth(mods, nme.apply, cdef)
}
看来我们走在正确的轨道上。我们还注意到name
nme.apply
这是
val apply: NameType = nameType("apply")
我们急切地发现caseModuleApplyMeth 的用法,我们被虫洞到Namer.addApplyUnapply
/** Given a case class
* case class C[Ts] (ps: Us)
* Add the following methods to toScope:
* 1. if case class is not abstract, add
* <synthetic> <case> def apply[Ts](ps: Us): C[Ts] = new C[Ts](ps)
* 2. add a method
* <synthetic> <case> def unapply[Ts](x: C[Ts]) = <ret-val>
* where <ret-val> is the caseClassUnapplyReturnValue of class C (see UnApplies.scala)
*
* @param cdef is the class definition of the case class
* @param namer is the namer of the module class (the comp. obj)
*/
def addApplyUnapply(cdef: ClassDef, namer: Namer): Unit = {
if (!cdef.symbol.hasAbstractFlag)
namer.enterSyntheticSym(caseModuleApplyMeth(cdef))
val primaryConstructorArity = treeInfo.firstConstructorArgs(cdef.impl.body).size
if (primaryConstructorArity <= MaxTupleArity)
namer.enterSyntheticSym(caseModuleUnapplyMeth(cdef))
}
哇哦!文档说明
<synthetic> <case> def apply[Ts](ps: Us): C[Ts] = new C[Ts](ps)
这似乎与 SLS 版本非常相似
def apply[tps](ps1)…(ps?): ?[tps] = new ?[Ts](xs1)…(xs?)
我们在黑暗中的绊脚石似乎让我们有了一个发现。