The static constructor of DotNetFrameworkDependencies throws an ArgumentNullException when FSharp.Compiler.Service doesn't have a disk presence. This occurs when FSharp.Compiler.Service.dll is loaded directly into memory with Assembly.Load(byte[]); for instance, as is the case if you're using Microsoft's new single-file executable deployment feature in .NET Core.
The problem is in this line of code:
let fSharpCompilerLocation =
let location = Path.GetDirectoryName(typeof<TypeInThisAssembly>.Assembly.Location)
This evaluates to null when FSharp.Compiler.Service.dll doesn't have a disk presence, which then
causes an ArgumentNullException to be thrown when later calling Path.Combine:
let getDefaultFSharpCoreLocation = Path.Combine(fSharpCompilerLocation, getFSharpCoreLibraryName + ".dll")
The call to Path.Combine fails when fSharpCompilerLocation is null.
Note that this problem has just appeared in version 34 of FSharp.Compiler.Service. It did not occur in version 33.
@KevinRansom @jonsequitur looks like we have a regression
Note that LINQPad's F# support is locked at version 33 until this bug is fixed :)
Hmmm .... I'm actually not sure what to do about this. We use the heuristic, alongside the FSharp.Compiler dll to load assemblies quite frequently in the compiler. We use it specifically as the fall back to load FSharp.Core.dll, as well as loading the package manager in .fsi. I guess we will need a more complete heuristic ....
I'm also waiting this bug to be fixed
link to: https://forum.linqpad.net/discussion/2289/linqpad-support-for-f-5
Angetha and Anna-Frid are saying: gimme, gimme, gimme LinqPad after F#5. Won't somebody help me chase this bug away?
Also here because I'm missing F#5 support in LINQPad. LINQPad is how I gain fluency in new language features before I try "speaking them in production", and I'm not currently, well, fluent.
This occurs when FSharp.Compiler.Service.dll is loaded directly into memory with Assembly.Load(byte[]); for instance, as is the case if you're using Microsoft's new single-file executable deployment feature in .NET Core.
@albahari Where would we expect FSharp.Core.dll to be resolved from in this case? Are you also expecting an in-memory load of that assembly, or will you have the nuget pckage available, or will you be providing the -r:...FSharp.Core.dll arguments explicitly, or will you be relying on .NET SDK resolution (which uses a nuget package)?
In version 33, it resolved using typeof
So I guess the request is to never use
let fSharpCompilerLocation =
let location = Path.GetDirectoryName(typeof<TypeInThisAssembly>.Assembly.Location)
but rather use typeof<Microsoft.FSharp.Core.Unit>.Assembly.Location as the backup for FSHarp.COre.
Hmmmm I don't see anythying wrong with this. I'll look to see if we can make the change
@dsyme, when the assembly is in memory location throws. So that is probably the issue.
@dsyme,
| typeof
That's very cunning but probably won't work well on the coreclr, since there is no guarantee that the FSharp.Core is alongside the compiler. Which I know is bizzarre, but remember this is the last chance fall back and very dektop framework centered. On the coreclr, for most apps the location of FSharp.Core is going to be the nuget cache.
\
So I guess the request is to never use
let fSharpCompilerLocation = let location = Path.GetDirectoryName(typeof<TypeInThisAssembly>.Assembly.Location)but rather use
typeof<Microsoft.FSharp.Core.Unit>.Assembly.Locationas the backup for FSHarp.COre.Hmmmm I don't see anythying wrong with this. I'll look to see if we can make the change
How about:
Path.GetDirectoryName(typeof<TypeInThisAssembly>.Assembly.Location) |> ifEmptyUse typeof<Microsoft.FSharp.Core.Unit>.Assembly.Location
Then you won't break anything.
@albahari, so we use it to find the default location of two files.
The thing is that the reason for the exception is that fcs was loaded from memory, which isn't a scenario it was designed for that whole code is about groveling the file system for the locations of files on disk. We need to figure out how we want to handle that scenario probably the best thing to do would be to fire an event asking for some help from the app host - the thing that loaded fcs. We can clearly make something work, it's just relatively simple code, but ... we want to know whether we want to keep the scenario working for ever.
May I ask why you are loading FCS from an in-memory assembly, and why are you satisfied with other dependencies being loaded from disk?
A good answer is because it's executable code.
FCS doesn't ship with : FSharp.Compiler.Interactive.Settings so it can't really hurt not to find it in this scenario. So I expect we can go with something close to your proposal.
Most helpful comment
I'm also waiting this bug to be fixed
link to: https://forum.linqpad.net/discussion/2289/linqpad-support-for-f-5