Skip to content

Commit

Permalink
Use indexes in TrieNodeInfo, consider auto open modules and do some s…
Browse files Browse the repository at this point in the history
…tricter checks in the TypedTreeGraph.
  • Loading branch information
nojaf committed Nov 21, 2022
1 parent dc7d2aa commit d320c81
Show file tree
Hide file tree
Showing 7 changed files with 366 additions and 189 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
module ParallelTypeCheckingTests.Code.TrieApproach.AutoOpenDetection

open FSharp.Compiler.Syntax

let private autoOpenShapes =
set
[|
"FSharp.Core.AutoOpenAttribute"
"Core.AutoOpenAttribute"
"AutoOpenAttribute"
"FSharp.Core.AutoOpen"
"Core.AutoOpen"
"AutoOpen"
|]

/// This isn't bullet proof but I wonder who would really alias this very core attribute.
let isAutoOpenAttribute (attribute: SynAttribute) =
match attribute.ArgExpr with
| SynExpr.Const(constant = SynConst.Unit _)
| SynExpr.Const(constant = SynConst.String _)
| SynExpr.Paren(expr = SynExpr.Const(constant = SynConst.String _)) ->
let attributeName =
attribute.TypeName.LongIdent
|> List.map (fun ident -> ident.idText)
|> String.concat "."

autoOpenShapes.Contains attributeName
| _ -> false

let isAnyAttributeAutoOpen (attributes: SynAttributes) =
List.exists (fun (atl: SynAttributeList) -> List.exists isAutoOpenAttribute atl.Attributes) attributes

let rec hasNestedModuleWithAutoOpenAttribute (decls: SynModuleDecl list) : bool =
decls
|> List.exists (function
| SynModuleDecl.NestedModule (moduleInfo = SynComponentInfo (attributes = attributes); decls = decls) ->
isAnyAttributeAutoOpen attributes || hasNestedModuleWithAutoOpenAttribute decls
| _ -> false)

let rec hasNestedSigModuleWithAutoOpenAttribute (decls: SynModuleSigDecl list) : bool =
decls
|> List.exists (function
| SynModuleSigDecl.NestedModule (moduleInfo = SynComponentInfo (attributes = attributes); moduleDecls = decls) ->
isAnyAttributeAutoOpen attributes
|| hasNestedSigModuleWithAutoOpenAttribute decls
| _ -> false)

let hasAutoOpenAttributeInFile (ast: ParsedInput) : bool =
match ast with
| ParsedInput.SigFile (ParsedSigFileInput (contents = contents)) ->
contents
|> List.exists (fun (SynModuleOrNamespaceSig (attribs = attribs; decls = decls)) ->
isAnyAttributeAutoOpen attribs || hasNestedSigModuleWithAutoOpenAttribute decls)
| ParsedInput.ImplFile (ParsedImplFileInput (contents = contents)) ->
contents
|> List.exists (fun (SynModuleOrNamespace (attribs = attribs; decls = decls)) ->
isAnyAttributeAutoOpen attribs || hasNestedModuleWithAutoOpenAttribute decls)

// ==============================================================================================================================
// ==============================================================================================================================

open NUnit.Framework
open FSharp.Compiler.Service.Tests.Common

[<Test>]
let ``detect auto open`` () =
let file =
@"C:\Users\nojaf\Projects\safesparrow-fsharp\src\Compiler\Utilities\ImmutableArray.fsi"

let ast = parseSourceCode (file, System.IO.File.ReadAllText(file))
Assert.True(hasAutoOpenAttributeInFile ast)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module ParallelTypeCheckingTests.Code.TrieApproach.DependencyResolution

open System.Linq
open FSharp.Compiler.Syntax

// This is pseudo code of how we could restructure the trie code
Expand Down Expand Up @@ -113,7 +114,7 @@ let rec processStateEntry (queryTrie: QueryTrie) (state: FileContentQueryState)
}

let getFileNameBefore (files: FileWithAST array) idx =
files.[0 .. (idx - 1)] |> Array.map (fun f -> f.File) |> Set.ofArray
files.[0 .. (idx - 1)] |> Array.map (fun f -> f.Idx) |> Set.ofArray

let time msg f a =
let sw = System.Diagnostics.Stopwatch.StartNew()
Expand All @@ -123,21 +124,25 @@ let time msg f a =
result

let mkGraph (files: FileWithAST array) =
let trie =
let input =
files
|> Array.filter (fun f ->
match f.AST with
| ParsedInput.SigFile _ -> true
| ParsedInput.ImplFile _ -> Array.forall (fun (sigFile: FileWithAST) -> sigFile.File <> $"{f.File}i") files)
let trieInput =
files
|> Array.filter (fun f ->
match f.AST with
| ParsedInput.SigFile _ -> true
| ParsedInput.ImplFile _ -> Array.forall (fun (sigFile: FileWithAST) -> sigFile.File <> $"{f.File}i") files)

time "TrieMapping.mkTrie" TrieMapping.mkTrie input
let trie = time "TrieMapping.mkTrie" TrieMapping.mkTrie trieInput

let queryTrie: QueryTrie = queryTrieMemoized trie

let fileContents =
time "FileContentMapping.mkFileContent" Array.Parallel.map FileContentMapping.mkFileContent files

let filesWithAutoOpen =
trieInput
|> Array.filter (fun f -> AutoOpenDetection.hasAutoOpenAttributeInFile f.AST)
|> Array.map (fun f -> f.Idx)

time
"mkGraph"
Array.Parallel.map
Expand All @@ -146,9 +151,18 @@ let mkGraph (files: FileWithAST array) =
let knownFiles = getFileNameBefore files file.Idx

let result =
Seq.fold (processStateEntry queryTrie) (FileContentQueryState.Create file.File knownFiles) fileContent
Seq.fold (processStateEntry queryTrie) (FileContentQueryState.Create file.Idx knownFiles) fileContent

let allDependencies =
if filesWithAutoOpen.Length > 0 then
let autoOpenDependencies =
set ([| 0 .. (file.Idx - 1) |].Intersect(filesWithAutoOpen))

Set.union result.FoundDependencies autoOpenDependencies
else
result.FoundDependencies

file, Set.toArray result.FoundDependencies)
file, Set.toArray allDependencies)
files

// =============================================================================================================
Expand All @@ -170,7 +184,10 @@ let mkGraphAndReport files =
let graph = mkGraph filesWithAST

for fileName, deps in graph do
let depString = String.concat "\n " deps
let depString =
deps
|> Array.map (fun depIdx -> filesWithAST.[depIdx].File)
|> String.concat "\n "

if deps.Length = 0 then
printfn $"%s{fileName.File}: []"
Expand Down

0 comments on commit d320c81

Please sign in to comment.