diff --git a/compiler/ast.nim b/compiler/ast.nim index d8f9fc36c..cba23c02c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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 diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 12e457e90..30eed9c47 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -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: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 8fb096c70..f5d266063 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -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", diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 7a2e221ee..275c2ddb6 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -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) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 80383ea84..76d0c0158 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -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) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 56002459e..26a84f16d 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -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) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index bc3771700..ab896716d 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -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) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0dd67b184..1993504d7 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 1e89ea1e2..2d6817b06 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -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", diff --git a/todo.txt b/todo.txt index 941016a02..7c35b851d 100644 --- a/todo.txt +++ b/todo.txt @@ -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()