From 14b539e23c476e8025404666d933d9cc78d2b300 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 18 Sep 2014 17:36:12 +0200 Subject: Take receiver into account when selecting default getters. Previously, we determined the default getters solely from the method TermRef type. This is wrong if the method is prefix is not a path -- the prefix of the term ref will be a TypeRef and the getter selection will be a SelectFromType tree, which makes no sense. --- src/dotty/tools/dotc/typer/Applications.scala | 96 +++++++++++++++------------ 1 file changed, 53 insertions(+), 43 deletions(-) (limited to 'src/dotty/tools/dotc/typer') diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 77298e610..035f19028 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -132,8 +132,7 @@ trait Applications extends Compatibility { self: Typer => protected def appPos: Position - /** If constructing trees, the current function part, which might be - * affected by lifting. EmptyTree otherwise. + /** The current function part, which might be affected by lifting. */ protected def normalizedFun: Tree @@ -251,40 +250,52 @@ trait Applications extends Compatibility { self: Typer => /** Find reference to default parameter getter for parameter #n in current * parameter list, or NoType if none was found */ - def findDefaultGetter(n: Int)(implicit ctx: Context): Type = { - val meth = methRef.symbol - val prefix = - if ((meth is Synthetic) && meth.name == nme.apply) nme.CONSTRUCTOR else methRef.name - def getterName = prefix.defaultGetterName(n) - def ref(pre: Type, sym: Symbol): Type = - if (pre.exists && sym.isTerm) pre select sym else NoType - if (meth.hasDefaultParams) - methRef.prefix match { - case NoPrefix => - def findDefault(cx: Context): Type = { - if (cx eq NoContext) NoType - else if (cx.scope != cx.outer.scope && - cx.denotNamed(methRef.name).hasAltWith(_.symbol == meth)) { - val denot = cx.denotNamed(getterName) - assert(denot.exists, s"non-existent getter denotation ($denot) for getter($getterName)") - cx.owner.thisType.select(getterName, denot) - } else findDefault(cx.outer) - } - findDefault(ctx) - case mpre => - val cls = meth.owner - val pre = - if (meth.isClassConstructor) { - // default getters for class constructors are found in the companion object - mpre.baseTypeRef(cls) match { - case tp: TypeRef => ref(tp.prefix, cls.companionModule) - case _ => NoType - } - } else mpre - val getter = pre.member(getterName) - ref(pre, getter.symbol) + def findDefaultGetter(n: Int)(implicit ctx: Context): Tree = { + val meth = methRef.symbol.asTerm + val receiver: Tree = methPart(normalizedFun) match { + case Select(receiver, _) => receiver + case mr => mr.tpe.normalizedPrefix match { + case mr: TermRef => ref(mr) + case _ => EmptyTree + } + } + val getterPrefix = + if ((meth is Synthetic) && meth.name == nme.apply) nme.CONSTRUCTOR else meth.name + def getterName = getterPrefix.defaultGetterName(n) + if (!meth.hasDefaultParams) + EmptyTree + else if (receiver.isEmpty) { + def findGetter(cx: Context): Tree = { + if (cx eq NoContext) EmptyTree + else if (cx.scope != cx.outer.scope && + cx.denotNamed(meth.name).hasAltWith(_.symbol == meth)) { + val denot = cx.denotNamed(getterName) + assert(denot.exists, s"non-existent getter denotation ($denot) for getter($getterName)") + ref(TermRef(cx.owner.thisType, getterName, denot)) + } else findGetter(cx.outer) + } + findGetter(ctx) + } + else { + def selectGetter(qual: Tree): Tree = { + val getterDenot = qual.tpe.member(getterName) + if (getterDenot.exists) qual.select(TermRef(qual.tpe, getterName, getterDenot)) + else EmptyTree + } + if (!meth.isClassConstructor) + selectGetter(receiver) + else { + // default getters for class constructors are found in the companion object + val cls = meth.owner + val companion = cls.companionModule + receiver.tpe.baseTypeRef(cls) match { + case tp: TypeRef if companion.isTerm => + selectGetter(ref(TermRef(tp.prefix, companion.asTerm))) + case _ => + EmptyTree + } } - else NoType + } } /** Match re-ordered arguments against formal parameters @@ -305,13 +316,12 @@ trait Applications extends Compatibility { self: Typer => } def tryDefault(n: Int, args1: List[Arg]): Unit = { - findDefaultGetter(n + numArgs(normalizedFun)) match { - case dref: NamedType => - liftFun() - addTyped(treeToArg(spliceMeth(ref(dref) withPos appPos, normalizedFun)), formal) - matchArgs(args1, formals1, n + 1) - case _ => - missingArg(n) + liftFun() + val getter = findDefaultGetter(n + numArgs(normalizedFun)) + if (getter.isEmpty) missingArg(n) + else { + addTyped(treeToArg(spliceMeth(getter withPos appPos, normalizedFun)), formal) + matchArgs(args1, formals1, n + 1) } } @@ -364,7 +374,7 @@ trait Applications extends Compatibility { self: Typer => def fail(msg: => String) = ok = false def appPos = NoPosition - def normalizedFun = EmptyTree + lazy val normalizedFun = ref(methRef) init() } -- cgit v1.2.3