Skip to content

Handle implicits with default parameters. #1073

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}
Expand Down
18 changes: 18 additions & 0 deletions tests/pos/i576.scala
Original file line number Diff line number Diff line change
@@ -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()
}
}