From 277bf1098c2662d21314692963f0596abfc30d3e Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sun, 17 Sep 2017 13:43:22 +0100 Subject: [PATCH 01/10] Add check for broken code-block in docs --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 095c3ec74f..6b8cdbe03b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,3 +48,5 @@ script: - ./koch csource - ./koch nimsuggest # - nim c -r nimsuggest/tester + - ( ! grep -F '.. code-block' -l -r --include '*.html' --exclude contributing.html --exclude docgen.html --exclude tut2.html ) + - ( ! grep -F '..code-block' -l -r --include '*.html' --exclude contributing.html --exclude docgen.html --exclude tut2.html ) From ff98fe1387a24fbe5a09f64264a75a1b25f086d5 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sun, 17 Sep 2017 17:32:06 +0100 Subject: [PATCH 02/10] Fix broken code-block in docs --- lib/pure/times.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index c1d6c3e530..587ea1903b 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -305,6 +305,7 @@ proc `+`*(ti1, ti2: TimeInterval): TimeInterval = proc `-`*(ti: TimeInterval): TimeInterval = ## Reverses a time interval + ## ## .. code-block:: nim ## ## let day = -initInterval(hours=24) From 25831a83d799a0400fbd086ea9a6f704d4d6b216 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sat, 11 Nov 2017 16:59:42 +0000 Subject: [PATCH 03/10] Add unittest suite/test name filters Support simple globbing --- lib/pure/unittest.nim | 91 +++++++++++++++++++++++++++++++++----- tests/stdlib/tunittest.nim | 38 ++++++++++++++++ 2 files changed, 118 insertions(+), 11 deletions(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 7a8d1dad09..fbce087ffd 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -21,13 +21,41 @@ ## ``nim c -r `` exits with 0 or 1 ## ## Running a single test -## --------------------- +## ===================== ## -## Simply specify the test name as a command line argument. +## Specify the test name as a command line argument. ## ## .. code:: ## -## nim c -r test "my super awesome test name" +## nim c -r test "my test name" "another test" +## +## Multiple arguments can be used. +## +## Running a single test suite +## =========================== +## +## Specify the suite name delimited by ``"::"``. +## +## .. code:: +## +## nim c -r test "my test name::" +## +## Selecting tests by pattern +## ========================== +## +## A single ``"*"`` can be used for globbing. +## +## Delimit the end of a suite name with ``"::"``. +## +## Tests matching **any** of the arguments are executed. +## +## .. code:: +## +## nim c -r test fast_suite::mytest1 fast_suite::mytest2 +## nim c -r test "fast_suite::mytest*" +## nim c -r test "auth*::" "crypto::hashing*" +## # Run suites starting with 'bug #' and standalone tests starting with '#' +## nim c -r test 'bug #*::' '::#*' ## ## Example ## ------- @@ -121,7 +149,7 @@ var checkpoints {.threadvar.}: seq[string] formatters {.threadvar.}: seq[OutputFormatter] - testsToRun {.threadvar.}: HashSet[string] + testsFilters {.threadvar.}: HashSet[string] when declared(stdout): abortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR") @@ -300,22 +328,63 @@ method testEnded*(formatter: JUnitOutputFormatter, testResult: TestResult) = method suiteEnded*(formatter: JUnitOutputFormatter) = formatter.stream.writeLine("\t") -proc shouldRun(testName: string): bool = - if testsToRun.len == 0: +proc glob(matcher, filter: string): bool = + ## Globbing using a single `*`. Empty `filter` matches everything. + if filter.len == 0: return true - result = testName in testsToRun + if not filter.contains('*'): + return matcher == filter + + let beforeAndAfter = filter.split('*', maxsplit=1) + if beforeAndAfter.len == 1: + # "foo*" + return matcher.startswith(beforeAndAfter[0]) + + if matcher.len < filter.len - 1: + return false # "12345" should not match "123*345" + + return matcher.startsWith(beforeAndAfter[0]) and matcher.endsWith(beforeAndAfter[1]) + +proc matchFilter(suiteName, testName, filter: string): bool = + if filter == "": + return true + if testName == filter: + # corner case for tests containing "::" in their name + return true + let suiteAndTestFilters = filter.split("::", maxsplit=1) + + if suiteAndTestFilters.len == 1: + # no suite specified + let test_f = suiteAndTestFilters[0] + return glob(testName, test_f) + + return glob(suiteName, suiteAndTestFilters[0]) and glob(testName, suiteAndTestFilters[1]) + +when defined(testing): export matchFilter + +proc shouldRun(currentSuiteName, testName: string): bool = + ## Check if a test should be run by matching suiteName and testName against + ## test filters. + if testsFilters.len == 0: + return true + + for f in testsFilters: + if matchFilter(currentSuiteName, testName, f): + return true + + return false proc ensureInitialized() = if formatters == nil: formatters = @[OutputFormatter(defaultConsoleFormatter())] - if not testsToRun.isValid: - testsToRun.init() + if not testsFilters.isValid: + testsFilters.init() when declared(paramCount): # Read tests to run from the command line. for i in 1 .. paramCount(): - testsToRun.incl(paramStr(i)) + testsFilters.incl(paramStr(i)) # These two procs are added as workarounds for # https://github.com/nim-lang/Nim/issues/5549 @@ -395,7 +464,7 @@ template test*(name, body) {.dirty.} = ensureInitialized() - if shouldRun(name): + if shouldRun(when declared(testSuiteName): testSuiteName else: "", name): checkpoints = @[] var testStatusIMPL {.inject.} = OK diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim index e4a8018713..86b9fd0370 100644 --- a/tests/stdlib/tunittest.nim +++ b/tests/stdlib/tunittest.nim @@ -13,6 +13,8 @@ discard """ [Suite] bug #5784 +[Suite] test name filtering + ''' """ @@ -120,3 +122,39 @@ suite "bug #5784": field: int var obj: Obj check obj.isNil or obj.field == 0 + +when defined(testing): + suite "test name filtering": + test "test name": + check matchFilter("suite1", "foo", "") + check matchFilter("suite1", "foo", "foo") + check matchFilter("suite1", "foo", "::") + check matchFilter("suite1", "foo", "*") + check matchFilter("suite1", "foo", "::foo") + check matchFilter("suite1", "::foo", "::foo") + + test "test name - glob": + check matchFilter("suite1", "foo", "f*") + check matchFilter("suite1", "foo", "*oo") + check matchFilter("suite1", "12345", "12*345") + check matchFilter("suite1", "q*wefoo", "q*wefoo") + check false == matchFilter("suite1", "foo", "::x") + check false == matchFilter("suite1", "foo", "::x*") + check false == matchFilter("suite1", "foo", "::*x") + # overlap + check false == matchFilter("suite1", "12345", "123*345") + check matchFilter("suite1", "ab*c::d*e::f", "ab*c::d*e::f") + + test "suite name": + check matchFilter("suite1", "foo", "suite1::") + check false == matchFilter("suite1", "foo", "suite2::") + check matchFilter("suite1", "qwe::foo", "qwe::foo") + check matchFilter("suite1", "qwe::foo", "suite1::qwe::foo") + + test "suite name - glob": + check matchFilter("suite1", "foo", "::*") + check matchFilter("suite1", "foo", "*::*") + check matchFilter("suite1", "foo", "*::foo") + check false == matchFilter("suite1", "foo", "*ite2::") + check matchFilter("suite1", "q**we::foo", "q**we::foo") + check matchFilter("suite1", "a::b*c::d*e", "a::b*c::d*e") From b22d9e4339f06e6af02f8da50e68a98707987612 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Thu, 21 Dec 2017 16:45:42 +0200 Subject: [PATCH 04/10] Fix #6906 --- lib/pure/asyncdispatch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 675e8fc5eb..23eb80b37b 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1234,7 +1234,7 @@ else: processBasicCallbacks(fd, writeList) result = true - if Event.User in events or events == {Event.Error}: + if Event.User in events: processBasicCallbacks(fd, readList) custom = true if rLength == 0: From ca9f3b47d41c1a2a525df1b850194e28ac0da728 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 23 Dec 2017 14:08:47 +0000 Subject: [PATCH 05/10] Add link to #6934 in changelog.md --- changelog.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 4d205faf89..efdd1f5207 100644 --- a/changelog.md +++ b/changelog.md @@ -102,10 +102,12 @@ This now needs to be written as: - Nim's ``rst2html`` command now supports the testing of code snippets via an RST extension that we called ``:test:``:: + ```rst .. code-block:: nim :test: # shows how the 'if' statement works if true: echo "yes" + ``` - The ``[]`` proc for strings now raises an ``IndexError`` exception when the specified slice is out of bounds. See issue [#6223](https://github.com/nim-lang/Nim/issues/6223) for more details. @@ -130,7 +132,8 @@ This now needs to be written as: - The ``random`` procs in ``random.nim`` have all been deprecated. Instead use the new ``rand`` procs. The module now exports the state of the random number generator as type ``Rand`` so multiple threads can easily use their - own random number generators that do not require locking. + own random number generators that do not require locking. For more information + about this rename see issue [#6934](https://github.com/nim-lang/Nim/issues/6934) - The compiler is now more consistent in its treatment of ambiguous symbols: Types that shadow procs and vice versa are marked as ambiguous (bug #6693). - ``yield`` (or ``await`` which is mapped to ``yield``) never worked reliably From 6bd3a2826fb559d4e88cd2fa5ba89be995553700 Mon Sep 17 00:00:00 2001 From: Mathias Stearn Date: Sun, 24 Dec 2017 09:23:17 -0500 Subject: [PATCH 06/10] cmp(x, y: string) now uses memcmp rather than strcmp (#6869) (#6968) --- lib/system.nim | 5 ++++- lib/system/sysstr.nim | 8 ++++---- tests/stdlib/tstring.nim | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 83e87683ab..85643891ba 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2916,7 +2916,10 @@ when not defined(JS): #and not defined(nimscript): elif x > y: result = 1 else: result = 0 else: - result = int(c_strcmp(x, y)) + let minlen = min(x.len, y.len) + result = int(c_memcmp(x.cstring, y.cstring, minlen.csize)) + if result == 0: + result = x.len - y.len when defined(nimscript): proc readFile*(filename: string): string {.tags: [ReadIOEffect], benign.} diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 56b8ade97a..4c5f3d9a15 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -24,10 +24,10 @@ proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} = if a == b: return 0 if a == nil: return -1 if b == nil: return 1 - when defined(nimNoArrayToCstringConversion): - return c_strcmp(addr a.data, addr b.data) - else: - return c_strcmp(a.data, b.data) + let minlen = min(a.len, b.len) + result = c_memcmp(addr a.data, addr b.data, minlen.csize) + if result == 0: + result = a.len - b.len proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} = if a == b: return true diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim index 904bc462a2..6607461500 100644 --- a/tests/stdlib/tstring.nim +++ b/tests/stdlib/tstring.nim @@ -56,4 +56,24 @@ proc test_string_slice() = echo("OK") +proc test_string_cmp() = + let world = "hello\0world" + let earth = "hello\0earth" + let short = "hello\0" + let hello = "hello" + let goodbye = "goodbye" + + doAssert world == world + doAssert world != earth + doAssert world != short + doAssert world != hello + doAssert world != goodbye + + doAssert cmp(world, world) == 0 + doAssert cmp(world, earth) > 0 + doAssert cmp(world, short) > 0 + doAssert cmp(world, hello) > 0 + doAssert cmp(world, goodbye) > 0 + test_string_slice() +test_string_cmp() From 2b3ec0a7c66d2246371ed51348aaa87d4c3cf0f9 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 25 Dec 2017 00:22:03 +0300 Subject: [PATCH 07/10] Implement language feature #6885 (#6954) --- changelog.md | 22 ++++++++++++++ compiler/msgs.nim | 6 ++-- compiler/pragmas.nim | 2 ++ compiler/sem.nim | 13 ++++++++ compiler/semstmts.nim | 24 ++++++++------- lib/system/chcks.nim | 1 - tests/casestmt/tcasestm.nim | 59 +++++++++++++++++++++++++++++++++++++ tests/pragmas/tnoreturn.nim | 18 +++++++++++ 8 files changed, 131 insertions(+), 14 deletions(-) create mode 100644 tests/pragmas/tnoreturn.nim diff --git a/changelog.md b/changelog.md index efdd1f5207..5734a4cb12 100644 --- a/changelog.md +++ b/changelog.md @@ -144,3 +144,25 @@ This now needs to be written as: - codegenDecl pragma now works for the JavaScript backend. It returns an empty string for function return type placeholders. - Asynchronous programming for the JavaScript backend using the `asyncjs` module. +- Extra semantic checks for procs with noreturn pragma: return type is not allowed, + statements after call to noreturn procs are no longer allowed. +- Noreturn proc calls and raising exceptions branches are now skipped during common type + deduction in if and case expressions. The following code snippets now compile: +```nim +import strutils +let str = "Y" +let a = case str: + of "Y": true + of "N": false + else: raise newException(ValueError, "Invalid boolean") +let b = case str: + of nil, "": raise newException(ValueError, "Invalid boolean") + elif str.startsWith("Y"): true + elif str.startsWith("N"): false + else: false +let c = if str == "Y": true + elif str == "N": false + else: + echo "invalid bool" + quit("this is the end") +``` diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 2668c72ae0..4e6226122e 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -26,7 +26,8 @@ type errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation, errExceptionExpected, errExceptionAlreadyHandled, errYieldNotAllowedHere, errYieldNotAllowedInTryStmt, - errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine, + errInvalidNumberOfYieldExpr, errCannotReturnExpr, + errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine, errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel, errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected, errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler, @@ -179,8 +180,9 @@ const errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator", errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions", errCannotReturnExpr: "current routine cannot return an expression", + errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type", errAttemptToRedefine: "redefinition of \'$1\'", - errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\' or \'continue'", + errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\', \'continue\' or proc call with noreturn pragma", errStmtExpected: "statement expected", errInvalidLabel: "\'$1\' is no label", errInvalidCmdLineOption: "invalid command line option: \'$1\'", diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index b598cadb20..35fedf4ea1 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -771,6 +771,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, of wNoreturn: noVal(it) incl(sym.flags, sfNoReturn) + if sym.ast[paramsPos][0].kind != nkEmpty: + localError(sym.ast[paramsPos][0].info, errNoReturnWithReturnTypeNotAllowed) of wDynlib: processDynLib(c, it, sym) of wCompilerproc: diff --git a/compiler/sem.nim b/compiler/sem.nim index bc994201d1..ababbd303c 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -165,6 +165,19 @@ proc commonType*(x, y: PType): PType = result = newType(k, r.owner) result.addSonSkipIntLit(r) +proc endsInNoReturn(n: PNode): bool = + # check if expr ends in raise exception or call of noreturn proc + var it = n + while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0: + it = it.lastSon + result = it.kind == nkRaiseStmt or + it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags + +proc commonType*(x: PType, y: PNode): PType = + # ignore exception raising branches in case/if expressions + if endsInNoReturn(y): return x + commonType(x, y.typ) + proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) when defined(nimsuggest): diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 8ed120c98f..b1fa8c19b8 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -165,14 +165,14 @@ proc semIf(c: PContext, n: PNode): PNode = it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0])) when not newScopeForIf: openScope(c) it.sons[1] = semExprBranch(c, it.sons[1]) - typ = commonType(typ, it.sons[1].typ) + typ = commonType(typ, it.sons[1]) closeScope(c) elif it.len == 1: hasElse = true it.sons[0] = semExprBranchScope(c, it.sons[0]) - typ = commonType(typ, it.sons[0].typ) + typ = commonType(typ, it.sons[0]) else: illFormedAst(it) - if isEmptyType(typ) or typ.kind == tyNil or not hasElse: + if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: for it in n: discardCheck(c, it.lastSon) result.kind = nkIfStmt # propagate any enforced VoidContext: @@ -180,7 +180,8 @@ proc semIf(c: PContext, n: PNode): PNode = else: for it in n: let j = it.len-1 - it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info) + if not endsInNoReturn(it.sons[j]): + it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info) result.kind = nkIfExpr result.typ = typ @@ -213,7 +214,7 @@ proc semCase(c: PContext, n: PNode): PNode = semCaseBranch(c, n, x, i, covered) var last = sonsLen(x)-1 x.sons[last] = semExprBranchScope(c, x.sons[last]) - typ = commonType(typ, x.sons[last].typ) + typ = commonType(typ, x.sons[last]) of nkElifBranch: chckCovered = false checkSonsLen(x, 2) @@ -221,13 +222,13 @@ proc semCase(c: PContext, n: PNode): PNode = x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0])) when not newScopeForIf: openScope(c) x.sons[1] = semExprBranch(c, x.sons[1]) - typ = commonType(typ, x.sons[1].typ) + typ = commonType(typ, x.sons[1]) closeScope(c) of nkElse: chckCovered = false checkSonsLen(x, 1) x.sons[0] = semExprBranchScope(c, x.sons[0]) - typ = commonType(typ, x.sons[0].typ) + typ = commonType(typ, x.sons[0]) hasElse = true else: illFormedAst(x) @@ -237,7 +238,7 @@ proc semCase(c: PContext, n: PNode): PNode = else: localError(n.info, errNotAllCasesCovered) closeScope(c) - if isEmptyType(typ) or typ.kind == tyNil or not hasElse: + if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) # propagate any enforced VoidContext: if typ == enforceVoidContext: @@ -246,7 +247,8 @@ proc semCase(c: PContext, n: PNode): PNode = for i in 1..n.len-1: var it = n.sons[i] let j = it.len-1 - it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info) + if not endsInNoReturn(it.sons[j]): + it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info) result.typ = typ proc semTry(c: PContext, n: PNode): PNode = @@ -1851,8 +1853,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = else: n.typ = n.sons[i].typ if not isEmptyType(n.typ): n.kind = nkStmtListExpr - case n.sons[i].kind - of LastBlockStmts: + if n.sons[i].kind in LastBlockStmts or + n.sons[i].kind in nkCallKinds and n.sons[i][0].kind == nkSym and sfNoReturn in n.sons[i][0].sym.flags: for j in countup(i + 1, length - 1): case n.sons[j].kind of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr, diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 1520f231e1..69b680dbdc 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -63,7 +63,6 @@ proc chckObj(obj, subclass: PNimType) {.compilerproc.} = while x != subclass: if x == nil: sysFatal(ObjectConversionError, "invalid object conversion") - break x = x.base proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} = diff --git a/tests/casestmt/tcasestm.nim b/tests/casestmt/tcasestm.nim index 7ac20bf2f6..b005d8120e 100644 --- a/tests/casestmt/tcasestm.nim +++ b/tests/casestmt/tcasestm.nim @@ -36,5 +36,64 @@ var z = case i echo z #OUT ayyy +let str1 = "Y" +let str2 = "NN" +let a = case str1: + of "Y": true + of "N": false + else: + echo "no good" + quit("quiting") + +let b = case str2: + of nil, "": raise newException(ValueError, "Invalid boolean") + elif str2[0] == 'Y': true + elif str2[0] == 'N': false + else: "error".quit(2) + +doAssert(a == true) +doAssert(b == false) + +var bb: bool +doassert(not compiles( + bb = case str2: + of nil, "": raise newException(ValueError, "Invalid boolean") + elif str.startsWith("Y"): true + elif str.startsWith("N"): false +)) + +doassert(not compiles( + bb = case str2: + of "Y": true + of "N": false +)) + +doassert(not compiles( + bb = case str2: + of "Y": true + of "N": raise newException(ValueError, "N not allowed") +)) + +doassert(not compiles( + bb = case str2: + of "Y": raise newException(ValueError, "Invalid Y") + else: raise newException(ValueError, "Invalid N") +)) +doassert(not compiles( + bb = case str2: + of "Y": + raise newException(ValueError, "Invalid Y") + true + else: raise newException(ValueError, "Invalid") +)) + + +doassert(not compiles( + bb = case str2: + of "Y": + "invalid Y".quit(3) + true + else: raise newException(ValueError, "Invalid") +)) \ No newline at end of file diff --git a/tests/pragmas/tnoreturn.nim b/tests/pragmas/tnoreturn.nim new file mode 100644 index 0000000000..2075b352e6 --- /dev/null +++ b/tests/pragmas/tnoreturn.nim @@ -0,0 +1,18 @@ +discard """ +ccodeCheck: "\\i @'__attribute__((noreturn))' .*" +""" + +proc noret1*(i: int) {.noreturn.} = + echo i + +var p {.used.}: proc(i: int): int +doAssert(not compiles( + p = proc(i: int): int {.noreturn.} = i # noreturn lambda returns int +)) + + +doAssert(not compiles( + block: + noret1(5) + echo 1 # statement after noreturn +)) From 53cf0b2c24e5adc4fa99e49ddf1834991d663846 Mon Sep 17 00:00:00 2001 From: cooldome Date: Wed, 27 Dec 2017 12:09:24 +0300 Subject: [PATCH 08/10] Allow noreturn procs with void type (#6973) --- compiler/pragmas.nim | 2 +- tests/pragmas/tnoreturn.nim | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 35fedf4ea1..02b57d5a30 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -771,7 +771,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, of wNoreturn: noVal(it) incl(sym.flags, sfNoReturn) - if sym.ast[paramsPos][0].kind != nkEmpty: + if sym.typ[0] != nil: localError(sym.ast[paramsPos][0].info, errNoReturnWithReturnTypeNotAllowed) of wDynlib: processDynLib(c, it, sym) diff --git a/tests/pragmas/tnoreturn.nim b/tests/pragmas/tnoreturn.nim index 2075b352e6..4d00c60346 100644 --- a/tests/pragmas/tnoreturn.nim +++ b/tests/pragmas/tnoreturn.nim @@ -5,6 +5,10 @@ ccodeCheck: "\\i @'__attribute__((noreturn))' .*" proc noret1*(i: int) {.noreturn.} = echo i + +proc noret2*(i: int): void {.noreturn.} = + echo i + var p {.used.}: proc(i: int): int doAssert(not compiles( p = proc(i: int): int {.noreturn.} = i # noreturn lambda returns int From b103b4d3f2c8ac16e8f30f72cf733ace21bbc3a6 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 27 Dec 2017 10:23:57 +0100 Subject: [PATCH 09/10] manual: clarify the rules for integer literals --- doc/manual/types.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual/types.txt b/doc/manual/types.txt index 56584f2570..1477995dda 100644 --- a/doc/manual/types.txt +++ b/doc/manual/types.txt @@ -41,7 +41,8 @@ These integer types are pre-defined: ``int`` the generic signed integer type; its size is platform dependent and has the same size as a pointer. This type should be used in general. An integer - literal that has no type suffix is of this type. + literal that has no type suffix is of this type if it is in the range + ``low(int32)..high(int32)`` otherwise the literal's type is ``int64``. intXX additional signed integer types of XX bits use this naming scheme From 5c08092b88c0b6399c52804fd6f2c1fc92c58a86 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 27 Dec 2017 10:25:45 +0100 Subject: [PATCH 10/10] minor todo.txt update --- todo.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/todo.txt b/todo.txt index 1fae1ddacb..e06ddf5554 100644 --- a/todo.txt +++ b/todo.txt @@ -1,8 +1,6 @@ version 1.0 battle plan ======================= -- introduce ``nkStmtListExpr`` for template/macro invokations to produce - better stack traces - let 'doAssert' analyse the expressions and produce more helpful output - fix "high priority" bugs - try to fix as many compiler crashes as reasonable @@ -11,6 +9,8 @@ version 1.0 battle plan Not critical for 1.0 ==================== +- introduce ``nkStmtListExpr`` for template/macro invokations to produce + better stack traces - make 'break' not leave named blocks - make FlowVar compatible to Futures - make 'not nil' the default (produce warnings instead of errors for