mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-20 01:48:31 +00:00
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:
@@ -511,6 +511,7 @@ type
|
||||
nfFirstWrite # this node is a first write
|
||||
nfFirstWrite2 # alternative first write implementation
|
||||
nfHasComment # node has a comment
|
||||
nfUseDefaultField # node has a default value (object constructor)
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45)
|
||||
@@ -713,7 +714,7 @@ type
|
||||
mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2,
|
||||
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
|
||||
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
|
||||
mSymIsInstantiationOf, mNodeId, mPrivateAccess
|
||||
mSymIsInstantiationOf, mNodeId, mPrivateAccess, mZeroDefault
|
||||
|
||||
|
||||
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",
|
||||
[mangleDynLibProc(prc), getTypeDesc(p.module, prc.loc.t), getModuleDllPath(p.module, prc)])
|
||||
genCall(p, e, d)
|
||||
of mDefault: genDefault(p, e, d)
|
||||
of mDefault, mZeroDefault: genDefault(p, e, d)
|
||||
of mReset: genReset(p, e)
|
||||
of mEcho: genEcho(p, e[1].skipConv)
|
||||
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 mNewSeqOfCap: unaryExpr(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 mEcho: genEcho(p, n, r)
|
||||
of mNLen..mNError, mSlurp, mStaticExec:
|
||||
@@ -2342,7 +2342,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
gen(p, val, a)
|
||||
var f = it[0].sym
|
||||
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)
|
||||
if a.typ == etyBaseIndex:
|
||||
|
||||
@@ -6,6 +6,7 @@ define:booting
|
||||
define:nimcore
|
||||
define:nimPreviewFloatRoundtrip
|
||||
define:nimPreviewSlimSystem
|
||||
define:nimPreviewRangeDefault
|
||||
threads:off
|
||||
|
||||
#import:"$projectpath/testability"
|
||||
|
||||
@@ -1960,16 +1960,12 @@ proc parseObjectCase(p: var Parser): PNode =
|
||||
#| objectBranches = objectBranch (IND{=} objectBranch)*
|
||||
#| (IND{=} 'elif' expr colcom objectPart)*
|
||||
#| (IND{=} 'else' colcom objectPart)?
|
||||
#| objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
|
||||
#| objectCase = 'case' declColonEquals ':'? COMMENT?
|
||||
#| (IND{>} objectBranches DED
|
||||
#| | IND{=} objectBranches)
|
||||
result = newNodeP(nkRecCase, p)
|
||||
getTokNoInd(p)
|
||||
var a = newNodeP(nkIdentDefs, p)
|
||||
a.add(identWithPragma(p))
|
||||
eat(p, tkColon)
|
||||
a.add(parseTypeDesc(p))
|
||||
a.add(p.emptyNode)
|
||||
var a = parseIdentColonEquals(p, {withPragma})
|
||||
result.add(a)
|
||||
if p.tok.tokType == tkColon: getTok(p)
|
||||
flexComment(p, result)
|
||||
|
||||
117
compiler/sem.nim
117
compiler/sem.nim
@@ -538,6 +538,123 @@ proc setGenericParamsMisc(c: PContext; n: PNode) =
|
||||
else:
|
||||
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
|
||||
|
||||
proc addCodeForGenerics(c: PContext, n: PNode) =
|
||||
|
||||
@@ -926,8 +926,6 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||
rawAddSon(typ, result.typ)
|
||||
result.typ = typ
|
||||
|
||||
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode
|
||||
|
||||
proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
|
||||
t: PType): TCandidate =
|
||||
initCandidate(c, result, t)
|
||||
|
||||
@@ -10,6 +10,26 @@
|
||||
# This include file implements the semantic checking for magics.
|
||||
# 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 =
|
||||
let x = semExprWithType(c, n)
|
||||
if x.kind == nkSym:
|
||||
@@ -494,13 +514,20 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
|
||||
bindTypeHook(c, transFormedSym, n, attachedDestructor)
|
||||
else:
|
||||
bindTypeHook(c, turnFinalizerIntoDestructor(c, fin, n.info), n, attachedDestructor)
|
||||
result = n
|
||||
result = addDefaultFieldForNew(c, n)
|
||||
|
||||
proc semPrivateAccess(c: PContext, n: PNode): PNode =
|
||||
let t = n[1].typ[0].toObjectFromRefPtrGeneric
|
||||
c.currentScope.allowPrivateAccess.add t.sym
|
||||
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,
|
||||
flags: TExprFlags): PNode =
|
||||
## This is the preferred code point to implement magics.
|
||||
@@ -559,6 +586,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
result = n
|
||||
else:
|
||||
result = plugin(c, n)
|
||||
of mNew:
|
||||
result = addDefaultFieldForNew(c, n)
|
||||
of mNewFinalize:
|
||||
result = semNewFinalize(c, n)
|
||||
of mDestroy:
|
||||
@@ -587,11 +616,13 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
if seqType.kind == tySequence and seqType.base.requiresInit:
|
||||
message(c.config, n.info, warnUnsafeSetLen, typeToString(seqType.base))
|
||||
of mDefault:
|
||||
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))
|
||||
result = checkDefault(c, n)
|
||||
let typ = result[^1].typ.skipTypes({tyTypeDesc})
|
||||
let defaultExpr = defaultNodeField(c, result[^1], typ)
|
||||
if defaultExpr != nil:
|
||||
result = defaultExpr
|
||||
of mZeroDefault:
|
||||
result = checkDefault(c, n)
|
||||
of mIsolate:
|
||||
if not checkIsolate(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
|
||||
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) =
|
||||
case newStatus
|
||||
of initConflict:
|
||||
@@ -72,7 +76,9 @@ proc semConstrField(c: PContext, flags: TExprFlags,
|
||||
let assignment = locateFieldInInitExpr(c, field, initExpr)
|
||||
if assignment != nil:
|
||||
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,
|
||||
"the field '$1' is not accessible." % [field.name.s])
|
||||
return
|
||||
@@ -85,15 +91,6 @@ proc semConstrField(c: PContext, flags: TExprFlags,
|
||||
assignment.flags.incl nfSem
|
||||
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,
|
||||
isStmtBranch: bool): IntSet =
|
||||
if caseNode[caseIdx].kind == nkOfBranch:
|
||||
@@ -155,18 +152,14 @@ proc collectMissingFields(c: PContext, fieldsRecList: PNode,
|
||||
if assignment == nil:
|
||||
constrCtx.missingFields.add r.sym
|
||||
|
||||
|
||||
proc semConstructFields(c: PContext, n: PNode,
|
||||
constrCtx: var ObjConstrContext,
|
||||
flags: TExprFlags): InitStatus =
|
||||
result = initUnknown
|
||||
|
||||
proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
|
||||
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
for field in n:
|
||||
let status = semConstructFields(c, field, constrCtx, flags)
|
||||
mergeInitStatus(result, status)
|
||||
|
||||
let (subSt, subDf) = semConstructFields(c, field, constrCtx, flags)
|
||||
result.status.mergeInitStatus subSt
|
||||
result.defaults.add subDf
|
||||
of nkRecCase:
|
||||
template fieldsPresentInBranch(branchIdx: int): string =
|
||||
let branch = n[branchIdx]
|
||||
@@ -184,9 +177,9 @@ proc semConstructFields(c: PContext, n: PNode,
|
||||
|
||||
for i in 1..<n.len:
|
||||
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}:
|
||||
mergeInitStatus(result, status)
|
||||
result.status.mergeInitStatus status
|
||||
if selectedBranch != -1:
|
||||
let prevFields = fieldsPresentInBranch(selectedBranch)
|
||||
let currentFields = fieldsPresentInBranch(i)
|
||||
@@ -194,7 +187,7 @@ proc semConstructFields(c: PContext, n: PNode,
|
||||
("The fields '$1' and '$2' cannot be initialized together, " &
|
||||
"because they are from conflicting branches in the case object.") %
|
||||
[prevFields, currentFields])
|
||||
result = initConflict
|
||||
result.status = initConflict
|
||||
else:
|
||||
selectedBranch = i
|
||||
|
||||
@@ -206,7 +199,7 @@ proc semConstructFields(c: PContext, n: PNode,
|
||||
("cannot prove that it's safe to initialize $1 with " &
|
||||
"the runtime value for the discriminator '$2' ") %
|
||||
[fields, discriminator.sym.name.s])
|
||||
mergeInitStatus(result, initNone)
|
||||
mergeInitStatus(result.status, initNone)
|
||||
|
||||
template wrongBranchError(i) =
|
||||
if c.inUncheckedAssignSection == 0:
|
||||
@@ -289,13 +282,16 @@ proc semConstructFields(c: PContext, n: PNode,
|
||||
else:
|
||||
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
|
||||
# that were not initialized may be mandatory. We must check for this:
|
||||
if result == initPartial:
|
||||
if result.status == initPartial:
|
||||
collectMissingFields branchNode
|
||||
|
||||
else:
|
||||
result = initNone
|
||||
result.status = initNone
|
||||
let discriminatorVal = semConstrField(c, flags + {efPreferStatic},
|
||||
discriminator.sym,
|
||||
constrCtx.initExpr)
|
||||
@@ -308,33 +304,41 @@ proc semConstructFields(c: PContext, n: PNode,
|
||||
let matchedBranch = n.pickCaseBranch defaultValue
|
||||
collectMissingFields matchedBranch
|
||||
else:
|
||||
result = initPartial
|
||||
result.status = initPartial
|
||||
if discriminatorVal.kind == nkIntLit:
|
||||
# When the discriminator is a compile-time value, we also know
|
||||
# which branch will be selected:
|
||||
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:
|
||||
# All bets are off. If any of the branches has a mandatory
|
||||
# fields we must produce an error:
|
||||
for i in 1..<n.len: collectMissingFields n[i]
|
||||
|
||||
of nkSym:
|
||||
let field = n.sym
|
||||
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:
|
||||
internalAssert c.config, false
|
||||
|
||||
proc semConstructTypeAux(c: PContext,
|
||||
constrCtx: var ObjConstrContext,
|
||||
flags: TExprFlags): InitStatus =
|
||||
result = initUnknown
|
||||
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
|
||||
result.status = initUnknown
|
||||
var t = constrCtx.typ
|
||||
while true:
|
||||
let status = semConstructFields(c, t.n, constrCtx, flags)
|
||||
mergeInitStatus(result, status)
|
||||
let (status, defaults) = semConstructFields(c, t.n, constrCtx, flags)
|
||||
result.status.mergeInitStatus status
|
||||
result.defaults.add defaults
|
||||
if status in {initPartial, initNone, initUnknown}:
|
||||
collectMissingFields c, t.n, constrCtx
|
||||
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 =
|
||||
var t = semTypeNode(c, n[0], nil)
|
||||
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:
|
||||
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
|
||||
# branches will be reported as an error):
|
||||
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
|
||||
|
||||
# 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 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:
|
||||
def = semExprWithType(c, a[^1], {}, typ)
|
||||
|
||||
@@ -680,6 +685,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
addToVarSection(c, result, n, a)
|
||||
continue
|
||||
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)
|
||||
onDef(a[j].info, v)
|
||||
if sfGenSym notin v.flags:
|
||||
|
||||
@@ -23,7 +23,6 @@ const
|
||||
errXExpectsOneTypeParam = "'$1' expects one type parameter"
|
||||
errArrayExpectsTwoTypeParams = "array expects two type parameters"
|
||||
errInvalidVisibilityX = "invalid visibility: '$1'"
|
||||
errInitHereNotAllowed = "initialization not allowed here"
|
||||
errXCannotBeAssignedTo = "'$1' cannot be assigned to"
|
||||
errIteratorNotAllowed = "iterators can only be defined at the module's top level"
|
||||
errXNeedsReturnType = "$1 needs a return type"
|
||||
@@ -293,17 +292,18 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
|
||||
if n.len == 2:
|
||||
if isRange(n[1]):
|
||||
result = semRangeAux(c, n[1], prev)
|
||||
let n = result.n
|
||||
if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0:
|
||||
incl(result.flags, tfRequiresInit)
|
||||
elif n[1].kind in {nkCharLit..nkUInt64Lit} and n[1].intVal < 0:
|
||||
incl(result.flags, tfRequiresInit)
|
||||
elif n[0].kind in {nkFloatLit..nkFloat64Lit} and
|
||||
n[0].floatVal > 0.0:
|
||||
incl(result.flags, tfRequiresInit)
|
||||
elif n[1].kind in {nkFloatLit..nkFloat64Lit} and
|
||||
n[1].floatVal < 0.0:
|
||||
incl(result.flags, tfRequiresInit)
|
||||
if not isDefined(c.config, "nimPreviewRangeDefault"):
|
||||
let n = result.n
|
||||
if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0:
|
||||
incl(result.flags, tfRequiresInit)
|
||||
elif n[1].kind in {nkCharLit..nkUInt64Lit} and n[1].intVal < 0:
|
||||
incl(result.flags, tfRequiresInit)
|
||||
elif n[0].kind in {nkFloatLit..nkFloat64Lit} and
|
||||
n[0].floatVal > 0.0:
|
||||
incl(result.flags, tfRequiresInit)
|
||||
elif n[1].kind in {nkFloatLit..nkFloat64Lit} and
|
||||
n[1].floatVal < 0.0:
|
||||
incl(result.flags, tfRequiresInit)
|
||||
else:
|
||||
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")
|
||||
@@ -481,13 +481,19 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
var a = n[i]
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a, 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)
|
||||
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:
|
||||
localError(c.config, a.info, errTypeExpected)
|
||||
typ = errorType(c)
|
||||
if a[^1].kind != nkEmpty:
|
||||
localError(c.config, a[^1].info, errInitHereNotAllowed)
|
||||
for j in 0..<a.len - 2:
|
||||
var field = newSymG(skField, a[j], c)
|
||||
field.typ = typ
|
||||
@@ -496,7 +502,11 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
if containsOrIncl(check, field.name.id):
|
||||
localError(c.config, a[j].info, "attempt to redefine: '" & field.name.s & "'")
|
||||
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)
|
||||
styleCheckDef(c, a[j].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
|
||||
if father.kind != nkRecList and n.len >= 4: a = newNodeI(nkRecList, n.info)
|
||||
else: a = newNodeI(nkEmpty, n.info)
|
||||
if n[^1].kind != nkEmpty:
|
||||
localError(c.config, n[^1].info, errInitHereNotAllowed)
|
||||
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)
|
||||
typ = errorType(c)
|
||||
else:
|
||||
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)
|
||||
var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner
|
||||
else: rectype.sym
|
||||
@@ -834,8 +851,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
inc(pos)
|
||||
if containsOrIncl(check, f.name.id):
|
||||
localError(c.config, info, "attempt to redefine: '" & f.name.s & "'")
|
||||
if a.kind == nkEmpty: father.add newSymNode(f)
|
||||
else: a.add newSymNode(f)
|
||||
let fSym = 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)
|
||||
onDef(f.info, f)
|
||||
if a.kind != nkEmpty: father.add a
|
||||
|
||||
@@ -46,7 +46,6 @@ type
|
||||
module: PSym
|
||||
transCon: PTransCon # top of a TransCon stack
|
||||
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'
|
||||
deferDetected, tooEarly: bool
|
||||
graph: ModuleGraph
|
||||
@@ -1061,6 +1060,13 @@ proc transform(c: PTransf, n: PNode): PNode =
|
||||
result = n
|
||||
of nkExceptBranch:
|
||||
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:
|
||||
result = transformSons(c, n)
|
||||
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, opcNodeToReg, d, d)
|
||||
c.genAsgnPatch(n[1], d)
|
||||
of mDefault:
|
||||
of mDefault, mZeroDefault:
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABx(n, ldNullOpcode(n.typ), dest, c.genType(n.typ))
|
||||
of mOf, mIs:
|
||||
|
||||
@@ -22,6 +22,7 @@ hint[LineTooLong]=off
|
||||
#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
|
||||
|
||||
@@ -166,7 +166,7 @@ objectBranch = 'of' exprList colcom objectPart
|
||||
objectBranches = objectBranch (IND{=} objectBranch)*
|
||||
(IND{=} 'elif' expr colcom objectPart)*
|
||||
(IND{=} 'else' colcom objectPart)?
|
||||
objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
|
||||
objectCase = 'case' declColonEquals ':'? COMMENT?
|
||||
(IND{>} objectBranches DED
|
||||
| IND{=} objectBranches)
|
||||
objectPart = IND{>} objectPart^+IND{=} DED
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
|
||||
include "system/basic_types"
|
||||
|
||||
func zeroDefault*[T](_: typedesc[T]): T {.magic: "ZeroDefault".} =
|
||||
## returns the default value of the type `T`.
|
||||
|
||||
include "system/compilation"
|
||||
|
||||
{.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
|
||||
# via: `template default*[T](t: typedesc[T]): T = (var v: T; v)`
|
||||
|
||||
|
||||
proc reset*[T](obj: var T) {.noSideEffect.} =
|
||||
## Resets an object `obj` to its default value.
|
||||
obj = default(typeof(obj))
|
||||
@@ -2753,3 +2757,8 @@ when notJSnotNims and not defined(nimSeqsV2):
|
||||
moveMem(addr y[0], addr x[0], x.len)
|
||||
assert y == "abcgh"
|
||||
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:
|
||||
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T)))
|
||||
xu.len = newlen
|
||||
for i in oldLen..<newlen:
|
||||
xu.p.data[i] = default(T)
|
||||
|
||||
proc newSeq[T](s: var seq[T], len: Natural) =
|
||||
shrink(s, 0)
|
||||
|
||||
@@ -40,5 +40,6 @@ switch("define", "nimPreviewFloatRoundtrip")
|
||||
switch("define", "nimPreviewDotLikeOps")
|
||||
switch("define", "nimPreviewJsonutilsHoleyEnum")
|
||||
switch("define", "nimPreviewHashRef")
|
||||
switch("define", "nimPreviewRangeDefault")
|
||||
when defined(windows):
|
||||
switch("tlsEmulation", "off")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
cmd: "nim check $file"
|
||||
cmd: "nim check --mm:refc $file"
|
||||
errormsg: "'t' has unspecified generic parameters"
|
||||
nimout: '''
|
||||
t5167_5.nim(10, 16) Error: expression 'system' has no type (or is ambiguous)
|
||||
|
||||
@@ -303,7 +303,7 @@ g = {},
|
||||
h = {},
|
||||
i = ["", "", ""],
|
||||
j = @[],
|
||||
k = 0,
|
||||
k = -12,
|
||||
l = [a = "",
|
||||
b = @[]],
|
||||
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 """
|
||||
disabled: "i386"
|
||||
matrix: "-d:ssl"
|
||||
"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user