backend preparations for incomplete/forwarded object types

This commit is contained in:
Andreas Rumpf
2017-10-28 13:46:43 +02:00
parent dcfc2b0e5f
commit c6235920cb
10 changed files with 122 additions and 90 deletions

View File

@@ -1665,3 +1665,8 @@ when false:
if n[i].containsNil: return true
template hasDestructor*(t: PType): bool = tfHasAsgn in t.flags
template incompleteType*(t: PType): bool =
t.sym != nil and {sfForward, sfNoForward} * t.sym.flags == {sfForward}
template typeCompleted*(t: PType) =
incl t.sym.flags, sfNoForward

View File

@@ -270,10 +270,10 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
addrLoc(dest), addrLoc(src), rdLoc(dest))
else:
linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n",
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t, dest.lode.info))
else:
linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t, dest.lode.info))
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# This function replaces all other methods for generating
@@ -291,7 +291,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
genRefAssign(p, dest, src, flags)
else:
linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t))
addrLoc(dest), rdLoc(src),
genTypeInfo(p.module, dest.t, dest.lode.info))
of tyString:
if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
genRefAssign(p, dest, src, flags)
@@ -352,7 +353,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if needsComplexAssignment(dest.t):
linefmt(p, cpsStmts, # XXX: is this correct for arrays?
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
addrLoc(dest), addrLoc(src),
genTypeInfo(p.module, dest.t, dest.lode.info))
else:
useStringh(p.module)
linefmt(p, cpsStmts,
@@ -393,14 +395,17 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
of tyPtr, tyRef, tyProc, tyTuple, tyObject, tyArray:
# XXX optimize this
linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n",
addrLoc(dest), addrLocOrTemp(src), genTypeInfo(p.module, dest.t))
addrLoc(dest), addrLocOrTemp(src),
genTypeInfo(p.module, dest.t, dest.lode.info))
of tySequence, tyString:
linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n",
addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t))
addrLoc(dest), rdLoc(src),
genTypeInfo(p.module, dest.t, dest.lode.info))
of tyOpenArray, tyVarargs:
linefmt(p, cpsStmts,
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
addrLoc(dest), addrLocOrTemp(src), genTypeInfo(p.module, dest.t))
addrLoc(dest), addrLocOrTemp(src),
genTypeInfo(p.module, dest.t, dest.lode.info))
of tySet:
if mapType(ty) == ctArray:
useStringh(p.module)
@@ -1101,7 +1106,8 @@ proc genReset(p: BProc, n: PNode) =
var a: TLoc
initLocExpr(p, n.sons[1], a)
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, {tyVar})))
addrLoc(a),
genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info))
proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
var sizeExpr = sizeExpr
@@ -1115,7 +1121,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
sizeExpr = "sizeof($1)" %
[getTypeDesc(p.module, bt)]
let args = [getTypeDesc(p.module, typ),
genTypeInfo(p.module, typ),
genTypeInfo(p.module, typ, a.lode.info),
sizeExpr]
if a.storage == OnHeap and usesNativeGC():
# use newObjRC1 as an optimization
@@ -1145,7 +1151,7 @@ proc genNew(p: BProc, e: PNode) =
proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
let seqtype = skipTypes(dest.t, abstractVarRange)
let args = [getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype), length]
genTypeInfo(p.module, seqtype, dest.lode.info), length]
var call: TLoc
initLoc(call, locExpr, dest.lode, OnHeap)
if dest.storage == OnHeap and usesNativeGC():
@@ -1173,7 +1179,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
putIntoDest(p, d, e, ropecg(p.module,
"($1)#nimNewSeqOfCap($2, $3)", [
getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype), a.rdLoc]))
genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
gcUsage(e)
proc genConstExpr(p: BProc, n: PNode): Rope
@@ -1290,7 +1296,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], f)
initLoc(b, locExpr, a.lode, OnHeap)
ti = genTypeInfo(p.module, refType)
ti = genTypeInfo(p.module, refType, e.info)
addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
getTypeDesc(p.module, refType),
@@ -1300,10 +1306,10 @@ proc genNewFinalize(p: BProc, e: PNode) =
genObjectInit(p, cpsStmts, bt, a, false)
gcUsage(e)
proc genOfHelper(p: BProc; dest: PType; a: Rope): Rope =
proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
# unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
# have to call it here first:
let ti = genTypeInfo(p.module, dest)
let ti = genTypeInfo(p.module, dest, info)
if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and
tfObjHasKids notin dest.flags):
result = "$1.m_type == $2" % [a, ti]
@@ -1316,7 +1322,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope): Rope =
when false:
# former version:
result = rfmt(p.module, "#isObj($1.m_type, $2)",
a, genTypeInfo(p.module, dest))
a, genTypeInfo(p.module, dest, info))
proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
var a: TLoc
@@ -1338,9 +1344,9 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
globalError(x.info, errGenerated,
"no 'of' operator available for pure objects")
if nilCheck != nil:
r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r))
r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r, x.info))
else:
r = rfmt(p.module, "($1)", genOfHelper(p, dest, r))
r = rfmt(p.module, "($1)", genOfHelper(p, dest, r, x.info))
putIntoDest(p, d, x, r, a.storage)
proc genOf(p: BProc, n: PNode, d: var TLoc) =
@@ -1363,12 +1369,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
of tyEnum, tyOrdinal:
putIntoDest(p, d, e,
ropecg(p.module, "#reprEnum((NI)$1, $2)", [
rdLoc(a), genTypeInfo(p.module, t)]), a.storage)
rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage)
of tyString:
putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage)
of tySet:
putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [
addrLoc(a), genTypeInfo(p.module, t)]), a.storage)
addrLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage)
of tyOpenArray, tyVarargs:
var b: TLoc
case a.t.kind
@@ -1383,22 +1389,22 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
else: internalError(e.sons[0].info, "genRepr()")
putIntoDest(p, d, e,
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
genTypeInfo(p.module, elemType(t))]), a.storage)
genTypeInfo(p.module, elemType(t), e.info)]), a.storage)
of tyCString, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence:
putIntoDest(p, d, e,
ropecg(p.module, "#reprAny($1, $2)", [
rdLoc(a), genTypeInfo(p.module, t)]), a.storage)
rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage)
of tyEmpty, tyVoid:
localError(e.info, "'repr' doesn't support 'void' type")
else:
putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)",
[addrLoc(a), genTypeInfo(p.module, t)]),
[addrLoc(a), genTypeInfo(p.module, t, e.info)]),
a.storage)
gcUsage(e)
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
let t = e.sons[1].typ
putIntoDest(p, d, e, genTypeInfo(p.module, t))
putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info))
proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
var a: TLoc
@@ -1980,10 +1986,10 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
t = skipTypes(t.sons[0], skipPtrs)
if nilCheck != nil:
linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n",
nilCheck, r, genTypeInfo(p.module, dest))
nilCheck, r, genTypeInfo(p.module, dest, n.info))
else:
linefmt(p, cpsStmts, "#chckObj($1.m_type, $2);$n",
r, genTypeInfo(p.module, dest))
r, genTypeInfo(p.module, dest, n.info))
if n.sons[0].typ.kind != tyObject:
putIntoDest(p, d, n,
"(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage)
@@ -2266,7 +2272,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
result = rope"{NIM_NIL, NIM_NIL}"
of tyObject:
if not isObjLackingTypeField(t) and not p.module.compileToCpp:
result = "{{$1}}" % [genTypeInfo(p.module, t)]
result = "{{$1}}" % [genTypeInfo(p.module, t, info)]
else:
result = rope"{}"
of tyArray, tyTuple: result = rope"{}"
@@ -2311,7 +2317,7 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode, result: var Ro
base = skipTypes(base, skipPtrs)
getNullValueAuxT(p, orig, base, base.n, cons, result, count)
elif not isObjLackingTypeField(t) and not p.module.compileToCpp:
addf(result, "$1", [genTypeInfo(p.module, orig)])
addf(result, "$1", [genTypeInfo(p.module, orig, obj.info)])
inc count
getNullValueAux(p, t, obj, cons, result, count)
# do not emit '{}' as that is not valid C:

View File

@@ -20,7 +20,7 @@ proc registerGcRoot(p: BProc, v: PSym) =
containsGarbageCollectedRef(v.loc.t):
# we register a specialized marked proc here; this has the advantage
# that it works out of the box for thread local storage then :-)
let prc = genTraverseProcForGlobal(p.module, v)
let prc = genTraverseProcForGlobal(p.module, v, v.info)
appcg(p.module, p.module.initProc.procSec(cpsInit),
"#nimRegisterGlobalMarker($1);$n", [prc])
@@ -835,7 +835,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if orExpr != nil: add(orExpr, "||")
appcg(p.module, orExpr,
"#isObj($1.exp->m_type, $2)",
[exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
[exc, genTypeInfo(p.module, t[i][j].typ, t[i][j].info)])
lineF(p, cpsStmts, "if ($1) ", [orExpr])
startBlock(p)
expr(p, t.sons[i].sons[blen-1], d)
@@ -944,7 +944,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
"#isObj(#getCurrentException()->Sup.m_type, $1)"
else: "#isObj(#getCurrentException()->m_type, $1)"
appcg(p.module, orExpr, isObjFormat,
[genTypeInfo(p.module, t.sons[i].sons[j].typ)])
[genTypeInfo(p.module, t[i][j].typ, t[i][j].info)])
if i > 1: line(p, cpsStmts, "else ")
startBlock(p, "if ($1) {$n", [orExpr])
linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
@@ -1062,7 +1062,7 @@ proc genWatchpoint(p: BProc, n: PNode) =
let typ = skipTypes(n.sons[1].typ, abstractVarRange)
lineCg(p, cpsStmts, "#dbgRegisterWatchpoint($1, (NCSTRING)$2, $3);$n",
[a.addrLoc, makeCString(renderTree(n.sons[1])),
genTypeInfo(p.module, typ)])
genTypeInfo(p.module, typ, n.info)])
proc genPragma(p: BProc, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
@@ -1092,7 +1092,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
field: PSym) =
var t = skipTypes(objtype, abstractVar)
assert t.kind == tyObject
discard genTypeInfo(p.module, t)
discard genTypeInfo(p.module, t, a.lode.info)
var L = lengthOrd(field.typ)
if not containsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1",

