-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Function Arguments of named tuples can't infer param types despite explicit type #20456
Comments
This looks like its because of the desugaring - i.e (foo = _.length) : (foo: String => Int) becomes NamedTuple.withNames(Tuple1(_.length))[Tuple1["foo"]] : (foo: String => Int)
// ^^^^^^^^
// nested lambda with no expected type it might be worth reconsidering this desugaring, or perhaps tunnelling through any expected type to the argument of A tentative plan - perhaps we can add a type ascription to some "watcher" type, that then is resolved on the outside - (NamedTuple.withNames(Tuple1(_.length): <watch[target]>)[Tuple1["foo"]] : <target>) : (foo: String => Int) |
Named tuples are constructed with extension [V <: Tuple](x: V)
inline def withNames[N <: Tuple]: NamedTuple[N, V] = x So the call looks like NamedTuple.withNames[V](tuple)[N] It's important to have two type parameter lists because the def build[N <: Tuple]()[V <: Tuple](x: V): NamedTuple[N, V] Maybe that would fix the problem. I think it might be worth trying out, but I don't have the bandwidth to do it myself right now. |
This solution seems to work without needing clause interleaving, and leaves no trace after inlining: object NamedTupleBuilder {
opaque type Builder[N <: Tuple] = Unit
def apply[N <: Tuple]: Builder[N] = ()
}
extension [N <: Tuple](inline b: NamedTupleBuilder.Builder[N])
transparent inline def build[V <: Tuple](inline v: V): NamedTuple[N, V] = v.withNames[N] then we can have the example here: val m: (foo: String => Int, bar: String => Int) =
(foo = _.length, bar = _.length) desugar to val m: (foo: String => Int, bar: String => Int) =
NamedTupleBuilder.apply[("foo", "bar")].build((_.length, _.length)) and it infers perfectly. here is the tree after typer: scala> val m: (foo: String => Int, bar: String => Int) = NamedTupleBuilder.apply[("foo", "bar")].build((_.length, _.length))
[[syntax trees at end of typer]] // rs$line$5
package <empty> {
final lazy module val rs$line$5: rs$line$5 = new rs$line$5()
final module class rs$line$5() extends Object() { this: rs$line$5.type =>
val m: (foo : String => Int, bar : String => Int) =
NamedTuple.withNames[(String => Int, String => Int)](
Tuple2.apply[String => Int, String => Int](
{
def $anonfun(_$1: String): Int = _$1.length()
closure($anonfun)
},
{
def $anonfun(_$2: String): Int = _$2.length()
closure($anonfun)
}
)
)[(("foo" : String), ("bar" : String))]
}
}
val m: (foo : String => Int, bar : String => Int) = (rs$line$5$$$Lambda$2022/0x000000012d6005d8@5e08ed28,rs$line$5$$$Lambda$2023/0x000000012d6009a8@24b05292) |
I have implemented a fix in #20497 - which also includes a variant of https://github.com/bishabosha/ops-mirror that makes use of named tuples to implement server logic |
Adds a new `NamedTuple.build` method which fixes the types of the labels first, as suggested in #20456 (comment) It requires `language.experimental.clauseInterleaving` language import. Keeps `withNames` as a friendlier option for end-users fixes #20456
Compiler version
3.5.0-RC1
Minimized code
Output
Expectation
correctly infer the arguments, as with normal tuples.
Use Case
I would like to be able to construct programatically a type for a named tuple where all its fields are function types, and then the user should be able to construct this object without explicit parameter types
The text was updated successfully, but these errors were encountered: