Skip to content

Commit

Permalink
Eta lifts function before args.
Browse files Browse the repository at this point in the history
The comment says it, the spec says it, and most importantly, Dotty says it.

Update the examples in the spec, which didn't say it.

Maybe qualify for the coveted "performance" label by avoiding an
argument load.

Fixes scala/bug#11465.
  • Loading branch information
hrhino committed Apr 6, 2019
1 parent 9795ad8 commit 64a2e55
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 5 deletions.
4 changes: 2 additions & 2 deletions spec/06-expressions.md
Expand Up @@ -431,8 +431,8 @@ The method values in the left column are each equivalent to the [eta-expanded ex
|`math.sin _` | `x => math.sin(x)` |
|`math.pow _` | `(x1, x2) => math.pow(x1, x2)` |
|`val vs = 1 to 9; vs.fold _` | `(z) => (op) => vs.fold(z)(op)` |
|`(1 to 9).fold(z)_` | `{ val eta1 = z; val eta2 = 1 to 9; op => eta2.fold(eta1)(op) }` |
|`Some(1).fold(??? : Int)_` | `{ val eta1 = () => ???; val eta2 = Some(1); op => eta2.fold(eta1())(op) }` |
|`(1 to 9).fold(z)_` | `{ val eta1 = 1 to 9; val eta2 = z; op => eta1.fold(eta2)(op) }` |
|`Some(1).fold(??? : Int)_` | `{ val eta1 = Some(1); val eta2 = () => ???; op => eta1.fold(eta2())(op) }` |

Note that a space is necessary between a method name and the trailing underscore
because otherwise the underscore would be considered part of the name.
Expand Down
5 changes: 3 additions & 2 deletions src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
Expand Up @@ -46,7 +46,7 @@ trait EtaExpansion { self: Analyzer =>
* - typedEta (when type checking a method value, `m _`).
*
**/
def etaExpand(unit: CompilationUnit, tree: Tree, owner: Symbol)(implicit creator: FreshNameCreator): Tree = {
def etaExpand(tree: Tree, owner: Symbol)(implicit creator: FreshNameCreator): Tree = {
val tpe = tree.tpe
var cnt = 0 // for NoPosition
def freshName() = {
Expand Down Expand Up @@ -95,11 +95,12 @@ trait EtaExpansion { self: Analyzer =>
liftoutPrefix(fun)
case Apply(fn, args) =>
val byName: Int => Option[Boolean] = fn.tpe.params.map(p => definitions.isByNameParamType(p.tpe)).lift
val liftedFn = liftoutPrefix(fn) // scala/bug#11465: lift fn before args
val newArgs = mapWithIndex(args) { (arg, i) =>
// with repeated params, there might be more or fewer args than params
liftout(arg, byName(i).getOrElse(false))
}
treeCopy.Apply(tree, liftoutPrefix(fn), newArgs).clearType()
treeCopy.Apply(tree, liftedFn, newArgs).clearType()
case TypeApply(fn, args) =>
treeCopy.TypeApply(tree, liftoutPrefix(fn), args).clearType()
case Select(qual, name) =>
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/typechecker/Typers.scala
Expand Up @@ -3203,7 +3203,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper

if (tree.tpe.isDependentMethodType) DependentMethodTpeConversionToFunctionError(tree, tree.tpe) // TODO: support this
else {
val expansion = etaExpand(context.unit, tree, context.owner)
val expansion = etaExpand(tree, context.owner)
if (context.undetparams.isEmpty) typed(expansion, mode, pt)
else instantiate(typed(expansion, mode), mode, pt)
}
Expand Down
6 changes: 6 additions & 0 deletions test/files/run/t11465.check
@@ -0,0 +1,6 @@
F
Z
55
F
Z
55
5 changes: 5 additions & 0 deletions test/files/run/t11465.scala
@@ -0,0 +1,5 @@
object Test extends App {
def f = { println("F") ; 1 to 10 }
println { f.foldLeft{ println("Z"); 0 }(_ + _) }
println { (f.foldLeft{ println("Z"); 0 } _) (_ + _) }
}

0 comments on commit 64a2e55

Please sign in to comment.