View File

@@ -151,8 +151,8 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash;
m.s[cfsProcHeaders].addf("$1;$n", [header])
m.s[cfsProcs].add(generatedProc)
proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
discard genTypeInfo(m, s.loc.t)
proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
discard genTypeInfo(m, s.loc.t, info)
var c: TTraversalClosure
var p = newProc(nil, m)

View File

@@ -278,7 +278,10 @@ proc ccgIntroducedPtr(s: PSym): bool =
elif tfByCopy in pt.flags: return false
case pt.kind
of tyObject:
if (optByRef in s.options) or (getSize(pt) > platform.floatSize * 3):
if s.typ.sym != nil and sfForward in s.typ.sym.flags:
# forwarded objects are *always* passed by pointers for consistency!
result = true
elif (optByRef in s.options) or (getSize(pt) > platform.floatSize * 3):
result = true # requested anyway
elif (tfFinal in pt.flags) and (pt.sons[0] == nil):
result = false # no need, because no subtyping possible
@@ -854,11 +857,12 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
[structOrUnion(t), result])
assert m.forwTypeCache[sig] == result
m.typeCache[sig] = result # always call for sideeffects:
let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
else: getTupleDesc(m, t, result, check)
if not isImportedType(t):
add(m.s[cfsTypes], recdesc)
elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result)
if not incompleteType(t):
let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
else: getTupleDesc(m, t, result, check)
if not isImportedType(t):
add(m.s[cfsTypes], recdesc)
elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result)
of tySet:
result = $t.kind & '_' & getTypeName(m, t.lastSon, hashType t.lastSon)
m.typeCache[sig] = result
@@ -935,12 +939,13 @@ proc genProcHeader(m: BModule, prc: PSym): Rope =
# ------------------ type info generation -------------------------------------
proc genTypeInfo(m: BModule, t: PType): Rope
proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope
proc getNimNode(m: BModule): Rope =
result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
inc(m.typeNodes)
proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: Rope) =
proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
name, base: Rope; info: TLineInfo) =
var nimtypeKind: int
#allocMemTI(m, typ, name)
if isObjLackingTypeField(typ):
@@ -970,15 +975,16 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: Rope) =
[name])
addf(m.s[cfsVars], "TNimType $1;$n", [name])
proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope) =
proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope;
info: TLineInfo) =
var base: Rope
if sonsLen(typ) > 0 and typ.lastSon != nil:
var x = typ.lastSon
if typ.kind == tyObject: x = x.skipTypes(skipPtrs)
base = genTypeInfo(m, x)
base = genTypeInfo(m, x, info)
else:
base = rope("0")
genTypeInfoAuxBase(m, typ, origType, name, base)
genTypeInfoAuxBase(m, typ, origType, name, base, info)
proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
# bugfix: we need to search the type that contains the discriminator:
@@ -994,19 +1000,20 @@ proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
var tmp = discriminatorTableName(m, objtype, d)
result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(d.typ)+1)]
proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope) =
proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
info: TLineInfo) =
case n.kind
of nkRecList:
var L = sonsLen(n)
if L == 1:
genObjectFields(m, typ, origType, n.sons[0], expr)
genObjectFields(m, typ, origType, n.sons[0], expr, info)
elif L > 0:
var tmp = getTempName(m)
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
for i in countup(0, L-1):
var tmp2 = getNimNode(m)
addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
genObjectFields(m, typ, origType, n.sons[i], tmp2)
genObjectFields(m, typ, origType, n.sons[i], tmp2, info)
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
[expr, rope(L), tmp])
else:
@@ -1024,14 +1031,14 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope) =
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
"$1.len = $7;$n", [expr, getTypeDesc(m, origType), field.loc.r,
genTypeInfo(m, field.typ),
genTypeInfo(m, field.typ, info),
makeCString(field.name.s),
tmp, rope(L)])
addf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, rope(L+1)])
for i in countup(1, sonsLen(n)-1):
var b = n.sons[i] # branch
var tmp2 = getNimNode(m)
genObjectFields(m, typ, origType, lastSon(b), tmp2)
genObjectFields(m, typ, origType, lastSon(b), tmp2, info)
case b.kind
of nkOfBranch:
if sonsLen(b) < 2:
@@ -1059,15 +1066,20 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope) =
addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n", [expr, getTypeDesc(m, origType),
field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
field.loc.r, genTypeInfo(m, field.typ, info), makeCString(field.name.s)])
else: internalError(n.info, "genObjectFields")
proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) =
if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
else: genTypeInfoAuxBase(m, typ, origType, name, rope("0"))
proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) =
if typ.kind == tyObject:
if incompleteType(typ):
localError(info, "request for RTTI generation for incomplete object: " &
typeToString(typ))
genTypeInfoAux(m, typ, origType, name, info)
else:
genTypeInfoAuxBase(m, typ, origType, name, rope("0"), info)
var tmp = getNimNode(m)
if not isImportedType(typ):
genObjectFields(m, typ, origType, typ.n, tmp)
genObjectFields(m, typ, origType, typ.n, tmp, info)
addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
var t = typ.sons[0]
while t != nil:
@@ -1075,8 +1087,8 @@ proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) =
t.flags.incl tfObjHasKids
t = t.sons[0]
proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope) =
genTypeInfoAuxBase(m, typ, typ, name, rope("0"))
proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) =
genTypeInfoAuxBase(m, typ, typ, name, rope("0"), info)
var expr = getNimNode(m)
var length = sonsLen(typ)
if length > 0:
@@ -1090,7 +1102,7 @@ proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope) =
"$1.offset = offsetof($2, Field$3);$n" &
"$1.typ = $4;$n" &
"$1.name = \"Field$3\";$n",
[tmp2, getTypeDesc(m, origType), rope(i), genTypeInfo(m, a)])
[tmp2, getTypeDesc(m, origType), rope(i), genTypeInfo(m, a, info)])
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
[expr, rope(length), tmp])
else:
@@ -1098,12 +1110,12 @@ proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope) =
[expr, rope(length)])
addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, expr])
proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
proc genEnumInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
# Type information for enumerations is quite heavy, so we do some
# optimizations here: The ``typ`` field is never set, as it is redundant
# anyway. We generate a cstring array and a loop over it. Exceptional
# positions will be reset after the loop.
genTypeInfoAux(m, typ, typ, name)
genTypeInfoAux(m, typ, typ, name, info)
var nodePtrs = getTempName(m)
var length = sonsLen(typ.n)
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
@@ -1141,15 +1153,15 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
# 1 << 2 is {ntfEnumHole}
addf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [name])
proc genSetInfo(m: BModule, typ: PType, name: Rope) =
proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
assert(typ.sons[0] != nil)
genTypeInfoAux(m, typ, typ, name)
genTypeInfoAux(m, typ, typ, name, info)
var tmp = getNimNode(m)
addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
[tmp, rope(firstOrd(typ)), name])
proc genArrayInfo(m: BModule, typ: PType, name: Rope) =
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1]))
proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1], info), info)
proc fakeClosureType(owner: PSym): PType =
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
@@ -1171,11 +1183,11 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
addf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
[result, s.loc.r])
proc genTypeInfo(m: BModule, t: PType): Rope =
proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
let origType = t
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
if t.kind == tyOpt:
return genTypeInfo(m, optLowering(t))
return genTypeInfo(m, optLowering(t), info)
let sig = hashType(origType)
result = m.typeInfoMarker.getOrDefault(sig)
@@ -1197,7 +1209,7 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
let owner = t.skipTypes(typedescPtrs).owner.getModule
if owner != m.module:
# make sure the type info is created in the owner module
discard genTypeInfo(m.g.modules[owner.position], origType)
discard genTypeInfo(m.g.modules[owner.position], origType, info)
# reference the type info as extern here
discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode")
@@ -1208,35 +1220,35 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
case t.kind
of tyEmpty, tyVoid: result = rope"0"
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
genTypeInfoAuxBase(m, t, t, result, rope"0")
genTypeInfoAuxBase(m, t, t, result, rope"0", info)
of tyStatic:
if t.n != nil: result = genTypeInfo(m, lastSon t)
if t.n != nil: result = genTypeInfo(m, lastSon t, info)
else: internalError("genTypeInfo(" & $t.kind & ')')
of tyUserTypeClasses:
internalAssert t.isResolvedUserTypeClass
return genTypeInfo(m, t.lastSon)
return genTypeInfo(m, t.lastSon, info)
of tyProc:
if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, t, result, rope"0")
genTypeInfoAuxBase(m, t, t, result, rope"0", info)
else:
let x = fakeClosureType(t.owner)
genTupleInfo(m, x, x, result)
genTupleInfo(m, x, x, result, info)
of tySequence, tyRef, tyOptAsRef:
genTypeInfoAux(m, t, t, result)
genTypeInfoAux(m, t, t, result, info)
if gSelectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, origType, sig, tiNew)
addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
of tyPtr, tyRange: genTypeInfoAux(m, t, t, result)
of tyArray: genArrayInfo(m, t, result)
of tySet: genSetInfo(m, t, result)
of tyEnum: genEnumInfo(m, t, result)
of tyObject: genObjectInfo(m, t, origType, result)
of tyPtr, tyRange: genTypeInfoAux(m, t, t, result, info)
of tyArray: genArrayInfo(m, t, result, info)
of tySet: genSetInfo(m, t, result, info)
of tyEnum: genEnumInfo(m, t, result, info)
of tyObject: genObjectInfo(m, t, origType, result, info)
of tyTuple:
# if t.n != nil: genObjectInfo(m, t, result)
# else:
# BUGFIX: use consistently RTTI without proper field names; otherwise
# results are not deterministic!
genTupleInfo(m, t, origType, result)
genTupleInfo(m, t, origType, result, info)
else: internalError("genTypeInfo(" & $t.kind & ')')
if t.deepCopy != nil:
genDeepCopyProc(m, t.deepCopy, result)

