first steps of making 'opt' a first class type for Nim

This commit is contained in:
Andreas Rumpf 2017-09-25 13:19:36 +02:00
commit f7f3a25be8
20 changed files with 198 additions and 35 deletions

View file

@ -354,7 +354,7 @@ type
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
tyFloat, tyFloat32, tyFloat64, tyFloat128, tyFloat, tyFloat32, tyFloat64, tyFloat128,
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64, tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
tyUnused0, tyUnused1, tyUnused2, tyOptAsRef, tyUnused1, tyUnused2,
tyVarargs, tyVarargs,
tyUnused, tyUnused,
tyProxy # used as errornous type (for idetools) tyProxy # used as errornous type (for idetools)

View file

@ -121,7 +121,8 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash;
var c: TTraversalClosure var c: TTraversalClosure
var p = newProc(nil, m) var p = newProc(nil, m)
result = "Marker_" & getTypeName(m, origTyp, sig) result = "Marker_" & getTypeName(m, origTyp, sig)
let typ = origTyp.skipTypes(abstractInst) var typ = origTyp.skipTypes(abstractInst)
if typ.kind == tyOpt: typ = optLowering(typ)
case reason case reason
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n" of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"

View file

@ -183,7 +183,7 @@ proc mapType(typ: PType): TCTypeKind =
of 8: result = ctInt64 of 8: result = ctInt64
else: internalError("mapType") else: internalError("mapType")
of tyRange: result = mapType(typ.sons[0]) of tyRange: result = mapType(typ.sons[0])
of tyPtr, tyVar, tyRef: of tyPtr, tyVar, tyRef, tyOptAsRef:
var base = skipTypes(typ.lastSon, typedescInst) var base = skipTypes(typ.lastSon, typedescInst)
case base.kind case base.kind
of tyOpenArray, tyArray, tyVarargs: result = ctPtrToArray of tyOpenArray, tyArray, tyVarargs: result = ctPtrToArray
@ -194,6 +194,13 @@ proc mapType(typ: PType): TCTypeKind =
else: result = ctPtr else: result = ctPtr
of tyPointer: result = ctPtr of tyPointer: result = ctPtr
of tySequence: result = ctNimSeq of tySequence: result = ctNimSeq
of tyOpt:
case optKind(typ)
of oBool: result = ctStruct
of oNil, oPtr: result = ctPtr
of oEnum:
# The 'nil' value is always negative, so we always use a signed integer
result = if getSize(typ.sons[0]) == 8: ctInt64 else: ctInt32
of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct
of tyString: result = ctNimStr of tyString: result = ctNimStr
of tyCString: result = ctCString of tyCString: result = ctCString
@ -350,7 +357,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
if result != nil: return if result != nil: return
result = getTypePre(m, typ, sig) result = getTypePre(m, typ, sig)
if result != nil: return if result != nil: return
let concrete = typ.skipTypes(abstractInst) let concrete = typ.skipTypes(abstractInst + {tyOpt})
case concrete.kind case concrete.kind
of tySequence, tyTuple, tyObject: of tySequence, tyTuple, tyObject:
result = getTypeName(m, typ, sig) result = getTypeName(m, typ, sig)
@ -376,6 +383,12 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
of tySequence: of tySequence:
result = getTypeForward(m, t, hashType(t)) & "*" result = getTypeForward(m, t, hashType(t)) & "*"
pushType(m, t) pushType(m, t)
of tyOpt:
if optKind(etB) == oPtr:
result = getTypeForward(m, t, hashType(t)) & "*"
pushType(m, t)
else:
result = getTypeDescAux(m, t, check)
else: else:
result = getTypeDescAux(m, t, check) result = getTypeDescAux(m, t, check)
@ -506,7 +519,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
addf(result, "$1 $2[SEQ_DECL_SIZE];$n", addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
[getTypeDescAux(m, fieldType.elemType, check), sname]) [getTypeDescAux(m, fieldType.elemType, check), sname])
elif fieldType.kind == tySequence: elif fieldType.kind in {tySequence, tyOpt}:
# we need to use a weak dependency here for trecursive_table. # we need to use a weak dependency here for trecursive_table.
addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname]) addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
elif field.bitsize != 0: elif field.bitsize != 0:
@ -625,7 +638,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
excl(check, t.id) excl(check, t.id)
return return
case t.kind case t.kind
of tyRef, tyPtr, tyVar: of tyRef, tyOptAsRef, tyPtr, tyVar:
var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and
compileToCpp(m): "&" else: "*" compileToCpp(m): "&" else: "*"
var et = origTyp.skipTypes(abstractInst).lastSon var et = origTyp.skipTypes(abstractInst).lastSon
@ -652,6 +665,21 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
result = name & "*" & star result = name & "*" & star
m.typeCache[sig] = result m.typeCache[sig] = result
pushType(m, et) pushType(m, et)
of tyOpt:
if etB.sons[0].kind in {tyObject, tyTuple}:
let name = getTypeForward(m, et, hashType et)
result = name & "*" & star
m.typeCache[sig] = result
pushType(m, et)
elif optKind(etB) == oBool:
let name = getTypeForward(m, et, hashType et)
result = name & "*"
m.typeCache[sig] = result
pushType(m, et)
else:
# else we have a strong dependency :-(
result = getTypeDescAux(m, et, check) & star
m.typeCache[sig] = result
else: else:
# else we have a strong dependency :-( # else we have a strong dependency :-(
result = getTypeDescAux(m, et, check) & star result = getTypeDescAux(m, et, check) & star
@ -727,6 +755,38 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
else: else:
result = rope("TGenericSeq") result = rope("TGenericSeq")
add(result, "*") add(result, "*")
of tyOpt:
result = cacheGetType(m.typeCache, sig)
if result == nil:
case optKind(t)
of oBool:
result = cacheGetType(m.forwTypeCache, sig)
if result == nil:
result = getTypeName(m, origTyp, sig)
addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(t), result])
m.forwTypeCache[sig] = result
appcg(m, m.s[cfsSeqTypes], "struct $2 {$n" &
" NIM_BOOL Field0;$n" &
" $1 Field1;$n" &
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
of oPtr:
let et = t.sons[0]
if et.kind in {tyTuple, tyObject}:
let name = getTypeForward(m, et, hashType et)
result = name & "*"
pushType(m, et)
else:
result = getTypeDescAux(m, t.sons[0], check) & "*"
of oNil:
result = getTypeDescAux(m, t.sons[0], check)
of oEnum:
result = getTypeName(m, origTyp, sig)
if getSize(t.sons[0]) == 8:
addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
else:
addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
m.typeCache[sig] = result
of tyArray: of tyArray:
var n: BiggestInt = lengthOrd(t) var n: BiggestInt = lengthOrd(t)
if n <= 0: n = 1 # make an array of at least one element if n <= 0: n = 1 # make an array of at least one element
@ -1114,6 +1174,8 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
proc genTypeInfo(m: BModule, t: PType): Rope = proc genTypeInfo(m: BModule, t: PType): Rope =
let origType = t let origType = t
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses) var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
if t.kind == tyOpt:
return genTypeInfo(m, optLowering(t))
let sig = hashType(origType) let sig = hashType(origType)
result = m.typeInfoMarker.getOrDefault(sig) result = m.typeInfoMarker.getOrDefault(sig)
@ -1159,7 +1221,7 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
else: else:
let x = fakeClosureType(t.owner) let x = fakeClosureType(t.owner)
genTupleInfo(m, x, x, result) genTupleInfo(m, x, x, result)
of tySequence, tyRef: of tySequence, tyRef, tyOptAsRef:
genTypeInfoAux(m, t, t, result) genTypeInfoAux(m, t, t, result)
if gSelectedGC >= gcMarkAndSweep: if gSelectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, origType, sig, tiNew) let markerProc = genTraverseProc(m, origType, sig, tiNew)

