diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md index 3d4288458c9..36abbb99f5d 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md @@ -9,6 +9,7 @@ * Compiler fails to recognise namespace in FQN with enabled GraphBasedChecking. ([Issue #17508](https://github.com/dotnet/fsharp/issues/17508), [PR #17510](https://github.com/dotnet/fsharp/pull/17510)) * Fix missing message for type error (FS0001). ([Issue #17373](https://github.com/dotnet/fsharp/issues/17373), [PR #17516](https://github.com/dotnet/fsharp/pull/17516)) * MethodAccessException on equality comparison of a type private to module. ([Issue #17541](https://github.com/dotnet/fsharp/issues/17541), [PR #17548](https://github.com/dotnet/fsharp/pull/17548)) +* Fixed checking failure when `global` namespace is involved with enabled GraphBasedChecking ([PR #17553](https://github.com/dotnet/fsharp/pull/17553)) ### Added diff --git a/src/Compiler/Driver/GraphChecking/DependencyResolution.fs b/src/Compiler/Driver/GraphChecking/DependencyResolution.fs index 11ba984ca51..1425ec0f9ed 100644 --- a/src/Compiler/Driver/GraphChecking/DependencyResolution.fs +++ b/src/Compiler/Driver/GraphChecking/DependencyResolution.fs @@ -117,7 +117,7 @@ let rec processStateEntry (trie: TrieNode) (state: FileContentQueryState) (entry FoundDependencies = foundDependencies } - | ModuleName name -> + | FileContentEntry.ModuleName name -> // We need to check if the module name is a hit in the Trie. let state' = let queryResult = queryTrie trie [ name ] diff --git a/src/Compiler/Driver/GraphChecking/FileContentMapping.fs b/src/Compiler/Driver/GraphChecking/FileContentMapping.fs index 13ee0c312f9..c1f6ce8ddb4 100644 --- a/src/Compiler/Driver/GraphChecking/FileContentMapping.fs +++ b/src/Compiler/Driver/GraphChecking/FileContentMapping.fs @@ -9,6 +9,13 @@ type Continuations = ((FileContentEntry list -> FileContentEntry list) -> FileCo let collectFromOption (mapping: 'T -> 'U list) (t: 'T option) : 'U list = List.collect mapping (Option.toList t) let longIdentToPath (skipLast: bool) (longId: LongIdent) : LongIdentifier = + + // We always skip the "special" `global` identifier. + let longId = + match longId with + | h :: t when h.idText = "`global`" -> t + | _ -> longId + match skipLast, longId with | true, _ :: _ -> List.take (longId.Length - 1) longId | _ -> longId diff --git a/src/Compiler/Driver/GraphChecking/Types.fs b/src/Compiler/Driver/GraphChecking/Types.fs index c667a573f69..7443df58204 100644 --- a/src/Compiler/Driver/GraphChecking/Types.fs +++ b/src/Compiler/Driver/GraphChecking/Types.fs @@ -61,6 +61,7 @@ type internal TrieNode = /// A significant construct found in the syntax tree of a file. /// This construct needs to be processed in order to deduce potential links to other files in the project. +[] type internal FileContentEntry = /// Any toplevel namespace a file might have. /// In case a file has `module X.Y.Z`, then `X.Y` is considered to be the toplevel namespace diff --git a/src/Compiler/Driver/GraphChecking/Types.fsi b/src/Compiler/Driver/GraphChecking/Types.fsi index 096719b6be7..5f075a1bad7 100644 --- a/src/Compiler/Driver/GraphChecking/Types.fsi +++ b/src/Compiler/Driver/GraphChecking/Types.fsi @@ -55,6 +55,7 @@ type internal TrieNode = /// A significant construct found in the syntax tree of a file. /// This construct needs to be processed in order to deduce potential links to other files in the project. +[] type internal FileContentEntry = /// Any toplevel namespace a file might have. /// In case a file has `module X.Y.Z`, then `X.Y` is considered to be the toplevel namespace diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/CompilationTests.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/CompilationTests.fs index 829810f3eea..14244f46ad8 100644 --- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/CompilationTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/CompilationTests.fs @@ -2,7 +2,7 @@ open FSharp.Test open FSharp.Test.Compiler -open NUnit.Framework +open Xunit; open Scenarios [] @@ -44,12 +44,14 @@ let compileAValidScenario (scenario: Scenario) (method: Method) = |> shouldSucceed |> ignore -let scenarios = codebases +let scenarios = codebases |> List.map (fun c -> [| box c |]) |> Array.ofList -[] -let ``Compile a valid scenario using graph-based type-checking`` (scenario: Scenario) = +[] +[] +let ``Compile a valid scenario using graph-based type-checking`` (scenario) = compileAValidScenario scenario Method.Graph -[] -let ``Compile a valid scenario using sequential type-checking`` (scenario: Scenario) = +[] +[] +let ``Compile a valid scenario using sequential type-checking`` (scenario) = compileAValidScenario scenario Method.Sequential diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/QueryTrieTests.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/QueryTrieTests.fs index e6fd44a3505..8a3b903e16c 100644 --- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/QueryTrieTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/QueryTrieTests.fs @@ -36,7 +36,7 @@ let private nestedModule name content = let private prefIdent (lid: string) = let parts = lid.Split(".") - Array.take (parts.Length - 1) parts |> List.ofArray |> PrefixedIdentifier + Array.take (parts.Length - 1) parts |> List.ofArray |> FileContentEntry.PrefixedIdentifier // Some hardcoded files that reflect the file content of the first files in the Fantomas.Core project. // See https://github.com/fsprojects/fantomas/tree/0938a3daabec80a22d2e17f82aba38456bb793df/src/Fantomas.Core diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/Scenarios.fs b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/Scenarios.fs index fe0c270edc5..6ab98da50eb 100644 --- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/Scenarios.fs +++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/Scenarios.fs @@ -256,7 +256,7 @@ module Y.C // This open statement does not do anything. // It can safely be removed, but because of its presence we need to link it to something that exposes the namespace X. -// We try and pick the file with the lowest index +// We try and pick the file with the lowest index open X let c = 0 @@ -572,7 +572,7 @@ type Bar() = static member Foo () : unit = failwith "" -let Foo () : unit = +let Foo () : unit = Bar.Foo () """ (set [| 0 |]) @@ -792,7 +792,7 @@ open My.Great.Namespace type Foo = class end """ (set [| 0 |]) - + sourceFile "Program" """ @@ -897,7 +897,7 @@ do """ (set [| 0 |]) ] - + scenario "parentheses around module name in nameof expression" [ @@ -1042,4 +1042,52 @@ type Bar(foo: MyRootNamespace.A.Foo, s: string) = class end """ (set [| 0 |]) ] + scenario + "Library with using global namespace" + [ + sourceFile + "Library.fs" + """ +namespace Lib +module File1 = + let mutable discState = System.DateTime.Now + +module File2 = + [] + type DiscState(rep : int) = + member this.Rep = rep + + let mutable discState = DiscState(0) + """ + Set.empty + sourceFile + "App.fs" + """ +module X +let v = global.Lib.File1.discState.Second +let v2 = global.Lib.File2.discState.Rep + """ + (set [| 0 |]) + ] + scenario + "Library with using global namespace as module alias" + [ + sourceFile + "Library.fs" + """ +namespace Z + +module N = + let mutable discState = System.DateTime.Now + """ + Set.empty + sourceFile + "App.fs" + """ +module X + +module Y = global.Z.N + """ + (set [| 0 |]) + ] ] \ No newline at end of file