ionide / ionide-vscode-fsharp

VS Code plugin for F# development
http://ionide.io
MIT License
859 stars 277 forks source link

FSI only shows "Error: An index satisfying the predicate was not found in the collection." for local values #1711

Closed jcmrva closed 2 years ago

jcmrva commented 2 years ago

Description

When an FSI session is started by sending code from a file (fs or fsx), values are replaced with "Error: An index satisfying the predicate was not found in the collection."

Steps to reproduce

  1. Select a complete line of code.
  2. Use Alt+Enter or Send Selection in the command palette.

example.fs

let x = 1

fsi

> let x = 1;;     
val x: int =
  Error: An index satisfying the predicate was not found in the collection.

Expected behaviour

Value appears as expected, e.g.

> let x = 1;;     
val x: int = 1

Machine info

Additional context

The most recent change was updating to SDK 6.0.300 so I suspect that's the culprit. I have SDK 7 preview 4 on another machine and the error does not occur there.

I'm not able to reproduce this in VS, Rider, or an FSI session started with dotnet fsi (terminal or within VS Code).

baronfel commented 2 years ago

I repro on Windows, would be interested in seeing if it repros on MaOS or Linux

jcmrva commented 2 years ago

Pretty sure I've identified the cause, going to see if I can fix it.

baronfel commented 2 years ago

Heck yeah! Let me know if you need any guidance.

jcmrva commented 2 years ago

Quick fix: turn off FSI Watcher and restart VS Code. (the setting doesn't say to restart but it appears necessary)

It bombs on this line: https://github.com/ionide/ionide-vscode-fsharp/blob/6c0a9e7e34d279f9dd6541db421b30501a3231b4/release/watcher/watcher.fsx#L4

...because there are tons of them:

FSI-ASSEMBLY1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null; FSI-ASSEMBLY2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null; FSI-ASSEMBLY3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null; FSI-ASSEMBLY4, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null; FSI-ASSEMBLY5, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null; FSI-ASSEMBLY6, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null; FSI-ASSEMBLY7, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null; FSI-ASSEMBLY8, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null; FSI-ASSEMBLY9, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null; FSI-ASSEMBLY10, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null;

Possibly related to this bit of weirdness:

   CustomAttributes = seq
                        [[System.Runtime.CompilerServices.InternalsVisibleToAttribute("FSI-ASSEMBLY5")];
                         [System.Runtime.CompilerServices.InternalsVisibleToAttribute("FSI-ASSEMBLY6")];
                         [System.Runtime.CompilerServices.InternalsVisibleToAttribute("FSI-ASSEMBLY7")];
                         [System.Runtime.CompilerServices.InternalsVisibleToAttribute("FSI-ASSEMBLY8")];
                         ...];

They proliferate like tribbles: I had 14, opened a new FSI in the terminal, and they jumped to 38.

Also, I was wrong about SDK 7 preview 4, I just didn't have the watcher on. I did test this on my linux machine which is still on 6.0.1 and the error does not occur.

Any known behavior change to System.AppDomain.CurrentDomain.GetAssemblies() ?

I'm stuck at this point:

baronfel commented 2 years ago

Oh, this is probably related to the FSI evaluation changes that Don did - the FSI-ASSEMBLY is no longer one assembly, it's a series of chained assemblies that is added to. so the watcher would need to change to do it's scraping across all of those assemblies.

Ref: https://github.com/dotnet/fsharp/pull/12722

jcmrva commented 2 years ago

Oh yeah, that must be it.

I tried adding --multiemit to the FSI extra parameters just now but it didn't make a difference.

jcmrva commented 2 years ago

If each interaction creates a new assembly, is it correct to assume the existing ones never change? Then the watcher should only need to lazily search the new one on each update.

baronfel commented 2 years ago

yeah, that should be correct. One caveat there is that shadowing is done via the new binding being in the new assembly, so you may need to do a pass to update the values of existing binding names based on the values in the newest FSI assembly.

jcmrva commented 2 years ago

As I work through this, it seems like I could add a "step counter" to show the number of interactions & a (shadowed) label on those bindings, rather than just hiding/updating them. Could be useful in long-running sessions. Thoughts?

baronfel commented 2 years ago

That seems like a reasonable thing to do. We can maybe have a flag in the config for the watcher that will let the user show/hide the shadowed entries, but that can come after a first implementation.

saebs commented 2 years ago

Any solutions on this. I have little experience with F# , picking it up again after a long while.

jcmrva commented 2 years ago

Hi @saebs - the immediate solution is to turn off the FSI watcher in the settings. I've made some progress with the update & should be making a PR within a few days.

saebs commented 2 years ago

Alright thanks

Wallace-Kelly commented 2 years ago

For those of us that need a little more hand-holding, the quick fix is...

image

jcmrva commented 2 years ago

The update for this has been released.