View file

@ -157,7 +157,7 @@ proc getUniqueType*(key: PType): PType =
else: else:
# ugh, we need the canon here: # ugh, we need the canon here:
result = slowSearch(key, k) result = slowSearch(key, k)
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("getUniqueType") of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("getUniqueType")
proc makeSingleLineCString*(s: string): string = proc makeSingleLineCString*(s: string): string =
result = "\"" result = "\""

View file

@ -107,3 +107,4 @@ proc initDefines*() =
defineSymbol("nimDistros") defineSymbol("nimDistros")
defineSymbol("nimHasCppDefine") defineSymbol("nimHasCppDefine")
defineSymbol("nimGenericInOutFlags") defineSymbol("nimGenericInOutFlags")
when false: defineSymbol("nimHasOpt")

View file

@ -202,7 +202,7 @@ proc mapType(typ: PType): TJSTypeKind =
else: result = etyNone else: result = etyNone
of tyProc: result = etyProc of tyProc: result = etyProc
of tyCString: result = etyString of tyCString: result = etyString
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("mapType") of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("mapType")
proc mapType(p: PProc; typ: PType): TJSTypeKind = proc mapType(p: PProc; typ: PType): TJSTypeKind =
if p.target == targetPHP: result = etyObject if p.target == targetPHP: result = etyObject

