diff options
author | ringabout <43030857+ringabout@users.noreply.github.com> | 2022-10-04 18:45:10 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-04 12:45:10 +0200 |
commit | f89ba2c951232fe7f82d211fe43f774e68563a73 (patch) | |
tree | 6ff5b198d40c501a20af953df362e7a654c3fb4f /compiler/semobjconstr.nim | |
parent | 6cf07271923a6c43d0ccaa0490c8a3d38ead678e (diff) | |
download | Nim-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.nim | 79 |
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 |