diff options
-rw-r--r-- | compiler/src/dotty/tools/dotc/typer/ReTyper.scala | 4 | ||||
-rw-r--r-- | compiler/src/dotty/tools/dotc/typer/Typer.scala | 32 | ||||
-rw-r--r-- | tests/neg/i1639.scala | 10 |
3 files changed, 35 insertions, 11 deletions
diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index 2413c0c22..4829e5ab2 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -73,8 +73,8 @@ class ReTyper extends Typer { override def index(trees: List[untpd.Tree])(implicit ctx: Context) = ctx - override def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree = - fallBack(tree, ctx.typerState) + override def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: => Tree)(implicit ctx: Context): Tree = + fallBack override def completeAnnotations(mdef: untpd.MemberDef, sym: Symbol)(implicit ctx: Context): Unit = () diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ccc74cfff..f5a4e36a2 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1585,18 +1585,34 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit * `fallBack`. * * 1st strategy: Try to insert `.apply` so that the result conforms to prototype `pt`. + * This strategy is not tried if the prototype represents already + * another `.apply` or `.apply()` selection. * 2nd strategy: If tree is a select `qual.name`, try to insert an implicit conversion * around the qualifier part `qual` so that the result conforms to the expected type * with wildcard result type. */ - def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree = - tryEither { implicit ctx => + def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: => Tree)(implicit ctx: Context): Tree = { + + /** Is `pt` a prototype of an `apply` selection, or a parameterless function yielding one? */ + def isApplyProto(pt: Type): Boolean = pt match { + case pt: SelectionProto => pt.name == nme.apply + case pt: FunProto => pt.args.isEmpty && isApplyProto(pt.resultType) + case pt: IgnoredProto => isApplyProto(pt.ignored) + case _ => false + } + + def tryApply(implicit ctx: Context) = { val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt) if (sel.tpe.isError) sel else adapt(sel, pt) - } { (failedTree, failedState) => - tryInsertImplicitOnQualifier(tree, pt).getOrElse(fallBack(failedTree, failedState)) } + def tryImplicit = + tryInsertImplicitOnQualifier(tree, pt).getOrElse(fallBack) + + if (isApplyProto(pt)) tryImplicit + else tryEither(tryApply(_))((_, _) => tryImplicit) + } + /** If this tree is a select node `qual.name`, try to insert an implicit conversion * `c` around `qual` so that `c(qual).name` conforms to `pt`. */ @@ -1688,7 +1704,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def hasEmptyParams(denot: SingleDenotation) = denot.info.paramTypess == ListOfNil pt match { case pt: FunProto => - tryInsertApplyOrImplicit(tree, pt)((_, _) => noMatches) + tryInsertApplyOrImplicit(tree, pt)(noMatches) case _ => if (altDenots exists (_.info.paramTypess == ListOfNil)) typed(untpd.Apply(untpd.TypedSplice(tree), Nil), pt) @@ -1727,7 +1743,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case Apply(_, _) => " more" case _ => "" } - (_, _) => errorTree(tree, em"$methodStr does not take$more parameters") + errorTree(tree, em"$methodStr does not take$more parameters") } } @@ -1946,9 +1962,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case pt: FunProto => adaptToArgs(wtp, pt) case pt: PolyProto => - tryInsertApplyOrImplicit(tree, pt) { - (_, _) => tree // error will be reported in typedTypeApply - } + tryInsertApplyOrImplicit(tree, pt)(tree) // error will be reported in typedTypeApply case _ => if (ctx.mode is Mode.Type) adaptType(tree.tpe) else adaptNoArgs(wtp) diff --git a/tests/neg/i1639.scala b/tests/neg/i1639.scala new file mode 100644 index 000000000..952cb5ed8 --- /dev/null +++ b/tests/neg/i1639.scala @@ -0,0 +1,10 @@ +class Bar { + implicit def f(implicit x: String): String = x + + implicitly[String](f) // error: divergent (turn -explaintypes on to see it) +} + +class Foo(implicit val bar: String) { + def this() = this("baz") // error: none of the alternatives match arguments +} + |