Skip to content

Commit fc9ce02

Browse files
committed
Fix #5606: Handle closures in extension method calls
Handle closures as left arguments of extension method calls.
1 parent dab02ed commit fc9ce02

File tree

3 files changed

+41
-7
lines changed

3 files changed

+41
-7
lines changed

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,25 @@ object Applications {
167167

168168
/** A wrapper indicating that its argument is an application of an extension method.
169169
*/
170-
case class ExtMethodApply(app: Tree) extends tpd.Tree {
170+
class ExtMethodApply(val app: Tree) extends tpd.Tree {
171171
override def pos = app.pos
172+
173+
def canEqual(that: Any): Boolean = app.canEqual(that)
174+
def productArity: Int = app.productArity
175+
def productElement(n: Int): Any = app.productElement(n)
176+
}
177+
178+
/** The unapply method of this extractor also recognizes ExtMethodApplys in closure blocks.
179+
* This is necessary to deal with closures as left arguments of extension method applications.
180+
* A test case is i5606.scala
181+
*/
182+
object ExtMethodApply {
183+
def apply(app: Tree) = new ExtMethodApply(app)
184+
def unapply(tree: Tree)(implicit ctx: Context): Option[Tree] = tree match {
185+
case tree: ExtMethodApply => Some(tree.app)
186+
case Block(stats, ExtMethodApply(app)) => Some(tpd.cpy.Block(tree)(stats, app))
187+
case _ => None
188+
}
172189
}
173190
}
174191

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import EtaExpansion.etaExpand
2727
import util.Positions._
2828
import util.common._
2929
import util.Property
30+
import Applications.{ExtMethodApply, wrapDefs, productSelectorTypes}
3031

3132
import collection.mutable
3233
import annotation.tailrec
@@ -426,7 +427,7 @@ class Typer extends Namer
426427

427428
def typeSelectOnTerm(implicit ctx: Context): Tree =
428429
typedExpr(tree.qualifier, selectionProto(tree.name, pt, this)) match {
429-
case qual1 @ Applications.ExtMethodApply(app) =>
430+
case qual1 @ ExtMethodApply(app) =>
430431
pt.revealIgnored match {
431432
case _: PolyProto => qual1 // keep the ExtMethodApply to strip at next typedTypeApply
432433
case _ => app
@@ -926,7 +927,7 @@ class Typer extends Namer
926927
def ptIsCorrectProduct(formal: Type) = {
927928
isFullyDefined(formal, ForceDegree.noBottom) &&
928929
(defn.isProductSubType(formal) || formal.derivesFrom(defn.PairClass)) &&
929-
Applications.productSelectorTypes(formal).corresponds(params) {
930+
productSelectorTypes(formal).corresponds(params) {
930931
(argType, param) =>
931932
param.tpt.isEmpty || argType <:< typedAheadType(param.tpt).tpe
932933
}
@@ -1837,7 +1838,7 @@ class Typer extends Namer
18371838
case Block(stats, expr) =>
18381839
tpd.cpy.Block(app)(stats, lift(expr))
18391840
}
1840-
Applications.wrapDefs(defs, lift(app))
1841+
wrapDefs(defs, lift(app))
18411842
}
18421843
}
18431844

@@ -2640,7 +2641,9 @@ class Typer extends Namer
26402641
val app = tryExtension(nestedCtx)
26412642
if (!app.isEmpty && !nestedCtx.reporter.hasErrors) {
26422643
nestedCtx.typerState.commit()
2643-
return Applications.ExtMethodApply(app).withType(app.tpe)
2644+
return ExtMethodApply(app).withType(WildcardType)
2645+
// Use wildcard type in order not to prompt any further adaptations such as eta expansion
2646+
// before the method is fully applied.
26442647
}
26452648
case _ =>
26462649
}
@@ -2652,7 +2655,7 @@ class Typer extends Namer
26522655
else err.typeMismatch(tree, pt, failure)
26532656
if (ctx.mode.is(Mode.ImplicitsEnabled) && tree.typeOpt.isValueType)
26542657
inferView(tree, pt) match {
2655-
case SearchSuccess(inferred: Applications.ExtMethodApply, _, _) =>
2658+
case SearchSuccess(inferred: ExtMethodApply, _, _) =>
26562659
inferred // nothing to check or adapt for extension method applications
26572660
case SearchSuccess(inferred, _, _) =>
26582661
checkImplicitConversionUseOK(inferred.symbol, tree.pos)
@@ -2732,7 +2735,7 @@ class Typer extends Namer
27322735
adaptToArgs(wtp, pt)
27332736
case pt: PolyProto =>
27342737
tree match {
2735-
case _: Applications.ExtMethodApply => tree
2738+
case _: ExtMethodApply => tree
27362739
case _ => tryInsertApplyOrImplicit(tree, pt, locked)(tree) // error will be reported in typedTypeApply
27372740
}
27382741
case _ =>

tests/run/i5606.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Test extends App {
2+
3+
def (f: A => B) $[A, B](a: A): B = f(a)
4+
5+
assert((((a: Int) => a.toString()) $ 10) == "10")
6+
7+
def g(x: Int): String = x.toString
8+
9+
assert((g $ 10) == "10")
10+
11+
val h: Int => String = _.toString
12+
13+
assert((h $ 10) == "10")
14+
}

0 commit comments

Comments
 (0)