Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7497,21 +7497,26 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, withExprOpt, synRecdFields, m
| None -> expr
expr, tpenv

and CheckAnonRecdExprDuplicateFields (elems: Ident array) =
elems |> Array.iteri (fun i (uc1: Ident) ->
elems |> Array.iteri (fun j (uc2: Ident) ->
if j > i && uc1.idText = uc2.idText then
errorR(Error (FSComp.SR.tcAnonRecdDuplicateFieldId(uc1.idText), uc1.idRange))))

// Check '{| .... |}'
and TcAnonRecdExpr cenv (overallTy: TType) env tpenv (isStruct, optOrigSynExpr, unsortedFieldIdsAndSynExprsGiven, mWholeExpr) =

// Check for duplicate field IDs
unsortedFieldIdsAndSynExprsGiven
|> List.countBy (fun (fId, _, _) -> textOfLid fId.LongIdent)
|> List.iter (fun (label, count) ->
if count > 1 then error (Error (FSComp.SR.tcAnonRecdDuplicateFieldId(label), mWholeExpr)))

match optOrigSynExpr with
| None ->
TcNewAnonRecdExpr cenv overallTy env tpenv (isStruct, unsortedFieldIdsAndSynExprsGiven, mWholeExpr)

| Some orig ->
// Ideally we should also check for duplicate field IDs in the TcCopyAndUpdateAnonRecdExpr case, but currently the logic is too complex to garante a proper error reporting
// So here we error instead errorR to avoid cascading internal errors
unsortedFieldIdsAndSynExprsGiven
|> List.countBy (fun (fId, _, _) -> textOfLid fId.LongIdent)
|> List.iter (fun (label, count) ->
if count > 1 then error (Error (FSComp.SR.tcAnonRecdDuplicateFieldId(label), mWholeExpr)))

TcCopyAndUpdateAnonRecdExpr cenv overallTy env tpenv (isStruct, orig, unsortedFieldIdsAndSynExprsGiven, mWholeExpr)

and TcNewAnonRecdExpr cenv (overallTy: TType) env tpenv (isStruct, unsortedFieldIdsAndSynExprsGiven, mWholeExpr) =
Expand All @@ -7521,6 +7526,9 @@ and TcNewAnonRecdExpr cenv (overallTy: TType) env tpenv (isStruct, unsortedField
let unsortedFieldIds = unsortedFieldIdsAndSynExprsGiven |> List.map (fun (synLongIdent, _, _) -> synLongIdent.LongIdent[0]) |> List.toArray
let anonInfo, sortedFieldTys = UnifyAnonRecdTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv mWholeExpr overallTy isStruct unsortedFieldIds

if unsortedFieldIds.Length > 1 then
CheckAnonRecdExprDuplicateFields unsortedFieldIds

// Sort into canonical order
let sortedIndexedArgs =
unsortedFieldIdsAndSynExprsGiven
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ module AnonRecd =
"""
|> compile
|> shouldFail
|> withErrorCode 3522
|> withSingleDiagnostic (Error 3522, Line 5, Col 13, Line 5, Col 48, "The field 'y' appears multiple times in this record expression.")

[<Fact>]
let ``Anonymous Record type annotation with duplicate labels`` () =
Expand All @@ -138,7 +138,7 @@ module AnonRecd =
"""
|> compile
|> shouldFail
|> withErrorCode 3523
|> withSingleDiagnostic (Error 3523, Line 5, Col 17, Line 5, Col 18, "The field 'A' appears multiple times in this anonymous record type.")

[<Fact>]
let ``Anonymous record types with parser errors or no fields do not produce overlapping diagnostics`` () =
Expand All @@ -163,7 +163,7 @@ type ErrorResponse =
]

[<Fact>]
let ``Anonymous Record type annotation with with fields defined in a record`` () =
let ``Anonymous Record type annotation with fields defined in a record`` () =
Fsx """
type T = { ff : int }

Expand Down Expand Up @@ -303,3 +303,73 @@ let foo: {| A: int; C: string; A: int; B: int; A: int |} = failwith "foo"
(Error 3523, Line 2, Col 13, Line 2, Col 14, "The field 'A' appears multiple times in this anonymous record type.")
(Error 3523, Line 2, Col 32, Line 2, Col 33, "The field 'A' appears multiple times in this anonymous record type.")
]

[<Fact>]
let ``Anonymous Records field appears multiple times in this record expression`` () =
Fsx """
let v = {| A = 1; A = 2 |}
"""
|> compile
|> shouldFail
|> withDiagnostics [
(Error 3522, Line 2, Col 12, Line 2, Col 13, "The field 'A' appears multiple times in this record expression.")
]

[<Fact>]
let ``Anonymous Records field appears multiple times in this record expression 2`` () =
Fsx """
let v = {| A = 1; A = 2; A = 3 |}
"""
|> compile
|> shouldFail
|> withDiagnostics [
(Error 3522, Line 2, Col 12, Line 2, Col 13, "The field 'A' appears multiple times in this record expression.")
(Error 3522, Line 2, Col 19, Line 2, Col 20, "The field 'A' appears multiple times in this record expression.")
]

[<Fact>]
let ``Anonymous Records field appears multiple times in this record expression 3`` () =
Fsx """
let v = {| A = 0; B = 2; A = 5; B = 6 |}
"""
|> compile
|> shouldFail
|> withDiagnostics [
(Error 3522, Line 2, Col 12, Line 2, Col 13, "The field 'A' appears multiple times in this record expression.")
(Error 3522, Line 2, Col 19, Line 2, Col 20, "The field 'B' appears multiple times in this record expression.")
]

[<Fact>]
let ``Anonymous Records field appears multiple times in this record expression 4`` () =
Fsx """
let v = {| A = 2; C = "W"; A = 8; B = 6 |}
"""
|> compile
|> shouldFail
|> withDiagnostics [
(Error 3522, Line 2, Col 12, Line 2, Col 13, "The field 'A' appears multiple times in this record expression.")
]

[<Fact>]
let ``Anonymous Records field appears multiple times in this record expression 5`` () =
Fsx """
let v = {| A = 0; C = ""; A = 1; B = 2; A = 5 |}
"""
|> compile
|> shouldFail
|> withDiagnostics [
(Error 3522, Line 2, Col 12, Line 2, Col 13, "The field 'A' appears multiple times in this record expression.")
(Error 3522, Line 2, Col 27, Line 2, Col 28, "The field 'A' appears multiple times in this record expression.")
]

[<Fact>]
let ``Anonymous Records field appears multiple times in this record expression 6`` () =
Fsx """
let v = {| ``A`` = 0; B = 5; A = ""; B = 0 |}
"""
|> compile
|> shouldFail
|> withDiagnostics [
(Error 3522, Line 2, Col 12, Line 2, Col 17, "The field 'A' appears multiple times in this record expression.")
(Error 3522, Line 2, Col 23, Line 2, Col 24, "The field 'B' appears multiple times in this record expression.")
]