diff options
author | ringabout <43030857+ringabout@users.noreply.github.com> | 2023-07-25 18:08:32 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-25 12:08:32 +0200 |
commit | 1c2ccfad08191e936fadd52450b53dfea105a34d (patch) | |
tree | d848422b5cd391db4efb14bf2a5b7db2307266df | |
parent | dce714b2598c41e36113a4339fb9fb14655bc090 (diff) | |
download | Nim-1c2ccfad08191e936fadd52450b53dfea105a34d.tar.gz |
fixes #22301; fixes #22324; rejects branch initialization with a runtime discriminator with defaults (#22303)
* fixes #22301; rejects branch initialization with a runtime discriminator with defaults * undefault nimPreviewRangeDefault * fixes tests * use oldCheckDefault
-rw-r--r-- | compiler/sem.nim | 34 | ||||
-rw-r--r-- | compiler/semmagic.nim | 4 | ||||
-rw-r--r-- | compiler/semobjconstr.nim | 13 | ||||
-rw-r--r-- | config/nim.cfg | 1 | ||||
-rw-r--r-- | tests/objects/t22301.nim | 17 | ||||
-rw-r--r-- | tests/system/tfielditerator.nim | 16 |
6 files changed, 64 insertions, 21 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) diff --git a/config/nim.cfg b/config/nim.cfg index efb058121..1470de780 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -21,7 +21,6 @@ cc = gcc #hint[XDeclaredButNotUsed]=off threads:on -define:nimPreviewRangeDefault # Examples of how to setup a cross-compiler: # Nim can target architectures and OSes different than the local host diff --git a/tests/objects/t22301.nim b/tests/objects/t22301.nim new file mode 100644 index 000000000..8746bf584 --- /dev/null +++ b/tests/objects/t22301.nim @@ -0,0 +1,17 @@ +discard """ + errormsg: "branch initialization with a runtime discriminator is not supported for a branch whose fields have default values." +""" + +# bug #22301 +type + Enum = enum A, B + Object = object + case a: Enum + of A: + integer: int = 200 + of B: + time: string + +let x = A +let s = Object(a: x) +echo s \ No newline at end of file diff --git a/tests/system/tfielditerator.nim b/tests/system/tfielditerator.nim index d1fbf02f9..7e063c6cf 100644 --- a/tests/system/tfielditerator.nim +++ b/tests/system/tfielditerator.nim @@ -109,4 +109,18 @@ block titerator2: echo key, ": ", val for val in fields(co): - echo val \ No newline at end of file + echo val + +block: + type + Enum = enum A, B + Object = object + case a: Enum + of A: + integer: int + of B: + time: string + + let x = A + let s = Object(a: x) + doAssert s.integer == 0 |