Header menu logo FSharp.TypeProviders.SDK

Technical Notes

A type provider is simultaneously a tool and a library. There is a component that runs at compile-time (also called "design-time") and a component that runs at runtime. F# type providers are hosted by applications using FSharp.Compiler.Service.

First, some terminology:

The Type Provider Runtime Component (TPRTC)

This contains either a TypeProviderAssembly attribute indicating that this component is also a TPDTC, or TypeProviderAssembly("MyDesignTime.dll") attribute indicating that the name of the design time component.

TPRTCs are normally netstandard2.0 or above.

The Type Provider Design Time Component (TPDTC)

The Type Provider Design Time Component (TPDTC) is, for example, FSharp.Data.DesignTime.dll.

This is the DLL that gets loaded into host tools, and may be the same physical file as the TPRTC. This component includes the ProvidedTypes.fs/fsi files from the type provider SDK.

TPDTC are generally netstandard2.0 or netstandard2.1 components.

See Loading type providers for the rules to find TPDTC components.

Naming Conventions

The following guidance extends https://fsharp.github.io/2014/09/19/fsharp-libraries.html.

Good type provider naming examples:

Here are some examples of existing type providers that aren't too bad (they are clear) but could be renamed to follow the guidelines:

Lifetime of type provider instantiations

F# type providers are hosted by applications using FSharp.Compiler.Service. These notes describe the lifetime and typical resource usage of type provider instances for applications that incorporate FSharp.Compiler.Service (the host).

Each time the host application (e.g. devenv.exe) checks a file using type providers (e.g. containing JsonProvider<"...">), one or more new TP instantiations may be created, along with subsequent calls to ApplyStaticArguments.

The lifetime of TAST structures is as long as they are held in the IncrementalBuilder, or you hold on to FSharpCheckFileResults, or FSharpCheckProjectResults, or FSharpAssemblyContents.

Explicit construction of code: MakeGenericType, MakeGenericMethod and UncheckedQuotations

Some type providers need to build code via explicit calls to FSharp.Quotations.Expr.* rather than via quotation literals. Frequently, this is needed when code must instantiate generic methods or types. However, in some cases limitations of the F# quotations API are reached.

In these cases, follow these rules

  1. Always use ProvidedTypeBuilder.MakeGenericType(type, typeArguments) rather than type.MakeGenericType(typeArguments)
  2. Always use ProvidedTypeBuilder.MakeGenericMethod(methInfo, methTypeArguments) rather than methInfo.MakeGenericType(methTypeArguments)
  3. Where necessary open open ProviderImplementation.ProvidedTypes.UncheckedQuotations and make quotation nodes representing calls and other operations using Expr.CallUnchecked.

If you don't do this you may get errors like

    The type provider 'FSharp.Configuration.ConfigTypeProvider+FSharpConfigurationProvider' reported an error: Type mismatch when building 'args': invalid parameter for a method or indexer property. Expected 'System.Collections.Generic.IEnumerable`1[System.String]', but received type 'System.Collections.Generic.IEnumerable`1[System.String]'.�Parameter name: receivedType

or

    System.InvalidOperationException: the operation is not valid due to the current state of the object. at System.Reflection.MemberInfo.get_MetadataToken() in f:\dd\ndp\clr\src\BCL\system\reflection\memberinfo.cs:line 65

Type something to start searching.