Skip to content

Take the current index into account in the QueryTrieNodeResult. #16085

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

Merged
merged 3 commits into from
Oct 10, 2023
Merged
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
27 changes: 16 additions & 11 deletions src/Compiler/Driver/GraphChecking/DependencyResolution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,33 @@ let queryTriePartial (trie: TrieNode) (path: LongIdentifier) : TrieNode option =

visit trie path

let mapNodeToQueryResult (node: TrieNode option) : QueryTrieNodeResult =
let mapNodeToQueryResult (currentFileIndex: FileIndex) (node: TrieNode option) : QueryTrieNodeResult =
match node with
| Some finalNode ->
if Set.isEmpty finalNode.Files then
if
Set.isEmpty finalNode.Files
// If this node exposes files which the current index cannot see, we consider it not to have data at all.
|| Set.forall (fun idx -> idx >= currentFileIndex) finalNode.Files
then
QueryTrieNodeResult.NodeDoesNotExposeData
else
QueryTrieNodeResult.NodeExposesData(finalNode.Files)
| None -> QueryTrieNodeResult.NodeDoesNotExist

/// <summary>Find a path in the Trie.</summary>
let queryTrie (trie: TrieNode) (path: LongIdentifier) : QueryTrieNodeResult =
queryTriePartial trie path |> mapNodeToQueryResult
let queryTrie (currentFileIndex: FileIndex) (trie: TrieNode) (path: LongIdentifier) : QueryTrieNodeResult =
queryTriePartial trie path |> mapNodeToQueryResult currentFileIndex

/// <summary>Same as 'queryTrie' but allows passing in a path combined from two parts, avoiding list allocation.</summary>
let queryTrieDual (trie: TrieNode) (path1: LongIdentifier) (path2: LongIdentifier) : QueryTrieNodeResult =
let queryTrieDual (currentFileIndex: FileIndex) (trie: TrieNode) (path1: LongIdentifier) (path2: LongIdentifier) : QueryTrieNodeResult =
match queryTriePartial trie path1 with
| Some intermediateNode -> queryTriePartial intermediateNode path2
| None -> None
|> mapNodeToQueryResult
|> mapNodeToQueryResult currentFileIndex

/// Process namespace declaration.
let processNamespaceDeclaration (trie: TrieNode) (path: LongIdentifier) (state: FileContentQueryState) : FileContentQueryState =
let queryResult = queryTrie trie path
let queryResult = queryTrie state.CurrentFile trie path

match queryResult with
| QueryTrieNodeResult.NodeDoesNotExist -> state
Expand All @@ -49,7 +53,7 @@ let processNamespaceDeclaration (trie: TrieNode) (path: LongIdentifier) (state:
/// Process an "open" statement.
/// The statement could link to files and/or should be tracked as an open namespace.
let processOpenPath (trie: TrieNode) (path: LongIdentifier) (state: FileContentQueryState) : FileContentQueryState =
let queryResult = queryTrie trie path
let queryResult = queryTrie state.CurrentFile trie path

match queryResult with
| QueryTrieNodeResult.NodeDoesNotExist -> state
Expand Down Expand Up @@ -99,12 +103,13 @@ let rec processStateEntry (trie: TrieNode) (state: FileContentQueryState) (entry
||> Array.fold (fun state takeParts ->
let path = List.take takeParts path
// process the name was if it were a FQN
let stateAfterFullIdentifier = processIdentifier (queryTrieDual trie [] path) state
let stateAfterFullIdentifier =
processIdentifier (queryTrieDual state.CurrentFile trie [] path) state

// Process the name in combination with the existing open namespaces
(stateAfterFullIdentifier, state.OpenNamespaces)
||> Set.fold (fun acc openNS ->
let queryResult = queryTrieDual trie openNS path
let queryResult = queryTrieDual state.CurrentFile trie openNS path
processIdentifier queryResult acc))

| FileContentEntry.NestedModule (nestedContent = nestedContent) ->
Expand Down Expand Up @@ -137,7 +142,7 @@ let collectGhostDependencies (fileIndex: FileIndex) (trie: TrieNode) (result: Fi
// For each opened namespace, if none of already resolved dependencies define it, return the top-most file that defines it.
Set.toArray result.OpenedNamespaces
|> Array.choose (fun path ->
match queryTrie trie path with
match queryTrie fileIndex trie path with
| QueryTrieNodeResult.NodeExposesData _
| QueryTrieNodeResult.NodeDoesNotExist -> None
| QueryTrieNodeResult.NodeDoesNotExposeData ->
Expand Down
7 changes: 5 additions & 2 deletions src/Compiler/Driver/GraphChecking/DependencyResolution.fsi
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
/// Logic for constructing a file dependency graph for the purposes of parallel type-checking.
module internal FSharp.Compiler.GraphChecking.DependencyResolution

/// <summary>Query a TrieNode to find a certain path.</summary>
/// <summary>
/// Query a TrieNode to find a certain path.
/// The result will take the current file index into account to determine if the result node contains data.
/// </summary>
/// <remarks>This code is only used directly in unit tests.</remarks>
val queryTrie: trie: TrieNode -> path: LongIdentifier -> QueryTrieNodeResult
val queryTrie: currentFileIndex: FileIndex -> trie: TrieNode -> path: LongIdentifier -> QueryTrieNodeResult

/// <summary>Process an open path (found in the ParsedInput) with a given FileContentQueryState.</summary>
/// <remarks>This code is only used directly in unit tests.</remarks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -762,15 +762,15 @@ let private fantomasCoreTrie: TrieNode =
[<Test>]
let ``Query non existing node in trie`` () =
let result =
queryTrie fantomasCoreTrie [ "System"; "System"; "Runtime"; "CompilerServices" ]
queryTrie 7 fantomasCoreTrie [ "System"; "System"; "Runtime"; "CompilerServices" ]

match result with
| QueryTrieNodeResult.NodeDoesNotExist -> Assert.Pass()
| result -> Assert.Fail $"Unexpected result: %A{result}"

[<Test>]
let ``Query node that does not expose data in trie`` () =
let result = queryTrie fantomasCoreTrie [ "Fantomas"; "Core" ]
let result = queryTrie 7 fantomasCoreTrie [ "Fantomas"; "Core" ]

match result with
| QueryTrieNodeResult.NodeDoesNotExposeData -> Assert.Pass()
Expand All @@ -779,7 +779,7 @@ let ``Query node that does not expose data in trie`` () =
[<Test>]
let ``Query module node that exposes one file`` () =
let result =
queryTrie fantomasCoreTrie [ "Fantomas"; "Core"; "ISourceTextExtensions" ]
queryTrie 7 fantomasCoreTrie [ "Fantomas"; "Core"; "ISourceTextExtensions" ]

match result with
| QueryTrieNodeResult.NodeExposesData file ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,28 @@ module S
let main _ =
F.br ()
0
"""
(set [| 0 |])
]
scenario
"Ghost dependency via top-level namespace"
[
sourceFile
"Graph.fs"
"""
namespace Graphoscope.Graph

type UndirectedGraph = obj
"""
Set.empty
sourceFile
"DiGraph.fs"
"""
namespace Graphoscope

open Graphoscope

type DiGraph = obj
"""
(set [| 0 |])
]
Expand Down