Skip to content

Commit 3183d55

Browse files
authored
Improve error reporting for anonymous records declarations (#15824)
* Improve error reporting on anonymous record declarations
1 parent 579961f commit 3183d55

File tree

2 files changed

+91
-7
lines changed

2 files changed

+91
-7
lines changed

src/Compiler/Checking/CheckExpressions.fs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4511,20 +4511,22 @@ and TcTupleType kindOpt (cenv: cenv) newOk checkConstraints occ env tpenv isStru
45114511
else
45124512
let argsR,tpenv = TcTypesAsTuple cenv newOk checkConstraints occ env tpenv args m
45134513
TType_tuple(tupInfo, argsR), tpenv
4514+
4515+
and CheckAnonRecdTypeDuplicateFields (elems: Ident array) =
4516+
elems |> Array.iteri (fun i (uc1: Ident) ->
4517+
elems |> Array.iteri (fun j (uc2: Ident) ->
4518+
if j > i && uc1.idText = uc2.idText then
4519+
errorR(Error(FSComp.SR.tcAnonRecdTypeDuplicateFieldId(uc1.idText), uc1.idRange))))
45144520

45154521
and TcAnonRecdType (cenv: cenv) newOk checkConstraints occ env tpenv isStruct args m =
45164522
let tupInfo = mkTupInfo isStruct
4523+
let unsortedFieldIds = args |> List.map fst |> List.toArray
4524+
if unsortedFieldIds.Length > 1 then
4525+
CheckAnonRecdTypeDuplicateFields unsortedFieldIds
45174526
let tup = args |> List.map (fun (_, t) -> SynTupleTypeSegment.Type t)
45184527
let argsR,tpenv = TcTypesAsTuple cenv newOk checkConstraints occ env tpenv tup m
4519-
let unsortedFieldIds = args |> List.map fst |> List.toArray
45204528
let anonInfo = AnonRecdTypeInfo.Create(cenv.thisCcu, tupInfo, unsortedFieldIds)
45214529

4522-
// Check for duplicate field IDs
4523-
unsortedFieldIds
4524-
|> Array.countBy (fun fieldId -> fieldId.idText)
4525-
|> Array.iter (fun (idText, count) ->
4526-
if count > 1 then error (Error (FSComp.SR.tcAnonRecdTypeDuplicateFieldId(idText), m)))
4527-
45284530
// Sort into canonical order
45294531
let sortedFieldTys, sortedCheckedArgTys = List.zip args argsR |> List.indexed |> List.sortBy (fun (i,_) -> unsortedFieldIds[i].idText) |> List.map snd |> List.unzip
45304532

tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,85 @@ let x = {| abcd = {| ab = 4; cd = 1 |} |}
221221
"""
222222
|> compile
223223
|> shouldSucceed
224+
225+
[<Fact>]
226+
let ``Anonymous Records field appears multiple times in this anonymous record definition`` () =
227+
Fsx """
228+
let x(f: {| A: int; A: int |}) = ()
229+
"""
230+
|> compile
231+
|> shouldFail
232+
|> withDiagnostics [
233+
(Error 3523, Line 2, Col 13, Line 2, Col 14, "The field 'A' appears multiple times in this anonymous record type.")
234+
]
235+
236+
[<Fact>]
237+
let ``Anonymous Records field appears multiple times in this anonymous record definition 2`` () =
238+
Fsx """
239+
let x(f: {| A: int; A: int; A:int |}) = ()
240+
"""
241+
|> compile
242+
|> shouldFail
243+
|> withDiagnostics [
244+
(Error 3523, Line 2, Col 13, Line 2, Col 14, "The field 'A' appears multiple times in this anonymous record type.")
245+
(Error 3523, Line 2, Col 21, Line 2, Col 22, "The field 'A' appears multiple times in this anonymous record type.")
246+
]
247+
248+
[<Fact>]
249+
let ``Anonymous Records field appears multiple times in this anonymous record declaration 3`` () =
250+
Fsx """
251+
let f(x:{| A: int; B: int; A:string; B: int |}) = ()
252+
"""
253+
|> compile
254+
|> shouldFail
255+
|> withDiagnostics [
256+
(Error 3523, Line 2, Col 12, Line 2, Col 13, "The field 'A' appears multiple times in this anonymous record type.")
257+
(Error 3523, Line 2, Col 20, Line 2, Col 21, "The field 'B' appears multiple times in this anonymous record type.")
258+
]
259+
260+
[<Fact>]
261+
let ``Anonymous Records field appears multiple times in this anonymous record declaration 4`` () =
262+
Fsx """
263+
let f(x:{| A: int; C: string; A: int; B: int |}) = ()
264+
"""
265+
|> compile
266+
|> shouldFail
267+
|> withDiagnostics [
268+
(Error 3523, Line 2, Col 12, Line 2, Col 13, "The field 'A' appears multiple times in this anonymous record type.")
269+
]
270+
271+
[<Fact>]
272+
let ``Anonymous Records field appears multiple times in this anonymous record declaration 5`` () =
273+
Fsx """
274+
let f(x:{| A: int; C: string; A: int; B: int; A: int |}) = ()
275+
"""
276+
|> compile
277+
|> shouldFail
278+
|> withDiagnostics [
279+
(Error 3523, Line 2, Col 12, Line 2, Col 13, "The field 'A' appears multiple times in this anonymous record type.")
280+
(Error 3523, Line 2, Col 31, Line 2, Col 32, "The field 'A' appears multiple times in this anonymous record type.")
281+
]
282+
283+
[<Fact>]
284+
let ``Anonymous Records field with in double backticks appears multiple times in this anonymous record declaration`` () =
285+
Fsx """
286+
let f(x:{| ``A``: int; B: int; A:string; B: int |}) = ()
287+
"""
288+
|> compile
289+
|> shouldFail
290+
|> withDiagnostics [
291+
(Error 3523, Line 2, Col 12, Line 2, Col 17, "The field 'A' appears multiple times in this anonymous record type.")
292+
(Error 3523, Line 2, Col 24, Line 2, Col 25, "The field 'B' appears multiple times in this anonymous record type.")
293+
]
294+
295+
[<Fact>]
296+
let ``Anonymous Records field appears multiple times in this anonymous record declaration 6`` () =
297+
Fsx """
298+
let foo: {| A: int; C: string; A: int; B: int; A: int |} = failwith "foo"
299+
"""
300+
|> compile
301+
|> shouldFail
302+
|> withDiagnostics [
303+
(Error 3523, Line 2, Col 13, Line 2, Col 14, "The field 'A' appears multiple times in this anonymous record type.")
304+
(Error 3523, Line 2, Col 32, Line 2, Col 33, "The field 'A' appears multiple times in this anonymous record type.")
305+
]

0 commit comments

Comments
 (0)