View File

@@ -271,11 +271,11 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
while (s.kind == tyObject) and (s.sons[0] != nil):
add(r, ".Sup")
s = skipTypes(s.sons[0], skipPtrs)
linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t))
linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t, a.lode.info))
of frEmbedded:
# worst case for performance:
var r = if takeAddr: addrLoc(a) else: rdLoc(a)
linefmt(p, section, "#objectInit($1, $2);$n", r, genTypeInfo(p.module, t))
linefmt(p, section, "#objectInit($1, $2);$n", r, genTypeInfo(p.module, t, a.lode.info))
type
TAssignmentFlag = enum
@@ -306,7 +306,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", addrLoc(loc))
if loc.storage != OnStack:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(loc), genTypeInfo(p.module, loc.t))
addrLoc(loc), genTypeInfo(p.module, loc.t, loc.lode.info))
# XXX: generated reset procs should not touch the m_type
# field, so disabling this should be safe:
genObjectInit(p, cpsStmts, loc.t, loc, true)
@@ -381,7 +381,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
lineF(p, cpsInit,
"FR_.s[$1].address = (void*)$3; FR_.s[$1].typ = $4; FR_.s[$1].name = $2;$n",
[p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
genTypeInfo(p.module, s.loc.t)])
genTypeInfo(p.module, s.loc.t, s.info)])
inc(p.maxFrameLen)
inc p.blocks[p.blocks.len-1].frameLen
@@ -451,7 +451,7 @@ proc assignGlobalVar(p: BProc, n: PNode) =
appcg(p.module, p.module.s[cfsDebugInit],
"#dbgRegisterGlobal($1, &$2, $3);$n",
[makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
s.loc.r, genTypeInfo(p.module, s.typ)])
s.loc.r, genTypeInfo(p.module, s.typ, n.info)])
proc assignParam(p: BProc, s: PSym) =
assert(s.loc.r != nil)

