diff --git a/src/Compiler/Driver/GraphChecking/DependencyResolution.fs b/src/Compiler/Driver/GraphChecking/DependencyResolution.fs index 1425ec0f9ed..91292a82450 100644 --- a/src/Compiler/Driver/GraphChecking/DependencyResolution.fs +++ b/src/Compiler/Driver/GraphChecking/DependencyResolution.fs @@ -206,6 +206,7 @@ let mkGraph (filePairs: FilePairMap) (files: FileInProject array) : Graph Array.empty | Some sigIdx -> Array.singleton sigIdx + let wrongOrderSignature = + if file.ParsedInput.IsSigFile then + match filePairs.TryGetWrongOrderSignatureToImplementationIndex file.Idx with + | Some idx -> Array.singleton idx + | None -> Array.empty + else + Array.empty + let allDependencies = [| yield! depsResult.FoundDependencies yield! ghostDependencies yield! signatureDependency + yield! wrongOrderSignature |] |> Array.distinct allDependencies - let graph = + // If there is a script in the project, we just process sequentially all the files that may have been added as part of the script closure. + // That means all files up to the last script file. + let scriptCompilationLength = + files |> Array.tryFindIndexBack (fun f -> f.IsScript) |> Option.map (fun idx -> idx + 1) |> Option.defaultValue 0 + + let sequentialPartForScriptCompilation = files + |> Array.take scriptCompilationLength + |> Array.map (fun file -> file.Idx, [| if file.Idx > 0 then file.Idx - 1 |]) + + let normalPart = + files + |> Array.skip scriptCompilationLength |> Array.Parallel.map (fun file -> file.Idx, findDependencies file) - |> readOnlyDict + + let graph = Array.append sequentialPartForScriptCompilation normalPart |> readOnlyDict let trie = trie |> Array.last |> snd diff --git a/src/Compiler/Driver/GraphChecking/Types.fs b/src/Compiler/Driver/GraphChecking/Types.fs index 7443df58204..7739bd531f6 100644 --- a/src/Compiler/Driver/GraphChecking/Types.fs +++ b/src/Compiler/Driver/GraphChecking/Types.fs @@ -25,6 +25,11 @@ type internal FileInProject = ParsedInput: ParsedInput } + member x.IsScript = + match x.ParsedInput with + | ParsedInput.ImplFile impl -> impl.IsScript + | _ -> false + /// There is a subtle difference between a module and namespace. /// A namespace does not necessarily expose a set of dependent files. /// Only when the namespace exposes types that could later be inferred. @@ -175,5 +180,14 @@ type internal FilePairMap(files: FileInProject array) = member x.IsSignature(index: FileIndex) = Map.containsKey index sigToImpl + member x.TryGetWrongOrderSignatureToImplementationIndex(index: FileIndex) = + let input = files[index].ParsedInput + + files + |> Array.truncate index + |> Array.tryFindIndex (fun f -> + f.ParsedInput.IsImplFile + && f.ParsedInput.QualifiedName.Text = input.QualifiedName.Text) + /// Callback that returns a previously calculated 'Result and updates 'State accordingly. type internal Finisher<'Node, 'State, 'Result> = Finisher of node: 'Node * finisher: ('State -> 'Result * 'State) diff --git a/src/Compiler/Driver/GraphChecking/Types.fsi b/src/Compiler/Driver/GraphChecking/Types.fsi index 5f075a1bad7..6a529b104ab 100644 --- a/src/Compiler/Driver/GraphChecking/Types.fsi +++ b/src/Compiler/Driver/GraphChecking/Types.fsi @@ -23,6 +23,8 @@ type internal FileInProject = FileName: FileName ParsedInput: ParsedInput } + member IsScript: bool + /// There is a subtle difference between a module and namespace. /// A namespace does not necessarily expose a set of dependent files. /// Only when the namespace exposes types that could later be inferred. @@ -115,6 +117,7 @@ type internal FilePairMap = member HasSignature: implementationIndex: FileIndex -> bool member TryGetSignatureIndex: implementationIndex: FileIndex -> FileIndex option member IsSignature: index: FileIndex -> bool + member TryGetWrongOrderSignatureToImplementationIndex: index: FileIndex -> FileIndex option /// Callback that returns a previously calculated 'Result and updates 'State accordingly. type internal Finisher<'Node, 'State, 'Result> = Finisher of node: 'Node * finisher: ('State -> 'Result * 'State) diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs index c6de5e776a1..5db05aa6e17 100644 --- a/src/Compiler/Driver/ParseAndCheckInputs.fs +++ b/src/Compiler/Driver/ParseAndCheckInputs.fs @@ -1786,7 +1786,7 @@ let CheckMultipleInputsUsingGraphMode (idx, friendlyFileName)) |> Graph.writeMermaidToFile graphFile) - let _ = ctok // TODO Use it + ignore ctok // TODO Use it let diagnosticsLogger = DiagnosticsThreadStatics.DiagnosticsLogger // In the first linear part of parallel checking, we use a 'checkForErrors' that checks either for errors @@ -1880,8 +1880,11 @@ let CheckMultipleInputsUsingGraphMode let CheckClosedInputSet (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, tcState, eagerFormat, inputs) = // tcEnvAtEndOfLastFile is the environment required by fsi.exe when incrementally adding definitions let results, tcState = - match tcConfig.typeCheckingConfig.Mode with - | TypeCheckingMode.Graph when (not tcConfig.isInteractive && not tcConfig.compilingFSharpCore) -> + if + not tcConfig.deterministic + && not tcConfig.isInteractive + && not tcConfig.compilingFSharpCore + then CheckMultipleInputsUsingGraphMode( ctok, checkForErrors, @@ -1893,7 +1896,8 @@ let CheckClosedInputSet (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tc eagerFormat, inputs ) - | _ -> CheckMultipleInputsSequential(ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcState, inputs) + else + CheckMultipleInputsSequential(ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcState, inputs) let (tcEnvAtEndOfLastFile, topAttrs, implFiles, _), tcState = CheckMultipleInputsFinish(results, tcState) diff --git a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/MigratedTypeCheckTests.fs b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/MigratedTypeCheckTests.fs index b52d62858fa..eaed687d4a0 100644 --- a/tests/FSharp.Compiler.ComponentTests/Miscellaneous/MigratedTypeCheckTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Miscellaneous/MigratedTypeCheckTests.fs @@ -191,7 +191,7 @@ let ``type check neg55`` () = singleNegTest ( "typecheck/sigs") "neg55" [] let ``type check neg56`` () = singleNegTest ( "typecheck/sigs") "neg56" -[] +[] let ``type check neg56_a`` () = singleNegTest ( "typecheck/sigs") "neg56_a" [] diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index c8cbfdab257..764481fc469 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -2282,9 +2282,6 @@ module TypecheckTests = [] let ``type check neg49`` () = singleNegTest (testConfig "typecheck/sigs") "neg49" - [] - let ``type check neg56_a`` () = singleNegTest (testConfig "typecheck/sigs") "neg56_a" - [] let ``type check neg94`` () = singleNegTest (testConfig "typecheck/sigs") "neg94" diff --git a/tests/fsharp/typecheck/sigs/neg14.bsl b/tests/fsharp/typecheck/sigs/neg14.bsl index 28f4763d71c..41e52bbdc2f 100644 --- a/tests/fsharp/typecheck/sigs/neg14.bsl +++ b/tests/fsharp/typecheck/sigs/neg14.bsl @@ -1,4 +1,12 @@ neg14a.fs(9,6,9,33): typecheck error FS0343: The type 'missingInterfaceInSignature' implements 'System.IComparable' explicitly but provides no corresponding override for 'Object.Equals'. An implementation of 'Object.Equals' has been automatically provided, implemented via 'System.IComparable'. Consider implementing the override 'Object.Equals' explicitly +neg14a.fs(2,8,2,11): typecheck error FS0193: Module 'Lib' requires a type 'z' + +neg14a.fs(2,8,2,11): typecheck error FS0193: Module 'Lib' requires a type 'missingTypeVariableInSignature' + +neg14a.fs(2,8,2,11): typecheck error FS0193: Module 'Lib' requires a type 'missingTypeInImplementation' + +neg14a.fs(2,8,2,11): typecheck error FS0193: Module 'Lib' requires a type 'fieldsInWrongOrder' + neg14b.fs(2,13,2,14): typecheck error FS0039: The value, constructor, namespace or type 'X' is not defined. diff --git a/tests/fsharp/typecheck/sigs/neg56_a.bsl b/tests/fsharp/typecheck/sigs/neg56_a.bsl index ca83218a1b9..7d477679f7b 100644 --- a/tests/fsharp/typecheck/sigs/neg56_a.bsl +++ b/tests/fsharp/typecheck/sigs/neg56_a.bsl @@ -1,2 +1,4 @@ neg56_a.fs(11,35,11,47): typecheck error FS1125: The instantiation of the generic type 'list1' is missing and can't be inferred from the arguments or return type of this member. Consider providing a type instantiation when accessing this type, e.g. 'list1<_>'. + +neg56_a.fs(15,18,15,33): typecheck error FS3068: The function or member 'toList' is used in a way that requires further type annotations at its definition to ensure consistency of inferred types. The inferred signature is 'static member private list1.toList: ('a list1 -> 'a list)'.