add default field support for object in ARC/ORC (#20480)
* fresh start * add cpp target * add result support * add nimPreviewRangeDefault * reduce * use orc * refactor common parts * add tuple support * add testcase for tuple * cleanup; fixes nimsuggest tests * there is something wrong with cpp * remove * add support for seqs * fixes style * addd initial distinct support * remove links * typo * fixes tuple defaults * add rangedefault * add cpp support * fixes one more bugs * add more hasDefaults * fixes ordinal types * add testcase for #16744 * add testcase for #3608 * fixes docgen * small fix * recursive * fixes * cleanup and remove tuple support * fixes nimsuggest * fixes generics procs * refactor * increases timeout * refactor hasDefault * zero default; disable i386 * add tuples back * fixes bugs * fixes tuple * add more tests * fix one more bug regarding tuples * more tests and cleanup * remove messy distinct types which must be initialized by original types * add tests * fixes zero default * fixes grammar * fixes tests * fixes tests * fixes tests * fixes comments * fixes and add testcase * undo default values for results Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com>
This commit is contained in:
parent
6cf0727192
commit
f89ba2c951
23 changed files with 727 additions and 80 deletions
|
|
@ -511,6 +511,7 @@ type
|
||||||
nfFirstWrite # this node is a first write
|
nfFirstWrite # this node is a first write
|
||||||
nfFirstWrite2 # alternative first write implementation
|
nfFirstWrite2 # alternative first write implementation
|
||||||
nfHasComment # node has a comment
|
nfHasComment # node has a comment
|
||||||
|
nfUseDefaultField # node has a default value (object constructor)
|
||||||
|
|
||||||
TNodeFlags* = set[TNodeFlag]
|
TNodeFlags* = set[TNodeFlag]
|
||||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45)
|
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45)
|
||||||
|
|
@ -713,7 +714,7 @@ type
|
||||||
mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2,
|
mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2,
|
||||||
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
|
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
|
||||||
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
|
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
|
||||||
mSymIsInstantiationOf, mNodeId, mPrivateAccess
|
mSymIsInstantiationOf, mNodeId, mPrivateAccess, mZeroDefault
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
|
||||||
|
|
@ -2572,7 +2572,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
p.module.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
|
p.module.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
|
||||||
[mangleDynLibProc(prc), getTypeDesc(p.module, prc.loc.t), getModuleDllPath(p.module, prc)])
|
[mangleDynLibProc(prc), getTypeDesc(p.module, prc.loc.t), getModuleDllPath(p.module, prc)])
|
||||||
genCall(p, e, d)
|
genCall(p, e, d)
|
||||||
of mDefault: genDefault(p, e, d)
|
of mDefault, mZeroDefault: genDefault(p, e, d)
|
||||||
of mReset: genReset(p, e)
|
of mReset: genReset(p, e)
|
||||||
of mEcho: genEcho(p, e[1].skipConv)
|
of mEcho: genEcho(p, e[1].skipConv)
|
||||||
of mArrToSeq: genArrToSeq(p, e, d)
|
of mArrToSeq: genArrToSeq(p, e, d)
|
||||||
|
|
|
||||||
|
|
@ -2231,7 +2231,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of mNewSeq: genNewSeq(p, n)
|
of mNewSeq: genNewSeq(p, n)
|
||||||
of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]")
|
of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]")
|
||||||
of mOf: genOf(p, n, r)
|
of mOf: genOf(p, n, r)
|
||||||
of mDefault: genDefault(p, n, r)
|
of mDefault, mZeroDefault: genDefault(p, n, r)
|
||||||
of mReset, mWasMoved: genReset(p, n)
|
of mReset, mWasMoved: genReset(p, n)
|
||||||
of mEcho: genEcho(p, n, r)
|
of mEcho: genEcho(p, n, r)
|
||||||
of mNLen..mNError, mSlurp, mStaticExec:
|
of mNLen..mNError, mSlurp, mStaticExec:
|
||||||
|
|
@ -2342,7 +2342,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
gen(p, val, a)
|
gen(p, val, a)
|
||||||
var f = it[0].sym
|
var f = it[0].sym
|
||||||
if f.loc.r == "": f.loc.r = mangleName(p.module, f)
|
if f.loc.r == "": f.loc.r = mangleName(p.module, f)
|
||||||
fieldIDs.incl(lookupFieldAgain(nTyp, f).id)
|
fieldIDs.incl(lookupFieldAgain(n.typ.skipTypes({tyDistinct}), f).id)
|
||||||
|
|
||||||
let typ = val.typ.skipTypes(abstractInst)
|
let typ = val.typ.skipTypes(abstractInst)
|
||||||
if a.typ == etyBaseIndex:
|
if a.typ == etyBaseIndex:
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ define:booting
|
||||||
define:nimcore
|
define:nimcore
|
||||||
define:nimPreviewFloatRoundtrip
|
define:nimPreviewFloatRoundtrip
|
||||||
define:nimPreviewSlimSystem
|
define:nimPreviewSlimSystem
|
||||||
|
define:nimPreviewRangeDefault
|
||||||
threads:off
|
threads:off
|
||||||
|
|
||||||
#import:"$projectpath/testability"
|
#import:"$projectpath/testability"
|
||||||
|
|
|
||||||
|
|
@ -1960,16 +1960,12 @@ proc parseObjectCase(p: var Parser): PNode =
|
||||||
#| objectBranches = objectBranch (IND{=} objectBranch)*
|
#| objectBranches = objectBranch (IND{=} objectBranch)*
|
||||||
#| (IND{=} 'elif' expr colcom objectPart)*
|
#| (IND{=} 'elif' expr colcom objectPart)*
|
||||||
#| (IND{=} 'else' colcom objectPart)?
|
#| (IND{=} 'else' colcom objectPart)?
|
||||||
#| objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
|
#| objectCase = 'case' declColonEquals ':'? COMMENT?
|
||||||
#| (IND{>} objectBranches DED
|
#| (IND{>} objectBranches DED
|
||||||
#| | IND{=} objectBranches)
|
#| | IND{=} objectBranches)
|
||||||
result = newNodeP(nkRecCase, p)
|
result = newNodeP(nkRecCase, p)
|
||||||
getTokNoInd(p)
|
getTokNoInd(p)
|
||||||
var a = newNodeP(nkIdentDefs, p)
|
var a = parseIdentColonEquals(p, {withPragma})
|
||||||
a.add(identWithPragma(p))
|
|
||||||
eat(p, tkColon)
|
|
||||||
a.add(parseTypeDesc(p))
|
|
||||||
a.add(p.emptyNode)
|
|
||||||
result.add(a)
|
result.add(a)
|
||||||
if p.tok.tokType == tkColon: getTok(p)
|
if p.tok.tokType == tkColon: getTok(p)
|
||||||
flexComment(p, result)
|
flexComment(p, result)
|
||||||
|
|
|
||||||
117
compiler/sem.nim
117
compiler/sem.nim
|
|
@ -538,6 +538,123 @@ proc setGenericParamsMisc(c: PContext; n: PNode) =
|
||||||
else:
|
else:
|
||||||
n[miscPos][1] = orig
|
n[miscPos][1] = orig
|
||||||
|
|
||||||
|
proc caseBranchMatchesExpr(branch, matched: PNode): bool =
|
||||||
|
for i in 0 ..< branch.len-1:
|
||||||
|
if branch[i].kind == nkRange:
|
||||||
|
if overlap(branch[i], matched): return true
|
||||||
|
elif exprStructuralEquivalent(branch[i], matched):
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc pickCaseBranchIndex(caseExpr, matched: PNode): int =
|
||||||
|
let endsWithElse = caseExpr[^1].kind == nkElse
|
||||||
|
for i in 1..<caseExpr.len - endsWithElse.int:
|
||||||
|
if caseExpr[i].caseBranchMatchesExpr(matched):
|
||||||
|
return i
|
||||||
|
if endsWithElse:
|
||||||
|
return caseExpr.len - 1
|
||||||
|
|
||||||
|
proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[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] =
|
||||||
|
case recNode.kind
|
||||||
|
of nkRecList:
|
||||||
|
for field in recNode:
|
||||||
|
result.add defaultFieldsForTuple(c, field, hasDefault)
|
||||||
|
of nkSym:
|
||||||
|
let field = recNode.sym
|
||||||
|
let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes)
|
||||||
|
if field.ast != nil: #Try to use default value
|
||||||
|
hasDefault = true
|
||||||
|
result.add newTree(nkExprColonExpr, recNode, field.ast)
|
||||||
|
else:
|
||||||
|
if recType.kind in {tyObject, tyArray, tyTuple}:
|
||||||
|
let asgnExpr = defaultNodeField(c, recNode, recNode.typ)
|
||||||
|
if asgnExpr != nil:
|
||||||
|
hasDefault = true
|
||||||
|
asgnExpr.flags.incl nfUseDefaultField
|
||||||
|
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
|
||||||
|
return
|
||||||
|
|
||||||
|
let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), recType.owner)
|
||||||
|
rawAddSon(asgnType, recType)
|
||||||
|
let asgnExpr = newTree(nkCall,
|
||||||
|
newSymNode(getSysMagic(c.graph, recNode.info, "zeroDefault", mZeroDefault)),
|
||||||
|
newNodeIT(nkType, recNode.info, asgnType)
|
||||||
|
)
|
||||||
|
asgnExpr.flags.incl nfUseDefaultField
|
||||||
|
asgnExpr.typ = recType
|
||||||
|
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
|
||||||
|
else:
|
||||||
|
doAssert false
|
||||||
|
|
||||||
|
proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] =
|
||||||
|
case recNode.kind
|
||||||
|
of nkRecList:
|
||||||
|
for field in recNode:
|
||||||
|
result.add defaultFieldsForTheUninitialized(c, field)
|
||||||
|
of nkRecCase:
|
||||||
|
let discriminator = recNode[0]
|
||||||
|
var selectedBranch: int
|
||||||
|
let defaultValue = discriminator.sym.ast
|
||||||
|
if defaultValue == nil:
|
||||||
|
# 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:
|
||||||
|
selectedBranch = recNode.pickCaseBranchIndex newIntNode(nkIntLit#[c.graph]#, 0)
|
||||||
|
else: # Try to use default value
|
||||||
|
selectedBranch = recNode.pickCaseBranchIndex defaultValue
|
||||||
|
result.add newTree(nkExprColonExpr, discriminator, defaultValue)
|
||||||
|
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, recNode.typ)
|
||||||
|
if asgnExpr != nil:
|
||||||
|
asgnExpr.flags.incl nfUseDefaultField
|
||||||
|
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
|
||||||
|
else:
|
||||||
|
doAssert false
|
||||||
|
|
||||||
|
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode =
|
||||||
|
let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes)
|
||||||
|
if aTypSkip.kind == tyObject:
|
||||||
|
let child = defaultFieldsForTheUninitialized(c, aTyp.skipTypes(defaultFieldsSkipTypes).n)
|
||||||
|
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])
|
||||||
|
|
||||||
|
if child != nil:
|
||||||
|
let node = newNode(nkIntLit)
|
||||||
|
node.intVal = toInt64(lengthOrd(c.graph.config, aTypSkip))
|
||||||
|
result = semExpr(c, newTree(nkCall, newSymNode(getSysSym(c.graph, a.info, "arrayWith"), a.info),
|
||||||
|
semExprWithType(c, child),
|
||||||
|
node
|
||||||
|
))
|
||||||
|
result.typ = aTyp
|
||||||
|
elif aTypSkip.kind == tyTuple:
|
||||||
|
var hasDefault = false
|
||||||
|
if aTypSkip.n != nil:
|
||||||
|
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): PNode =
|
||||||
|
result = defaultNodeField(c, a, a.typ)
|
||||||
|
|
||||||
include semtempl, semgnrc, semstmts, semexprs
|
include semtempl, semgnrc, semstmts, semexprs
|
||||||
|
|
||||||
proc addCodeForGenerics(c: PContext, n: PNode) =
|
proc addCodeForGenerics(c: PContext, n: PNode) =
|
||||||
|
|
|
||||||
|
|
@ -926,8 +926,6 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||||
rawAddSon(typ, result.typ)
|
rawAddSon(typ, result.typ)
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode
|
|
||||||
|
|
||||||
proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
|
proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
|
||||||
t: PType): TCandidate =
|
t: PType): TCandidate =
|
||||||
initCandidate(c, result, t)
|
initCandidate(c, result, t)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,26 @@
|
||||||
# This include file implements the semantic checking for magics.
|
# This include file implements the semantic checking for magics.
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
|
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode
|
||||||
|
|
||||||
|
|
||||||
|
proc addDefaultFieldForNew(c: PContext, n: PNode): PNode =
|
||||||
|
result = n
|
||||||
|
let typ = result[1].typ # new(x)
|
||||||
|
if typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyRef and typ.skipTypes({tyGenericInst, tyAlias, tySink})[0].kind == tyObject:
|
||||||
|
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[1].info, typ))
|
||||||
|
asgnExpr.typ = typ
|
||||||
|
var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0]
|
||||||
|
while true:
|
||||||
|
asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n)
|
||||||
|
let base = t[0]
|
||||||
|
if base == nil:
|
||||||
|
break
|
||||||
|
t = skipTypes(base, skipPtrs)
|
||||||
|
|
||||||
|
if asgnExpr.sons.len > 1:
|
||||||
|
result = newTree(nkAsgn, result[1], asgnExpr)
|
||||||
|
|
||||||
proc semAddrArg(c: PContext; n: PNode): PNode =
|
proc semAddrArg(c: PContext; n: PNode): PNode =
|
||||||
let x = semExprWithType(c, n)
|
let x = semExprWithType(c, n)
|
||||||
if x.kind == nkSym:
|
if x.kind == nkSym:
|
||||||
|
|
@ -494,13 +514,20 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
|
||||||
bindTypeHook(c, transFormedSym, n, attachedDestructor)
|
bindTypeHook(c, transFormedSym, n, attachedDestructor)
|
||||||
else:
|
else:
|
||||||
bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor)
|
bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor)
|
||||||
result = n
|
result = addDefaultFieldForNew(c, n)
|
||||||
|
|
||||||
proc semPrivateAccess(c: PContext, n: PNode): PNode =
|
proc semPrivateAccess(c: PContext, n: PNode): PNode =
|
||||||
let t = n[1].typ[0].toObjectFromRefPtrGeneric
|
let t = n[1].typ[0].toObjectFromRefPtrGeneric
|
||||||
c.currentScope.allowPrivateAccess.add t.sym
|
c.currentScope.allowPrivateAccess.add t.sym
|
||||||
result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid))
|
result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid))
|
||||||
|
|
||||||
|
proc checkDefault(c: PContext, n: PNode): PNode =
|
||||||
|
result = n
|
||||||
|
c.config.internalAssert result[1].typ.kind == tyTypeDesc
|
||||||
|
let constructed = result[1].typ.base
|
||||||
|
if constructed.requiresInit:
|
||||||
|
message(c.config, n.info, warnUnsafeDefault, typeToString(constructed))
|
||||||
|
|
||||||
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
flags: TExprFlags): PNode =
|
flags: TExprFlags): PNode =
|
||||||
## This is the preferred code point to implement magics.
|
## This is the preferred code point to implement magics.
|
||||||
|
|
@ -559,6 +586,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
result = n
|
result = n
|
||||||
else:
|
else:
|
||||||
result = plugin(c, n)
|
result = plugin(c, n)
|
||||||
|
of mNew:
|
||||||
|
result = addDefaultFieldForNew(c, n)
|
||||||
of mNewFinalize:
|
of mNewFinalize:
|
||||||
result = semNewFinalize(c, n)
|
result = semNewFinalize(c, n)
|
||||||
of mDestroy:
|
of mDestroy:
|
||||||
|
|
@ -587,11 +616,13 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
if seqType.kind == tySequence and seqType.base.requiresInit:
|
if seqType.kind == tySequence and seqType.base.requiresInit:
|
||||||
message(c.config, n.info, warnUnsafeSetLen, typeToString(seqType.base))
|
message(c.config, n.info, warnUnsafeSetLen, typeToString(seqType.base))
|
||||||
of mDefault:
|
of mDefault:
|
||||||
result = n
|
result = checkDefault(c, n)
|
||||||
c.config.internalAssert result[1].typ.kind == tyTypeDesc
|
let typ = result[^1].typ.skipTypes({tyTypeDesc})
|
||||||
let constructed = result[1].typ.base
|
let defaultExpr = defaultNodeField(c, result[^1], typ)
|
||||||
if constructed.requiresInit:
|
if defaultExpr != nil:
|
||||||
message(c.config, n.info, warnUnsafeDefault, typeToString(constructed))
|
result = defaultExpr
|
||||||
|
of mZeroDefault:
|
||||||
|
result = checkDefault(c, n)
|
||||||
of mIsolate:
|
of mIsolate:
|
||||||
if not checkIsolate(n[1]):
|
if not checkIsolate(n[1]):
|
||||||
localError(c.config, n.info, "expression cannot be isolated: " & $n[1])
|
localError(c.config, n.info, "expression cannot be isolated: " & $n[1])
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,10 @@ type
|
||||||
initNone # None of the fields have been initialized
|
initNone # None of the fields have been initialized
|
||||||
initConflict # Fields from different branches have been initialized
|
initConflict # Fields from different branches have been initialized
|
||||||
|
|
||||||
|
|
||||||
|
proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
|
||||||
|
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]]
|
||||||
|
|
||||||
proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) =
|
proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) =
|
||||||
case newStatus
|
case newStatus
|
||||||
of initConflict:
|
of initConflict:
|
||||||
|
|
@ -72,7 +76,9 @@ proc semConstrField(c: PContext, flags: TExprFlags,
|
||||||
let assignment = locateFieldInInitExpr(c, field, initExpr)
|
let assignment = locateFieldInInitExpr(c, field, initExpr)
|
||||||
if assignment != nil:
|
if assignment != nil:
|
||||||
if nfSem in assignment.flags: return assignment[1]
|
if nfSem in assignment.flags: return assignment[1]
|
||||||
if not fieldVisible(c, field):
|
if nfUseDefaultField in assignment[1].flags:
|
||||||
|
discard
|
||||||
|
elif not fieldVisible(c, field):
|
||||||
localError(c.config, initExpr.info,
|
localError(c.config, initExpr.info,
|
||||||
"the field '$1' is not accessible." % [field.name.s])
|
"the field '$1' is not accessible." % [field.name.s])
|
||||||
return
|
return
|
||||||
|
|
@ -85,15 +91,6 @@ proc semConstrField(c: PContext, flags: TExprFlags,
|
||||||
assignment.flags.incl nfSem
|
assignment.flags.incl nfSem
|
||||||
return initValue
|
return initValue
|
||||||
|
|
||||||
proc caseBranchMatchesExpr(branch, matched: PNode): bool =
|
|
||||||
for i in 0..<branch.len-1:
|
|
||||||
if branch[i].kind == nkRange:
|
|
||||||
if overlap(branch[i], matched): return true
|
|
||||||
elif exprStructuralEquivalent(branch[i], matched):
|
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
|
proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
|
||||||
isStmtBranch: bool): IntSet =
|
isStmtBranch: bool): IntSet =
|
||||||
if caseNode[caseIdx].kind == nkOfBranch:
|
if caseNode[caseIdx].kind == nkOfBranch:
|
||||||
|
|
@ -155,18 +152,14 @@ proc collectMissingFields(c: PContext, fieldsRecList: PNode,
|
||||||
if assignment == nil:
|
if assignment == nil:
|
||||||
constrCtx.missingFields.add r.sym
|
constrCtx.missingFields.add r.sym
|
||||||
|
|
||||||
|
proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
|
||||||
proc semConstructFields(c: PContext, n: PNode,
|
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
|
||||||
constrCtx: var ObjConstrContext,
|
|
||||||
flags: TExprFlags): InitStatus =
|
|
||||||
result = initUnknown
|
|
||||||
|
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkRecList:
|
of nkRecList:
|
||||||
for field in n:
|
for field in n:
|
||||||
let status = semConstructFields(c, field, constrCtx, flags)
|
let (subSt, subDf) = semConstructFields(c, field, constrCtx, flags)
|
||||||
mergeInitStatus(result, status)
|
result.status.mergeInitStatus subSt
|
||||||
|
result.defaults.add subDf
|
||||||
of nkRecCase:
|
of nkRecCase:
|
||||||
template fieldsPresentInBranch(branchIdx: int): string =
|
template fieldsPresentInBranch(branchIdx: int): string =
|
||||||
let branch = n[branchIdx]
|
let branch = n[branchIdx]
|
||||||
|
|
@ -184,9 +177,9 @@ proc semConstructFields(c: PContext, n: PNode,
|
||||||
|
|
||||||
for i in 1..<n.len:
|
for i in 1..<n.len:
|
||||||
let innerRecords = n[i][^1]
|
let innerRecords = n[i][^1]
|
||||||
let status = semConstructFields(c, innerRecords, constrCtx, flags)
|
let (status, _) = semConstructFields(c, innerRecords, constrCtx, flags) # todo
|
||||||
if status notin {initNone, initUnknown}:
|
if status notin {initNone, initUnknown}:
|
||||||
mergeInitStatus(result, status)
|
result.status.mergeInitStatus status
|
||||||
if selectedBranch != -1:
|
if selectedBranch != -1:
|
||||||
let prevFields = fieldsPresentInBranch(selectedBranch)
|
let prevFields = fieldsPresentInBranch(selectedBranch)
|
||||||
let currentFields = fieldsPresentInBranch(i)
|
let currentFields = fieldsPresentInBranch(i)
|
||||||
|
|
@ -194,7 +187,7 @@ proc semConstructFields(c: PContext, n: PNode,
|
||||||
("The fields '$1' and '$2' cannot be initialized together, " &
|
("The fields '$1' and '$2' cannot be initialized together, " &
|
||||||
"because they are from conflicting branches in the case object.") %
|
"because they are from conflicting branches in the case object.") %
|
||||||
[prevFields, currentFields])
|
[prevFields, currentFields])
|
||||||
result = initConflict
|
result.status = initConflict
|
||||||
else:
|
else:
|
||||||
selectedBranch = i
|
selectedBranch = i
|
||||||
|
|
||||||
|
|
@ -206,7 +199,7 @@ proc semConstructFields(c: PContext, n: PNode,
|
||||||
("cannot prove that it's safe to initialize $1 with " &
|
("cannot prove that it's safe to initialize $1 with " &
|
||||||
"the runtime value for the discriminator '$2' ") %
|
"the runtime value for the discriminator '$2' ") %
|
||||||
[fields, discriminator.sym.name.s])
|
[fields, discriminator.sym.name.s])
|
||||||
mergeInitStatus(result, initNone)
|
mergeInitStatus(result.status, initNone)
|
||||||
|
|
||||||
template wrongBranchError(i) =
|
template wrongBranchError(i) =
|
||||||
if c.inUncheckedAssignSection == 0:
|
if c.inUncheckedAssignSection == 0:
|
||||||
|
|
@ -289,13 +282,16 @@ proc semConstructFields(c: PContext, n: PNode,
|
||||||
else:
|
else:
|
||||||
wrongBranchError(failedBranch)
|
wrongBranchError(failedBranch)
|
||||||
|
|
||||||
|
let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags)
|
||||||
|
result.defaults.add defaults
|
||||||
|
|
||||||
# When a branch is selected with a partial match, some of the fields
|
# When a branch is selected with a partial match, some of the fields
|
||||||
# that were not initialized may be mandatory. We must check for this:
|
# that were not initialized may be mandatory. We must check for this:
|
||||||
if result == initPartial:
|
if result.status == initPartial:
|
||||||
collectMissingFields branchNode
|
collectMissingFields branchNode
|
||||||
|
|
||||||
else:
|
else:
|
||||||
result = initNone
|
result.status = initNone
|
||||||
let discriminatorVal = semConstrField(c, flags + {efPreferStatic},
|
let discriminatorVal = semConstrField(c, flags + {efPreferStatic},
|
||||||
discriminator.sym,
|
discriminator.sym,
|
||||||
constrCtx.initExpr)
|
constrCtx.initExpr)
|
||||||
|
|
@ -308,33 +304,41 @@ proc semConstructFields(c: PContext, n: PNode,
|
||||||
let matchedBranch = n.pickCaseBranch defaultValue
|
let matchedBranch = n.pickCaseBranch defaultValue
|
||||||
collectMissingFields matchedBranch
|
collectMissingFields matchedBranch
|
||||||
else:
|
else:
|
||||||
result = initPartial
|
result.status = initPartial
|
||||||
if discriminatorVal.kind == nkIntLit:
|
if discriminatorVal.kind == nkIntLit:
|
||||||
# When the discriminator is a compile-time value, we also know
|
# When the discriminator is a compile-time value, we also know
|
||||||
# which branch will be selected:
|
# which branch will be selected:
|
||||||
let matchedBranch = n.pickCaseBranch discriminatorVal
|
let matchedBranch = n.pickCaseBranch discriminatorVal
|
||||||
if matchedBranch != nil: collectMissingFields matchedBranch
|
if matchedBranch != nil:
|
||||||
|
let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags)
|
||||||
|
result.defaults.add defaults
|
||||||
|
collectMissingFields matchedBranch
|
||||||
else:
|
else:
|
||||||
# All bets are off. If any of the branches has a mandatory
|
# All bets are off. If any of the branches has a mandatory
|
||||||
# fields we must produce an error:
|
# fields we must produce an error:
|
||||||
for i in 1..<n.len: collectMissingFields n[i]
|
for i in 1..<n.len: collectMissingFields n[i]
|
||||||
|
|
||||||
of nkSym:
|
of nkSym:
|
||||||
let field = n.sym
|
let field = n.sym
|
||||||
let e = semConstrField(c, flags, field, constrCtx.initExpr)
|
let e = semConstrField(c, flags, field, constrCtx.initExpr)
|
||||||
result = if e != nil: initFull else: initNone
|
if e != nil:
|
||||||
|
result.status = initFull
|
||||||
|
elif field.ast != nil:
|
||||||
|
result.status = initUnknown
|
||||||
|
result.defaults.add newTree(nkExprColonExpr, n, field.ast)
|
||||||
|
else:
|
||||||
|
result.status = initNone
|
||||||
else:
|
else:
|
||||||
internalAssert c.config, false
|
internalAssert c.config, false
|
||||||
|
|
||||||
proc semConstructTypeAux(c: PContext,
|
proc semConstructTypeAux(c: PContext,
|
||||||
constrCtx: var ObjConstrContext,
|
constrCtx: var ObjConstrContext,
|
||||||
flags: TExprFlags): InitStatus =
|
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
|
||||||
result = initUnknown
|
result.status = initUnknown
|
||||||
var t = constrCtx.typ
|
var t = constrCtx.typ
|
||||||
while true:
|
while true:
|
||||||
let status = semConstructFields(c, t.n, constrCtx, flags)
|
let (status, defaults) = semConstructFields(c, t.n, constrCtx, flags)
|
||||||
mergeInitStatus(result, status)
|
result.status.mergeInitStatus status
|
||||||
|
result.defaults.add defaults
|
||||||
if status in {initPartial, initNone, initUnknown}:
|
if status in {initPartial, initNone, initUnknown}:
|
||||||
collectMissingFields c, t.n, constrCtx
|
collectMissingFields c, t.n, constrCtx
|
||||||
let base = t[0]
|
let base = t[0]
|
||||||
|
|
@ -378,7 +382,9 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
|
||||||
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
|
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
|
||||||
var t = semTypeNode(c, n[0], nil)
|
var t = semTypeNode(c, n[0], nil)
|
||||||
result = newNodeIT(nkObjConstr, n.info, t)
|
result = newNodeIT(nkObjConstr, n.info, t)
|
||||||
for child in n: result.add child
|
result.add newNodeIT(nkType, n.info, t) #This will contain the default values to be added in transf
|
||||||
|
for i in 1..<n.len:
|
||||||
|
result.add n[i]
|
||||||
|
|
||||||
if t == nil:
|
if t == nil:
|
||||||
return localErrorNode(c, result, "object constructor needs an object type")
|
return localErrorNode(c, result, "object constructor needs an object type")
|
||||||
|
|
@ -409,7 +415,8 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
|
||||||
# field (if this is a case object, initialized fields in two different
|
# field (if this is a case object, initialized fields in two different
|
||||||
# branches will be reported as an error):
|
# branches will be reported as an error):
|
||||||
var constrCtx = initConstrContext(t, result)
|
var constrCtx = initConstrContext(t, result)
|
||||||
let initResult = semConstructTypeAux(c, constrCtx, flags)
|
let (initResult, defaults) = semConstructTypeAux(c, constrCtx, flags)
|
||||||
|
result[0].sons.add defaults
|
||||||
var hasError = false # needed to split error detect/report for better msgs
|
var hasError = false # needed to split error detect/report for better msgs
|
||||||
|
|
||||||
# It's possible that the object was not fully initialized while
|
# It's possible that the object was not fully initialized while
|
||||||
|
|
|
||||||
|
|
@ -612,6 +612,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
var typFlags: TTypeAllowedFlags
|
var typFlags: TTypeAllowedFlags
|
||||||
|
|
||||||
var def: PNode = c.graph.emptyNode
|
var def: PNode = c.graph.emptyNode
|
||||||
|
if a[^1].kind == nkEmpty and symkind == skVar and a[^2].typ != nil:
|
||||||
|
let field = defaultNodeField(c, a[^2])
|
||||||
|
if field != nil:
|
||||||
|
a[^1] = field
|
||||||
|
field.flags.incl nfUseDefaultField
|
||||||
if a[^1].kind != nkEmpty:
|
if a[^1].kind != nkEmpty:
|
||||||
def = semExprWithType(c, a[^1], {}, typ)
|
def = semExprWithType(c, a[^1], {}, typ)
|
||||||
|
|
||||||
|
|
@ -680,6 +685,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
addToVarSection(c, result, n, a)
|
addToVarSection(c, result, n, a)
|
||||||
continue
|
continue
|
||||||
var v = semIdentDef(c, a[j], symkind, false)
|
var v = semIdentDef(c, a[j], symkind, false)
|
||||||
|
if a[^1].kind != nkEmpty:
|
||||||
|
if {sfThread, sfNoInit} * v.flags != {} and
|
||||||
|
nfUseDefaultField in a[^1].flags:
|
||||||
|
a[^1] = c.graph.emptyNode
|
||||||
|
def = c.graph.emptyNode
|
||||||
|
a[^1].flags.excl nfUseDefaultField
|
||||||
styleCheckDef(c, v)
|
styleCheckDef(c, v)
|
||||||
onDef(a[j].info, v)
|
onDef(a[j].info, v)
|
||||||
if sfGenSym notin v.flags:
|
if sfGenSym notin v.flags:
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ const
|
||||||
errXExpectsOneTypeParam = "'$1' expects one type parameter"
|
errXExpectsOneTypeParam = "'$1' expects one type parameter"
|
||||||
errArrayExpectsTwoTypeParams = "array expects two type parameters"
|
errArrayExpectsTwoTypeParams = "array expects two type parameters"
|
||||||
errInvalidVisibilityX = "invalid visibility: '$1'"
|
errInvalidVisibilityX = "invalid visibility: '$1'"
|
||||||
errInitHereNotAllowed = "initialization not allowed here"
|
|
||||||
errXCannotBeAssignedTo = "'$1' cannot be assigned to"
|
errXCannotBeAssignedTo = "'$1' cannot be assigned to"
|
||||||
errIteratorNotAllowed = "iterators can only be defined at the module's top level"
|
errIteratorNotAllowed = "iterators can only be defined at the module's top level"
|
||||||
errXNeedsReturnType = "$1 needs a return type"
|
errXNeedsReturnType = "$1 needs a return type"
|
||||||
|
|
@ -293,17 +292,18 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if n.len == 2:
|
if n.len == 2:
|
||||||
if isRange(n[1]):
|
if isRange(n[1]):
|
||||||
result = semRangeAux(c, n[1], prev)
|
result = semRangeAux(c, n[1], prev)
|
||||||
let n = result.n
|
if not isDefined(c.config, "nimPreviewRangeDefault"):
|
||||||
if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0:
|
let n = result.n
|
||||||
incl(result.flags, tfRequiresInit)
|
if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0:
|
||||||
elif n[1].kind in {nkCharLit..nkUInt64Lit} and n[1].intVal < 0:
|
incl(result.flags, tfRequiresInit)
|
||||||
incl(result.flags, tfRequiresInit)
|
elif n[1].kind in {nkCharLit..nkUInt64Lit} and n[1].intVal < 0:
|
||||||
elif n[0].kind in {nkFloatLit..nkFloat64Lit} and
|
incl(result.flags, tfRequiresInit)
|
||||||
n[0].floatVal > 0.0:
|
elif n[0].kind in {nkFloatLit..nkFloat64Lit} and
|
||||||
incl(result.flags, tfRequiresInit)
|
n[0].floatVal > 0.0:
|
||||||
elif n[1].kind in {nkFloatLit..nkFloat64Lit} and
|
incl(result.flags, tfRequiresInit)
|
||||||
n[1].floatVal < 0.0:
|
elif n[1].kind in {nkFloatLit..nkFloat64Lit} and
|
||||||
incl(result.flags, tfRequiresInit)
|
n[1].floatVal < 0.0:
|
||||||
|
incl(result.flags, tfRequiresInit)
|
||||||
else:
|
else:
|
||||||
if n[1].kind == nkInfix and considerQuotedIdent(c, n[1][0]).s == "..<":
|
if n[1].kind == nkInfix and considerQuotedIdent(c, n[1][0]).s == "..<":
|
||||||
localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported")
|
localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported")
|
||||||
|
|
@ -481,13 +481,19 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||||
var a = n[i]
|
var a = n[i]
|
||||||
if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
|
if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
|
||||||
checkMinSonsLen(a, 3, c.config)
|
checkMinSonsLen(a, 3, c.config)
|
||||||
if a[^2].kind != nkEmpty:
|
var hasDefaultField = a[^1].kind != nkEmpty
|
||||||
|
if hasDefaultField:
|
||||||
|
a[^1] = semConstExpr(c, a[^1])
|
||||||
|
typ = a[^1].typ
|
||||||
|
elif a[^2].kind != nkEmpty:
|
||||||
typ = semTypeNode(c, a[^2], nil)
|
typ = semTypeNode(c, a[^2], nil)
|
||||||
|
if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange:
|
||||||
|
a[^1] = newIntNode(nkIntLit, firstOrd(c.config, typ))
|
||||||
|
a[^1].typ = typ
|
||||||
|
hasDefaultField = true
|
||||||
else:
|
else:
|
||||||
localError(c.config, a.info, errTypeExpected)
|
localError(c.config, a.info, errTypeExpected)
|
||||||
typ = errorType(c)
|
typ = errorType(c)
|
||||||
if a[^1].kind != nkEmpty:
|
|
||||||
localError(c.config, a[^1].info, errInitHereNotAllowed)
|
|
||||||
for j in 0..<a.len - 2:
|
for j in 0..<a.len - 2:
|
||||||
var field = newSymG(skField, a[j], c)
|
var field = newSymG(skField, a[j], c)
|
||||||
field.typ = typ
|
field.typ = typ
|
||||||
|
|
@ -496,7 +502,11 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if containsOrIncl(check, field.name.id):
|
if containsOrIncl(check, field.name.id):
|
||||||
localError(c.config, a[j].info, "attempt to redefine: '" & field.name.s & "'")
|
localError(c.config, a[j].info, "attempt to redefine: '" & field.name.s & "'")
|
||||||
else:
|
else:
|
||||||
result.n.add newSymNode(field)
|
let fSym = newSymNode(field)
|
||||||
|
if hasDefaultField:
|
||||||
|
fSym.sym.ast = a[^1]
|
||||||
|
fSym.sym.ast.flags.incl nfUseDefaultField
|
||||||
|
result.n.add fSym
|
||||||
addSonSkipIntLit(result, typ, c.idgen)
|
addSonSkipIntLit(result, typ, c.idgen)
|
||||||
styleCheckDef(c, a[j].info, field)
|
styleCheckDef(c, a[j].info, field)
|
||||||
onDef(field.info, field)
|
onDef(field.info, field)
|
||||||
|
|
@ -805,14 +815,21 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
var a: PNode
|
var a: PNode
|
||||||
if father.kind != nkRecList and n.len >= 4: a = newNodeI(nkRecList, n.info)
|
if father.kind != nkRecList and n.len >= 4: a = newNodeI(nkRecList, n.info)
|
||||||
else: a = newNodeI(nkEmpty, n.info)
|
else: a = newNodeI(nkEmpty, n.info)
|
||||||
if n[^1].kind != nkEmpty:
|
|
||||||
localError(c.config, n[^1].info, errInitHereNotAllowed)
|
|
||||||
var typ: PType
|
var typ: PType
|
||||||
if n[^2].kind == nkEmpty:
|
var hasDefaultField = n[^1].kind != nkEmpty
|
||||||
|
if hasDefaultField:
|
||||||
|
n[^1] = semConstExpr(c, n[^1])
|
||||||
|
typ = n[^1].typ
|
||||||
|
propagateToOwner(rectype, typ)
|
||||||
|
elif n[^2].kind == nkEmpty:
|
||||||
localError(c.config, n.info, errTypeExpected)
|
localError(c.config, n.info, errTypeExpected)
|
||||||
typ = errorType(c)
|
typ = errorType(c)
|
||||||
else:
|
else:
|
||||||
typ = semTypeNode(c, n[^2], nil)
|
typ = semTypeNode(c, n[^2], nil)
|
||||||
|
if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange:
|
||||||
|
n[^1] = newIntNode(nkIntLit, firstOrd(c.config, typ))
|
||||||
|
n[^1].typ = typ
|
||||||
|
hasDefaultField = true
|
||||||
propagateToOwner(rectype, typ)
|
propagateToOwner(rectype, typ)
|
||||||
var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner
|
var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner
|
||||||
else: rectype.sym
|
else: rectype.sym
|
||||||
|
|
@ -834,8 +851,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
inc(pos)
|
inc(pos)
|
||||||
if containsOrIncl(check, f.name.id):
|
if containsOrIncl(check, f.name.id):
|
||||||
localError(c.config, info, "attempt to redefine: '" & f.name.s & "'")
|
localError(c.config, info, "attempt to redefine: '" & f.name.s & "'")
|
||||||
if a.kind == nkEmpty: father.add newSymNode(f)
|
let fSym = newSymNode(f)
|
||||||
else: a.add newSymNode(f)
|
if hasDefaultField:
|
||||||
|
fSym.sym.ast = n[^1]
|
||||||
|
fSym.sym.ast.flags.incl nfUseDefaultField
|
||||||
|
if a.kind == nkEmpty: father.add fSym
|
||||||
|
else: a.add fSym
|
||||||
styleCheckDef(c, f)
|
styleCheckDef(c, f)
|
||||||
onDef(f.info, f)
|
onDef(f.info, f)
|
||||||
if a.kind != nkEmpty: father.add a
|
if a.kind != nkEmpty: father.add a
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ type
|
||||||
module: PSym
|
module: PSym
|
||||||
transCon: PTransCon # top of a TransCon stack
|
transCon: PTransCon # top of a TransCon stack
|
||||||
inlining: int # > 0 if we are in inlining context (copy vars)
|
inlining: int # > 0 if we are in inlining context (copy vars)
|
||||||
nestedProcs: int # > 0 if we are in a nested proc
|
|
||||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||||
deferDetected, tooEarly: bool
|
deferDetected, tooEarly: bool
|
||||||
graph: ModuleGraph
|
graph: ModuleGraph
|
||||||
|
|
@ -1061,6 +1060,13 @@ proc transform(c: PTransf, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
of nkExceptBranch:
|
of nkExceptBranch:
|
||||||
result = transformExceptBranch(c, n)
|
result = transformExceptBranch(c, n)
|
||||||
|
of nkObjConstr:
|
||||||
|
result = n
|
||||||
|
if result.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject or
|
||||||
|
result.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyRef and result.typ.skipTypes({tyGenericInst, tyAlias, tySink})[0].kind == tyObject:
|
||||||
|
result.sons.add result[0].sons
|
||||||
|
result[0] = newNodeIT(nkType, result.info, result.typ)
|
||||||
|
result = transformSons(c, result)
|
||||||
of nkCheckedFieldExpr:
|
of nkCheckedFieldExpr:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
if result[0].kind != nkDotExpr:
|
if result[0].kind != nkDotExpr:
|
||||||
|
|
|
||||||
|
|
@ -1181,7 +1181,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||||
c.gABx(n, opcLdNull, d, c.genType(n[1].typ))
|
c.gABx(n, opcLdNull, d, c.genType(n[1].typ))
|
||||||
c.gABx(n, opcNodeToReg, d, d)
|
c.gABx(n, opcNodeToReg, d, d)
|
||||||
c.genAsgnPatch(n[1], d)
|
c.genAsgnPatch(n[1], d)
|
||||||
of mDefault:
|
of mDefault, mZeroDefault:
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
c.gABx(n, ldNullOpcode(n.typ), dest, c.genType(n.typ))
|
c.gABx(n, ldNullOpcode(n.typ), dest, c.genType(n.typ))
|
||||||
of mOf, mIs:
|
of mOf, mIs:
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ hint[LineTooLong]=off
|
||||||
#hint[XDeclaredButNotUsed]=off
|
#hint[XDeclaredButNotUsed]=off
|
||||||
|
|
||||||
threads:on
|
threads:on
|
||||||
|
define:nimPreviewRangeDefault
|
||||||
|
|
||||||
# Examples of how to setup a cross-compiler:
|
# Examples of how to setup a cross-compiler:
|
||||||
# Nim can target architectures and OSes different than the local host
|
# Nim can target architectures and OSes different than the local host
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ objectBranch = 'of' exprList colcom objectPart
|
||||||
objectBranches = objectBranch (IND{=} objectBranch)*
|
objectBranches = objectBranch (IND{=} objectBranch)*
|
||||||
(IND{=} 'elif' expr colcom objectPart)*
|
(IND{=} 'elif' expr colcom objectPart)*
|
||||||
(IND{=} 'else' colcom objectPart)?
|
(IND{=} 'else' colcom objectPart)?
|
||||||
objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
|
objectCase = 'case' declColonEquals ':'? COMMENT?
|
||||||
(IND{>} objectBranches DED
|
(IND{>} objectBranches DED
|
||||||
| IND{=} objectBranches)
|
| IND{=} objectBranches)
|
||||||
objectPart = IND{>} objectPart^+IND{=} DED
|
objectPart = IND{>} objectPart^+IND{=} DED
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@
|
||||||
|
|
||||||
include "system/basic_types"
|
include "system/basic_types"
|
||||||
|
|
||||||
|
func zeroDefault*[T](_: typedesc[T]): T {.magic: "ZeroDefault".} =
|
||||||
|
## returns the default value of the type `T`.
|
||||||
|
|
||||||
include "system/compilation"
|
include "system/compilation"
|
||||||
|
|
||||||
{.push warning[GcMem]: off, warning[Uninit]: off.}
|
{.push warning[GcMem]: off, warning[Uninit]: off.}
|
||||||
|
|
@ -911,6 +914,7 @@ proc default*[T](_: typedesc[T]): T {.magic: "Default", noSideEffect.} =
|
||||||
# note: the doc comment also explains why `default` can't be implemented
|
# note: the doc comment also explains why `default` can't be implemented
|
||||||
# via: `template default*[T](t: typedesc[T]): T = (var v: T; v)`
|
# via: `template default*[T](t: typedesc[T]): T = (var v: T; v)`
|
||||||
|
|
||||||
|
|
||||||
proc reset*[T](obj: var T) {.noSideEffect.} =
|
proc reset*[T](obj: var T) {.noSideEffect.} =
|
||||||
## Resets an object `obj` to its default value.
|
## Resets an object `obj` to its default value.
|
||||||
obj = default(typeof(obj))
|
obj = default(typeof(obj))
|
||||||
|
|
@ -2753,3 +2757,8 @@ when notJSnotNims and not defined(nimSeqsV2):
|
||||||
moveMem(addr y[0], addr x[0], x.len)
|
moveMem(addr y[0], addr x[0], x.len)
|
||||||
assert y == "abcgh"
|
assert y == "abcgh"
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
proc arrayWith*[T](y: T, size: static int): array[size, T] {.noinit.} = # ? exempt from default value for result
|
||||||
|
## Creates a new array filled with `y`.
|
||||||
|
for i in 0..size-1:
|
||||||
|
result[i] = y
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,8 @@ proc setLen[T](s: var seq[T], newlen: Natural) =
|
||||||
if xu.p == nil or xu.p.cap < newlen:
|
if xu.p == nil or xu.p.cap < newlen:
|
||||||
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T)))
|
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T)))
|
||||||
xu.len = newlen
|
xu.len = newlen
|
||||||
|
for i in oldLen..<newlen:
|
||||||
|
xu.p.data[i] = default(T)
|
||||||
|
|
||||||
proc newSeq[T](s: var seq[T], len: Natural) =
|
proc newSeq[T](s: var seq[T], len: Natural) =
|
||||||
shrink(s, 0)
|
shrink(s, 0)
|
||||||
|
|
|
||||||
|
|
@ -40,5 +40,6 @@ switch("define", "nimPreviewFloatRoundtrip")
|
||||||
switch("define", "nimPreviewDotLikeOps")
|
switch("define", "nimPreviewDotLikeOps")
|
||||||
switch("define", "nimPreviewJsonutilsHoleyEnum")
|
switch("define", "nimPreviewJsonutilsHoleyEnum")
|
||||||
switch("define", "nimPreviewHashRef")
|
switch("define", "nimPreviewHashRef")
|
||||||
|
switch("define", "nimPreviewRangeDefault")
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
switch("tlsEmulation", "off")
|
switch("tlsEmulation", "off")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: "nim check $file"
|
cmd: "nim check --mm:refc $file"
|
||||||
errormsg: "'t' has unspecified generic parameters"
|
errormsg: "'t' has unspecified generic parameters"
|
||||||
nimout: '''
|
nimout: '''
|
||||||
t5167_5.nim(10, 16) Error: expression 'system' has no type (or is ambiguous)
|
t5167_5.nim(10, 16) Error: expression 'system' has no type (or is ambiguous)
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@ g = {},
|
||||||
h = {},
|
h = {},
|
||||||
i = ["", "", ""],
|
i = ["", "", ""],
|
||||||
j = @[],
|
j = @[],
|
||||||
k = 0,
|
k = -12,
|
||||||
l = [a = "",
|
l = [a = "",
|
||||||
b = @[]],
|
b = @[]],
|
||||||
m = nil,
|
m = nil,
|
||||||
|
|
|
||||||
15
tests/objects/mobject_default_value.nim
Normal file
15
tests/objects/mobject_default_value.nim
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
type
|
||||||
|
Clean = object
|
||||||
|
mem: int
|
||||||
|
Default* = object
|
||||||
|
poi: int = 12
|
||||||
|
clc: Clean
|
||||||
|
se*: range[0'i32 .. high(int32)]
|
||||||
|
|
||||||
|
NonDefault* = object
|
||||||
|
poi: int
|
||||||
|
|
||||||
|
PrellDeque*[T] = object
|
||||||
|
pendingTasks*: range[0'i32 .. high(int32)]
|
||||||
|
head: T
|
||||||
|
tail: T
|
||||||
429
tests/objects/tobject_default_value.nim
Normal file
429
tests/objects/tobject_default_value.nim
Normal file
|
|
@ -0,0 +1,429 @@
|
||||||
|
discard """
|
||||||
|
matrix: "-d:nimPreviewRangeDefault --mm:refc; -d:nimPreviewRangeDefault --warningAsError:ProveInit --mm:orc"
|
||||||
|
targets: "c cpp js"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import times
|
||||||
|
|
||||||
|
type
|
||||||
|
Guess = object
|
||||||
|
poi: DateTime
|
||||||
|
|
||||||
|
GuessDistinct = distinct Guess
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: Guess
|
||||||
|
discard Guess()
|
||||||
|
|
||||||
|
var y: GuessDistinct
|
||||||
|
|
||||||
|
discard y
|
||||||
|
|
||||||
|
discard GuessDistinct(x)
|
||||||
|
|
||||||
|
|
||||||
|
import mobject_default_value
|
||||||
|
|
||||||
|
block:
|
||||||
|
let x = Default()
|
||||||
|
doAssert x.se == 0'i32
|
||||||
|
# echo Default(poi: 12)
|
||||||
|
# echo Default(poi: 17)
|
||||||
|
|
||||||
|
# echo NonDefault(poi: 77)
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: Default
|
||||||
|
doAssert x.se == 0'i32
|
||||||
|
|
||||||
|
type
|
||||||
|
ObjectBase = object of RootObj
|
||||||
|
value = 12
|
||||||
|
|
||||||
|
ObjectBaseDistinct = distinct ObjectBase
|
||||||
|
|
||||||
|
DinstinctInObject = object
|
||||||
|
data: ObjectBaseDistinct
|
||||||
|
|
||||||
|
Object = object of ObjectBase
|
||||||
|
time: float = 1.2
|
||||||
|
date: int
|
||||||
|
scale: range[1..10]
|
||||||
|
|
||||||
|
Object2 = object
|
||||||
|
name: Object
|
||||||
|
|
||||||
|
Object3 = object
|
||||||
|
obj: Object2
|
||||||
|
|
||||||
|
ObjectTuple = tuple
|
||||||
|
base: ObjectBase
|
||||||
|
typ: int
|
||||||
|
obj: Object
|
||||||
|
|
||||||
|
TupleInObject = object
|
||||||
|
size = 777
|
||||||
|
data: ObjectTuple
|
||||||
|
|
||||||
|
Ref = ref object of ObjectBase
|
||||||
|
|
||||||
|
RefInt = ref object of Ref
|
||||||
|
data = 73
|
||||||
|
|
||||||
|
Ref2 = ref object of ObjectBase
|
||||||
|
|
||||||
|
RefInt2 = ref object of Ref
|
||||||
|
data = 73
|
||||||
|
|
||||||
|
var t {.threadvar.}: Default
|
||||||
|
# var m1, m2 {.threadvar.}: Default
|
||||||
|
|
||||||
|
block:
|
||||||
|
doAssert t.se == 0'i32
|
||||||
|
|
||||||
|
block: # ARC/ORC cannot bind destructors twice, so it cannot
|
||||||
|
# be moved into main
|
||||||
|
block:
|
||||||
|
var x: Ref
|
||||||
|
new(x)
|
||||||
|
doAssert x.value == 12, "Ref.value = " & $x.value
|
||||||
|
|
||||||
|
var y: RefInt
|
||||||
|
new(y)
|
||||||
|
doAssert y.value == 12
|
||||||
|
doAssert y.data == 73
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: Ref2
|
||||||
|
new(x, proc (x: Ref2) {.nimcall.} = discard "call Ref")
|
||||||
|
doAssert x.value == 12, "Ref.value = " & $x.value
|
||||||
|
|
||||||
|
proc call(x: RefInt2) =
|
||||||
|
discard "call RefInt"
|
||||||
|
|
||||||
|
var y: RefInt2
|
||||||
|
new(y, call)
|
||||||
|
doAssert y.value == 12
|
||||||
|
doAssert y.data == 73
|
||||||
|
|
||||||
|
template main {.dirty.} =
|
||||||
|
block: # bug #16744
|
||||||
|
type
|
||||||
|
R = range[1..10]
|
||||||
|
Obj = object
|
||||||
|
r: R
|
||||||
|
|
||||||
|
var
|
||||||
|
rVal: R # Works fine
|
||||||
|
objVal: Obj
|
||||||
|
|
||||||
|
doAssert rVal == 0 # it should be 1
|
||||||
|
doAssert objVal.r == 1
|
||||||
|
|
||||||
|
block: # bug #3608
|
||||||
|
type
|
||||||
|
abc = ref object
|
||||||
|
w: range[2..100]
|
||||||
|
|
||||||
|
proc createABC(): abc =
|
||||||
|
new(result)
|
||||||
|
result.w = 20
|
||||||
|
|
||||||
|
doAssert createABC().w == 20
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = new ObjectBase
|
||||||
|
doAssert x.value == 12
|
||||||
|
|
||||||
|
proc hello(): ref ObjectBase =
|
||||||
|
new result
|
||||||
|
|
||||||
|
let z = hello()
|
||||||
|
doAssert z.value == 12
|
||||||
|
|
||||||
|
block:
|
||||||
|
var base: ObjectBase
|
||||||
|
var x: ObjectBaseDistinct = ObjectBaseDistinct(base)
|
||||||
|
doAssert ObjectBase(x).value == 12
|
||||||
|
let y = ObjectBaseDistinct(default(ObjectBase))
|
||||||
|
doAssert ObjectBase(y).value == 12
|
||||||
|
|
||||||
|
proc hello(): ObjectBaseDistinct =
|
||||||
|
result = ObjectBaseDistinct(default(ObjectBase))
|
||||||
|
|
||||||
|
let z = hello()
|
||||||
|
doAssert ObjectBase(z).value == 12
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: DinstinctInObject
|
||||||
|
x.data = ObjectBaseDistinct(default(ObjectBase))
|
||||||
|
|
||||||
|
doAssert ObjectBase(x.data).value == 12
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: Object
|
||||||
|
doAssert x.value == 12
|
||||||
|
doAssert x.time == 1.2
|
||||||
|
doAssert x.scale == 1
|
||||||
|
|
||||||
|
let y = default(Object)
|
||||||
|
doAssert y.value == 12
|
||||||
|
doAssert y.time == 1.2
|
||||||
|
doAssert y.scale == 1
|
||||||
|
|
||||||
|
var x1, x2, x3: Object
|
||||||
|
doAssert x1.value == 12
|
||||||
|
doAssert x1.time == 1.2
|
||||||
|
doAssert x1.scale == 1
|
||||||
|
doAssert x2.value == 12
|
||||||
|
doAssert x2.time == 1.2
|
||||||
|
doAssert x2.scale == 1
|
||||||
|
doAssert x3.value == 12
|
||||||
|
doAssert x3.time == 1.2
|
||||||
|
doAssert x3.scale == 1
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = new Object
|
||||||
|
doAssert x[] == default(Object)
|
||||||
|
|
||||||
|
block:
|
||||||
|
var 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: Object3
|
||||||
|
doAssert x.obj.name.value == 12
|
||||||
|
doAssert x.obj.name.time == 1.2
|
||||||
|
doAssert x.obj.name.scale == 1
|
||||||
|
|
||||||
|
when nimvm:
|
||||||
|
discard "fixme"
|
||||||
|
else:
|
||||||
|
when defined(gcArc) or defined(gcOrc):
|
||||||
|
block: #seq
|
||||||
|
var x = newSeq[Object](10)
|
||||||
|
let y = x[0]
|
||||||
|
doAssert y.value == 12
|
||||||
|
doAssert y.time == 1.2
|
||||||
|
doAssert y.scale == 1
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: seq[Object]
|
||||||
|
setLen(x, 5)
|
||||||
|
let y = x[^1]
|
||||||
|
doAssert y.value == 12
|
||||||
|
doAssert y.time == 1.2
|
||||||
|
doAssert y.scale == 1
|
||||||
|
|
||||||
|
block: # array
|
||||||
|
var x: array[10, Object]
|
||||||
|
let y = x[0]
|
||||||
|
doAssert y.value == 12
|
||||||
|
doAssert y.time == 1.2
|
||||||
|
doAssert y.scale == 1
|
||||||
|
|
||||||
|
block: # array
|
||||||
|
var x {.noinit.}: array[10, Object]
|
||||||
|
discard x
|
||||||
|
|
||||||
|
block: # tuple
|
||||||
|
var x: ObjectTuple
|
||||||
|
doAssert x.base.value == 12
|
||||||
|
doAssert x.typ == 0
|
||||||
|
doAssert x.obj.time == 1.2
|
||||||
|
doAssert x.obj.date == 0
|
||||||
|
doAssert x.obj.scale == 1
|
||||||
|
doAssert x.obj.value == 12
|
||||||
|
|
||||||
|
block: # tuple in object
|
||||||
|
var x: TupleInObject
|
||||||
|
doAssert x.data.base.value == 12
|
||||||
|
doAssert x.data.typ == 0
|
||||||
|
doAssert x.data.obj.time == 1.2
|
||||||
|
doAssert x.data.obj.date == 0
|
||||||
|
doAssert x.data.obj.scale == 1
|
||||||
|
doAssert x.data.obj.value == 12
|
||||||
|
doAssert x.size == 777
|
||||||
|
|
||||||
|
type
|
||||||
|
ObjectArray = object
|
||||||
|
data: array[10, Object]
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: ObjectArray
|
||||||
|
let y = x.data[0]
|
||||||
|
doAssert y.value == 12
|
||||||
|
doAssert y.time == 1.2
|
||||||
|
doAssert y.scale == 1
|
||||||
|
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: PrellDeque[int]
|
||||||
|
doAssert x.pendingTasks == 0
|
||||||
|
|
||||||
|
type
|
||||||
|
Color = enum
|
||||||
|
Red, Blue, Yellow
|
||||||
|
|
||||||
|
ObjectVarint = object
|
||||||
|
case kind: Color
|
||||||
|
of Red:
|
||||||
|
data: int = 10
|
||||||
|
of Blue:
|
||||||
|
fill = "123"
|
||||||
|
of Yellow:
|
||||||
|
time = 1.8'f32
|
||||||
|
|
||||||
|
ObjectVarint1 = object
|
||||||
|
case kind: Color = Blue
|
||||||
|
of Red:
|
||||||
|
data1: int = 10
|
||||||
|
of Blue:
|
||||||
|
fill2 = "123"
|
||||||
|
cry: float
|
||||||
|
of Yellow:
|
||||||
|
time3 = 1.8'f32
|
||||||
|
him: int
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = ObjectVarint(kind: Red)
|
||||||
|
doAssert x.kind == Red
|
||||||
|
doAssert x.data == 10
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = ObjectVarint(kind: Blue)
|
||||||
|
doAssert x.kind == Blue
|
||||||
|
doAssert x.fill == "123"
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = ObjectVarint(kind: Yellow)
|
||||||
|
doAssert x.kind == Yellow
|
||||||
|
doAssert typeof(x.time) is float32
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: ObjectVarint1
|
||||||
|
doAssert x.kind == Blue
|
||||||
|
doAssert x.fill2 == "123"
|
||||||
|
x.cry = 326
|
||||||
|
|
||||||
|
type
|
||||||
|
ObjectVarint2 = object
|
||||||
|
case kind: Color
|
||||||
|
of Red:
|
||||||
|
data: int = 10
|
||||||
|
of Blue:
|
||||||
|
fill = "123"
|
||||||
|
of Yellow:
|
||||||
|
time = 1.8'f32
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = ObjectVarint2(kind: Blue)
|
||||||
|
doAssert x.fill == "123"
|
||||||
|
|
||||||
|
block:
|
||||||
|
type
|
||||||
|
Color = enum
|
||||||
|
Red, Blue, Yellow
|
||||||
|
|
||||||
|
type
|
||||||
|
ObjectVarint3 = object # fixme it doesn't work with static
|
||||||
|
case kind: Color = Blue
|
||||||
|
of Red:
|
||||||
|
data1: int = 10
|
||||||
|
of Blue:
|
||||||
|
case name: Color = Blue
|
||||||
|
of Blue:
|
||||||
|
go = 12
|
||||||
|
else:
|
||||||
|
temp = 66
|
||||||
|
fill2 = "123"
|
||||||
|
cry: float
|
||||||
|
of Yellow:
|
||||||
|
time3 = 1.8'f32
|
||||||
|
him: int
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: ObjectVarint3
|
||||||
|
doAssert x.kind == Blue
|
||||||
|
doAssert x.name == Blue
|
||||||
|
doAssert x.go == 12
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x = ObjectVarint3(kind: Blue, name: Red, temp: 99)
|
||||||
|
doAssert x.kind == Blue
|
||||||
|
doAssert x.name == Red
|
||||||
|
doAssert x.temp == 99
|
||||||
|
|
||||||
|
block:
|
||||||
|
type
|
||||||
|
Default = tuple
|
||||||
|
id: int = 1
|
||||||
|
obj: ObjectBase
|
||||||
|
name: string
|
||||||
|
|
||||||
|
Class = object
|
||||||
|
def: Default
|
||||||
|
|
||||||
|
Member = object
|
||||||
|
def: Default = (id: 777, obj: ObjectBase(), name: "fine")
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: Default
|
||||||
|
doAssert x.id == 1
|
||||||
|
doAssert x.obj == default(ObjectBase)
|
||||||
|
doAssert x.name == ""
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x: Class
|
||||||
|
doAssert x.def == default(Default)
|
||||||
|
doAssert x.def.id == 1
|
||||||
|
doAssert x.def.obj == default(ObjectBase)
|
||||||
|
doAssert x.def.name == ""
|
||||||
|
|
||||||
|
when not defined(cpp):
|
||||||
|
block:
|
||||||
|
var x: Member
|
||||||
|
doAssert x.def.id == 777
|
||||||
|
doAssert x.def.obj == default(ObjectBase)
|
||||||
|
doAssert x.def.name == "fine"
|
||||||
|
|
||||||
|
block:
|
||||||
|
var x {.noinit.} = 12
|
||||||
|
doAssert x == 12
|
||||||
|
|
||||||
|
type
|
||||||
|
Pure = object
|
||||||
|
id: int = 12
|
||||||
|
|
||||||
|
var y {.noinit.}: Pure
|
||||||
|
doAssert y.id == 0
|
||||||
|
|
||||||
|
var z {.noinit.}: Pure = Pure(id: 77)
|
||||||
|
doAssert z.id == 77
|
||||||
|
|
||||||
|
|
||||||
|
proc main1 =
|
||||||
|
var my = @[1, 2, 3, 4, 5]
|
||||||
|
my.setLen(0)
|
||||||
|
my.setLen(5)
|
||||||
|
doAssert my == @[0, 0, 0, 0, 0]
|
||||||
|
|
||||||
|
proc main2 =
|
||||||
|
var my = "hello"
|
||||||
|
my.setLen(0)
|
||||||
|
my.setLen(5)
|
||||||
|
doAssert $(@my) == """@['\x00', '\x00', '\x00', '\x00', '\x00']"""
|
||||||
|
|
||||||
|
when defined(gcArc) or defined(gcOrc):
|
||||||
|
main1()
|
||||||
|
main2()
|
||||||
|
|
||||||
|
static: main()
|
||||||
|
main()
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
|
disabled: "i386"
|
||||||
matrix: "-d:ssl"
|
matrix: "-d:ssl"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue