Search code examples
visual-studiof#intellisensetype-providers

F# Type Provider slows down intellisense in Visual Studio 2017


I have a very simple type provider; all types are erased, the provided type has 2000 int readonly properties Tag1..Tag2000

let ns = "MyNamespace"
let asm = Assembly.GetExecutingAssembly()

let private newProperty t name getter isStatic = ProvidedProperty(name, t, getter, isStatic = isStatic)
let private newStaticProperty t name getter = newProperty t name (fun _ -> getter) true
let private newInstanceProperty t name getter = newProperty t name (fun _ -> getter) false
let private addStaticProperty t name getter (``type``:ProvidedTypeDefinition) = ``type``.AddMember (newStaticProperty t name getter); ``type``
let private addInstanceProperty t name getter (``type``:ProvidedTypeDefinition) = ``type``.AddMember (newInstanceProperty t name getter); ``type``

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

    let provider = ProvidedTypeDefinition(asm, ns, "Provider", Some typeof<obj>, hideObjectMethods = true)
    let tags = ProvidedTypeDefinition(asm, ns, "Tags", Some typeof<obj>, hideObjectMethods = true)           
    do [1..2000] |> Seq.iter (fun i -> addInstanceProperty typeof<int> (sprintf "Tag%d" i) <@@ i @@> tags |> ignore)

    do provider.DefineStaticParameters([ProvidedStaticParameter("Host", typeof<string>)], fun name args ->
        let provided = ProvidedTypeDefinition(asm, ns, name, Some typeof<obj>, hideObjectMethods = true)
        addStaticProperty tags "Tags" <@@ obj() @@> provided |> ignore
        provided
    )

    do this.AddNamespace(ns, [provider; tags])

Then a test project with two modules in separate files:

module Common
open MyNamespace

type Provided = Provider<"">
let providedTags = Provided.Tags

type LocalTags() = 
    member this.Tag1 with get() : int = 1
    member this.Tag2 with get() : int = 2
.
.
    member this.Tag1999 with get() : int = 1999
    member this.Tag2000 with get() : int = 2000

let localTags = LocalTags()

module Tests

open Common
open Xunit

[<Fact>]
let ProvidedTagsTest () =
    Assert.Equal<int>(providedTags.Tag1001, 1001)

[<Fact>]
let LocalTagsTest () =
    Assert.Equal<int>(localTags.Tag100, 100)

Everything works as expected (tests execution included). The problem I have is with the design time behavior inside Visual Studio, while I write code. I expect to have some overhead due to the type provider, but the slowness seems frankly excessive. The times reported below are in seconds and refer to the time measured from pushing the dot (.) key until the intellisense property list appears on the screen

  1. providedTags. -> 15
  2. localTags. -> 5

If I comment out or remove the first test code lines (so to eliminate any references to the provided stuff), then I get

  1. localTags. -> immediate

If the number of properties is greater, the time seems to increase exponentially, not linearly, so that at 10000 it becomes minutes.

Questions are:

  • Is this normal or am I doing something wrong?
  • Are there guidelines to achieve a faster response?

If someone is curious about why I need so many properties, I am trying to supply an instrument to data analysts so that they can write F# scripts and get data out of an historian database with more than 10000 tags in its schema.


Solution

  • Issue has been fixed by Don Syme, see https://github.com/fsprojects/FSharp.TypeProviders.SDK/issues/220

    and

    https://github.com/fsprojects/FSharp.TypeProviders.SDK/pull/229