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:
ringabout 2022-10-04 18:45:10 +08:00 • committed by GitHub
commit f89ba2c951
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 727 additions and 80 deletions

View file

@ -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

View file

@ -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)

View file

@ -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:

View file

@ -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"

View file

@ -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)

View file

@ -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) =

View file

@ -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)

View file

@ -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])

View file

@ -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

View file

@ -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:

View file

@ -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,6 +292,7 @@ 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)
if not isDefined(c.config, "nimPreviewRangeDefault"):
let n = result.n let n = result.n
if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0: if n[0].kind in {nkCharLit..nkUInt64Lit} and n[0].intVal > 0:
incl(result.flags, tfRequiresInit) incl(result.flags, tfRequiresInit)
@ -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

View file

@ -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:

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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")

View file

@ -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)

View file

@ -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,

View 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

View 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()

View file

@ -1,4 +1,5 @@
discard """ discard """
disabled: "i386"
matrix: "-d:ssl" matrix: "-d:ssl"
""" """