`[<System.ParamArray>]` parameter in member function causes type check error.
When I use the parameter of [<ParamArray>] attribute in member function, I cannot pass the parameter using pipeline operator:
> type X () = member _.ID ([<System.ParamArray>] arr) = arr;;
type X =
new: unit -> X
member ID: [<System.ParamArray>] arr: 'a -> 'a
> let x = X();;
val x: X
> x.ID([| 1; 2; 3 |]);;
val it: int array = [|1; 2; 3|]
> [| 1; 2; 3 |] |> x.ID;;
[| 1; 2; 3 |] |> x.ID;;
-----------------^^^^
/home/muqiu/stdin(10,18): error FS0001: This expression was expected to have type
'int array'
but here has type
'unit'
And no type check error occurs when the [<ParamArray>] attribute is not used or using [<ParamArray>] at the top level:
> type X () = member _.ID (arr) = arr;;
type X =
new: unit -> X
member ID: arr: 'a -> 'a
> let x = X();;
val x: X
> [| 1; 2; 3 |] |> x.ID;;
val it: int array = [|1; 2; 3|]
> let ID ([<System.ParamArray>] arr) = arr;;
val ID: [<System.ParamArray>] arr: 'a -> 'a
> [| 1; 2; 3 |] |> ID;;
val it: int array = [|1; 2; 3|]
Why does [<ParamArray>] behave differently in member functions? Is this a compiler bug?
Probably a duplicate of https://github.com/dotnet/fsharp/issues/11918.
I think it's a type inference + overload resolution thing: a method with a single parameter annotated with [<ParamArray>] can also be treated as a nullary method (or a method taking a single parameter of type unit).
But there is not perfect symmetry in how overload resolution works for directly-invoked methods and methods used in a first-class way (e.g., with piping). See https://github.com/dotnet/fsharp/issues/11918#issuecomment-894294044.
The error message is confusing, though:
> open System
-
- type T =
- static member M ([<ParamArray>] xs : int array) = xs
-
- let xs = [|1..10|]
-
- xs |> T.M;;
xs |> T.M;;
------^^^
stdin(8,7): error FS0001: This expression was expected to have type
'int array'
but here has type
'unit'
It sounds like the opposite of what the source code looks like.
Especially since this works:
() |> T.M
It is same situation for optional parameters. And this only occurs when the method doesn't have overloads.
type X () =
member _.ID ([<System.ParamArray>] arr) = arr
// another overload
member _.ID (x: int) = x
member _.OptionalParameter (?x: int) = x
let x = X()
// will not fail
[| 1; 2; 3 |] |> x.ID
// will fail
1 |> x.OptionalParameter
There is a comment say the optional and out args are resolved to their default values when the method doesn't have other overloads. Can we change this behavior to make it works like a normal function?
https://github.com/dotnet/fsharp/blob/5065f5bcff7498422d782caa538b43d19b492d7b/src/Compiler/Checking/Expressions/CheckExpressions.fs#L9944-L9947