Skip to content

Fix #18441 #18459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 92 additions & 102 deletions src/Compiler/Interactive/fsi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2415,15 +2415,9 @@ type internal FsiDynamicCompiler

member _.DynamicAssemblies = dynamicAssemblies.ToArray()

member _.FindDynamicAssembly(name, useFullName: bool) =
let getName (assemblyName: AssemblyName) : string MaybeNull =
if useFullName then
assemblyName.FullName
else
assemblyName.Name

member _.FindDynamicAssembly(assemblyName: AssemblyName) =
dynamicAssemblies
|> ResizeArray.tryFind (fun asm -> getName (asm.GetName()) = name)
|> ResizeArray.tryFind (fun asm -> asm.FullName = assemblyName.FullName)

member _.EvalParsedSourceFiles(ctok, diagnosticsLogger, istate, inputs, m) =
let prefix = mkFragmentPath m nextFragmentId
Expand Down Expand Up @@ -3274,7 +3268,8 @@ type internal MagicAssemblyResolution() =
try
// Grab the name of the assembly
let tcConfig = TcConfig.Create(tcConfigB, validate = false)
let simpleAssemName = fullAssemName.Split([| ',' |]).[0]
let assemblyName = AssemblyName(fullAssemName)
let simpleAssemName = !!assemblyName.Name

if progress then
fsiConsoleOutput.uprintfn "ATTEMPT MAGIC LOAD ON ASSEMBLY, simpleAssemName = %s" simpleAssemName // "Attempting to load a dynamically required assembly in response to an AssemblyResolve event by using known static assembly references..."
Expand All @@ -3286,128 +3281,123 @@ type internal MagicAssemblyResolution() =
null
else
// Check dynamic assemblies by exact version
match fsiDynamicCompiler.FindDynamicAssembly(fullAssemName, true) with
match fsiDynamicCompiler.FindDynamicAssembly(assemblyName) with
| Some asm -> asm
| None ->
// Check dynamic assemblies by simple name
match fsiDynamicCompiler.FindDynamicAssembly(simpleAssemName, false) with
| Some asm when not (tcConfigB.fsiMultiAssemblyEmit) -> asm
| _ ->
// Otherwise continue
let assemblyReferenceTextDll = (simpleAssemName + ".dll")
let assemblyReferenceTextExe = (simpleAssemName + ".exe")

// Otherwise continue
let assemblyReferenceTextDll = (simpleAssemName + ".dll")
let assemblyReferenceTextExe = (simpleAssemName + ".exe")
let overallSearchResult =

let overallSearchResult =
// OK, try to resolve as an existing DLL in the resolved reference set. This does unification by assembly name
// once an assembly has been referenced.
let searchResult =
tcImports.TryFindExistingFullyQualifiedPathBySimpleAssemblyName simpleAssemName

// OK, try to resolve as an existing DLL in the resolved reference set. This does unification by assembly name
// once an assembly has been referenced.
match searchResult with
| Some r -> OkResult([], Choice1Of2 r)
| _ ->

// OK, try to resolve as a .dll
let searchResult =
tcImports.TryFindExistingFullyQualifiedPathBySimpleAssemblyName simpleAssemName
tcImports.TryResolveAssemblyReference(
ctok,
AssemblyReference(m, assemblyReferenceTextDll, None),
ResolveAssemblyReferenceMode.Speculative
)

match searchResult with
| Some r -> OkResult([], Choice1Of2 r)
| OkResult(warns, [ r ]) -> OkResult(warns, Choice1Of2 r.resolvedPath)
| _ ->

// OK, try to resolve as a .dll
// OK, try to resolve as a .exe
let searchResult =
tcImports.TryResolveAssemblyReference(
ctok,
AssemblyReference(m, assemblyReferenceTextDll, None),
AssemblyReference(m, assemblyReferenceTextExe, None),
ResolveAssemblyReferenceMode.Speculative
)

match searchResult with
| OkResult(warns, [ r ]) -> OkResult(warns, Choice1Of2 r.resolvedPath)
| _ ->

// OK, try to resolve as a .exe
if progress then
fsiConsoleOutput.uprintfn "ATTEMPT LOAD, assemblyReferenceTextDll = %s" assemblyReferenceTextDll