View file

@ -229,7 +229,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of tyOrdinal, tyRange, tyInferred, of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyStatic, tyVar, tyAlias: tyGenericInst, tyStatic, tyVar, tyAlias:
liftBodyAux(c, lastSon(t), body, x, y) liftBodyAux(c, lastSon(t), body, x, y)
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("liftBodyAux") of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("liftBodyAux")
proc newProcType(info: TLineInfo; owner: PSym): PType = proc newProcType(info: TLineInfo; owner: PSym): PType =
result = newType(tyProc, owner) result = newType(tyProc, owner)

View file

@ -1393,6 +1393,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of mSet: result = semSet(c, n, prev) of mSet: result = semSet(c, n, prev)
of mOrdinal: result = semOrdinal(c, n, prev) of mOrdinal: result = semOrdinal(c, n, prev)
of mSeq: result = semContainer(c, n, tySequence, "seq", prev) of mSeq: result = semContainer(c, n, tySequence, "seq", prev)
of mOpt: result = semContainer(c, n, tyOpt, "opt", prev)
of mVarargs: result = semVarargs(c, n, prev) of mVarargs: result = semVarargs(c, n, prev)
of mTypeDesc: result = makeTypeDesc(c, semTypeNode(c, n[1], nil)) of mTypeDesc: result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
of mExpr: of mExpr:

View file

