Skip to content

Commit 2fabdaa

Browse files
authored
Merge pull request #7213 from dotnet/merges/master-to-release/dev16.3
Merge master to release/dev16.3
2 parents 660a545 + 60c915a commit 2fabdaa

30 files changed

Lines changed: 1181 additions & 1128 deletions

src/fsharp/NicePrint.fs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ module internal PrintUtilities =
3232
let bracketIfL x lyt = if x then bracketL lyt else lyt
3333
let squareAngleL x = LeftL.leftBracketAngle ^^ x ^^ RightL.rightBracketAngle
3434
let angleL x = sepL Literals.leftAngle ^^ x ^^ rightL Literals.rightAngle
35-
let braceL x = leftL Literals.leftBrace ^^ x ^^ rightL Literals.rightBrace
36-
let braceBarL x = leftL Literals.leftBraceBar ^^ x ^^ rightL Literals.rightBraceBar
35+
let braceL x = wordL Literals.leftBrace ^^ x ^^ wordL Literals.rightBrace
36+
let braceBarL x = wordL Literals.leftBraceBar ^^ x ^^ wordL Literals.rightBraceBar
3737

3838
let comment str = wordL (tagText (sprintf "(* %s *)" str))
3939

@@ -942,7 +942,7 @@ module private PrintTypes =
942942

943943
// Layout a tuple type
944944
| TType_anon (anonInfo, tys) ->
945-
let core = sepListL (wordL (tagPunctuation ";")) (List.map2 (fun nm ty -> wordL (tagField nm) ^^ wordL (tagPunctuation ":") ^^ layoutTypeWithInfoAndPrec denv env prec ty) (Array.toList anonInfo.SortedNames) tys)
945+
let core = sepListL (rightL (tagPunctuation ";")) (List.map2 (fun nm ty -> wordL (tagField nm) ^^ rightL (tagPunctuation ":") ^^ layoutTypeWithInfoAndPrec denv env prec ty) (Array.toList anonInfo.SortedNames) tys)
946946
if evalAnonInfoIsStruct anonInfo then
947947
WordL.keywordStruct --- braceBarL core
948948
else
@@ -1457,7 +1457,7 @@ module private TastDefinitionPrinting =
14571457
let lhs =
14581458
tagRecordField fld.Name
14591459
|> mkNav fld.DefinitionRange
1460-
|> wordL
1460+
|> wordL
14611461
let lhs = (if addAccess then layoutAccessibility denv fld.Accessibility lhs else lhs)
14621462
let lhs = if fld.IsMutable then wordL (tagKeyword "mutable") --- lhs else lhs
14631463
(lhs ^^ RightL.colon) --- layoutType denv fld.FormalType
@@ -1738,8 +1738,15 @@ module private TastDefinitionPrinting =
17381738
let denv = denv.AddAccessibility tycon.TypeReprAccessibility
17391739
match repr with
17401740
| TRecdRepr _ ->
1741-
let recdFieldRefL fld = layoutRecdField false denv fld ^^ rightL (tagPunctuation ";")
1742-
let recdL = tycon.TrueFieldsAsList |> List.map recdFieldRefL |> applyMaxMembers denv.maxMembers |> aboveListL |> braceL
1741+
let recdFieldRefL fld = layoutRecdField false denv fld
1742+
1743+
let recdL =
1744+
tycon.TrueFieldsAsList
1745+
|> List.map recdFieldRefL
1746+
|> applyMaxMembers denv.maxMembers
1747+
|> aboveListL
1748+
|> braceL
1749+
17431750
Some (addMembersAsWithEnd (addReprAccessL recdL))
17441751

17451752
| TFSharpObjectRepr r ->
@@ -1771,8 +1778,7 @@ module private TastDefinitionPrinting =
17711778
| _ -> []
17721779
let vsprs =
17731780
tycon.MembersOfFSharpTyconSorted
1774-
|> List.filter (fun v -> isNil (Option.get v.MemberInfo).ImplementedSlotSigs)
1775-
|> List.filter (fun v -> v.IsDispatchSlot)
1781+
|> List.filter (fun v -> isNil (Option.get v.MemberInfo).ImplementedSlotSigs && v.IsDispatchSlot)
17761782
|> List.map (fun vref -> PrintTastMemberOrVals.prettyLayoutOfValOrMemberNoInst denv vref.Deref)
17771783
let staticValsLs =
17781784
tycon.TrueFieldsAsList

