diff --git a/tests/fsharp/Compiler/CompilerAssert.fs b/tests/fsharp/Compiler/CompilerAssert.fs index 3d392585b9a3..291e2e85a2b9 100644 --- a/tests/fsharp/Compiler/CompilerAssert.fs +++ b/tests/fsharp/Compiler/CompilerAssert.fs @@ -63,7 +63,7 @@ module CompilerAssert = Assert.IsEmpty(typeCheckResults.Errors, sprintf "Type Check errors: %A" typeCheckResults.Errors) - let TypeCheckSingleError (source: string) (expectedErrorNumber: int) (expectedErrorRange: int * int * int * int) (expectedErrorMsg: string) = + let TypeCheckWithErrors (source: string) expectedTypeErrors = lock lockObj <| fun () -> let parseResults, fileAnswer = checker.ParseAndCheckFileInProject("test.fs", 0, SourceText.ofString source, defaultProjectOptions) |> Async.RunSynchronously @@ -76,16 +76,20 @@ module CompilerAssert = let errors = typeCheckResults.Errors |> Array.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) + + Assert.AreEqual(Array.length expectedTypeErrors, errors.Length, sprintf "Expected one type check error: %A" typeCheckResults.Errors) - Assert.AreEqual(1, errors.Length, sprintf "Expected one type check error: %A" typeCheckResults.Errors) - errors - |> Array.iter (fun info -> + Array.zip errors expectedTypeErrors + |> Array.iter (fun (info,(expectedErrorNumber: int, expectedErrorRange: int * int * int * int, expectedErrorMsg: string)) -> Assert.AreEqual(FSharpErrorSeverity.Error, info.Severity) Assert.AreEqual(expectedErrorNumber, info.ErrorNumber, "expectedErrorNumber") Assert.AreEqual(expectedErrorRange, (info.StartLineAlternate, info.StartColumn + 1, info.EndLineAlternate, info.EndColumn + 1), "expectedErrorRange") Assert.AreEqual(expectedErrorMsg, info.Message, "expectedErrorMsg") ) + let TypeCheckSingleError (source: string) (expectedErrorNumber: int) (expectedErrorRange: int * int * int * int) (expectedErrorMsg: string) = + TypeCheckWithErrors (source: string) [| expectedErrorNumber, expectedErrorRange, expectedErrorMsg |] + let RunScript (source: string) (expectedErrorMessages: string list) = lock lockObj <| fun () -> // Intialize output and input streams diff --git a/tests/fsharp/Compiler/ErrorMessages/ElseBranchHasWrongTypeTests.fs b/tests/fsharp/Compiler/ErrorMessages/ElseBranchHasWrongTypeTests.fs new file mode 100644 index 000000000000..fe3efb2f6d60 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/ElseBranchHasWrongTypeTests.fs @@ -0,0 +1,167 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open NUnit.Framework + +[] +module ``Else branch has wrong type`` = + + [] + let ``Else branch is int while if branch is string``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let y = + if test > 10 then "test" + else 123 + """ + 1 + (5, 10, 5, 13) + "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'." + + [] + let ``Else branch is a function that returns int while if branch is string``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let f x = test +let y = + if test > 10 then "test" + else f 10 + """ + 1 + (6, 10, 6, 14) + "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'." + + + [] + let ``Else branch is a sequence of expressions that returns int while if branch is string``() = + CompilerAssert.TypeCheckSingleError + """ +let f x = x + 4 + +let y = + if true then + "" + else + "" |> ignore + (f 5) + """ + 1 + (9, 10, 9, 13) + "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'." + + + [] + let ``Else branch is a longer sequence of expressions that returns int while if branch is string``() = + CompilerAssert.TypeCheckSingleError + """ +let f x = x + 4 + +let y = + if true then + "" + else + "" |> ignore + let z = f 4 + let a = 3 * z + (f a) + """ + 1 + (11, 10, 11, 13) + "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'." + + + [] + let ``Else branch context doesn't propagate into function application``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let f x : string = x +let y = + if test > 10 then "test" + else + f 123 + """ + 1 + (7, 11, 7, 14) + "This expression was expected to have type\n 'string' \nbut here has type\n 'int' " + + [] + let ``Else branch context doesn't propagate into function application even if not last expr``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let f x = printfn "%s" x +let y = + if test > 10 then "test" + else + f 123 + "test" + """ + 1 + (7, 11, 7, 14) + "This expression was expected to have type\n 'string' \nbut here has type\n 'int' " + + [] + let ``Else branch context doesn't propagate into for loop``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let list = [1..10] +let y = + if test > 10 then "test" + else + for (x:string) in list do + printfn "%s" x + + "test" + """ + 1 + (7, 14, 7, 22) + "This expression was expected to have type\n 'int' \nbut here has type\n 'string' " + + [] + let ``Else branch context doesn't propagate to lines before last line``() = + CompilerAssert.TypeCheckSingleError + """ +let test = 100 +let list = [1..10] +let y = + if test > 10 then "test" + else + printfn "%s" 1 + + "test" + """ + 1 + (7, 22, 7, 23) + "This expression was expected to have type\n 'string' \nbut here has type\n 'int' " + + [] + let ``Else branch should not have wrong context type``() = + CompilerAssert.TypeCheckWithErrors + """ +let x = 1 +let y : bool = + if x = 2 then "A" + else "B" + """ + [| 1, (4, 19, 4, 22), "The 'if' expression needs to have type 'bool' to satisfy context type requirements. It currently has type 'string'." + 1, (5, 10, 5, 13), "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'bool'. This branch returns a value of type 'string'." |] + + + [] + let ``Else branch has wrong type in nested if``() = + CompilerAssert.TypeCheckWithErrors + """ +let x = 1 +let f = + if x = 1 then true + else + if x = 2 then "A" + else "B" + """ + [| 1, (6, 23, 6, 26), "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'bool'. This branch returns a value of type 'string'." + 1, (7, 14, 7, 17), "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'bool'. This branch returns a value of type 'string'." |] diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj index 56240b466b43..43b7183cb588 100644 --- a/tests/fsharp/FSharpSuite.Tests.fsproj +++ b/tests/fsharp/FSharpSuite.Tests.fsproj @@ -31,6 +31,7 @@ + diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl.fs b/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl.fs deleted file mode 100644 index 79152abb78aa..000000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Warnings -//This expression was expected to have - -let test = 100 -let f x : string = x -let y = - if test > 10 then "test" - else - f 123 - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl2.fs b/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl2.fs deleted file mode 100644 index 5478d8b09d3e..000000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInAppl2.fs +++ /dev/null @@ -1,12 +0,0 @@ -// #Warnings -//This expression was expected to have - -let test = 100 -let f x = printfn "%s" x -let y = - if test > 10 then "test" - else - f 123 - "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInForLoop.fs b/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInForLoop.fs deleted file mode 100644 index bfd5a18dd17a..000000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateInForLoop.fs +++ /dev/null @@ -1,14 +0,0 @@ -// #Warnings -//This expression was expected to have - -let test = 100 -let list = [1..10] -let y = - if test > 10 then "test" - else - for (x:string) in list do - printfn "%s" x - - "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateToLinesBeforeLastLine.fs b/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateToLinesBeforeLastLine.fs deleted file mode 100644 index 9facc603ff6e..000000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchContextDoesntPropagateToLinesBeforeLastLine.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//This expression was expected to have type - -let test = 100 -let list = [1..10] -let y = - if test > 10 then "test" - else - printfn "%s" 1 - - "test" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongContextType.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongContextType.fs deleted file mode 100644 index 895881ac7bef..000000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongContextType.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//The 'if' expression needs to have type 'bool' - -let x = 1 -let y : bool = - if x = 2 then "A" - else "B" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType.fs deleted file mode 100644 index b14b495304ee..000000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType.fs +++ /dev/null @@ -1,9 +0,0 @@ -// #Warnings -//All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'. - -let test = 100 -let y = - if test > 10 then "test" - else 123 - -exit 0 diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType2.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType2.fs deleted file mode 100644 index 06d83f76aa01..000000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType2.fs +++ /dev/null @@ -1,10 +0,0 @@ -// #Warnings -//All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'. - -let test = 100 -let f x = test -let y = - if test > 10 then "test" - else f 10 - -exit 0 diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType3.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType3.fs deleted file mode 100644 index 1306c794759d..000000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType3.fs +++ /dev/null @@ -1,13 +0,0 @@ -// #Warnings -//All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'. - -let f x = x + 4 - -let y = - if true then - "" - else - "" |> ignore - (f 5) - -exit 0 diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType4.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType4.fs deleted file mode 100644 index 8339a930d300..000000000000 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType4.fs +++ /dev/null @@ -1,15 +0,0 @@ -// #Warnings -//All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'. - -let f x = x + 4 - -let y = - if true then - "" - else - "" |> ignore - let z = f 4 - let a = 3 * z - (f a) - -exit 0 diff --git a/tests/fsharpqa/Source/Warnings/NestedElseBranchHasWrongType.fs b/tests/fsharpqa/Source/Warnings/NestedElseBranchHasWrongType.fs deleted file mode 100644 index a8e63cee65ac..000000000000 --- a/tests/fsharpqa/Source/Warnings/NestedElseBranchHasWrongType.fs +++ /dev/null @@ -1,10 +0,0 @@ -// #Warnings -//All branches of an 'if' expression must return values of the same type as the first branch, which here is 'bool'. This branch returns a value of type 'string'. - -let x = 1 -if x = 1 then true -else - if x = 2 then "A" - else "B" - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/env.lst b/tests/fsharpqa/Source/Warnings/env.lst index 383c291e9069..127d78a21c58 100644 --- a/tests/fsharpqa/Source/Warnings/env.lst +++ b/tests/fsharpqa/Source/Warnings/env.lst @@ -45,16 +45,6 @@ SOURCE=SuggestDoubleBacktickIdentifiers.fs SCFLAGS="--vserrors" # SuggestDoubleBacktickIdentifiers.fs SOURCE=SuggestDoubleBacktickUnions.fs SCFLAGS="--vserrors" # SuggestDoubleBacktickUnions.fs SOURCE=GuardHasWrongType.fs # GuardHasWrongType.fs - SOURCE=ElseBranchHasWrongType.fs # ElseBranchHasWrongType.fs - SOURCE=ElseBranchHasWrongType2.fs # ElseBranchHasWrongType2.fs - SOURCE=ElseBranchHasWrongType3.fs # ElseBranchHasWrongType3.fs - SOURCE=ElseBranchHasWrongType4.fs # ElseBranchHasWrongType4.fs - SOURCE=NestedElseBranchHasWrongType.fs # NestedElseBranchHasWrongType.fs - SOURCE=ElseBranchHasWrongContextType.fs # ElseBranchHasWrongContextType.fs - SOURCE=ElseBranchContextDoesntPropagateInAppl.fs # ElseBranchContextDoesntPropagateInAppl.fs - SOURCE=ElseBranchContextDoesntPropagateInAppl2.fs # ElseBranchContextDoesntPropagateInAppl2.fs - SOURCE=ElseBranchContextDoesntPropagateInForLoop.fs # ElseBranchContextDoesntPropagateInForLoop.fs - SOURCE=ElseBranchContextDoesntPropagateToLinesBeforeLastLine.fs # ElseBranchContextDoesntPropagateToLinesBeforeLastLine.fs SOURCE=MatchingMethodWithSameNameIsNotAbstract.fs # MatchingMethodWithSameNameIsNotAbstract.fs SOURCE=NoMatchingAbstractMethodWithSameName.fs # NoMatchingAbstractMethodWithSameName.fs SOURCE=MissingExpressionAfterLet.fs # MissingExpressionAfterLet.fs