diff options
author | ringabout <43030857+ringabout@users.noreply.github.com> | 2023-01-18 18:52:18 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-18 11:52:18 +0100 |
commit | fc35f83eee55610af3931f95771b6d1bce1fc845 (patch) | |
tree | ff4314e15cfb5405160c45a0afa67b9033de0be2 | |
parent | c4035d7f7c424caa81ee449d2032ecd8e8967ebd (diff) | |
download | Nim-fc35f83eee55610af3931f95771b6d1bce1fc845.tar.gz |
fixes #21260; add check for illegal recursion for defaults (#21270)
* fixes #21260; add check for illegal recursion for defaults * fixes differently
-rw-r--r-- | compiler/sem.nim | 36 | ||||
-rw-r--r-- | compiler/semdata.nim | 1 | ||||
-rw-r--r-- | compiler/semmagic.nim | 3 | ||||
-rw-r--r-- | compiler/semobjconstr.nim | 15 | ||||
-rw-r--r-- | tests/types/t21260.nim | 13 |
5 files changed, 38 insertions, 30 deletions
diff --git a/compiler/sem.nim b/compiler/sem.nim index f5283fa3d..c1bb89fc8 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -550,18 +550,17 @@ proc pickCaseBranchIndex(caseExpr, matched: PNode): int = if endsWithElse: return caseExpr.len - 1 -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 defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode +proc defaultNodeField(c: PContext, a: PNode): PNode const defaultFieldsSkipTypes = {tyGenericInst, tyAlias, tySink} -proc defaultFieldsForTuple(c: PContext, recNode: PNode, id: var IntSet, hasDefault: var bool): seq[PNode] = +proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): seq[PNode] = case recNode.kind of nkRecList: for field in recNode: - result.add defaultFieldsForTuple(c, field, id, hasDefault) + result.add defaultFieldsForTuple(c, field, hasDefault) of nkSym: let field = recNode.sym let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes) @@ -570,7 +569,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, id: var IntSet, hasDefau result.add newTree(nkExprColonExpr, recNode, field.ast) else: if recType.kind in {tyObject, tyArray, tyTuple}: - let asgnExpr = defaultNodeField(c, recNode, recNode.typ, id) + let asgnExpr = defaultNodeField(c, recNode, recNode.typ) if asgnExpr != nil: hasDefault = true asgnExpr.flags.incl nfUseDefaultField @@ -589,11 +588,11 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, id: var IntSet, hasDefau else: doAssert false -proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, id: var IntSet): seq[PNode] = +proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = case recNode.kind of nkRecList: for field in recNode: - result.add defaultFieldsForTheUninitialized(c, field, id) + result.add defaultFieldsForTheUninitialized(c, field) of nkRecCase: let discriminator = recNode[0] var selectedBranch: int @@ -607,14 +606,14 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, id: var IntSe selectedBranch = recNode.pickCaseBranchIndex defaultValue defaultValue.flags.incl nfUseDefaultField result.add newTree(nkExprColonExpr, discriminator, defaultValue) - result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1], id) + result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1]) 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, recType, id) + let asgnExpr = defaultNodeField(c, recNode, recType) if asgnExpr != nil: asgnExpr.typ = recType asgnExpr.flags.incl nfUseDefaultField @@ -622,19 +621,17 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, id: var IntSe else: doAssert false -proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, id: var IntSet): PNode = +proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode = let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes) if aTypSkip.kind == tyObject: - if id.containsOrIncl(aTypSkip.id): - return - let child = defaultFieldsForTheUninitialized(c, aTypSkip.n, id) + let child = defaultFieldsForTheUninitialized(c, aTypSkip.n) if child.len > 0: 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], id) + let child = defaultNodeField(c, a, aTypSkip[1]) if child != nil: let node = newNode(nkIntLit) @@ -647,20 +644,15 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, id: var IntSet): PNode elif aTypSkip.kind == tyTuple: var hasDefault = false if aTypSkip.n != nil: - let children = defaultFieldsForTuple(c, aTypSkip.n, id, hasDefault) + let children = defaultFieldsForTuple(c, aTypSkip.n, 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 = - var s = initIntSet() - result = defaultNodeField(c, a, a.typ, s) + result = defaultNodeField(c, a, a.typ) include semtempl, semgnrc, semstmts, semexprs diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 29c2c139f..5b94cc770 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -75,6 +75,7 @@ type # overload resolution. efNoDiagnostics, efTypeAllowed # typeAllowed will be called after + efWantNoDefaults TExprFlags* = set[TExprFlag] diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 7025dc867..751ca8fe7 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -20,9 +20,8 @@ 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, id) + asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n) let base = t[0] if base == nil: break diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 206602677..15e53a639 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -326,10 +326,13 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, result.status = initUnknown result.defaults.add newTree(nkExprColonExpr, n, field.ast) else: - let defaultExpr = defaultNodeField(c, n) - if defaultExpr != nil: - result.status = initUnknown - result.defaults.add newTree(nkExprColonExpr, n, defaultExpr) + if efWantNoDefaults notin flags: # cannot compute defaults at the typeRightPass + let defaultExpr = defaultNodeField(c, n) + if defaultExpr != nil: + result.status = initUnknown + result.defaults.add newTree(nkExprColonExpr, n, defaultExpr) + else: + result.status = initNone else: result.status = initNone else: @@ -364,7 +367,7 @@ proc initConstrContext(t: PType, initExpr: PNode): ObjConstrContext = proc computeRequiresInit(c: PContext, t: PType): bool = assert t.kind == tyObject var constrCtx = initConstrContext(t, newNode(nkObjConstr)) - let initResult = semConstructTypeAux(c, constrCtx, {}) + let initResult = semConstructTypeAux(c, constrCtx, {efWantNoDefaults}) constrCtx.missingFields.len > 0 proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) = @@ -374,7 +377,7 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) = assert objType != nil if objType.kind == tyObject: var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info)) - let initResult = semConstructTypeAux(c, constrCtx, {}) + let initResult = semConstructTypeAux(c, constrCtx, {efWantNoDefaults}) if constrCtx.missingFields.len > 0: localError(c.config, info, "The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)]) diff --git a/tests/types/t21260.nim b/tests/types/t21260.nim new file mode 100644 index 000000000..90d6613c1 --- /dev/null +++ b/tests/types/t21260.nim @@ -0,0 +1,13 @@ +discard """ + errormsg: "illegal recursion in type 'Foo'" + line: 8 +""" + +type + Kind = enum kA, kB + Foo = object + case k: Kind: + of kA: + foo: Foo + of kB: + discard |