src/utils/sformat.fs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -759,18 +759,14 @@ namespace Microsoft.FSharp.Text.StructuredPrintfImpl
759759
// pprinter: attributes
760760
// --------------------------------------------------------------------
761761

762-
let makeRecordVerticalL nameXs =
763-
let itemL (name,xL) = let labelL = wordL name in ((labelL ^^ wordL Literals.equals)) -- (xL ^^ (rightL Literals.semicolon))
764-
let braceL xs = (leftL Literals.leftBrace) ^^ xs ^^ (rightL Literals.rightBrace)
765-
braceL (aboveListL (List.map itemL nameXs))
766-
767-
// This is a more compact rendering of records - and is more like tuples
768-
let makeRecordHorizontalL nameXs =
769-
let itemL (name,xL) = let labelL = wordL name in ((labelL ^^ wordL Literals.equals)) -- xL
770-
let braceL xs = (leftL Literals.leftBrace) ^^ xs ^^ (rightL Literals.rightBrace)
771-
braceL (sepListL (rightL Literals.semicolon) (List.map itemL nameXs))
772-
773-
let makeRecordL nameXs = makeRecordVerticalL nameXs
762+
let makeRecordL nameXs =
763+
let itemL (name,xL) = wordL name ^^ wordL Literals.equals -- xL
764+
let braceL xs = (wordL Literals.leftBrace) ^^ xs ^^ (wordL Literals.rightBrace)
765+
766+
nameXs
767+
|> List.map itemL
768+
|> aboveListL
769+
|> braceL
774770

