From c4be2191e0c17767911377d7bc835d1b40eb39af Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 16 Feb 2016 13:46:46 +0100 Subject: [PATCH 1/2] Handle implicits with default parameters If an implicit parameter has a default, then that default should be taken in case no implicit argument is found. --- src/dotty/tools/dotc/typer/Typer.scala | 30 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 6a2ff30fa7c2..b65e3cd4226d 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1435,10 +1435,15 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit wtp.paramTypes.foreach(instantiateSelected(_, tvarsToInstantiate)) val constr = ctx.typerState.constraint def addImplicitArgs = { - def implicitArgError(msg: => String): Tree = { - ctx.error(msg, tree.pos.endPos) + val errors = new mutable.ListBuffer[() => String] + def implicitArgError(msg: => String) = { + errors += (() => msg) EmptyTree } + def issueErrors() = { + for (err <- errors) ctx.error(err(), tree.pos.endPos) + tree + } val args = (wtp.paramNames, wtp.paramTypes).zipped map { (pname, formal) => def where = d"parameter $pname of $methodStr" inferImplicit(formal, EmptyTree, tree.pos.endPos) match { @@ -1450,12 +1455,27 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit implicitArgError(d"no implicit argument of type $formal found for $where" + failure.postscript) } } - if (args.exists(_.isEmpty)) { + if (errors.nonEmpty) { // If there are several arguments, some arguments might already - // have influenced the context, binfing variables, but later ones + // have influenced the context, binding variables, but later ones // might fail. In that case the constraint needs to be reset. ctx.typerState.constraint = constr - tree + + // If method has default params, fall back to regular application + // where all inferred implicits are passed as named args. + if (tree.symbol.hasDefaultParams) { + val namedArgs = (wtp.paramNames, args).zipped.flatMap { (pname, arg) => + arg match { + case EmptyTree => Nil + case _ => untpd.NamedArg(pname, untpd.TypedSplice(arg)) :: Nil + } + } + tryEither { implicit ctx => + typed(untpd.Apply(untpd.TypedSplice(tree), namedArgs), pt) + } { (_, _) => + issueErrors() + } + } else issueErrors() } else adapt(tpd.Apply(tree, args), pt) } From 5c21583669ff9128784ce128d36e723b9d4517ee Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 16 Feb 2016 13:49:02 +0100 Subject: [PATCH 2/2] Add test case --- tests/pos/i576.scala | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/pos/i576.scala diff --git a/tests/pos/i576.scala b/tests/pos/i576.scala new file mode 100644 index 000000000000..77b38d742d65 --- /dev/null +++ b/tests/pos/i576.scala @@ -0,0 +1,18 @@ +class A + +object Impl { + def foo()(implicit x: A = null): Int = 2 + def test: Int = { + foo()() // ok + foo() // did not work before, does now + } +} + +// same with multiple parameters +object Impl2 { + def foo()(implicit ev: Int, x: A = null): Int = 2 + def test: Int = { + implicit val ii: Int = 1 + foo() + } +}