Skip to content
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

Wrapping a constructor parameter with Option.Some before setting an optional field throws method not supported error. #366

Open
bdkoepke opened this issue Sep 2, 2021 · 2 comments
Labels

Comments

@bdkoepke
Copy link

bdkoepke commented Sep 2, 2021

Description

I'm building a type provider for Bloomberg (they have xml based schema files that describe the entire API). The code-generation part of the API is pretty close to working (there are four primary different types: enums, records, unions, and operations). For the implementation of the record type and union types, I'm trying to improve the API so 'optional' parameters can be specified as the value directly rather than (Some t'). When I change the code from the following:

es
|> Result.mapError (fun xs -> ChoiceError.Element(c.Name, xs))
|> Result.map (fun xs ->
    xs
    |> List.iter (fun (_, field) ->
        let parameter = ProvidedParameter(field.Name, field.FieldType)
        providedChoiceType.AddMember
        <| ProvidedConstructor(
            [parameter],
            invokeCode =
                fun args ->
                    match args with
                    | this :: [arg] ->
                        let setValue = Expr.FieldSet(this, field, arg)
                        let enumField = Expr.FieldSet(this, enumField, Expr.FieldGet(enum.GetField(field.Name)))
                        Expr.Sequential(enumField, setValue)
                    | _ -> failwith "wrong ctor parameters"))
    {
        Enum = enum
        Object = providedChoiceType
    }))

to

es
|> Result.mapError (fun xs -> ChoiceError.Element(c.Name, xs))
|> Result.map (fun xs ->
    xs
    |> List.iter (fun (type', field) ->
        let parameter = ProvidedParameter(field.Name, type')
        providedChoiceType.AddMember
        <| ProvidedConstructor(
            [parameter],
            invokeCode =
                fun args ->
                    match args with
                    | this :: [arg] ->
                        let some =
                            FSharpType.GetUnionCases(field.FieldType)
                            |> Array.filter (fun x -> x.Name = "Some")
                            |> Array.exactlyOne
                        let arg' = Expr.NewUnionCase(some, arg)
                        let setValue = Expr.FieldSet(this, field, arg')
                        let enumField = Expr.FieldSet(this, enumField, Expr.FieldGet(enum.GetField(field.Name)))
                        Expr.Sequential(enumField, setValue)
                    | _ -> failwith "wrong ctor parameters"))
    {
        Enum = enum
        Object = providedChoiceType
    }))

Then I get the error "Specified method is not supported."

The key part is really just the following:

from

 let setValue = Expr.FieldSet(this, field, arg)

to

let some =
    FSharpType.GetUnionCases(field.FieldType)
    |> Array.filter (fun x -> x.Name = "Some")
    |> Array.exactlyOne
let arg' = Expr.NewUnionCase(some, arg)
let setValue = Expr.FieldSet(this, field, arg')

Wrapping the argument in 'Some' seems to be causing this error.

Expected behavior

I'm trying to generate a type like the following:

type Example(x: int) as self =
    [<DefaultValue>] val mutable X: option<int>

    do
        self.X <- Some x

    member this.GetX with get() = self.X

Such that the argument is not an "optional" type but the backing field is.

Actual behavior

I get the error "Specified method is not supported."

image

Known workarounds

I have this working:

type Example(x: option<int>) as self =
    [<DefaultValue>] val mutable X: option<int>

    do
        self.X <- x

    member this.GetX with get() = self.X

But that sucks because now you can only instantiate the Example object by doing:

Example(Some 1)

Rather than

Example(1)

Thank you!

Related information

dotnet 3.1

@dsyme
Copy link
Contributor

dsyme commented Sep 21, 2021

@bdkoepke I'm only just catching up on this issue

Did you find an adequate workaround? Also, please feel free to ask further questions or start discussions here.

@dsyme dsyme added the bug label Sep 21, 2021
@bdkoepke
Copy link
Author

Hello, apologies it took so long to respond. No workaround yet.

The code is here: https://github.com/alphaarchitect/BloombergProvider

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants