diff options
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 8 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Inferencing.scala | 16 |
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 } |