775771
let makePropertiesL nameXs =
776772
let itemL (name,v) =
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
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+
open FSharp.Compiler.SourceCodeServices
7+
8+
[<TestFixture>]
9+
module ``Else branch has wrong type`` =
10+
11+
[<Test>]
12+
let ``Else branch is int while if branch is string``() =
13+
CompilerAssert.TypeCheckSingleError
14+
"""
15+
let test = 100
16+
let y =
17+
if test > 10 then "test"
18+
else 123
19+
"""
20+
FSharpErrorSeverity.Error
21+
1
22+
(5, 10, 5, 13)
23+
"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'."
24+
25+
[<Test>]
26+
let ``Else branch is a function that returns int while if branch is string``() =
27+
CompilerAssert.TypeCheckSingleError
28+
"""
29+
let test = 100
30+
let f x = test
31+
let y =
32+
if test > 10 then "test"
33+
else f 10
34+
"""
35+
FSharpErrorSeverity.Error
36+
1
37+
(6, 10, 6, 14)
38+
"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'."
39+
40+
41+
[<Test>]
42+
let ``Else branch is a sequence of expressions that returns int while if branch is string``() =
43+
CompilerAssert.TypeCheckSingleError
44+
"""
45+
let f x = x + 4
46+
47+
let y =
48+
if true then
49+
""
50+
else
51+
"" |> ignore
52+
(f 5)
53+
"""
54+
FSharpErrorSeverity.Error
55+
1
56+
(9, 10, 9, 13)
57+
"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'."
58+
59+
60+
[<Test>]
61+
let ``Else branch is a longer sequence of expressions that returns int while if branch is string``() =
62+
CompilerAssert.TypeCheckSingleError
63+
"""
64+
let f x = x + 4
65+
66+
let y =
67+
if true then
68+
""
69+
else
70+
"" |> ignore
71+
let z = f 4
72+
let a = 3 * z
73+
(f a)
74+
"""
75+
FSharpErrorSeverity.Error
76+
1
77+
(11, 10, 11, 13)
78+
"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'."
79+
80+
81+
[<Test>]
82+
let ``Else branch context doesn't propagate into function application``() =
83+
CompilerAssert.TypeCheckSingleError
84+
"""
85+
let test = 100
86+
let f x : string = x
87+
let y =
88+
if test > 10 then "test"
89+
else
90+
f 123
91+
"""
92+
FSharpErrorSeverity.Error
93+
1
94+
(7, 11, 7, 14)
95+
"This expression was expected to have type\n 'string' \nbut here has type\n 'int' "
96+
97+
[<Test>]
98+
let ``Else branch context doesn't propagate into function application even if not last expr``() =
99+
CompilerAssert.TypeCheckSingleError
100+
"""
101+
let test = 100
102+
let f x = printfn "%s" x
103+
let y =
104+
if test > 10 then "test"
105+
else
106+
f 123
107+
"test"
108+
"""
109+
FSharpErrorSeverity.Error
110+
1
111+
(7, 11, 7, 14)
112+
"This expression was expected to have type\n 'string' \nbut here has type\n 'int' "
113+
114+
[<Test>]
115+
let ``Else branch context doesn't propagate into for loop``() =
116+
CompilerAssert.TypeCheckSingleError
117+
"""
118+
let test = 100
119+
let list = [1..10]
120+
let y =
121+
if test > 10 then "test"
122+
else
123+
for (x:string) in list do
124+
printfn "%s" x
125+
126+
"test"
127+
"""
128+
FSharpErrorSeverity.Error
129+
1
130+
(7, 14, 7, 22)
131+
"This expression was expected to have type\n 'int' \nbut here has type\n 'string' "
132+
133+
[<Test>]
134+
let ``Else branch context doesn't propagate to lines before last line``() =
135+
CompilerAssert.TypeCheckSingleError
136+
"""
137+
let test = 100
138+
let list = [1..10]
139+
let y =
140+
if test > 10 then "test"
141+
else
142+
printfn "%s" 1
143+
144+
"test"
145+
"""
146+
FSharpErrorSeverity.Error
147+
1
148+
(7, 22, 7, 23)
149+
"This expression was expected to have type\n 'string' \nbut here has type\n 'int' "
150+
151+
[<Test>]
152+
let ``Else branch should not have wrong context type``() =
153+
CompilerAssert.TypeCheckWithErrors
154+
"""
155+
let x = 1
156+
let y : bool =
157+
if x = 2 then "A"
158+
else "B"
159+
"""
160+
[| FSharpErrorSeverity.Error, 1, (4, 19, 4, 22), "The 'if' expression needs to have type 'bool' to satisfy context type requirements. It currently has type 'string'."
161+
FSharpErrorSeverity.Error, 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'." |]
162+
163+
164+
[<Test>]
165+
let ``Else branch has wrong type in nested if``() =
166+
CompilerAssert.TypeCheckWithErrors
167+
"""
168+
let x = 1
169+
if x = 1 then true
170+
else
171+
if x = 2 then "A"
172+
else "B"
173+
"""
174+
[| FSharpErrorSeverity.Error, 1, (5, 19, 5, 22), "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'."
175+
FSharpErrorSeverity.Error, 1, (6, 10, 6, 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'."
176+
FSharpErrorSeverity.Warning, 20, (3, 1, 6, 13), "The result of this expression has type 'bool' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'." |]

tests/fsharp/Compiler/Language/AnonRecordTests.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ let rAnon = RefClass<struct {| R: int |}>()
3434
FSharpErrorSeverity.Error
3535
1
3636
(3, 13, 3, 42)
37-
"A generic construct requires that the type 'struct {|R : int|}' have reference semantics, but it does not, i.e. it is a struct"
37+
"A generic construct requires that the type 'struct {| R: int |}' have reference semantics, but it does not, i.e. it is a struct"
3838

3939
[<Test>]
4040
let StructConstraintFail() =
@@ -46,4 +46,4 @@ let sAnon = StructClass<{| S: int |}>()
4646
FSharpErrorSeverity.Error
4747
1
4848
(3, 13, 3, 38)
49-
"A generic construct requires that the type '{|S : int|}' is a CLI or F# struct type"
49+
"A generic construct requires that the type '{| S: int |}' is a CLI or F# struct type"

tests/fsharp/FSharpSuite.Tests.fsproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<Project Sdk="Microsoft.NET.Sdk">
33

44
<PropertyGroup>
@@ -32,6 +32,7 @@
3232
<Compile Include="tests.fs" />
3333
<Compile Include="Compiler\ILChecker.fs" />
3434
<Compile Include="Compiler\CompilerAssert.fs" />
35+
<Compile Include="Compiler\ErrorMessages\ElseBranchHasWrongTypeTests.fs" />
3536
<Compile Include="Compiler\SourceTextTests.fs" />
3637
<Compile Include="Compiler\Language\AnonRecordTests.fs" />
3738
<Compile Include="Compiler\Language\SpanOptimizationTests.fs" />

tests/fsharp/core/anon/lib.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ module KindB1 =
5252
check "coijoiwcnkwle1" {| a = 1 |} {| a = 1 |}
5353
check "coijoiwcnkwle2" {| a = 2 |} {| a = 2 |}
5454

55-
check "coijoiwcnkwle3" (sprintf "%A" {| X = 10 |}) "{X = 10;}"
56-
check "coijoiwcnkwle4" (sprintf "%A" {| X = 10; Y = 1 |} |> fun s -> s.Replace("\n","").Replace("\r","")) ("{X = 10; Y = 1;}".Replace("\n","").Replace("\r",""))
55+
check "coijoiwcnkwle3" (sprintf "%A" {| X = 10 |}) "{ X = 10 }"
56+
check "coijoiwcnkwle4" (sprintf "%A" {| X = 10; Y = 1 |}) "{ X = 10\n Y = 1 }"
5757
check "clekoiew09" (f2 {| X = {| X = 10 |} |}) 10
5858
check "cewkew0oijew" (f2 {| X = {| X = 20 |} |}) 20
5959

tests/fsharp/core/anon/test.fsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ module Test =
2525

2626
let testAccess = (KindB1.data1.X, KindB1.data3.X)
2727

28-
check "coijoiwcnkwle2" (sprintf "%A" KindB1.data1) "{X = 1;}"
28+
check "coijoiwcnkwle2" (sprintf "%A" KindB1.data1) "{ X = 1 }"
2929

3030
module Tests2 =
3131

3232
let testAccess = (KindB2.data1.X, KindB2.data3.X, KindB2.data3.Y)
3333

34-
check "coijoiwcnkwle3" (sprintf "%A" KindB2.data1) "{X = 1;}"
34+
check "coijoiwcnkwle3" (sprintf "%A" KindB2.data1) "{ X = 1 }"
3535

3636
let _ = (KindB2.data1 = KindB2.data1)
3737

@@ -49,7 +49,7 @@ module CrossAssemblyTest =
4949
check "vrknvio1" (SampleAPI.SampleFunction {| A=1; B = "abc" |}) 4 // note, this is creating an instance of an anonymous record from another assembly.
5050
check "vrknvio2" (SampleAPI.SampleFunctionAcceptingList [ {| A=1; B = "abc" |}; {| A=2; B = "def" |} ]) [4; 5] // note, this is creating an instance of an anonymous record from another assembly.
5151
check "vrknvio3" (let d = SampleAPI.SampleFunctionReturningAnonRecd() in d.A + d.B.Length) 4
52-
check "vrknvio4" (let d = SampleAPIStruct.SampleFunctionReturningAnonRecd() in d.ToString().Replace("\n","").Replace("\r","")) """{A = 1; B = "abc";}"""
52+
check "vrknvio4" (let d = SampleAPIStruct.SampleFunctionReturningAnonRecd() in d.ToString()) ("{ A = 1\n " + """B = "abc" }""")
5353
tests()
5454

5555
module CrossAssemblyTestStruct =

tests/fsharp/core/members/basics/test.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,8 +1178,8 @@ module ToStringOnRecordTest = begin
11781178

11791179
let a1 = {A = "201"; B = 7}
11801180
let c1 = {C = "20"; D = 17}
1181-
let expected1 = "{A = \"201\";\n B = 7;}"
1182-
let expected2 = "{C = \"20\";\n D = 17;}"
1181+
let expected1 = "{ A = \"201\"\n B = 7 }"
1182+
let expected2 = "{ C = \"20\"\n D = 17 }"
11831183

11841184
do test "record-tostring-def" (a1.ToString() = expected1)
11851185
do test "record-sprintfO-def" ((sprintf "%O" a1) = expected1)

0 commit comments

Comments
 (0)