@ -45,8 +45,6 @@ type
proc equalParams*(a, b: PNode): TParamsEquality proc equalParams*(a, b: PNode): TParamsEquality
# returns whether the parameter lists of the procs a, b are exactly the same # returns whether the parameter lists of the procs a, b are exactly the same
proc isOrdinalType*(t: PType): bool
proc enumHasHoles*(t: PType): bool
const const
# TODO: Remove tyTypeDesc from each abstractX and (where necessary) # TODO: Remove tyTypeDesc from each abstractX and (where necessary)
@ -129,7 +127,7 @@ proc elemType*(t: PType): PType =
else: result = t.lastSon else: result = t.lastSon
assert(result != nil) assert(result != nil)
proc isOrdinalType(t: PType): bool = proc isOrdinalType*(t: PType): bool =
assert(t != nil) assert(t != nil)
const const
# caution: uint, uint64 are no ordinal types! # caution: uint, uint64 are no ordinal types!
@ -137,7 +135,7 @@ proc isOrdinalType(t: PType): bool =
parentKinds = {tyRange, tyOrdinal, tyGenericInst, tyAlias, tyDistinct} parentKinds = {tyRange, tyOrdinal, tyGenericInst, tyAlias, tyDistinct}
t.kind in baseKinds or (t.kind in parentKinds and isOrdinalType(t.sons[0])) t.kind in baseKinds or (t.kind in parentKinds and isOrdinalType(t.sons[0]))
proc enumHasHoles(t: PType): bool = proc enumHasHoles*(t: PType): bool =
var b = t var b = t
while b.kind in {tyRange, tyGenericInst, tyAlias}: b = b.sons[0] while b.kind in {tyRange, tyGenericInst, tyAlias}: b = b.sons[0]
result = b.kind == tyEnum and tfEnumHasHoles in b.flags result = b.kind == tyEnum and tfEnumHasHoles in b.flags
@ -995,7 +993,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
cycleCheck() cycleCheck()
result = sameTypeAux(a.lastSon, b.lastSon, c) result = sameTypeAux(a.lastSon, b.lastSon, c)
of tyNone: result = false of tyNone: result = false
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("sameFlags") of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("sameFlags")
proc sameBackendType*(x, y: PType): bool = proc sameBackendType*(x, y: PType): bool =
var c = initSameTypeClosure() var c = initSameTypeClosure()
@ -1176,7 +1174,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
# for now same as error node; we say it's a valid type as it should # for now same as error node; we say it's a valid type as it should
# prevent cascading errors: # prevent cascading errors:
result = nil result = nil
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("typeAllowedAux") of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("typeAllowedAux")
proc typeAllowed*(t: PType, kind: TSymKind): PType = proc typeAllowed*(t: PType, kind: TSymKind): PType =
# returns 'nil' on success and otherwise the part of the type that is # returns 'nil' on success and otherwise the part of the type that is
@ -1187,6 +1185,63 @@ proc typeAllowed*(t: PType, kind: TSymKind): PType =
proc align(address, alignment: BiggestInt): BiggestInt = proc align(address, alignment: BiggestInt): BiggestInt =
result = (address + (alignment - 1)) and not (alignment - 1) result = (address + (alignment - 1)) and not (alignment - 1)
type
OptKind* = enum ## What to map 'opt T' to internally.
oBool ## opt[T] requires an additional 'bool' field
oNil ## opt[T] has no overhead since 'nil'
## is available
oEnum ## We can use some enum value that is not yet
## used for opt[T]
oPtr ## opt[T] actually introduces a hidden pointer
## in order for the type recursion to work
proc optKind*(typ: PType): OptKind =
## return true iff 'opt[T]' can be mapped to 'T' internally
## because we have a 'nil' value available:
assert typ.kind == tyOpt
case typ.sons[0].skipTypes(abstractInst).kind
of tyRef, tyPtr, tyProc:
result = oNil
of tyArray, tyObject, tyTuple:
result = oPtr
of tyBool: result = oEnum
of tyEnum:
assert(typ.n.sons[0].kind == nkSym)
if typ.n.sons[0].sym.position != low(int):
result = oEnum
else:
result = oBool
else:
result = oBool
proc optLowering*(typ: PType): PType =
case optKind(typ)
of oNil: result = typ.sons[0]
of oPtr:
result = newType(tyOptAsRef, typ.owner)
result.rawAddSon typ.sons[0]
of oBool:
result = newType(tyTuple, typ.owner)
result.rawAddSon newType(tyBool, typ.owner)
result.rawAddSon typ.sons[0]
of oEnum:
if lastOrd(typ) + 1 < `shl`(BiggestInt(1), 32):
result = newType(tyInt32, typ.owner)
else:
result = newType(tyInt64, typ.owner)
proc optEnumValue*(typ: PType): BiggestInt =
assert typ.kind == tyOpt
assert optKind(typ) == oEnum
let elem = typ.sons[0].skipTypes(abstractInst).kind
if elem == tyBool:
result = 2
else:
assert elem == tyEnum
assert typ.n.sons[0].sym.position != low(int)
result = typ.n.sons[0].sym.position - 1
const const
szNonConcreteType* = -3 szNonConcreteType* = -3
szIllegalRecursion* = -2 szIllegalRecursion* = -2
@ -1341,6 +1396,14 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
of tyStatic: of tyStatic:
result = if typ.n != nil: computeSizeAux(typ.lastSon, a) result = if typ.n != nil: computeSizeAux(typ.lastSon, a)
else: szUnknownSize else: szUnknownSize
of tyOpt:
case optKind(typ)
of oBool: result = computeSizeAux(lastSon(typ), a) + 1
of oEnum:
if lastOrd(typ) + 1 < `shl`(BiggestInt(1), 32): result = 4
else: result = 8
of oNil: result = computeSizeAux(lastSon(typ), a)
of oPtr: result = ptrSize
else: else:
#internalError("computeSizeAux()") #internalError("computeSizeAux()")
result = szUnknownSize result = szUnknownSize

View file

@ -314,7 +314,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
result.add atomicType("static", mNone) result.add atomicType("static", mNone)
if t.n != nil: if t.n != nil:
result.add t.n.copyTree result.add t.n.copyTree
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("mapTypeToAstX") of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("mapTypeToAstX")
proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode = proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
result = mapTypeToAstX(t, info, false, true) result = mapTypeToAstX(t, info, false, true)