/// Take a look through the files quoted, perhaps with explicit paths
let searchResult =
tcImports.TryResolveAssemblyReference(
ctok,
AssemblyReference(m, assemblyReferenceTextExe, None),
ResolveAssemblyReferenceMode.Speculative
)
tcConfig.referencedDLLs
|> List.tryPick (fun assemblyReference ->
if progress then
fsiConsoleOutput.uprintfn
"ATTEMPT MAGIC LOAD ON FILE, referencedDLL = %s"
assemblyReference.Text

if
String.Compare(
FileSystemUtils.fileNameOfPath assemblyReference.Text,
assemblyReferenceTextDll,
StringComparison.OrdinalIgnoreCase
) = 0
|| String.Compare(
FileSystemUtils.fileNameOfPath assemblyReference.Text,
assemblyReferenceTextExe,
StringComparison.OrdinalIgnoreCase
) = 0
then
Some(
tcImports.TryResolveAssemblyReference(
ctok,
assemblyReference,
ResolveAssemblyReferenceMode.Speculative
)
)
else
None)

match searchResult with
| OkResult(warns, [ r ]) -> OkResult(warns, Choice1Of2 r.resolvedPath)
| Some(OkResult(warns, [ r ])) -> OkResult(warns, Choice1Of2 r.resolvedPath)
| _ ->

if progress then
fsiConsoleOutput.uprintfn "ATTEMPT LOAD, assemblyReferenceTextDll = %s" assemblyReferenceTextDll

/// Take a look through the files quoted, perhaps with explicit paths
let searchResult =
tcConfig.referencedDLLs
|> List.tryPick (fun assemblyReference ->
if progress then
fsiConsoleOutput.uprintfn
"ATTEMPT MAGIC LOAD ON FILE, referencedDLL = %s"
assemblyReference.Text

if
String.Compare(
FileSystemUtils.fileNameOfPath assemblyReference.Text,
assemblyReferenceTextDll,
StringComparison.OrdinalIgnoreCase
) = 0
|| String.Compare(
FileSystemUtils.fileNameOfPath assemblyReference.Text,
assemblyReferenceTextExe,
StringComparison.OrdinalIgnoreCase
) = 0
then
Some(
tcImports.TryResolveAssemblyReference(
ctok,
assemblyReference,
ResolveAssemblyReferenceMode.Speculative
)
)
else
None)

match searchResult with
| Some(OkResult(warns, [ r ])) -> OkResult(warns, Choice1Of2 r.resolvedPath)
| _ ->

#if !NO_TYPEPROVIDERS
match tcImports.TryFindProviderGeneratedAssemblyByName(ctok, simpleAssemName) with
| Some assembly -> OkResult([], Choice2Of2 assembly)
| None ->
match tcImports.TryFindProviderGeneratedAssemblyByName(ctok, simpleAssemName) with
| Some assembly -> OkResult([], Choice2Of2 assembly)
| None ->
#endif

// As a last resort, try to find the reference without an extension
match
tcImports.TryFindExistingFullyQualifiedPathByExactAssemblyRef(
ILAssemblyRef.Create(simpleAssemName, None, None, false, None, None)
)
with
| Some resolvedPath -> OkResult([], Choice1Of2 resolvedPath)
| None ->

ErrorResult([], Failure(FSIstrings.SR.fsiFailedToResolveAssembly (simpleAssemName)))

match overallSearchResult with
| ErrorResult _ -> null
| OkResult _ ->
let res = CommitOperationResult overallSearchResult

match res with
| Choice1Of2 assemblyName ->
if simpleAssemName <> "Mono.Posix" && progress then
fsiConsoleOutput.uprintfn "%s" (FSIstrings.SR.fsiBindingSessionTo (assemblyName))

if isRunningOnCoreClr then
// As a last resort, try to find the reference without an extension
match
tcImports.TryFindExistingFullyQualifiedPathByExactAssemblyRef(
ILAssemblyRef.Create(simpleAssemName, None, None, false, None, None)
)
with
| Some resolvedPath -> OkResult([], Choice1Of2 resolvedPath)
| None ->

ErrorResult([], Failure(FSIstrings.SR.fsiFailedToResolveAssembly (simpleAssemName)))

match overallSearchResult with
| ErrorResult _ -> null
| OkResult _ ->
let res = CommitOperationResult overallSearchResult

match res with
| Choice1Of2 assemblyName ->
if simpleAssemName <> "Mono.Posix" && progress then
fsiConsoleOutput.uprintfn "%s" (FSIstrings.SR.fsiBindingSessionTo (assemblyName))

if isRunningOnCoreClr then
assemblyLoadFrom assemblyName
else
try
let an = AssemblyName.GetAssemblyName(assemblyName)
an.CodeBase <- assemblyName
Assembly.Load an
with _ ->
assemblyLoadFrom assemblyName
else
try
let an = AssemblyName.GetAssemblyName(assemblyName)
an.CodeBase <- assemblyName
Assembly.Load an
with _ ->
assemblyLoadFrom assemblyName
| Choice2Of2 assembly -> assembly
| Choice2Of2 assembly -> assembly

