diff options
32 files changed, 648 insertions, 247 deletions
diff --git a/changelog.md b/changelog.md index 6fd12e62f..aae275c1c 100644 --- a/changelog.md +++ b/changelog.md @@ -85,6 +85,7 @@ - The `terminal` module now exports additional procs for generating ANSI color codes as strings. - Added the parameter ``val`` for the ``CritBitTree[int].inc`` proc. +- Added the parameter ``val`` for the ``CritBitTree[T].incl`` proc. - An exception raised from ``test`` block of ``unittest`` now shows its type in the error message - The proc ``tgamma`` was renamed to ``gamma``. ``tgamma`` is deprecated. diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 7d355db5f..22733f6ac 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -83,7 +83,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool = result = isInCurrentFrame(p, n.sons[0]) else: discard -proc genIndexCheck(p: BProc; arr, idx: TLoc) +proc genBoundsCheck(p: BProc; arr, a, b: TLoc) proc openArrayLoc(p: BProc, n: PNode): Rope = var a: TLoc @@ -97,8 +97,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope = initLocExpr(p, q[3], c) # but first produce the required index checks: if optBoundsCheck in p.options: - genIndexCheck(p, a, b) - genIndexCheck(p, a, c) + genBoundsCheck(p, a, b, c) let ty = skipTypes(a.t, abstractVar+{tyPtr}) case ty.kind of tyArray: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 352402e0e..20b68b0aa 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -351,7 +351,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: useStringh(p.module) linefmt(p, cpsStmts, - "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);$n", + # bug #4799, keep the memcpy for a while + #"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);$n", + "$1 = $2;$n", rdLoc(dest), rdLoc(src)) of tySet: if mapType(ty) == ctArray: @@ -873,21 +875,26 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) = putIntoDest(p, d, n, ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage) -proc genIndexCheck(p: BProc; arr, idx: TLoc) = +proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = let ty = skipTypes(arr.t, abstractVarRange) case ty.kind of tyOpenArray, tyVarargs: - linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError();$n", - rdLoc(idx), rdLoc(arr)) + linefmt(p, cpsStmts, + "if ($2-$1 != -1 && " & + "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))) #raiseIndexError();$n", + rdLoc(a), rdLoc(b), rdLoc(arr)) of tyArray: let first = intLiteral(firstOrd(ty)) if tfUncheckedArray notin ty.flags: - linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n", - rdCharLoc(idx), first, intLiteral(lastOrd(ty))) + linefmt(p, cpsStmts, + "if ($2-$1 != -1 && " & + "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n", + rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(ty))) of tySequence, tyString: linefmt(p, cpsStmts, - "if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", - rdLoc(idx), rdLoc(arr), lenField(p)) + "if ($2-$1 != -1 && " & + "(!$3 || (NU)($1) >= (NU)($3->$4) || (NU)($2) >= (NU)($3->$4))) #raiseIndexError();$n", + rdLoc(a), rdLoc(b), rdLoc(arr), lenField(p)) else: discard proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 91a3add70..f99ee9270 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -775,6 +775,13 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) = else: genOrdinalCase(p, t, d) +proc genRestoreFrameAfterException(p: BProc) = + if optStackTrace in p.module.config.options: + if not p.hasCurFramePointer: + p.hasCurFramePointer = true + p.procSec(cpsLocals).add(ropecg(p.module, "\tTFrame* _nimCurFrame;$n", [])) + p.procSec(cpsInit).add(ropecg(p.module, "\t_nimCurFrame = #getFrame();$n", [])) + linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n") proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = # code to generate: @@ -794,8 +801,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = # finallyPart(); template genExceptBranchBody(body: PNode) {.dirty.} = - if optStackTrace in p.options: - linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") + genRestoreFrameAfterException(p) expr(p, body, d) if not isEmptyType(t.typ) and d.k == locNone: @@ -898,8 +904,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = endBlock(p) startBlock(p, "else {$n") linefmt(p, cpsStmts, "#popSafePoint();$n") - if optStackTrace in p.options: - linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") + genRestoreFrameAfterException(p) p.nestedTryStmts[^1].inExcept = true var i = 1 while (i < length) and (t.sons[i].kind == nkExceptBranch): diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index ce3fc2f90..843677654 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -69,6 +69,8 @@ type prc*: PSym # the Nim proc that this C proc belongs to beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed threadVarAccessed*: bool # true if the proc already accessed some threadvar + hasCurFramePointer*: bool # true if _nimCurFrame var needed to recover after + # exception is generated lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements currLineInfo*: TLineInfo # AST codegen will make this superfluous nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]] diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 86b63e34b..5568fd37b 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -155,6 +155,10 @@ type nearestFinally: int # Index of the nearest finally block. For try/except it # is their finally. For finally it is parent finally. Otherwise -1 +const + nkSkip = { nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt, + nkCommentStmt } + procDefs + proc newStateAccess(ctx: var Ctx): PNode = if ctx.stateVarSym.isNil: result = rawIndirectAccess(newSymNode(getEnvParam(ctx.fn)), @@ -247,8 +251,7 @@ proc hasYields(n: PNode): bool = case n.kind of nkYieldStmt: result = true - of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit, - nkSym, nkIdent, procDefs, nkTemplateDef: + of nkSkip: discard else: for c in n: @@ -259,8 +262,7 @@ proc hasYields(n: PNode): bool = proc transformBreaksAndContinuesInWhile(ctx: var Ctx, n: PNode, before, after: PNode): PNode = result = n case n.kind - of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit, - nkSym, nkIdent, procDefs, nkTemplateDef: + of nkSkip: discard of nkWhileStmt: discard # Do not recurse into nested whiles of nkContinueStmt: @@ -279,8 +281,7 @@ proc transformBreaksAndContinuesInWhile(ctx: var Ctx, n: PNode, before, after: P proc transformBreaksInBlock(ctx: var Ctx, n: PNode, label, after: PNode): PNode = result = n case n.kind - of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit, - nkSym, nkIdent, procDefs, nkTemplateDef: + of nkSkip: discard of nkBlockStmt, nkWhileStmt: inc ctx.blockLevel @@ -380,8 +381,7 @@ proc getFinallyNode(n: PNode): PNode = proc hasYieldsInExpressions(n: PNode): bool = case n.kind - of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit, - nkSym, nkIdent, procDefs, nkTemplateDef: + of nkSkip: discard of nkStmtListExpr: if isEmptyType(n.typ): @@ -397,18 +397,17 @@ proc hasYieldsInExpressions(n: PNode): bool = proc exprToStmtList(n: PNode): tuple[s, res: PNode] = assert(n.kind == nkStmtListExpr) + result.s = newNodeI(nkStmtList, n.info) + result.s.sons = @[] - var parent = n - var lastSon = n[^1] + var n = n + while n.kind == nkStmtListExpr: + result.s.sons.add(n.sons) + result.s.sons.setLen(result.s.sons.len - 1) # delete last son + n = n[^1] - while lastSon.kind == nkStmtListExpr: - parent = lastSon - lastSon = lastSon[^1] + result.res = n - result.s = newNodeI(nkStmtList, n.info) - result.s.sons = parent.sons - result.s.sons.setLen(result.s.sons.len - 1) # delete last son - result.res = lastSon proc newEnvVarAsgn(ctx: Ctx, s: PSym, v: PNode): PNode = result = newTree(nkFastAsgn, ctx.newEnvVarAccess(s), v) @@ -433,8 +432,7 @@ proc newNotCall(g: ModuleGraph; e: PNode): PNode = proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = result = n case n.kind - of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit, - nkSym, nkIdent, procDefs, nkTemplateDef: + of nkSkip: discard of nkYieldStmt: @@ -443,7 +441,6 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = n[i] = ctx.lowerStmtListExprs(n[i], ns) if ns: - assert(n[0].kind == nkStmtListExpr) result = newNodeI(nkStmtList, n.info) let (st, ex) = exprToStmtList(n[0]) result.add(st) @@ -663,7 +660,6 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = c[^1] = ctx.lowerStmtListExprs(c[^1], ns) if ns: needsSplit = true - assert(c[^1].kind == nkStmtListExpr) let (st, ex) = exprToStmtList(c[^1]) result.add(st) c[^1] = ex @@ -736,6 +732,33 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = n[0] = newSymNode(ctx.g.getSysSym(n[0].info, "true")) n[1] = newBody + + of nkDotExpr: + var ns = false + n[0] = ctx.lowerStmtListExprs(n[0], ns) + if ns: + needsSplit = true + result = newNodeI(nkStmtListExpr, n.info) + result.typ = n.typ + let (st, ex) = exprToStmtList(n[0]) + result.add(st) + n[0] = ex + result.add(n) + + of nkBlockExpr: + var ns = false + n[1] = ctx.lowerStmtListExprs(n[1], ns) + if ns: + needsSplit = true + result = newNodeI(nkStmtListExpr, n.info) + result.typ = n.typ + let (st, ex) = exprToStmtList(n[1]) + n.kind = nkBlockStmt + n.typ = nil + n[1] = st + result.add(n) + result.add(ex) + else: for i in 0 ..< n.len: n[i] = ctx.lowerStmtListExprs(n[i], needsSplit) @@ -797,8 +820,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode = let goto = newTree(nkGotoState, ctx.g.newIntLit(n.info, ctx.nearestFinally)) result.add(goto) - of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit, - nkSym, nkIdent, procDefs, nkTemplateDef: + of nkSkip: discard else: for i in 0 ..< n.len: @@ -807,8 +829,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode = proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode = result = n case n.kind: - of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit, - nkSym, nkIdent, procDefs, nkTemplateDef: + of nkSkip: discard of nkStmtList, nkStmtListExpr: @@ -846,8 +867,8 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode result[0] = ctx.transformClosureIteratorBody(result[0], gotoOut) of nkElifBranch, nkElifExpr, nkOfBranch: - result[1] = addGotoOut(result[1], gotoOut) - result[1] = ctx.transformClosureIteratorBody(result[1], gotoOut) + result[^1] = addGotoOut(result[^1], gotoOut) + result[^1] = ctx.transformClosureIteratorBody(result[^1], gotoOut) of nkIfStmt, nkCaseStmt: for i in 0 ..< n.len: @@ -1013,8 +1034,7 @@ proc tranformStateAssignments(ctx: var Ctx, n: PNode): PNode = for i in 0 ..< n.len: n[i] = ctx.tranformStateAssignments(n[i]) - of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit, - nkSym, nkIdent, procDefs, nkTemplateDef: + of nkSkip: discard of nkReturnStmt: @@ -1066,8 +1086,7 @@ proc skipEmptyStates(ctx: Ctx, stateIdx: int): int = proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode = result = n case n.kind - of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit, - nkSym, nkIdent, procDefs, nkTemplateDef: + of nkSkip: discard of nkGotoState: result = copyTree(n) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 591561987..d498cf4af 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -25,7 +25,7 @@ const SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'} SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', - '|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'} + '|', '=', '%', '&', '$', '@', '~', ':'} # don't forget to update the 'highlite' module if these charsets should change diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index de98a5e42..d3fa506cb 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -374,6 +374,10 @@ proc processPush(c: PContext, n: PNode, start: int) = x.otherPragmas.add n.sons[i] #localError(c.config, n.info, errOptionExpected) + # If stacktrace is disabled globally we should not enable it + if optStackTrace notin c.optionStack[0].options: + c.config.options.excl(optStackTrace) + proc processPop(c: PContext, n: PNode) = if c.optionStack.len <= 1: localError(c.config, n.info, "{.pop.} without a corresponding {.push.}") diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 41cac2a4a..fcfdda8bb 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2013,6 +2013,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, if r == isGeneric: result.typ = getInstantiatedType(c, arg, m, base(f)) m.baseTypeMatch = true + # bug #4799, varargs accepting subtype relation object + elif r == isSubtype: + inc(m.subtypeMatches) + if f.kind == tyTypeDesc: + result = arg + else: + result = implicitConv(nkHiddenSubConv, f, arg, m, c) + m.baseTypeMatch = true else: result = userConvMatch(c, m, base(f), a, arg) if result != nil: m.baseTypeMatch = true diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index 4f1264c9e..fbd2d7eca 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -130,7 +130,7 @@ proc nimNumber(g: var GeneralTokenizer, position: int): int = const OpChars = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', - '|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'} + '|', '=', '%', '&', '$', '@', '~', ':'} proc nimNextToken(g: var GeneralTokenizer) = const diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 96a6fa158..4665ad25f 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -62,52 +62,6 @@ template createCb(retFutureSym, iteratorNameSym, identName() #{.pop.} -proc generateExceptionCheck(futSym, - tryStmt, rootReceiver, fromNode: NimNode): NimNode {.compileTime.} = - if tryStmt.kind == nnkNilLit: - result = rootReceiver - else: - var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[] - let errorNode = newDotExpr(futSym, newIdentNode("error")) - for i in 1 ..< tryStmt.len: - let exceptBranch = tryStmt[i] - if exceptBranch[0].kind == nnkStmtList: - exceptionChecks.add((newIdentNode("true"), exceptBranch[0])) - else: - var exceptIdentCount = 0 - var ifCond: NimNode - for i in 0 ..< exceptBranch.len: - let child = exceptBranch[i] - if child.kind == nnkIdent: - let cond = infix(errorNode, "of", child) - if exceptIdentCount == 0: - ifCond = cond - else: - ifCond = infix(ifCond, "or", cond) - else: - break - exceptIdentCount.inc - - expectKind(exceptBranch[exceptIdentCount], nnkStmtList) - exceptionChecks.add((ifCond, exceptBranch[exceptIdentCount])) - # -> -> else: raise futSym.error - exceptionChecks.add((newIdentNode("true"), - newNimNode(nnkRaiseStmt).add(errorNode))) - # Read the future if there is no error. - # -> else: futSym.read - let elseNode = newNimNode(nnkElse, fromNode) - elseNode.add newNimNode(nnkStmtList, fromNode) - elseNode[0].add rootReceiver - - let ifBody = newStmtList() - ifBody.add newCall(newIdentNode("setCurrentException"), errorNode) - ifBody.add newIfStmt(exceptionChecks) - ifBody.add newCall(newIdentNode("setCurrentException"), newNilLit()) - - result = newIfStmt( - (newDotExpr(futSym, newIdentNode("failed")), ifBody) - ) - result.add elseNode template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver, rootReceiver: untyped, fromNode: NimNode) = @@ -123,8 +77,7 @@ template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver, result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode) # -> future<x>.read valueReceiver = newDotExpr(futureVarNode, newIdentNode("read")) - result.add generateExceptionCheck(futureVarNode, tryStmt, rootReceiver, - fromNode) + result.add rootReceiver template createVar(result: var NimNode, futSymName: string, asyncProc: NimNode, @@ -154,8 +107,8 @@ proc createFutureVarCompletions(futureVarIdents: seq[NimNode], ) proc processBody(node, retFutureSym: NimNode, - subTypeIsVoid: bool, futureVarIdents: seq[NimNode], - tryStmt: NimNode): NimNode {.compileTime.} = + subTypeIsVoid: bool, + futureVarIdents: seq[NimNode]): NimNode {.compileTime.} = #echo(node.treeRepr) result = node case node.kind @@ -173,7 +126,7 @@ proc processBody(node, retFutureSym: NimNode, result.add newCall(newIdentNode("complete"), retFutureSym) else: let x = node[0].processBody(retFutureSym, subTypeIsVoid, - futureVarIdents, tryStmt) + futureVarIdents) if x.kind == nnkYieldStmt: result.add x else: result.add newCall(newIdentNode("complete"), retFutureSym, x) @@ -224,63 +177,11 @@ proc processBody(node, retFutureSym: NimNode, var newDiscard = node result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1], newDiscard[0], newDiscard, node) - of nnkTryStmt: - # try: await x; except: ... - result = newNimNode(nnkStmtList, node) - template wrapInTry(n, tryBody: untyped) = - var temp = n - n[0] = tryBody - tryBody = temp - - # Transform ``except`` body. - # TODO: Could we perform some ``await`` transformation here to get it - # working in ``except``? - tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, - futureVarIdents, nil) - - proc processForTry(n: NimNode, i: var int, - res: NimNode): bool {.compileTime.} = - ## Transforms the body of the tryStmt. Does not transform the - ## body in ``except``. - ## Returns true if the tryStmt node was transformed into an ifStmt. - result = false - var skipped = n.skipStmtList() - while i < skipped.len: - var processed = processBody(skipped[i], retFutureSym, - subTypeIsVoid, futureVarIdents, n) - - # Check if we transformed the node into an exception check. - # This suggests skipped[i] contains ``await``. - if processed.kind != skipped[i].kind or processed.len != skipped[i].len: - processed = processed.skipUntilStmtList() - expectKind(processed, nnkStmtList) - expectKind(processed[2][1], nnkElse) - i.inc - - if not processForTry(n, i, processed[2][1][0]): - # We need to wrap the nnkElse nodes back into a tryStmt. - # As they are executed if an exception does not happen - # inside the awaited future. - # The following code will wrap the nodes inside the - # original tryStmt. - wrapInTry(n, processed[2][1][0]) - - res.add processed - result = true - else: - res.add skipped[i] - i.inc - var i = 0 - if not processForTry(node, i, result): - # If the tryStmt hasn't been transformed we can just put the body - # back into it. - wrapInTry(node, result) - return else: discard for i in 0 ..< result.len: result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, - futureVarIdents, nil) + futureVarIdents) proc getName(node: NimNode): string {.compileTime.} = case node.kind @@ -362,7 +263,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = # -> complete(retFuture, result) var iteratorNameSym = genSym(nskIterator, $prcName & "Iter") var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid, - futureVarIdents, nil) + futureVarIdents) # don't do anything with forward bodies (empty) if procBody.kind != nnkEmpty: procBody.add(createFutureVarCompletions(futureVarIdents, nil)) diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 5ae5e26b2..c94e08098 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -165,16 +165,18 @@ proc containsOrIncl*(c: var CritBitTree[void], key: string): bool = proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) = ## increments `c[key]` by `val`. - let oldCount = c.count var n = rawInsert(c, key) - if c.count == oldCount or oldCount == 0: - # not a new key: - inc n.val, val + inc n.val, val proc incl*(c: var CritBitTree[void], key: string) = ## includes `key` in `c`. discard rawInsert(c, key) +proc incl*[T](c: var CritBitTree[T], key: string, val: T) = + ## inserts `key` with value `val` into `c`. + var n = rawInsert(c, key) + n.val = val + proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) = ## puts a (key, value)-pair into `t`. var n = rawInsert(c, key) @@ -322,10 +324,14 @@ proc `$`*[T](c: CritBitTree[T]): string = const avgItemLen = 16 result = newStringOfCap(c.count * avgItemLen) result.add("{") - for key, val in pairs(c): - if result.len > 1: result.add(", ") - result.add($key) - when T isnot void: + when T is void: + for key in keys(c): + if result.len > 1: result.add(", ") + result.addQuoted(key) + else: + for key, val in pairs(c): + if result.len > 1: result.add(", ") + result.addQuoted(key) result.add(": ") result.addQuoted(val) result.add("}") @@ -362,3 +368,27 @@ when isMainModule: c.inc("a", -5) assert c["a"] == 0 + + c.inc("b", 2) + assert c["b"] == 2 + + c.inc("c", 3) + assert c["c"] == 3 + + c.inc("a", 1) + assert c["a"] == 1 + + var cf = CritBitTree[float]() + + cf.incl("a", 1.0) + assert cf["a"] == 1.0 + + cf.incl("b", 2.0) + assert cf["b"] == 2.0 + + cf.incl("c", 3.0) + assert cf["c"] == 3.0 + + assert cf.len == 3 + cf.excl("c") + assert cf.len == 2 diff --git a/lib/pure/json.nim b/lib/pure/json.nim index e7ad5bd5a..1bd53edb7 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -328,14 +328,14 @@ proc toJson(x: NimNode): NimNode {.compiletime.} = result = newNimNode(nnkBracket) for i in 0 ..< x.len: result.add(toJson(x[i])) - result = newCall(bindSym"%", result) + result = newCall(bindSym("%", brOpen), result) of nnkTableConstr: # object if x.len == 0: return newCall(bindSym"newJObject") result = newNimNode(nnkTableConstr) for i in 0 ..< x.len: x[i].expectKind nnkExprColonExpr result.add newTree(nnkExprColonExpr, x[i][0], toJson(x[i][1])) - result = newCall(bindSym"%", result) + result = newCall(bindSym("%", brOpen), result) of nnkCurly: # empty object x.expectLen(0) result = newCall(bindSym"newJObject") @@ -343,9 +343,9 @@ proc toJson(x: NimNode): NimNode {.compiletime.} = result = newCall(bindSym"newJNull") of nnkPar: if x.len == 1: result = toJson(x[0]) - else: result = newCall(bindSym"%", x) + else: result = newCall(bindSym("%", brOpen), x) else: - result = newCall(bindSym"%", x) + result = newCall(bindSym("%", brOpen), x) macro `%*`*(x: untyped): untyped = ## Convert an expression to a JsonNode directly, without having to specify diff --git a/lib/pure/net.nim b/lib/pure/net.nim index bf5f3f57e..5d2efebee 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -405,33 +405,40 @@ proc isIpAddress*(address_str: string): bool {.tags: [].} = return false return true -proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage, sl: var Socklen) = +proc toSockAddr*(address: IpAddress, port: Port, sa: var Sockaddr_storage, + sl: var Socklen) = ## Converts `IpAddress` and `Port` to `SockAddr` and `Socklen` let port = htons(uint16(port)) case address.family of IpAddressFamily.IPv4: sl = sizeof(Sockaddr_in).Socklen let s = cast[ptr Sockaddr_in](addr sa) - s.sin_family = type(s.sin_family)(AF_INET) + s.sin_family = type(s.sin_family)(toInt(AF_INET)) s.sin_port = port - copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0], sizeof(s.sin_addr)) + copyMem(addr s.sin_addr, unsafeAddr address.address_v4[0], + sizeof(s.sin_addr)) of IpAddressFamily.IPv6: sl = sizeof(Sockaddr_in6).Socklen let s = cast[ptr Sockaddr_in6](addr sa) - s.sin6_family = type(s.sin6_family)(AF_INET6) + s.sin6_family = type(s.sin6_family)(toInt(AF_INET6)) s.sin6_port = port - copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], sizeof(s.sin6_addr)) + copyMem(addr s.sin6_addr, unsafeAddr address.address_v6[0], + sizeof(s.sin6_addr)) -proc fromSockAddrAux(sa: ptr Sockaddr_storage, sl: Socklen, address: var IpAddress, port: var Port) = - if sa.ss_family.int == AF_INET.int and sl == sizeof(Sockaddr_in).Socklen: +proc fromSockAddrAux(sa: ptr Sockaddr_storage, sl: Socklen, + address: var IpAddress, port: var Port) = + if sa.ss_family.int == toInt(AF_INET) and sl == sizeof(Sockaddr_in).Socklen: address = IpAddress(family: IpAddressFamily.IPv4) let s = cast[ptr Sockaddr_in](sa) - copyMem(addr address.address_v4[0], addr s.sin_addr, sizeof(address.address_v4)) + copyMem(addr address.address_v4[0], addr s.sin_addr, + sizeof(address.address_v4)) port = ntohs(s.sin_port).Port - elif sa.ss_family.int == AF_INET6.int and sl == sizeof(Sockaddr_in6).Socklen: + elif sa.ss_family.int == toInt(AF_INET6) and + sl == sizeof(Sockaddr_in6).Socklen: address = IpAddress(family: IpAddressFamily.IPv6) let s = cast[ptr Sockaddr_in6](sa) - copyMem(addr address.address_v6[0], addr s.sin6_addr, sizeof(address.address_v6)) + copyMem(addr address.address_v6[0], addr s.sin6_addr, + sizeof(address.address_v6)) port = ntohs(s.sin6_port).Port else: raise newException(ValueError, "Neither IPv4 nor IPv6") @@ -440,7 +447,7 @@ proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6, sl: Socklen, address: var IpAddress, port: var Port) {.inline.} = ## Converts `SockAddr` and `Socklen` to `IpAddress` and `Port`. Raises ## `ObjectConversionError` in case of invalid `sa` and `sl` arguments. - fromSockAddrAux(unsafeAddr sa, sl, address, port) + fromSockAddrAux(cast[ptr Sockaddr_storage](unsafeAddr sa), sl, address, port) when defineSsl: CRYPTO_malloc_init() @@ -1149,7 +1156,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int, return 1 let sslPending = SSLPending(socket.sslHandle) if sslPending != 0: - return sslPending + return min(sslPending, size) var startTime = epochTime() let selRet = select(socket, timeout - int(waited * 1000.0)) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 60b362665..7cecc31ab 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -185,8 +185,7 @@ type DurationParts* = array[FixedTimeUnit, int64] # Array of Duration parts starts TimeIntervalParts* = array[TimeUnit, int] # Array of Duration parts starts - - + TimesMutableTypes = DateTime | Time | Duration | TimeInterval {.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time, TTimeInterval: TimeInterval, TTimeInfo: DateTime, TimeInfo: DateTime].} @@ -607,30 +606,12 @@ proc `+`*(a: Time, b: Duration): Time {.operator, extern: "ntAddTime".} = doAssert (fromUnix(0) + initDuration(seconds = 1)) == fromUnix(1) addImpl[Time](a, b) -proc `+=`*(a: var Time, b: Duration) {.operator.} = - ## Modify ``a`` in place by subtracting ``b``. - runnableExamples: - var tm = fromUnix(0) - tm += initDuration(seconds = 1) - doAssert tm == fromUnix(1) - - a = addImpl[Time](a, b) - proc `-`*(a: Time, b: Duration): Time {.operator, extern: "ntSubTime".} = ## Subtracts a duration of time from a ``Time``. runnableExamples: doAssert (fromUnix(0) - initDuration(seconds = 1)) == fromUnix(-1) subImpl[Time](a, b) -proc `-=`*(a: var Time, b: Duration) {.operator.} = - ## Modify ``a`` in place by adding ``b``. - runnableExamples: - var tm = fromUnix(0) - tm -= initDuration(seconds = 1) - doAssert tm == fromUnix(-1) - - a = subImpl[Time](a, b) - proc `<`*(a, b: Time): bool {.operator, extern: "ntLtTime".} = ## Returns true iff ``a < b``, that is iff a happened before b. ltImpl(a, b) @@ -1377,17 +1358,6 @@ proc `+`*(time: Time, interval: TimeInterval): Time = else: toTime(time.local + interval) -proc `+=`*(time: var Time, interval: TimeInterval) = - ## Modifies `time` by adding `interval`. - ## If `interval` contains any years, months, weeks or days the operation - ## is performed in the local timezone. - runnableExamples: - var tm = fromUnix(0) - tm += 5.seconds - doAssert tm == fromUnix(5) - - time = time + interval - proc `-`*(time: Time, interval: TimeInterval): Time = ## Subtracts `interval` from Time `time`. ## If `interval` contains any years, months, weeks or days the operation @@ -1401,15 +1371,30 @@ proc `-`*(time: Time, interval: TimeInterval): Time = else: toTime(time.local - interval) -proc `-=`*(time: var Time, interval: TimeInterval) = - ## Modifies `time` by subtracting `interval`. - ## If `interval` contains any years, months, weeks or days the operation - ## is performed in the local timezone. +proc `+=`*[T, U: TimesMutableTypes](a: var T, b: U) = + ## Modify ``a`` in place by adding ``b``. + runnableExamples: + var tm = fromUnix(0) + tm += initDuration(seconds = 1) + doAssert tm == fromUnix(1) + a = a + b + +proc `-=`*[T, U: TimesMutableTypes](a: var T, b: U) = + ## Modify ``a`` in place by subtracting ``b``. runnableExamples: var tm = fromUnix(5) - tm -= 5.seconds + tm -= initDuration(seconds = 5) doAssert tm == fromUnix(0) - time = time - interval + a = a - b + +proc `*=`*[T: TimesMutableTypes, U](a: var T, b: U) = + # Mutable type is often multiplied by number + runnableExamples: + var dur = initDuration(seconds = 1) + dur *= 5 + doAssert dur == initDuration(seconds = 5) + + a = a * b proc formatToken(dt: DateTime, token: string, buf: var string) = ## Helper of the format proc to parse individual tokens. diff --git a/lib/system.nim b/lib/system.nim index b8aa170ea..fee9dc314 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2681,7 +2681,7 @@ when not defined(nimscript) and hasAlloc: {.warning: "GC_unref is a no-op in JavaScript".} template GC_getStatistics*(): string = - {.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".} + {.warning: "GC_getStatistics is a no-op in JavaScript".} "" template accumulateResult*(iter: untyped) = diff --git a/lib/system/channels.nim b/lib/system/channels.nim index 3c5bda4b1..254b87dfc 100644 --- a/lib/system/channels.nim +++ b/lib/system/channels.nim @@ -116,7 +116,7 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, if mode == mStore: x[] = alloc0(t.region, seq.len *% mt.base.size +% GenericSeqSize) else: - unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize)) + unsureAsgnRef(x, newSeq(mt, seq.len)) var dst = cast[ByteAddress](cast[PPointer](dest)[]) var dstseq = cast[PGenericSeq](dst) dstseq.len = seq.len diff --git a/tests/async/t7985.nim b/tests/async/t7985.nim new file mode 100644 index 000000000..0365499d3 --- /dev/null +++ b/tests/async/t7985.nim @@ -0,0 +1,19 @@ +discard """ + file: "t7985.nim" + exitcode: 0 + output: "(value: 1)" +""" +import json, asyncdispatch + +proc getData(): Future[JsonNode] {.async.} = + result = %*{"value": 1} + +type + MyData = object + value: BiggestInt + +proc main() {.async.} = + let data = to(await(getData()), MyData) + echo data + +waitFor(main()) diff --git a/tests/async/tasync_traceback.nim b/tests/async/tasync_traceback.nim index 618a1dc76..b6c6a916b 100644 --- a/tests/async/tasync_traceback.nim +++ b/tests/async/tasync_traceback.nim @@ -3,7 +3,7 @@ discard """ disabled: "windows" output: "Matched" """ -import asyncdispatch +import asyncdispatch, strutils # Tests to ensure our exception trace backs are friendly. @@ -117,10 +117,26 @@ Exception message: bar failure Exception type: """ -if result.match(re(expected)): - echo("Matched") -else: - echo("Not matched!") +let resLines = splitLines(result.strip) +let expLines = splitLines(expected.strip) + +if resLines.len != expLines.len: + echo("Not matched! Wrong number of lines!") echo() echo(result) quit(QuitFailure) + +var ok = true +for i in 0 ..< resLines.len: + if not resLines[i].match(re(expLines[i])): + echo "Not matched! Line ", i + 1 + echo "Expected:" + echo expLines[i] + echo "Actual:" + echo resLines[i] + ok = false + +if ok: + echo("Matched") +else: + quit(QuitFailure) diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim index 5930f296f..6749aabbf 100644 --- a/tests/async/tasynctry.nim +++ b/tests/async/tasynctry.nim @@ -9,7 +9,7 @@ Multiple except branches Multiple except branches 2 ''' """ -import asyncdispatch +import asyncdispatch, strutils # Here we are testing the ability to catch exceptions. @@ -22,7 +22,7 @@ proc catch() {.async.} = try: await foobar() except: - echo("Generic except: ", getCurrentExceptionMsg()) + echo("Generic except: ", getCurrentExceptionMsg().splitLines[0]) try: await foobar() diff --git a/tests/async/tasynctry2.nim b/tests/async/tasynctry2.nim index f82b6cfe0..4b3f17cc5 100644 --- a/tests/async/tasynctry2.nim +++ b/tests/async/tasynctry2.nim @@ -1,7 +1,7 @@ discard """ file: "tasynctry2.nim" errormsg: "\'yield\' cannot be used within \'try\' in a non-inlined iterator" - line: 17 + line: 14 """ import asyncdispatch diff --git a/tests/collections/tcollections_to_string.nim b/tests/collections/tcollections_to_string.nim index 48b06a6aa..0c4f1e91c 100644 --- a/tests/collections/tcollections_to_string.nim +++ b/tests/collections/tcollections_to_string.nim @@ -68,15 +68,15 @@ block: block: var t: CritBitTree[int] t["a"] = 1 - doAssert $t == "{a: 1}" + doAssert $t == """{"a": 1}""" block: var t: CritBitTree[string] t["a"] = "1" - doAssert $t == """{a: "1"}""" + doAssert $t == """{"a": "1"}""" block: var t: CritBitTree[char] t["a"] = '1' - doAssert $t == "{a: '1'}" + doAssert $t == """{"a": '1'}""" # Test escaping behavior diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim index 31ec65a83..6f0acb169 100644 --- a/tests/iter/tyieldintry.nim +++ b/tests/iter/tyieldintry.nim @@ -368,5 +368,40 @@ block: # Short cirquits test(it, 1, 0, 0) +block: #7969 + type + SomeObj = object + id: int + + iterator it(): int {.closure.} = + template yieldAndSomeObj: SomeObj = + var s: SomeObj + s.id = 2 + yield 1 + s + + checkpoint(yieldAndSomeObj().id) + + var i = 5 + case i + of 0: + checkpoint(123) + of 1, 2, 5: + checkpoint(3) + else: + checkpoint(123) + + test(it, 1, 2, 3) + +block: # yield in blockexpr + iterator it(): int {.closure.} = + yield(block: + checkpoint(1) + yield 2 + 3 + ) + + test(it, 1, 2, 3) + echo "ok" diff --git a/tests/lexer/thexlit.nim b/tests/lexer/thexlit.nim deleted file mode 100644 index 2b7f0a40e..000000000 --- a/tests/lexer/thexlit.nim +++ /dev/null @@ -1,12 +0,0 @@ -discard """ - file: "thexlit.nim" - output: "equal" -""" - -var t=0x950412DE - -if t==0x950412DE: - echo "equal" -else: - echo "not equal" - diff --git a/tests/lexer/thexrange.nim b/tests/lexer/thexrange.nim deleted file mode 100644 index 461e41dfd..000000000 --- a/tests/lexer/thexrange.nim +++ /dev/null @@ -1,8 +0,0 @@ - -type - TArray = array[0x0012..0x0013, int] - -var a: TArray - -echo a[0x0012] #OUT 0 - diff --git a/tests/lexer/tlexermisc.nim b/tests/lexer/tlexermisc.nim new file mode 100644 index 000000000..3e3993599 --- /dev/null +++ b/tests/lexer/tlexermisc.nim @@ -0,0 +1,27 @@ +discard """ + action: run + output: "equal" +""" + +var t=0x950412DE + +if t==0x950412DE: + echo "equal" +else: + echo "not equal" + +type + TArray = array[0x0012..0x0013, int] + +var a: TArray + +doAssert a[0x0012] == 0 + + +# #7884 + +type Obj = object + ö: int + +let o = Obj(ö: 1) +doAssert o.ö == 1 diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim index 64d690fc9..d364447da 100644 --- a/tests/stdlib/tnet.nim +++ b/tests/stdlib/tnet.nim @@ -66,6 +66,18 @@ block: # "IpAddress/Sockaddr conversion" doAssert(ipaddr_1 == ipaddr_2) doAssert($ipaddr_1 == $ipaddr_2) + if sockaddr.ss_family == AF_INET.toInt: + var sockaddr4: Sockaddr_in + copyMem(addr sockaddr4, addr sockaddr, sizeof(sockaddr4)) + fromSockAddr(sockaddr4, socklen, ipaddr_2, port_2) + elif sockaddr.ss_family == AF_INET6.toInt: + var sockaddr6: Sockaddr_in6 + copyMem(addr sockaddr6, addr sockaddr, sizeof(sockaddr6)) + fromSockAddr(sockaddr6, socklen, ipaddr_2, port_2) + + doAssert(ipaddr_1 == ipaddr_2) + doAssert($ipaddr_1 == $ipaddr_2) + # ipv6 address of example.com test("2606:2800:220:1:248:1893:25c8:1946") diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim index 85228e9e7..6d14aa68f 100644 --- a/tests/system/tsystem_misc.nim +++ b/tests/system/tsystem_misc.nim @@ -11,6 +11,10 @@ discard """ 2 3 4 +2 +1 +2 +3 ''' """ @@ -47,3 +51,38 @@ foo(toOpenArray(arr, 8, 12)) var seqq = @[1, 2, 3, 4, 5] foo(toOpenArray(seqq, 1, 3)) + +# empty openArray issue #7904 +foo(toOpenArray(seqq, 0, -1)) +foo(toOpenArray(seqq, 1, 0)) +doAssertRaises(IndexError): + foo(toOpenArray(seqq, 0, -2)) + +foo(toOpenArray(arr, 9, 8)) +foo(toOpenArray(arr, 0, -1)) +foo(toOpenArray(arr, 1, 0)) +doAssertRaises(IndexError): + foo(toOpenArray(arr, 10, 8)) + +# test openArray of openArray +proc oaEmpty(a: openArray[int]) = + foo(toOpenArray(a, 0, -1)) + +proc oaFirstElm(a: openArray[int]) = + foo(toOpenArray(a, 0, 0)) + +oaEmpty(toOpenArray(seqq, 0, -1)) +oaEmpty(toOpenArray(seqq, 1, 0)) +oaEmpty(toOpenArray(seqq, 1, 2)) +oaFirstElm(toOpenArray(seqq, 1, seqq.len-1)) + +var arrNeg: array[-3 .. -1, int] = [1, 2, 3] +foo(toOpenArray(arrNeg, -3, -1)) +foo(toOpenArray(arrNeg, 0, -1)) +foo(toOpenArray(arrNeg, -3, -4)) +doAssertRaises(IndexError): + foo(toOpenArray(arrNeg, -4, -1)) +doAssertRaises(IndexError): + foo(toOpenArray(arrNeg, -1, 0)) +doAssertRaises(IndexError): + foo(toOpenArray(arrNeg, -1, -3)) diff --git a/tests/typerel/t4799.nim b/tests/typerel/t4799.nim new file mode 100644 index 000000000..075893476 --- /dev/null +++ b/tests/typerel/t4799.nim @@ -0,0 +1,245 @@ +discard """ + output: "OK" +""" + +type + GRBase[T] = ref object of RootObj + val: T + GRC[T] = ref object of GRBase[T] + GRD[T] = ref object of GRBase[T] + +proc testGR[T](x: varargs[GRBase[T]]): string = + result = "" + for c in x: + result.add $c.val + +block test_t4799_1: + var rgv = GRBase[int](val: 3) + var rgc = GRC[int](val: 4) + var rgb = GRD[int](val: 2) + doAssert(testGR(rgb, rgc, rgv) == "243") + doAssert(testGR(rgc, rgv, rgb) == "432") + doAssert(testGR(rgv, rgb, rgc) == "324") + doAssert(testGR([rgb, rgc, rgv]) == "243") + doAssert(testGR([rgc, rgv, rgb]) == "432") + doAssert(testGR([rgv, rgb, rgc]) == "324") + +type + PRBase[T] = object of RootObj + val: T + PRC[T] = object of PRBase[T] + PRD[T] = object of PRBase[T] + +proc testPR[T](x: varargs[ptr PRBase[T]]): string = + result = "" + for c in x: + result.add $c.val + +block test_t4799_2: + var pgv = PRBase[int](val: 3) + var pgc = PRC[int](val: 4) + var pgb = PRD[int](val: 2) + doAssert(testPR(pgb.addr, pgc.addr, pgv.addr) == "243") + doAssert(testPR(pgc.addr, pgv.addr, pgb.addr) == "432") + doAssert(testPR(pgv.addr, pgb.addr, pgc.addr) == "324") + doAssert(testPR([pgb.addr, pgc.addr, pgv.addr]) == "243") + doAssert(testPR([pgc.addr, pgv.addr, pgb.addr]) == "432") + doAssert(testPR([pgv.addr, pgb.addr, pgc.addr]) == "324") + +type + RBase = ref object of RootObj + val: int + RC = ref object of RBase + RD = ref object of RBase + +proc testR(x: varargs[RBase]): string = + result = "" + for c in x: + result.add $c.val + +block test_t4799_3: + var rv = RBase(val: 3) + var rc = RC(val: 4) + var rb = RD(val: 2) + doAssert(testR(rb, rc, rv) == "243") + doAssert(testR(rc, rv, rb) == "432") + doAssert(testR(rv, rb, rc) == "324") + doAssert(testR([rb, rc, rv]) == "243") + doAssert(testR([rc, rv, rb]) == "432") + doAssert(testR([rv, rb, rc]) == "324") + +type + PBase = object of RootObj + val: int + PC = object of PBase + PD = object of PBase + +proc testP(x: varargs[ptr PBase]): string = + result = "" + for c in x: + result.add $c.val + +block test_t4799_4: + var pv = PBase(val: 3) + var pc = PC(val: 4) + var pb = PD(val: 2) + doAssert(testP(pb.addr, pc.addr, pv.addr) == "243") + doAssert(testP(pc.addr, pv.addr, pb.addr) == "432") + doAssert(testP(pv.addr, pb.addr, pc.addr) == "324") + doAssert(testP([pb.addr, pc.addr, pv.addr]) == "243") + doAssert(testP([pc.addr, pv.addr, pb.addr]) == "432") + doAssert(testP([pv.addr, pb.addr, pc.addr]) == "324") + +type + PSBase[T, V] = ref object of RootObj + val: T + color: V + PSRC[T] = ref object of PSBase[T, int] + PSRD[T] = ref object of PSBase[T, int] + +proc testPS[T, V](x: varargs[PSBase[T, V]]): string = + result = "" + for c in x: + result.add c.val + result.add $c.color + +block test_t4799_5: + var a = PSBase[string, int](val: "base", color: 1) + var b = PSRC[string](val: "rc", color: 2) + var c = PSRD[string](val: "rd", color: 3) + + doAssert(testPS(a, b, c) == "base1rc2rd3") + doAssert(testPS(b, a, c) == "rc2base1rd3") + doAssert(testPS(c, b, a) == "rd3rc2base1") + doAssert(testPS([a, b, c]) == "base1rc2rd3") + doAssert(testPS([b, a, c]) == "rc2base1rd3") + doAssert(testPS([c, b, a]) == "rd3rc2base1") + +type + SBase[T, V] = ref object of RootObj + val: T + color: V + SRC = ref object of SBase[string, int] + SRD = ref object of SBase[string, int] + +proc testS[T, V](x: varargs[SBase[T, V]]): string = + result = "" + for c in x: + result.add c.val + result.add $c.color + +block test_t4799_6: + var a = SBase[string, int](val: "base", color: 1) + var b = SRC(val: "rc", color: 2) + var c = SRD(val: "rd", color: 3) + + doAssert(testS(a, b, c) == "base1rc2rd3") + doAssert(testS(b, a, c) == "rc2base1rd3") + doAssert(testS(c, b, a) == "rd3rc2base1") + doAssert(testS([a, b, c]) == "base1rc2rd3") + # this is not varargs bug, but array construction bug + # see #7955 + #doAssert(testS([b, c, a]) == "rc2rd3base1") + #doAssert(testS([c, b, a]) == "rd3rc2base1") + +proc test_inproc() = + block test_inproc_1: + var rgv = GRBase[int](val: 3) + var rgc = GRC[int](val: 4) + var rgb = GRD[int](val: 2) + doAssert(testGR(rgb, rgc, rgv) == "243") + doAssert(testGR(rgc, rgv, rgb) == "432") + doAssert(testGR(rgv, rgb, rgc) == "324") + doAssert(testGR([rgb, rgc, rgv]) == "243") + doAssert(testGR([rgc, rgv, rgb]) == "432") + doAssert(testGR([rgv, rgb, rgc]) == "324") + + block test_inproc_2: + var pgv = PRBase[int](val: 3) + var pgc = PRC[int](val: 4) + var pgb = PRD[int](val: 2) + doAssert(testPR(pgb.addr, pgc.addr, pgv.addr) == "243") + doAssert(testPR(pgc.addr, pgv.addr, pgb.addr) == "432") + doAssert(testPR(pgv.addr, pgb.addr, pgc.addr) == "324") + doAssert(testPR([pgb.addr, pgc.addr, pgv.addr]) == "243") + doAssert(testPR([pgc.addr, pgv.addr, pgb.addr]) == "432") + doAssert(testPR([pgv.addr, pgb.addr, pgc.addr]) == "324") + +test_inproc() + +template reject(x) = + static: assert(not compiles(x)) + +block test_t4799_7: + type + Vehicle[T] = ref object of RootObj + tire: T + Car[T] = object of Vehicle[T] + Bike[T] = object of Vehicle[T] + + proc testVehicle[T](x: varargs[Vehicle[T]]): string {.used.} = + result = "" + for c in x: + result.add $c.tire + + var v = Vehicle[int](tire: 3) + var c = Car[int](tire: 4) + var b = Bike[int](tire: 2) + + reject: + echo testVehicle(b, c, v) + +block test_t4799_8: + type + Vehicle = ref object of RootObj + tire: int + Car = object of Vehicle + Bike = object of Vehicle + + proc testVehicle(x: varargs[Vehicle]): string {.used.} = + result = "" + for c in x: + result.add $c.tire + + var v = Vehicle(tire: 3) + var c = Car(tire: 4) + var b = Bike(tire: 2) + + reject: + echo testVehicle(b, c, v) + +type + PGVehicle[T] = ptr object of RootObj + tire: T + PGCar[T] = object of PGVehicle[T] + PGBike[T] = object of PGVehicle[T] + +proc testVehicle[T](x: varargs[PGVehicle[T]]): string {.used.} = + result = "" + for c in x: + result.add $c.tire + +var pgc = PGCar[int](tire: 4) +var pgb = PGBike[int](tire: 2) + +reject: + echo testVehicle(pgb, pgc) + +type + RVehicle = ptr object of RootObj + tire: int + RCar = object of RVehicle + RBike = object of RVehicle + +proc testVehicle(x: varargs[RVehicle]): string {.used.} = + result = "" + for c in x: + result.add $c.tire + +var rc = RCar(tire: 4) +var rb = RBike(tire: 2) + +reject: + echo testVehicle(rb, rc) + +echo "OK" diff --git a/tests/typerel/t4799_1.nim b/tests/typerel/t4799_1.nim new file mode 100644 index 000000000..549b6bf3c --- /dev/null +++ b/tests/typerel/t4799_1.nim @@ -0,0 +1,20 @@ +discard """ + outputsub: '''ObjectAssignmentError''' + exitcode: "1" +""" + +type + Vehicle[T] = object of RootObj + tire: T + Car[T] = object of Vehicle[T] + Bike[T] = object of Vehicle[T] + +proc testVehicle[T](x: varargs[Vehicle[T]]): string = + result = "" + for c in x: + result.add $c.tire + +var v = Vehicle[int](tire: 3) +var c = Car[int](tire: 4) +var b = Bike[int](tire: 2) +echo testVehicle b, c, v diff --git a/tests/typerel/t4799_2.nim b/tests/typerel/t4799_2.nim new file mode 100644 index 000000000..cfd399a6e --- /dev/null +++ b/tests/typerel/t4799_2.nim @@ -0,0 +1,20 @@ +discard """ + outputsub: '''ObjectAssignmentError''' + exitcode: "1" +""" + +type + Vehicle[T] = object of RootObj + tire: T + Car[T] = object of Vehicle[T] + Bike[T] = object of Vehicle[T] + +proc testVehicle[T](x: varargs[Vehicle[T]]): string = + result = "" + for c in x: + result.add $c.tire + +var v = Vehicle[int](tire: 3) +var c = Car[int](tire: 4) +var b = Bike[int](tire: 2) +echo testVehicle([b, c, v]) \ No newline at end of file diff --git a/tests/typerel/t4799_3.nim b/tests/typerel/t4799_3.nim new file mode 100644 index 000000000..784eee8fc --- /dev/null +++ b/tests/typerel/t4799_3.nim @@ -0,0 +1,20 @@ +discard """ + outputsub: '''ObjectAssignmentError''' + exitcode: "1" +""" + +type + Vehicle = object of RootObj + tire: int + Car = object of Vehicle + Bike = object of Vehicle + +proc testVehicle(x: varargs[Vehicle]): string = + result = "" + for c in x: + result.add $c.tire + +var v = Vehicle(tire: 3) +var c = Car(tire: 4) +var b = Bike(tire: 2) +echo testVehicle([b, c, v]) \ No newline at end of file |