-
Notifications
You must be signed in to change notification settings - Fork 123
Description
I have been experimenting with dynamic assembly compilation and the results of my tests have been going really well, while I was launching the compiler from F# Interactive sessions.
However, when switching to a Visual Studio Command Line F# project with the FSharp.Compiler.Service 0.76 NuGet package (so I can move to building a production version) I am getting StackOverflowExceptions from infinite loops in the compiler service.
This occurs regardless of the code being compiled.
For example, creating a project with the Hosted Compiler example code results in the same StackOverflowException as my actual project code.
// Learn more about F# at http://fsharp.net
// See the 'F# Tutorial' project for more help.
open Microsoft.FSharp.Compiler.SimpleSourceCodeServices
open System.IO
let scs = SimpleSourceCodeServices()
[<EntryPoint>]
let main argv =
let fn = Path.GetTempFileName()
let fn2 = Path.ChangeExtension(fn, ".fs")
let fn3 = Path.ChangeExtension(fn, ".dll")
File.WriteAllText(fn2, """
module M
type C() =
member x.P = 1
let x = 3 + 4
""")
let errors2, exitCode2, dynAssembly2 =
scs.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], execute=None)
// return an integer exit code
0
I have traced the infinite loop to the following set of stack entries.
FSharp.Compiler.Service.dll!Microsoft.FSharp.Compiler.Build.TcImports.RegisterAndImportReferencedAssemblies(Microsoft.FSharp.Core.FSharpOption<Microsoft.FSharp.Core.FSharpFunc<string,Microsoft.FSharp.Core.Unit>> displayPSTypeProviderSecurityDialogBlockingUI, Microsoft.FSharp.Collections.FSharpList<Microsoft.FSharp.Compiler.Build.AssemblyResolution> nms) Line 4408 F#
FSharp.Compiler.Service.dll!Microsoft.FSharp.Compiler.Build.tryFile@4420(Microsoft.FSharp.Compiler.Build.TcImports tcImports, Microsoft.FSharp.Compiler.Range.range m, string speculativeFileName) Line 4425 F#
FSharp.Compiler.Service.dll!Microsoft.FSharp.Compiler.Build.TcImports.ImplicitLoadIfAllowed(Microsoft.FSharp.Compiler.Range.range m, string assemblyName, bool lookupOnly) Line 4431 F#
FSharp.Compiler.Service.dll!Microsoft.FSharp.Compiler.Build.TcImports.FindCcuInfo(Microsoft.FSharp.Compiler.Range.range m, string assemblyName, bool lookupOnly) Line 3806 F#
FSharp.Compiler.Service.dll!Microsoft.FSharp.Compiler.Build.RegisterAndPrepareToImportReferencedDll@4363.Invoke(Microsoft.FSharp.Core.Unit unitVar0) Line 4363 F#
FSharp.Compiler.Service.dll!Microsoft.FSharp.Compiler.Build.TcImports.RegisterAndImportReferencedAssemblies(Microsoft.FSharp.Core.FSharpOption<Microsoft.FSharp.Core.FSharpFunc<string,Microsoft.FSharp.Core.Unit>> displayPSTypeProviderSecurityDialogBlockingUI, Microsoft.FSharp.Collections.FSharpList<Microsoft.FSharp.Compiler.Build.AssemblyResolution> nms) Line 4408 F#
The relevant code is this, from build.fs around line 4414. assemblyName is "FSharp.Core"
member tcImports.ImplicitLoadIfAllowed (m, assemblyName, lookupOnly) =
CheckDisposed()
// If the user is asking for the default framework then also try to resolve other implicit assemblies as they are discovered.
// Using this flag to mean 'allow implicit discover of assemblies'.
let tcConfig = tcConfigP.Get()
if not lookupOnly && tcConfig.implicitlyResolveAssemblies then
let tryFile speculativeFileName =
let foundFile = tcImports.TryResolveAssemblyReference (AssemblyReference (m, speculativeFileName, None), ResolveAssemblyReferenceMode.Speculative)
match foundFile with
| OkResult (warns, res) ->
ReportWarnings warns
tcImports.DoRegisterAndImportReferencedAssemblies(None,res)
true
| ErrorResult (_warns, _err) ->
// Throw away warnings and errors - this is speculative loading
false
if tryFile (assemblyName + ".dll") then ()
else tryFile (assemblyName + ".exe") |> ignore
If there is something that I'm doing wrong here, it's not obvious to me.