View File

@@ -55,7 +55,7 @@ const
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wBorrow, wGcSafe, wExportNims, wPartial, wUsed, wExplain}
wBorrow, wGcSafe, wExportNims, wPartial, wUsed, wExplain, wForward}
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed}
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
@@ -799,6 +799,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
noVal(it)
if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it)
else: incl(sym.typ.flags, tfInheritable)
of wForward:
noVal(it)
if sym.typ == nil: invalidPragma(it)
else: incl(sym.flags, sfForward)
of wAcyclic:
noVal(it)
if sym.typ == nil: invalidPragma(it)

View File

@@ -787,6 +787,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
s.typ.sym = s # process pragmas:
if name.kind == nkPragmaExpr:
pragma(c, s, name.sons[1], typePragmas)
if sfForward in s.flags: strTableAdd(c.graph.forwardedTypes, s)
# add it here, so that recursive types are possible:
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
a.sons[0] = newSymNode(s)

View File

@@ -55,7 +55,7 @@ type
wFloatchecks, wNanChecks, wInfChecks,
wAssertions, wPatterns, wWarnings,
wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags,
wDeadCodeElim, wSafecode, wNoForward, wReorder, wNoRewrite,
wDeadCodeElim, wSafecode, wForward, wNoForward, wReorder, wNoRewrite,
wPragma,
wCompileTime, wNoInit,
wPassc, wPassl, wBorrow, wDiscardable,
@@ -143,7 +143,7 @@ const
"assertions", "patterns", "warnings", "hints",
"optimization", "raises", "writes", "reads", "size", "effects", "tags",
"deadcodeelim", "safecode", "noforward", "reorder", "norewrite",
"deadcodeelim", "safecode", "forward", "noforward", "reorder", "norewrite",
"pragma",
"compiletime", "noinit",
"passc", "passl", "borrow", "discardable", "fieldchecks",

View File

@@ -1,11 +1,11 @@
version 1.0 battle plan
=======================
- make 'not nil' the default (produce warnings instead of errors for
a smooth migration path)
- case objects needs to be safe and need to support pattern matching
- implement a way to forward object type declarations across module
boundaries; C++ style
- deprecate unary '<'
- remove 'mod x' type rule
- implement x[^1] differently, no compiler magic
- fix "high priority" bugs
- try to fix as many compiler crashes as reasonable
@@ -13,6 +13,10 @@ version 1.0 battle plan
Not critical for 1.0
====================
- make 'not nil' the default (produce warnings instead of errors for
a smooth migration path)
- case objects needs to be safe and need to support pattern matching
- find a solution for the x.f[T](y) gotcha
- implement ``.delegate`` for .experimental
- annotation support for getType()