dotnet / fsharp

The F# compiler, F# core library, F# language service, and F# tooling integration for Visual Studio
https://dotnet.microsoft.com/languages/fsharp
MIT License
3.91k stars 785 forks source link

fsi reference order matter #3600

Open enricosada opened 7 years ago

enricosada commented 7 years ago

scenario

User has a working project, and try to run some part in fsi, so:

  1. send the references to fsi, correctly
  2. evaluate some code => error
stdin(7,5): error FS0074: The type referenced through '<SomeClass>' is defined in an assembly that is not referenced. You must add a reference to assembly '<Assembly1>'.

but was already sent to fsi and referenced correctly.

The error happen if:

Repro

based on detailed repro of @chanjunweimy in https://github.com/ionide/ionide-vscode-fsharp/issues/539

#r @"<path_to>\mathnet.numerics.fsharp\3.20.0\lib\net40\MathNet.Numerics.FSharp.dll"
#r @"<path_to>\mathnet.numerics\3.20.0\lib\net40\MathNet.Numerics.dll"

if i try to

open MathNet.Numerics.LinearAlgebra;

let MatrixToRowSeqSeq matrix1 = 
    Matrix.toRowArrays matrix1
    |> Array.map Array.toSeq
    |> Array.toSeq

then fails.

If i invert the order or loading, so first MathNet.Numerics.dll and after MathNet.Numerics.FSharp.dll it succed.

As a note, fsc with same order build correctly

KevinRansom commented 7 years ago

@enricosada this is by design. FSI is really quite lazy about assembly references and tries very hard to delay going and getting them.

I tried quite hard to reproduce tour issue, and it was harder than I thought however, this is what I did.

Create 2 assemblies A and B

B has a dependency on A and 2 apis, one which uses the dependency, and one which does not.

Then I referenced B used the API that referenced A .. it failed with a type load. referenced A used the API that referenced A .. it still failed with a type load.

Then I reset the FSI session Then I referenced B used the API that doesnot reference A .. it worked referenced A used the API that referenced A .. it worked.

This shows that the failure is caused because FSI, remembers resolved assemblies, and caches them. But does not resolve assemblies unless it has to.

so:

R B

R A

should always work unless FSI has already tried and failed to resolve B.

I suppose we could do some work to re-resolve assemblies in this situation.

What do you think?

dsyme commented 7 years ago

@KevinRansom @enricosada I don't see any specific reason why this should fail (i.e. why we should regard this as by design) - both #r are known to FSI, we should surely be able to resolve these assemblies correctly.

haraldsteinlechner commented 4 years ago

hi,

what is the state of this matter? I have not seen this problem for a long time but now it popped up again. Getting the order right in, say paket generated load scripts is rather time consuming ;)

If there is no solution possible from fsi side, we could at least create a tool which automatically finds out the correct ordering.

cartermp commented 4 years ago

I think this is greatly alleviated by #r nuget:, since that will correctly reference transitive dependencies.

haraldsteinlechner commented 4 years ago

ok. when will #r nuget: arrive? is this the associated issue? https://github.com/fsharp/fslang-suggestions/issues/542

cartermp commented 4 years ago

.NET 5/F# 5 is when it'll ship, though it's already available in the .NET Kernel: https://github.com/dotnet/try/blob/master/NotebooksOnBinder.md

In fact I'd encourage moving away from FSI entirely and using the notebooks experience for interactive scripting since it's so much more powerful

haraldsteinlechner commented 4 years ago

in fact i was exactly working on notebooks and went away from official dotnet f# to IfSharp since i got weired input.fsx (7,6)-(7,29) typecheck error The type referenced through .... errors. i thought ok - maybe this is to "new" ;). so i arrived at lfSharp i was facing (different but similar) fsi troubles :D. i will checkout the kernel and create a repo for my original problem