How to check if a type is an Option in FSharp Compiler Service?

Viewed 131
let foo = None

In the above example, is there a way in FSharp or FSharp Compiler Services to determine if foo is an Option type without resorting to reflection?

I tried the following function but I'm getting a System.InvalidOperationException: 'the type 'obj' does not have a qualified name' error when accessing the fsharpType.TypeDefinition.FullName property in the code below.

let private isOptionType (fsharpType:FSharpType) =    
    if fsharpType.HasTypeDefinition then    
        let fullnme = fsharpType.TypeDefinition.FullName
        match fsharpType.TypeDefinition.TryFullName with
        | Some fullName -> (Type.GetType fullName).GetGenericTypeDefinition() = typedefof<Option<_>>
        | None -> false
    else
        false

let private checkOptionType (checkFile:FSharpCheckFileResults) = fun () ->   
    let partialAssemblySignature = checkFile.PartialAssemblySignature    
    let moduleEntity = partialAssemblySignature.Entities.[0]
    let fnVal = moduleEntity.MembersFunctionsAndValues.[0]
    isOptionType fnVal.FullType
1 Answers

I'm not sure why the F# option type, as understood by the F# Compiler Service, does not have a qualified name, but I can confirm that I get the same error when I tried to do this.

That said, I think you can reconsider how you detect whether a type is option. Your approach is to get a fully qualified name and then see if this matches the name of option that is in the F# library running the compiler service. I suppose that could work, but equally, you can just check the name as string:

let isOptionType (fsharpType:FSharpType) =    
  fsharpType.HasTypeDefinition &&
  fsharpType.TypeDefinition.Namespace = Some "Microsoft.FSharp.Core" &&
  fsharpType.TypeDefinition.CompiledName = "option`1"

If you wanted something more robust, then I think the best option would be to use the F# compiler service to type check a minimal code snippet with just "let x = None", extract the type of the x variable, save this and then, when you need to check whether something else is an option type, compare the type definition of that with the type definition of the type of x.

For reference, I took the code sample from the F# Compiler Service docs and added the following:

let file = "/home/user/Test.fsx"
let input = "let x = None"

let parseFileResults, checkFileResults = 
  parseAndTypeCheckSingleFile(file, SourceText.ofString input)

let partialAssemblySignature =  
  checkFileResults.PartialAssemblySignature

let typ = 
  partialAssemblySignature.Entities.[0].
    MembersFunctionsAndValues.[0].FullType

isOptionType typ // Returns 'true'
Related