-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Allow partial eta expansion #2691
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
Conversation
Allow partial eta expansion using the following rule: Assume we have an application (x_1, ..., x_m) => f(<arg_1, ..., arg_n>) every `x_i` occurs exactly once as argument to `f`, and typing `f` with `(?, ..., ?) => ?` as expected type (where there are n occurrences of `?` in the argument list) yields a method type `(T_1, ..., T_n)R`. Let `p` be the mapping from `1..m` to `1..n` which maps every parameter `x_i` to the position where it occurs in `<arg_1, ..., arg_n>`. In this case, if one of the parameter types `x_i` is not given and not inferred from the expected type, assume `T_p(i)` as the type of `x_i`, provided `T_p(i)` is fully defined and not a repeated type `T*` or `=>T*`. The reason for excluding repeated types `T*` is that `T*` is not a valid type for a lambda parameter.
Reverted back to initial commit because the rest is not directly related (and more subtle, it turns out). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Added a few questions / suggestions for clarification.
for (param <- params; idx <- paramIndices(param, args, 0)) | ||
yield param.name -> idx | ||
}.toMap | ||
if (paramIndex.size == params.length) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it's a map, wouldn't this miss the (unlikely) case where the same param (one key) occurs in multiple args (multiple values, of which only the last one is retained). I don't think it's a big deal, as this could not arise from the _
syntax, but the other comments do mention "exactly once" as a requirement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The revised implementation of paramIndices makes sure that a parameter is entered in the map only if there is a unique occurrence in args.
case untpd.TypedSplice(expr1) => | ||
expr1.tpe | ||
case _ => | ||
val protoArgs = args map (_ withType WildcardType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, the current implementation in Scala 2 includes the known argument types / result type, to enable overload resolution. Would be good to indicate the difference in a comment.
@@ -0,0 +1,29 @@ | |||
object Test { | |||
|
|||
def repeat(s: String, i: Int, j: Int = 22) = s * i |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When discussing this with Seth, he suggested to play around with currying by adding another argument list. The partial application should be fine: repeat(_, 1)
, but what about repeat(_, 1)(_)
? (uncurrying?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In dotc you get:
1 |repeat(1, _)(_)
| ^
| unbound placeholder parameter; incorrect use of `_`
In scalac you get:
scala> repeat(1, _)(_)
<console>:13: error: missing parameter type for expanded function ((x$1: <error>, x$2) => repeat(1, x$1)(x$2))
repeat(1, _)(_)
^
<console>:13: error: missing parameter type for expanded function ((x$1: <error>, x$2: <error>) => repeat(1, x$1)(x$2))
repeat(1, _)(_)
The fact that the types already contain <error>
markers makes me suspect that scalac also issues a parsing error but somehow suppresses the error message.
I made a note to add the missing comment about differences between dotc and scalsc in the followup PR |
Allow partial eta expansion using the following rule:
Assume we have an application
where every
x_i
occurs exactly once as argument tof
, and typingf
with(?, ..., ?) => ?
as expected type (where there are n occurrences of
?
in the argument list)yields a method type
(T_1, ..., T_n)R
. Letp
be the mapping from1..m
to1..n
which maps every parameter
x_i
to the position where it occurs in<arg_1, ..., arg_n>
.In this case, if one of the parameter types
x_i
is not given and not inferred from theexpected type, assume
T_p(i)
as the type ofx_i
, providedT_p(i)
is fully definedand not a repeated type
T*
or=>T*
.The reason for excluding repeated types
T*
is thatT*
is not a valid type for alambda parameter.
Fixes one part of #2570.