mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
gc: destructors is beginning to work (#10483)
* kochdocs.nim: code cleanup * docgen: nicer indentation * parser.nim: code cleanup * fixes #10458 * make tests green again * make =destroy mixins * gc:destructors: produced C code is almost working * --gc:destructors simple program compiles (but leaks memory) * gc:destructors make examples compile in C++ mode * destructors: string implementation bugfixes * strs.nim: minor code cleanup * destructors: builtin seqs are beginning to work * remove debugging helpers
This commit is contained in:
@@ -1352,7 +1352,6 @@ proc copySym*(s: PSym): PSym =
|
||||
result = newSym(s.kind, s.name, s.owner, s.info, s.options)
|
||||
#result.ast = nil # BUGFIX; was: s.ast which made problems
|
||||
result.typ = s.typ
|
||||
result.id = getID()
|
||||
when debugIds: registerId(result)
|
||||
result.flags = s.flags
|
||||
result.magic = s.magic
|
||||
|
||||
@@ -460,7 +460,7 @@ proc binaryStmtAddr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
||||
if d.k != locNone: internalError(p.config, e.info, "binaryStmtAddr")
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
lineCg(p, cpsStmts, frmt, addrLoc(p.config, a), rdLoc(b))
|
||||
lineCg(p, cpsStmts, frmt, byRefLoc(p, a), rdLoc(b))
|
||||
|
||||
proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
||||
var a: TLoc
|
||||
@@ -1028,7 +1028,7 @@ proc gcUsage(conf: ConfigRef; n: PNode) =
|
||||
|
||||
proc strLoc(p: BProc; d: TLoc): Rope =
|
||||
if p.config.selectedGc == gcDestructors:
|
||||
result = addrLoc(p.config, d)
|
||||
result = byRefLoc(p, d)
|
||||
else:
|
||||
result = rdLoc(d)
|
||||
|
||||
@@ -1110,7 +1110,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||
strLoc(p, dest), rdLoc(a)))
|
||||
if p.config.selectedGC == gcDestructors:
|
||||
linefmt(p, cpsStmts, "#prepareAdd($1, $2$3);$n",
|
||||
addrLoc(p.config, dest), lens, rope(L))
|
||||
byRefLoc(p, dest), lens, rope(L))
|
||||
else:
|
||||
initLoc(call, locCall, e, OnHeap)
|
||||
call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)])
|
||||
|
||||
@@ -264,6 +264,12 @@ proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t) != ctArray:
|
||||
result = "(&" & result & ")"
|
||||
|
||||
proc byRefLoc(p: BProc; a: TLoc): Rope =
|
||||
result = a.r
|
||||
if lfIndirect notin a.flags and mapType(p.config, a.t) != ctArray and not
|
||||
p.module.compileToCpp:
|
||||
result = "(&" & result & ")"
|
||||
|
||||
proc rdCharLoc(a: TLoc): Rope =
|
||||
# read a location that may need a char-cast:
|
||||
result = rdLoc(a)
|
||||
|
||||
@@ -244,7 +244,10 @@ proc patchHead(n: PNode) =
|
||||
|
||||
proc patchHead(s: PSym) =
|
||||
if sfFromGeneric in s.flags:
|
||||
patchHead(s.ast[bodyPos])
|
||||
# do not patch the builtin type bound operators for seqs:
|
||||
let dest = s.typ.sons[1].skipTypes(abstractVar)
|
||||
if dest.kind != tySequence:
|
||||
patchHead(s.ast[bodyPos])
|
||||
|
||||
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
|
||||
var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
|
||||
@@ -267,7 +270,8 @@ template genOp(opr, opname, ri) =
|
||||
globalError(c.graph.config, dest.info, "internal error: '" & opname &
|
||||
"' operator not found for type " & typeToString(t))
|
||||
elif op.ast[genericParamsPos].kind != nkEmpty:
|
||||
globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator is generic")
|
||||
globalError(c.graph.config, dest.info, "internal error: '" & opname &
|
||||
"' operator is generic")
|
||||
patchHead op
|
||||
if sfError in op.flags: checkForErrorPragma(c, t, ri, opname)
|
||||
let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
|
||||
@@ -275,6 +279,12 @@ template genOp(opr, opname, ri) =
|
||||
result = newTree(nkCall, newSymNode(op), addrExp)
|
||||
|
||||
proc genSink(c: Con; t: PType; dest, ri: PNode): PNode =
|
||||
when false:
|
||||
if t.kind != tyString:
|
||||
echo "this one ", c.graph.config$dest.info, " for ", typeToString(t, preferDesc)
|
||||
debug t.sink.typ.sons[2]
|
||||
echo t.sink.id, " owner ", t.id
|
||||
quit 1
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
genOp(if t.sink != nil: t.sink else: t.assignment, "=sink", ri)
|
||||
|
||||
|
||||
@@ -724,6 +724,14 @@ const
|
||||
tkTypeClasses = {tkRef, tkPtr, tkVar, tkStatic, tkType,
|
||||
tkEnum, tkTuple, tkObject, tkProc}
|
||||
|
||||
proc commandExpr(p: var TParser; r: PNode; mode: TPrimaryMode): PNode =
|
||||
result = newNodeP(nkCommand, p)
|
||||
addSon(result, r)
|
||||
var isFirstParam = true
|
||||
# progress NOT guaranteed
|
||||
p.hasProgress = false
|
||||
addSon result, commandParam(p, isFirstParam, mode)
|
||||
|
||||
proc primarySuffix(p: var TParser, r: PNode,
|
||||
baseIndent: int, mode: TPrimaryMode): PNode =
|
||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||
@@ -734,8 +742,6 @@ proc primarySuffix(p: var TParser, r: PNode,
|
||||
#| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
|
||||
result = r
|
||||
|
||||
template somePar() =
|
||||
if p.tok.strongSpaceA > 0: break
|
||||
# progress guaranteed
|
||||
while p.tok.indent < 0 or
|
||||
(p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
|
||||
@@ -749,6 +755,8 @@ proc primarySuffix(p: var TParser, r: PNode,
|
||||
result = newNodeP(nkCommand, p)
|
||||
result.addSon r
|
||||
result.addSon primary(p, pmNormal)
|
||||
else:
|
||||
result = commandExpr(p, result, mode)
|
||||
break
|
||||
result = namedParams(p, result, nkCall, tkParRi)
|
||||
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
|
||||
@@ -759,39 +767,27 @@ proc primarySuffix(p: var TParser, r: PNode,
|
||||
result = parseGStrLit(p, result)
|
||||
of tkBracketLe:
|
||||
# progress guaranteed
|
||||
somePar()
|
||||
if p.tok.strongSpaceA > 0:
|
||||
result = commandExpr(p, result, mode)
|
||||
break
|
||||
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
|
||||
of tkCurlyLe:
|
||||
# progress guaranteed
|
||||
somePar()
|
||||
if p.tok.strongSpaceA > 0:
|
||||
result = commandExpr(p, result, mode)
|
||||
break
|
||||
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
|
||||
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast,
|
||||
tkOpr, tkDotDot, tkTypeClasses - {tkRef, tkPtr}:
|
||||
# XXX: In type sections we allow the free application of the
|
||||
# command syntax, with the exception of expressions such as
|
||||
# `foo ref` or `foo ptr`. Unfortunately, these two are also
|
||||
# used as infix operators for the memory regions feature and
|
||||
# the current parsing rules don't play well here.
|
||||
# XXX: In type sections we allow the free application of the
|
||||
# command syntax, with the exception of expressions such as
|
||||
# `foo ref` or `foo ptr`. Unfortunately, these two are also
|
||||
# used as infix operators for the memory regions feature and
|
||||
# the current parsing rules don't play well here.
|
||||
if p.inPragma == 0 and (isUnary(p) or p.tok.tokType notin {tkOpr, tkDotDot}):
|
||||
# actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
|
||||
# solution, but pragmas.nim can't handle that
|
||||
let a = result
|
||||
result = newNodeP(nkCommand, p)
|
||||
addSon(result, a)
|
||||
var isFirstParam = true
|
||||
when true:
|
||||
# progress NOT guaranteed
|
||||
p.hasProgress = false
|
||||
addSon result, commandParam(p, isFirstParam, mode)
|
||||
if not p.hasProgress: break
|
||||
else:
|
||||
while p.tok.tokType != tkEof:
|
||||
let x = parseExpr(p)
|
||||
addSon(result, x)
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, x)
|
||||
result = postExprBlocks(p, result)
|
||||
result = commandExpr(p, result, mode)
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
@@ -316,6 +316,11 @@ proc liftBody(g: ModuleGraph; typ: PType; kind: TTypeAttachedOp;
|
||||
info: TLineInfo): PSym =
|
||||
if typ.kind == tyDistinct:
|
||||
return liftBodyDistinctType(g, typ, kind, info)
|
||||
when false:
|
||||
var typ = typ
|
||||
if c.config.selectedGC == gcDestructors and typ.kind == tySequence:
|
||||
# use the canonical type to access the =sink and =destroy etc.
|
||||
typ = c.graph.sysTypes[tySequence]
|
||||
|
||||
var a: TLiftCtx
|
||||
a.info = info
|
||||
|
||||
@@ -168,7 +168,7 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
else: illFormedAst(it, c.config)
|
||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
|
||||
(not hasElse and efInTypeof notin flags):
|
||||
for it in n:
|
||||
for it in n:
|
||||
it.sons[^1] = discardCheck(c, it.sons[^1], flags)
|
||||
result.kind = nkIfStmt
|
||||
# propagate any enforced VoidContext:
|
||||
@@ -1563,6 +1563,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, objB):
|
||||
# attach these ops to the canonical tySequence
|
||||
obj = canonType(c, obj)
|
||||
#echo "ATTACHING TO ", obj.id, " ", s.name.s, " ", cast[int](obj)
|
||||
let opr = if s.name.s == "=": addr(obj.assignment) else: addr(obj.sink)
|
||||
if opr[].isNil:
|
||||
opr[] = s
|
||||
|
||||
@@ -1159,7 +1159,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
# compiler only checks for 'nil':
|
||||
if skipTypes(r, {tyGenericInst, tyAlias, tySink}).kind != tyVoid:
|
||||
if kind notin {skMacro, skTemplate} and r.kind in {tyStmt, tyExpr}:
|
||||
localError(c.config, n.sons[0].info, "return type '" & typeToString(r) &
|
||||
localError(c.config, n.sons[0].info, "return type '" & typeToString(r) &
|
||||
"' is only valid for macros and templates")
|
||||
# 'auto' as a return type does not imply a generic:
|
||||
elif r.kind == tyAnything:
|
||||
@@ -1577,11 +1577,16 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
assert s != nil
|
||||
assert prev == nil
|
||||
result = copyType(s, s.owner, keepId=false)
|
||||
# XXX figure out why this has children already...
|
||||
# Remove the 'T' parameter from tySequence:
|
||||
result.sons.setLen 0
|
||||
result.n = nil
|
||||
result.flags = {tfHasAsgn}
|
||||
semContainerArg(c, n, "seq", result)
|
||||
if result.len > 0:
|
||||
var base = result[0]
|
||||
if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base)
|
||||
if base.kind != tyGenericParam:
|
||||
c.typesWithOps.add((result, result))
|
||||
else:
|
||||
result = semContainer(c, n, tySequence, "seq", prev)
|
||||
if c.config.selectedGc == gcDestructors:
|
||||
@@ -1714,11 +1719,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
n.typ = result
|
||||
dec c.inTypeContext
|
||||
if c.inTypeContext == 0: instAllTypeBoundOp(c, n.info)
|
||||
|
||||
when false:
|
||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = semTypeNodeInner(c, n, prev)
|
||||
if c.inTypeContext == 0:
|
||||
#if $n == "var seq[StackTraceEntry]":
|
||||
# echo "begin ", n
|
||||
instAllTypeBoundOp(c, n.info)
|
||||
|
||||
proc setMagicType(conf: ConfigRef; m: PSym, kind: TTypeKind, size: int) =
|
||||
|
||||
@@ -297,12 +297,6 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
|
||||
#result.destructor = nil
|
||||
result.sink = nil
|
||||
|
||||
template typeBound(c, newty, oldty, field, info) =
|
||||
let opr = newty.field
|
||||
if opr != nil and sfFromGeneric notin opr.flags:
|
||||
# '=' needs to be instantiated for generics when the type is constructed:
|
||||
newty.field = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1)
|
||||
|
||||
proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
|
||||
# is difficult to handle:
|
||||
@@ -317,7 +311,10 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
else:
|
||||
result = searchInstTypes(t)
|
||||
|
||||
if result != nil and eqFlags*result.flags == eqFlags*t.flags: return
|
||||
if result != nil and eqFlags*result.flags == eqFlags*t.flags:
|
||||
when defined(reportCacheHits):
|
||||
echo "Generic instantiation cached ", typeToString(result), " for ", typeToString(t)
|
||||
return
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
var x = t.sons[i]
|
||||
if x.kind in {tyGenericParam}:
|
||||
@@ -332,7 +329,11 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
if header != t:
|
||||
# search again after first pass:
|
||||
result = searchInstTypes(header)
|
||||
if result != nil and eqFlags*result.flags == eqFlags*t.flags: return
|
||||
if result != nil and eqFlags*result.flags == eqFlags*t.flags:
|
||||
when defined(reportCacheHits):
|
||||
echo "Generic instantiation cached ", typeToString(result), " for ",
|
||||
typeToString(t), " header ", typeToString(header)
|
||||
return
|
||||
else:
|
||||
header = instCopyType(cl, t)
|
||||
|
||||
@@ -384,7 +385,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
rawAddSon(result, newbody)
|
||||
checkPartialConstructedType(cl.c.config, cl.info, newbody)
|
||||
let dc = newbody.deepCopy
|
||||
if cl.allowMetaTypes == false:
|
||||
if not cl.allowMetaTypes:
|
||||
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
||||
# 'deepCopy' needs to be instantiated for
|
||||
# generics *when the type is constructed*:
|
||||
@@ -402,6 +403,11 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
discard
|
||||
else:
|
||||
newbody.lastSon.typeInst = result
|
||||
# DESTROY: adding object|opt for opt[topttree.Tree]
|
||||
# sigmatch: Formal opt[=destroy.T] real opt[topttree.Tree]
|
||||
# adding myseq for myseq[system.int]
|
||||
# sigmatch: Formal myseq[=destroy.T] real myseq[system.int]
|
||||
#echo "DESTROY: adding ", typeToString(newbody), " for ", typeToString(result, preferDesc)
|
||||
cl.c.typesWithOps.add((newbody, result))
|
||||
let mm = skipTypes(bbody, abstractPtrs)
|
||||
if tfFromGeneric notin mm.flags:
|
||||
@@ -432,7 +438,7 @@ proc eraseVoidParams*(t: PType) =
|
||||
inc pos
|
||||
setLen t.sons, pos
|
||||
setLen t.n.sons, pos
|
||||
return
|
||||
break
|
||||
|
||||
proc skipIntLiteralParams*(t: PType) =
|
||||
for i in 0 ..< t.sonsLen:
|
||||
@@ -561,9 +567,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
for i in countup(0, sonsLen(result) - 1):
|
||||
if result.sons[i] != nil:
|
||||
if result.sons[i].kind == tyGenericBody:
|
||||
localError(
|
||||
cl.c.config,
|
||||
t.sym.info,
|
||||
localError(cl.c.config, t.sym.info,
|
||||
"cannot instantiate '" &
|
||||
typeToString(result.sons[i], preferDesc) &
|
||||
"' inside of type definition: '" &
|
||||
@@ -603,6 +607,13 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
result.size = -1
|
||||
result.n = replaceObjBranches(cl, result.n)
|
||||
|
||||
template typeBound(c, newty, oldty, field, info) =
|
||||
let opr = newty.field
|
||||
if opr != nil and sfFromGeneric notin opr.flags:
|
||||
# '=' needs to be instantiated for generics when the type is constructed:
|
||||
#echo "DESTROY: instantiating ", astToStr(field), " for ", typeToString(oldty)
|
||||
newty.field = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1)
|
||||
|
||||
proc instAllTypeBoundOp*(c: PContext, info: TLineInfo) =
|
||||
var i = 0
|
||||
while i < c.typesWithOps.len:
|
||||
|
||||
@@ -2505,6 +2505,11 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
||||
else:
|
||||
if f.kind == tyVar: f = f.lastSon
|
||||
#if c.config.selectedGC == gcDestructors and f.kind == tySequence:
|
||||
# use the canonical type to access the =sink and =destroy etc.
|
||||
# f = c.graph.sysTypes[tySequence]
|
||||
#echo "YUP_---------Formal ", typeToString(f, preferDesc), " real ", typeToString(t, preferDesc), " ", f.id, " ", t.id
|
||||
|
||||
if typeRel(m, f, t) == isNone:
|
||||
localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'")
|
||||
else:
|
||||
|
||||
@@ -15,7 +15,7 @@ proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait".}
|
||||
|
||||
## Default seq implementation used by Nim's core.
|
||||
type
|
||||
NimSeqPayload {.core.}[T] = object
|
||||
NimSeqPayload[T] = object
|
||||
cap: int
|
||||
region: Allocator
|
||||
data: UncheckedArray[T]
|
||||
@@ -40,6 +40,7 @@ proc `=destroy`[T](s: var seq[T]) =
|
||||
var x = cast[ptr NimSeqV2[T]](addr s)
|
||||
var p = x.p
|
||||
if p != nil:
|
||||
mixin `=destroy`
|
||||
when not supportsCopyMem(T):
|
||||
for i in 0..<x.len: `=destroy`(p.data[i])
|
||||
p.region.dealloc(p.region, p, payloadSize(p.cap))
|
||||
@@ -47,11 +48,12 @@ proc `=destroy`[T](s: var seq[T]) =
|
||||
x.len = 0
|
||||
|
||||
proc `=`[T](x: var seq[T]; y: seq[T]) =
|
||||
mixin `=destroy`
|
||||
var a = cast[ptr NimSeqV2[T]](addr x)
|
||||
var b = cast[ptr NimSeqV2[T]](unsafeAddr y)
|
||||
|
||||
if a.p == b.p: return
|
||||
`=destroy`(a)
|
||||
`=destroy`(x)
|
||||
a.len = b.len
|
||||
if b.p != nil:
|
||||
a.p = cast[type(a.p)](alloc(payloadSize(a.len)))
|
||||
@@ -63,10 +65,11 @@ proc `=`[T](x: var seq[T]; y: seq[T]) =
|
||||
a.p.data[i] = b.p.data[i]
|
||||
|
||||
proc `=sink`[T](x: var seq[T]; y: seq[T]) =
|
||||
mixin `=destroy`
|
||||
var a = cast[ptr NimSeqV2[T]](addr x)
|
||||
var b = cast[ptr NimSeqV2[T]](unsafeAddr y)
|
||||
if a.p != nil and a.p != b.p:
|
||||
`=destroy`(a)
|
||||
`=destroy`(x)
|
||||
a.len = b.len
|
||||
a.p = b.p
|
||||
|
||||
@@ -109,6 +112,7 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
|
||||
result = q
|
||||
|
||||
proc shrink*[T](x: var seq[T]; newLen: Natural) =
|
||||
mixin `=destroy`
|
||||
sysAssert newLen <= x.len, "invalid newLen parameter for 'shrink'"
|
||||
when not supportsCopyMem(T):
|
||||
for i in countdown(x.len - 1, newLen - 1):
|
||||
|
||||
@@ -51,15 +51,12 @@ proc `=destroy`(s: var string) =
|
||||
a.len = 0
|
||||
a.p = nil
|
||||
|
||||
template lose(a) =
|
||||
frees(a)
|
||||
|
||||
proc `=sink`(x: var string, y: string) =
|
||||
var a = cast[ptr NimStringV2](addr x)
|
||||
var b = cast[ptr NimStringV2](unsafeAddr y)
|
||||
# we hope this is optimized away for not yet alive objects:
|
||||
if unlikely(a.p == b.p): return
|
||||
lose(a)
|
||||
frees(a)
|
||||
a.len = b.len
|
||||
a.p = b.p
|
||||
|
||||
@@ -67,13 +64,13 @@ proc `=`(x: var string, y: string) =
|
||||
var a = cast[ptr NimStringV2](addr x)
|
||||
var b = cast[ptr NimStringV2](unsafeAddr y)
|
||||
if unlikely(a.p == b.p): return
|
||||
lose(a)
|
||||
frees(a)
|
||||
a.len = b.len
|
||||
if isLiteral(b):
|
||||
# we can shallow copy literals:
|
||||
a.p = b.p
|
||||
else:
|
||||
let region = if a.p.region != nil: a.p.region else: getLocalAllocator()
|
||||
let region = if a.p != nil and a.p.region != nil: a.p.region else: getLocalAllocator()
|
||||
# we have to allocate the 'cap' here, consider
|
||||
# 'let y = newStringOfCap(); var x = y'
|
||||
# on the other hand... These get turned into moves now.
|
||||
@@ -136,6 +133,7 @@ proc appendString(dest: var NimStringV2; src: NimStringV2) {.compilerproc, inlin
|
||||
if src.len > 0:
|
||||
# also copy the \0 terminator:
|
||||
copyMem(unsafeAddr dest.p.data[dest.len], unsafeAddr src.p.data[0], src.len+1)
|
||||
inc dest.len, src.len
|
||||
|
||||
proc appendChar(dest: var NimStringV2; c: char) {.compilerproc, inline.} =
|
||||
dest.p.data[dest.len] = c
|
||||
@@ -166,7 +164,6 @@ proc mnewString(len: int): NimStringV2 {.compilerProc.} =
|
||||
proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} =
|
||||
if newLen > s.len:
|
||||
prepareAdd(s, newLen - s.len)
|
||||
else:
|
||||
s.len = newLen
|
||||
# this also only works because the destructor
|
||||
# looks at s.p and not s.len
|
||||
s.len = newLen
|
||||
# this also only works because the destructor
|
||||
# looks at s.p and not s.len
|
||||
|
||||
@@ -3049,6 +3049,19 @@ else:
|
||||
if x < 0: -x else: x
|
||||
{.pop.}
|
||||
|
||||
when defined(nimNewRoof):
|
||||
iterator `..<`*[T](a, b: T): T =
|
||||
var i = T(a)
|
||||
while i < b:
|
||||
yield i
|
||||
inc i
|
||||
else:
|
||||
iterator `..<`*[S, T](a: S, b: T): T =
|
||||
var i = T(a)
|
||||
while i < b:
|
||||
yield i
|
||||
inc i
|
||||
|
||||
when not defined(JS):
|
||||
proc likelyProc(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
|
||||
proc unlikelyProc(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
|
||||
@@ -3144,7 +3157,7 @@ when not defined(JS): #and not defined(nimscript):
|
||||
# ----------------- IO Part ------------------------------------------------
|
||||
type
|
||||
CFile {.importc: "FILE", header: "<stdio.h>",
|
||||
final, incompletestruct.} = object
|
||||
incompletestruct.} = object
|
||||
File* = ptr CFile ## The type representing a file handle.
|
||||
|
||||
FileMode* = enum ## The file mode when opening a file.
|
||||
@@ -3392,6 +3405,10 @@ when not defined(JS): #and not defined(nimscript):
|
||||
## returns the OS file handle of the file ``f``. This is only useful for
|
||||
## platform specific programming.
|
||||
|
||||
when defined(gcDestructors) and not defined(nimscript):
|
||||
include "core/strs"
|
||||
include "core/seqs"
|
||||
|
||||
when declared(newSeq):
|
||||
proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
|
||||
## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
|
||||
@@ -3483,10 +3500,6 @@ when not defined(JS): #and not defined(nimscript):
|
||||
when defined(memtracker):
|
||||
include "system/memtracker"
|
||||
|
||||
when defined(gcDestructors):
|
||||
include "core/strs"
|
||||
include "core/seqs"
|
||||
|
||||
when hostOS == "standalone":
|
||||
include "system/embedded"
|
||||
else:
|
||||
@@ -3716,19 +3729,6 @@ template `..<`*(a, b: untyped): untyped =
|
||||
## a shortcut for 'a .. (when b is BackwardsIndex: succ(b) else: pred(b))'.
|
||||
a .. (when b is BackwardsIndex: succ(b) else: pred(b))
|
||||
|
||||
when defined(nimNewRoof):
|
||||
iterator `..<`*[T](a, b: T): T =
|
||||
var i = T(a)
|
||||
while i < b:
|
||||
yield i
|
||||
inc i
|
||||
else:
|
||||
iterator `..<`*[S, T](a: S, b: T): T =
|
||||
var i = T(a)
|
||||
while i < b:
|
||||
yield i
|
||||
inc i
|
||||
|
||||
template spliceImpl(s, a, L, b: untyped): untyped =
|
||||
# make room for additional elements or cut:
|
||||
var shift = b.len - max(0,L) # ignore negative slice size
|
||||
|
||||
@@ -220,11 +220,12 @@ proc auxWriteStackTrace(f: PFrame; s: var seq[StackTraceEntry]) =
|
||||
inc(i)
|
||||
it = it.prev
|
||||
var last = i-1
|
||||
if s.len == 0:
|
||||
s = newSeq[StackTraceEntry](i)
|
||||
else:
|
||||
last = s.len + i - 1
|
||||
s.setLen(last+1)
|
||||
when true: # not defined(gcDestructors):
|
||||
if s.len == 0:
|
||||
s = newSeq[StackTraceEntry](i)
|
||||
else:
|
||||
last = s.len + i - 1
|
||||
s.setLen(last+1)
|
||||
it = f
|
||||
while it != nil:
|
||||
s[last] = StackTraceEntry(procname: it.procname,
|
||||
@@ -440,11 +441,13 @@ proc getStackTrace(e: ref Exception): string =
|
||||
else:
|
||||
result = ""
|
||||
|
||||
when not defined(gcDestructors):
|
||||
proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] =
|
||||
## Returns the attached stack trace to the exception ``e`` as
|
||||
## a ``seq``. This is not yet available for the JS backend.
|
||||
proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] =
|
||||
## Returns the attached stack trace to the exception ``e`` as
|
||||
## a ``seq``. This is not yet available for the JS backend.
|
||||
when not defined(gcDestructors):
|
||||
shallowCopy(result, e.trace)
|
||||
else:
|
||||
result = move(e.trace)
|
||||
|
||||
const nimCallDepthLimit {.intdefine.} = 2000
|
||||
|
||||
|
||||
@@ -195,6 +195,19 @@ proc runFinalizers(c: Chunk) =
|
||||
(cast[Finalizer](it.typ.finalizer))(it+!sizeof(ObjHeader))
|
||||
it = it.nextFinal
|
||||
|
||||
proc runFinalizers(c: Chunk; newbump: pointer) =
|
||||
var it = c.head
|
||||
var prev: ptr ObjHeader = nil
|
||||
while it != nil:
|
||||
let nxt = it.nextFinal
|
||||
if it >= newbump:
|
||||
if it.typ != nil and it.typ.finalizer != nil:
|
||||
(cast[Finalizer](it.typ.finalizer))(it+!sizeof(ObjHeader))
|
||||
elif prev != nil:
|
||||
prev.nextFinal = nil
|
||||
prev = it
|
||||
it = nxt
|
||||
|
||||
proc dealloc(r: var MemRegion; p: pointer; size: int) =
|
||||
let it = cast[ptr ObjHeader](p-!sizeof(ObjHeader))
|
||||
if it.typ != nil and it.typ.finalizer != nil:
|
||||
@@ -237,16 +250,15 @@ template computeRemaining(r): untyped =
|
||||
|
||||
proc setObstackPtr*(r: var MemRegion; sp: StackPtr) =
|
||||
# free everything after 'sp':
|
||||
if sp.current.next != nil:
|
||||
if sp.current != nil and sp.current.next != nil:
|
||||
deallocAll(r, sp.current.next)
|
||||
sp.current.next = nil
|
||||
when false:
|
||||
# better leak this memory than be sorry:
|
||||
for i in 0..high(r.freeLists): r.freeLists[i] = nil
|
||||
r.holes = nil
|
||||
#else:
|
||||
# deallocAll(r, r.head)
|
||||
# r.head = nil
|
||||
if r.tail != nil: runFinalizers(r.tail, sp.bump)
|
||||
|
||||
r.bump = sp.bump
|
||||
r.tail = sp.current
|
||||
r.remaining = sp.remaining
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# imported by other modules, unlike helpers.nim which is included
|
||||
|
||||
template formatErrorIndexBound*[T](i, a, b: T): string =
|
||||
"index out of bounds: (a:" & $a & ") <= (i:" & $i & ") <= (b:" & $b & ") "
|
||||
"index out of bounds: (a: " & $a & ") <= (i: " & $i & ") <= (b: " & $b & ") "
|
||||
|
||||
template formatErrorIndexBound*[T](i, n: T): string =
|
||||
"index out of bounds: (i:" & $i & ") <= (n:" & $n & ") "
|
||||
"index out of bounds: (i: " & $i & ") <= (n: " & $n & ") "
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
errormsg: "index out of bounds: (a:0) <= (i:2) <= (b:1) "
|
||||
errormsg: "index out of bounds: (a: 0) <= (i: 2) <= (b: 1) "
|
||||
line: 18
|
||||
"""
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
errormsg: "index out of bounds: (a:0) <= (i:3) <= (b:1) "
|
||||
errormsg: "index out of bounds: (a: 0) <= (i: 3) <= (b: 1) "
|
||||
line: 9
|
||||
"""
|
||||
|
||||
|
||||
@@ -40,3 +40,12 @@ proc getX(x: MyObject): lent MyField {.inline.} =
|
||||
|
||||
let a = MyObject()
|
||||
echo a.getX.b.len
|
||||
|
||||
|
||||
# bug #10458
|
||||
template t(x: untyped): untyped = "x"
|
||||
|
||||
let
|
||||
aaa = t 2 + 4
|
||||
ccc = t (1, 1) + 6
|
||||
ddd = t [0, 1, 2] + 5
|
||||
|
||||
Reference in New Issue
Block a user