aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty/tools/dotc/typer')
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala99
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala2
2 files changed, 54 insertions, 47 deletions
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index c162abd5f..ec516c56c 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -966,6 +966,53 @@ trait Applications extends Compatibility { self: Typer =>
def narrowByTypes(alts: List[TermRef], argTypes: List[Type], resultType: Type): List[TermRef] =
alts filter (isApplicable(_, argTypes, resultType))
+ /** Is `alt` a method or polytype whose result type after the first value parameter
+ * section conforms to the expected type `resultType`? If `resultType`
+ * is a `IgnoredProto`, pick the underlying type instead.
+ */
+ def resultConforms(alt: Type, resultType: Type)(implicit ctx: Context): Boolean = resultType match {
+ case IgnoredProto(ignored) => resultConforms(alt, ignored)
+ case _: ValueType =>
+ alt.widen match {
+ case tp: PolyType => resultConforms(constrained(tp).resultType, resultType)
+ case tp: MethodType => constrainResult(tp.resultType, resultType)
+ case _ => true
+ }
+ case _ => true
+ }
+
+ /** If the `chosen` alternative has a result type incompatible with the expected result
+ * type `pt`, run overloading resolution again on all alternatives that do match `pt`.
+ * If the latter succeeds with a single alternative, return it, otherwise
+ * fallback to `chosen`.
+ *
+ * Note this order of events is done for speed. One might be tempted to
+ * preselect alternatives by result type. But is slower, because it discriminates
+ * less. The idea is when searching for a best solution, as is the case in overloading
+ * resolution, we should first try criteria which are cheap and which have a high
+ * probability of pruning the search. result type comparisons are neither cheap nor
+ * do they prune much, on average.
+ */
+ def adaptByResult(alts: List[TermRef], chosen: TermRef) =
+ if (ctx.isAfterTyper) chosen
+ else {
+ def nestedCtx = ctx.fresh.setExploreTyperState
+ pt match {
+ case pt: FunProto if !resultConforms(chosen, pt.resultType)(nestedCtx) =>
+ alts.filter(alt =>
+ (alt ne chosen) && resultConforms(alt, pt.resultType)(nestedCtx)) match {
+ case Nil => chosen
+ case alt2 :: Nil => alt2
+ case alts2 =>
+ resolveOverloaded(alts2, pt) match {
+ case alt2 :: Nil => alt2
+ case _ => chosen
+ }
+ }
+ case _ => chosen
+ }
+ }
+
val candidates = pt match {
case pt @ FunProto(args, resultType, _) =>
val numArgs = args.length
@@ -1029,56 +1076,16 @@ trait Applications extends Compatibility { self: Typer =>
}
if (isDetermined(candidates)) candidates
else narrowMostSpecific(candidates) match {
- case result @ (alt1 :: alt2 :: _) =>
-// overload.println(i"ambiguous $alt1 $alt2")
+ case Nil => Nil
+ case alt :: Nil => adaptByResult(candidates, alt) :: Nil
+ case alts =>
+// overload.println(i"ambiguous $alts%, %")
val deepPt = pt.deepenProto
- if (deepPt ne pt) resolveOverloaded(alts, deepPt, targs)
- else result
- case result =>
- result
+ if (deepPt ne pt) resolveOverloaded(candidates, deepPt, targs)
+ else alts
}
}
- /** If the `chosen` alternative has a result type incompatible with the expected result
- * type `pt`, run overloading resolution again on all alternatives that do match `pt`.
- * If the latter succeeds with a single alternative, return it, otherwise
- * fallback to `chosen`.
- */
- def adaptByResult(alts: List[TermRef], chosen: TermRef, pt: Type)(implicit ctx: Context) =
- if (ctx.isAfterTyper) chosen
- else {
- def nestedCtx = ctx.fresh.setExploreTyperState
- pt match {
- case pt: FunProto if !resultConforms(chosen, pt.resultType)(nestedCtx) =>
- alts.filter(alt =>
- (alt ne chosen) && resultConforms(alt, pt.resultType)(nestedCtx)) match {
- case Nil => chosen
- case alt2 :: Nil => alt2
- case alts2 =>
- resolveOverloaded(alts2, pt) match {
- case alt2 :: Nil => alt2
- case _ => chosen
- }
- }
- case _ => chosen
- }
- }
-
- /** Is `alt` a method or polytype whose result type after the first value parameter
- * section conforms to the expected type `resultType`? If `resultType`
- * is a `IgnoredProto`, pick the underlying type instead.
- */
- private def resultConforms(alt: Type, resultType: Type)(implicit ctx: Context): Boolean = resultType match {
- case IgnoredProto(ignored) => resultConforms(alt, ignored)
- case _: ValueType =>
- alt.widen match {
- case tp: PolyType => resultConforms(constrained(tp).resultType, resultType)
- case tp: MethodType => constrainResult(tp.resultType, resultType)
- case _ => true
- }
- case _ => true
- }
-
private def harmonizeWith[T <: AnyRef](ts: List[T])(tpe: T => Type, adapt: (T, Type) => T)(implicit ctx: Context): List[T] = {
def numericClasses(ts: List[T], acc: Set[Symbol]): Set[Symbol] = ts match {
case t :: ts1 =>
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index ce0a181c3..2bdd0d197 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -1238,7 +1238,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def expectedStr = err.expectedTypeStr(pt)
resolveOverloaded(alts, pt) match {
case alt :: Nil =>
- adapt(tree.withType(adaptByResult(alts, alt, pt)), pt, original)
+ adapt(tree.withType(alt), pt, original)
case Nil =>
def noMatches =
errorTree(tree,