View file

@ -1537,6 +1537,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
addSon(result, getNullValue(t.sons[i], info)) addSon(result, getNullValue(t.sons[i], info))
of tySet: of tySet:
result = newNodeIT(nkCurly, info, t) result = newNodeIT(nkCurly, info, t)
of tyOpt:
result = newNodeIT(nkNilLit, info, t)
else: else:
globalError(info, "cannot create null element for: " & $t.kind) globalError(info, "cannot create null element for: " & $t.kind)

View file

@ -54,6 +54,7 @@ type
akUInt16 = 42, ## any represents an unsigned in16 akUInt16 = 42, ## any represents an unsigned in16
akUInt32 = 43, ## any represents an unsigned int32 akUInt32 = 43, ## any represents an unsigned int32
akUInt64 = 44, ## any represents an unsigned int64 akUInt64 = 44, ## any represents an unsigned int64
akOpt = 44+18 ## the builtin 'opt' type.
Any* = object ## can represent any nim value; NOTE: the wrapped Any* = object ## can represent any nim value; NOTE: the wrapped
## value can be modified with its wrapper! This means ## value can be modified with its wrapper! This means

View file

@ -246,6 +246,9 @@ type
UncheckedArray* {.unchecked.}[T] = array[0, T] UncheckedArray* {.unchecked.}[T] = array[0, T]
## Array with no bounds checking ## Array with no bounds checking
when defined(nimHasOpt):
type opt*{.magic: "Opt".}[T]
proc high*[T: Ordinal](x: T): T {.magic: "High", noSideEffect.} proc high*[T: Ordinal](x: T): T {.magic: "High", noSideEffect.}
## returns the highest possible index of an array, a sequence, a string or ## returns the highest possible index of an array, a sequence, a string or
## the highest possible value of an ordinal value `x`. As a special ## the highest possible value of an ordinal value `x`. As a special

View file

@ -89,6 +89,19 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
cast[pointer](s +% i*% mt.base.size), mt.base, shallow) cast[pointer](s +% i*% mt.base.size), mt.base, shallow)
of tyRef: of tyRef:
unsureAsgnRef(cast[PPointer](dest), cast[PPointer](s)[]) unsureAsgnRef(cast[PPointer](dest), cast[PPointer](s)[])
of tyOptAsRef:
let s2 = cast[PPointer](src)[]
let d = cast[PPointer](dest)
if s2 == nil:
unsureAsgnRef(d, s2)
else:
when declared(usrToCell):
let realType = usrToCell(s2).typ
else:
let realType = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[]
else: mt.base
var z = newObj(realType, realType.base.size)
genericAssignAux(d, addr z, mt.base, shallow)
else: else:
copyMem(dest, src, mt.size) # copy raw bits copyMem(dest, src, mt.size) # copy raw bits
@ -115,6 +128,7 @@ when false:
of tyPtr: k = "ptr" of tyPtr: k = "ptr"
of tyRef: k = "ref" of tyRef: k = "ref"
of tyVar: k = "var" of tyVar: k = "var"
of tyOptAsRef: k = "optref"
of tySequence: k = "seq" of tySequence: k = "seq"
of tyProc: k = "proc" of tyProc: k = "proc"
of tyPointer: k = "range" of tyPointer: k = "range"
@ -195,7 +209,7 @@ proc genericReset(dest: pointer, mt: PNimType) =
var d = cast[ByteAddress](dest) var d = cast[ByteAddress](dest)
sysAssert(mt != nil, "genericReset 2") sysAssert(mt != nil, "genericReset 2")
case mt.kind case mt.kind
of tyString, tyRef, tySequence: of tyString, tyRef, tyOptAsRef, tySequence:
unsureAsgnRef(cast[PPointer](dest), nil) unsureAsgnRef(cast[PPointer](dest), nil)
of tyTuple: of tyTuple:
genericResetAux(dest, mt.node) genericResetAux(dest, mt.node)

View file

