Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better anonymous record error reporting #15598

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b09d8dc
Better anonymous record error reporting
edgarfgp Jul 13, 2023
fec845b
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 13, 2023
229192e
remove extra ticks
edgarfgp Jul 13, 2023
80a3fdb
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 13, 2023
70c34d9
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 19, 2023
216a6e2
Another possible approach
edgarfgp Jul 19, 2023
b075dbb
Remove previous approach and update tests
edgarfgp Jul 19, 2023
d528edc
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 19, 2023
8fa772e
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 19, 2023
9900e78
Don't change unrelated lines
edgarfgp Jul 19, 2023
0aec3c0
Merge branch 'inaccurate-error-in-anonymous-record' of github.com:edg…
edgarfgp Jul 19, 2023
b9213fc
revert unrelated change to make easy to review
edgarfgp Jul 19, 2023
f62fc28
SendEntityPathToSink
edgarfgp Jul 19, 2023
3e9200b
Add struct anon record test
edgarfgp Jul 19, 2023
f65c8c8
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 19, 2023
372c4c1
Fix merge
edgarfgp Jul 19, 2023
78297dc
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 20, 2023
3a629db
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 21, 2023
a13e971
Update error name and message
edgarfgp Jul 21, 2023
73f3a9b
Use the type name as part of the error message
edgarfgp Jul 21, 2023
b1a4037
More tests
edgarfgp Jul 21, 2023
31b8222
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 21, 2023
d26aed5
format code
edgarfgp Jul 21, 2023
adc45f1
Move to CheckExpressions to avoid poluting sig file
edgarfgp Jul 23, 2023
1556f76
Add Symbol tests
edgarfgp Jul 23, 2023
622f56f
Update to minimize diff
edgarfgp Jul 23, 2023
4ef7e80
Update ConvertToAnonymousRecordQuickFix and Tests
edgarfgp Jul 24, 2023
f16ef8e
revert changes to minimize diff
edgarfgp Jul 24, 2023
53a9359
Fix PR comments
edgarfgp Jul 25, 2023
cd92b3c
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 25, 2023
1d111fb
Symbols test take 3
edgarfgp Jul 25, 2023
2237714
Merge branch 'inaccurate-error-in-anonymous-record' of https://github…
edgarfgp Jul 25, 2023
6e8e08b
take 4
edgarfgp Jul 25, 2023
ccefaed
take 5
edgarfgp Jul 25, 2023
32f159a
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 26, 2023
29f757b
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 27, 2023
9480d75
Merge branch 'main' into inaccurate-error-in-anonymous-record
edgarfgp Jul 27, 2023
f5f27af
Ok one more time
edgarfgp Jul 27, 2023
468396f
Merge branch 'inaccurate-error-in-anonymous-record' of https://github…
edgarfgp Jul 27, 2023
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
45 changes: 32 additions & 13 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1808,7 +1808,6 @@ let BuildFieldMap (cenv: cenv) env isPartial ty (flds: ((Ident list * Ident) * '
if isNil flds then invalidArg "flds" "BuildFieldMap"

let fldCount = flds.Length

let fldResolutions =
let allFields = flds |> List.map (fun ((_, ident), _) -> ident)
flds
Expand Down Expand Up @@ -7383,21 +7382,41 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, withExprOpt, synRecdFields, m
| _ -> List.frontAndBack synLongId.LongIdent, exprBeingAssigned)

let flds = if hasOrigExpr then GroupUpdatesToNestedFields flds else flds
// Check if the overall type is an anon record type and if so raise an copy-update syntax error
// let f (r: {| A: int; C: int |}) = { r with A = 1; B = 2; C = 3 }
if isAnonRecdTy cenv.g overallTy || isStructAnonRecdTy cenv.g overallTy then
for fld, _ in flds do
let _, fldId = fld
match TryFindAnonRecdFieldOfType g overallTy fldId.idText with
| Some item ->
CallNameResolutionSink cenv.tcSink (fldId.idRange, env.eNameResEnv, item, emptyTyparInst, ItemOccurence.UseInType, env.eAccessRights)
| None -> ()

match flds with
| [] -> []
| _ ->
match BuildFieldMap cenv env hasOrigExpr overallTy flds mWholeExpr with
| None -> []
| Some(tinst, tcref, _, fldsList) ->
try
let firstPartRange = mkRange mWholeExpr.FileName mWholeExpr.Start (mkPos mWholeExpr.StartLine (mWholeExpr.StartColumn + 1))
// Use the left { in the expression
error(Error(FSComp.SR.chkCopyUpdateSyntaxInAnonRecords(), firstPartRange))
with _ ->
// Use the right } in the expression
let lastPartRange = mkRange mWholeExpr.FileName (mkPos mWholeExpr.StartLine (mWholeExpr.EndColumn - 1)) (mkPos mWholeExpr.StartLine (mWholeExpr.EndColumn))
error(Error(FSComp.SR.chkCopyUpdateSyntaxInAnonRecords(), lastPartRange))
[]
else
// If the overall type is a record type build a map of the fields
match flds with
| [] -> []
| _ ->
match BuildFieldMap cenv env hasOrigExpr overallTy flds mWholeExpr with
| None -> []
| Some(tinst, tcref, _, fldsList) ->

let gtyp = mkAppTy tcref tinst
UnifyTypes cenv env mWholeExpr overallTy gtyp
let gtyp = mkAppTy tcref tinst
UnifyTypes cenv env mWholeExpr overallTy gtyp

[ for n, v in fldsList do
match v with
| Some v -> yield n, v
| None -> () ]
[ for n, v in fldsList do
match v with
| Some v -> yield n, v
| None -> () ]

let withExprInfoOpt =
match withExprOptChecked with
Expand Down
3 changes: 1 addition & 2 deletions src/Compiler/Checking/NameResolution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3685,8 +3685,7 @@ let ResolveFieldPrim sink (ncenv: NameResolver) nenv ad ty (mp, id: Ident) allFi
error(ErrorWithSuggestions(errorText, m, id.idText, suggestLabels))
else
lookup()
| _ ->
lookup()
| ValueNone -> lookup()
| _ ->
let lid = (mp@[id])
let tyconSearch ad () =
Expand Down
3 changes: 2 additions & 1 deletion src/Compiler/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1710,4 +1710,5 @@ featureAccessorFunctionShorthand,"underscore dot shorthand for accessor only fun
3569,chkNotTailRecursive,"The member or function '%s' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way."
3570,tcStaticBindingInExtrinsicAugmentation,"Static bindings cannot be added to extrinsic augmentations. Consider using a 'static member' instead."
3571,pickleFsharpCoreBackwardsCompatible,"Newly added pickle state cannot be used in FSharp.Core, since it must be working in older compilers+tooling as well. The time window is at least 3 years after feature introduction. Violation: %s . Context: \n %s "
3577,tcOverrideUsesMultipleArgumentsInsteadOfTuple,"This override takes a tuple instead of multiple arguments. Try to add an additional layer of parentheses at the method definition (e.g. 'member _.Foo((x, y))'), or remove parentheses at the abstract method declaration (e.g. 'abstract member Foo: 'a * 'b -> 'c')."
3577,tcOverrideUsesMultipleArgumentsInsteadOfTuple,"This override takes a tuple instead of multiple arguments. Try to add an additional layer of parentheses at the method definition (e.g. 'member _.Foo((x, y))'), or remove parentheses at the abstract method declaration (e.g. 'abstract member Foo: 'a * 'b -> 'c')."
3578,chkCopyUpdateSyntaxInAnonRecords,"This expression is an anonymous record, use {{|...|}} instead of {{...}}."
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.zh-Hans.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.zh-Hant.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ module AnonRecd =
|> shouldFail
|> withErrorCode 3522
|> withMessage "The field 'A' appears multiple times in this record expression."


[<Fact>]
let ``Anonymous Records incomplete`` () =
Fsx """
let x () : {| A: int; B: string |} = {| A = 123 |}
"""
|> compile
|> shouldFail
|> withDiagnostics [
(Error 1, Line 2, Col 40, Line 2, Col 53, "This anonymous record does not have enough fields. Add the missing fields [B].")
0101 marked this conversation as resolved.
Show resolved Hide resolved
]

[<Fact>]
let ``Anonymous Records with duplicate labels - Copy and update expression`` () =
FSharp """
Expand Down Expand Up @@ -65,7 +76,57 @@ type ErrorResponse =
Error 10, Line 7, Col 12, Line 7, Col 14, "Unexpected symbol '|}' in field declaration. Expected identifier or other token."
Error 10, Line 10, Col 17, Line 10, Col 21, "Incomplete structured construct at or before this point in field declaration. Expected identifier or other token."
]

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

let t3 (t1: {| gu: string; ff: int |}) = { t1 with ff = 3 }
"""
|> compile
|> shouldFail
|> withDiagnostics [
(Error 3578, Line 4, Col 42, Line 4, Col 43, "This expression is an anonymous record, use {|...|} instead of {...}.")
(Error 3578, Line 4, Col 59, Line 4, Col 60, "This expression is an anonymous record, use {|...|} instead of {...}.")
]

[<Fact>]
let ``This expression was expected to have an anonymous Record but has a record`` () =
Fsx """
let t3 (t1: {| gu: string; ff: int |}) = { t1 with ff = 3 }
"""
|> compile
|> shouldFail
|> withDiagnostics [
(Error 3578, Line 2, Col 42, Line 2, Col 43, "This expression is an anonymous record, use {|...|} instead of {...}.")
(Error 3578, Line 2, Col 59, Line 2, Col 60, "This expression is an anonymous record, use {|...|} instead of {...}.")
]

[<Fact>]
let ``This expression was expected to have an struct anonymous Record but has a record`` () =
Fsx """
let t3 (t1: struct {| gu: string; ff: int |}) = { t1 with ff = 3 }
"""
|> compile
|> shouldFail
|> withDiagnostics [
(Error 3578, Line 2, Col 49, Line 2, Col 50, "This expression is an anonymous record, use {|...|} instead of {...}.")
(Error 3578, Line 2, Col 66, Line 2, Col 67, "This expression is an anonymous record, use {|...|} instead of {...}.")
]

[<Fact>]
let ``This expression was expected to have an anonymous with various properties Record but has a record`` () =
Fsx """
let f (r: {| A: int; C: int |}) = { r with A = 1; B = 2; C = 3 }
"""
|> compile
|> shouldFail
|> withDiagnostics [
(Error 3578, Line 2, Col 35, Line 2, Col 36, "This expression is an anonymous record, use {|...|} instead of {...}.")
(Error 3578, Line 2, Col 64, Line 2, Col 65, "This expression is an anonymous record, use {|...|} instead of {...}.")
]

[<Fact>]
let ``Nested anonymous records where outer label = concatenated inner labels (see secondary issue reported in 6411)`` () =
FSharp """
Expand All @@ -75,16 +136,3 @@ let x = {| abcd = {| ab = 4; cd = 1 |} |}
"""
|> compile
|> shouldSucceed

[<Fact>]
let ``Wrong update syntax`` () =
Fsx """
let f (r: {| A: int |}) =
{ r with A = 1 }
"""
|> ignoreWarnings
|> compile
|> shouldFail
|> withDiagnostics [
(Error 39, Line 3, Col 14, Line 3, Col 15, "The record label 'A' is not defined.")
]
Loading
Loading