From d19a7787dff92f49208e9ff1d144a02ae3f8ff48 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 8 Feb 2019 14:15:54 -0800 Subject: [PATCH 1/3] Fixed not struct constraint for anon records. Added better way to test source code. --- src/fsharp/TastOps.fs | 3 +- tests/FSharp.Compiler.UnitTests/Compiler.fs | 41 +++++++++++++++++++ .../FSharp.Compiler.UnitTests.fsproj | 2 + tests/FSharp.Compiler.UnitTests/ILHelpers.fs | 3 +- .../Language/AnonRecords.fs | 15 +++++++ 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 tests/FSharp.Compiler.UnitTests/Compiler.fs create mode 100644 tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs diff --git a/src/fsharp/TastOps.fs b/src/fsharp/TastOps.fs index 23242b1aff6..1c2361f711b 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -1773,7 +1773,8 @@ let isRefTy g ty = isFunTy g ty || isReprHiddenTy g ty || isFSharpObjModelRefTy g ty || - isUnitTy g ty + isUnitTy g ty || + (isAnonRecdTy g ty && not (isStructAnonRecdTy g ty)) ) // ECMA C# LANGUAGE SPECIFICATION, 27.2 diff --git a/tests/FSharp.Compiler.UnitTests/Compiler.fs b/tests/FSharp.Compiler.UnitTests/Compiler.fs new file mode 100644 index 00000000000..e445e22ab63 --- /dev/null +++ b/tests/FSharp.Compiler.UnitTests/Compiler.fs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests + +open System +open Microsoft.FSharp.Compiler.Text +open Microsoft.FSharp.Compiler.SourceCodeServices + +open NUnit.Framework + +[] +module Compiler = + + let checker = FSharpChecker.Create() + + let private defaultProjectOptions = + { + ProjectFileName = "Z:\\test.fsproj" + ProjectId = None + SourceFiles = [|"test.fs"|] + OtherOptions = [||] + ReferencedProjects = [||] + IsIncompleteTypeCheckEnvironment = false + UseScriptResolutionRules = false + LoadTime = DateTime() + UnresolvedReferences = None + OriginalLoadReferences = [] + ExtraProjectInfo = None + Stamp = None + } + + let AssertPositive (source: string) = + let parseResults, fileAnswer = checker.ParseAndCheckFileInProject("test.fs", 0, SourceText.ofString source, defaultProjectOptions) |> Async.RunSynchronously + + Assert.True(parseResults.Errors.Length = 0, sprintf "Parse errors: %A" parseResults.Errors) + + match fileAnswer with + | FSharpCheckFileAnswer.Aborted _ -> Assert.Fail("Type Checker Aborted") + | FSharpCheckFileAnswer.Succeeded(typeCheckResults) -> + + Assert.True(typeCheckResults.Errors.Length = 0, sprintf "Type Checker errors: %A" typeCheckResults.Errors) \ No newline at end of file diff --git a/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj b/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj index bbeac7ee59f..39f58117621 100644 --- a/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj +++ b/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj @@ -16,7 +16,9 @@ + + diff --git a/tests/FSharp.Compiler.UnitTests/ILHelpers.fs b/tests/FSharp.Compiler.UnitTests/ILHelpers.fs index 372e11d0702..ddaf4c6fd60 100644 --- a/tests/FSharp.Compiler.UnitTests/ILHelpers.fs +++ b/tests/FSharp.Compiler.UnitTests/ILHelpers.fs @@ -10,9 +10,10 @@ open NUnit.Framework open Microsoft.FSharp.Compiler.SourceCodeServices +[] module ILChecker = - let checker = FSharpChecker.Create() + let checker = Compiler.checker let private (++) a b = Path.Combine(a,b) diff --git a/tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs b/tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs new file mode 100644 index 00000000000..05e67f6d3d4 --- /dev/null +++ b/tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs @@ -0,0 +1,15 @@ +// 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 AnonRecords = + + [] + let NotStructConstraintPass() = + Compiler.AssertPositive(""" +type RefClass<'a when 'a : not struct>() = class end +let rAnon = RefClass< {| R: int |}>()""") + From 0565988a7abab7932212637af167e7c53c09ba92 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 8 Feb 2019 15:36:04 -0800 Subject: [PATCH 2/3] Added more tests --- tests/FSharp.Compiler.UnitTests/Compiler.fs | 22 ++++++++++++++-- .../Language/AnonRecords.fs | 25 +++++++++++++++++-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/tests/FSharp.Compiler.UnitTests/Compiler.fs b/tests/FSharp.Compiler.UnitTests/Compiler.fs index e445e22ab63..a83d8a6f7c3 100644 --- a/tests/FSharp.Compiler.UnitTests/Compiler.fs +++ b/tests/FSharp.Compiler.UnitTests/Compiler.fs @@ -29,7 +29,7 @@ module Compiler = Stamp = None } - let AssertPositive (source: string) = + let AssertPass (source: string) = let parseResults, fileAnswer = checker.ParseAndCheckFileInProject("test.fs", 0, SourceText.ofString source, defaultProjectOptions) |> Async.RunSynchronously Assert.True(parseResults.Errors.Length = 0, sprintf "Parse errors: %A" parseResults.Errors) @@ -38,4 +38,22 @@ module Compiler = | FSharpCheckFileAnswer.Aborted _ -> Assert.Fail("Type Checker Aborted") | FSharpCheckFileAnswer.Succeeded(typeCheckResults) -> - Assert.True(typeCheckResults.Errors.Length = 0, sprintf "Type Checker errors: %A" typeCheckResults.Errors) \ No newline at end of file + Assert.True(typeCheckResults.Errors.Length = 0, sprintf "Type Check errors: %A" typeCheckResults.Errors) + + let AssertSingleErrorTypeCheck (source: string) (expectedErrorNumber: int) (expectedErrorRange: int * int * int * int) (expectedErrorMsg: string) = + let parseResults, fileAnswer = checker.ParseAndCheckFileInProject("test.fs", 0, SourceText.ofString source, defaultProjectOptions) |> Async.RunSynchronously + + Assert.True(parseResults.Errors.Length = 0, sprintf "Parse errors: %A" parseResults.Errors) + + match fileAnswer with + | FSharpCheckFileAnswer.Aborted _ -> Assert.Fail("Type Checker Aborted") + | FSharpCheckFileAnswer.Succeeded(typeCheckResults) -> + + Assert.True(typeCheckResults.Errors.Length = 1, sprintf "Expected one type check error: %A" typeCheckResults.Errors) + typeCheckResults.Errors + |> Array.iter (fun info -> + Assert.AreEqual(FSharpErrorSeverity.Error, info.Severity) + Assert.AreEqual(expectedErrorNumber, info.ErrorNumber, "expectedErrorNumber") + Assert.AreEqual(expectedErrorRange, (info.StartLineAlternate, info.StartColumn, info.EndLineAlternate, info.EndColumn), "expectedErrorRange") + Assert.AreEqual(expectedErrorMsg, info.Message, "expectedErrorMsg") + ) \ No newline at end of file diff --git a/tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs b/tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs index 05e67f6d3d4..c865c831b5a 100644 --- a/tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs +++ b/tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs @@ -9,7 +9,28 @@ module AnonRecords = [] let NotStructConstraintPass() = - Compiler.AssertPositive(""" + Compiler.AssertPass + """ type RefClass<'a when 'a : not struct>() = class end -let rAnon = RefClass< {| R: int |}>()""") +let rAnon = RefClass<{| R: int |}>() + """ + + [] + let StructConstraintPass() = + Compiler.AssertPass + """ +type StructClass<'a when 'a : struct>() = class end +let sAnon = StructClass() + """ + + [] + let StructConstraintFail() = + Compiler.AssertSingleErrorTypeCheck + """ +type StructClass<'a when 'a : struct>() = class end +let sAnon = StructClass<{| S: int |}>() + """ + 1 + (3, 12, 3, 37) + "A generic construct requires that the type '{|S : int|}' is a CLI or F# struct type" From eaf3e539ccf987b72595814fbd55ff8bf399455c Mon Sep 17 00:00:00 2001 From: Will Smith Date: Fri, 8 Feb 2019 16:15:30 -0800 Subject: [PATCH 3/3] Added one more test --- .../FSharp.Compiler.UnitTests/Language/AnonRecords.fs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs b/tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs index c865c831b5a..b507fa9afe2 100644 --- a/tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs +++ b/tests/FSharp.Compiler.UnitTests/Language/AnonRecords.fs @@ -23,6 +23,17 @@ type StructClass<'a when 'a : struct>() = class end let sAnon = StructClass() """ + [] + let NotStructConstraintFail() = + Compiler.AssertSingleErrorTypeCheck + """ + type RefClass<'a when 'a : not struct>() = class end + let rAnon = RefClass() + """ + 1 + (3, 16, 3, 45) + "A generic construct requires that the type 'struct {|R : int|}' have reference semantics, but it does not, i.e. it is a struct" + [] let StructConstraintFail() = Compiler.AssertSingleErrorTypeCheck