diff options
-rw-r--r-- | compiler/sem.nim | 39 | ||||
-rw-r--r-- | compiler/semmagic.nim | 3 | ||||
-rw-r--r-- | compiler/semobjconstr.nim | 7 | ||||
-rw-r--r-- | tests/objects/tobject_default_value.nim | 37 |
4 files changed, 66 insertions, 20 deletions
diff --git a/compiler/sem.nim b/compiler/sem.nim index 3c8ced6b8..25116f8d6 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -553,17 +553,18 @@ proc pickCaseBranchIndex(caseExpr, matched: PNode): int = if endsWithElse: return caseExpr.len - 1 -proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] +proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, id: var IntSet): seq[PNode] +proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, id: var IntSet): PNode proc defaultNodeField(c: PContext, a: PNode): PNode proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode const defaultFieldsSkipTypes = {tyGenericInst, tyAlias, tySink} -proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): seq[PNode] = +proc defaultFieldsForTuple(c: PContext, recNode: PNode, id: var IntSet, hasDefault: var bool): seq[PNode] = case recNode.kind of nkRecList: for field in recNode: - result.add defaultFieldsForTuple(c, field, hasDefault) + result.add defaultFieldsForTuple(c, field, id, hasDefault) of nkSym: let field = recNode.sym let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes) @@ -572,7 +573,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, id) if asgnExpr != nil: hasDefault = true asgnExpr.flags.incl nfUseDefaultField @@ -591,11 +592,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, id: var IntSet): seq[PNode] = case recNode.kind of nkRecList: for field in recNode: - result.add defaultFieldsForTheUninitialized(c, field) + result.add defaultFieldsForTheUninitialized(c, field, id) of nkRecCase: let discriminator = recNode[0] var selectedBranch: int @@ -609,31 +610,34 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = selectedBranch = recNode.pickCaseBranchIndex defaultValue defaultValue.flags.incl nfUseDefaultField result.add newTree(nkExprColonExpr, discriminator, defaultValue) - result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1]) + result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1], id) 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, recType, id) if asgnExpr != nil: + asgnExpr.typ = recType asgnExpr.flags.incl nfUseDefaultField result.add newTree(nkExprColonExpr, recNode, asgnExpr) else: doAssert false -proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode = +proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, id: var IntSet): PNode = let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes) if aTypSkip.kind == tyObject: - let child = defaultFieldsForTheUninitialized(c, aTyp.skipTypes(defaultFieldsSkipTypes).n) + if id.containsOrIncl(aTypSkip.id): + return + let child = defaultFieldsForTheUninitialized(c, aTypSkip.n, id) if child.len > 0: - var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTyp)) - asgnExpr.typ = aTyp + var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTypSkip)) + asgnExpr.typ = aTypSkip 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], id) if child != nil: let node = newNode(nkIntLit) @@ -646,15 +650,20 @@ 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, id, hasDefault) 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, aTyp: PType): PNode = + var s = initIntSet() + defaultNodeField(c, a, aTyp, s) + proc defaultNodeField(c: PContext, a: PNode): PNode = - result = defaultNodeField(c, a, a.typ) + var s = initIntSet() + result = defaultNodeField(c, a, a.typ, s) include semtempl, semgnrc, semstmts, semexprs diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 751ca8fe7..7025dc867 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -20,8 +20,9 @@ proc addDefaultFieldForNew(c: PContext, n: PNode): PNode = var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[1].info, typ)) asgnExpr.typ = typ var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0] + var id = initIntSet() while true: - asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n) + asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n, id) let base = t[0] if base == nil: break diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 1463ba833..7f76dbee9 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -326,7 +326,12 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, result.status = initUnknown result.defaults.add newTree(nkExprColonExpr, n, field.ast) else: - result.status = initNone + let defaultExpr = defaultNodeField(c, n) + if defaultExpr != nil: + result.status = initUnknown + result.defaults.add newTree(nkExprColonExpr, n, defaultExpr) + else: + result.status = initNone else: internalAssert c.config, false diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim index 789571bbf..7ea4b42ae 100644 --- a/tests/objects/tobject_default_value.nim +++ b/tests/objects/tobject_default_value.nim @@ -3,7 +3,7 @@ discard """ targets: "c cpp js" """ -import std/[times, tables, macros] +import std/[times, macros] type Guess = object @@ -27,6 +27,10 @@ import mobject_default_value block: let x = Default() doAssert x.se == 0'i32 + +block: + let x = default(Default) + doAssert x.se == 0'i32 # echo Default(poi: 12) # echo Default(poi: 17) @@ -120,6 +124,19 @@ template main {.dirty.} = doAssert rVal == 0 # it should be 1 doAssert objVal.r == 1 + block: # bug #16744 + type + R = range[1..10] + Obj = object + r: R + + var + rVal: R = default(R) # Works fine + objVal = Obj() + + doAssert rVal == 0 # it should be 1 + doAssert objVal.r == 1 + block: # bug #3608 type abc = ref object @@ -148,6 +165,9 @@ template main {.dirty.} = let y = ObjectBaseDistinct(default(ObjectBase)) doAssert ObjectBase(y).value == 12 + let m = ObjectBaseDistinct(ObjectBase()) + doAssert ObjectBase(m).value == 12 + proc hello(): ObjectBaseDistinct = result = ObjectBaseDistinct(default(ObjectBase)) @@ -193,12 +213,24 @@ template main {.dirty.} = doAssert x.name.scale == 1 block: + let x = Object2() + doAssert x.name.value == 12 + doAssert x.name.time == 1.2 + doAssert x.name.scale == 1 + + block: var x: ref Object2 new x doAssert x[] == default(Object2) block: - var x = default(Object3) # todo Object3() ? + var x = default(Object3) + doAssert x.obj.name.value == 12 + doAssert x.obj.name.time == 1.2 + doAssert x.obj.name.scale == 1 + + block: + var x = Object3() doAssert x.obj.name.value == 12 doAssert x.obj.name.time == 1.2 doAssert x.obj.name.scale == 1 @@ -275,7 +307,6 @@ template main {.dirty.} = doAssert y.time == 1.2 doAssert y.scale == 1 - block: var x: PrellDeque[int] doAssert x.pendingTasks == 0 |