From a7df3ffbe0ed6d10cc952e47f4e92a69403363dc Mon Sep 17 00:00:00 2001 From: Kay Zheng Date: Sun, 12 Apr 2015 12:59:56 +0800 Subject: [PATCH 01/13] Ignore EvError in `asyncdispatch.poll(...)` for non-windows systems, so that exceptions can be raised from `send(...)` and `recv(...)` --- lib/pure/asyncdispatch.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 27f77cef21..6ed7825453 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -882,9 +882,9 @@ else: let data = PData(info.key.data) assert data.fd == info.key.fd.TAsyncFD #echo("In poll ", data.fd.cint) - if EvError in info.events: - closeSocket(data.fd) - continue + # There may be EvError here, but we handle them in callbacks, + # so that exceptions can be raised from `send(...)` and + # `recv(...)` routines. if EvRead in info.events: # Callback may add items to ``data.readCBs`` which causes issues if From 371d2739249ad33267e0b330e582a04d7d28fd98 Mon Sep 17 00:00:00 2001 From: Kay Zheng Date: Fri, 17 Apr 2015 22:24:06 +0800 Subject: [PATCH 02/13] Add a test case for the EvError handling issue --- tests/async/tasynceverror.nim | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 tests/async/tasynceverror.nim diff --git a/tests/async/tasynceverror.nim b/tests/async/tasynceverror.nim new file mode 100644 index 0000000000..564df569e2 --- /dev/null +++ b/tests/async/tasynceverror.nim @@ -0,0 +1,62 @@ +discard """ + file: "tasynceverror.nim" + exitcode: 1 + outputsub: "Error: unhandled exception: Connection reset by peer [Exception]" +""" + +import + asyncdispatch, + asyncnet, + rawsockets, + os + + +const + testHost = "127.0.0.1" + testPort = Port(17357) + + +proc createListenSocket(host: string, port: Port): TAsyncFD = + result = newAsyncRawSocket() + + SocketHandle(result).setSockOptInt(SOL_SOCKET, SO_REUSEADDR, 1) + + var aiList = getAddrInfo(host, port, AF_INET) + if SocketHandle(result).bindAddr(aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: + dealloc(aiList) + raiseOSError(osLastError()) + dealloc(aiList) + + if SocketHandle(result).listen(1) < 0'i32: + raiseOSError(osLastError()) + + +proc testAsyncSend() {.async.} = + var + ls = createListenSocket(testHost, testPort) + s = newAsyncSocket() + + await s.connect(testHost, testPort) + + var ps = await ls.accept() + SocketHandle(ls).close() + + await ps.send("test 1", flags={}) + s.close() + # This send should raise EPIPE + await ps.send("test 2", flags={}) + SocketHandle(ps).close() + + +# The bug was, when the poll function handled EvError for us, +# our callbacks may never get executed, thus making the event +# loop block indefinitely. This is a timer to keep everything +# rolling. 400 ms is an arbitrary value, should be enough though. +proc timer() {.async.} = + await sleepAsync(400) + echo("Timer expired.") + quit(2) + + +asyncCheck(testAsyncSend()) +waitFor(timer()) From 3125058b6ab4bd9c3ad2cb103bb326463af0a7ff Mon Sep 17 00:00:00 2001 From: Kay Zheng Date: Fri, 17 Apr 2015 22:40:53 +0800 Subject: [PATCH 03/13] Only run the test for the fixed version of poll(...) --- tests/async/tasynceverror.nim | 69 ++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/tests/async/tasynceverror.nim b/tests/async/tasynceverror.nim index 564df569e2..3b81680cbd 100644 --- a/tests/async/tasynceverror.nim +++ b/tests/async/tasynceverror.nim @@ -16,47 +16,50 @@ const testPort = Port(17357) -proc createListenSocket(host: string, port: Port): TAsyncFD = - result = newAsyncRawSocket() +when defined(windows) or defined(nimdoc): + discard +else: + proc createListenSocket(host: string, port: Port): TAsyncFD = + result = newAsyncRawSocket() - SocketHandle(result).setSockOptInt(SOL_SOCKET, SO_REUSEADDR, 1) + SocketHandle(result).setSockOptInt(SOL_SOCKET, SO_REUSEADDR, 1) - var aiList = getAddrInfo(host, port, AF_INET) - if SocketHandle(result).bindAddr(aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: - dealloc(aiList) - raiseOSError(osLastError()) - dealloc(aiList) + var aiList = getAddrInfo(host, port, AF_INET) + if SocketHandle(result).bindAddr(aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: + dealloc(aiList) + raiseOSError(osLastError()) + dealloc(aiList) - if SocketHandle(result).listen(1) < 0'i32: - raiseOSError(osLastError()) + if SocketHandle(result).listen(1) < 0'i32: + raiseOSError(osLastError()) -proc testAsyncSend() {.async.} = - var - ls = createListenSocket(testHost, testPort) - s = newAsyncSocket() + proc testAsyncSend() {.async.} = + var + ls = createListenSocket(testHost, testPort) + s = newAsyncSocket() - await s.connect(testHost, testPort) - - var ps = await ls.accept() - SocketHandle(ls).close() + await s.connect(testHost, testPort) + + var ps = await ls.accept() + SocketHandle(ls).close() - await ps.send("test 1", flags={}) - s.close() - # This send should raise EPIPE - await ps.send("test 2", flags={}) - SocketHandle(ps).close() + await ps.send("test 1", flags={}) + s.close() + # This send should raise EPIPE + await ps.send("test 2", flags={}) + SocketHandle(ps).close() -# The bug was, when the poll function handled EvError for us, -# our callbacks may never get executed, thus making the event -# loop block indefinitely. This is a timer to keep everything -# rolling. 400 ms is an arbitrary value, should be enough though. -proc timer() {.async.} = - await sleepAsync(400) - echo("Timer expired.") - quit(2) + # The bug was, when the poll function handled EvError for us, + # our callbacks may never get executed, thus making the event + # loop block indefinitely. This is a timer to keep everything + # rolling. 400 ms is an arbitrary value, should be enough though. + proc timer() {.async.} = + await sleepAsync(400) + echo("Timer expired.") + quit(2) -asyncCheck(testAsyncSend()) -waitFor(timer()) + asyncCheck(testAsyncSend()) + waitFor(timer()) From a11a2f0fdb3ecdd995e4fc1a6cb41de4e7fc12f2 Mon Sep 17 00:00:00 2001 From: Kay Zheng Date: Sat, 18 Apr 2015 10:27:35 +0800 Subject: [PATCH 04/13] Check for async errors in --- lib/pure/asyncdispatch.nim | 14 +++++++++++--- tests/async/tasyncconnect.nim | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 tests/async/tasyncconnect.nim diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 6ed7825453..ca5b13c78e 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -923,9 +923,17 @@ else: var retFuture = newFuture[void]("connect") proc cb(fd: TAsyncFD): bool = - # We have connected. - retFuture.complete() - return true + var ret = SocketHandle(fd).getSockOptInt(cint(SOL_SOCKET), cint(SO_ERROR)) + if ret == 0: + # We have connected. + retFuture.complete() + return true + elif ret == EINTR: + # interrupted, keep waiting + return false + else: + retFuture.fail(newException(OSError, osErrorMsg(OSErrorCode(ret)))) + return true var aiList = getAddrInfo(address, port, af) var success = false diff --git a/tests/async/tasyncconnect.nim b/tests/async/tasyncconnect.nim new file mode 100644 index 0000000000..bc63b8e82a --- /dev/null +++ b/tests/async/tasyncconnect.nim @@ -0,0 +1,33 @@ +discard """ + file: "tasyncconnect.nim" + exitcode: 1 + outputsub: "Error: unhandled exception: Connection refused [Exception]" +""" + +import + asyncdispatch, + posix + + +const + testHost = "127.0.0.1" + testPort = Port(17357) + + +when defined(windows) or defined(nimdoc): + discard +else: + proc testAsyncConnect() {.async.} = + var s = newAsyncRawSocket() + + await s.connect(testHost, testPort) + + var peerAddr: SockAddr + var addrSize = Socklen(sizeof(peerAddr)) + var ret = SocketHandle(s).getpeername(addr(peerAddr), addr(addrSize)) + + if ret < 0: + echo("`connect(...)` failed but no exception was raised.") + quit(2) + + waitFor(testAsyncConnect()) From 464ec61e9c11deb1a52df431a266ba50bf132304 Mon Sep 17 00:00:00 2001 From: fenekku Date: Thu, 9 Jul 2015 13:22:26 -0400 Subject: [PATCH 05/13] document unittest.nim + code agreement --- lib/pure/unittest.nim | 144 +++++++++++++++++++++++++++++++++---- tests/stdlib/tunittest.nim | 14 ++++ 2 files changed, 145 insertions(+), 13 deletions(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 407db0a517..70b314e635 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -9,7 +9,7 @@ ## :Author: Zahary Karadjov ## -## This module implements boilerplate to make testing easy. +## This module implements boilerplate to make unit testing easy. ## ## Example: ## @@ -41,27 +41,69 @@ when not defined(ECMAScript): import terminal type - TestStatus* = enum OK, FAILED - OutputLevel* = enum PRINT_ALL, PRINT_FAILURES, PRINT_NONE + TestStatus* = enum OK, FAILED ## The status of a test when it is done. + OutputLevel* = enum ## The output verbosity of the tests. + PRINT_ALL, ## Print as much as possible. + PRINT_FAILURES, ## Print only the failed tests. + PRINT_NONE ## Print nothing. {.deprecated: [TTestStatus: TestStatus, TOutputLevel: OutputLevel]} -var - abortOnError* {.threadvar.}: bool - outputLevel* {.threadvar.}: OutputLevel - colorOutput* {.threadvar.}: bool +var ## Global unittest settings! + + abortOnError* {.threadvar.}: bool ## Set to true in order to quit + ## immediately on fail. Default is false, + ## unless the ``NIMTEST_ABORT_ON_ERROR`` + ## environment variable is set for + ## the non-js target. + outputLevel* {.threadvar.}: OutputLevel ## Set the verbosity of test results. + ## Default is ``PRINT_ALL``, unless + ## the ``NIMTEST_OUTPUT_LVL`` environment + ## variable is set for the non-js target. + + colorOutput* {.threadvar.}: bool ## Have test results printed in color. + ## Default is true for the non-js target + ## unless, the environment variable + ## ``NIMTEST_NO_COLOR`` is set. checkpoints {.threadvar.}: seq[string] checkpoints = @[] -template testSetupIMPL*: stmt {.immediate, dirty.} = discard +template testSetupIMPL*: stmt {.immediate, dirty.} = discard #Should this be public or even exist? template testTeardownIMPL*: stmt {.immediate, dirty.} = discard proc shouldRun(testName: string): bool = result = true template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} = + ## Declare a test suite identified by `name` with optional ``setup`` + ## and/or ``teardown`` section. + ## + ## A test suite is a series of one or more related tests sharing a + ## common fixture (``setup``, ``teardown``). The fixture is executed + ## for EACH test. + ## + ## .. code-block:: nim + ## suite "test suite for addition": + ## setup: + ## let result = 4 + ## + ## test "2 + 2 = 4": + ## check(2+2 == result) + ## + ## test "2 + -2 != 4": + ## check(2+2 != result) + ## + ## # No teardown needed + ## + ## The suite will run the individual test cases in the order in which + ## they were listed. With default global settings the above code prints: + ## + ## .. code-block:: + ## + ## [OK] 2 + 2 = 4 + ## [OK] (2 + -2) != 4 block: template setup*(setupBody: stmt): stmt {.immediate, dirty.} = template testSetupIMPL: stmt {.immediate, dirty.} = setupBody @@ -87,6 +129,19 @@ proc testDone(name: string, s: TestStatus) = rawPrint() template test*(name: expr, body: stmt): stmt {.immediate, dirty.} = + ## Define a single test case identified by `name`. + ## + ## .. code-block:: nim + ## + ## test "roses are red": + ## let roses = "red" + ## check(roses == "red") + ## + ## The above code outputs: + ## + ## .. code-block:: + ## + ## [OK] roses are red bind shouldRun, checkpoints, testDone if shouldRun(name): @@ -108,10 +163,32 @@ template test*(name: expr, body: stmt): stmt {.immediate, dirty.} = testDone name, testStatusIMPL proc checkpoint*(msg: string) = + ## Set a checkpoint identified by `msg`. Upon test failure all + ## checkpoints encountered so far are printed out. Example: + ## + ## .. code-block:: nim + ## + ## checkpoint("Checkpoint A") + ## check((42, "the Answer to life and everything") == (1, "a")) + ## checkpoint("Checkpoint B") + ## + ## outputs "Checkpoint A" once it fails. checkpoints.add(msg) # TODO: add support for something like SCOPED_TRACE from Google Test template fail* = + ## Print out the checkpoints encountered so far and quit if ``abortOnError`` + ## is true. Otherwise, erase the checkpoints and indicate the test has + ## failed (change exit code and test status). This template is useful + ## for debugging, but is otherwise mostly used internally. Example: + ## + ## .. code-block:: nim + ## + ## checkpoint("Checkpoint A") + ## complicatedProcInThread() + ## fail() + ## + ## outputs "Checkpoint A" before quitting. bind checkpoints for msg in items(checkpoints): echo msg @@ -127,8 +204,23 @@ template fail* = checkpoints = @[] macro check*(conditions: stmt): stmt {.immediate.} = + ## Verify if a statement or a list of statements is true. + ## A helpful error message and set checkpoints are printed out on + ## failure (if ``outputLevel`` is not ``PRINT_NONE``). + ## Example: + ## + ## .. code-block:: nim + ## + ## import strutils + ## + ## check("AKB48".toLower() == "akb48") + ## + ## let teams = {'A', 'K', 'B', '4', '8'} + ## + ## check: + ## "AKB48".toLower() == "akb48" + ## 'C' in teams let checked = callsite()[1] - var argsAsgns = newNimNode(nnkStmtList) argsPrintOuts = newNimNode(nnkStmtList) @@ -143,7 +235,7 @@ macro check*(conditions: stmt): stmt {.immediate.} = checkpoint(name & " was " & $value) proc inspectArgs(exp: NimNode) = - for i in 1 .. Date: Fri, 24 Jul 2015 18:08:05 +0200 Subject: [PATCH 06/13] Fix times' parse with literal strings --- lib/pure/times.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index e4d3f7494e..fd5eb7ba4a 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1020,10 +1020,10 @@ proc parse*(value, layout: string): TimeInfo = # These are literals in both the layout and the value string if layout[i] == '\'': inc(i) - inc(j) while layout[i] != '\'' and layout.len-1 > i: inc(i) inc(j) + inc(i) else: inc(i) inc(j) @@ -1112,6 +1112,8 @@ when isMainModule: s = "2006-01-12T15:04:05Z-07:00" f = "yyyy-MM-ddTHH:mm:ssZzzz" assert($s.parse(f) == "Thu Jan 12 15:04:05 2006") + f = "yyyy-MM-dd'T'HH:mm:ss'Z'zzz" + assert($s.parse(f) == "Thu Jan 12 15:04:05 2006") # RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" s = "2006-01-12T15:04:05.999999999Z-07:00" f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz" From a88131ed4a660d6eba543a11c2df66c04cdd3908 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 24 Jul 2015 22:46:24 +0100 Subject: [PATCH 07/13] Improved errors in times.parse. --- lib/pure/times.nim | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index fd5eb7ba4a..f1315a9fd7 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -789,7 +789,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = of "sat": info.weekday = dSat else: - raise newException(ValueError, "invalid day of week ") + raise newException(ValueError, + "Couldn't parse day of week (ddd), got: " & value[j..j+2]) j += 3 of "dddd": if value.len >= j+6 and value[j..j+5].cmpIgnoreCase("sunday") == 0: @@ -814,7 +815,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = info.weekday = dSat j += 8 else: - raise newException(ValueError, "invalid day of week ") + raise newException(ValueError, + "Couldn't parse day of week (dddd), got: " & value) of "h", "H": var pd = parseInt(value[j..j+1], sv) info.hour = sv @@ -865,7 +867,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = of "dec": info.month = mDec else: - raise newException(ValueError, "invalid month") + raise newException(ValueError, + "Couldn't parse month (MMM), got: " & value) j += 3 of "MMMM": if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0: @@ -905,7 +908,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = info.month = mDec j += 8 else: - raise newException(ValueError, "invalid month") + raise newException(ValueError, + "Couldn't parse month (MMMM), got: " & value) of "s": var pd = parseInt(value[j..j+1], sv) info.second = sv @@ -936,7 +940,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = elif value[j] == '-': info.timezone = 0-parseInt($value[j+1]) else: - raise newException(ValueError, "Sign for timezone " & value[j]) + raise newException(ValueError, + "Couldn't parse timezone offset (z), got: " & value[j]) j += 2 of "zz": if value[j] == '+': @@ -944,7 +949,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = elif value[j] == '-': info.timezone = 0-value[j+1..j+2].parseInt() else: - raise newException(ValueError, "Sign for timezone " & value[j]) + raise newException(ValueError, + "Couldn't parse timezone offset (zz), got: " & value[j]) j += 3 of "zzz": if value[j] == '+': @@ -952,7 +958,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = elif value[j] == '-': info.timezone = 0-value[j+1..j+2].parseInt() else: - raise newException(ValueError, "Sign for timezone " & value[j]) + raise newException(ValueError, + "Couldn't parse timezone offset (zzz), got: " & value[j]) j += 6 of "ZZZ": info.tzname = value[j..j+2].toUpper() From ce4e877702d361acd511b14364c26956c06a63d7 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 26 Jul 2015 18:15:19 +0100 Subject: [PATCH 08/13] `$` for tuples/objects now handles a nil value correctly. Fixes #3149. --- lib/system.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index c5b0e0cc77..91495f31a6 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2173,7 +2173,11 @@ proc `$`*[T: tuple|object](x: T): string = if not firstElement: result.add(", ") result.add(name) result.add(": ") - result.add($value) + when compiles(value.isNil): + if value.isNil: result.add "nil" + else: result.add($value) + else: + result.add($value) firstElement = false result.add(")") From 94ad731964af518745647f15ce56d1c65e155847 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 26 Jul 2015 18:21:14 +0100 Subject: [PATCH 09/13] Fixes example code in marshal module. --- lib/pure/marshal.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 49f049e468..173cd1e811 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -17,7 +17,7 @@ ## .. code-block:: nim ## ## type -## A = object +## A = object of RootObj ## B = object of A ## f: int ## From beca7ded1b352493bf5aa1bd4d3067bdb736547b Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 26 Jul 2015 21:06:59 +0200 Subject: [PATCH 10/13] fixes #3144 --- compiler/ccgcalls.nim | 38 ++++++++++++++++----------------- compiler/jsgen.nim | 11 +++++++++- tests/metatype/tstatic_ones.nim | 28 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 20 deletions(-) create mode 100644 tests/metatype/tstatic_ones.nim diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 2dacc25e9f..86ecc9db88 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -159,6 +159,17 @@ proc genArgNoParam(p: BProc, n: PNode): Rope = initLocExprSingleUse(p, n, a) result = rdLoc(a) +template genParamLoop(params) {.dirty.} = + if i < sonsLen(typ): + assert(typ.n.sons[i].kind == nkSym) + let paramType = typ.n.sons[i] + if not paramType.typ.isCompileTimeOnly: + if params != nil: add(params, ~", ") + add(params, genArg(p, ri.sons[i], paramType.sym, ri)) + else: + if params != nil: add(params, ~", ") + add(params, genArgNoParam(p, ri.sons[i])) + proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = var op: TLoc # this is a hotspot in the compiler @@ -170,13 +181,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = assert(sonsLen(typ) == sonsLen(typ.n)) var length = sonsLen(ri) for i in countup(1, length - 1): - if ri.sons[i].typ.isCompileTimeOnly: continue - if params != nil: add(params, ~", ") - if i < sonsLen(typ): - assert(typ.n.sons[i].kind == nkSym) - add(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri)) - else: - add(params, genArgNoParam(p, ri.sons[i])) + genParamLoop(params) fixupCall(p, le, ri, d, op.r, params) proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = @@ -198,13 +203,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = var length = sonsLen(ri) for i in countup(1, length - 1): assert(sonsLen(typ) == sonsLen(typ.n)) - if ri.sons[i].typ.isCompileTimeOnly: continue - if i < sonsLen(typ): - assert(typ.n.sons[i].kind == nkSym) - add(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri)) - else: - add(pl, genArgNoParam(p, ri.sons[i])) - if i < length - 1: add(pl, ~", ") + genParamLoop(pl) template genCallPattern {.dirty.} = lineF(p, cpsStmts, callPattern & ";$n", [op.r, pl, pl.addComma, rawProc]) @@ -241,13 +240,14 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = genCallPattern() proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = - if ri.sons[i].typ.isCompileTimeOnly: - result = nil - elif i < sonsLen(typ): + if i < sonsLen(typ): # 'var T' is 'T&' in C++. This means we ignore the request of # any nkHiddenAddr when it's a 'var T'. - assert(typ.n.sons[i].kind == nkSym) - if typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr: + let paramType = typ.n.sons[i] + assert(paramType.kind == nkSym) + if paramType.typ.isCompileTimeOnly: + result = nil + elif typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr: result = genArgNoParam(p, ri.sons[i][0]) else: result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 87408f3955..6e317fb7e8 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1046,9 +1046,18 @@ proc genArg(p: PProc, n: PNode, r: var TCompRes) = proc genArgs(p: PProc, n: PNode, r: var TCompRes) = add(r.res, "(") var hasArgs = false + + var typ = skipTypes(n.sons[0].typ, abstractInst) + assert(typ.kind == tyProc) + assert(sonsLen(typ) == sonsLen(typ.n)) + for i in countup(1, sonsLen(n) - 1): let it = n.sons[i] - if it.typ.isCompileTimeOnly: continue + if i < sonsLen(typ): + assert(typ.n.sons[i].kind == nkSym) + let paramType = typ.n.sons[i] + if paramType.typ.isCompileTimeOnly: continue + if hasArgs: add(r.res, ", ") genArg(p, it, r) hasArgs = true diff --git a/tests/metatype/tstatic_ones.nim b/tests/metatype/tstatic_ones.nim new file mode 100644 index 0000000000..73a88447d2 --- /dev/null +++ b/tests/metatype/tstatic_ones.nim @@ -0,0 +1,28 @@ +discard """ + output: "@[2, 2, 2, 2, 2]" +""" + +# bug #3144 + +type IntArray[N: static[int]] = array[N, int] + +proc `$`(a: IntArray): string = $(@(a)) + +proc `+=`[N: static[int]](a: var IntArray[N], b: IntArray[N]) = + for i in 0 .. < N: + a[i] += b[i] + +proc zeros(N: static[int]): IntArray[N] = + for i in 0 .. < N: + result[i] = 0 + +proc ones(N: static[int]): IntArray[N] = + for i in 0 .. < N: + result[i] = 1 + +proc sum[N: static[int]](vs: seq[IntArray[N]]): IntArray[N] = + result = zeros(N) + for v in vs: + result += v + +echo sum(@[ones(5), ones(5)]) From 54fdeb4f76e0fc1e07332e2d4f0b00ff014d4f5f Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 26 Jul 2015 22:03:52 +0200 Subject: [PATCH 11/13] gc:none works again --- compiler/cgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index bfc80b2a1a..2e95918cc7 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -950,7 +950,7 @@ proc genMainProc(m: BModule) = gBreakpoints.add(m.genFilenames) let initStackBottomCall = - if platform.targetOS == osStandalone: "".rope + if platform.targetOS == osStandalone or gSelectedGC == gcNone: "".rope else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N") inc(m.labels) appcg(m, m.s[cfsProcs], PreMainBody, [ From 8913e82f4505cb542c06545696ef687a52cd080c Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 28 Jul 2015 02:54:07 +0200 Subject: [PATCH 12/13] removed macros.high as it never worked outside of macros.nim --- lib/core/macros.nim | 18 ++++++++---------- web/news.txt | 2 ++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 7d1c15610a..c89fa354a3 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -592,10 +592,8 @@ proc newNilLit*(): NimNode {.compileTime.} = ## New nil literal shortcut result = newNimNode(nnkNilLit) -proc high*(node: NimNode): int {.compileTime.} = len(node) - 1 - ## Return the highest index available for a node -proc last*(node: NimNode): NimNode {.compileTime.} = node[node.high] - ## Return the last item in nodes children. Same as `node[node.high()]` +proc last*(node: NimNode): NimNode {.compileTime.} = node[