summary refs log tree commit diff stats
path: root/compiler/semobjconstr.nim
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2022-10-04 18:45:10 +0800
committerGitHub <noreply@github.com>2022-10-04 12:45:10 +0200
commitf89ba2c951232fe7f82d211fe43f774e68563a73 (patch)
tree6ff5b198d40c501a20af953df362e7a654c3fb4f /compiler/semobjconstr.nim
parent6cf07271923a6c43d0ccaa0490c8a3d38ead678e (diff)
downloadNim-f89ba2c951232fe7f82d211fe43f774e68563a73.tar.gz
add default field support for object in ARC/ORC (#20480)
* fresh start

* add cpp target

* add result support

* add nimPreviewRangeDefault

* reduce

* use orc

* refactor common parts

* add tuple support

* add testcase for tuple

* cleanup; fixes nimsuggest tests

* there is something wrong with cpp

* remove

* add support for seqs

* fixes style

* addd initial distinct support

* remove links

* typo

* fixes tuple defaults

* add rangedefault

* add cpp support

* fixes one more bugs

* add more hasDefaults

* fixes ordinal types

* add testcase for #16744

* add testcase for #3608

* fixes docgen

* small fix

* recursive

* fixes

* cleanup and remove tuple support

* fixes nimsuggest

* fixes generics procs

* refactor

* increases timeout

* refactor hasDefault

* zero default; disable i386

* add tuples back

* fixes bugs

* fixes tuple

* add more tests

* fix one more bug regarding tuples

* more tests and cleanup

* remove messy distinct types which must be initialized by original types

* add tests

* fixes zero default

* fixes grammar

* fixes tests

* fixes tests

* fixes tests

* fixes comments

* fixes and add testcase

* undo default values for results

Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com>
Diffstat (limited to 'compiler/semobjconstr.nim')
-rw-r--r--compiler/semobjconstr.nim79
1 files changed, 43 insertions, 36 deletions
diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim
index 77bd6b975..1463ba833 100644
--- a/compiler/semobjconstr.nim
+++ b/compiler/semobjconstr.nim
@@ -29,6 +29,10 @@ type
     initNone     # None of the fields have been initialized
     initConflict # Fields from different branches have been initialized
 
+
+proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
+                        flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]]
+
 proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) =
   case newStatus
   of initConflict:
