diff --git a/tests/fsharp/Compiler/CompilerAssert.fs b/tests/fsharp/Compiler/CompilerAssert.fs index d5f93d7810e..ade3ca8e4a3 100644 --- a/tests/fsharp/Compiler/CompilerAssert.fs +++ b/tests/fsharp/Compiler/CompilerAssert.fs @@ -217,3 +217,22 @@ module CompilerAssert = Assert.AreEqual(expectedErrorMessage, errorMessage) ) + let ParseWithErrors (source: string) expectedParseErrors = + let parseResults = checker.ParseFile("test.fs", SourceText.ofString source, FSharpParsingOptions.Default) |> Async.RunSynchronously + + Assert.True(parseResults.ParseHadErrors) + + let errors = + parseResults.Errors + |> Array.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message) + + Assert.AreEqual(Array.length expectedParseErrors, errors.Length, sprintf "Type check errors: %A" parseResults.Errors) + + Array.zip errors expectedParseErrors + |> Array.iter (fun (info, expectedError) -> + let (expectedServerity: FSharpErrorSeverity, expectedErrorNumber: int, expectedErrorRange: int * int * int * int, expectedErrorMsg: string) = expectedError + Assert.AreEqual(expectedServerity, 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") + ) \ No newline at end of file diff --git a/tests/fsharp/Compiler/ErrorMessages/AssignmentErrorTests.fs b/tests/fsharp/Compiler/ErrorMessages/AssignmentErrorTests.fs new file mode 100644 index 00000000000..51b75dd87d7 --- /dev/null +++ b/tests/fsharp/Compiler/ErrorMessages/AssignmentErrorTests.fs @@ -0,0 +1,23 @@ +// 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.Compiler.SourceCodeServices + +[] +module ``Errors assigning to mutable objects`` = + + [] + let ``Assign to immutable error``() = + CompilerAssert.TypeCheckSingleError + """ +let x = 10 +x <- 20 + +exit 0 + """ + FSharpErrorSeverity.Error + 27 + (3, 1, 3, 8) + "This value is not mutable. Consider using the mutable keyword, e.g. 'let mutable x = expression'." \ No newline at end of file diff --git a/tests/fsharp/Compiler/Warnings/AssignmentWarningTests.fs b/tests/fsharp/Compiler/Warnings/AssignmentWarningTests.fs new file mode 100644 index 00000000000..2a0d15d8f8b --- /dev/null +++ b/tests/fsharp/Compiler/Warnings/AssignmentWarningTests.fs @@ -0,0 +1,108 @@ +// 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.Compiler.SourceCodeServices + +[] +module ``Warnings assigning to mutable and immutable objects`` = + + [] + let ``Unused compare with immutable when assignment might be intended``() = + CompilerAssert.TypeCheckSingleError + """ +let x = 10 +let y = "hello" + +let changeX() = + x = 20 + y = "test" + +exit 0 + """ + FSharpErrorSeverity.Warning + 20 + (6, 5, 6, 11) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to mutate a value, then mark the value 'mutable' and use the '<-' operator e.g. 'x <- expression'." + + [] + let ``Unused compare with mutable when assignment might be intended``() = + CompilerAssert.TypeCheckSingleError + """ +let mutable x = 10 +let y = "hello" + +let changeX() = + x = 20 + y = "test" + +exit 0 + """ + FSharpErrorSeverity.Warning + 20 + (6, 5, 6, 11) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to mutate a value, then use the '<-' operator e.g. 'x <- expression'." + + [] + let ``Unused comparison of property in dotnet object when assignment might be intended``() = + CompilerAssert.TypeCheckSingleError + """ +open System + +let z = new System.Timers.Timer() +let y = "hello" + +let changeProperty() = + z.Enabled = true + y = "test" + +exit 0 + """ + FSharpErrorSeverity.Warning + 20 + (8, 5, 8, 21) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to set a value to a property, then use the '<-' operator e.g. 'z.Enabled <- expression'." + + [] + let ``Unused comparison of property when assignment might be intended ``() = + CompilerAssert.TypeCheckSingleError + """ +type MyClass(property1 : int) = + member val Property1 = property1 + member val Property2 = "" with get, set + +let x = MyClass(1) +let y = "hello" + +let changeProperty() = + x.Property2 = "20" + y = "test" + +exit 0 + """ + FSharpErrorSeverity.Warning + 20 + (10, 5, 10, 23) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'. If you intended to set a value to a property, then use the '<-' operator e.g. 'x.Property2 <- expression'." + + [] + let ``Don't warn if assignment to property without setter ``() = + CompilerAssert.TypeCheckSingleError + """ +type MyClass(property1 : int) = + member val Property2 = "" with get + +let x = MyClass(1) +let y = "hello" + +let changeProperty() = + x.Property2 = "22" + y = "test" + +exit 0 + """ + FSharpErrorSeverity.Warning + 20 + (9, 5, 9, 23) + "The result of this equality expression has type 'bool' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'." \ No newline at end of file diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj index b1bb4c1e33a..50e3e4f2d47 100644 --- a/tests/fsharp/FSharpSuite.Tests.fsproj +++ b/tests/fsharp/FSharpSuite.Tests.fsproj @@ -38,6 +38,7 @@ + @@ -45,6 +46,7 @@ + diff --git a/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_GlobalQualifierAfterDot.fs b/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_GlobalQualifierAfterDot.fs deleted file mode 100644 index 9bde0edbc4f..00000000000 --- a/tests/fsharpqa/Source/ErrorMessages/NameResolution/E_GlobalQualifierAfterDot.fs +++ /dev/null @@ -1,6 +0,0 @@ -// #ErrorMessages #NameResolution -//'global' may only be used as the first name in a qualified path - -let x = global.System.String.Empty.global.System.String.Empty - -exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/ErrorMessages/NameResolution/env.lst b/tests/fsharpqa/Source/ErrorMessages/NameResolution/env.lst deleted file mode 100644 index 71bc0eb3900..00000000000 --- a/tests/fsharpqa/Source/ErrorMessages/NameResolution/env.lst +++ /dev/null @@ -1 +0,0 @@ -SOURCE=E_GlobalQualifierAfterDot.fs # E_GlobalQualifierAfterDot \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/AssignmentOnImmutable.fs b/tests/fsharpqa/Source/Warnings/AssignmentOnImmutable.fs deleted file mode 100644 index a2e35c78a90..00000000000 --- a/tests/fsharpqa/Source/Warnings/AssignmentOnImmutable.fs +++ /dev/null @@ -1,7 +0,0 @@ -// #Warnings -//This value is not mutable. Consider using the mutable keyword, e.g. 'let mutable x = expression'. - -let x = 10 -x <- 20 - -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 9b5fbffaeba..a3d677bf0fc 100644 --- a/tests/fsharpqa/Source/Warnings/env.lst +++ b/tests/fsharpqa/Source/Warnings/env.lst @@ -32,7 +32,6 @@ SOURCE=MatchingMethodWithSameNameIsNotAbstract.fs # MatchingMethodWithSameNameIsNotAbstract.fs SOURCE=NoMatchingAbstractMethodWithSameName.fs # NoMatchingAbstractMethodWithSameName.fs SOURCE=MissingExpressionAfterLet.fs # MissingExpressionAfterLet.fs - SOURCE=AssignmentOnImmutable.fs # AssignmentOnImmutable.fs SOURCE=SuggestFieldsInCtor.fs # SuggestFieldsInCtor.fs SOURCE=FieldSuggestion.fs # FieldSuggestion.fs SOURCE=SuggestToUseIndexer.fs # SuggestToUseIndexer.fs diff --git a/tests/fsharpqa/Source/test.lst b/tests/fsharpqa/Source/test.lst index f3d79d7a03f..147475acc7f 100644 --- a/tests/fsharpqa/Source/test.lst +++ b/tests/fsharpqa/Source/test.lst @@ -264,7 +264,6 @@ Misc01 Libraries\Core\Operators Misc01 Libraries\Core\Reflection Misc01 Libraries\Core\Unchecked Misc01 Warnings -Misc01 ErrorMessages\NameResolution Misc01 ErrorMessages\UnitGenericAbstractType Misc01 ErrorMessages\ConfusingTypeName