with e ->
stopProcessingRecovery e range0
Expand Down
23 changes: 16 additions & 7 deletions tests/FSharp.Compiler.ComponentTests/Scripting/Interactive.fs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ module ``Interactive tests`` =
]

[<Theory>]
[<InlineData(true)>]
[<InlineData(false)>]
let ``Evaluation of multiple sessions should succeed`` (useMultiEmit) =
[<InlineData(true, true)>]
[<InlineData(false, false)>]
[<InlineData(false, true)>]
let ``Evaluation of multiple sessions should succeed`` (useMultiEmit1, useMultiEmit2) =

let args : string array = [| if useMultiEmit then "--multiemit+" else "--multiemit-"|]
use sessionOne = new FSharpScript(additionalArgs=args)
use sessionTwo = new FSharpScript(additionalArgs=args)
let args useMultiEmit : string array = [| if useMultiEmit then "--multiemit+" else "--multiemit-"|]
use sessionOne = new FSharpScript(additionalArgs = args useMultiEmit1)
use sessionTwo = new FSharpScript(additionalArgs = args useMultiEmit2)

sessionOne.Eval("""
module Test1 =
Expand All @@ -63,6 +64,15 @@ module Test2 =
Assert.Equal(typeof<string>, value2.ReflectionType)
Assert.Equal("Execute - Test2.test2 - 27", value2.ReflectionValue :?> string)

[<Theory>]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks more like a bcl test case than one interesting to us.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I'll remove it.

[<InlineData(true)>]
[<InlineData(false)>]
let ``Currently executing dynamic assembly can be resolved by full name`` useMultiEmit =
let args = [| if useMultiEmit then "--multiemit+" else "--multiemit-" |]
use session = new FSharpScript(additionalArgs = args)
let fullNameResult = session.Eval("""System.Reflection.Assembly.GetExecutingAssembly().FullName""") |> getValue
System.Reflection.Assembly.Load(string fullNameResult.Value.ReflectionValue) |> ignore

module ``External FSI tests`` =
[<Fact>]
let ``Eval object value``() =
Expand All @@ -76,7 +86,6 @@ module ``External FSI tests`` =
|> runFsi
|> shouldFail


[<Fact>]
let ``Internals visible over a large number of submissions``() =
let submission =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
[IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000065][found Char] Unexpected type on the stack.
[IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x00000082][found Char] Unexpected type on the stack.
[IL]: Error [StackUnexpected]: : FSharp.Compiler.CodeAnalysis.Hosted.CompilerHelpers::fscCompile([FSharp.Compiler.Service]FSharp.Compiler.CodeAnalysis.LegacyReferenceResolver, string, string[])][offset 0x0000008B][found Char] Unexpected type on the stack.
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+MagicAssemblyResolution::ResolveAssemblyCore([FSharp.Compiler.Service]Internal.Utilities.Library.CompilationThreadToken, [FSharp.Compiler.Service]FSharp.Compiler.Text.Range, [FSharp.Compiler.Service]FSharp.Compiler.CompilerConfig+TcConfigBuilder, [FSharp.Compiler.Service]FSharp.Compiler.CompilerImports+TcImports, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiDynamicCompiler, [FSharp.Compiler.Service]FSharp.Compiler.Interactive.Shell+FsiConsoleOutput, string)][offset 0x00000015][found Char] Unexpected type on the stack.
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3502-805::Invoke([S.P.CoreLib]System.Tuple`3<char[],int32,int32>)][offset 0x000001E5][found Char] Unexpected type on the stack.
[IL]: Error [StackUnexpected]: : FSharp.Compiler.Interactive.Shell+clo@3492-805::Invoke([S.P.CoreLib]System.Tuple`3<char[],int32,int32>)][offset 0x000001E5][found Char] Unexpected type on the stack.
[IL]: Error [UnmanagedPointer]: : FSharp.Compiler.Interactive.Shell+Utilities+pointerToNativeInt@110::Invoke(object)][offset 0x00000007] Unmanaged pointers are not a verifiable type.
[IL]: Error [StackUnexpected]: : <StartupCode$FSharp-Compiler-Service>.$FSharpCheckerResults+dataTipOfReferences@2225::Invoke([FSharp.Core]Microsoft.FSharp.Core.Unit)][offset 0x00000084][found Char] Unexpected type on the stack.
[IL]: Error [StackUnexpected]: : <StartupCode$FSharp-Compiler-Service>.$ServiceLexing+clo@921-509::Invoke([FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<System.Tuple`3<FSharp.Compiler.Parser+token,int32,int32>,Microsoft.FSharp.Core.Unit>)][offset 0x00000032][found Char] Unexpected type on the stack.
Expand Down
Loading
Loading