Skip to content

Commit 0b9f214

Browse files
TIHanKevinRansom
authored andcommitted
Fixed not struct constraint for anon records. (#6217)
* Fixed not struct constraint for anon records. Added better way to test source code. * Added more tests * Added one more test
1 parent d84d5ad commit 0b9f214

5 files changed

Lines changed: 112 additions & 2 deletions

File tree

src/fsharp/TastOps.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1773,7 +1773,8 @@ let isRefTy g ty =
17731773
isFunTy g ty ||
17741774
isReprHiddenTy g ty ||
17751775
isFSharpObjModelRefTy g ty ||
1776-
isUnitTy g ty
1776+
isUnitTy g ty ||
1777+
(isAnonRecdTy g ty && not (isStructAnonRecdTy g ty))
17771778
)
17781779

17791780
// ECMA C# LANGUAGE SPECIFICATION, 27.2
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
2+
3+
namespace FSharp.Compiler.UnitTests
4+
5+
open System
6+
open Microsoft.FSharp.Compiler.Text
7+
open Microsoft.FSharp.Compiler.SourceCodeServices
8+
9+
open NUnit.Framework
10+
11+
[<RequireQualifiedAccess>]
12+
module Compiler =
13+
14+
let checker = FSharpChecker.Create()
15+
16+
let private defaultProjectOptions =
17+
{
18+
ProjectFileName = "Z:\\test.fsproj"
19+
ProjectId = None
20+
SourceFiles = [|"test.fs"|]
21+
OtherOptions = [||]
22+
ReferencedProjects = [||]
23+
IsIncompleteTypeCheckEnvironment = false
24+
UseScriptResolutionRules = false
25+
LoadTime = DateTime()
26+
UnresolvedReferences = None
27+
OriginalLoadReferences = []
28+
ExtraProjectInfo = None
29+
Stamp = None
30+
}
31+
32+
let AssertPass (source: string) =
33+
let parseResults, fileAnswer = checker.ParseAndCheckFileInProject("test.fs", 0, SourceText.ofString source, defaultProjectOptions) |> Async.RunSynchronously
34+
35+
Assert.True(parseResults.Errors.Length = 0, sprintf "Parse errors: %A" parseResults.Errors)
36+
37+
match fileAnswer with
38+
| FSharpCheckFileAnswer.Aborted _ -> Assert.Fail("Type Checker Aborted")
39+
| FSharpCheckFileAnswer.Succeeded(typeCheckResults) ->
40+
41+
Assert.True(typeCheckResults.Errors.Length = 0, sprintf "Type Check errors: %A" typeCheckResults.Errors)
42+
43+
let AssertSingleErrorTypeCheck (source: string) (expectedErrorNumber: int) (expectedErrorRange: int * int * int * int) (expectedErrorMsg: string) =
44+
let parseResults, fileAnswer = checker.ParseAndCheckFileInProject("test.fs", 0, SourceText.ofString source, defaultProjectOptions) |> Async.RunSynchronously
45+
46+
Assert.True(parseResults.Errors.Length = 0, sprintf "Parse errors: %A" parseResults.Errors)
47+
48+
match fileAnswer with
49+
| FSharpCheckFileAnswer.Aborted _ -> Assert.Fail("Type Checker Aborted")
50+
| FSharpCheckFileAnswer.Succeeded(typeCheckResults) ->
51+
52+
Assert.True(typeCheckResults.Errors.Length = 1, sprintf "Expected one type check error: %A" typeCheckResults.Errors)
53+
typeCheckResults.Errors
54+
|> Array.iter (fun info ->
55+
Assert.AreEqual(FSharpErrorSeverity.Error, info.Severity)
56+
Assert.AreEqual(expectedErrorNumber, info.ErrorNumber, "expectedErrorNumber")
57+
Assert.AreEqual(expectedErrorRange, (info.StartLineAlternate, info.StartColumn, info.EndLineAlternate, info.EndColumn), "expectedErrorRange")
58+
Assert.AreEqual(expectedErrorMsg, info.Message, "expectedErrorMsg")
59+
)

tests/FSharp.Compiler.UnitTests/FSharp.Compiler.UnitTests.fsproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
<Compile Include="HashIfExpression.fs" />
1717
<Compile Include="ProductVersion.fs" />
1818
<Compile Include="EditDistance.fs" />
19+
<Compile Include="Compiler.fs" />
1920
<Compile Include="ILHelpers.fs" />
21+
<Compile Include="Language\AnonRecords.fs" />
2022
<Compile Include="Language\StringConcat.fs" />
2123
<Compile Include="SourceTextTests.fs" />
2224
</ItemGroup>

tests/FSharp.Compiler.UnitTests/ILHelpers.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ open NUnit.Framework
1010

1111
open Microsoft.FSharp.Compiler.SourceCodeServices
1212

13+
[<RequireQualifiedAccess>]
1314
module ILChecker =
1415

15-
let checker = FSharpChecker.Create()
16+
let checker = Compiler.checker
1617

1718
let private (++) a b = Path.Combine(a,b)
1819

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
2+
3+
namespace FSharp.Compiler.UnitTests
4+
5+
open NUnit.Framework
6+
7+
[<TestFixture>]
8+
module AnonRecords =
9+
10+
[<Test>]
11+
let NotStructConstraintPass() =
12+
Compiler.AssertPass
13+
"""
14+
type RefClass<'a when 'a : not struct>() = class end
15+
let rAnon = RefClass<{| R: int |}>()
16+
"""
17+
18+
[<Test>]
19+
let StructConstraintPass() =
20+
Compiler.AssertPass
21+
"""
22+
type StructClass<'a when 'a : struct>() = class end
23+
let sAnon = StructClass<struct {| S: int |}>()
24+
"""
25+
26+
[<Test>]
27+
let NotStructConstraintFail() =
28+
Compiler.AssertSingleErrorTypeCheck
29+
"""
30+
type RefClass<'a when 'a : not struct>() = class end
31+
let rAnon = RefClass<struct {| R: int |}>()
32+
"""
33+
1
34+
(3, 16, 3, 45)
35+
"A generic construct requires that the type 'struct {|R : int|}' have reference semantics, but it does not, i.e. it is a struct"
36+
37+
[<Test>]
38+
let StructConstraintFail() =
39+
Compiler.AssertSingleErrorTypeCheck
40+
"""
41+
type StructClass<'a when 'a : struct>() = class end
42+
let sAnon = StructClass<{| S: int |}>()
43+
"""
44+
1
45+
(3, 12, 3, 37)
46+
"A generic construct requires that the type '{|S : int|}' is a CLI or F# struct type"
47+

0 commit comments

Comments
 (0)