aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Applications.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-01-04 10:33:29 +0100
committerMartin Odersky <odersky@gmail.com>2014-01-04 10:33:29 +0100
commiteeab526ef293abdb15d1776e470aca59c4697cfd (patch)
treea14677567bd9d87b37cc4e3f7dd1a4d91bab5707 /src/dotty/tools/dotc/typer/Applications.scala
parent5cff81ca46d771033b9877f510080871cbaebbfc (diff)
downloaddotty-eeab526ef293abdb15d1776e470aca59c4697cfd.tar.gz
dotty-eeab526ef293abdb15d1776e470aca59c4697cfd.tar.bz2
dotty-eeab526ef293abdb15d1776e470aca59c4697cfd.zip
Generalize overloading resolution to type arguments.
We need to take type arguments + value arguments into account when there are several overloaded alternatives that are all polymorphic and can be instantiated with the type arguments.
Diffstat (limited to 'src/dotty/tools/dotc/typer/Applications.scala')
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala64
1 files changed, 40 insertions, 24 deletions
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 5c05b87a0..9a17f5a71 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -336,15 +336,17 @@ trait Applications extends Compatibility { self: Typer =>
init()
}
- /** Subclass of Application for applicability tests with trees as arguments. */
- class ApplicableToTrees(methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context)
- extends TestApplication(methRef, methRef, args, resultType) {
+ /** Subclass of Application for applicability tests with type arguments and value
+ * argument trees.
+ */
+ class ApplicableToTrees(methRef: TermRef, targs: List[Type], args: List[Tree], resultType: Type)(implicit ctx: Context)
+ extends TestApplication(methRef, methRef.widen.appliedTo(targs), args, resultType) {
def argType(arg: Tree, formal: Type): Type = normalize(arg.tpe, formal)
def treeToArg(arg: Tree): Tree = arg
def isVarArg(arg: Tree): Boolean = tpd.isWildcardStarArg(arg)
}
- /** Subclass of Application for applicability tests with types as arguments. */
+ /** Subclass of Application for applicability tests with value argument types. */
class ApplicableToTypes(methRef: TermRef, args: List[Type], resultType: Type)(implicit ctx: Context)
extends TestApplication(methRef, methRef, args, resultType) {
def argType(arg: Type, formal: Type): Type = arg
@@ -527,8 +529,8 @@ trait Applications extends Compatibility { self: Typer =>
}
def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = track("typedTypeApply") {
- val typedFn = typedExpr(tree.fun, PolyProto(tree.args.length, pt))
val typedArgs = tree.args mapconserve (typedType(_))
+ val typedFn = typedExpr(tree.fun, PolyProto(typedArgs.tpes, pt))
val ownType = typedFn.tpe.widen match {
case pt: PolyType =>
checkBounds(typedArgs, pt, tree.pos)
@@ -707,26 +709,40 @@ trait Applications extends Compatibility { self: Typer =>
}
}
- /** Is given method reference applicable to argument trees or types `args`?
+ /** Is given method reference applicable to type arguments `targs` and argument trees `args`?
* @param resultType The expected result type of the application
*/
- def isApplicable[Arg: ClassTag](methRef: TermRef, args: List[Arg], resultType: Type)(implicit ctx: Context): Boolean = {
+ def isApplicable(methRef: TermRef, targs: List[Type], args: List[Tree], resultType: Type)(implicit ctx: Context): Boolean = {
val nestedContext = ctx.fresh.withExploreTyperState
- if (implicitly[ClassTag[Arg]].runtimeClass == classOf[Trees.Tree[_]])
- new ApplicableToTrees(methRef, args.asInstanceOf[List[Tree]], resultType)(nestedContext).success
- else
- new ApplicableToTypes(methRef, args.asInstanceOf[List[Type]], resultType)(nestedContext).success
+ new ApplicableToTrees(methRef, targs, args, resultType)(nestedContext).success
}
- /** Is given type applicable to argument trees `args`, possibly after inserting an `apply`?
+ /** Is given method reference applicable to argument types `args`?
* @param resultType The expected result type of the application
*/
- def isApplicable[Arg: ClassTag](tp: Type, args: List[Arg], resultType: Type)(implicit ctx: Context): Boolean = tp match {
+ def isApplicable(methRef: TermRef, args: List[Type], resultType: Type)(implicit ctx: Context): Boolean = {
+ val nestedContext = ctx.fresh.withExploreTyperState
+ new ApplicableToTypes(methRef, args, resultType)(nestedContext).success
+ }
+
+ /** Is given type applicable to type arguments `targs` and argument trees `args`,
+ * possibly after inserting an `apply`?
+ * @param resultType The expected result type of the application
+ */
+ def isApplicable(tp: Type, targs: List[Type], args: List[Tree], resultType: Type)(implicit ctx: Context): Boolean =
+ onMethod(tp, isApplicable(_, targs, args, resultType))
+
+ /** Is given type applicable to argument types `args`, possibly after inserting an `apply`?
+ * @param resultType The expected result type of the application
+ */
+ def isApplicable(tp: Type, args: List[Type], resultType: Type)(implicit ctx: Context): Boolean =
+ onMethod(tp, isApplicable(_, args, resultType))
+
+ private def onMethod(tp: Type, p: TermRef => Boolean)(implicit ctx: Context): Boolean = tp match {
case methRef: TermRef if methRef.widenSingleton.isInstanceOf[SignedType] =>
- isApplicable(methRef, args, resultType)
+ p(methRef)
case _ =>
- val app = tp.member(nme.apply)
- app.exists && app.hasAltWith(d => isApplicable(TermRef(tp, nme.apply, d), args, resultType))
+ tp.member(nme.apply).hasAltWith(d => p(TermRef(tp, nme.apply, d)))
}
/** In a set of overloaded applicable alternatives, is `alt1` at least as good as
@@ -813,10 +829,12 @@ trait Applications extends Compatibility { self: Typer =>
}
}
- /** Resolve overloaded alternative `alts`, given expected type `pt`.
+ /** Resolve overloaded alternative `alts`, given expected type `pt` and
+ * possibly also type argument `targs` that need to be applied to each alternative
+ * to form the method type.
* todo: use techniques like for implicits to pick candidates quickly?
*/
- def resolveOverloaded(alts: List[TermRef], pt: Type)(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") {
+ def resolveOverloaded(alts: List[TermRef], pt: Type, targs: List[Type] = Nil)(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") {
def isDetermined(alts: List[TermRef]) = alts.isEmpty || alts.tail.isEmpty
@@ -873,7 +891,7 @@ trait Applications extends Compatibility { self: Typer =>
alts
def narrowByTrees(alts: List[TermRef], args: List[Tree], resultType: Type): List[TermRef] =
- alts filter (isApplicable(_, args, resultType))
+ alts filter (isApplicable(_, targs, args, resultType))
val alts1 = narrowBySize(alts)
if (isDetermined(alts1)) alts1
@@ -883,11 +901,9 @@ trait Applications extends Compatibility { self: Typer =>
else narrowByTrees(alts2, pt.typedArgs, resultType)
}
- case pt @ PolyProto(nargs, _) =>
- alts filter (alt => alt.widen match {
- case PolyType(pnames) if pnames.length == nargs => true
- case _ => false
- })
+ case pt @ PolyProto(targs, pt1) =>
+ val alts1 = alts filter pt.isMatchedBy
+ resolveOverloaded(alts1, pt1, targs)
case defn.FunctionType(args, resultType) =>
narrowByTypes(alts, args, resultType)