3
votes

I'm messing with my new statically parameterized type provider that provides a type with statically parameterized static methods. I haven't found documentation about this not being allowed. I'm getting some strange type provider behavior:

enter image description here

This type-provider-consuming code runs correctly but the intellisense gives crappy info. Members just keep getting added but never removed. The OpDef method shouldn't be available without the type parameters but intellisense kinda shows that as an option but still gives an error about a missing invoker if I actually refer to it. The required arguments to the provided OpDef method are not shown - always shows OpDef() -> unit instead of OpDef(suffix : string * id : string) -> unit that I currently expect to see (from this draft of the type provider). But as I've given all the arguments it really needs then it stops complaining.

Am I doing something that isn't supported or correct? Or, doubtfully, is there a bug in the f# stuff (and can you isolate where the bug is apparent)?

Here is the full implementation which uses the starter-pack files.

namespace OfflineSql

open ProviderImplementation.ProvidedTypes
open Microsoft.FSharp.Core.CompilerServices
open System.Text.RegularExpressions

#nowarn "0025"

[<TypeProvider>]
type OfflineSqlProvider (config : TypeProviderConfig) as this =
    inherit TypeProviderForNamespaces ()

    let ns = "OfflineSql"
    let asm = System.Reflection.Assembly.GetExecutingAssembly()

    let buildDomainProvider nm schema invariants =
        let parameterizedType = ProvidedTypeDefinition(asm, ns, nm, None)
        let m = ProvidedMethod("OpDef", list.Empty, typeof<unit>, IsStaticMethod = true)
        m.DefineStaticParameters(
            [
                ProvidedStaticParameter("script", typeof<string>)
            ],
            fun nm [| :? string as operation |] -> 
                let results = 
                    Regex.Matches(operation, "@([a-zA-Z_][a-zA-Z0-9_]*)") |> Seq.cast
                    |> Seq.map (fun (regmatch: Match) -> regmatch.Groups.[1].Captures.[0].ToString())
                let ps = [ for a in results -> ProvidedParameter(a, typeof<string>) ] |> List.distinct
                let opDef = ProvidedMethod(nm, ps, typeof<unit>, IsStaticMethod = true, InvokeCode = (fun _ -> <@@ () @@>))
                opDef.AddXmlDoc("Constructs a guarded method for the operation's script")
                parameterizedType.AddMember(opDef)
                opDef)
        let schemaProp = 
            ProvidedProperty("Schema", typeof<string>, IsStatic = true, 
                GetterCode = (fun _ -> <@@ schema @@>))
        let invariantsProp = 
            ProvidedProperty("Invariants", typeof<string>, IsStatic = true, 
                GetterCode = (fun _ -> <@@ invariants @@>))
        parameterizedType.AddMember(m)
        parameterizedType.AddMember(schemaProp)
        parameterizedType.AddMember(invariantsProp)
        parameterizedType

    do
        let root = ProvidedTypeDefinition(asm, ns, "Domain", None)
        root.DefineStaticParameters(
            [
                ProvidedStaticParameter("schema", typeof<string>)
                ProvidedStaticParameter("invariants", typeof<string>, "")
            ],
            fun nm [| :? string as schema ; :? string as invariants |] -> 
                buildDomainProvider nm schema invariants)
        this.AddNamespace(ns, [ root ])

[<assembly:TypeProviderAssembly>]
do ()
1

1 Answers

2
votes

This is directly related to known bugs with a fix:

Thanks to @gauthier on functionalprogramming.slack.com/fsharp for this find.