@ -144,7 +144,7 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
for i in 0..(mt.size div mt.base.size)-1: for i in 0..(mt.size div mt.base.size)-1:
storeAux(cast[pointer](d +% i*% mt.base.size), storeAux(cast[pointer](d +% i*% mt.base.size),
cast[pointer](s +% i*% mt.base.size), mt.base, t, mode) cast[pointer](s +% i*% mt.base.size), mt.base, t, mode)
of tyRef: of tyRef, tyOptAsRef:
var s = cast[PPointer](src)[] var s = cast[PPointer](src)[]
var x = cast[PPointer](dest) var x = cast[PPointer](dest)
if s == nil: if s == nil:

View file

@ -124,7 +124,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
for i in 0..(mt.size div mt.base.size)-1: for i in 0..(mt.size div mt.base.size)-1:
genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size), genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size),
cast[pointer](s +% i*% mt.base.size), mt.base, tab) cast[pointer](s +% i*% mt.base.size), mt.base, tab)
of tyRef: of tyRef, tyOptAsRef:
let s2 = cast[PPointer](src)[] let s2 = cast[PPointer](src)[]
if s2 == nil: if s2 == nil:
unsureAsgnRef(cast[PPointer](dest), s2) unsureAsgnRef(cast[PPointer](dest), s2)

View file

@ -349,7 +349,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
for i in 0..n.len-1: for i in 0..n.len-1:
# inlined for speed # inlined for speed
if n.sons[i].kind == nkSlot: if n.sons[i].kind == nkSlot:
if n.sons[i].typ.kind in {tyRef, tyString, tySequence}: if n.sons[i].typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}:
doOperation(cast[PPointer](d +% n.sons[i].offset)[], op) doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
else: else:
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset), forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
@ -366,7 +366,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
if dest == nil: return # nothing to do if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags: if ntfNoRefs notin mt.flags:
case mt.kind case mt.kind
of tyRef, tyString, tySequence: # leaf: of tyRef, tyOptAsRef, tyString, tySequence: # leaf:
doOperation(cast[PPointer](d)[], op) doOperation(cast[PPointer](d)[], op)
of tyObject, tyTuple: of tyObject, tyTuple:
forAllSlotsAux(dest, mt.node, op) forAllSlotsAux(dest, mt.node, op)
@ -379,13 +379,13 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
gcAssert(cell != nil, "forAllChildren: 1") gcAssert(cell != nil, "forAllChildren: 1")
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2") gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
gcAssert(cell.typ != nil, "forAllChildren: 3") gcAssert(cell.typ != nil, "forAllChildren: 3")
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 4" gcAssert cell.typ.kind in {tyRef, tyOptAsRef, tySequence, tyString}, "forAllChildren: 4"
let marker = cell.typ.marker let marker = cell.typ.marker
if marker != nil: if marker != nil:
marker(cellToUsr(cell), op.int) marker(cellToUsr(cell), op.int)
else: else:
case cell.typ.kind case cell.typ.kind
of tyRef: # common case of tyRef, tyOptAsRef: # common case
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
of tySequence: of tySequence:
var d = cast[ByteAddress](cellToUsr(cell)) var d = cast[ByteAddress](cellToUsr(cell))
@ -461,7 +461,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
incTypeSize typ, size incTypeSize typ, size
sysAssert(allocInv(gch.region), "rawNewObj begin") sysAssert(allocInv(gch.region), "rawNewObj begin")
acquire(gch) acquire(gch)
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
collectCT(gch) collectCT(gch)
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
#gcAssert typ.kind in {tyString, tySequence} or size >= typ.base.size, "size too small" #gcAssert typ.kind in {tyString, tySequence} or size >= typ.base.size, "size too small"
@ -509,7 +509,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
incTypeSize typ, size incTypeSize typ, size
sysAssert(allocInv(gch.region), "newObjRC1 begin") sysAssert(allocInv(gch.region), "newObjRC1 begin")
acquire(gch) acquire(gch)
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
collectCT(gch) collectCT(gch)
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT") sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")

View file

