fsprojects / FSharp.TypeProviders.SDK

The SDK for creating F# type providers
https://fsprojects.github.io/FSharp.TypeProviders.SDK/
MIT License
298 stars 94 forks source link

Cannot access type from 3rd party assembly from quotation #278

Closed sergey-tihon closed 2 years ago

sergey-tihon commented 5 years ago

Description

The following provided method does not compile. It tries to access type System.Text.Encoding.UTF8 defined in assembly System.Net.Http.dll restored from Nuget

        let meth = ProvidedMethod("GetContent", [ProvidedParameter("s", typeof<string>)], 
                    typeof<StringContent>, isStatic=false, 
                    invokeCode = (fun args -> 
                        <@@
                           let s = (%%args.[1] : string)
                           new StringContent(s, System.Text.Encoding.UTF8, "application/json")
                        @@>))

Repro steps

Please provide the steps required to reproduce the problem

  1. Clone repo https://github.com/sergey-tihon/tp-encoding-bug

  2. dotnet build

Expected behavior

Compile without error

Actual behavior

Compilation fails with error

/Users/sergey/github/tp-temp/LemonadeEncodingProvider/tests/LemonadeEncodingProvider.Tests/LemonadeEncodingProvider.Tests.fs(7,20): error FS3033: The type provider 'LemonadeEncodingProviderImplementation+BasicGenerativeProvider' reported an error: assembly System.Text.Encoding not found [/Users/sergey/github/tp-temp/LemonadeEncodingProvider/tests/LemonadeEncodingProvider.Tests/LemonadeEncodingProvider.Tests.fsproj]

Known workarounds

Define helper function in Runtime assembly

module Utilities = 
    open System.Net.Http

    let toContentString s =
        new StringContent(s, System.Text.Encoding.UTF8, "application/json")

and call it from quotation

        let meth = ProvidedMethod("GetContent", [ProvidedParameter("s", typeof<string>)], 
                    typeof<StringContent>, isStatic=false, 
                    invokeCode = (fun args -> 
                        <@@
                           let s = (%%args.[1] : string)
                           //new StringContent(s, System.Text.Encoding.UTF8, "application/json")
                           Utilities.toContentString s
                        @@>))

Related information

kevmal commented 5 years ago

Compiled fine for me with dotnet 2.2.100-preview2-009404 on windows.

sergey-tihon commented 5 years ago

Thank @kevmal. Indeed, it works on win even with 2.1.403 I guess it is because System.Net.Http.dll in available from GAC on Windows.

I've updated sample to use SharpYaml.dll instead of System.Net.Http.dll (this dll should not be in GAC on most of machines)

So when I do

        let meth = ProvidedMethod("ToYaml", [ProvidedParameter("o", typeof<obj>)], 
                    typeof<string>, isStatic=false, 
                    invokeCode = (fun args -> 
                        <@@
                           let o = (%%args.[1] : obj)
                           let serializer = SharpYaml.Serialization.Serializer()
                           serializer.Serialize(o)
                        @@>))

compilation fails with

X:\tp-temp\LemonadeEncodingProvider\tests\LemonadeEncodingProvider.Tests\LemonadeEncodingProvider.Tests.fs(7,20): error FS3033: The type provider 'LemonadeEncodingProviderImplementation+BasicGenerativeProvider' reported an error: Could not load file or assembly 'SharpYaml, Version=1.6.4.0, Culture=neutral, PublicKeyToken=1ced8108e942bc02'. The system cannot find the file specified. [X:\tp-temp\LemonadeEncodingProvider\tests\LemonadeEncodingProvider.Tests\LemonadeEncodingProvider.Tests.fsproj]

but when I replace it with

        let meth = ProvidedMethod("ToYaml", [ProvidedParameter("o", typeof<obj>)], 
                    typeof<string>, isStatic=false, 
                    invokeCode = (fun args -> 
                        <@@
                           let o = (%%args.[1] : obj)
                           Utilities.toYaml o
                        @@>))

when runtime assembly contains

module Utilities = 
    let toYaml o =
        let serializer = SharpYaml.Serialization.Serializer()
        serializer.Serialize(o)

it compiles without errors

@kevmal could you please try again https://github.com/sergey-tihon/tp-encoding-bug

kevmal commented 5 years ago

Now I'm seeing the same error with dotnet build. Though it seems VS 2017 Preview has no issues, builds and tests fine.

dsyme commented 2 years ago

CLosing out this old issue