From 48ed5d74a713210c0d3e6846afeb815cc75231dc Mon Sep 17 00:00:00 2001 From: Anatolii Date: Wed, 19 Feb 2020 17:16:22 +0100 Subject: [PATCH] Fix #7793: Account for context params preceding normal ones in overloading --- .../dotty/tools/dotc/typer/Applications.scala | 52 ++++++++++++++----- tests/pos/i7793.scala | 9 ++++ 2 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 tests/pos/i7793.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 92d19d12a78b..922c9ae541d1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -339,7 +339,7 @@ trait Applications extends Compatibility { else args - protected def init(): Unit = methType match { + protected def initWith(mt: Type): Unit = mt match { case methType: MethodType => // apply the result type constraint, unless method type is dependent val resultApprox = resultTypeApprox(methType) @@ -358,6 +358,28 @@ trait Applications extends Compatibility { else fail(s"$methString does not take parameters") } + protected def reset(): Unit = + ok = true + + /** + * This function tests whether a given method is applicable to the + * given arguments. Context parameters that precede the normal parameters + * pose problems for such a test. E.g.: + + * def f(using String)(g: Int => String): Int + * f(x => "2") + * f(using summon[String])(x => "2") + + * At the first call site, the context parameter is omitted. For the + * applicability test to pass in that case, we should also test + * the function `f` with its context parameters dropped. + */ + protected def init(): Unit = + initWith(methType) + if !success then + reset() + initWith(stripImplicit(methType)) + /** The application was successful */ def success: Boolean = ok @@ -688,6 +710,12 @@ trait Applications extends Compatibility { private var typedArgBuf = new mutable.ListBuffer[Tree] private var liftedDefs: mutable.ListBuffer[Tree] = null private var myNormalizedFun: Tree = fun + override protected def reset(): Unit = + super.reset() + typedArgBuf = new mutable.ListBuffer[Tree] + liftedDefs = null + myNormalizedFun = fun + init() def addArg(arg: Tree, formal: Type): Unit = @@ -1299,6 +1327,16 @@ trait Applications extends Compatibility { } } + /** Drop any implicit parameter section */ + def stripImplicit(tp: Type)(using Context): Type = tp match { + case mt: MethodType if mt.isImplicitMethod => + stripImplicit(resultTypeApprox(mt)) + case pt: PolyType => + pt.derivedLambdaType(pt.paramNames, pt.paramInfos, stripImplicit(pt.resultType)) + case _ => + tp + } + /** Compare owner inheritance level. * @param sym1 The first owner * @param sym2 The second owner @@ -1466,16 +1504,6 @@ trait Applications extends Compatibility { else tp } - /** Drop any implicit parameter section */ - def stripImplicit(tp: Type): Type = tp match { - case mt: MethodType if mt.isImplicitMethod => - stripImplicit(resultTypeApprox(mt)) - case pt: PolyType => - pt.derivedLambdaType(pt.paramNames, pt.paramInfos, stripImplicit(pt.resultType)) - case _ => - tp - } - def compareWithTypes(tp1: Type, tp2: Type) = { val ownerScore = compareOwner(alt1.symbol.maybeOwner, alt2.symbol.maybeOwner) def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2) @@ -1901,7 +1929,7 @@ trait Applications extends Compatibility { recur(altFormals.map(_.tail), args1) case _ => } - recur(alts.map(_.widen.firstParamTypes), pt.args) + recur(alts.map(alt => stripImplicit(alt.widen).firstParamTypes), pt.args) } private def harmonizeWith[T <: AnyRef](ts: List[T])(tpe: T => Type, adapt: (T, Type) => T)(implicit ctx: Context): List[T] = { diff --git a/tests/pos/i7793.scala b/tests/pos/i7793.scala new file mode 100644 index 000000000000..4e34bd133a1e --- /dev/null +++ b/tests/pos/i7793.scala @@ -0,0 +1,9 @@ +trait Foo: + def g(f: Int => Int): Int = 1 + def g(using String)(f: Int => String): String = "2" + +@main def Test = + val m: Foo = ??? + given String = "foo" + m.g(x => "2") + m.g(using summon[String])(x => "2")