mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-11 22:08:54 +00:00
* fixes #21260; add check for illegal recursion for defaults * fixes differently
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ type
|
||||
# overload resolution.
|
||||
efNoDiagnostics,
|
||||
efTypeAllowed # typeAllowed will be called after
|
||||
efWantNoDefaults
|
||||
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)])
|
||||
|
||||
13
tests/types/t21260.nim
Normal file
13
tests/types/t21260.nim
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user