Type provider providing me with an “Unsuported Constant Type : System.double” error in f#

StackOverflow https://stackoverflow.com/questions/10161437

  •  31-05-2021
  •  | 
  •  

Question

I wonder where this error is coming from. Here is the code, and below the TP, which uses fsahrpx DSL

Update: I found a 'solution', which is to do the cast outside and construct one getter per cast. If anyone knows why this happens, or has better solution, I'd be glad to know. (limited quotation pattern in the ProvidedTypes-0.2.fs ?)

edit : my desperate failed attempts are not so interesting. the two interesting ones are Test93 for instance, or Test92. why would they be failing ?

update added the most litigious cases 90,91,92,93

module Module =
   open System.Reflection
   open Samples.FSharp.ProvidedTypes
   open FSharpx.TypeProviders.DSL
   open Microsoft.FSharp.Core.CompilerServices

   type ReflectiveBuilder = static member Cast<'a> (args:obj) = args :?> 'a
      static member BuildTypedCast lType (args: obj) = 
            typeof<ReflectiveBuilder>
               .GetMethod("Cast")
               .MakeGenericMethod([|lType|])
               .Invoke(null, [|args|])

   let bbgReference ns =
       erasedType<obj> (Assembly.GetExecutingAssembly()) ns "Reference"
       |> staticParameter "file"
          (fun typeName (parameterValues:string) ->
               let otwo = 2.0 :> obj
               let dtwo = 2.0 
               let dotwo = otwo :?> float

               let dcast = ReflectiveBuilder.BuildTypedCast typeof<float>

               let getter = match otwo with
                              | :? double as d -> (fun args -> <@@ d @@>)
                              | :? string as d -> (fun args -> <@@ d @@>)

               erasedType<string> (Assembly.GetExecutingAssembly()) ns typeName
           |+!> (   provideProperty 
                       "test90"                             //KO
                       (typeof<obj>)                   
                       (fun args -> <@@  otwo  @@>)     
                 )
           |+!> (   provideProperty 
                       "test91"                             //KO
                       (otwo.GetType())                  
                       (fun args -> <@@  otwo  @@>)     
                 )
           |+!> (   provideProperty 
                       "test92"                             //KO
                       (otwo.GetType())                  
                       (fun args -> <@@  otwo  @@>)     
                 )
           |+!> (   provideProperty 
                       "test93"                              //NO
                       typeof<float>                   
                       (fun args -> <@@  otwo :?> float  @@>)     
                 )

               |+!> (   provideProperty 
                           "test"                             //OK
                           typeof<float>                   
                           (fun args -> <@@  dtwo  @@>)      
                     )
               |+!> (   provideProperty 
                           "test2"                              //NO
                           typeof<float>                   
                           (fun args -> <@@  dtwo :> obj @@>)     
                     )
               |+!> (   provideProperty 
                           "test3"                              //NO
                           typeof<float>                   
                           (fun args -> <@@  otwo  @@>)     
                     )
               |+!> (   provideProperty 
                           "test4"                              //NO
                           typeof<float>                   
                           (fun args -> <@@  otwo :?> float  @@>)     
                     )
               |+!> (   provideProperty 
                           "test5"                              //OK
                           typeof<float>                   
                           (fun args -> <@@  dotwo  @@>)     
                     )
               |+!> (   provideProperty 
                           "test6"                              //OK
                           typeof<float>                   
                           (fun args -> <@@  dotwo :> obj  @@>)     
                     )
               |+!> (   provideProperty 
                           "test7"                              //NO
                           typeof<float>                   
                           (fun args -> <@@  dcast otwo  @@>)     
                     )
               |+!> (   provideProperty 
                           "test8"                              //OK
                           typeof<float>                   
                           getter    
                     )
               |+!> (provideConstructor
                        []
                        (fun _ -> <@@ "I will be the internal representation" @@>)))


   [<TypeProvider>]
   type public CustomTypeProvider(cfg:TypeProviderConfig) as this =
      inherit TypeProviderForNamespaces()

      do this.AddNamespace("TEST", [bbgReference "TEST"])

   [<TypeProviderAssembly>]
   do()

the tests

module Program =
   open System

   type t = TEST.Reference<"">
   let price = t().Test90
   let price = t().Test91
   let price = t().Test92
   let price = t().Test93
   let price = t().Test    //OK
   let price = t().Test2   //OK
   let price = t().Test3   //NO OK
   let price = t().Test4   //NO OK
   let price = t().Test5   //OK
   let price = t().Test6   //OK
   let price = t().Test7   //NO OK
   let price = t().Test8   //OK
Was it helpful?

Solution

We are planning to publish updates/fixes to ProvidedTypes API on samples codeplex site in coming weeks. This issue will be addressed as well.

OTHER TIPS

The expressions that can appear in quoted code for properties and methods for F# type providers are quite limited - I faced the same problem when writing a type provider. I don't think there is a precise specification at the moment, so the only way to find out is to look at the source code or experiment with it.

The reason is that compiling F# quotations to IL wasn't already fully implemented anywhere and so the code generator for type providers probably just implements the basic functionality that is sufficient to make it work.

When writing providers, I generally follow a pattern where all the "runtime" code is placed in a module and the quoted code passed to methods or properties just calls this runtime. This works, because the quotation is just a method call. Something like:

module CultureRuntime =
  let getCulture (name:string) = 
    // The runtime can contain arbitrary complex F# code
    CultureInfo.GetCultureInfo(name)

When adding properites to a provider, the quotation just calls CultureRuntime.getCulture:

for culture in CultureInfo.GetCultures(CultureTypes.AllCultures) do
  let id = culture.Name
  ProvidedProperty
    ( culture.DisplayName, typeof<CultureInfo>, IsStatic = true,
      GetterCode = fun args -> <@@ CultureRuntime.getCulture id @@>)
  |> sampleTy.AddMember

EDIT: I'm not too familiar with how the code generation for type providers works internally, but the cases that you find surprising almost always work with <@ otwo @> or similar, where otwo is something of type System.Object.

When the type provider generates code from the quotation, it needs to generate IL code for the expression otwo. However, this does not make sense in general, because if otwo is of type System.Object, then you cannot generate IL that re-creates the object (or serialize the object in some other way).

For this reason, the F# type provider mechanism (probably) only allows primitive values that can be easily translated to IL (such as values of type float as in your <@ dtwo @> example).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top