@ -358,7 +358,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
if dest == nil: return # nothing to do if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags: if ntfNoRefs notin mt.flags:
case mt.kind case mt.kind
of tyRef, tyString, tySequence: # leaf: of tyRef, tyOptAsRef, tyString, tySequence: # leaf:
doOperation(cast[PPointer](d)[], op) doOperation(cast[PPointer](d)[], op)
of tyObject, tyTuple: of tyObject, tyTuple:
forAllSlotsAux(dest, mt.node, op) forAllSlotsAux(dest, mt.node, op)
@ -371,13 +371,13 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
gcAssert(cell != nil, "forAllChildren: 1") gcAssert(cell != nil, "forAllChildren: 1")
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2") gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
gcAssert(cell.typ != nil, "forAllChildren: 3") gcAssert(cell.typ != nil, "forAllChildren: 3")
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 4" gcAssert cell.typ.kind in {tyRef, tyOptAsRef, tySequence, tyString}, "forAllChildren: 4"
let marker = cell.typ.marker let marker = cell.typ.marker
if marker != nil: if marker != nil:
marker(cellToUsr(cell), op.int) marker(cellToUsr(cell), op.int)
else: else:
case cell.typ.kind case cell.typ.kind
of tyRef: # common case of tyRef, tyOptAsRef: # common case
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
of tySequence: of tySequence:
var d = cast[ByteAddress](cellToUsr(cell)) var d = cast[ByteAddress](cellToUsr(cell))
@ -442,7 +442,7 @@ proc gcInvariant*() =
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
# generates a new object and sets its reference counter to 0 # generates a new object and sets its reference counter to 0
sysAssert(allocInv(gch.region), "rawNewObj begin") sysAssert(allocInv(gch.region), "rawNewObj begin")
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
collectCT(gch) collectCT(gch)
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
@ -487,7 +487,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
# generates a new object and sets its reference counter to 1 # generates a new object and sets its reference counter to 1
sysAssert(allocInv(gch.region), "newObjRC1 begin") sysAssert(allocInv(gch.region), "newObjRC1 begin")
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
collectCT(gch) collectCT(gch)
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT") sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")

View file

@ -252,7 +252,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
if dest == nil: return # nothing to do if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags: if ntfNoRefs notin mt.flags:
case mt.kind case mt.kind
of tyRef, tyString, tySequence: # leaf: of tyRef, tyOptAsRef, tyString, tySequence: # leaf:
doOperation(cast[PPointer](d)[], op) doOperation(cast[PPointer](d)[], op)
of tyObject, tyTuple: of tyObject, tyTuple:
forAllSlotsAux(dest, mt.node, op) forAllSlotsAux(dest, mt.node, op)
@ -264,13 +264,13 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
proc forAllChildren(cell: PCell, op: WalkOp) = proc forAllChildren(cell: PCell, op: WalkOp) =
gcAssert(cell != nil, "forAllChildren: 1") gcAssert(cell != nil, "forAllChildren: 1")
gcAssert(cell.typ != nil, "forAllChildren: 2") gcAssert(cell.typ != nil, "forAllChildren: 2")
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3" gcAssert cell.typ.kind in {tyRef, tyOptAsRef, tySequence, tyString}, "forAllChildren: 3"
let marker = cell.typ.marker let marker = cell.typ.marker
if marker != nil: if marker != nil:
marker(cellToUsr(cell), op.int) marker(cellToUsr(cell), op.int)
else: else:
case cell.typ.kind case cell.typ.kind
of tyRef: # common case of tyRef, tyOptAsRef: # common case
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
of tySequence: of tySequence:
var d = cast[ByteAddress](cellToUsr(cell)) var d = cast[ByteAddress](cellToUsr(cell))
@ -285,7 +285,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
# generates a new object and sets its reference counter to 0 # generates a new object and sets its reference counter to 0
incTypeSize typ, size incTypeSize typ, size
acquire(gch) acquire(gch)
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
collectCT(gch) collectCT(gch)
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")

View file

@ -62,6 +62,21 @@ type
tyUInt16, tyUInt16,
tyUInt32, tyUInt32,
tyUInt64, tyUInt64,
tyOptAsRef, tyUnused1, tyUnused2,
tyVarargsHidden,
tyUnusedHidden,
tyProxyHidden,
tyBuiltInTypeClassHidden,
tyUserTypeClassHidden,
tyUserTypeClassInstHidden,
tyCompositeTypeClassHidden,
tyInferredHidden,
tyAndHidden, tyOrHidden, tyNotHidden,
tyAnythingHidden,
tyStaticHidden,
tyFromExprHidden,
tyOpt,
tyVoidHidden
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
TNimNode {.codegenType.} = object TNimNode {.codegenType.} = object