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

Compilation stalls when using System.Type.FullName on a generic type #236

Closed Tarmil closed 2 years ago

Tarmil commented 6 years ago

Description

Compilation stalls indefinitely when a .NET Standard 2.0 TPDTC is loaded into .NET Core App 2.0 tooling (e.g. loaded into the F# compiler in the .NET Core SDK). This happens when some code uses System.Type.FullName on a generic type instantiated with a provided type using typ.MakeGenericType(...)

Repro steps

Here's a minimal repro project: https://github.com/Tarmil/tploop.fail

Workaround 1

Replaces all uses of typ.MakeGenericType by ProvidedTypeBuilder.MakeGenericType. The latter constructs type instances less prone to this problem.

let instTy = ProvidedTypeBuilder.MakeGenericType(genTy, [ myType ] ).FullName

However the underlying problem can still occur if type instances are constructed by the default MakeGenericType.

Workaround 2

Give up trying to make a .NET Standard 2.0 TPDTC and instead multi-target your TPDTC to both .NET Core App 2.0 and .NET Framework 4.5

Related information

Occurs only with the compiler running on .NET Core 2.0 or 2.1; running on .NET Framework succeeds, regardless of target framework.

Occurs with the standard F# compiler as well as with FCS (tested with versions 22 and 23).

Tested with FSharp.Core 4.2 and 4.3.

dsyme commented 6 years ago

@Tarmil At the moment I have no fix for this. I've emailed internally, we copy below.

The workaround is to use ProvidedTypeBuilder.MakeGenericType which constructs a type instance less prone to this problem.

    let fails = ProvidedTypeBuilder.MakeGenericType(genTy, [ myType ] ).FullName

However the underlying problem can still occur if type instances are constructed by the default MakeGenericType.


Internal email:

Last year we ran into an issue and a variation of it has come up again.

Background: The F# type provider architecture needing .NET Standard custom implementations of System.Type/MethodInfo/… However .NET Standard did not expose public/protected constructors to System.Type. The solution we eventually hit on was to inherit from TypeDelegator and reimplement all methods. This has worked so far.

However, this has run into a problem: .NET CoreApp 2.0 or 2.1 has introduced new virtual methods on TypeDelegator such as IsSZArray (see https://github.com/dotnet/coreclr/issues/1877) Like all other methods, the default implementations looks like this:

    public override bool IsSZArray => typeImpl.IsSZArray;

For other methods, we override and replace this implementation, which allows us to use TypeDelegator as a kind of backdoor to create custom implementations of System.Type. However, for this one we can’t do that since the IsSZArray contract isn’t in .NET Standard 2.0. As a result any code which uses IsSZArray on one of our System.Type is liable to loop.

This is causing this problem:

            https://github.com/fsprojects/FSharp.TypeProviders.SDK/issues/236

Three things

  1. Is there any way to work around this problem?
  2. Can we just make System.Type properly extensible please by exposing the protected constructor?
  3. Can we take extra care with TypeDelegator and add tests where we generate new System.Type implementations by extending TypeDelegator

If there is no workaround then as far as I can see this means .NET Standard 2.0 code can’t reliably extend System.Type.

Many thanks Don

dsyme commented 2 years ago

This problem is resolved by building the TPSDK as netstandard 2.1