From 1ca38f5127e7964f1ed794be6f3a4ae8285dde83 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Tue, 7 Jul 2020 19:33:16 +0200 Subject: [PATCH 01/21] [WIP] Simplified compiler API for testing --- .../FSharp.Compiler.ComponentTests.fsproj | 3 +- .../Language/CompilerDirectiveTests.fs | 26 ++++ tests/FSharp.Test.Utilities/Compiler.fs | 147 ++++++++++++++++++ tests/FSharp.Test.Utilities/CompilerAssert.fs | 11 ++ .../FSharp.Test.Utilities.fsproj | 1 + 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs create mode 100644 tests/FSharp.Test.Utilities/Compiler.fs diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index e78ad8e7725..b251c1767fd 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -37,8 +37,9 @@ + - + diff --git a/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs new file mode 100644 index 00000000000..555c1713bf8 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.Language.ComponentTests + +open Xunit +open FSharp.Test.Utilities +open FSharp.Test.Utilities.Compiler +open FSharp.Compiler.SourceCodeServices + +module ``Test Compiler Directives`` = + + [] + let ``r# "" is invalid`` () = + Fsx""" +#r "" + """ |> compile + |> shouldFail + |> withWarnings [213] + + [] + let ``#r " " is invalid`` () = + Fsx""" +#r " " + """ |> compile + |> shouldFail + |> withWarnings [213] diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs new file mode 100644 index 00000000000..3696694a314 --- /dev/null +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -0,0 +1,147 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Test.Utilities + +open FSharp.Compiler.SourceCodeServices + +module Compiler = + + type SourceType = + | Text of string + | Path of string + + type OutputType = Library | Exe + + type CompilationUnit = + | FS of CompilationSource + | FSX of CompilationSource + | CS of CompilationSource + | CSx of CompilationSource + | IL of CompilationSource + + and CompilationSource = + { Source: SourceType + Options: string list + OutputType: OutputType + References: CompilationUnit list } + + type CompilationOutput = { Compilation: CompilationUnit + OutputPath: string option + Errors: FSharpErrorInfo list + Warnings: FSharpErrorInfo list } + + type CompilationResult = + | Success of CompilationOutput + | Failure of CompilationOutput + + let private defaultOptions : string list = [] + + let Fsx (source: string) : CompilationUnit = + match source with + | null -> failwith "Source cannot be null" + | _ -> { Source = Text source; + Options = defaultOptions; + OutputType = Library + References = [] } |> CompilationUnit.FSX + + let FSharp (source: string) : CompilationUnit = + match source with + | null -> failwith "Source cannot be null" + | _ -> { Source = Text source; + Options = defaultOptions; + OutputType = Library + References = [] } |> CompilationUnit.FS + + let CSharp (_: string) : CompilationUnit = failwith "TODO" + + let IL (_: string) : CompilationUnit = failwith "TODO" + + let withOptions (_: string list) (_: CompilationUnit) : CompilationUnit option = failwith "TODO" + let asLibrary (_: CompilationUnit) : CompilationUnit = failwith "TODO" + let asExe (_: CompilationUnit) : CompilationUnit = failwith "TODO" + + let compile (cUnit: CompilationUnit) : CompilationResult = + let cSource = match cUnit with + | FS f | FSX f -> f + | _ -> failwith "TODO" + + let source = match cSource.Source with + | Text t -> t + | _ -> failwith "TODO" + + let sourceKind = match cUnit with + | FS _ -> SourceKind.Fs + | FSX _ -> SourceKind.Fsx + | _ -> failwith "TODO" + + let output = (if cSource.OutputType = Exe then CompileOutput.Exe else CompileOutput.Library) + let options = cSource.Options |> Array.ofList + let references = [] // cSource.References + + let compilation = Compilation.Create(source, sourceKind, output, options, references) + + let ((err: FSharpErrorInfo[], outputFilePath: string), _) = CompilerAssert.CompileRaw(compilation) + + let (errors, warnings) = err |> Array.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) + |> Array.partition (fun e -> e.Severity = FSharpErrorSeverity.Error) + |> fun (f, s) -> f |> List.ofArray, s |> List.ofArray + + let result = { Compilation = cUnit; + OutputPath = None; + Warnings = warnings; + Errors = errors } + + if err.Length > 0 then + Failure { result with Warnings = warnings; + Errors = errors } + else + Success { result with Warnings = warnings; + OutputPath = Some outputFilePath } + + // TODO: baseline helpers + let typecheck (_: CompilationUnit option) = failwith "TODO" + + let execute (_: CompilationUnit option) = failwith "TODO" + + let getIL (_: CompilationUnit option) = failwith "TODO" + + [] + // TODO: Reuse FluentAssertions' assertions here. + module Assertions = + + let private getErrorInfo (info: FSharpErrorInfo) : string = + sprintf "%A %A %A" info.Severity info.ErrorNumber info.Message + + let shouldSucceed (result: CompilationResult) : CompilationResult = + match result with + | Success _ -> result + | Failure _ -> failwith "Compilation failed (expected: Success)." + + let shouldFail (result: CompilationResult) : CompilationResult = + match result with + | Failure _ -> result + | Success _ -> failwith "Compilation succeded (expected: Failure)." + + // TODO: Better error messages. + let private assertFSharpErrorInfo (source: FSharpErrorInfo list) (expected: int list) : unit = + for exp in expected do + if not (List.exists (fun (el: FSharpErrorInfo) -> el.ErrorNumber = exp) source) then + failwith (sprintf "Expected issue '%A' was not found during compilation.\nAll messages:\n%A" exp (List.map getErrorInfo source)) + + if (List.length source) <> (List.length expected) then + failwith (sprintf "Expected list of issues differ from compilation result:\nExpected:\n %A\nActual:\n %A" expected (List.map getErrorInfo source)) + + // TODO: withWarnings and withErrors + Ranges and mesages checking + let withWarnings (expectedWarnings: int list) (result: CompilationResult) : CompilationResult = + match result with + | Success r | Failure r -> + assertFSharpErrorInfo r.Warnings expectedWarnings + + result + + let withErrors (expectedErrors: int list) (result: CompilationResult) : CompilationResult = + match result with + | Success r | Failure r -> + assertFSharpErrorInfo r.Errors expectedErrors + + result diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index ac75e88ee9a..5c02af9fffe 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -362,6 +362,14 @@ let main argv = 0""" disposals |> Seq.iter (fun x -> x.Dispose()) + // NOTE: This function will not clean up all the compiled projects after itself. + // The reason behind is so we can compose verification of test runs easier. + // TODO: We must not rely on the filesystem when compiling + static let rec returnCompilation (cmpl: Compilation) = + let compileDirectory = Path.Combine(Path.GetTempPath(), "CompilerAssert", Path.GetRandomFileName()) + Directory.CreateDirectory(compileDirectory) |> ignore + compileCompilationAux compileDirectory (ResizeArray()) false cmpl + static member CompileWithErrors(cmpl: Compilation, expectedErrors, ?ignoreWarnings) = let ignoreWarnings = defaultArg ignoreWarnings false lock gate (fun () -> @@ -371,6 +379,9 @@ let main argv = 0""" static member Compile(cmpl: Compilation, ?ignoreWarnings) = CompilerAssert.CompileWithErrors(cmpl, [||], defaultArg ignoreWarnings false) + static member CompileRaw(cmpl: Compilation) = + lock gate (fun () -> returnCompilation cmpl) + static member Execute(cmpl: Compilation, ?ignoreWarnings, ?beforeExecute, ?newProcess, ?onOutput) = let ignoreWarnings = defaultArg ignoreWarnings false let beforeExecute = defaultArg beforeExecute (fun _ _ -> ()) diff --git a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj index 5ddfa74eb83..8487625d4de 100644 --- a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj +++ b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj @@ -22,6 +22,7 @@ + From b66d8ae0b26d8fb04acad2c1e7f0501b31db2937 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 8 Jul 2020 14:42:10 +0200 Subject: [PATCH 02/21] [WIP] Support of references, for F#, C# projects. Added more asserts. --- .../ErrorMessages/ConfusingTypeName.fs | 49 ++++ .../Language/CompilerDirectiveTests.fs | 8 +- tests/FSharp.Test.Utilities/Assert.fs | 3 + tests/FSharp.Test.Utilities/Compiler.fs | 251 +++++++++++++----- 4 files changed, 241 insertions(+), 70 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs index b67a75ec601..10ef9925664 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs @@ -4,11 +4,60 @@ namespace FSharp.Compiler.ErrorMessages.ComponentTests open Xunit open FSharp.Test.Utilities +open FSharp.Test.Utilities.Compiler open FSharp.Test.Utilities.Utilities open FSharp.Compiler.SourceCodeServices module ``Confusing Type Name`` = + [] + let ``Expected types with multiple references`` () = + + let csLibA = + CSharp """ +public class A { } +public class B { } + """ |> withName "libA" + + let csLibB = + csLibA |> withName "libB" + + let fsLibC = + FSharp """ +module AMaker +let makeA () : A = A() +let makeB () = B<_>() + """ |> withName "libC" |> withReferences [csLibA] + + let fsLibD = + FSharp """ +module OtherAMaker +let makeOtherA () : A = A() +let makeOtherB () = B<_>() + """ |> withName "libD" |> withReferences [csLibB] + + let app = + FSharp """ +module ConfusingTypeName +let a = AMaker.makeA() +let otherA = OtherAMaker.makeOtherA() +printfn "%A %A" (a.GetType().AssemblyQualifiedName) (otherA.GetType().AssemblyQualifiedName) +printfn "%A" (a = otherA) + +let b = AMaker.makeB() +let otherB = OtherAMaker.makeOtherB() +printfn "%A %A" (b.GetType().AssemblyQualifiedName) (otherB.GetType().AssemblyQualifiedName) +printfn "%A" (b = otherB) + """ |> withReferences [csLibA; csLibB; fsLibC; fsLibD] + + app + |> compile + |> shouldFail + |> withErrors [ + (1, (6, 19, 6, 25), ("This expression was expected to have type\n 'A (libA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' \nbut here has type\n 'A (libB, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' ")) + (1, (11, 19, 11, 25), ("This expression was expected to have type\n 'B (libA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' \nbut here has type\n 'B (libB, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' "))] + + [] let ``Checks expected types with multiple references``() = let csLibAB = """ diff --git a/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs index 555c1713bf8..98c8759dbd2 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs @@ -15,12 +15,12 @@ module ``Test Compiler Directives`` = #r "" """ |> compile |> shouldFail - |> withWarnings [213] + |> withWarning (213, (2,1,2,6), "'' is not a valid assembly name") [] - let ``#r " " is invalid`` () = + let ``#r " " is invalid`` () = Fsx""" -#r " " +#r " " """ |> compile |> shouldFail - |> withWarnings [213] + |> withWarning (213, (2,1,2,10), "'' is not a valid assembly name") diff --git a/tests/FSharp.Test.Utilities/Assert.fs b/tests/FSharp.Test.Utilities/Assert.fs index d059337834e..64a4b732160 100644 --- a/tests/FSharp.Test.Utilities/Assert.fs +++ b/tests/FSharp.Test.Utilities/Assert.fs @@ -4,6 +4,9 @@ module Assert = open FluentAssertions open System.Collections + let inline shouldBeEqualWith (expected : ^T) (message: string) (actual: ^U) = + actual.Should().BeEquivalentTo(expected, message) |> ignore + let inline shouldBeEquivalentTo (expected : ^T) (actual : ^U) = actual.Should().BeEquivalentTo(expected, "") |> ignore diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 3696694a314..b664924f745 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -3,6 +3,12 @@ namespace FSharp.Test.Utilities open FSharp.Compiler.SourceCodeServices +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.CSharp +open FSharp.Test.Utilities.Assert +open FSharp.Test.Utilities +open FSharp.Test.Utilities.Utilities +open NUnit.Framework module Compiler = @@ -10,23 +16,33 @@ module Compiler = | Text of string | Path of string - type OutputType = Library | Exe - type CompilationUnit = - | FS of CompilationSource - | FSX of CompilationSource - | CS of CompilationSource - | CSx of CompilationSource - | IL of CompilationSource - - and CompilationSource = + | FS of FSharpCompilationSource + | CS of CSharpCompilationSource + | IL of ILCompilationSource + + and FSharpCompilationSource = + { Source: SourceType + Options: string list + OutputType: CompileOutput + SourceKind: SourceKind + Name : string option + IgnoreWarnings: bool + References: CompilationUnit list } + + and CSharpCompilationSource = + { Source: SourceType + LangVersion: CSharpLanguageVersion + TargetFramework: TargetFramework + Name: string option + References: CompilationUnit list } + + and ILCompilationSource = { Source: SourceType - Options: string list - OutputType: OutputType - References: CompilationUnit list } + References: CompilationUnit list} - type CompilationOutput = { Compilation: CompilationUnit - OutputPath: string option + type CompilationOutput = { OutputPath: string option + Adjust: int Errors: FSharpErrorInfo list Warnings: FSharpErrorInfo list } @@ -36,47 +52,94 @@ module Compiler = let private defaultOptions : string list = [] - let Fsx (source: string) : CompilationUnit = + // Not very safe version of reading stuff from file, but we want to fail fast for now if anything goes wrong. + let private getSource (src: SourceType) : string = + match src with + | Text t -> t + | Path p -> System.IO.File.ReadAllText p + + let private fsFromString (source: string) (kind: SourceKind) : FSharpCompilationSource = match source with | null -> failwith "Source cannot be null" - | _ -> { Source = Text source; - Options = defaultOptions; - OutputType = Library - References = [] } |> CompilationUnit.FSX - - let FSharp (source: string) : CompilationUnit = + | _ -> { Source = Text source; + Options = defaultOptions; + OutputType = Library; + SourceKind = kind; + Name = None; + IgnoreWarnings = false; + References = [] } + + let private csFromString (source: string) : CSharpCompilationSource = match source with | null -> failwith "Source cannot be null" - | _ -> { Source = Text source; - Options = defaultOptions; - OutputType = Library - References = [] } |> CompilationUnit.FS - - let CSharp (_: string) : CompilationUnit = failwith "TODO" - - let IL (_: string) : CompilationUnit = failwith "TODO" - - let withOptions (_: string list) (_: CompilationUnit) : CompilationUnit option = failwith "TODO" - let asLibrary (_: CompilationUnit) : CompilationUnit = failwith "TODO" - let asExe (_: CompilationUnit) : CompilationUnit = failwith "TODO" - - let compile (cUnit: CompilationUnit) : CompilationResult = - let cSource = match cUnit with - | FS f | FSX f -> f - | _ -> failwith "TODO" + | _ -> { Source = Text source; + LangVersion = CSharpLanguageVersion.CSharp8; + TargetFramework = TargetFramework.NetCoreApp30; + Name = None; + References = [] } - let source = match cSource.Source with - | Text t -> t - | _ -> failwith "TODO" + let private fromFile (_: string) : CompilationUnit = failwith "TODO" - let sourceKind = match cUnit with - | FS _ -> SourceKind.Fs - | FSX _ -> SourceKind.Fsx - | _ -> failwith "TODO" + let Fsx (source: string) : CompilationUnit = + fsFromString source SourceKind.Fsx |> CompilationUnit.FS - let output = (if cSource.OutputType = Exe then CompileOutput.Exe else CompileOutput.Library) - let options = cSource.Options |> Array.ofList - let references = [] // cSource.References + let FSharp (source: string) : CompilationUnit = + fsFromString source SourceKind.Fs |> CompilationUnit.FS + + let CSharp (source: string) : CompilationUnit = + csFromString source |> CompilationUnit.CS + + let withName (name: string) (cUnit: CompilationUnit) : CompilationUnit = + match cUnit with + | FS src -> CompilationUnit.FS { src with Name = Some name } + | CS src -> CompilationUnit.CS { src with Name = Some name } + | IL _ -> failwith "TODO: Implement named IL" + + let withReferences (references: CompilationUnit list) (cUnit: CompilationUnit) : CompilationUnit = + match cUnit with + | FS fs -> FS { fs with References = fs.References @ references } + | CS cs -> CS { cs with References = cs.References @ references } + | IL _ -> failwith "TODO: Support references for IL" + + // TODO: C# and IL versions where applicable + let withOptions (options: string list) (src: FSharpCompilationSource) : CompilationUnit = + CompilationUnit.FS { src with Options = options } + + let asLibrary (src: FSharpCompilationSource) : CompilationUnit = + CompilationUnit.FS { src with OutputType = CompileOutput.Library } + + let asExe (src: FSharpCompilationSource) : CompilationUnit = + CompilationUnit.FS { src with OutputType = CompileOutput.Exe } + + + let private processReferences (references: CompilationUnit list) = + let rec loop acc = function + | [] -> List.rev acc + | x::xs -> + match x with + | FS fs -> + let refs = loop [] fs.References + let source = getSource fs.Source + let name = if Option.isSome fs.Name then fs.Name.Value else null + let cmpl = Compilation.Create(source, fs.SourceKind, fs.OutputType, cmplRefs = refs, name = name) |> CompilationReference.CreateFSharp + loop (cmpl::acc) xs + | CS cs -> + let source = getSource cs.Source + // TODO: reference support for C#, convert CompilationReference to MetadataReference + let name = if Option.isSome cs.Name then cs.Name.Value else null + let cmpl = CompilationUtil.CreateCSharpCompilation(source, cs.LangVersion, cs.TargetFramework, name = name) |> CompilationReference.Create + loop (cmpl::acc) xs + | IL _ -> failwith "TODO: Process references for IL" + loop [] references + + let private compileFSharp (fsSource: FSharpCompilationSource) : CompilationResult = + + let source = getSource fsSource.Source + let sourceKind = fsSource.SourceKind + let output = fsSource.OutputType + let options = fsSource.Options |> Array.ofList + + let references = processReferences fsSource.References let compilation = Compilation.Create(source, sourceKind, output, options, references) @@ -86,17 +149,23 @@ module Compiler = |> Array.partition (fun e -> e.Severity = FSharpErrorSeverity.Error) |> fun (f, s) -> f |> List.ofArray, s |> List.ofArray - let result = { Compilation = cUnit; - OutputPath = None; + let result = { OutputPath = None; + Adjust = 0; Warnings = warnings; Errors = errors } - if err.Length > 0 then + // Treat warnings as errors if "IgnoreWarnings" is false; + if errors.Length > 0 || (warnings.Length > 0 && not fsSource.IgnoreWarnings) then Failure { result with Warnings = warnings; Errors = errors } else Success { result with Warnings = warnings; - OutputPath = Some outputFilePath } + OutputPath = Some outputFilePath } + + let compile (cUnit: CompilationUnit) : CompilationResult = + match cUnit with + | FS fs -> compileFSharp fs + | _ -> failwith "TODO" // TODO: baseline helpers let typecheck (_: CompilationUnit option) = failwith "TODO" @@ -108,10 +177,50 @@ module Compiler = [] // TODO: Reuse FluentAssertions' assertions here. module Assertions = - + let private getErrorInfo (info: FSharpErrorInfo) : string = sprintf "%A %A %A" info.Severity info.ErrorNumber info.Message + // TODO: Better error messages. + // TODO: Should we preserve the order (i.e. expect errors/warnings to be in the same order as in parameters)? + // TODO: Should probably generalize/dedupicate asserts + let private assertErrorsLength (source: FSharpErrorInfo list) (expected: int list) : unit = + if (List.length source) <> (List.length expected) then + failwith (sprintf "Expected list of issues differ from compilation result:\nExpected:\n %A\nActual:\n %A" expected (List.map getErrorInfo source)) + () + + let private assertErrorNumber (source: FSharpErrorInfo list) (expected: int list) : unit = + for exp in expected do + if not (List.exists (fun (el: FSharpErrorInfo) -> el.ErrorNumber = exp) source) then + failwith (sprintf "Mismatch in ErrorNumber, expected '%A' was not found during compilation.\nAll messages:\n%A" exp (List.map getErrorInfo source)) + assertErrorsLength source expected + + let private assertErrors (what: string) libAdjust (source: FSharpErrorInfo list) (expected: (int * (int * int * int * int) * string) list) : unit = + let errors = + source + |> List.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) + |> List.map (fun info -> (info.ErrorNumber, (info.StartLineAlternate - libAdjust, info.StartColumn + 1, info.EndLineAlternate - libAdjust, info.EndColumn + 1), info.Message)) + + let inline checkEqual k a b = + if a <> b then + Assert.AreEqual(a, b, sprintf "%s: Mismatch in %s, expected '%A', got '%A'.\nAll errors:\n%A" what k a b errors) + + checkEqual "Errors" expected.Length errors.Length + + List.zip errors expected + |> List.iter (fun (actualError, expectedError) -> + let (expectedErrorNumber, expectedErrorRange, expectedErrorMsg) = expectedError + let (actualErrorNumber, actualErrorRange, actualErrorMsg) = actualError + checkEqual "ErrorNumber" expectedErrorNumber actualErrorNumber + checkEqual "ErrorRange" expectedErrorRange actualErrorRange + checkEqual "Message" expectedErrorMsg actualErrorMsg) + () + + let adjust (adjust: int) (result: CompilationResult) : CompilationResult = + match result with + | Success s -> Success { s with Adjust = adjust } + | Failure f -> Failure { f with Adjust = adjust } + let shouldSucceed (result: CompilationResult) : CompilationResult = match result with | Success _ -> result @@ -122,26 +231,36 @@ module Compiler = | Failure _ -> result | Success _ -> failwith "Compilation succeded (expected: Failure)." - // TODO: Better error messages. - let private assertFSharpErrorInfo (source: FSharpErrorInfo list) (expected: int list) : unit = - for exp in expected do - if not (List.exists (fun (el: FSharpErrorInfo) -> el.ErrorNumber = exp) source) then - failwith (sprintf "Expected issue '%A' was not found during compilation.\nAll messages:\n%A" exp (List.map getErrorInfo source)) + let withWarnings (expectedWarnings: (int * (int * int * int * int) * string) list) (result: CompilationResult) : CompilationResult = + match result with + | Success r | Failure r -> + assertErrors "Warnings" r.Adjust r.Warnings expectedWarnings - if (List.length source) <> (List.length expected) then - failwith (sprintf "Expected list of issues differ from compilation result:\nExpected:\n %A\nActual:\n %A" expected (List.map getErrorInfo source)) - - // TODO: withWarnings and withErrors + Ranges and mesages checking - let withWarnings (expectedWarnings: int list) (result: CompilationResult) : CompilationResult = + result + + let withWarning (expectedWarning: (int * (int * int * int * int) * string)) (result: CompilationResult) : CompilationResult = + withWarnings [expectedWarning] result + + let withWarningCodes (expectedWarnings: int list) (result: CompilationResult) : CompilationResult = match result with | Success r | Failure r -> - assertFSharpErrorInfo r.Warnings expectedWarnings + assertErrorNumber r.Warnings expectedWarnings result - let withErrors (expectedErrors: int list) (result: CompilationResult) : CompilationResult = + let withErrors (expectedErrors: (int * (int * int * int * int) * string) list) (result: CompilationResult) : CompilationResult = + match result with + | Success r | Failure r -> + assertErrors "Errors" r.Adjust r.Errors expectedErrors + + result + + let withError (expectedError: (int * (int * int * int * int) * string)) (result: CompilationResult) : CompilationResult = + withErrors [expectedError] result + + let withErrorCodes (expectedErrors: int list) (result: CompilationResult) : CompilationResult = match result with | Success r | Failure r -> - assertFSharpErrorInfo r.Errors expectedErrors + assertErrorNumber r.Errors expectedErrors result From b34ca95b8835d69e96fa3c233bed879a7e188f72 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 8 Jul 2020 14:57:55 +0200 Subject: [PATCH 03/21] Added more examples + ignoreWarnings support --- .../Language/CompilerDirectiveTests.fs | 5 +++-- tests/FSharp.Test.Utilities/Compiler.fs | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs index 98c8759dbd2..7ee9b15610d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs @@ -13,8 +13,9 @@ module ``Test Compiler Directives`` = let ``r# "" is invalid`` () = Fsx""" #r "" - """ |> compile - |> shouldFail + """ |> ignoreWarnings + |> compile + |> shouldSucceed |> withWarning (213, (2,1,2,6), "'' is not a valid assembly name") [] diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index b664924f745..3f3f1248f69 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -111,6 +111,10 @@ module Compiler = let asExe (src: FSharpCompilationSource) : CompilationUnit = CompilationUnit.FS { src with OutputType = CompileOutput.Exe } + let ignoreWarnings (cUnit: CompilationUnit) : CompilationUnit = + match cUnit with + | FS fs -> CompilationUnit.FS { fs with IgnoreWarnings = true } + | _ -> failwith "TODO: Implement ignorewarnings for the rest." let private processReferences (references: CompilationUnit list) = let rec loop acc = function @@ -167,13 +171,18 @@ module Compiler = | FS fs -> compileFSharp fs | _ -> failwith "TODO" - // TODO: baseline helpers + // TODO: Typecheck with baseline + let parse (_: CompilationUnit option) = failwith "TODO" + let typecheck (_: CompilationUnit option) = failwith "TODO" let execute (_: CompilationUnit option) = failwith "TODO" + let run (_: CompilationUnit option) = failwith "TODO" + let getIL (_: CompilationUnit option) = failwith "TODO" + [] // TODO: Reuse FluentAssertions' assertions here. module Assertions = @@ -182,7 +191,6 @@ module Compiler = sprintf "%A %A %A" info.Severity info.ErrorNumber info.Message // TODO: Better error messages. - // TODO: Should we preserve the order (i.e. expect errors/warnings to be in the same order as in parameters)? // TODO: Should probably generalize/dedupicate asserts let private assertErrorsLength (source: FSharpErrorInfo list) (expected: int list) : unit = if (List.length source) <> (List.length expected) then From 9e4561e37e40dac4d10b5dfc484f68e24e454f81 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 9 Jul 2020 14:21:14 +0200 Subject: [PATCH 04/21] Added typecheck + baseline test helpers. --- .../ConstraintSolver/MemberConstraints.fs | 20 +++++ .../ConstraintSolver/PrimitiveConstraints.fs | 21 +++++ .../FSharp.Compiler.ComponentTests.fsproj | 2 + .../constructors/neg_invalid_constructor.bsl | 22 ++++++ .../constructors/neg_invalid_constructor.fs | 7 ++ tests/FSharp.Test.Utilities/Compiler.fs | 78 ++++++++++++++++--- tests/FSharp.Test.Utilities/CompilerAssert.fs | 22 ++++++ 7 files changed, 162 insertions(+), 10 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/ConstraintSolver/PrimitiveConstraints.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/testables/typecheck/constructors/neg_invalid_constructor.bsl create mode 100644 tests/FSharp.Compiler.ComponentTests/testables/typecheck/constructors/neg_invalid_constructor.fs diff --git a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs new file mode 100644 index 00000000000..ca3741ad655 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.ConstraintSolver.ComponentTests + +open Xunit +open FSharp.Test.Utilities +open FSharp.Test.Utilities.Compiler +open FSharp.Compiler.SourceCodeServices + +module MemberConstraints = + + [] + let ``Invalid member constraint with ErrorRanges``() = // Regression test for FSharp1.0:2262 + FSharp """ + let inline length (x: ^a) : int = (^a : (member Length : int with get, set) (x, ())) + """ + |> withOptions ["--test:ErrorRanges"] + |> typecheck + |> shouldFail + |> withError (697, (2, 43, 2, 76), "Invalid constraint") diff --git a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/PrimitiveConstraints.fs b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/PrimitiveConstraints.fs new file mode 100644 index 00000000000..33c82b45cc9 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/PrimitiveConstraints.fs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.ConstraintSolver.ComponentTests + +open Xunit +open FSharp.Test.Utilities +open FSharp.Test.Utilities.Compiler +open FSharp.Compiler.SourceCodeServices + +module PrimitiveConstraints = + + [] + /// Title: Type checking oddity + /// + /// This suggestion was resolved as by design, + /// so the test makes sure, we're emitting error message about 'not being a valid object construction expression' + let ``Invalid object constructor`` () = // Regression test for FSharp1.0:4189 + baseline + ((__SOURCE_DIRECTORY__ ++ "../testables/"), "typecheck/constructors/neg_invalid_constructor.fs") + |> withOptions ["--test:ErrorRanges"] + |> typecheck diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index b251c1767fd..ebfd10323fc 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -38,6 +38,8 @@ + + diff --git a/tests/FSharp.Compiler.ComponentTests/testables/typecheck/constructors/neg_invalid_constructor.bsl b/tests/FSharp.Compiler.ComponentTests/testables/typecheck/constructors/neg_invalid_constructor.bsl new file mode 100644 index 00000000000..3b2777c1504 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/testables/typecheck/constructors/neg_invalid_constructor.bsl @@ -0,0 +1,22 @@ +typecheck/constructors/neg_invalid_constructor.fs (3,29)-(3,56) typecheck error A unique overload for method 'ImmutableStack`1' could not be determined based on type information prior to this program point. A type annotation may be needed. + +Known type of argument: 'a list + +Candidates: + - new : col:'b -> ImmutableStack<'a> + - private new : items:'a list -> ImmutableStack<'a> +typecheck/constructors/neg_invalid_constructor.fs (4,93)-(4,111) typecheck error A unique overload for method 'ImmutableStack`1' could not be determined based on type information prior to this program point. A type annotation may be needed. + +Known type of argument: 'a list + +Candidates: + - new : col:'b -> ImmutableStack<'a> + - private new : items:'a list -> ImmutableStack<'a> +typecheck/constructors/neg_invalid_constructor.fs (7,30)-(7,60) typecheck error A unique overload for method 'ImmutableStack`1' could not be determined based on type information prior to this program point. A type annotation may be needed. + +Known type of argument: 'a list + +Candidates: + - new : col:'b -> ImmutableStack<'a> when 'b :> seq<'c> + - private new : items:'a list -> ImmutableStack<'a> +typecheck/constructors/neg_invalid_constructor.fs (7,30)-(7,60) typecheck error This is not a valid object construction expression. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor. \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/testables/typecheck/constructors/neg_invalid_constructor.fs b/tests/FSharp.Compiler.ComponentTests/testables/typecheck/constructors/neg_invalid_constructor.fs new file mode 100644 index 00000000000..02be510295d --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/testables/typecheck/constructors/neg_invalid_constructor.fs @@ -0,0 +1,7 @@ +type ImmutableStack<'a> private(items: 'a list) = + + member this.Push item = ImmutableStack(item::items) + member this.Pop = match items with | [] -> failwith "No elements in stack" | x::xs -> x,ImmutableStack(xs) + + // Notice type annotation is commented out, which results in an error + new(col (*: seq<'a>*)) = ImmutableStack(List.ofSeq col) diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 3f3f1248f69..1029ca049ea 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -3,18 +3,20 @@ namespace FSharp.Test.Utilities open FSharp.Compiler.SourceCodeServices -open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.CSharp -open FSharp.Test.Utilities.Assert open FSharp.Test.Utilities +open FSharp.Test.Utilities.Assert open FSharp.Test.Utilities.Utilities +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.CSharp open NUnit.Framework +open System module Compiler = type SourceType = | Text of string | Path of string + | Baseline of (string * string) type CompilationUnit = | FS of FSharpCompilationSource @@ -41,6 +43,7 @@ module Compiler = { Source: SourceType References: CompilationUnit list} + // TODO: Do we need separate types for Compilation/Typecheck/Run results? type CompilationOutput = { OutputPath: string option Adjust: int Errors: FSharpErrorInfo list @@ -57,6 +60,7 @@ module Compiler = match src with | Text t -> t | Path p -> System.IO.File.ReadAllText p + | Baseline (d, f) -> System.IO.File.ReadAllText (System.IO.Path.Combine(d, f)) let private fsFromString (source: string) (kind: SourceKind) : FSharpCompilationSource = match source with @@ -86,6 +90,18 @@ module Compiler = let FSharp (source: string) : CompilationUnit = fsFromString source SourceKind.Fs |> CompilationUnit.FS + let baseline (dir: string, file: string) : CompilationUnit = + match (dir, file) with + | dir, _ when String.IsNullOrWhiteSpace dir -> failwith "Baseline tests directory cannot be null or empty." + | _, file when String.IsNullOrWhiteSpace file -> failwith "Baseline source file name cannot be null or empty." + | _ -> { Source = Baseline (dir, file); + Options = defaultOptions; + OutputType = Library; + SourceKind = SourceKind.Fs; + Name = None; + IgnoreWarnings = false; + References = [] } |> CompilationUnit.FS + let CSharp (source: string) : CompilationUnit = csFromString source |> CompilationUnit.CS @@ -93,7 +109,7 @@ module Compiler = match cUnit with | FS src -> CompilationUnit.FS { src with Name = Some name } | CS src -> CompilationUnit.CS { src with Name = Some name } - | IL _ -> failwith "TODO: Implement named IL" + | IL _ -> failwith "IL Compilation cannot be named." let withReferences (references: CompilationUnit list) (cUnit: CompilationUnit) : CompilationUnit = match cUnit with @@ -101,9 +117,10 @@ module Compiler = | CS cs -> CS { cs with References = cs.References @ references } | IL _ -> failwith "TODO: Support references for IL" - // TODO: C# and IL versions where applicable - let withOptions (options: string list) (src: FSharpCompilationSource) : CompilationUnit = - CompilationUnit.FS { src with Options = options } + let withOptions (options: string list) (cUnit: CompilationUnit) : CompilationUnit = + match cUnit with + | FS fs -> CompilationUnit.FS { fs with Options = options } + | _ -> failwith "TODO: Implement where applicable." let asLibrary (src: FSharpCompilationSource) : CompilationUnit = CompilationUnit.FS { src with OutputType = CompileOutput.Library } @@ -171,10 +188,51 @@ module Compiler = | FS fs -> compileFSharp fs | _ -> failwith "TODO" - // TODO: Typecheck with baseline - let parse (_: CompilationUnit option) = failwith "TODO" + // TODO: Probably want to return a proper compilation result here as well to process it later. + let private typecheckFSharpWithBaseline (options: string list) (dir: string) (file: string) : CompilationResult = + // Since TypecheckWithErrorsAndOptionsAgainsBaseLine throws if doesn't match expected baseline, + // We return a successfull CompilationResult if it succeds. + CompilerAssert.TypeCheckWithErrorsAndOptionsAgainstBaseLine (Array.ofList options) dir file + + Success { OutputPath = None; + Adjust = 0; + Warnings = []; + Errors = [] } + + // TODO: Extract error handling to a separate function; + let private typecheckFSharpSource (fsSource: FSharpCompilationSource) : CompilationResult = + let source = getSource fsSource.Source + let options = fsSource.Options |> Array.ofList + + let (err: FSharpErrorInfo []) = CompilerAssert.TypeCheckWithOptions options source - let typecheck (_: CompilationUnit option) = failwith "TODO" + let (errors, warnings) = err |> Array.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) + |> Array.partition (fun e -> e.Severity = FSharpErrorSeverity.Error) + |> fun (f, s) -> List.ofArray f, List.ofArray s + + let result = { OutputPath = None; + Adjust = 0; + Warnings = warnings; + Errors = errors } + + // Treat warnings as errors if "IgnoreWarnings" is false; + if errors.Length > 0 || (warnings.Length > 0 && not fsSource.IgnoreWarnings) then + Failure { result with Warnings = warnings; + Errors = errors } + else + Success { result with Warnings = warnings } + + let private typecheckFSharp (fsSource: FSharpCompilationSource) : CompilationResult = + match fsSource.Source with + | Baseline (f, d) -> typecheckFSharpWithBaseline fsSource.Options f d + | _ -> typecheckFSharpSource fsSource + + let typecheck (cUnit: CompilationUnit) : CompilationResult = + match cUnit with + | FS fs -> typecheckFSharp fs + | _ -> failwith "TODO: Implement typeckeck for C# and IL if applicable." + + let parse (_: CompilationUnit option) = failwith "TODO" let execute (_: CompilationUnit option) = failwith "TODO" diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index 5c02af9fffe..88e69b97fce 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -492,6 +492,27 @@ let main argv = 0""" Assert.AreEqual(errorsExpectedBaseLine.Replace("\r\n","\n"), errorsActual.Replace("\r\n","\n")) + static member TypeCheckWithOptions options (source: string) = + lock gate <| fun () -> + let errors = + let parseResults, fileAnswer = + checker.ParseAndCheckFileInProject( + "test.fs", + 0, + SourceText.ofString source, + { defaultProjectOptions with OtherOptions = Array.append options defaultProjectOptions.OtherOptions}) + |> Async.RunSynchronously + + if parseResults.Errors.Length > 0 then + parseResults.Errors + else + + match fileAnswer with + | FSharpCheckFileAnswer.Aborted _ -> Assert.Fail("Type Checker Aborted"); [| |] + | FSharpCheckFileAnswer.Succeeded(typeCheckResults) -> typeCheckResults.Errors + + errors + static member TypeCheckWithErrorsAndOptionsAndAdjust options libAdjust (source: string) expectedTypeErrors = lock gate <| fun () -> let errors = @@ -513,6 +534,7 @@ let main argv = 0""" assertErrors libAdjust false errors expectedTypeErrors + static member TypeCheckWithErrorsAndOptions options (source: string) expectedTypeErrors = CompilerAssert.TypeCheckWithErrorsAndOptionsAndAdjust options 0 (source: string) expectedTypeErrors From e1f6ee955092317ad3bcf263281670cd0e93082e Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 9 Jul 2020 14:44:25 +0200 Subject: [PATCH 05/21] Added running functionality --- .../ConstraintSolver/MemberConstraints.fs | 31 +++++++++++++++++-- tests/FSharp.Test.Utilities/Compiler.fs | 31 ++++++++++++------- tests/FSharp.Test.Utilities/CompilerAssert.fs | 3 ++ 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs index ca3741ad655..599d58ecd5c 100644 --- a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs +++ b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs @@ -3,9 +3,7 @@ namespace FSharp.Compiler.ConstraintSolver.ComponentTests open Xunit -open FSharp.Test.Utilities open FSharp.Test.Utilities.Compiler -open FSharp.Compiler.SourceCodeServices module MemberConstraints = @@ -18,3 +16,32 @@ module MemberConstraints = |> typecheck |> shouldFail |> withError (697, (2, 43, 2, 76), "Invalid constraint") + + [] + let ``we can overload operators on a type and not add all the extra jazz such as inlining and the ^ operator.``() = + + FSharp """ +type Foo(x : int) = + member this.Val = x + + static member (-->) ((src : Foo), (target : Foo)) = new Foo(src.Val + target.Val) + static member (-->) ((src : Foo), (target : int)) = new Foo(src.Val + target) + + static member (+) ((src : Foo), (target : Foo)) = new Foo(src.Val + target.Val) + static member (+) ((src : Foo), (target : int)) = new Foo(src.Val + target) + +let x = Foo(3) --> 4 +let y = Foo(3) --> Foo(4) +let x2 = Foo(3) + 4 +let y2 = Foo(3) + Foo(4) + +if x.Val <> 7 then failwith "x.Val <> 7" +elif y.Val <> 7 then failwith "y.Val <> 7" +elif x2.Val <> 7 then failwith "x2.Val <> 7" +elif y2.Val <> 7 then failwith "x.Val <> 7" +else () + """ + |> asExe + |> compile + |> run + // OR |> compileAsExeAndRun diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 1029ca049ea..9c7517df377 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -122,11 +122,15 @@ module Compiler = | FS fs -> CompilationUnit.FS { fs with Options = options } | _ -> failwith "TODO: Implement where applicable." - let asLibrary (src: FSharpCompilationSource) : CompilationUnit = - CompilationUnit.FS { src with OutputType = CompileOutput.Library } + let asLibrary (cUnit: CompilationUnit) : CompilationUnit = + match cUnit with + | FS fs -> CompilationUnit.FS { fs with OutputType = CompileOutput.Library } + | _ -> failwith "TODO: Implement where applicable." - let asExe (src: FSharpCompilationSource) : CompilationUnit = - CompilationUnit.FS { src with OutputType = CompileOutput.Exe } + let asExe (cUnit: CompilationUnit) : CompilationUnit = + match cUnit with + | FS fs -> CompilationUnit.FS { fs with OutputType = CompileOutput.Exe } + | _ -> failwith "TODO: Implement where applicable." let ignoreWarnings (cUnit: CompilationUnit) : CompilationUnit = match cUnit with @@ -181,7 +185,7 @@ module Compiler = Errors = errors } else Success { result with Warnings = warnings; - OutputPath = Some outputFilePath } + OutputPath = Some outputFilePath } let compile (cUnit: CompilationUnit) : CompilationResult = match cUnit with @@ -232,15 +236,18 @@ module Compiler = | FS fs -> typecheckFSharp fs | _ -> failwith "TODO: Implement typeckeck for C# and IL if applicable." - let parse (_: CompilationUnit option) = failwith "TODO" - - let execute (_: CompilationUnit option) = failwith "TODO" - - let run (_: CompilationUnit option) = failwith "TODO" - - let getIL (_: CompilationUnit option) = failwith "TODO" + let run (cResult: CompilationResult ) : unit = + match cResult with + | Failure o -> failwith (sprintf "Compilatoin should be successfull in order to run the output.\n Errors: %A" (o.Errors @ o.Warnings)) + | Success s -> + match s.OutputPath with + | None -> failwith "Compilation didn't produce any output. Unable to run. (did you forget to set output type to Exe?)" + | Some p -> CompilerAssert.Run p + let compileAndRun = compile >> run + let compileExeAndRun = asExe >> compileAndRun + [] // TODO: Reuse FluentAssertions' assertions here. module Assertions = diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index 88e69b97fce..4956b3e2035 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -620,6 +620,9 @@ let main argv = 0""" static member RunScript source expectedErrorMessages = CompilerAssert.RunScriptWithOptions [||] source expectedErrorMessages + static member Run (exe: string) = + executeBuiltApp exe [] + static member ParseWithErrors (source: string) expectedParseErrors = let sourceFileName = "test.fs" let parsingOptions = { FSharpParsingOptions.Default with SourceFiles = [| sourceFileName |] } From 54c313fd22ba70c3bfc46f2986a9170f439b1058 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 9 Jul 2020 14:52:27 +0200 Subject: [PATCH 06/21] Moved a bunch of compiler tests to a new suite --- .../ConstraintSolver/PrimitiveConstraints.fs | 80 +++++++++++++++- .../ConstraintSolver/MemberConstraints.fs | 47 --------- .../ConstraintSolver/PrimitiveConstraints.fs | 95 ------------------- tests/fsharp/FSharpSuite.Tests.fsproj | 2 - 4 files changed, 78 insertions(+), 146 deletions(-) delete mode 100644 tests/fsharp/Compiler/ConstraintSolver/MemberConstraints.fs delete mode 100644 tests/fsharp/Compiler/ConstraintSolver/PrimitiveConstraints.fs diff --git a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/PrimitiveConstraints.fs b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/PrimitiveConstraints.fs index 33c82b45cc9..873864edaff 100644 --- a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/PrimitiveConstraints.fs +++ b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/PrimitiveConstraints.fs @@ -3,9 +3,7 @@ namespace FSharp.Compiler.ConstraintSolver.ComponentTests open Xunit -open FSharp.Test.Utilities open FSharp.Test.Utilities.Compiler -open FSharp.Compiler.SourceCodeServices module PrimitiveConstraints = @@ -19,3 +17,81 @@ module PrimitiveConstraints = ((__SOURCE_DIRECTORY__ ++ "../testables/"), "typecheck/constructors/neg_invalid_constructor.fs") |> withOptions ["--test:ErrorRanges"] |> typecheck + + + [] + let ``Test primitive : constraints``() = + FSharp""" +#light + +type Foo(x : int) = + member this.Value = x + override this.ToString() = "Foo" + +type Bar(x : int) = + inherit Foo(-1) + member this.Value2 = x + override this.ToString() = "Bar" + +let test1 (x : Foo) = x.Value +let test2 (x : Bar) = (x.Value, x.Value2) + +let f = new Foo(128) +let b = new Bar(256) + +if test1 f <> 128 then failwith "test1 f <> 128" +elif test2 b <> (-1, 256) then failwith "test2 b <> (-1, 256)" +else () + """ + |> compileExeAndRun + + [] + let ``Test primitive :> constraints``() = + FSharp""" +#light +type Foo(x : int) = + member this.Value = x + override this.ToString() = "Foo" + +type Bar(x : int) = + inherit Foo(-1) + member this.Value2 = x + override this.ToString() = "Bar" + +type Ram(x : int) = + inherit Foo(10) + member this.ValueA = x + override this.ToString() = "Ram" + +let test (x : Foo) = (x.Value, x.ToString()) + +let f = new Foo(128) +let b = new Bar(256) +let r = new Ram(314) + +if test f <> (128, "Foo") then failwith "test f <> (128, 'Foo')" +elif test b <> (-1, "Bar") then failwith "test b <> (-1, 'Bar')" +elif test r <> (10, "Ram") then failwith "test r <> (10, 'Ram')" +else () + """ + |> compileExeAndRun + + [] + let ``Test primitive : null constraint``() = + FSharp""" +let inline isNull<'a when 'a : null> (x : 'a) = + match x with + | null -> "is null" + | _ -> (x :> obj).ToString() + +let runTest = + // Wrapping in try block to work around FSB 1989 + try + if isNull null <> "is null" then failwith "isNull null <> is null" + if isNull "F#" <> "F#" then failwith "isNull F# <> F#" + () + with _ -> reraise() + +runTest + """ + |> compileExeAndRun diff --git a/tests/fsharp/Compiler/ConstraintSolver/MemberConstraints.fs b/tests/fsharp/Compiler/ConstraintSolver/MemberConstraints.fs deleted file mode 100644 index e2be187bd78..00000000000 --- a/tests/fsharp/Compiler/ConstraintSolver/MemberConstraints.fs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -namespace FSharp.Compiler.UnitTests - -open NUnit.Framework -open FSharp.Test.Utilities -open FSharp.Compiler.SourceCodeServices - -[] -module MemberConstraints = - - [] - let ``we can overload operators on a type and not add all the extra jazz such as inlining and the ^ operator.``() = - CompilerAssert.CompileExeAndRun - """ -type Foo(x : int) = - member this.Val = x - - static member (-->) ((src : Foo), (target : Foo)) = new Foo(src.Val + target.Val) - static member (-->) ((src : Foo), (target : int)) = new Foo(src.Val + target) - - static member (+) ((src : Foo), (target : Foo)) = new Foo(src.Val + target.Val) - static member (+) ((src : Foo), (target : int)) = new Foo(src.Val + target) - -let x = Foo(3) --> 4 -let y = Foo(3) --> Foo(4) -let x2 = Foo(3) + 4 -let y2 = Foo(3) + Foo(4) - -if x.Val <> 7 then failwith "x.Val <> 7" -elif y.Val <> 7 then failwith "y.Val <> 7" -elif x2.Val <> 7 then failwith "x2.Val <> 7" -elif y2.Val <> 7 then failwith "x.Val <> 7" -else () - """ - - [] - let ``Invalid member constraint with ErrorRanges``() = // Regression test for FSharp1.0:2262 - CompilerAssert.TypeCheckSingleErrorWithOptions - [| "--test:ErrorRanges" |] - """ -let inline length (x: ^a) : int = (^a : (member Length : int with get, set) (x, ())) - """ - FSharpErrorSeverity.Error - 697 - (2, 42, 2, 75) - "Invalid constraint" diff --git a/tests/fsharp/Compiler/ConstraintSolver/PrimitiveConstraints.fs b/tests/fsharp/Compiler/ConstraintSolver/PrimitiveConstraints.fs deleted file mode 100644 index c86f85eb04e..00000000000 --- a/tests/fsharp/Compiler/ConstraintSolver/PrimitiveConstraints.fs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -namespace FSharp.Compiler.UnitTests - -open NUnit.Framework -open FSharp.Test.Utilities -open FSharp.Compiler.SourceCodeServices - -[] -module PrimitiveConstraints = - - [] - let ``Test primitive : constraints``() = - CompilerAssert.CompileExeAndRun - """ -#light - -type Foo(x : int) = - member this.Value = x - override this.ToString() = "Foo" - -type Bar(x : int) = - inherit Foo(-1) - member this.Value2 = x - override this.ToString() = "Bar" - -let test1 (x : Foo) = x.Value -let test2 (x : Bar) = (x.Value, x.Value2) - -let f = new Foo(128) -let b = new Bar(256) - -if test1 f <> 128 then failwith "test1 f <> 128" -elif test2 b <> (-1, 256) then failwith "test2 b <> (-1, 256)" -else () -""" - - [] - let ``Test primitive :> constraints``() = - CompilerAssert.CompileExeAndRun - """ -#light -type Foo(x : int) = - member this.Value = x - override this.ToString() = "Foo" - -type Bar(x : int) = - inherit Foo(-1) - member this.Value2 = x - override this.ToString() = "Bar" - -type Ram(x : int) = - inherit Foo(10) - member this.ValueA = x - override this.ToString() = "Ram" - -let test (x : Foo) = (x.Value, x.ToString()) - -let f = new Foo(128) -let b = new Bar(256) -let r = new Ram(314) - -if test f <> (128, "Foo") then failwith "test f <> (128, 'Foo')" -elif test b <> (-1, "Bar") then failwith "test b <> (-1, 'Bar')" -elif test r <> (10, "Ram") then failwith "test r <> (10, 'Ram')" -else () -""" - - [] - let ``Test primitive : null constraint``() = - CompilerAssert.CompileExeAndRun - """ -let inline isNull<'a when 'a : null> (x : 'a) = - match x with - | null -> "is null" - | _ -> (x :> obj).ToString() - -let runTest = - // Wrapping in try block to work around FSB 1989 - try - if isNull null <> "is null" then failwith "isNull null <> is null" - if isNull "F#" <> "F#" then failwith "isNull F# <> F#" - () - with _ -> reraise() - -runTest -""" - - [] - /// Title: Type checking oddity - /// - /// This suggestion was resolved as by design, - /// so the test makes sure, we're emitting error message about 'not being a valid object construction expression' - let ``Invalid object constructor``() = // Regression test for FSharp1.0:4189 - CompilerAssert.TypeCheckWithErrorsAndOptionsAgainstBaseLine [| "--test:ErrorRanges" |] (__SOURCE_DIRECTORY__ ++ "../../") "typecheck/constructors/neg_invalid_constructor.fs" diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj index f8d78ae0d17..f5cb5c464ab 100644 --- a/tests/fsharp/FSharpSuite.Tests.fsproj +++ b/tests/fsharp/FSharpSuite.Tests.fsproj @@ -37,8 +37,6 @@ - - From 7a6fe9bfba8912bdbb27ff71fabfc90a6ec8c724 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 9 Jul 2020 15:03:02 +0200 Subject: [PATCH 07/21] Changed error message --- tests/FSharp.Test.Utilities/Compiler.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 9c7517df377..4441280a065 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -238,7 +238,7 @@ module Compiler = let run (cResult: CompilationResult ) : unit = match cResult with - | Failure o -> failwith (sprintf "Compilatoin should be successfull in order to run the output.\n Errors: %A" (o.Errors @ o.Warnings)) + | Failure o -> failwith (sprintf "Compilatoin should be successfull in order to run.\n Errors: %A" (o.Errors @ o.Warnings)) | Success s -> match s.OutputPath with | None -> failwith "Compilation didn't produce any output. Unable to run. (did you forget to set output type to Exe?)" From dcf30fae3aa8d7f14372b92d1d6e1571769c91ef Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Sun, 19 Jul 2020 22:52:29 +0200 Subject: [PATCH 08/21] [WIP] Added CSharp compilation + referencing --- RoslynPackageVersion.txt | 2 +- eng/Versions.props | 1 + .../FSharp.Compiler.ComponentTests.fsproj | 5 +- tests/FSharp.Test.Utilities/Compiler.fs | 215 +++++++++++++----- .../FSharp.Test.Utilities.fsproj | 2 +- tests/FSharp.Test.Utilities/Utilities.fs | 4 +- 6 files changed, 162 insertions(+), 67 deletions(-) diff --git a/RoslynPackageVersion.txt b/RoslynPackageVersion.txt index cc99af67911..40c341bdcdb 100644 --- a/RoslynPackageVersion.txt +++ b/RoslynPackageVersion.txt @@ -1 +1 @@ -3.2.0-beta4-19312-15 +3.6.0 diff --git a/eng/Versions.props b/eng/Versions.props index a9b401f28bd..1dac69b52fa 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -174,6 +174,7 @@ 1.0.30 8.0.0-alpha 2.7.0 + 3.6.0 3.0.0-preview-27318-01 3.0.0-preview-27318-01 16.6.1 diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index ebfd10323fc..a9d26284751 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -40,8 +40,9 @@ + - + @@ -49,7 +50,7 @@ - + diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 4441280a065..8bb383522bc 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -10,10 +10,12 @@ open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.CSharp open NUnit.Framework open System +open System.Collections.Immutable +open System.IO module Compiler = - type SourceType = + type TestType = | Text of string | Path of string | Baseline of (string * string) @@ -24,39 +26,48 @@ module Compiler = | IL of ILCompilationSource and FSharpCompilationSource = - { Source: SourceType + { Source: TestType Options: string list OutputType: CompileOutput SourceKind: SourceKind - Name : string option + Name: string option IgnoreWarnings: bool References: CompilationUnit list } and CSharpCompilationSource = - { Source: SourceType + { Source: TestType LangVersion: CSharpLanguageVersion TargetFramework: TargetFramework Name: string option References: CompilationUnit list } and ILCompilationSource = - { Source: SourceType + { Source: TestType References: CompilationUnit list} - // TODO: Do we need separate types for Compilation/Typecheck/Run results? - type CompilationOutput = { OutputPath: string option - Adjust: int - Errors: FSharpErrorInfo list - Warnings: FSharpErrorInfo list } + type ErrorSeverity = Error | Warning + + type ErrorInfo = { Severity: ErrorSeverity + ErrorNumber: int + StartLineAlternate: int + StartColumn: int + EndLineAlternate: int + EndColumn: int + Message: string } + + type Output = { OutputPath: string option + Adjust: int + Errors: ErrorInfo list + Warnings: ErrorInfo list } type CompilationResult = - | Success of CompilationOutput - | Failure of CompilationOutput + | Success of Output + | Failure of Output let private defaultOptions : string list = [] // Not very safe version of reading stuff from file, but we want to fail fast for now if anything goes wrong. - let private getSource (src: SourceType) : string = + let private getSource (src: TestType) : string = match src with | Text t -> t | Path p -> System.IO.File.ReadAllText p @@ -82,13 +93,26 @@ module Compiler = Name = None; References = [] } - let private fromFile (_: string) : CompilationUnit = failwith "TODO" + let private fromFSharpErrorInfo (errors: FSharpErrorInfo[]) : (ErrorInfo list * ErrorInfo list) = + let toErrorInfo (e: FSharpErrorInfo) : ErrorInfo = + { Severity = if e.Severity = FSharpErrorSeverity.Warning then Warning else Error; + ErrorNumber = e.ErrorNumber; + StartLineAlternate = e.StartLineAlternate; + StartColumn = e.StartColumn; + EndLineAlternate = e.EndLineAlternate; + EndColumn = e.EndColumn; + Message = e.Message } + + errors |> List.ofArray + |> List.map toErrorInfo + |> List.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) + |> List.partition (fun e -> e.Severity = Error) let Fsx (source: string) : CompilationUnit = - fsFromString source SourceKind.Fsx |> CompilationUnit.FS + fsFromString source Fsx |> FS let FSharp (source: string) : CompilationUnit = - fsFromString source SourceKind.Fs |> CompilationUnit.FS + fsFromString source Fs |> FS let baseline (dir: string, file: string) : CompilationUnit = match (dir, file) with @@ -97,44 +121,44 @@ module Compiler = | _ -> { Source = Baseline (dir, file); Options = defaultOptions; OutputType = Library; - SourceKind = SourceKind.Fs; + SourceKind = Fs; Name = None; IgnoreWarnings = false; - References = [] } |> CompilationUnit.FS + References = [] } |> FS let CSharp (source: string) : CompilationUnit = - csFromString source |> CompilationUnit.CS + csFromString source |> CS let withName (name: string) (cUnit: CompilationUnit) : CompilationUnit = match cUnit with - | FS src -> CompilationUnit.FS { src with Name = Some name } - | CS src -> CompilationUnit.CS { src with Name = Some name } + | FS src -> FS { src with Name = Some name } + | CS src -> CS { src with Name = Some name } | IL _ -> failwith "IL Compilation cannot be named." let withReferences (references: CompilationUnit list) (cUnit: CompilationUnit) : CompilationUnit = match cUnit with | FS fs -> FS { fs with References = fs.References @ references } | CS cs -> CS { cs with References = cs.References @ references } - | IL _ -> failwith "TODO: Support references for IL" + | IL _ -> failwith "References are not supported in IL" let withOptions (options: string list) (cUnit: CompilationUnit) : CompilationUnit = match cUnit with - | FS fs -> CompilationUnit.FS { fs with Options = options } - | _ -> failwith "TODO: Implement where applicable." + | FS fs -> FS { fs with Options = options } + | _ -> failwith "withOptions is only supported n F#" let asLibrary (cUnit: CompilationUnit) : CompilationUnit = match cUnit with - | FS fs -> CompilationUnit.FS { fs with OutputType = CompileOutput.Library } + | FS fs -> FS { fs with OutputType = CompileOutput.Library } | _ -> failwith "TODO: Implement where applicable." let asExe (cUnit: CompilationUnit) : CompilationUnit = match cUnit with - | FS fs -> CompilationUnit.FS { fs with OutputType = CompileOutput.Exe } + | FS fs -> FS { fs with OutputType = CompileOutput.Exe } | _ -> failwith "TODO: Implement where applicable." let ignoreWarnings (cUnit: CompilationUnit) : CompilationUnit = match cUnit with - | FS fs -> CompilationUnit.FS { fs with IgnoreWarnings = true } + | FS fs -> FS { fs with IgnoreWarnings = true } | _ -> failwith "TODO: Implement ignorewarnings for the rest." let private processReferences (references: CompilationUnit list) = @@ -149,9 +173,10 @@ module Compiler = let cmpl = Compilation.Create(source, fs.SourceKind, fs.OutputType, cmplRefs = refs, name = name) |> CompilationReference.CreateFSharp loop (cmpl::acc) xs | CS cs -> - let source = getSource cs.Source // TODO: reference support for C#, convert CompilationReference to MetadataReference + let source = getSource cs.Source let name = if Option.isSome cs.Name then cs.Name.Value else null + // TODO: Move to internal 'compileCSharp' and wrap into the TestCompilation let cmpl = CompilationUtil.CreateCSharpCompilation(source, cs.LangVersion, cs.TargetFramework, name = name) |> CompilationReference.Create loop (cmpl::acc) xs | IL _ -> failwith "TODO: Process references for IL" @@ -170,9 +195,7 @@ module Compiler = let ((err: FSharpErrorInfo[], outputFilePath: string), _) = CompilerAssert.CompileRaw(compilation) - let (errors, warnings) = err |> Array.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) - |> Array.partition (fun e -> e.Severity = FSharpErrorSeverity.Error) - |> fun (f, s) -> f |> List.ofArray, s |> List.ofArray + let (errors, warnings) = err |> fromFSharpErrorInfo let result = { OutputPath = None; Adjust = 0; @@ -187,15 +210,58 @@ module Compiler = Success { result with Warnings = warnings; OutputPath = Some outputFilePath } + let private compileCSharp (csSource: CSharpCompilationSource) : CompilationResult = + + let source = getSource csSource.Source + let name = if Option.isSome csSource.Name then csSource.Name.Value else Guid.NewGuid().ToString () + + // TODO: Process references (and convert CompilationReference -> MetadataReference) + let additionalReferences = ImmutableArray.Empty + let references = TargetFrameworkUtil.getReferences csSource.TargetFramework + + // TODO: Remove once moved reference processing to this function instead of CompilationUtil + let lv = + match csSource.LangVersion with + | CSharpLanguageVersion.CSharp8 -> LanguageVersion.CSharp8 + | _ -> LanguageVersion.Default + + let cmpl = + CSharpCompilation.Create( + name, + [ CSharpSyntaxTree.ParseText (source, CSharpParseOptions lv) ], + references.As().AddRange additionalReferences, + CSharpCompilationOptions (OutputKind.DynamicallyLinkedLibrary)) + + let outputPath = Path.Combine(Path.GetTempPath(), "FSharpCompilerTests", Path.GetRandomFileName()) + + Directory.CreateDirectory(outputPath) |> ignore + + let filename = cmpl.AssemblyName + let output = Path.Combine(outputPath, Path.ChangeExtension(filename, ".dll")) + + let cmplResult = cmpl.Emit (output) + + let result = { OutputPath = None; + Adjust = 0; + Warnings = []; + Errors = [] } + + if cmplResult.Success then + Success { result with OutputPath = Some output } + else + cmplResult.Diagnostics |> printfn "%A" + Failure result + + let compile (cUnit: CompilationUnit) : CompilationResult = match cUnit with | FS fs -> compileFSharp fs + | CS cs -> compileCSharp cs | _ -> failwith "TODO" - // TODO: Probably want to return a proper compilation result here as well to process it later. let private typecheckFSharpWithBaseline (options: string list) (dir: string) (file: string) : CompilationResult = // Since TypecheckWithErrorsAndOptionsAgainsBaseLine throws if doesn't match expected baseline, - // We return a successfull CompilationResult if it succeds. + // We return a successfull CompilationResult if it succeeds. CompilerAssert.TypeCheckWithErrorsAndOptionsAgainstBaseLine (Array.ofList options) dir file Success { OutputPath = None; @@ -203,16 +269,13 @@ module Compiler = Warnings = []; Errors = [] } - // TODO: Extract error handling to a separate function; let private typecheckFSharpSource (fsSource: FSharpCompilationSource) : CompilationResult = let source = getSource fsSource.Source let options = fsSource.Options |> Array.ofList let (err: FSharpErrorInfo []) = CompilerAssert.TypeCheckWithOptions options source - let (errors, warnings) = err |> Array.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) - |> Array.partition (fun e -> e.Severity = FSharpErrorSeverity.Error) - |> fun (f, s) -> List.ofArray f, List.ofArray s + let (errors, warnings) = err |> fromFSharpErrorInfo let result = { OutputPath = None; Adjust = 0; @@ -234,11 +297,11 @@ module Compiler = let typecheck (cUnit: CompilationUnit) : CompilationResult = match cUnit with | FS fs -> typecheckFSharp fs - | _ -> failwith "TODO: Implement typeckeck for C# and IL if applicable." + | _ -> failwith "Typecheck only supports F#" let run (cResult: CompilationResult ) : unit = match cResult with - | Failure o -> failwith (sprintf "Compilatoin should be successfull in order to run.\n Errors: %A" (o.Errors @ o.Warnings)) + | Failure o -> failwith (sprintf "Compilation should be successfull in order to run.\n Errors: %A" (o.Errors @ o.Warnings)) | Success s -> match s.OutputPath with | None -> failwith "Compilation didn't produce any output. Unable to run. (did you forget to set output type to Exe?)" @@ -247,38 +310,40 @@ module Compiler = let compileAndRun = compile >> run let compileExeAndRun = asExe >> compileAndRun - + [] - // TODO: Reuse FluentAssertions' assertions here. module Assertions = - - let private getErrorInfo (info: FSharpErrorInfo) : string = + let private getErrorInfo (info: ErrorInfo) : string = sprintf "%A %A %A" info.Severity info.ErrorNumber info.Message - // TODO: Better error messages. - // TODO: Should probably generalize/dedupicate asserts - let private assertErrorsLength (source: FSharpErrorInfo list) (expected: int list) : unit = + let inline private assertErrorsLength (source: ErrorInfo list) (expected: 'a list) : unit = if (List.length source) <> (List.length expected) then failwith (sprintf "Expected list of issues differ from compilation result:\nExpected:\n %A\nActual:\n %A" expected (List.map getErrorInfo source)) () - let private assertErrorNumber (source: FSharpErrorInfo list) (expected: int list) : unit = + let private assertErrorMessages (source: ErrorInfo list) (expected: string list) : unit = for exp in expected do - if not (List.exists (fun (el: FSharpErrorInfo) -> el.ErrorNumber = exp) source) then - failwith (sprintf "Mismatch in ErrorNumber, expected '%A' was not found during compilation.\nAll messages:\n%A" exp (List.map getErrorInfo source)) + if not (List.exists (fun (el: ErrorInfo) -> el.Message = exp) source) then + failwith (sprintf "Mismatch in error message, expected '%A' was not found during compilation.\nAll errors:\n%A" exp (List.map getErrorInfo source)) assertErrorsLength source expected - let private assertErrors (what: string) libAdjust (source: FSharpErrorInfo list) (expected: (int * (int * int * int * int) * string) list) : unit = + let private assertErrorNumbers (source: ErrorInfo list) (expected: int list) : unit = + for exp in expected do + if not (List.exists (fun (el: ErrorInfo) -> el.ErrorNumber = exp) source) then + failwith (sprintf "Mismatch in ErrorNumber, expected '%A' was not found during compilation.\nAll errors:\n%A" exp (List.map getErrorInfo source)) + assertErrorsLength source expected + + let private assertErrors (what: string) libAdjust (source: ErrorInfo list) (expected: (int * (int * int * int * int) * string) list) : unit = let errors = source - |> List.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) |> List.map (fun info -> (info.ErrorNumber, (info.StartLineAlternate - libAdjust, info.StartColumn + 1, info.EndLineAlternate - libAdjust, info.EndColumn + 1), info.Message)) let inline checkEqual k a b = if a <> b then Assert.AreEqual(a, b, sprintf "%s: Mismatch in %s, expected '%A', got '%A'.\nAll errors:\n%A" what k a b errors) - checkEqual "Errors" expected.Length errors.Length + // TODO: Check all "categories", collect all results and print alltogether. + checkEqual "Errors count" expected.Length errors.Length List.zip errors expected |> List.iter (fun (actualError, expectedError) -> @@ -297,18 +362,43 @@ module Compiler = let shouldSucceed (result: CompilationResult) : CompilationResult = match result with | Success _ -> result - | Failure _ -> failwith "Compilation failed (expected: Success)." + | Failure r -> + let message = sprintf "Compilation failed (expected to succeed).\n All errors:\n%A" (r.Errors @ r.Warnings) + failwith message let shouldFail (result: CompilationResult) : CompilationResult = match result with - | Failure _ -> result | Success _ -> failwith "Compilation succeded (expected: Failure)." + | Failure _ -> result + + let withMessages (messages: string list) (result: CompilationResult) : CompilationResult = + match result with + | Success r | Failure r -> assertErrorMessages (r.Warnings @ r.Errors) messages + result + + let withMessage (message: string) (result: CompilationResult) : CompilationResult = + withMessages [message] result + + let withErrorMessages (messages: string list) (result: CompilationResult) : CompilationResult = + match result with + | Success r | Failure r -> assertErrorMessages r.Errors messages + result + + let withErrorMessage (message: string) (result: CompilationResult) : CompilationResult = + withErrorMessages [message] result + + let withWarningMessages (messages: string list) (result: CompilationResult) : CompilationResult = + match result with + | Success r | Failure r -> assertErrorMessages r.Warnings messages + result + + let withWarningMessage (message: string) (result: CompilationResult) : CompilationResult = + withWarningMessages [message] result let withWarnings (expectedWarnings: (int * (int * int * int * int) * string) list) (result: CompilationResult) : CompilationResult = match result with | Success r | Failure r -> assertErrors "Warnings" r.Adjust r.Warnings expectedWarnings - result let withWarning (expectedWarning: (int * (int * int * int * int) * string)) (result: CompilationResult) : CompilationResult = @@ -317,15 +407,16 @@ module Compiler = let withWarningCodes (expectedWarnings: int list) (result: CompilationResult) : CompilationResult = match result with | Success r | Failure r -> - assertErrorNumber r.Warnings expectedWarnings - + assertErrorNumbers r.Warnings expectedWarnings result + let withWarningCode (expectedWarning: int) (result: CompilationResult) : CompilationResult = + withWarningCodes [expectedWarning] result + let withErrors (expectedErrors: (int * (int * int * int * int) * string) list) (result: CompilationResult) : CompilationResult = match result with | Success r | Failure r -> assertErrors "Errors" r.Adjust r.Errors expectedErrors - result let withError (expectedError: (int * (int * int * int * int) * string)) (result: CompilationResult) : CompilationResult = @@ -334,6 +425,10 @@ module Compiler = let withErrorCodes (expectedErrors: int list) (result: CompilationResult) : CompilationResult = match result with | Success r | Failure r -> - assertErrorNumber r.Errors expectedErrors - + assertErrorNumbers r.Errors expectedErrors result + + let withErrorCode (expectedError: int) (result: CompilationResult) : CompilationResult = + withErrorCodes [expectedError] result + + let withRange = ignore diff --git a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj index 8487625d4de..3d97f8aea6a 100644 --- a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj +++ b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj @@ -35,7 +35,7 @@ - + diff --git a/tests/FSharp.Test.Utilities/Utilities.fs b/tests/FSharp.Test.Utilities/Utilities.fs index 1415fee273f..5ffee2b6877 100644 --- a/tests/FSharp.Test.Utilities/Utilities.fs +++ b/tests/FSharp.Test.Utilities/Utilities.fs @@ -39,7 +39,7 @@ module Utilities = let systemConsoleRef = lazy AssemblyMetadata.CreateFromImage(TestResources.NetFX.netcoreapp30.System_Console).GetReference(display = "System.Console.dll (netcoreapp 3.0 ref)") [] - module private TargetFrameworkUtil = + module internal TargetFrameworkUtil = open TestReferences @@ -60,8 +60,6 @@ module Utilities = | None = 0x0 | InternalsVisibleTo = 0x1 - // TODO: this and Compilation.Compile needs to be merged for sake of consistency. - // TODO: After merging, add new type of FSharp compilation. [] type TestCompilation = | CSharp of CSharpCompilation From 285d6e89a9317f9e34e63ee8bee7f924d74fdd08 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Sun, 19 Jul 2020 23:05:37 +0200 Subject: [PATCH 09/21] Added some simple interop tests --- .../Interop/SimpleInteropTests.fs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs new file mode 100644 index 00000000000..b2bc2a86270 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.ErrorMessages.ComponentTests + +open Xunit +open FSharp.Test.Utilities +open FSharp.Test.Utilities.Compiler + +module ``C# <-> F# basic interop`` = + + [] + let ``Instantiate C# type from F#`` () = + + let CSLib = + CSharp """ +public class A { } + """ |> withName "CSLib" + + let FSLib = + FSharp """ +module AMaker +let makeA () : A = A() + """ |> withName "FSLib" |> withReferences [CSLib] + + let app = + FSharp """ +module ReferenceCSfromFS +let a = AMaker.makeA() + """ |> withReferences [CSLib; FSLib] + + app + |> compile + |> shouldSucceed + + + [] + let ``Instantiate F# type from C#`` () = + let FSLib = + FSharp """ +namespace Interop.FS +type Bicycle(manufacturer: string) = + member this.Manufactirer = manufacturer + """ |> withName "FSLib" + + let app = + CSharp """ +public class BicycleShop { + public Bicycle[] cycles; +} + """ |> withReferences [FSLib] + app + |> compile + |> shouldSucceed From ed00d7e1ea0c67b22d2026175ddfd6a97f65d1ff Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Mon, 20 Jul 2020 15:32:27 +0200 Subject: [PATCH 10/21] [WIP] Process MetadataReference recursively --- .../Interop/SimpleInteropTests.fs | 2 + tests/FSharp.Test.Utilities/Compiler.fs | 97 ++++++++++++------- 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs index b2bc2a86270..7fdbfa5f20a 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs @@ -44,10 +44,12 @@ type Bicycle(manufacturer: string) = let app = CSharp """ +using Interop.FS; public class BicycleShop { public Bicycle[] cycles; } """ |> withReferences [FSLib] + app |> compile |> shouldSucceed diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 8bb383522bc..cb684c9a94d 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -161,7 +161,22 @@ module Compiler = | FS fs -> FS { fs with IgnoreWarnings = true } | _ -> failwith "TODO: Implement ignorewarnings for the rest." - let private processReferences (references: CompilationUnit list) = + let rec private asMetadataReference reference = + match reference with + | CompilationReference (cmpl, _) -> + let result = compileFSharpCompilation cmpl false + match result with + | Failure f -> + let message = sprintf "Compilation failed (expected to succeed).\n All errors:\n%A" (f.Errors @ f.Warnings) + failwith message + | Success s -> + match s.OutputPath with + | None -> failwith "Compilation didn't produce any output!" + | Some p -> p |> MetadataReference.CreateFromFile + | _ -> failwith "Conversion isn't possible" + + and private processReferences (references: CompilationUnit list) = + let rec loop acc = function | [] -> List.rev acc | x::xs -> @@ -173,25 +188,19 @@ module Compiler = let cmpl = Compilation.Create(source, fs.SourceKind, fs.OutputType, cmplRefs = refs, name = name) |> CompilationReference.CreateFSharp loop (cmpl::acc) xs | CS cs -> - // TODO: reference support for C#, convert CompilationReference to MetadataReference + let refs = loop [] cs.References let source = getSource cs.Source let name = if Option.isSome cs.Name then cs.Name.Value else null - // TODO: Move to internal 'compileCSharp' and wrap into the TestCompilation - let cmpl = CompilationUtil.CreateCSharpCompilation(source, cs.LangVersion, cs.TargetFramework, name = name) |> CompilationReference.Create + let metadataReferences = List.map asMetadataReference refs + metadataReferences |> ignore + // additionalReferences = ImmutableArray.CreateRange metadataReferences, + let cmpl = CompilationUtil.CreateCSharpCompilation(source, cs.LangVersion, cs.TargetFramework, name = name) + |> CompilationReference.Create loop (cmpl::acc) xs | IL _ -> failwith "TODO: Process references for IL" loop [] references - let private compileFSharp (fsSource: FSharpCompilationSource) : CompilationResult = - - let source = getSource fsSource.Source - let sourceKind = fsSource.SourceKind - let output = fsSource.OutputType - let options = fsSource.Options |> Array.ofList - - let references = processReferences fsSource.References - - let compilation = Compilation.Create(source, sourceKind, output, options, references) + and private compileFSharpCompilation compilation ignoreWarnings : CompilationResult = let ((err: FSharpErrorInfo[], outputFilePath: string), _) = CompilerAssert.CompileRaw(compilation) @@ -203,43 +212,36 @@ module Compiler = Errors = errors } // Treat warnings as errors if "IgnoreWarnings" is false; - if errors.Length > 0 || (warnings.Length > 0 && not fsSource.IgnoreWarnings) then + if errors.Length > 0 || (warnings.Length > 0 && not ignoreWarnings) then Failure { result with Warnings = warnings; Errors = errors } else Success { result with Warnings = warnings; OutputPath = Some outputFilePath } - let private compileCSharp (csSource: CSharpCompilationSource) : CompilationResult = + and private compileFSharp (fsSource: FSharpCompilationSource) : CompilationResult = - let source = getSource csSource.Source - let name = if Option.isSome csSource.Name then csSource.Name.Value else Guid.NewGuid().ToString () + let source = getSource fsSource.Source + let sourceKind = fsSource.SourceKind + let output = fsSource.OutputType + let options = fsSource.Options |> Array.ofList - // TODO: Process references (and convert CompilationReference -> MetadataReference) - let additionalReferences = ImmutableArray.Empty - let references = TargetFrameworkUtil.getReferences csSource.TargetFramework + let references = processReferences fsSource.References - // TODO: Remove once moved reference processing to this function instead of CompilationUtil - let lv = - match csSource.LangVersion with - | CSharpLanguageVersion.CSharp8 -> LanguageVersion.CSharp8 - | _ -> LanguageVersion.Default + let compilation = Compilation.Create(source, sourceKind, output, options, references) - let cmpl = - CSharpCompilation.Create( - name, - [ CSharpSyntaxTree.ParseText (source, CSharpParseOptions lv) ], - references.As().AddRange additionalReferences, - CSharpCompilationOptions (OutputKind.DynamicallyLinkedLibrary)) + compileFSharpCompilation compilation fsSource.IgnoreWarnings + + and private compileCSharpCompilation (compilation: CSharpCompilation) : CompilationResult = let outputPath = Path.Combine(Path.GetTempPath(), "FSharpCompilerTests", Path.GetRandomFileName()) Directory.CreateDirectory(outputPath) |> ignore - let filename = cmpl.AssemblyName + let filename = compilation.AssemblyName let output = Path.Combine(outputPath, Path.ChangeExtension(filename, ".dll")) - let cmplResult = cmpl.Emit (output) + let cmplResult = compilation.Emit (output) let result = { OutputPath = None; Adjust = 0; @@ -252,8 +254,33 @@ module Compiler = cmplResult.Diagnostics |> printfn "%A" Failure result + and private compileCSharp (csSource: CSharpCompilationSource) : CompilationResult = + + let source = getSource csSource.Source + let name = if Option.isSome csSource.Name then csSource.Name.Value else Guid.NewGuid().ToString () + + let additionalReferences = + match processReferences csSource.References with + | [] -> ImmutableArray.Empty + | r -> (List.map asMetadataReference r).ToImmutableArray().As() + + let references = TargetFrameworkUtil.getReferences csSource.TargetFramework + + let lv = + match csSource.LangVersion with + | CSharpLanguageVersion.CSharp8 -> LanguageVersion.CSharp8 + | _ -> LanguageVersion.Default + + let cmpl = + CSharpCompilation.Create( + name, + [ CSharpSyntaxTree.ParseText (source, CSharpParseOptions lv) ], + references.As().AddRange additionalReferences, + CSharpCompilationOptions (OutputKind.DynamicallyLinkedLibrary)) + + cmpl |> compileCSharpCompilation - let compile (cUnit: CompilationUnit) : CompilationResult = + and compile (cUnit: CompilationUnit) : CompilationResult = match cUnit with | FS fs -> compileFSharp fs | CS cs -> compileCSharp cs From a91288cc134f923ce373945efb4f9589e26a1cbc Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Mon, 20 Jul 2020 18:04:27 +0200 Subject: [PATCH 11/21] [WIP] Added netcorapp31 support for tests --- eng/Versions.props | 2 +- tests/FSharp.Test.Utilities/Compiler.fs | 4 +- tests/FSharp.Test.Utilities/Utilities.fs | 65 ++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 1dac69b52fa..415cf5eb7d1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -103,7 +103,7 @@ $(RoslynVersion) $(RoslynVersion) $(RoslynVersion) - 2.0.17 + 2.0.28 $(RoslynVersion) 16.4 diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index cb684c9a94d..464d0e0aced 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -192,9 +192,7 @@ module Compiler = let source = getSource cs.Source let name = if Option.isSome cs.Name then cs.Name.Value else null let metadataReferences = List.map asMetadataReference refs - metadataReferences |> ignore - // additionalReferences = ImmutableArray.CreateRange metadataReferences, - let cmpl = CompilationUtil.CreateCSharpCompilation(source, cs.LangVersion, cs.TargetFramework, name = name) + let cmpl = CompilationUtil.CreateCSharpCompilation(source, cs.LangVersion, cs.TargetFramework, additionalReferences = metadataReferences.ToImmutableArray().As(), name = name) |> CompilationReference.Create loop (cmpl::acc) xs | IL _ -> failwith "TODO: Process references for IL" diff --git a/tests/FSharp.Test.Utilities/Utilities.fs b/tests/FSharp.Test.Utilities/Utilities.fs index 5ffee2b6877..f99121c1434 100644 --- a/tests/FSharp.Test.Utilities/Utilities.fs +++ b/tests/FSharp.Test.Utilities/Utilities.fs @@ -4,6 +4,7 @@ namespace FSharp.Test.Utilities open System open System.IO +open System.Reflection open System.Collections.Immutable open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.CSharp @@ -18,8 +19,59 @@ module Utilities = type TargetFramework = | NetStandard20 | NetCoreApp30 + | NetCoreApp31 + + let private getResourceStream name = + let assembly = typeof.GetTypeInfo().Assembly + + let stream = assembly.GetManifestResourceStream(name); + + match stream with + | null -> failwith (sprintf "Resource '%s' not found in %s." name assembly.FullName) + | _ -> stream + + let private getResourceBlob name = + use stream = getResourceStream name + let (bytes: byte[]) = Array.zeroCreate (int stream.Length) + use memoryStream = new MemoryStream (bytes) + stream.CopyTo(memoryStream) + bytes + + let private getOrCreateResource (resource: byref) (name: string) = + match resource with + | null -> getResourceBlob name + | _ -> resource module private TestReferences = + module NetCoreApp31Refs = + let mutable (_Microsoft_CSharp: byte[]) = Unchecked.defaultof + let mutable (_Microsoft_VisualBasic_Core: byte[]) = Unchecked.defaultof + let mutable (_mscorlib: byte[]) = Unchecked.defaultof + let mutable (_netstandard: byte[]) = Unchecked.defaultof + let mutable (_System_Collections: byte[]) = Unchecked.defaultof + let mutable (_System_Console: byte[]) = Unchecked.defaultof + let mutable (_System_Core: byte[]) = Unchecked.defaultof + let mutable (_System_Dynamic_Runtime: byte[]) = Unchecked.defaultof + let mutable (_System_Linq: byte[]) = Unchecked.defaultof + let mutable (_System_Linq_Expressions: byte[]) = Unchecked.defaultof + let mutable (_System_Runtime: byte[]) = Unchecked.defaultof + let mutable (_System_Threading_Tasks: byte[]) = Unchecked.defaultof + let mutable (_System_Runtime_InteropServices_WindowsRuntime: byte[]) = Unchecked.defaultof + let mscorlib () = getOrCreateResource &_mscorlib "netcoreapp31.mscorlib.dll" + let netstandard () = getOrCreateResource &_netstandard "netcoreapp31.netstandard.dll" + let System_Core () = getOrCreateResource &_System_Core "netcoreapp31.System.Core.dll" + let System_Linq () = getOrCreateResource &_System_Linq "netcoreapp31.System.Linq.dll" + let System_Console () = getOrCreateResource &_System_Console "netcoreapp31.System.Console.dll" + let System_Runtime () = getOrCreateResource &_System_Runtime "netcoreapp31.System.Runtime.dll" + let Microsoft_CSharp () = getOrCreateResource &_Microsoft_CSharp "netcoreapp31.Microsoft.CSharp.dll" + let System_Collections () = getOrCreateResource &_System_Collections "netcoreapp31.System.Collections.dll" + let System_Threading_Tasks () = getOrCreateResource &_System_Threading_Tasks "netcoreapp31.System.Threading.Tasks.dll" + let System_Dynamic_Runtime () = getOrCreateResource &_System_Dynamic_Runtime "netcoreapp31.System.Dynamic.Runtime.dll" + let System_Linq_Expressions () = getOrCreateResource &_System_Linq_Expressions "netcoreapp31.System.Linq.Expressions.dll" + let Microsoft_VisualBasic_Core () = getOrCreateResource &_Microsoft_VisualBasic_Core "netcoreapp31.Microsoft.VisualBasic.Core.dll" + let System_Runtime_InteropServices_WindowsRuntime () = getOrCreateResource &_System_Runtime_InteropServices_WindowsRuntime "netcoreapp31.System.Runtime.InteropServices.WindowsRuntime.dll" + + [] module NetStandard20 = @@ -38,6 +90,15 @@ module Utilities = let systemDynamicRuntimeRef = lazy AssemblyMetadata.CreateFromImage(TestResources.NetFX.netcoreapp30.System_Dynamic_Runtime).GetReference(display = "System.Dynamic.Runtime.dll (netcoreapp 3.0 ref)") let systemConsoleRef = lazy AssemblyMetadata.CreateFromImage(TestResources.NetFX.netcoreapp30.System_Console).GetReference(display = "System.Console.dll (netcoreapp 3.0 ref)") + [] + module NetCoreApp31 = + let netStandard = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.netstandard ()).GetReference(display = "netstandard.dll (netcoreapp 3.1 ref)") + let mscorlibRef = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.mscorlib ()).GetReference(display = "mscorlib.dll (netcoreapp 3.1 ref)") + let systemRuntimeRef = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.System_Runtime ()).GetReference(display = "System.Runtime.dll (netcoreapp 3.1 ref)") + let systemCoreRef = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.System_Core ()).GetReference(display = "System.Core.dll (netcoreapp 3.1 ref)") + let systemDynamicRuntimeRef = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.System_Dynamic_Runtime ()).GetReference(display = "System.Dynamic.Runtime.dll (netcoreapp 3.1 ref)") + let systemConsoleRef = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.System_Console ()).GetReference(display = "System.Console.dll (netcoreapp 3.1 ref)") + [] module internal TargetFrameworkUtil = @@ -47,11 +108,15 @@ module Utilities = lazy ImmutableArray.Create(NetStandard20.netStandard.Value, NetStandard20.mscorlibRef.Value, NetStandard20.systemRuntimeRef.Value, NetStandard20.systemCoreRef.Value, NetStandard20.systemDynamicRuntimeRef.Value) let private netCoreApp30References = lazy ImmutableArray.Create(NetCoreApp30.netStandard.Value, NetCoreApp30.mscorlibRef.Value, NetCoreApp30.systemRuntimeRef.Value, NetCoreApp30.systemCoreRef.Value, NetCoreApp30.systemDynamicRuntimeRef.Value, NetCoreApp30.systemConsoleRef.Value) + let private netCoreApp31References = + lazy ImmutableArray.Create(NetCoreApp31.netStandard.Value, NetCoreApp31.mscorlibRef.Value, NetCoreApp31.systemRuntimeRef.Value, NetCoreApp31.systemCoreRef.Value, NetCoreApp31.systemDynamicRuntimeRef.Value, NetCoreApp31.systemConsoleRef.Value) + let internal getReferences tf = match tf with | TargetFramework.NetStandard20 -> netStandard20References.Value | TargetFramework.NetCoreApp30 -> netCoreApp30References.Value + | TargetFramework.NetCoreApp31 -> netCoreApp31References.Value type RoslynLanguageVersion = LanguageVersion From d8f4542344b4ce781f401080880e56c9bc93d17d Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Tue, 21 Jul 2020 18:23:46 +0200 Subject: [PATCH 12/21] [WIP] Termporary revert to using netcoreapp30 in the tests (instead of netcoreapp31) --- .../Interop/SimpleInteropTests.fs | 20 ++++++ tests/FSharp.Test.Utilities/CompilerAssert.fs | 6 +- tests/FSharp.Test.Utilities/Utilities.fs | 64 ------------------- 3 files changed, 23 insertions(+), 67 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs index 7fdbfa5f20a..a32e83e9e18 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs @@ -53,3 +53,23 @@ public class BicycleShop { app |> compile |> shouldSucceed + + [] + let ``Instantiate F# type from C# fails without import`` () = + let FSLib = + FSharp """ +namespace Interop.FS +type Bicycle(manufacturer: string) = + member this.Manufactirer = manufacturer + """ |> withName "FSLib" + + let app = + CSharp """ +public class BicycleShop { + public Bicycle[] cycles; +} + """ |> withReferences [FSLib] + + app + |> compile + |> shouldFail diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index 4956b3e2035..73a15f94d6b 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -90,7 +90,7 @@ type CompilerAssert private () = Exe - netcoreapp3.1 + netcoreapp3.0 true true @@ -405,10 +405,10 @@ let main argv = 0""" """ { "runtimeOptions": { - "tfm": "netcoreapp3.1", + "tfm": "netcoreapp3.0", "framework": { "name": "Microsoft.NETCore.App", - "version": "3.1.0" + "version": "3.0.0" } } } diff --git a/tests/FSharp.Test.Utilities/Utilities.fs b/tests/FSharp.Test.Utilities/Utilities.fs index f99121c1434..9db412a1361 100644 --- a/tests/FSharp.Test.Utilities/Utilities.fs +++ b/tests/FSharp.Test.Utilities/Utilities.fs @@ -19,60 +19,8 @@ module Utilities = type TargetFramework = | NetStandard20 | NetCoreApp30 - | NetCoreApp31 - - let private getResourceStream name = - let assembly = typeof.GetTypeInfo().Assembly - - let stream = assembly.GetManifestResourceStream(name); - - match stream with - | null -> failwith (sprintf "Resource '%s' not found in %s." name assembly.FullName) - | _ -> stream - - let private getResourceBlob name = - use stream = getResourceStream name - let (bytes: byte[]) = Array.zeroCreate (int stream.Length) - use memoryStream = new MemoryStream (bytes) - stream.CopyTo(memoryStream) - bytes - - let private getOrCreateResource (resource: byref) (name: string) = - match resource with - | null -> getResourceBlob name - | _ -> resource module private TestReferences = - module NetCoreApp31Refs = - let mutable (_Microsoft_CSharp: byte[]) = Unchecked.defaultof - let mutable (_Microsoft_VisualBasic_Core: byte[]) = Unchecked.defaultof - let mutable (_mscorlib: byte[]) = Unchecked.defaultof - let mutable (_netstandard: byte[]) = Unchecked.defaultof - let mutable (_System_Collections: byte[]) = Unchecked.defaultof - let mutable (_System_Console: byte[]) = Unchecked.defaultof - let mutable (_System_Core: byte[]) = Unchecked.defaultof - let mutable (_System_Dynamic_Runtime: byte[]) = Unchecked.defaultof - let mutable (_System_Linq: byte[]) = Unchecked.defaultof - let mutable (_System_Linq_Expressions: byte[]) = Unchecked.defaultof - let mutable (_System_Runtime: byte[]) = Unchecked.defaultof - let mutable (_System_Threading_Tasks: byte[]) = Unchecked.defaultof - let mutable (_System_Runtime_InteropServices_WindowsRuntime: byte[]) = Unchecked.defaultof - let mscorlib () = getOrCreateResource &_mscorlib "netcoreapp31.mscorlib.dll" - let netstandard () = getOrCreateResource &_netstandard "netcoreapp31.netstandard.dll" - let System_Core () = getOrCreateResource &_System_Core "netcoreapp31.System.Core.dll" - let System_Linq () = getOrCreateResource &_System_Linq "netcoreapp31.System.Linq.dll" - let System_Console () = getOrCreateResource &_System_Console "netcoreapp31.System.Console.dll" - let System_Runtime () = getOrCreateResource &_System_Runtime "netcoreapp31.System.Runtime.dll" - let Microsoft_CSharp () = getOrCreateResource &_Microsoft_CSharp "netcoreapp31.Microsoft.CSharp.dll" - let System_Collections () = getOrCreateResource &_System_Collections "netcoreapp31.System.Collections.dll" - let System_Threading_Tasks () = getOrCreateResource &_System_Threading_Tasks "netcoreapp31.System.Threading.Tasks.dll" - let System_Dynamic_Runtime () = getOrCreateResource &_System_Dynamic_Runtime "netcoreapp31.System.Dynamic.Runtime.dll" - let System_Linq_Expressions () = getOrCreateResource &_System_Linq_Expressions "netcoreapp31.System.Linq.Expressions.dll" - let Microsoft_VisualBasic_Core () = getOrCreateResource &_Microsoft_VisualBasic_Core "netcoreapp31.Microsoft.VisualBasic.Core.dll" - let System_Runtime_InteropServices_WindowsRuntime () = getOrCreateResource &_System_Runtime_InteropServices_WindowsRuntime "netcoreapp31.System.Runtime.InteropServices.WindowsRuntime.dll" - - - [] module NetStandard20 = let netStandard = lazy AssemblyMetadata.CreateFromImage(TestResources.NetFX.netstandard20.netstandard).GetReference(display = "netstandard.dll (netstandard 2.0 ref)") @@ -90,14 +38,6 @@ module Utilities = let systemDynamicRuntimeRef = lazy AssemblyMetadata.CreateFromImage(TestResources.NetFX.netcoreapp30.System_Dynamic_Runtime).GetReference(display = "System.Dynamic.Runtime.dll (netcoreapp 3.0 ref)") let systemConsoleRef = lazy AssemblyMetadata.CreateFromImage(TestResources.NetFX.netcoreapp30.System_Console).GetReference(display = "System.Console.dll (netcoreapp 3.0 ref)") - [] - module NetCoreApp31 = - let netStandard = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.netstandard ()).GetReference(display = "netstandard.dll (netcoreapp 3.1 ref)") - let mscorlibRef = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.mscorlib ()).GetReference(display = "mscorlib.dll (netcoreapp 3.1 ref)") - let systemRuntimeRef = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.System_Runtime ()).GetReference(display = "System.Runtime.dll (netcoreapp 3.1 ref)") - let systemCoreRef = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.System_Core ()).GetReference(display = "System.Core.dll (netcoreapp 3.1 ref)") - let systemDynamicRuntimeRef = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.System_Dynamic_Runtime ()).GetReference(display = "System.Dynamic.Runtime.dll (netcoreapp 3.1 ref)") - let systemConsoleRef = lazy AssemblyMetadata.CreateFromImage(NetCoreApp31Refs.System_Console ()).GetReference(display = "System.Console.dll (netcoreapp 3.1 ref)") [] module internal TargetFrameworkUtil = @@ -108,15 +48,11 @@ module Utilities = lazy ImmutableArray.Create(NetStandard20.netStandard.Value, NetStandard20.mscorlibRef.Value, NetStandard20.systemRuntimeRef.Value, NetStandard20.systemCoreRef.Value, NetStandard20.systemDynamicRuntimeRef.Value) let private netCoreApp30References = lazy ImmutableArray.Create(NetCoreApp30.netStandard.Value, NetCoreApp30.mscorlibRef.Value, NetCoreApp30.systemRuntimeRef.Value, NetCoreApp30.systemCoreRef.Value, NetCoreApp30.systemDynamicRuntimeRef.Value, NetCoreApp30.systemConsoleRef.Value) - let private netCoreApp31References = - lazy ImmutableArray.Create(NetCoreApp31.netStandard.Value, NetCoreApp31.mscorlibRef.Value, NetCoreApp31.systemRuntimeRef.Value, NetCoreApp31.systemCoreRef.Value, NetCoreApp31.systemDynamicRuntimeRef.Value, NetCoreApp31.systemConsoleRef.Value) - let internal getReferences tf = match tf with | TargetFramework.NetStandard20 -> netStandard20References.Value | TargetFramework.NetCoreApp30 -> netCoreApp30References.Value - | TargetFramework.NetCoreApp31 -> netCoreApp31References.Value type RoslynLanguageVersion = LanguageVersion From 8bf7ded5f100f78efe631f89b4db6abcf84e2d91 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 22 Jul 2020 13:56:40 +0200 Subject: [PATCH 13/21] Added types to errors/warnings as oppose to just having tuples --- tests/FSharp.Test.Utilities/Compiler.fs | 181 ++++++++++++++---------- 1 file changed, 108 insertions(+), 73 deletions(-) diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 464d0e0aced..4cd1cc2f37b 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -45,15 +45,19 @@ module Compiler = { Source: TestType References: CompilationUnit list} - type ErrorSeverity = Error | Warning + type ErrorType = Error of int | Warning of int - type ErrorInfo = { Severity: ErrorSeverity - ErrorNumber: int - StartLineAlternate: int - StartColumn: int - EndLineAlternate: int - EndColumn: int - Message: string } + type Line = Line of int + type Col = Col of int + + type Range = { StartLine: int + StartColumn: int + EndLine: int + EndColumn: int } + + type ErrorInfo = { Error: ErrorType + Range: Range + Message: string } type Output = { OutputPath: string option Adjust: int @@ -95,18 +99,29 @@ module Compiler = let private fromFSharpErrorInfo (errors: FSharpErrorInfo[]) : (ErrorInfo list * ErrorInfo list) = let toErrorInfo (e: FSharpErrorInfo) : ErrorInfo = - { Severity = if e.Severity = FSharpErrorSeverity.Warning then Warning else Error; - ErrorNumber = e.ErrorNumber; - StartLineAlternate = e.StartLineAlternate; - StartColumn = e.StartColumn; - EndLineAlternate = e.EndLineAlternate; - EndColumn = e.EndColumn; - Message = e.Message } + let errorNumber = e.ErrorNumber + let severity = e.Severity + + let error = if severity = FSharpErrorSeverity.Warning then Warning errorNumber else Error errorNumber + + { Error = error; + Range = { StartLine = e.StartLineAlternate; + StartColumn = e.StartColumn; + EndLine = e.EndLineAlternate; + EndColumn = e.EndColumn } + Message = e.Message } errors |> List.ofArray - |> List.map toErrorInfo |> List.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) - |> List.partition (fun e -> e.Severity = Error) + |> List.map toErrorInfo + |> List.partition (fun e -> match e.Error with Error _ -> true | _ -> false) + + let private adjustRange (range: Range) (adjust: int) : Range = + { range with + StartLine = range.StartLine - adjust; + StartColumn = range.StartColumn + 1; + EndLine = range.EndLine - adjust; + EndColumn = range.EndColumn + 1 } let Fsx (source: string) : CompilationUnit = fsFromString source Fsx |> FS @@ -338,8 +353,12 @@ module Compiler = [] module Assertions = + let private getErrorNumber (error: ErrorType) : int = + match error with + | Error e | Warning e -> e + let private getErrorInfo (info: ErrorInfo) : string = - sprintf "%A %A %A" info.Severity info.ErrorNumber info.Message + sprintf "%A %A" info.Error info.Message let inline private assertErrorsLength (source: ErrorInfo list) (expected: 'a list) : unit = if (List.length source) <> (List.length expected) then @@ -354,29 +373,27 @@ module Compiler = let private assertErrorNumbers (source: ErrorInfo list) (expected: int list) : unit = for exp in expected do - if not (List.exists (fun (el: ErrorInfo) -> el.ErrorNumber = exp) source) then + if not (List.exists (fun (el: ErrorInfo) -> (getErrorNumber el.Error) = exp) source) then failwith (sprintf "Mismatch in ErrorNumber, expected '%A' was not found during compilation.\nAll errors:\n%A" exp (List.map getErrorInfo source)) assertErrorsLength source expected - let private assertErrors (what: string) libAdjust (source: ErrorInfo list) (expected: (int * (int * int * int * int) * string) list) : unit = - let errors = - source - |> List.map (fun info -> (info.ErrorNumber, (info.StartLineAlternate - libAdjust, info.StartColumn + 1, info.EndLineAlternate - libAdjust, info.EndColumn + 1), info.Message)) + let private assertErrors (what: string) libAdjust (source: ErrorInfo list) (expected: ErrorInfo list) : unit = + let errors = source |> List.map (fun error -> { error with Range = adjustRange error.Range libAdjust }) let inline checkEqual k a b = - if a <> b then - Assert.AreEqual(a, b, sprintf "%s: Mismatch in %s, expected '%A', got '%A'.\nAll errors:\n%A" what k a b errors) + if a <> b then + Assert.AreEqual(a, b, sprintf "%s: Mismatch in %s, expected '%A', got '%A'.\nAll errors:\n%A" what k a b errors) // TODO: Check all "categories", collect all results and print alltogether. checkEqual "Errors count" expected.Length errors.Length List.zip errors expected |> List.iter (fun (actualError, expectedError) -> - let (expectedErrorNumber, expectedErrorRange, expectedErrorMsg) = expectedError - let (actualErrorNumber, actualErrorRange, actualErrorMsg) = actualError - checkEqual "ErrorNumber" expectedErrorNumber actualErrorNumber - checkEqual "ErrorRange" expectedErrorRange actualErrorRange - checkEqual "Message" expectedErrorMsg actualErrorMsg) + let { Error = actualError; Range = actualRange; Message = actualMessage } = actualError + let { Error = expectedError; Range = expectedRange; Message = expectedMessage } = expectedError + checkEqual "Error" expectedError actualError + checkEqual "ErrorRange" expectedRange actualRange + checkEqual "Message" expectedMessage actualMessage) () let adjust (adjust: int) (result: CompilationResult) : CompilationResult = @@ -393,67 +410,85 @@ module Compiler = let shouldFail (result: CompilationResult) : CompilationResult = match result with - | Success _ -> failwith "Compilation succeded (expected: Failure)." + | Success _ -> failwith "Compilation was \"Success\" (expected: \"Failure\")." | Failure _ -> result - let withMessages (messages: string list) (result: CompilationResult) : CompilationResult = - match result with - | Success r | Failure r -> assertErrorMessages (r.Warnings @ r.Errors) messages - result - - let withMessage (message: string) (result: CompilationResult) : CompilationResult = - withMessages [message] result - - let withErrorMessages (messages: string list) (result: CompilationResult) : CompilationResult = + let private assertResultsCategory (what: string) (selector: Output -> ErrorInfo list) (expected: ErrorInfo list) (result: CompilationResult) : CompilationResult = match result with - | Success r | Failure r -> assertErrorMessages r.Errors messages + | Success r | Failure r -> + assertErrors what r.Adjust (selector r) expected result - let withErrorMessage (message: string) (result: CompilationResult) : CompilationResult = - withErrorMessages [message] result + let withResults (expectedResults: ErrorInfo list) result : CompilationResult = + assertResultsCategory "Results" (fun r -> r.Warnings @ r.Errors) expectedResults result + + let withResult (expectedResult: ErrorInfo ) (result: CompilationResult) : CompilationResult = + withResults [expectedResult] result + + let with' (expected: (ErrorType * Line * Col * Line * Col * string) list) (result: CompilationResult) = + let (expectedResults: ErrorInfo list) = + expected |> + List.map( + fun e -> + let (error, (Line startLine), (Col startCol), (Line endLine), (Col endCol), message) = e + { Error = error; + Range = { + StartLine = startLine; + StartColumn = startCol; + EndLine = endLine; + EndColumn = endCol }; + Message = message }) + withResults expectedResults result + + let withErrors (expectedErrors: ErrorInfo list) (result: CompilationResult) : CompilationResult = + assertResultsCategory "Errors" (fun r -> r.Errors) expectedErrors result + + let withError (expectedError: ErrorInfo) (result: CompilationResult) : CompilationResult = + withErrors [expectedError] result - let withWarningMessages (messages: string list) (result: CompilationResult) : CompilationResult = + let checkCodes (expected: int list) (selector: Output -> ErrorInfo list) (result: CompilationResult) : CompilationResult = match result with - | Success r | Failure r -> assertErrorMessages r.Warnings messages + | Success r | Failure r -> + assertErrorNumbers (selector r) expected result - let withWarningMessage (message: string) (result: CompilationResult) : CompilationResult = - withWarningMessages [message] result + let withErrorCodes (expectedCodes: int list) (result: CompilationResult) : CompilationResult = + checkCodes expectedCodes (fun r -> r.Errors) result - let withWarnings (expectedWarnings: (int * (int * int * int * int) * string) list) (result: CompilationResult) : CompilationResult = - match result with - | Success r | Failure r -> - assertErrors "Warnings" r.Adjust r.Warnings expectedWarnings - result + let withErrorCode (expectedCode: int) (result: CompilationResult) : CompilationResult = + withErrorCodes [expectedCode] result + + let withWarnings (expectedWarnings: ErrorInfo list) (result: CompilationResult) : CompilationResult = + assertResultsCategory "Warnings" (fun r -> r.Warnings) expectedWarnings result - let withWarning (expectedWarning: (int * (int * int * int * int) * string)) (result: CompilationResult) : CompilationResult = + let withWarning (expectedWarning: ErrorInfo) (result: CompilationResult) : CompilationResult = withWarnings [expectedWarning] result - let withWarningCodes (expectedWarnings: int list) (result: CompilationResult) : CompilationResult = - match result with - | Success r | Failure r -> - assertErrorNumbers r.Warnings expectedWarnings - result + let withWarningCodes (expectedCodes: int list) (result: CompilationResult) : CompilationResult = + checkCodes expectedCodes (fun r -> r.Warnings) result - let withWarningCode (expectedWarning: int) (result: CompilationResult) : CompilationResult = - withWarningCodes [expectedWarning] result + let withWarningCode (expectedCode: int) (result: CompilationResult) : CompilationResult = + withWarningCodes [expectedCode] result - let withErrors (expectedErrors: (int * (int * int * int * int) * string) list) (result: CompilationResult) : CompilationResult = + let private checkErrorMessages (messages: string list) (selector: Output -> ErrorInfo list) (result: CompilationResult) : CompilationResult = match result with - | Success r | Failure r -> - assertErrors "Errors" r.Adjust r.Errors expectedErrors + | Success r | Failure r -> assertErrorMessages (selector r) messages result - let withError (expectedError: (int * (int * int * int * int) * string)) (result: CompilationResult) : CompilationResult = - withErrors [expectedError] result + let withMessages (messages: string list) (result: CompilationResult) : CompilationResult = + checkErrorMessages messages (fun r -> r.Warnings @ r.Errors) result - let withErrorCodes (expectedErrors: int list) (result: CompilationResult) : CompilationResult = - match result with - | Success r | Failure r -> - assertErrorNumbers r.Errors expectedErrors - result + let withMessage (message: string) (result: CompilationResult) : CompilationResult = + withMessages [message] result - let withErrorCode (expectedError: int) (result: CompilationResult) : CompilationResult = - withErrorCodes [expectedError] result + let withErrorMessages (messages: string list) (result: CompilationResult) : CompilationResult = + checkErrorMessages messages (fun r -> r.Errors) result - let withRange = ignore + let withErrorMessage (message: string) (result: CompilationResult) : CompilationResult = + withErrorMessages [message] result + + let withWarningMessages (messages: string list) (result: CompilationResult) : CompilationResult = + checkErrorMessages messages (fun r -> r.Warnings) result + + let withWarningMessage (message: string) (result: CompilationResult) : CompilationResult = + withWarningMessages [message] result From 879925345465c3962e00a5ad34207f3872159ce7 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 22 Jul 2020 14:40:19 +0200 Subject: [PATCH 14/21] Fixed tests to fit newer API --- .../ConstraintSolver/MemberConstraints.fs | 4 ++-- .../ErrorMessages/ConfusingTypeName.fs | 14 +++++++++----- .../Language/CompilerDirectiveTests.fs | 4 ++-- tests/FSharp.Test.Utilities/Compiler.fs | 5 ++++- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs index 599d58ecd5c..03a5c458000 100644 --- a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs +++ b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs @@ -6,7 +6,7 @@ open Xunit open FSharp.Test.Utilities.Compiler module MemberConstraints = - + [] let ``Invalid member constraint with ErrorRanges``() = // Regression test for FSharp1.0:2262 FSharp """ @@ -15,7 +15,7 @@ module MemberConstraints = |> withOptions ["--test:ErrorRanges"] |> typecheck |> shouldFail - |> withError (697, (2, 43, 2, 76), "Invalid constraint") + |> withSingle (Error 697, Line 2, Col 43, Line 2, Col 76, "Invalid constraint") [] let ``we can overload operators on a type and not add all the extra jazz such as inlining and the ^ operator.``() = diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs index 10ef9925664..b06cff374af 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs @@ -49,13 +49,17 @@ let otherB = OtherAMaker.makeOtherB() printfn "%A %A" (b.GetType().AssemblyQualifiedName) (otherB.GetType().AssemblyQualifiedName) printfn "%A" (b = otherB) """ |> withReferences [csLibA; csLibB; fsLibC; fsLibD] - + app |> compile |> shouldFail - |> withErrors [ - (1, (6, 19, 6, 25), ("This expression was expected to have type\n 'A (libA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' \nbut here has type\n 'A (libB, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' ")) - (1, (11, 19, 11, 25), ("This expression was expected to have type\n 'B (libA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' \nbut here has type\n 'B (libB, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' "))] + |> with' [ + (Warning 686, Line 8, Col 9, Line 8, Col 21, "The method or function 'makeB' should not be given explicit type argument(s) because it does not declare its type parameters explicitly") + (Warning 686, Line 9, Col 14, Line 9, Col 36, "The method or function 'makeOtherB' should not be given explicit type argument(s) because it does not declare its type parameters explicitly") + (Error 1, Line 6, Col 19, Line 6, Col 25, "This expression was expected to have type\n 'A (libA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' \nbut here has type\n 'A (libB, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' ") + (Error 1, Line 11, Col 19, Line 11, Col 25, "This expression was expected to have type\n 'B (libA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' \nbut here has type\n 'B (libB, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' ") + + ] [] @@ -91,7 +95,7 @@ let makeOtherB () = B<_>() let fsLibDCmpl = Compilation.Create(fsLibD, Fs, Library, cmplRefs = [csLibBCmpl], name = "libD") |> CompilationReference.CreateFSharp - + let app = """ module ConfusingTypeName let a = AMaker.makeA() diff --git a/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs index 7ee9b15610d..a9668213a36 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs @@ -16,7 +16,7 @@ module ``Test Compiler Directives`` = """ |> ignoreWarnings |> compile |> shouldSucceed - |> withWarning (213, (2,1,2,6), "'' is not a valid assembly name") + |> withSingle (Warning 213, Line 2, Col 1, Line 2, Col 6, "'' is not a valid assembly name") [] let ``#r " " is invalid`` () = @@ -24,4 +24,4 @@ module ``Test Compiler Directives`` = #r " " """ |> compile |> shouldFail - |> withWarning (213, (2,1,2,10), "'' is not a valid assembly name") + |> withSingle (Warning 213, Line 2, Col 1, Line 2, Col 10, "'' is not a valid assembly name") diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 4cd1cc2f37b..968a340ad91 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -425,7 +425,7 @@ module Compiler = let withResult (expectedResult: ErrorInfo ) (result: CompilationResult) : CompilationResult = withResults [expectedResult] result - let with' (expected: (ErrorType * Line * Col * Line * Col * string) list) (result: CompilationResult) = + let with' (expected: (ErrorType * Line * Col * Line * Col * string) list) (result: CompilationResult) : CompilationResult = let (expectedResults: ErrorInfo list) = expected |> List.map( @@ -440,6 +440,9 @@ module Compiler = Message = message }) withResults expectedResults result + let withSingle (expected: (ErrorType * Line * Col * Line * Col * string)) (result: CompilationResult) : CompilationResult = + with' [expected] result + let withErrors (expectedErrors: ErrorInfo list) (result: CompilationResult) : CompilationResult = assertResultsCategory "Errors" (fun r -> r.Errors) expectedErrors result From 2f36dc4310b6116b8f0efe48a68fcf77e4e33337 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 22 Jul 2020 15:18:44 +0200 Subject: [PATCH 15/21] Revert libraries upgrade --- RoslynPackageVersion.txt | 2 +- eng/Versions.props | 3 +-- .../FSharp.Compiler.ComponentTests.fsproj | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/RoslynPackageVersion.txt b/RoslynPackageVersion.txt index 40c341bdcdb..cc99af67911 100644 --- a/RoslynPackageVersion.txt +++ b/RoslynPackageVersion.txt @@ -1 +1 @@ -3.6.0 +3.2.0-beta4-19312-15 diff --git a/eng/Versions.props b/eng/Versions.props index 415cf5eb7d1..a9b401f28bd 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -103,7 +103,7 @@ $(RoslynVersion) $(RoslynVersion) $(RoslynVersion) - 2.0.28 + 2.0.17 $(RoslynVersion) 16.4 @@ -174,7 +174,6 @@ 1.0.30 8.0.0-alpha 2.7.0 - 3.6.0 3.0.0-preview-27318-01 3.0.0-preview-27318-01 16.6.1 diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index a9d26284751..14e96dfa23b 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -50,7 +50,7 @@ - + From 56e8c922dc0a149f024ba039893896e8e846d8ac Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 22 Jul 2020 16:00:57 +0200 Subject: [PATCH 16/21] Revert change netcoreapp31 -> netcoreapp30 --- .../Interop/SimpleInteropTests.fs | 2 +- tests/FSharp.Test.Utilities/CompilerAssert.fs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs index a32e83e9e18..0b174ea9c63 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs @@ -33,7 +33,7 @@ let a = AMaker.makeA() |> shouldSucceed - [] + // TODO: This is broken RN, since netcoreapp30 is used for C# and 3.1 for F#, should be fixed as part of https://github.com/dotnet/fsharp/issues/9740 let ``Instantiate F# type from C#`` () = let FSLib = FSharp """ diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index 73a15f94d6b..4956b3e2035 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -90,7 +90,7 @@ type CompilerAssert private () = Exe - netcoreapp3.0 + netcoreapp3.1 true true @@ -405,10 +405,10 @@ let main argv = 0""" """ { "runtimeOptions": { - "tfm": "netcoreapp3.0", + "tfm": "netcoreapp3.1", "framework": { "name": "Microsoft.NETCore.App", - "version": "3.0.0" + "version": "3.1.0" } } } From 3e10cdb2cb08b27a2e487530e046cd049086f155 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 22 Jul 2020 17:57:54 +0200 Subject: [PATCH 17/21] Update tests/FSharp.Test.Utilities/Compiler.fs Co-authored-by: Phillip Carter --- tests/FSharp.Test.Utilities/Compiler.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 968a340ad91..c6206023e39 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -43,7 +43,7 @@ module Compiler = and ILCompilationSource = { Source: TestType - References: CompilationUnit list} + References: CompilationUnit list } type ErrorType = Error of int | Warning of int From 957dd77e7e7ab779827352917e9b354e3a5be24e Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 22 Jul 2020 18:20:20 +0200 Subject: [PATCH 18/21] Addressed some PR comments --- .../ConstraintSolver/MemberConstraints.fs | 2 +- .../ErrorMessages/ConfusingTypeName.fs | 60 +-------- .../Interop/SimpleInteropTests.fs | 2 +- .../Language/CompilerDirectiveTests.fs | 4 +- tests/FSharp.Test.Utilities/Compiler.fs | 124 ++++++++++-------- 5 files changed, 71 insertions(+), 121 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs index 03a5c458000..6cdd83a5992 100644 --- a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs +++ b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs @@ -15,7 +15,7 @@ module MemberConstraints = |> withOptions ["--test:ErrorRanges"] |> typecheck |> shouldFail - |> withSingle (Error 697, Line 2, Col 43, Line 2, Col 76, "Invalid constraint") + |> withSingleDiagnostic (Error 697, Line 2, Col 43, Line 2, Col 76, "Invalid constraint") [] let ``we can overload operators on a type and not add all the extra jazz such as inlining and the ^ operator.``() = diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs index b06cff374af..3c7e569007d 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConfusingTypeName.fs @@ -53,68 +53,10 @@ printfn "%A" (b = otherB) app |> compile |> shouldFail - |> with' [ + |> withDiagnostics [ (Warning 686, Line 8, Col 9, Line 8, Col 21, "The method or function 'makeB' should not be given explicit type argument(s) because it does not declare its type parameters explicitly") (Warning 686, Line 9, Col 14, Line 9, Col 36, "The method or function 'makeOtherB' should not be given explicit type argument(s) because it does not declare its type parameters explicitly") (Error 1, Line 6, Col 19, Line 6, Col 25, "This expression was expected to have type\n 'A (libA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' \nbut here has type\n 'A (libB, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' ") (Error 1, Line 11, Col 19, Line 11, Col 25, "This expression was expected to have type\n 'B (libA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' \nbut here has type\n 'B (libB, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' ") ] - - - [] - let ``Checks expected types with multiple references``() = - let csLibAB = """ -public class A { } -public class B { } - """ - let csLibACmpl = - CompilationUtil.CreateCSharpCompilation(csLibAB, CSharpLanguageVersion.CSharp8, TargetFramework.NetCoreApp30, name = "libA") - |> CompilationReference.Create - - let csLibBCmpl = - CompilationUtil.CreateCSharpCompilation(csLibAB, CSharpLanguageVersion.CSharp8, TargetFramework.NetCoreApp30, name = "libB") - |> CompilationReference.Create - - let fsLibC = """ -module AMaker -let makeA () : A = A() -let makeB () = B<_>() - """ - - let fsLibD = """ -module OtherAMaker -let makeOtherA () : A = A() -let makeOtherB () = B<_>() - """ - - let fsLibCCmpl = - Compilation.Create(fsLibC, Fs, Library, cmplRefs = [csLibACmpl], name = "libC") - |> CompilationReference.CreateFSharp - - let fsLibDCmpl = - Compilation.Create(fsLibD, Fs, Library, cmplRefs = [csLibBCmpl], name = "libD") - |> CompilationReference.CreateFSharp - - let app = """ -module ConfusingTypeName -let a = AMaker.makeA() -let otherA = OtherAMaker.makeOtherA() -printfn "%A %A" (a.GetType().AssemblyQualifiedName) (otherA.GetType().AssemblyQualifiedName) -printfn "%A" (a = otherA) - -let b = AMaker.makeB() -let otherB = OtherAMaker.makeOtherB() -printfn "%A %A" (b.GetType().AssemblyQualifiedName) (otherB.GetType().AssemblyQualifiedName) -printfn "%A" (b = otherB) - """ - - let appCmpl = - Compilation.Create(app, Fs, Library, cmplRefs = [csLibACmpl; csLibBCmpl; fsLibCCmpl; fsLibDCmpl]) - - CompilerAssert.CompileWithErrors( - appCmpl, - [| - (FSharpErrorSeverity.Error, 1, (6, 19, 6, 25), ("This expression was expected to have type\n 'A (libA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' \nbut here has type\n 'A (libB, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' ")) - (FSharpErrorSeverity.Error, 1, (11, 19, 11, 25), ("This expression was expected to have type\n 'B (libA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' \nbut here has type\n 'B (libB, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)' ")) - |], true) diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs index 0b174ea9c63..59b0ce83438 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/SimpleInteropTests.fs @@ -33,7 +33,7 @@ let a = AMaker.makeA() |> shouldSucceed - // TODO: This is broken RN, since netcoreapp30 is used for C# and 3.1 for F#, should be fixed as part of https://github.com/dotnet/fsharp/issues/9740 + [] let ``Instantiate F# type from C#`` () = let FSLib = FSharp """ diff --git a/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs index a9668213a36..9f9d949667c 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/CompilerDirectiveTests.fs @@ -16,7 +16,7 @@ module ``Test Compiler Directives`` = """ |> ignoreWarnings |> compile |> shouldSucceed - |> withSingle (Warning 213, Line 2, Col 1, Line 2, Col 6, "'' is not a valid assembly name") + |> withSingleDiagnostic (Warning 213, Line 2, Col 1, Line 2, Col 6, "'' is not a valid assembly name") [] let ``#r " " is invalid`` () = @@ -24,4 +24,4 @@ module ``Test Compiler Directives`` = #r " " """ |> compile |> shouldFail - |> withSingle (Warning 213, Line 2, Col 1, Line 2, Col 10, "'' is not a valid assembly name") + |> withSingleDiagnostic (Warning 213, Line 2, Col 1, Line 2, Col 10, "'' is not a valid assembly name") diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index c6206023e39..3c8e5b96501 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -50,19 +50,22 @@ module Compiler = type Line = Line of int type Col = Col of int - type Range = { StartLine: int - StartColumn: int - EndLine: int - EndColumn: int } - - type ErrorInfo = { Error: ErrorType - Range: Range - Message: string } - - type Output = { OutputPath: string option - Adjust: int - Errors: ErrorInfo list - Warnings: ErrorInfo list } + type Range = + { StartLine: int + StartColumn: int + EndLine: int + EndColumn: int } + + type ErrorInfo = + { Error: ErrorType + Range: Range + Message: string } + + type Output = + { OutputPath: string option + Adjust: int + Errors: ErrorInfo list + Warnings: ErrorInfo list } type CompilationResult = | Success of Output @@ -80,22 +83,24 @@ module Compiler = let private fsFromString (source: string) (kind: SourceKind) : FSharpCompilationSource = match source with | null -> failwith "Source cannot be null" - | _ -> { Source = Text source; - Options = defaultOptions; - OutputType = Library; - SourceKind = kind; - Name = None; - IgnoreWarnings = false; - References = [] } + | _ -> + { Source = Text source + Options = defaultOptions + OutputType = Library + SourceKind = kind + Name = None + IgnoreWarnings = false + References = [] } let private csFromString (source: string) : CSharpCompilationSource = match source with | null -> failwith "Source cannot be null" - | _ -> { Source = Text source; - LangVersion = CSharpLanguageVersion.CSharp8; - TargetFramework = TargetFramework.NetCoreApp30; - Name = None; - References = [] } + | _ -> + { Source = Text source + LangVersion = CSharpLanguageVersion.CSharp8 + TargetFramework = TargetFramework.NetCoreApp30 + Name = None + References = [] } let private fromFSharpErrorInfo (errors: FSharpErrorInfo[]) : (ErrorInfo list * ErrorInfo list) = let toErrorInfo (e: FSharpErrorInfo) : ErrorInfo = @@ -104,23 +109,25 @@ module Compiler = let error = if severity = FSharpErrorSeverity.Warning then Warning errorNumber else Error errorNumber - { Error = error; - Range = { StartLine = e.StartLineAlternate; - StartColumn = e.StartColumn; - EndLine = e.EndLineAlternate; - EndColumn = e.EndColumn } + { Error = error + Range = + { StartLine = e.StartLineAlternate + StartColumn = e.StartColumn + EndLine = e.EndLineAlternate + EndColumn = e.EndColumn } Message = e.Message } - errors |> List.ofArray - |> List.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) - |> List.map toErrorInfo - |> List.partition (fun e -> match e.Error with Error _ -> true | _ -> false) + errors + |> List.ofArray + |> List.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) + |> List.map toErrorInfo + |> List.partition (fun e -> match e.Error with Error _ -> true | _ -> false) let private adjustRange (range: Range) (adjust: int) : Range = { range with - StartLine = range.StartLine - adjust; - StartColumn = range.StartColumn + 1; - EndLine = range.EndLine - adjust; + StartLine = range.StartLine - adjust + StartColumn = range.StartColumn + 1 + EndLine = range.EndLine - adjust EndColumn = range.EndColumn + 1 } let Fsx (source: string) : CompilationUnit = @@ -219,17 +226,18 @@ module Compiler = let (errors, warnings) = err |> fromFSharpErrorInfo - let result = { OutputPath = None; - Adjust = 0; - Warnings = warnings; - Errors = errors } + let result = + { OutputPath = None + Adjust = 0 + Warnings = warnings + Errors = errors } - // Treat warnings as errors if "IgnoreWarnings" is false; + // Treat warnings as errors if "IgnoreWarnings" is false if errors.Length > 0 || (warnings.Length > 0 && not ignoreWarnings) then - Failure { result with Warnings = warnings; + Failure { result with Warnings = warnings Errors = errors } else - Success { result with Warnings = warnings; + Success { result with Warnings = warnings OutputPath = Some outputFilePath } and private compileFSharp (fsSource: FSharpCompilationSource) : CompilationResult = @@ -256,15 +264,15 @@ module Compiler = let cmplResult = compilation.Emit (output) - let result = { OutputPath = None; - Adjust = 0; - Warnings = []; - Errors = [] } + let result = + { OutputPath = None + Adjust = 0 + Warnings = [] + Errors = [] } if cmplResult.Success then Success { result with OutputPath = Some output } else - cmplResult.Diagnostics |> printfn "%A" Failure result and private compileCSharp (csSource: CSharpCompilationSource) : CompilationResult = @@ -425,23 +433,23 @@ module Compiler = let withResult (expectedResult: ErrorInfo ) (result: CompilationResult) : CompilationResult = withResults [expectedResult] result - let with' (expected: (ErrorType * Line * Col * Line * Col * string) list) (result: CompilationResult) : CompilationResult = + let withDiagnostics (expected: (ErrorType * Line * Col * Line * Col * string) list) (result: CompilationResult) : CompilationResult = let (expectedResults: ErrorInfo list) = expected |> List.map( fun e -> let (error, (Line startLine), (Col startCol), (Line endLine), (Col endCol), message) = e - { Error = error; - Range = { - StartLine = startLine; - StartColumn = startCol; - EndLine = endLine; - EndColumn = endCol }; + { Error = error + Range = + { StartLine = startLine + StartColumn = startCol + EndLine = endLine + EndColumn = endCol } Message = message }) withResults expectedResults result - let withSingle (expected: (ErrorType * Line * Col * Line * Col * string)) (result: CompilationResult) : CompilationResult = - with' [expected] result + let withSingleDiagnostic (expected: (ErrorType * Line * Col * Line * Col * string)) (result: CompilationResult) : CompilationResult = + withDiagnostics [expected] result let withErrors (expectedErrors: ErrorInfo list) (result: CompilationResult) : CompilationResult = assertResultsCategory "Errors" (fun r -> r.Errors) expectedErrors result From aa70025594b17d6d56c8de131b9e9c1973103576 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 22 Jul 2020 18:28:40 +0200 Subject: [PATCH 19/21] Fixed missing styling inconsistensies --- tests/FSharp.Test.Utilities/Compiler.fs | 35 ++++++++++++++----------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 3c8e5b96501..49d0f07b3f1 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -140,13 +140,14 @@ module Compiler = match (dir, file) with | dir, _ when String.IsNullOrWhiteSpace dir -> failwith "Baseline tests directory cannot be null or empty." | _, file when String.IsNullOrWhiteSpace file -> failwith "Baseline source file name cannot be null or empty." - | _ -> { Source = Baseline (dir, file); - Options = defaultOptions; - OutputType = Library; - SourceKind = Fs; - Name = None; - IgnoreWarnings = false; - References = [] } |> FS + | _ -> + { Source = Baseline (dir, file) + Options = defaultOptions + OutputType = Library + SourceKind = Fs + Name = None + IgnoreWarnings = false + References = [] } |> FS let CSharp (source: string) : CompilationUnit = csFromString source |> CS @@ -312,10 +313,11 @@ module Compiler = // We return a successfull CompilationResult if it succeeds. CompilerAssert.TypeCheckWithErrorsAndOptionsAgainstBaseLine (Array.ofList options) dir file - Success { OutputPath = None; - Adjust = 0; - Warnings = []; - Errors = [] } + Success + { OutputPath = None + Adjust = 0 + Warnings = [] + Errors = [] } let private typecheckFSharpSource (fsSource: FSharpCompilationSource) : CompilationResult = let source = getSource fsSource.Source @@ -325,14 +327,15 @@ module Compiler = let (errors, warnings) = err |> fromFSharpErrorInfo - let result = { OutputPath = None; - Adjust = 0; - Warnings = warnings; - Errors = errors } + let result = + { OutputPath = None + Adjust = 0 + Warnings = warnings + Errors = errors } // Treat warnings as errors if "IgnoreWarnings" is false; if errors.Length > 0 || (warnings.Length > 0 && not fsSource.IgnoreWarnings) then - Failure { result with Warnings = warnings; + Failure { result with Warnings = warnings Errors = errors } else Success { result with Warnings = warnings } From a1e4293bdcb8d115cecfb33c1e12d862c063b4c0 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 23 Jul 2020 10:19:35 +0200 Subject: [PATCH 20/21] Addressed feedback: recursive module instead of forward type declarations + fixed options composition. --- tests/FSharp.Test.Utilities/Compiler.fs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 49d0f07b3f1..8ac6dae1e7f 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -13,7 +13,7 @@ open System open System.Collections.Immutable open System.IO -module Compiler = +module rec Compiler = type TestType = | Text of string @@ -25,7 +25,7 @@ module Compiler = | CS of CSharpCompilationSource | IL of ILCompilationSource - and FSharpCompilationSource = + type FSharpCompilationSource = { Source: TestType Options: string list OutputType: CompileOutput @@ -34,14 +34,14 @@ module Compiler = IgnoreWarnings: bool References: CompilationUnit list } - and CSharpCompilationSource = + type CSharpCompilationSource = { Source: TestType LangVersion: CSharpLanguageVersion TargetFramework: TargetFramework Name: string option References: CompilationUnit list } - and ILCompilationSource = + type ILCompilationSource = { Source: TestType References: CompilationUnit list } @@ -131,10 +131,10 @@ module Compiler = EndColumn = range.EndColumn + 1 } let Fsx (source: string) : CompilationUnit = - fsFromString source Fsx |> FS + fsFromString source SourceKind.Fsx |> FS let FSharp (source: string) : CompilationUnit = - fsFromString source Fs |> FS + fsFromString source SourceKind.Fs |> FS let baseline (dir: string, file: string) : CompilationUnit = match (dir, file) with @@ -198,7 +198,7 @@ module Compiler = | Some p -> p |> MetadataReference.CreateFromFile | _ -> failwith "Conversion isn't possible" - and private processReferences (references: CompilationUnit list) = + let private processReferences (references: CompilationUnit list) = let rec loop acc = function | [] -> List.rev acc @@ -221,7 +221,7 @@ module Compiler = | IL _ -> failwith "TODO: Process references for IL" loop [] references - and private compileFSharpCompilation compilation ignoreWarnings : CompilationResult = + let private compileFSharpCompilation compilation ignoreWarnings : CompilationResult = let ((err: FSharpErrorInfo[], outputFilePath: string), _) = CompilerAssert.CompileRaw(compilation) @@ -241,7 +241,7 @@ module Compiler = Success { result with Warnings = warnings OutputPath = Some outputFilePath } - and private compileFSharp (fsSource: FSharpCompilationSource) : CompilationResult = + let private compileFSharp (fsSource: FSharpCompilationSource) : CompilationResult = let source = getSource fsSource.Source let sourceKind = fsSource.SourceKind @@ -254,7 +254,7 @@ module Compiler = compileFSharpCompilation compilation fsSource.IgnoreWarnings - and private compileCSharpCompilation (compilation: CSharpCompilation) : CompilationResult = + let private compileCSharpCompilation (compilation: CSharpCompilation) : CompilationResult = let outputPath = Path.Combine(Path.GetTempPath(), "FSharpCompilerTests", Path.GetRandomFileName()) @@ -276,7 +276,7 @@ module Compiler = else Failure result - and private compileCSharp (csSource: CSharpCompilationSource) : CompilationResult = + let private compileCSharp (csSource: CSharpCompilationSource) : CompilationResult = let source = getSource csSource.Source let name = if Option.isSome csSource.Name then csSource.Name.Value else Guid.NewGuid().ToString () @@ -302,7 +302,7 @@ module Compiler = cmpl |> compileCSharpCompilation - and compile (cUnit: CompilationUnit) : CompilationResult = + let compile (cUnit: CompilationUnit) : CompilationResult = match cUnit with | FS fs -> compileFSharp fs | CS cs -> compileCSharp cs From cb9e1cbc334bac26c85584e90379989ebac26bb9 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Thu, 23 Jul 2020 14:44:19 +0200 Subject: [PATCH 21/21] Changed Option.isSome -> defaultArg --- tests/FSharp.Test.Utilities/Compiler.fs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 8ac6dae1e7f..6c6c51b10da 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -199,7 +199,6 @@ module rec Compiler = | _ -> failwith "Conversion isn't possible" let private processReferences (references: CompilationUnit list) = - let rec loop acc = function | [] -> List.rev acc | x::xs -> @@ -207,13 +206,13 @@ module rec Compiler = | FS fs -> let refs = loop [] fs.References let source = getSource fs.Source - let name = if Option.isSome fs.Name then fs.Name.Value else null + let name = defaultArg fs.Name null let cmpl = Compilation.Create(source, fs.SourceKind, fs.OutputType, cmplRefs = refs, name = name) |> CompilationReference.CreateFSharp loop (cmpl::acc) xs | CS cs -> let refs = loop [] cs.References let source = getSource cs.Source - let name = if Option.isSome cs.Name then cs.Name.Value else null + let name = defaultArg cs.Name null let metadataReferences = List.map asMetadataReference refs let cmpl = CompilationUtil.CreateCSharpCompilation(source, cs.LangVersion, cs.TargetFramework, additionalReferences = metadataReferences.ToImmutableArray().As(), name = name) |> CompilationReference.Create @@ -279,7 +278,7 @@ module rec Compiler = let private compileCSharp (csSource: CSharpCompilationSource) : CompilationResult = let source = getSource csSource.Source - let name = if Option.isSome csSource.Name then csSource.Name.Value else Guid.NewGuid().ToString () + let name = defaultArg csSource.Name (Guid.NewGuid().ToString ()) let additionalReferences = match processReferences csSource.References with