-
Notifications
You must be signed in to change notification settings - Fork 790
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
[WIP] Nested Record Field Copy and Update Expression #4511
Closed
williamtetlow
wants to merge
51
commits into
dotnet:master
from
williamtetlow:nested-recd-update-recdexpr
Closed
Changes from 47 commits
Commits
Show all changes
51 commits
Select commit
Hold shift + click to select a range
f2f23a0
no message
williamtetlow 0f1a8fa
convert nested record fields to correct ast in TcRecdExpr - copyInfo …
williamtetlow e7520f9
WIP - TypeName.PropertyName now works for { person with Person.A = { …
williamtetlow a004c5a
got nested record field TypeName.PropertyName.PropertyName working
williamtetlow 6980070
fix ambiguities between TypeName.PropertyName and PropertyName.Proper…
williamtetlow a974cd7
wip
williamtetlow 9e54406
added Module/Namespace.TypeName.FieldName resolution. [WIP] need to a…
williamtetlow dc792d3
remove comments
williamtetlow 3eb2b23
Merge pull request #1 from williamtetlow/nested-recd-module-res
williamtetlow a05aa22
fix error
AviAvni 8ae92d2
Merge branch 'master' into nested-recd-update-recdexpr
AviAvni 413672d
resolve nested module and namespace access
williamtetlow c160937
search whole list of module or namespace refs returned
williamtetlow ba2492a
Updated ModuleOrNamespace search to handle Namespace.Module.FieldName…
williamtetlow 59975e0
search abbreviated type fields
williamtetlow 85b43bb
[WIP] Add copy info so nested fields not referenced in nested express…
williamtetlow e4b3cc1
added basic conformance test for single update with varying levels of…
williamtetlow b8fc206
Merge branch 'master' of https://github.com/williamtetlow/visualfshar…
williamtetlow dc0bf4d
fix long ident range to be the total range of longident
williamtetlow 79d141b
fix TypeName.Fieldname & NamespaceOrModule.FieldName copyInfo to only…
williamtetlow 8597c01
first pass of multi updates
williamtetlow 8911432
refactor module or namespace search
williamtetlow 4edaee3
WIP refactoring code to fix ModuleName.TypeName.FieldName.FieldName
williamtetlow 8fa2ec3
fix ModuleOrNamespace.TypeName.FieldName.FieldName
williamtetlow 1ec29b6
simplify expanding AST
williamtetlow 5f4bc72
refactoring
williamtetlow 5b287f8
use active pattern throughout
williamtetlow 5a17d31
more tidying up
williamtetlow 9d45340
module and namespace test
williamtetlow 295df45
Merge branch 'master' of https://github.com/williamtetlow/visualfshar…
williamtetlow 0141e9e
Merge branch 'nested-recd-update-recdexpr' of https://github.com/will…
williamtetlow 685ac8d
adding conformance tests
williamtetlow 08416a4
Merge branch 'master' into nested-recd-update-recdexpr
williamtetlow 990792c
Merge branch 'nested-recd-update-recdexpr' into nestd-recd-refactoring
williamtetlow efc1e19
fixing conformance tests
williamtetlow 98d610f
Merge pull request #2 from williamtetlow/nestd-recd-refactoring
williamtetlow 0d6c454
moving lid res to NameResolution module
williamtetlow 45780fd
added conformance test for Type vs Field ambiguities
williamtetlow fdb0b01
moved resolution of lid representing nested field access to NameResol…
williamtetlow 8498ba8
fixing issues from moving resolution code to NameResolution module
williamtetlow ab70071
Merge pull request #3 from williamtetlow/nestd-recd-refactoring
williamtetlow 03f5b22
add missing exit to conformance tests
williamtetlow b5cb6af
Merge branch 'master' into nested-recd-update-recdexpr
williamtetlow 33d7990
fixes to conformance tests
williamtetlow 3a366af
make id used not the recd field reference
williamtetlow 1207879
Check the same field is not declared twice in a nested field update
brokenprogrammer 9f79a3b
Merge branch 'master' of https://github.com/williamtetlow/visualfshar…
williamtetlow 35568d8
Merge branch 'master' into nested-recd-update-recdexpr
williamtetlow 9dfc288
resolve issues from feedback
williamtetlow 5af5fae
Merge branch 'nested-recd-update-recdexpr' of https://github.com/will…
williamtetlow a5c0b09
missed update to solution file
williamtetlow File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6898,10 +6898,85 @@ and TcAssertExpr cenv overallTy env (m:range) tpenv x = | |
//------------------------------------------------------------------------- | ||
|
||
and TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr) = | ||
let buildForNestdFlds (lidwd : LongIdentWithDots) v = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think throwing a couple of chars saves a lot of space in this case. Why not |
||
let recdExprCopyInfo ids (optOrigExpr : (SynExpr * BlockSeparator) option) (id : Ident) = | ||
let upToId origSepRng id lidwd = | ||
let rec buildLid res (id : Ident) = | ||
function | ||
| [] -> res | ||
| (h : Ident) :: t -> if h.idText = id.idText then h :: res else buildLid (h :: res) id t | ||
|
||
let rec combineIds = | ||
function | ||
| [] | [_] -> [] | ||
| id1::id2::rest -> (id1, id2) :: (id2 :: rest |> combineIds) | ||
|
||
let calcLidSeparatorRanges lid = | ||
match lid with | ||
| [] | [_] -> [origSepRng] | ||
| _ :: t -> origSepRng :: List.map (fun (s : Ident, e : Ident) -> mkRange s.idRange.FileName s.idRange.End e.idRange.Start) t | ||
|
||
let lid = buildLid [] id lidwd |> List.rev | ||
|
||
(lid, lid |> combineIds |> calcLidSeparatorRanges) | ||
|
||
let totalRange (origId : Ident) (id : Ident) = | ||
mkRange origId.idRange.FileName origId.idRange.End id.idRange.Start | ||
|
||
match optOrigExpr with | ||
| Some (SynExpr.Ident origId, (sepRange, _)) -> | ||
let lid, rng = upToId sepRange id (origId :: ids) | ||
Some (SynExpr.LongIdent (false, LongIdentWithDots(lid, rng), None, totalRange origId id), (id.idRange, None)) // TODO: id.idRange should be the range of the next separator | ||
| _ -> None | ||
|
||
|
||
let rec synExprRecd copyInfo id flds = | ||
Some(SynExpr.Record((None, (copyInfo id), [ match flds with | ||
| [] -> yield ((LongIdentWithDots ([], []), true), v, None) | ||
| [fldId] -> yield ((LongIdentWithDots ([fldId],[]), true), v, None) | ||
| fldId :: rest -> | ||
let nestedFld = synExprRecd copyInfo fldId | ||
yield ((LongIdentWithDots ([fldId], []), true), nestedFld rest, None)], id.idRange))) | ||
|
||
let access, flds = lidwd.Lid |> ResolveNestedField cenv.tcSink cenv.nameResolver env.eNameResEnv env.eAccessRights overallTy | ||
|
||
let expanded = | ||
[ | ||
match (access, flds) with | ||
| [], [] -> () | ||
| accessIds, [] -> yield (accessIds |> List.frontAndBack), v | ||
| accessIds, [fldId] -> yield ((accessIds@[fldId]) |> List.frontAndBack), v | ||
| accessIds, fldId :: rest -> | ||
yield (accessIds, fldId), synExprRecd (recdExprCopyInfo flds optOrigExpr) fldId rest | ||
] | ||
|
||
expanded | ||
|
||
let reduceNstdUpdates flds = | ||
let grpdByFld = flds |> List.groupBy (fun ((_, fld : Ident), _) -> fld.idText) | ||
[ | ||
for (_, flds) in grpdByFld do | ||
if (flds |> List.length < 2) then | ||
yield! flds | ||
else | ||
let rec grpIfNstd res xs = | ||
match xs with | ||
| [] -> res | ||
| x::[] -> x :: res | ||
| x::y::ys -> match x, y with | ||
| (lidwid, Some(SynExpr.Record (aBI, aCI, aFlds, aRng))), (_, Some(SynExpr.Record (_, _, bFlds, _))) -> | ||
let combinedFlds = aFlds @ bFlds | ||
let reducedRecd = (lidwid, Some(SynExpr.Record (aBI, aCI, combinedFlds, aRng))) | ||
grpIfNstd (reducedRecd :: res) ys | ||
| _ -> grpIfNstd (x :: res) (y :: ys) | ||
|
||
yield! flds |> grpIfNstd [] | ||
] | ||
|
||
let requiresCtor = (GetCtorShapeCounter env = 1) // Get special expression forms for constructors | ||
let haveCtor = Option.isSome inherits | ||
|
||
|
||
let optOrigExprInfo, tpenv = | ||
match optOrigExpr with | ||
| None -> None, tpenv | ||
|
@@ -6915,7 +6990,7 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr | |
|
||
let hasOrigExpr = optOrigExprInfo.IsSome | ||
|
||
let fldsList = | ||
let fldsList = | ||
let flds = | ||
[ | ||
// if we met at least one field that is not syntactically correct - raise ReportedError to transfer control to the recovery routine | ||
|
@@ -6925,9 +7000,12 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr | |
// we assume that parse errors were already reported | ||
raise (ReportedError None) | ||
|
||
yield (List.frontAndBack lidwd.Lid, v) | ||
] | ||
|
||
match lidwd.Lid with | ||
| [] -> () | ||
| [id] -> yield (([], id), v) | ||
| _ -> yield! buildForNestdFlds lidwd v | ||
] |> reduceNstdUpdates | ||
|
||
match flds with | ||
| [] -> [] | ||
| _ -> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
...ce/Conformance/BasicTypeAndModuleDefinitions/RecordTypes/E_NestedUpdateRecordCloning01.fs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// #Regression #Conformance #TypesAndModules #Records | ||
// Verify same field cannot be declared twice in a nested field update | ||
//<Expects id="FS0668" status="error">The field 'A' appears twice in this record expression or pattern</Expects> | ||
#light | ||
|
||
type AnotherNestedRecTy = { A : int; } | ||
|
||
type NestdRecTy = { B : string; C : AnotherNestedRecTy; } | ||
|
||
type RecTy = { D : NestdRecTy; E : string option; } | ||
|
||
let t1 = { D = { B = "t1"; C = { A = 1; } }; E = None; } | ||
|
||
let t2 = { t1 with D.C.A = 3; D.C.A = 2} |
30 changes: 30 additions & 0 deletions
30
...urce/Conformance/BasicTypeAndModuleDefinitions/RecordTypes/NestedUpdateRecordCloning01.fs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// #Conformance #TypesAndModules #Records | ||
#light | ||
|
||
// Verify cloning and updating of fields using nested copy and update syntax | ||
|
||
type AnotherNestedRecTy = { A : int; } | ||
|
||
type NestdRecTy = { B : string; C : AnotherNestedRecTy; } | ||
|
||
type RecTy = { D : NestdRecTy; E : string option; } | ||
|
||
let t1 = { D = { B = "t1"; C = { A = 1; } }; E = None; } | ||
|
||
let t2 = { t1 with D.B = "t2" } | ||
|
||
let t3 = { t2 with D.C.A = 3 } | ||
|
||
// Changed fields t1 to t2 | ||
if t1.D.B <> "t1" || t2.D.B <> "t2" then exit 1 | ||
|
||
// Fields cloned t1 to t2 | ||
if t1.E <> t2.E || t1.D.C <> t2.D.C then exit 1 | ||
|
||
// Changed fields t2 to t3 | ||
if t2.D.C.A <> 1 || t3.D.C.A <> 3 then exit 1 | ||
|
||
// Fields cloned t2 to t3 | ||
if t2.E <> t3.E || t2.D.B <> t3.D.B then exit 1 | ||
|
||
exit 0 |
31 changes: 31 additions & 0 deletions
31
...urce/Conformance/BasicTypeAndModuleDefinitions/RecordTypes/NestedUpdateRecordCloning02.fs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// #Conformance #TypesAndModules #Records | ||
#light | ||
|
||
// Verify cloning and updating of fields accessed through TypeName using nested copy and update syntax | ||
|
||
type AnotherNestedRecTy = { A : int; } | ||
|
||
type NestdRecTy = { B : string; C : AnotherNestedRecTy; } | ||
|
||
type RecTy = { D : NestdRecTy; E : string option; } | ||
|
||
let t1 = { D = { B = "t1"; C = { A = 1; } }; E = None; } | ||
|
||
// TypeName.FieldName access | ||
let t2 = { t1 with RecTy.D.B = "t2"; } | ||
|
||
let t3 = { t2 with RecTy.D.B = "t3"; RecTy.D.C.A = 3; } | ||
|
||
// Changed Fields t1 to t2 | ||
if t1.D.B <> "t1" || t2.D.B <> "t2" then exit 1 | ||
|
||
// Fields Cloned t1 to t2 | ||
if t2.D.C.A <> t1.D.C.A || t2.E <> t1.E then exit 1 | ||
|
||
// Changed Fields t2 to t3 | ||
if t3.D.B <> "t3" || t2.D.C.A <> 1 || t3.D.C.A <> 3 then exit 1 | ||
|
||
// Fields Cloned t2 to t3 | ||
if t3.E <> t2.E then exit 1 | ||
|
||
exit 0 |
32 changes: 32 additions & 0 deletions
32
...urce/Conformance/BasicTypeAndModuleDefinitions/RecordTypes/NestedUpdateRecordCloning03.fs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// #Conformance #TypesAndModules #Records | ||
#light | ||
|
||
// Verify cloning and updating of fields with ambiguities between TypeName and FieldName using nested copy and update syntax | ||
|
||
type AnotherNestedRecTy = { A : int; } | ||
|
||
type NestdRecTy = { B : string; AnotherNestedRecTy : AnotherNestedRecTy; } | ||
|
||
type RecTy = { NestdRecTy : NestdRecTy; E : string option; } | ||
|
||
|
||
let t1 = { RecTy.NestdRecTy = { B = "t1"; AnotherNestedRecTy = { A = 1; } }; E = None; } | ||
|
||
// Ambiguous access | ||
let t2 = { t1 with NestdRecTy.B = "t2" } | ||
|
||
let t3 = { t2 with NestdRecTy.AnotherNestedRecTy.A = 3 } | ||
|
||
// Changed Fields t1 to t2 | ||
if t1.NestdRecTy.B <> "t1" || t2.NestdRecTy.B <> "t2" then exit 1 | ||
|
||
// Fields Cloned t1 to t2 | ||
if t2.E <> t1.E || t2.NestdRecTy.AnotherNestedRecTy.A <> t1.NestdRecTy.AnotherNestedRecTy.A then exit 1 | ||
|
||
// Changed Fields t2 to t3 | ||
if t3.NestdRecTy.AnotherNestedRecTy.A <> 3 then exit 1 | ||
|
||
// Fields Cloned t2 to t3 | ||
if t3.E <> t2.E || t3.NestdRecTy.B <> t2.NestdRecTy.B then exit 1 | ||
|
||
exit 0 |
34 changes: 34 additions & 0 deletions
34
...urce/Conformance/BasicTypeAndModuleDefinitions/RecordTypes/NestedUpdateRecordCloning04.fs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// #Conformance #TypesAndModules #Records | ||
#light | ||
|
||
// Verify cloning and updating of fields accessed through ModuleName using nested copy and update syntax | ||
module Test = | ||
module M = | ||
type AnotherNestedRecTy = { A : int; } | ||
|
||
type NestdRecTy = { B : string; C : AnotherNestedRecTy; } | ||
|
||
type RecTy = { D : NestdRecTy; E : string option; } | ||
|
||
|
||
let t1 = { M.RecTy.D = { M.B = "t1"; M.C = { M.A = 1; } }; M.E = None; } | ||
|
||
// Module.FieldName access | ||
let t2 = { t1 with M.D.B = "t2"; M.D.C.A = 2; } | ||
|
||
// Module.TypeName.FieldName access | ||
let t3 = { t2 with M.RecTy.E = Some "t3"; M.RecTy.D.B = "t3"; } | ||
|
||
// Changed Fields t1 to t2 | ||
if t1.D.B <> "t1" || t2.D.B <> "t2" || t2.D.C.A <> 2 || t1.D.C.A <> 1 then exit 1 | ||
|
||
// Fields Cloned t1 to t2 | ||
if t2.E <> t1.E then exit 1 | ||
|
||
// Changed Fields t2 to t3 | ||
if t2.E <> None || t3.E <> Some "t3" || t3.D.B <> "t3" then exit 1 | ||
|
||
// Fields Cloned t2 to t3 | ||
if t3.D.C <> t2.D.C then exit 1 | ||
|
||
exit 0 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not
Map.tryFind
with match?