aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-12-21 19:32:19 +0100
committerMartin Odersky <odersky@gmail.com>2013-12-21 19:36:02 +0100
commitbdb19a8ef9cf7caf108d9326108dc51a6b76cc15 (patch)
treeaafade2361c6a151a8105104300bd773bfc2c91f
parentedf00802ff454e6bdbe5526151cf14c68811932a (diff)
downloaddotty-bdb19a8ef9cf7caf108d9326108dc51a6b76cc15.tar.gz
dotty-bdb19a8ef9cf7caf108d9326108dc51a6b76cc15.tar.bz2
dotty-bdb19a8ef9cf7caf108d9326108dc51a6b76cc15.zip
Adding () insertion to normalization.
We need to take account of the possibility of inserting a () argument list in normalization. Otherwise, a type with a def toString(): String member would not count as a valid solution for ?{toString: String}. This would then lead to an implicit insertion, with a nice explosion of inference search because of course every implicit result has some sort of toString method. The problem is solved by dereferencing nullary method types if the corresponding function type is not compatible with the prototype.
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala8
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala16
2 files changed, 18 insertions, 6 deletions
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 08987a095..860a7be80 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -315,11 +315,11 @@ trait Applications extends Compatibility { self: Typer =>
type Result = Unit
/** The type of the given argument */
- protected def argType(arg: Arg): Type
+ protected def argType(arg: Arg, formal: Type): Type
def typedArg(arg: Arg, formal: Type): Arg = arg
def addArg(arg: TypedArg, formal: Type) =
- ok = ok & isCompatible(argType(arg), formal)
+ ok = ok & isCompatible(argType(arg, formal), formal)
def makeVarArg(n: Int, elemFormal: Type) = {}
def fail(msg: => String, arg: Arg) =
ok = false
@@ -333,7 +333,7 @@ trait Applications extends Compatibility { self: Typer =>
/** 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) {
- def argType(arg: Tree): Type = normalize(arg.tpe, NoType)
+ 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)
}
@@ -341,7 +341,7 @@ trait Applications extends Compatibility { self: Typer =>
/** Subclass of Application for applicability tests with types as arguments. */
class ApplicableToTypes(methRef: TermRef, args: List[Type], resultType: Type)(implicit ctx: Context)
extends TestApplication(methRef, methRef, args, resultType) {
- def argType(arg: Type): Type = arg
+ def argType(arg: Type, formal: Type): Type = arg
def treeToArg(arg: Tree): Type = arg.tpe
def isVarArg(arg: Type): Boolean = arg.isRepeatedParam
}
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index 92467c0e2..124f43391 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -32,7 +32,7 @@ object Inferencing {
def isCompatible(tp: Type, pt: Type)(implicit ctx: Context): Boolean =
tp.widenByName <:< pt.widenByName || viewExists(tp, pt)
- /** Test compatibility after normalization in a fresh typerstate */
+ /** Test compatibility after normalization in a fresh typerstate. */
def normalizedCompatible(tp: Type, pt: Type)(implicit ctx: Context) = {
val nestedCtx = ctx.fresh.withExploreTyperState
isCompatible(normalize(tp, pt)(nestedCtx), pt)(nestedCtx)
@@ -164,13 +164,25 @@ object Inferencing {
* - skips implicit parameters
* - converts non-dependent method types to the corresponding function types
* - dereferences parameterless method types
+ * - dereferences nullary method types provided the corresponding function type
+ * is not a subtype of the expected type.
+ * Note: We need to take account of the possibility of inserting a () argument list in normalization. Otherwise, a type with a
+ * def toString(): String
+ * member would not count as a valid solution for ?{toString: String}. This would then lead to an implicit
+ * insertion, with a nice explosion of inference search because of course every implicit result has some sort
+ * of toString method. The problem is solved by dereferencing nullary method types if the corresponding
+ * function type is not compatible with the prototype.
*/
def normalize(tp: Type, pt: Type)(implicit ctx: Context): Type = Stats.track("normalize") {
tp.widenSingleton match {
case pt: PolyType => normalize(constrained(pt).resultType, pt)
case mt: MethodType if !mt.isDependent /*&& !pt.isInstanceOf[ApplyingProto]*/ =>
if (mt.isImplicit) mt.resultType
- else defn.FunctionType(mt.paramTypes, normalize(mt.resultType, pt))
+ else {
+ val rt = normalize(mt.resultType, pt)
+ val ft = defn.FunctionType(mt.paramTypes, rt)
+ if (mt.paramTypes.nonEmpty || ft <:< pt) ft else rt
+ }
case et: ExprType => et.resultType
case _ => tp
}