diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index c7b4b6da3e2..92b189c016d 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -4511,20 +4511,22 @@ and TcTupleType kindOpt (cenv: cenv) newOk checkConstraints occ env tpenv isStru else let argsR,tpenv = TcTypesAsTuple cenv newOk checkConstraints occ env tpenv args m TType_tuple(tupInfo, argsR), tpenv + +and CheckAnonRecdTypeDuplicateFields (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.tcAnonRecdTypeDuplicateFieldId(uc1.idText), uc1.idRange)))) and TcAnonRecdType (cenv: cenv) newOk checkConstraints occ env tpenv isStruct args m = let tupInfo = mkTupInfo isStruct + let unsortedFieldIds = args |> List.map fst |> List.toArray + if unsortedFieldIds.Length > 1 then + CheckAnonRecdTypeDuplicateFields unsortedFieldIds let tup = args |> List.map (fun (_, t) -> SynTupleTypeSegment.Type t) let argsR,tpenv = TcTypesAsTuple cenv newOk checkConstraints occ env tpenv tup m - let unsortedFieldIds = args |> List.map fst |> List.toArray let anonInfo = AnonRecdTypeInfo.Create(cenv.thisCcu, tupInfo, unsortedFieldIds) - // Check for duplicate field IDs - unsortedFieldIds - |> Array.countBy (fun fieldId -> fieldId.idText) - |> Array.iter (fun (idText, count) -> - if count > 1 then error (Error (FSComp.SR.tcAnonRecdTypeDuplicateFieldId(idText), m))) - // Sort into canonical order let sortedFieldTys, sortedCheckedArgTys = List.zip args argsR |> List.indexed |> List.sortBy (fun (i,_) -> unsortedFieldIds[i].idText) |> List.map snd |> List.unzip diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs index b5074a29007..32588c31f47 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs @@ -221,3 +221,85 @@ let x = {| abcd = {| ab = 4; cd = 1 |} |} """ |> compile |> shouldSucceed + + [] + let ``Anonymous Records field appears multiple times in this anonymous record definition`` () = + Fsx """ +let x(f: {| A: int; A: int |}) = () + """ + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 3523, Line 2, Col 13, Line 2, Col 14, "The field 'A' appears multiple times in this anonymous record type.") + ] + + [] + let ``Anonymous Records field appears multiple times in this anonymous record definition 2`` () = + Fsx """ +let x(f: {| A: int; A: int; A:int |}) = () + """ + |> compile + |> shouldFail + |> withDiagnostics [ + (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 21, Line 2, Col 22, "The field 'A' appears multiple times in this anonymous record type.") + ] + + [] + let ``Anonymous Records field appears multiple times in this anonymous record declaration 3`` () = + Fsx """ +let f(x:{| A: int; B: int; A:string; B: int |}) = () + """ + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 3523, Line 2, Col 12, Line 2, Col 13, "The field 'A' appears multiple times in this anonymous record type.") + (Error 3523, Line 2, Col 20, Line 2, Col 21, "The field 'B' appears multiple times in this anonymous record type.") + ] + + [] + let ``Anonymous Records field appears multiple times in this anonymous record declaration 4`` () = + Fsx """ +let f(x:{| A: int; C: string; A: int; B: int |}) = () + """ + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 3523, Line 2, Col 12, Line 2, Col 13, "The field 'A' appears multiple times in this anonymous record type.") + ] + + [] + let ``Anonymous Records field appears multiple times in this anonymous record declaration 5`` () = + Fsx """ +let f(x:{| A: int; C: string; A: int; B: int; A: int |}) = () + """ + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 3523, Line 2, Col 12, Line 2, Col 13, "The field 'A' appears multiple times in this anonymous record type.") + (Error 3523, Line 2, Col 31, Line 2, Col 32, "The field 'A' appears multiple times in this anonymous record type.") + ] + + [] + let ``Anonymous Records field with in double backticks appears multiple times in this anonymous record declaration`` () = + Fsx """ +let f(x:{| ``A``: int; B: int; A:string; B: int |}) = () + """ + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 3523, Line 2, Col 12, Line 2, Col 17, "The field 'A' appears multiple times in this anonymous record type.") + (Error 3523, Line 2, Col 24, Line 2, Col 25, "The field 'B' appears multiple times in this anonymous record type.") + ] + + [] + let ``Anonymous Records field appears multiple times in this anonymous record declaration 6`` () = + Fsx """ +let foo: {| A: int; C: string; A: int; B: int; A: int |} = failwith "foo" + """ + |> compile + |> shouldFail + |> withDiagnostics [ + (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.") + ]