fsharp icon indicating copy to clipboard operation
fsharp copied to clipboard

[Regression] `FsiEvaluationSession` can't find method in hosting assembly

Open brettfo opened this issue 2 years ago • 3 comments

A console app that uses FsiEvaluationSession can't execute a method defined in the console app. The behavior worked in FSharp.Compiler.Service version 41.0.2 and started to fail in version 41.0.3. I've traced the failure back to commit 45518d21e1e135693ad3d9d32744792ba151aef4 from #12722.

Full repro. N.b., the repro as given here passes and shows the output of

value: "3"

and if you simply update the FSharp.Compiler.Service package version to 41.0.3 then the output becomes:

exception: System.MissingMethodException: Method not found: 'System.Int32 FSharpMissingMethod.MyModule.add(System.Int32, System.Int32)'.
   at <StartupCode$FSI_0001>.$FSI_0001.main@()

Project.fsproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="MyModule.fs" />
    <Compile Include="Program.fs" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="FSharp.Compiler.Service" Version="41.0.2" />
  </ItemGroup>

</Project>

MyModule.fs:

namespace FSharpMissingMethod

type Sentinel () =
    let x = ()

module MyModule =
    let add a b = a + b

Program.fs:

module Main

open FSharp.Compiler.Interactive.Shell
open System.IO
open System.Threading

[<EntryPoint>]
let main args =

    let config = FsiEvaluationSession.GetDefaultConfiguration()
    let argv = [|
        typeof<FSharpMissingMethod.Sentinel>.Assembly.Location
        "--noninteractive"
        "--targetprofile:netcore"
        "--langversion:preview"
        "/usesdkrefs-"
        |]
    let fsi = FsiEvaluationSession.Create(config, argv, TextReader.Null, TextWriter.Null, TextWriter.Null)
    let assemblyPath = typeof<FSharpMissingMethod.Sentinel>.Assembly.Location.Replace("\\", "/")
    let code = $@"
#r ""{assemblyPath}""
FSharpMissingMethod.MyModule.add 1 2"
    let ch, errors = fsi.EvalInteractionNonThrowing(code, CancellationToken.None)
    errors
    |> Array.iter (fun e -> printfn "error: %A" e)
    match ch with
    | Choice1Of2 v ->
        let v =
            match v with
            | Some v -> sprintf "%A" v.ReflectionValue
            | None -> "(none)"
        printfn "value: %A" v
    | Choice2Of2 e -> printfn "exception: %A" e
    0

brettfo avatar May 25 '22 18:05 brettfo

@brettfo will adding --multiemit- to the FsiEvaluationSession's args work for you as a workaround, while we investigating? This will is pretty much a fallback to the "old" way of emitting assemblies.

vzarytovskii avatar Jun 28 '22 15:06 vzarytovskii

Indeed --multiemit- allows us to work around the issue for now.

brettfo avatar Jun 29 '22 22:06 brettfo

We have run into the same issue, and --multiemit- worked for us as well. Interestingly, it only happened once deployed via docker - running it on development machines (even using release builds) worked without that flag.

dlitty avatar Jul 07 '22 18:07 dlitty

The disadvantage of using --multiemit- is that you lose the error line number in stack traces of the script itself: Change the code to evaluate: let code = "1/0" the first run was using --multiemit- , the second not: image

Here is a discussion on that topic https://github.com/dotnet/fsharp/discussions/13293

goswinr avatar Aug 12 '22 12:08 goswinr