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

Generated types with custom attributes can cause incorrect references at runtime #225

Closed allykzam closed 6 years ago

allykzam commented 6 years ago

Description

Generated types with custom attributes (including setting hideObjectMethods or nonNullable to true) from design-time libraries are not processed by the internal ProvidedTypesContext, and can therefore cause the compiled host application to reference the wrong versions. In my case, this is causing compiled applications to reference the ambient version of FSharp.Core used within Visual Studio at design time, because the TypeProviderEditorHideMethodsAttribute and AllowNullLiteralAttribute types are defined there.

This can probably be solved by implementing ProvidedTypesContext.convCustomAttributesDataToTgt, which currently has a TODO note suggesting this.

This is roughly related to Microsoft/visualfsharp#3049 and Microsoft/visualfsharp#2399, and has the same end-result for my purposes, but both of those issues were opened prior to the recent refactoring of this SDK which automatically creates cross-targeting type providers. As my current code is my first generative type provider, I do not know if the previous ProvidedTypesContext would have handled this, but I can try to reproduce the issue with an old version of the SDK if needed.

Repro steps

Please provide the steps required to reproduce the problem

  1. Create a generative type provider with the current code from this SDK (sample repro below)

  2. Create a host application that uses the generative type provider, and references an old version of FSharp.Core

  3. Build the host application while making use of the type provider, and review the compiled assembly's references

Expected behavior

The library versions referenced as part of the host application's project file should be the versions referenced in the compiled assembly.

Actual behavior

The ambient version of any referenced assemblies are used, rather than the ones specified in the project file.

Known workarounds

Do not use custom attributes from the ambient libraries. Besides any intentionally-used attributes, this additionally means not setting hideObjectMethods or nonNullable to true when creating ProvidedTypeDefinition values.

Related information

Sample type provider that reproduces this:

namespace Some.Name.Space

open ProviderImplementation
open ProviderImplementation.ProvidedTypes
open Microsoft.FSharp.Quotations

 [<Microsoft.FSharp.Core.CompilerServices.TypeProvider>]
 type TestProvider (typeProviderConfig) as providerThis =
    inherit TypeProviderForNamespaces(typeProviderConfig)

    let targetNamespace = "Some.Name.Space"
    let executingAssembly = System.Reflection.Assembly.GetExecutingAssembly()

    let SampleProviderType =
        let baseType = ProvidedTypeDefinition(executingAssembly, targetNamespace, "TestProvider", Some typeof<obj>, isErased = false)
        baseType.DefineStaticParameters(
            [ ProvidedStaticParameter("SomeParam", typeof<string>, "") ],
            (fun typeName _ ->
                let asm = ProvidedAssembly()
                // Change the line below to resolve this issue
                let t = ProvidedTypeDefinition(asm, targetNamespace, typeName, Some typeof<obj>, hideObjectMethods = true, isErased = false)
                asm.AddTypes [t]
                t
            ))
        baseType

    do
        providerThis.AddNamespace(targetNamespace, [SampleProviderType])

[<assembly: Microsoft.FSharp.Core.CompilerServices.TypeProviderAssembly>]
do ()
dsyme commented 6 years ago

@amazingant I agree this needs to be fixed, thanks