@@ -72,7 +76,9 @@ proc semConstrField(c: PContext, flags: TExprFlags,
   let assignment = locateFieldInInitExpr(c, field, initExpr)
   if assignment != nil:
     if nfSem in assignment.flags: return assignment[1]
-    if not fieldVisible(c, field):
+    if nfUseDefaultField in assignment[1].flags:
+      discard
+    elif not fieldVisible(c, field):
       localError(c.config, initExpr.info,
         "the field '$1' is not accessible." % [field.name.s])
       return
@@ -85,15 +91,6 @@ proc semConstrField(c: PContext, flags: TExprFlags,
     assignment.flags.incl nfSem
     return initValue
 
-proc caseBranchMatchesExpr(branch, matched: PNode): bool =
-  for i in 0..<branch.len-1:
-    if branch[i].kind == nkRange:
-      if overlap(branch[i], matched): return true
-    elif exprStructuralEquivalent(branch[i], matched):
-      return true
-
-  return false
-
 proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
                 isStmtBranch: bool): IntSet =
   if caseNode[caseIdx].kind == nkOfBranch:
@@ -155,18 +152,14 @@ proc collectMissingFields(c: PContext, fieldsRecList: PNode,
       if assignment == nil:
         constrCtx.missingFields.add r.sym
 
-
-proc semConstructFields(c: PContext, n: PNode,
-                        constrCtx: var ObjConstrContext,
-                        flags: TExprFlags): InitStatus =
-  result = initUnknown
-
+proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
+                        flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
   case n.kind
   of nkRecList:
     for field in n:
-      let status = semConstructFields(c, field, constrCtx, flags)
-      mergeInitStatus(result, status)
-
+      let (subSt, subDf) = semConstructFields(c, field, constrCtx, flags)
+      result.status.mergeInitStatus subSt
+      result.defaults.add subDf
   of nkRecCase:
     template fieldsPresentInBranch(branchIdx: int): string =
       let branch = n[branchIdx]
@@ -184,9 +177,9 @@ proc semConstructFields(c: PContext, n: PNode,
 
     for i in 1..<n.len:
       let innerRecords = n[i][^1]
-      let status = semConstructFields(c, innerRecords, constrCtx, flags)
+      let (status, _) = semConstructFields(c, innerRecords, constrCtx, flags) # todo
       if status notin {initNone, initUnknown}:
-        mergeInitStatus(result, status)
+        result.status.mergeInitStatus status
         if selectedBranch != -1:
           let prevFields = fieldsPresentInBranch(selectedBranch)
           let currentFields = fieldsPresentInBranch(i)
@@ -194,7 +187,7 @@ proc semConstructFields(c: PContext, n: PNode,
             ("The fields '$1' and '$2' cannot be initialized together, " &
             "because they are from conflicting branches in the case object.") %
             [prevFields, currentFields])
-          result = initConflict
+          result.status = initConflict
         else:
           selectedBranch = i
 
@@ -206,7 +199,7 @@ proc semConstructFields(c: PContext, n: PNode,
             ("cannot prove that it's safe to initialize $1 with " &
             "the runtime value for the discriminator '$2' ") %
             [fields, discriminator.sym.name.s])
-        mergeInitStatus(result, initNone)
+        mergeInitStatus(result.status, initNone)
 
       template wrongBranchError(i) =
         if c.inUncheckedAssignSection == 0:
@@ -289,13 +282,16 @@ proc semConstructFields(c: PContext, n: PNode,
           else:
             wrongBranchError(failedBranch)
 
+      let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags)
+      result.defaults.add defaults
+
       # When a branch is selected with a partial match, some of the fields
       # that were not initialized may be mandatory. We must check for this:
-      if result == initPartial:
+      if result.status == initPartial:
         collectMissingFields branchNode
 
     else:
-      result = initNone
+      result.status = initNone
       let discriminatorVal = semConstrField(c, flags + {efPreferStatic},
                                             discriminator.sym,
                                             constrCtx.initExpr)
@@ -308,33 +304,41 @@ proc semConstructFields(c: PContext, n: PNode,
         let matchedBranch = n.pickCaseBranch defaultValue
         collectMissingFields matchedBranch
       else:
-        result = initPartial
+        result.status = initPartial
         if discriminatorVal.kind == nkIntLit:
           # When the discriminator is a compile-time value, we also know
           # which branch will be selected:
           let matchedBranch = n.pickCaseBranch discriminatorVal
-          if matchedBranch != nil: collectMissingFields matchedBranch
+          if matchedBranch != nil:
+            let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags)
+            result.defaults.add defaults
+            collectMissingFields matchedBranch
         else:
           # All bets are off. If any of the branches has a mandatory
           # fields we must produce an error:
           for i in 1..<n.len: collectMissingFields n[i]
-
   of nkSym:
     let field = n.sym
     let e = semConstrField(c, flags, field, constrCtx.initExpr)
-    result = if e != nil: initFull else: initNone
-
+    if e != nil:
+      result.status = initFull
+    elif field.ast != nil:
+      result.status = initUnknown
+      result.defaults.add newTree(nkExprColonExpr, n, field.ast)
+    else:
+      result.status = initNone
   else:
     internalAssert c.config, false
 
 proc semConstructTypeAux(c: PContext,
                          constrCtx: var ObjConstrContext,
-                         flags: TExprFlags): InitStatus =
-  result = initUnknown
+                         flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
+  result.status = initUnknown
   var t = constrCtx.typ
   while true:
-    let status = semConstructFields(c, t.n, constrCtx, flags)
-    mergeInitStatus(result, status)
+    let (status, defaults) = semConstructFields(c, t.n, constrCtx, flags)
+    result.status.mergeInitStatus status
+    result.defaults.add defaults
     if status in {initPartial, initNone, initUnknown}:
       collectMissingFields c, t.n, constrCtx
     let base = t[0]
@@ -378,7 +382,9 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
 proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
   var t = semTypeNode(c, n[0], nil)
   result = newNodeIT(nkObjConstr, n.info, t)
-  for child in n: result.add child
+  result.add newNodeIT(nkType, n.info, t) #This will contain the default values to be added in transf
+  for i in 1..<n.len:
+    result.add n[i]
 
   if t == nil:
     return localErrorNode(c, result, "object constructor needs an object type")
@@ -409,7 +415,8 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
   # field (if this is a case object, initialized fields in two different
   # branches will be reported as an error):
   var constrCtx = initConstrContext(t, result)
-  let initResult = semConstructTypeAux(c, constrCtx, flags)
+  let (initResult, defaults) = semConstructTypeAux(c, constrCtx, flags)
+  result[0].sons.add defaults
   var hasError = false # needed to split error detect/report for better msgs
 
   # It's possible that the object was not fully initialized while