diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/sem.nim | 34 | ||||
-rw-r--r-- | compiler/semmagic.nim | 4 | ||||
-rw-r--r-- | compiler/semobjconstr.nim | 13 |
3 files changed, 32 insertions, 19 deletions
diff --git a/compiler/sem.nim b/compiler/sem.nim index f92853d9e..3324da55c 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -553,17 +553,17 @@ proc pickCaseBranchIndex(caseExpr, matched: PNode): int = if endsWithElse: return caseExpr.len - 1 -proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] -proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode -proc defaultNodeField(c: PContext, a: PNode): PNode +proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault: bool): seq[PNode] +proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): PNode +proc defaultNodeField(c: PContext, a: PNode, checkDefault: bool): PNode const defaultFieldsSkipTypes = {tyGenericInst, tyAlias, tySink} -proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): seq[PNode] = +proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool, checkDefault: bool): seq[PNode] = case recNode.kind of nkRecList: for field in recNode: - result.add defaultFieldsForTuple(c, field, hasDefault) + result.add defaultFieldsForTuple(c, field, hasDefault, checkDefault) of nkSym: let field = recNode.sym let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes) @@ -572,7 +572,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s result.add newTree(nkExprColonExpr, recNode, field.ast) else: if recType.kind in {tyObject, tyArray, tyTuple}: - let asgnExpr = defaultNodeField(c, recNode, recNode.typ) + let asgnExpr = defaultNodeField(c, recNode, recNode.typ, checkDefault) if asgnExpr != nil: hasDefault = true asgnExpr.flags.incl nfSkipFieldChecking @@ -591,11 +591,11 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s else: doAssert false -proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = +proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault: bool): seq[PNode] = case recNode.kind of nkRecList: for field in recNode: - result.add defaultFieldsForTheUninitialized(c, field) + result.add defaultFieldsForTheUninitialized(c, field, checkDefault) of nkRecCase: let discriminator = recNode[0] var selectedBranch: int @@ -604,19 +604,21 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = # None of the branches were explicitly selected by the user and no value # was given to the discrimator. We can assume that it will be initialized # to zero and this will select a particular branch as a result: + if checkDefault: # don't add defaults when checking whether a case branch has default fields + return defaultValue = newIntNode(nkIntLit#[c.graph]#, 0) defaultValue.typ = discriminator.typ selectedBranch = recNode.pickCaseBranchIndex defaultValue defaultValue.flags.incl nfSkipFieldChecking result.add newTree(nkExprColonExpr, discriminator, defaultValue) - result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1]) + result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1], checkDefault) of nkSym: let field = recNode.sym let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes) if field.ast != nil: #Try to use default value result.add newTree(nkExprColonExpr, recNode, field.ast) elif recType.kind in {tyObject, tyArray, tyTuple}: - let asgnExpr = defaultNodeField(c, recNode, recNode.typ) + let asgnExpr = defaultNodeField(c, recNode, recNode.typ, checkDefault) if asgnExpr != nil: asgnExpr.typ = recNode.typ asgnExpr.flags.incl nfSkipFieldChecking @@ -624,17 +626,17 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = else: doAssert false -proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode = +proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): PNode = let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes) if aTypSkip.kind == tyObject: - let child = defaultFieldsForTheUninitialized(c, aTypSkip.n) + let child = defaultFieldsForTheUninitialized(c, aTypSkip.n, checkDefault) if child.len > 0: var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTyp)) asgnExpr.typ = aTyp asgnExpr.sons.add child result = semExpr(c, asgnExpr) elif aTypSkip.kind == tyArray: - let child = defaultNodeField(c, a, aTypSkip[1]) + let child = defaultNodeField(c, a, aTypSkip[1], checkDefault) if child != nil: let node = newNode(nkIntLit) @@ -647,15 +649,15 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode = elif aTypSkip.kind == tyTuple: var hasDefault = false if aTypSkip.n != nil: - let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault) + let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault, checkDefault) if hasDefault and children.len > 0: result = newNodeI(nkTupleConstr, a.info) result.typ = aTyp result.sons.add children result = semExpr(c, result) -proc defaultNodeField(c: PContext, a: PNode): PNode = - result = defaultNodeField(c, a, a.typ) +proc defaultNodeField(c: PContext, a: PNode, checkDefault: bool): PNode = + result = defaultNodeField(c, a, a.typ, checkDefault) include semtempl, semgnrc, semstmts, semexprs diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index f94d8dc33..ad7e9821b 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -21,7 +21,7 @@ proc addDefaultFieldForNew(c: PContext, n: PNode): PNode = asgnExpr.typ = typ var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0] while true: - asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n) + asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n, false) let base = t[0] if base == nil: break @@ -647,7 +647,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, of mDefault: result = checkDefault(c, n) let typ = result[^1].typ.skipTypes({tyTypeDesc}) - let defaultExpr = defaultNodeField(c, result[^1], typ) + let defaultExpr = defaultNodeField(c, result[^1], typ, false) if defaultExpr != nil: result = defaultExpr of mZeroDefault: diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index d4eba2112..9b17676ee 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -21,6 +21,7 @@ type # set this to true while visiting # parent types. missingFields: seq[PSym] # Fields that the user failed to specify + checkDefault: bool # Checking defaults InitStatus = enum # This indicates the result of object construction initUnknown @@ -342,6 +343,16 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, # All bets are off. If any of the branches has a mandatory # fields we must produce an error: for i in 1..<n.len: + let branchNode = n[i] + if branchNode != nil: + let oldCheckDefault = constrCtx.checkDefault + constrCtx.checkDefault = true + let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags) + constrCtx.checkDefault = oldCheckDefault + if len(defaults) > 0: + localError(c.config, discriminatorVal.info, "branch initialization " & + "with a runtime discriminator is not supported " & + "for a branch whose fields have default values.") discard collectMissingCaseFields(c, n[i], constrCtx, @[]) of nkSym: let field = n.sym @@ -353,7 +364,7 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, result.defaults.add newTree(nkExprColonExpr, n, field.ast) else: if efWantNoDefaults notin flags: # cannot compute defaults at the typeRightPass - let defaultExpr = defaultNodeField(c, n) + let defaultExpr = defaultNodeField(c, n, constrCtx.checkDefault) if defaultExpr != nil: result.status = initUnknown result.defaults.add newTree(nkExprColonExpr, n, defaultExpr) |