From 733ed91d3377aee2d436b60da6a4d78afa2f9bc5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 9 Feb 2017 17:40:24 +0100 Subject: [PATCH 01/67] disable transitive closure computations; only semcheck procs that have the cursor --- compiler/modulegraphs.nim | 2 +- compiler/semstmts.nim | 60 +++++++++++++++++++++++++-------------- compiler/suggest.nim | 4 +-- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 87a35b2900..fb8f5cf04b 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -73,7 +73,7 @@ proc addDep*(g: ModuleGraph; m: PSym, dep: int32) = deps.incl m.position.dependsOn(dep) # we compute the transitive closure later when quering the graph lazily. # this improve efficiency quite a lot: - invalidTransitiveClosure = true + #invalidTransitiveClosure = true proc addIncludeDep*(g: ModuleGraph; module, includeFile: int32) = discard hasKeyOrPut(inclToMod, includeFile, module) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 25d4b3c745..5a59a62c0e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1177,11 +1177,22 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = localError(n.info, errGenerated, "'destroy' or 'deepCopy' expected for 'override'") +proc cursorInProcAux(n: PNode): bool = + if inCheckpoint(n.info) != cpNone: return true + for i in 0.. Date: Thu, 9 Feb 2017 17:41:21 +0100 Subject: [PATCH 02/67] added missing file --- compiler/compilerlog.nim | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 compiler/compilerlog.nim diff --git a/compiler/compilerlog.nim b/compiler/compilerlog.nim new file mode 100644 index 0000000000..fbf8cd9aa2 --- /dev/null +++ b/compiler/compilerlog.nim @@ -0,0 +1,9 @@ + +from os import getHomeDir, `/` + +proc logStr*(line: string) = + var f: File + if open(f, getHomeDir() / "nimsuggest.log", fmAppend): + f.writeLine(line) + f.close() + From 03b05bd346c1ecc18d1b7aa9e8731056efd6645a Mon Sep 17 00:00:00 2001 From: Emily Mabrey Date: Thu, 9 Feb 2017 17:18:19 -0500 Subject: [PATCH 03/67] Cleanup and reorganize readme.md Fix typos and grammatical errors while rearranging and cleaning up the readme. Change all links to use the reference style Markdown link for increased maintainability. Make all badges use a consistent flat style that matches the art style of the logo. Replace HTML snippet for logo with valid Markdown link by utilizing the freely available Google API for image resizing. --- readme.md | 229 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 128 insertions(+), 101 deletions(-) diff --git a/readme.md b/readme.md index 6eb85b0a38..f5dc1d6aba 100644 --- a/readme.md +++ b/readme.md @@ -1,146 +1,173 @@ -# Nim [![Build Status](https://travis-ci.org/nim-lang/Nim.svg?branch=devel)](https://travis-ci.org/nim-lang/Nim) +# ![Logo][image-nim-logo] Nim [![Build Status][badge-nim-travisci]][nim-travisci] -This repo contains the Nim compiler, Nim's stdlib, tools and -documentation. For more information about Nim, including downloads -and documentation for the latest release, check out -[Nim's website](http://nim-lang.org). +This repository contains the Nim compiler, Nim's stdlib, tools and documentation. +For more information about Nim, including downloads and documentation for +the latest release, check out [Nim's website][nim-site]. ## Compiling -Compiling the Nim compiler is quite straightforward. Because -the Nim compiler itself is written in the Nim programming language -the C source of an older version of the compiler are needed to bootstrap the -latest version. The C sources are available in a separate -repo [here](http://github.com/nim-lang/csources). - -The compiler currently supports the following platform and architecture -combinations: +The compiler currently officially supports the following platform and +architecture combinations: * Windows (Windows XP or greater) - x86 and x86_64 * Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l - * Mac OS X 10.04 or higher - x86, x86_64 and ppc64 + * Mac OS X (10.04 or greater) - x86, x86_64 and ppc64 -In reality a lot more are supported, however they are not tested regularly. +More platforms are supported, however they are not tested regularly and they +may not be as stable as the above-listed platforms. -To build from source you will need: +Compiling the Nim compiler is quite straightforward. First, the C source of +an older version of the Nim compiler is needed to bootstrap the latest +version because the Nim compiler itself is written in the Nim programming +language. Those C sources are available within the +[``nim-lang/csources``][csources-repo] repository. - * gcc 3.x or later recommended. Other alternatives which may work - are: clang, Visual C++, Intel's C++ compiler - * git or wget +Next, to build from source you will need: -**Note:** When installing ``gcc`` on Ubuntu (and likely other distros) ensure -that the ``build-essentials`` package is installed also. + * A C compiler such as ``gcc`` 3.x/later or an alternative such as ``clang``, + ``Visual C++`` or ``Intel C++``. It is recommended to use ``gcc`` 3.x or + later. + * Either ``git`` or ``wget`` to download the needed source repositories. + * The ``build-essentials`` package when using ``gcc`` on Ubuntu (and likely + other distros as well). -If you are on a fairly modern *nix system, the following steps should work: +Then, if you are on a \*nix system or Windows, the following steps should compile +Nim from source using ``gcc``, ``git`` and the ``koch`` build tool (in the place +of ``sh build.sh`` you should substitute ``build.bat`` on x86 Windows or +``build64.bat`` on x86_64 Windows): ``` $ git clone https://github.com/nim-lang/Nim.git $ cd Nim -$ git clone --depth 1 https://github.com/nim-lang/csources -$ cd csources && sh build.sh -$ cd .. +$ git clone --depth 1 https://github.com/nim-lang/csources.git +$ cd csources +$ sh build.sh +$ cd ../ $ bin/nim c koch $ ./koch boot -d:release ``` -You should then add the ``bin`` directory to your PATH, to make it easily -executable on your system. +Finally, once you have finished the build steps (on Windows, Mac or Linux) you +should add the ``bin`` directory to your PATH. -The above steps can be performed on Windows in a similar fashion, the -``build.bat`` and ``build64.bat`` (for x86_64 systems) are provided to be used -instead of ``build.sh``. +## Koch +``koch`` is the build tool used to build various parts of Nim and to generate +documentation and the website, among other things. The ``koch`` tool can also +be used to run the Nim test suite. -The ``koch`` tool is the Nim build tool, more ``koch`` related options are -documented in [doc/koch.rst](doc/koch.rst). +Assuming that you added Nim's ``bin`` directory to your PATH, you may execute +the tests using ``./koch tests``. The test suite takes a while to run, but you +can run a subset of tests by specifying a category (for example +``./koch tests cat async``). +For more information on the ``koch`` build tool please see the documentation +within the [doc/koch.rst](doc/koch.rst) file. ## Nimble -[Nimble](https://github.com/nim-lang/nimble) is Nim's package manager. For the -source based installations, where you added Nim's ``bin`` directory to your PATH, -the easiest way of installing Nimble is via: - -``` -$ koch nimble -``` +[Nimble][nimble-repo] is Nim's package manager. Assuming that you added Nim's +``bin`` directory to your PATH, you may install Nimble by running ``koch nimble`` +within the root of the cloned repository. ## Community -[![Join the Chat at irc.freenode.net#nim](https://img.shields.io/badge/IRC-join_chat_in_%23nim-blue.svg)](https://webchat.freenode.net/?channels=nim) -[![Join the Gitter channel](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/nim-lang/Nim) -[![Get help](https://img.shields.io/badge/Forum-get%20help-4eb899.svg)](http://forum.nim-lang.org) -[![Stackoverflow](https://img.shields.io/badge/stackoverflow-use_%23nim_tag-yellow.svg)](http://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15) -[![Follow @nim_lang!](https://img.shields.io/twitter/follow/nim_lang.svg?style=social)](https://twitter.com/nim_lang) +[![Join the IRC chat][badge-nim-irc]][nim-irc] +[![Join the Gitter chat][badge-nim-gitter]][nim-gitter] +[![Get help][badge-nim-forum-gethelp]][nim-forum] +[![View Nim posts on Stack Overflow][badge-nim-stackoverflow]][nim-stackoverflow-newest] +[![Follow @nim_lang on Twitter][badge-nim-twitter]][nim-twitter] -* The [forum](http://forum.nim-lang.org/) - the best place to ask questions and to discuss Nim. -* [IRC (Freenode#nim)](https://webchat.freenode.net/?channels=nim) - a place to discuss - Nim in real-time, this is also where most development decision get made! -* [Gitter](https://gitter.im/nim-lang/Nim) allows to discuss Nim from your browser, one click to join. - There is a bridge between Gitter and IRC channels. -* [Stackoverflow](http://stackoverflow.com/questions/tagged/nim) +* The [forum][nim-forum] - the best place to ask questions and to discuss Nim. +* [#nim IRC Channel (Freenode)][nim-irc] - a place to discuss Nim in real-time. + Also where most development decisions get made. +* [Gitter][nim-gitter] - an additional place to discuss Nim in real-time. There + is a bridge between Gitter and the IRC channel. +* [Stack Overflow][nim-stackoverflow] - a popular Q/A site for programming related + topics that includes posts about Nim. ## Contributing +[![Contribute to Nim via Gratipay][badge-nim-gratipay]][nim-gratipay] +[![Setup a bounty via Bountysource][badge-nim-bountysource]][nim-bountysource] +[![Donate Bitcoins][badge-nim-bitcoin]][nim-bitcoin] -[![Contribute to Nim via Gratipay!](https://img.shields.io/gratipay/team/nim.svg)](https://gratipay.com/nim/) -[![Bountysource](https://img.shields.io/bountysource/team/nim/activity.svg)](https://www.bountysource.com/teams/nim) - -We welcome everyone's contributions to Nim. No matter how small or large -the contribution is, anything from small spelling fixes to large modules -intended to be included in the standard library are accepted. Before -you get started, you should know the following about this repositories -structure: +We welcome everyone's contributions to Nim independent of how small or how large +they are. Anything from small spelling fixes to large modules intended to +be included in the standard library are welcome and appreciated. Before you get +started contributing, you should familiarize yourself with the repository structure: * ``bin/``, ``build/`` - these directories are empty, but are used when Nim is built. -* ``compiler/`` - the compiler source code, all the Nim source code files in this - directory implement the compiler. This also includes nimfix, and plugins - which live in ``compiler/nimfix`` and ``compiler/plugins`` - respectively. Nimsuggest used to live in the ``compiler`` directory also, - but was moved to https://github.com/nim-lang/nimsuggest. +* ``compiler/`` - the compiler source code. Also includes nimfix, and plugins within + ``compiler/nimfix`` and ``compiler/plugins`` respectively. Nimsuggest was moved to + the [``nim-lang/nimsuggest``][nimsuggest-repo] repository, though it previously also + lived within the ``compiler/`` directory. * ``config/`` - the configuration for the compiler and documentation generator. * ``doc/`` - the documentation files in reStructuredText format. -* ``lib/`` - where the standard library lives. +* ``lib/`` - the standard library, including: * ``pure/`` - modules in the standard library written in pure Nim. - * ``impure/`` - modules in the standard library written in pure Nim which - depend on libraries written in other languages. - * ``wrappers/`` - modules which wrap libraries written in other languages. -* ``tests/`` - contains tests for the compiler and standard library, organised by - category. -* ``tools/`` - the tools including ``niminst`` and ``nimweb``, most of these are invoked - via ``koch``. -* ``web/`` - the Nim website (http://nim-lang.org). -* ``koch.nim`` - tool used to bootstrap Nim, generate C sources, build the website, documentation - and more. + * ``impure/`` - modules in the standard library written in pure Nim with + dependencies written in other languages. + * ``wrappers/`` - modules which wrap dependencies written in other languages. +* ``tests/`` - contains categorized tests for the compiler and standard library. +* ``tools/`` - the tools including ``niminst`` and ``nimweb`` (mostly invoked via + ``koch``). +* ``web/`` - [the Nim website][nim-site]. +* ``koch.nim`` - tool used to bootstrap Nim, generate C sources, build the website, + and generate the documentation. -Most importantly, the ``koch`` tool can be used to run the test suite. To do so compile it first -by executing ``nim c koch``, then execute ``./koch tests``. The test suite takes a while to run, -but you can run specific tests by specifying a category to run, for example ``./koch tests cat async``. +If you are not familiar with making a pull request using GitHub and/or git, please +read [this guide][pull-request-instructions]. -Make sure that the tests all pass before -[submitting your pull request](https://help.github.com/articles/using-pull-requests/). -If you're short on time, you can -just run the tests specific to your change. Just run the category which corresponds to the change -you've made. When you create your pull request, Travis CI will verify that all the tests pass -anyway. +Ideally you should make sure that all tests pass before submitting a pull request. +However, if you are short on time, you can just run the tests specific to your +changes by only running the corresponding categories of tests. Travis CI verifies +that all tests pass before allowing the pull request to be accepted, so only +running specific tests should be harmless. -If you're looking for things to do, take a look at our -[issue tracker](https://github.com/nim-lang/Nim/issues). There is always plenty of issues -labelled [``Easy``](https://github.com/nim-lang/Nim/labels/Easy), these should be a good -starting point if this is your first contribution to Nim. +If you're looking for ways to contribute, please look at our [issue tracker][nim-issues]. +There are always plenty of issues labelled [``Easy``][nim-issues-easy]; these should +be a good starting point for an initial contribution to Nim. -You can also help with the development of Nim by making donations. You can do so -in many ways: +You can also help with the development of Nim by making donations. Donations can be +made using: -* [Gratipay](https://gratipay.com/nim/) -* [Bountysource](https://www.bountysource.com/teams/nim) -* Bitcoin - 1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ +* [Gratipay][nim-gratipay] +* [Bountysource][nim-bountysource] +* [Bitcoin][nim-bitcoin] -Finally, if you have any questions feel free to submit a question on the issue tracker, -on the [Nim forum](http://forum.nim-lang.org), or on IRC. +If you have any questions feel free to submit a question on the +[Nim forum][nim-forum], or via IRC on [the \#nim channel][nim-irc]. ## License -The compiler and the standard library are licensed under the MIT license, -except for some modules where the documentation suggests otherwise. This means -that you can use any license for your own programs developed with Nim, -allowing you to create commercial applications. +The compiler and the standard library are licensed under the MIT license, except +for some modules which explicitly state otherwise. As a result you may use any +compatible license (essentially any license) for your own programs developed with +Nim. You are explicitly permitted to develop commercial applications using Nim. -Read copying.txt for more details. +Please read the copying.txt file for more details. -Copyright (c) 2006-2017 Andreas Rumpf. -All rights reserved. +Copyright © 2006-2017 Andreas Rumpf, all rights reserved. + +[nim-site]: https://nim-lang.org +[nim-forum]: https://forum.nim-lang.org +[nim-issues]: https://github.com/nim-lang/Nim/issues +[nim-issues-easy]: https://github.com/nim-lang/Nim/labels/Easy +[nim-irc]: https://webchat.freenode.net/?channels=nim +[nim-travisci]: https://travis-ci.org/nim-lang/Nim +[nim-twitter]: https://twitter.com/nim_lang +[nim-stackoverflow]: https://stackoverflow.com/questions/tagged/nim +[nim-stackoverflow-newest]: https://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15 +[nim-gitter]: https://gitter.im/nim-lang/Nim +[nim-gratipay]: https://gratipay.com/nim/ +[nim-bountysource]: https://www.bountysource.com/teams/nim +[nim-bitcoin]: https://blockchain.info/address/1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ +[nimble-repo]: https://github.com/nim-lang/nimble +[nimsuggest-repo]: https://github.com/nim-lang/nimsuggest +[csources-repo]: https://github.com/nim-lang/csources +[badge-nim-travisci]: https://img.shields.io/travis/nim-lang/Nim/devel.svg?style=flat-square +[badge-nim-irc]: https://img.shields.io/badge/chat-on_irc-blue.svg?style=flat-square +[badge-nim-gitter]: https://img.shields.io/badge/chat-on_gitter-blue.svg?style=flat-square +[badge-nim-forum-gethelp]: https://img.shields.io/badge/Forum-get%20help-4eb899.svg?style=flat-square +[badge-nim-twitter]: https://img.shields.io/twitter/follow/nim_lang.svg?style=social +[badge-nim-stackoverflow]: https://img.shields.io/badge/stackoverflow-nim_tag-yellow.svg?style=flat-square +[badge-nim-gratipay]: https://img.shields.io/gratipay/team/nim.svg?style=flat-square +[badge-nim-bountysource]: https://img.shields.io/bountysource/team/nim/activity.svg?style=flat-square +[badge-nim-bitcoin]: https://img.shields.io/badge/bitcoin-1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ-D69134.svg?style=flat-square +[image-nim-logo]: https://images1-focus-opensocial.googleusercontent.com/gadgets/proxy?url=https://raw.githubusercontent.com/nim-lang/assets/master/Art/logo-crown.png&container=focus&resize_w=36&refresh=21600 +[pull-request-instructions]: https://help.github.com/articles/using-pull-requests/ From 1a7fdb09d923b43c6b4d8d11407730a349d5af76 Mon Sep 17 00:00:00 2001 From: Emily Mabrey Date: Thu, 9 Feb 2017 17:33:19 -0500 Subject: [PATCH 04/67] Make additional minor changes to readme.md Move the community section closer to the top of the readme. Make the reference to the copying.txt file in the license section actually link to that file. Adjust the nimble section to be more clear about how and where to acquire the nimble source. --- readme.md | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/readme.md b/readme.md index f5dc1d6aba..865724b716 100644 --- a/readme.md +++ b/readme.md @@ -4,6 +4,21 @@ This repository contains the Nim compiler, Nim's stdlib, tools and documentation For more information about Nim, including downloads and documentation for the latest release, check out [Nim's website][nim-site]. +## Community +[![Join the IRC chat][badge-nim-irc]][nim-irc] +[![Join the Gitter chat][badge-nim-gitter]][nim-gitter] +[![Get help][badge-nim-forum-gethelp]][nim-forum] +[![View Nim posts on Stack Overflow][badge-nim-stackoverflow]][nim-stackoverflow-newest] +[![Follow @nim_lang on Twitter][badge-nim-twitter]][nim-twitter] + +* The [forum][nim-forum] - the best place to ask questions and to discuss Nim. +* [#nim IRC Channel (Freenode)][nim-irc] - a place to discuss Nim in real-time. + Also where most development decisions get made. +* [Gitter][nim-gitter] - an additional place to discuss Nim in real-time. There + is a bridge between Gitter and the IRC channel. +* [Stack Overflow][nim-stackoverflow] - a popular Q/A site for programming related + topics that includes posts about Nim. + ## Compiling The compiler currently officially supports the following platform and architecture combinations: @@ -15,10 +30,11 @@ architecture combinations: More platforms are supported, however they are not tested regularly and they may not be as stable as the above-listed platforms. -Compiling the Nim compiler is quite straightforward. First, the C source of -an older version of the Nim compiler is needed to bootstrap the latest -version because the Nim compiler itself is written in the Nim programming -language. Those C sources are available within the +Compiling the Nim compiler is quite straightforward if you follow these steps: + +First, the C source of an older version of the Nim compiler is needed to +bootstrap the latest version because the Nim compiler itself is written in the +Nim programming language. Those C sources are available within the [``nim-lang/csources``][csources-repo] repository. Next, to build from source you will need: @@ -55,7 +71,7 @@ documentation and the website, among other things. The ``koch`` tool can also be used to run the Nim test suite. Assuming that you added Nim's ``bin`` directory to your PATH, you may execute -the tests using ``./koch tests``. The test suite takes a while to run, but you +the tests using ``./koch tests``. The tests take a while to run, but you can run a subset of tests by specifying a category (for example ``./koch tests cat async``). @@ -63,24 +79,10 @@ For more information on the ``koch`` build tool please see the documentation within the [doc/koch.rst](doc/koch.rst) file. ## Nimble -[Nimble][nimble-repo] is Nim's package manager. Assuming that you added Nim's -``bin`` directory to your PATH, you may install Nimble by running ``koch nimble`` -within the root of the cloned repository. - -## Community -[![Join the IRC chat][badge-nim-irc]][nim-irc] -[![Join the Gitter chat][badge-nim-gitter]][nim-gitter] -[![Get help][badge-nim-forum-gethelp]][nim-forum] -[![View Nim posts on Stack Overflow][badge-nim-stackoverflow]][nim-stackoverflow-newest] -[![Follow @nim_lang on Twitter][badge-nim-twitter]][nim-twitter] - -* The [forum][nim-forum] - the best place to ask questions and to discuss Nim. -* [#nim IRC Channel (Freenode)][nim-irc] - a place to discuss Nim in real-time. - Also where most development decisions get made. -* [Gitter][nim-gitter] - an additional place to discuss Nim in real-time. There - is a bridge between Gitter and the IRC channel. -* [Stack Overflow][nim-stackoverflow] - a popular Q/A site for programming related - topics that includes posts about Nim. +``nimble`` is Nim's package manager and it can be acquired from the +[``nim-lang/nimble``][nimble-repo] repository. Assuming that you added Nim's +``bin`` directory to your PATH, you may install Nimble from source by running +``koch nimble`` within the root of the cloned repository. ## Contributing [![Contribute to Nim via Gratipay][badge-nim-gratipay]][nim-gratipay] @@ -140,7 +142,7 @@ for some modules which explicitly state otherwise. As a result you may use any compatible license (essentially any license) for your own programs developed with Nim. You are explicitly permitted to develop commercial applications using Nim. -Please read the copying.txt file for more details. +Please read the [copying.txt](copying.txt) file for more details. Copyright © 2006-2017 Andreas Rumpf, all rights reserved. From 0bb18d1821183b08079e8cff03498454ff0b36f1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Feb 2017 09:22:28 +0100 Subject: [PATCH 05/67] introduce nimMaxHeap define to fight memory overcommit --- lib/system/alloc.nim | 5 +++++ tools/nimsuggest/nimsuggest.nim.cfg | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index a124d75378..f28a124d20 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -292,10 +292,15 @@ proc writeFreeList(a: MemRegion) = it, it.next, it.prev, it.size) it = it.next +const nimMaxHeap {.intdefine.} = 0 + proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = when not defined(emscripten): if not a.blockChunkSizeIncrease: let usedMem = a.currMem # - a.freeMem + when nimMaxHeap != 0: + if usedMem > nimMaxHeap * 1024 * 1024: + raiseOutOfMem() if usedMem < 64 * 1024: a.nextChunkSize = PageSize*4 else: diff --git a/tools/nimsuggest/nimsuggest.nim.cfg b/tools/nimsuggest/nimsuggest.nim.cfg index 949bd18e87..6525a206a0 100644 --- a/tools/nimsuggest/nimsuggest.nim.cfg +++ b/tools/nimsuggest/nimsuggest.nim.cfg @@ -8,6 +8,12 @@ path:"$lib/packages/docutils" define:useStdoutAsStdmsg define:nimsuggest +# die when nimsuggest uses more than 4GB: +@if cpu32: + define:"nimMaxHeap=2000" +@else: + define:"nimMaxHeap=4000" +@end #cs:partial #define:useNodeIds From 69fb2c61520fe11941814996f4758814acf02c80 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Fri, 10 Feb 2017 11:15:43 +0200 Subject: [PATCH 06/67] Fixed heapqueue.del for last elem (#5363) --- lib/pure/collections/heapqueue.nim | 47 +++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index abe20e5568..f86ba1d3f6 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -77,8 +77,10 @@ proc pop*[T](heap: var HeapQueue[T]): T = proc del*[T](heap: var HeapQueue[T], index: int) = ## Removes element at `index`, maintaining the heap invariant. swap(seq[T](heap)[^1], seq[T](heap)[index]) - seq[T](heap).setLen(heap.len - 1) - heap.siftup(index) + let newLen = heap.len - 1 + seq[T](heap).setLen(newLen) + if index < newLen: + heap.siftup(index) proc replace*[T](heap: var HeapQueue[T], item: T): T = ## Pop and return the current smallest value, and add the new item. @@ -101,16 +103,19 @@ proc pushpop*[T](heap: var HeapQueue[T], item: T): T = return item when isMainModule: + proc toSortedSeq[T](h: HeapQueue[T]): seq[T] = + var tmp = h + result = @[] + while tmp.len > 0: + result.add(pop(tmp)) + block: # Simple sanity test var heap = newHeapQueue[int]() let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] for item in data: push(heap, item) doAssert(heap[0] == 0) - var sort = newSeq[int]() - while heap.len > 0: - sort.add(pop(heap)) - doAssert(sort == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + doAssert(heap.toSortedSeq == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) block: # Test del var heap = newHeapQueue[int]() @@ -121,11 +126,27 @@ when isMainModule: doAssert(heap[0] == 1) heap.del(seq[int](heap).find(7)) - heap.del(seq[int](heap).find(5)) - heap.del(seq[int](heap).find(6)) - heap.del(seq[int](heap).find(2)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9]) - var sort = newSeq[int]() - while heap.len > 0: - sort.add(pop(heap)) - doAssert(sort == @[1, 3, 4, 8, 9]) + heap.del(seq[int](heap).find(5)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9]) + + heap.del(seq[int](heap).find(6)) + doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9]) + + heap.del(seq[int](heap).find(2)) + doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9]) + + block: # Test del last + var heap = newHeapQueue[int]() + let data = [1, 2, 3] + for item in data: push(heap, item) + + heap.del(2) + doAssert(heap.toSortedSeq == @[1, 2]) + + heap.del(1) + doAssert(heap.toSortedSeq == @[1]) + + heap.del(0) + doAssert(heap.toSortedSeq == @[]) From eb0d510195b5061ed840dc52cbe00cd21085f18a Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Fri, 10 Feb 2017 17:25:22 +0200 Subject: [PATCH 07/67] Removed $ from echo calls (#5368) --- doc/tut1.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/tut1.rst b/doc/tut1.rst index 47cafc7fac..e79214dee0 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -361,7 +361,7 @@ iterator: .. code-block:: nim echo "Counting to ten: " for i in countup(1, 10): - echo $i + echo i # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines The built-in `$ `_ operator turns an integer (``int``) and many @@ -374,7 +374,7 @@ Each value is ``echo``-ed. This code does the same: echo "Counting to 10: " var i = 1 while i <= 10: - echo $i + echo i inc(i) # increment i by 1 # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines @@ -383,7 +383,7 @@ Counting down can be achieved as easily (but is less often needed): .. code-block:: nim echo "Counting down from 10 to 1: " for i in countdown(10, 1): - echo $i + echo i # --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines Since counting up occurs so often in programs, Nim also has a `.. @@ -827,7 +827,7 @@ Let's return to the boring counting example: .. code-block:: nim echo "Counting to ten: " for i in countup(1, 10): - echo $i + echo i Can a `countup `_ proc be written that supports this loop? Lets try: @@ -1035,15 +1035,15 @@ there is a difference between the ``$`` and ``repr`` outputs: myString = "nim" myInteger = 42 myFloat = 3.14 - echo $myBool, ":", repr(myBool) + echo myBool, ":", repr(myBool) # --> true:true - echo $myCharacter, ":", repr(myCharacter) + echo myCharacter, ":", repr(myCharacter) # --> n:'n' - echo $myString, ":", repr(myString) + echo myString, ":", repr(myString) # --> nim:0x10fa8c050"nim" - echo $myInteger, ":", repr(myInteger) + echo myInteger, ":", repr(myInteger) # --> 42:42 - echo $myFloat, ":", repr(myFloat) + echo myFloat, ":", repr(myFloat) # --> 3.1400000000000001e+00:3.1400000000000001e+00 @@ -1075,7 +1075,7 @@ at runtime by 0, the second by 1 and so on. Example: north, east, south, west var x = south # `x` is of type `Direction`; its value is `south` - echo $x # writes "south" to `stdout` + echo x # writes "south" to `stdout` All comparison operators can be used with enumeration types. @@ -1289,7 +1289,7 @@ value. Here the ``for`` statement is looping over the results from the .. code-block:: nim for i in @[3, 4, 5]: - echo $i + echo i # --> 3 # --> 4 # --> 5 From 443a46b40d4c8db1aa9f77a374c0f9544bc524b5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Feb 2017 20:39:37 +0100 Subject: [PATCH 08/67] improve error message for mismatched proc types --- compiler/sigmatch.nim | 2 +- compiler/types.nim | 54 +++++++++++++++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 90253a691b..6d5e6f742e 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -543,7 +543,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = else: return isNone when useEffectSystem: - if not compatibleEffects(f, a): return isNone + if compatibleEffects(f, a) != efCompat: return isNone of tyNil: result = f.allowsNil diff --git a/compiler/types.nim b/compiler/types.nim index d5ec2972a4..8ea00e7e5e 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1377,7 +1377,16 @@ proc compatibleEffectsAux(se, re: PNode): bool = return false result = true -proc compatibleEffects*(formal, actual: PType): bool = +type + EffectsCompat* = enum + efCompat + efRaisesDiffer + efRaisesUnknown + efTagsDiffer + efTagsUnknown + efLockLevelsDiffer + +proc compatibleEffects*(formal, actual: PType): EffectsCompat = # for proc type compatibility checking: assert formal.kind == tyProc and actual.kind == tyProc internalAssert formal.n.sons[0].kind == nkEffectList @@ -1393,18 +1402,21 @@ proc compatibleEffects*(formal, actual: PType): bool = # 'r.msgHandler = if isNil(msgHandler): defaultMsgHandler else: msgHandler' if not isNil(se) and se.kind != nkArgList: # spec requires some exception or tag, but we don't know anything: - if real.len == 0: return false - result = compatibleEffectsAux(se, real.sons[exceptionEffects]) - if not result: return + if real.len == 0: return efRaisesUnknown + let res = compatibleEffectsAux(se, real.sons[exceptionEffects]) + if not res: return efRaisesDiffer let st = spec.sons[tagEffects] if not isNil(st) and st.kind != nkArgList: # spec requires some exception or tag, but we don't know anything: - if real.len == 0: return false - result = compatibleEffectsAux(st, real.sons[tagEffects]) - if not result: return - result = formal.lockLevel.ord < 0 or - actual.lockLevel.ord <= formal.lockLevel.ord + if real.len == 0: return efTagsUnknown + let res = compatibleEffectsAux(st, real.sons[tagEffects]) + if not res: return efTagsDiffer + if formal.lockLevel.ord < 0 or + actual.lockLevel.ord <= formal.lockLevel.ord: + result = efCompat + else: + result = efLockLevelsDiffer proc isCompileTimeOnly*(t: PType): bool {.inline.} = result = t.kind in {tyTypeDesc, tyStatic} @@ -1508,6 +1520,24 @@ proc typeMismatch*(n: PNode, formal, actual: PType) = let named = typeToString(formal) let desc = typeToString(formal, preferDesc) let x = if named == desc: named else: named & " = " & desc - localError(n.info, errGenerated, msgKindToString(errTypeMismatch) & - typeToString(actual) & ") " & - `%`(msgKindToString(errButExpectedX), [x])) + var msg = msgKindToString(errTypeMismatch) & + typeToString(actual) & ") " & + msgKindToString(errButExpectedX) % [x] + + if formal.kind == tyProc and actual.kind == tyProc: + case compatibleEffects(formal, actual) + of efCompat: discard + of efRaisesDiffer: + msg.add "\n.raise effects differ" + of efRaisesUnknown: + msg.add "\n.raise effect is 'can raise any'" + of efTagsDiffer: + msg.add "\n.tag effects differ" + of efTagsUnknown: + msg.add "\n.tag effect is 'any tag allowed'" + of efLockLevelsDiffer: + msg.add "\nlock levels differ" + writeStackTrace() + debug actual.n + debug formal.n + localError(n.info, errGenerated, msg) From 9b8150aef1f6a8d48dffc6ac4c5cba9a3f8e24d3 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 11 Feb 2017 00:23:22 +0100 Subject: [PATCH 09/67] sysio: check for IO errors for write operations --- lib/system/sysio.nim | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 115b67c18f..fa1bdbb4e2 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -171,21 +171,23 @@ proc readLine(f: File): TaintedString = proc write(f: File, i: int) = when sizeof(int) == 8: - c_fprintf(f, "%lld", i) + if c_fprintf(f, "%lld", i) < 0: checkErr(f) else: - c_fprintf(f, "%ld", i) + if c_fprintf(f, "%ld", i) < 0: checkErr(f) proc write(f: File, i: BiggestInt) = when sizeof(BiggestInt) == 8: - c_fprintf(f, "%lld", i) + if c_fprintf(f, "%lld", i) < 0: checkErr(f) else: - c_fprintf(f, "%ld", i) + if c_fprintf(f, "%ld", i) < 0: checkErr(f) proc write(f: File, b: bool) = if b: write(f, "true") else: write(f, "false") -proc write(f: File, r: float32) = c_fprintf(f, "%g", r) -proc write(f: File, r: BiggestFloat) = c_fprintf(f, "%g", r) +proc write(f: File, r: float32) = + if c_fprintf(f, "%g", r) < 0: checkErr(f) +proc write(f: File, r: BiggestFloat) = + if c_fprintf(f, "%g", r) < 0: checkErr(f) proc write(f: File, c: char) = discard c_putc(ord(c), f) proc write(f: File, a: varargs[string, `$`]) = From c8ae7164e502b585843c584af65f78f67002830e Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 11 Feb 2017 00:24:22 +0100 Subject: [PATCH 10/67] finish.nim: user has multiple chances to move .7z file to proper location --- tools/finish.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/finish.nim b/tools/finish.nim index a9fb444a07..e39062b027 100644 --- a/tools/finish.nim +++ b/tools/finish.nim @@ -209,6 +209,9 @@ proc main() = of Manual: echo "After download, move it to: ", dest if askBool("Download successful? (y/n) "): + while not fileExists("dist" / mingw): + echo "could not find: ", "dist" / mingw + if not askBool("Try again? (y/n) "): break if unzip(): retry = true of Failure: discard of Success: From 36d3fd64da21fe128f92ea49943c9dd834aa6848 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 11 Feb 2017 00:42:12 +0100 Subject: [PATCH 11/67] fixes #5354 --- compiler/semexprs.nim | 10 +++++----- tests/metatype/tfieldaccessor.nim | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 tests/metatype/tfieldaccessor.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 57674735a0..9972585c7b 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1093,11 +1093,11 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = return readTypeParameter(c, ty, i, n.info) of tyObject, tyTuple: if ty.n != nil and ty.n.kind == nkRecList: - for field in ty.n: - if field.sym.name == i: - n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ]) - n.typ.n = copyTree(n) - return n + let field = lookupInRecord(ty.n, i) + if field != nil: + n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.typ]) + n.typ.n = copyTree(n) + return n else: # echo "TYPE FIELD ACCESS" # debug ty diff --git a/tests/metatype/tfieldaccessor.nim b/tests/metatype/tfieldaccessor.nim new file mode 100644 index 0000000000..7054dd22b9 --- /dev/null +++ b/tests/metatype/tfieldaccessor.nim @@ -0,0 +1,17 @@ +type + Test = object + x: int + case p: bool + of true: + a: int + else: + case q: bool + of true: + b: int + else: + discard + +proc f[T](t: typedesc[T]): int = + 1 + +assert Test.f == 1 From 0d1aa9225a6190f4d54b699ef3a191cbbb3209a4 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sun, 12 Feb 2017 15:02:50 +0000 Subject: [PATCH 12/67] Make walkDirRec docstring more clear (#5377) --- lib/pure/os.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 4cd3870c7d..92e2958204 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1002,8 +1002,8 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {. tags: [ReadDirEffect].} = - ## walks over the directory `dir` and yields for each file in `dir`. The - ## full path for each file is returned. + ## Recursively walks over the directory `dir` and yields for each file in `dir`. + ## The full path for each file is returned. Directories are not returned. ## **Warning**: ## Modifying the directory structure while the iterator ## is traversing may result in undefined behavior! From 636b97745754c69f1709bd9dd295c0de56b87105 Mon Sep 17 00:00:00 2001 From: ionel anton Date: Mon, 13 Feb 2017 03:09:43 -0500 Subject: [PATCH 13/67] Column details for postgres. (#5380) --- lib/impure/db_postgres.nim | 184 +++++++++++++++++++++++--- tests/untestable/tpostgres.nim | 229 +++++++++++++++++++++++++++++++++ 2 files changed, 397 insertions(+), 16 deletions(-) diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim index 60bd1f0814..fc587b5df6 100644 --- a/lib/impure/db_postgres.nim +++ b/lib/impure/db_postgres.nim @@ -69,16 +69,14 @@ import db_common export db_common type - DbConn* = PPGconn ## encapsulates a database connection - Row* = seq[string] ## a row of a dataset. NULL database values will be - ## converted to nil. - InstantRow* = tuple[res: PPGresult, line: int32] ## a handle that can be - ## used to get a row's - ## column text on demand + DbConn* = PPGconn ## encapsulates a database connection + Row* = seq[string] ## a row of a dataset. NULL database values will be + ## converted to nil. + InstantRow* = object ## a handle that can be + res: PPGresult ## used to get a row's + line: int ## column text on demand SqlPrepared* = distinct string ## a identifier for the prepared queries - -{.deprecated: [TRow: Row, TDbConn: DbConn, - TSqlPrepared: SqlPrepared].} +{.deprecated: [TRow: Row, TDbConn: DbConn, TSqlPrepared: SqlPrepared].} proc dbError*(db: DbConn) {.noreturn.} = ## raises a DbError exception. @@ -213,7 +211,7 @@ iterator instantRows*(db: DbConn, query: SqlQuery, ## on demand using []. Returned handle is valid only within iterator body. var res = setupQuery(db, query, args) for i in 0..pqNtuples(res)-1: - yield (res: res, line: i) + yield InstantRow(res: res, line: i) pqClear(res) iterator instantRows*(db: DbConn, stmtName: SqlPrepared, @@ -223,16 +221,170 @@ iterator instantRows*(db: DbConn, stmtName: SqlPrepared, ## on demand using []. Returned handle is valid only within iterator body. var res = setupQuery(db, stmtName, args) for i in 0..pqNtuples(res)-1: - yield (res: res, line: i) + yield InstantRow(res: res, line: i) pqClear(res) -proc `[]`*(row: InstantRow, col: int32): string {.inline.} = - ## returns text for given column of the row - $pqgetvalue(row.res, row.line, col) +proc getColumnType(res: PPGresult, col: int) : DbType = + ## returns DbType for given column in the row + ## defined in pg_type.h file in the postgres source code + ## Wire representation for types: http://www.npgsql.org/dev/types.html + var oid = pqftype(res, int32(col)) + ## The integer returned is the internal OID number of the type + case oid + of 16: return DbType(kind: DbTypeKind.dbBool, name: "bool") + of 17: return DbType(kind: DbTypeKind.dbBlob, name: "bytea") -proc len*(row: InstantRow): int32 {.inline.} = + of 21: return DbType(kind: DbTypeKind.dbInt, name: "int2", size: 2) + of 23: return DbType(kind: DbTypeKind.dbInt, name: "int4", size: 4) + of 20: return DbType(kind: DbTypeKind.dbInt, name: "int8", size: 8) + of 1560: return DbType(kind: DbTypeKind.dbBit, name: "bit") + of 1562: return DbType(kind: DbTypeKind.dbInt, name: "varbit") + + of 18: return DbType(kind: DbTypeKind.dbFixedChar, name: "char") + of 19: return DbType(kind: DbTypeKind.dbFixedChar, name: "name") + of 1042: return DbType(kind: DbTypeKind.dbFixedChar, name: "bpchar") + + of 25: return DbType(kind: DbTypeKind.dbVarchar, name: "text") + of 1043: return DbType(kind: DbTypeKind.dbVarChar, name: "varchar") + of 2275: return DbType(kind: DbTypeKind.dbVarchar, name: "cstring") + + of 700: return DbType(kind: DbTypeKind.dbFloat, name: "float4") + of 701: return DbType(kind: DbTypeKind.dbFloat, name: "float8") + + of 790: return DbType(kind: DbTypeKind.dbDecimal, name: "money") + of 1700: return DbType(kind: DbTypeKind.dbDecimal, name: "numeric") + + of 704: return DbType(kind: DbTypeKind.dbTimeInterval, name: "tinterval") + of 702: return DbType(kind: DbTypeKind.dbTimestamp, name: "abstime") + of 703: return DbType(kind: DbTypeKind.dbTimeInterval, name: "reltime") + of 1082: return DbType(kind: DbTypeKind.dbDate, name: "date") + of 1083: return DbType(kind: DbTypeKind.dbTime, name: "time") + of 1114: return DbType(kind: DbTypeKind.dbTimestamp, name: "timestamp") + of 1184: return DbType(kind: DbTypeKind.dbTimestamp, name: "timestamptz") + of 1186: return DbType(kind: DbTypeKind.dbTimeInterval, name: "interval") + of 1266: return DbType(kind: DbTypeKind.dbTime, name: "timetz") + + of 114: return DbType(kind: DbTypeKind.dbJson, name: "json") + of 142: return DbType(kind: DbTypeKind.dbXml, name: "xml") + of 3802: return DbType(kind: DbTypeKind.dbJson, name: "jsonb") + + of 600: return DbType(kind: DbTypeKind.dbPoint, name: "point") + of 601: return DbType(kind: DbTypeKind.dbLseg, name: "lseg") + of 602: return DbType(kind: DbTypeKind.dbPath, name: "path") + of 603: return DbType(kind: DbTypeKind.dbBox, name: "box") + of 604: return DbType(kind: DbTypeKind.dbPolygon, name: "polygon") + of 628: return DbType(kind: DbTypeKind.dbLine, name: "line") + of 718: return DbType(kind: DbTypeKind.dbCircle, name: "circle") + + of 650: return DbType(kind: DbTypeKind.dbInet, name: "cidr") + of 829: return DbType(kind: DbTypeKind.dbMacAddress, name: "macaddr") + of 869: return DbType(kind: DbTypeKind.dbInet, name: "inet") + + of 2950: return DbType(kind: DbTypeKind.dbVarchar, name: "uuid") + of 3614: return DbType(kind: DbTypeKind.dbVarchar, name: "tsvector") + of 3615: return DbType(kind: DbTypeKind.dbVarchar, name: "tsquery") + of 2970: return DbType(kind: DbTypeKind.dbVarchar, name: "txid_snapshot") + + of 27: return DbType(kind: DbTypeKind.dbComposite, name: "tid") + of 1790: return DbType(kind: DbTypeKind.dbComposite, name: "refcursor") + of 2249: return DbType(kind: DbTypeKind.dbComposite, name: "record") + of 3904: return DbType(kind: DbTypeKind.dbComposite, name: "int4range") + of 3906: return DbType(kind: DbTypeKind.dbComposite, name: "numrange") + of 3908: return DbType(kind: DbTypeKind.dbComposite, name: "tsrange") + of 3910: return DbType(kind: DbTypeKind.dbComposite, name: "tstzrange") + of 3912: return DbType(kind: DbTypeKind.dbComposite, name: "daterange") + of 3926: return DbType(kind: DbTypeKind.dbComposite, name: "int8range") + + of 22: return DbType(kind: DbTypeKind.dbArray, name: "int2vector") + of 30: return DbType(kind: DbTypeKind.dbArray, name: "oidvector") + of 143: return DbType(kind: DbTypeKind.dbArray, name: "xml[]") + of 199: return DbType(kind: DbTypeKind.dbArray, name: "json[]") + of 629: return DbType(kind: DbTypeKind.dbArray, name: "line[]") + of 651: return DbType(kind: DbTypeKind.dbArray, name: "cidr[]") + of 719: return DbType(kind: DbTypeKind.dbArray, name: "circle[]") + of 791: return DbType(kind: DbTypeKind.dbArray, name: "money[]") + of 1000: return DbType(kind: DbTypeKind.dbArray, name: "bool[]") + of 1001: return DbType(kind: DbTypeKind.dbArray, name: "bytea[]") + of 1002: return DbType(kind: DbTypeKind.dbArray, name: "char[]") + of 1003: return DbType(kind: DbTypeKind.dbArray, name: "name[]") + of 1005: return DbType(kind: DbTypeKind.dbArray, name: "int2[]") + of 1006: return DbType(kind: DbTypeKind.dbArray, name: "int2vector[]") + of 1007: return DbType(kind: DbTypeKind.dbArray, name: "int4[]") + of 1008: return DbType(kind: DbTypeKind.dbArray, name: "regproc[]") + of 1009: return DbType(kind: DbTypeKind.dbArray, name: "text[]") + of 1028: return DbType(kind: DbTypeKind.dbArray, name: "oid[]") + of 1010: return DbType(kind: DbTypeKind.dbArray, name: "tid[]") + of 1011: return DbType(kind: DbTypeKind.dbArray, name: "xid[]") + of 1012: return DbType(kind: DbTypeKind.dbArray, name: "cid[]") + of 1013: return DbType(kind: DbTypeKind.dbArray, name: "oidvector[]") + of 1014: return DbType(kind: DbTypeKind.dbArray, name: "bpchar[]") + of 1015: return DbType(kind: DbTypeKind.dbArray, name: "varchar[]") + of 1016: return DbType(kind: DbTypeKind.dbArray, name: "int8[]") + of 1017: return DbType(kind: DbTypeKind.dbArray, name: "point[]") + of 1018: return DbType(kind: DbTypeKind.dbArray, name: "lseg[]") + of 1019: return DbType(kind: DbTypeKind.dbArray, name: "path[]") + of 1020: return DbType(kind: DbTypeKind.dbArray, name: "box[]") + of 1021: return DbType(kind: DbTypeKind.dbArray, name: "float4[]") + of 1022: return DbType(kind: DbTypeKind.dbArray, name: "float8[]") + of 1023: return DbType(kind: DbTypeKind.dbArray, name: "abstime[]") + of 1024: return DbType(kind: DbTypeKind.dbArray, name: "reltime[]") + of 1025: return DbType(kind: DbTypeKind.dbArray, name: "tinterval[]") + of 1027: return DbType(kind: DbTypeKind.dbArray, name: "polygon[]") + of 1040: return DbType(kind: DbTypeKind.dbArray, name: "macaddr[]") + of 1041: return DbType(kind: DbTypeKind.dbArray, name: "inet[]") + of 1263: return DbType(kind: DbTypeKind.dbArray, name: "cstring[]") + of 1115: return DbType(kind: DbTypeKind.dbArray, name: "timestamp[]") + of 1182: return DbType(kind: DbTypeKind.dbArray, name: "date[]") + of 1183: return DbType(kind: DbTypeKind.dbArray, name: "time[]") + of 1185: return DbType(kind: DbTypeKind.dbArray, name: "timestamptz[]") + of 1187: return DbType(kind: DbTypeKind.dbArray, name: "interval[]") + of 1231: return DbType(kind: DbTypeKind.dbArray, name: "numeric[]") + of 1270: return DbType(kind: DbTypeKind.dbArray, name: "timetz[]") + of 1561: return DbType(kind: DbTypeKind.dbArray, name: "bit[]") + of 1563: return DbType(kind: DbTypeKind.dbArray, name: "varbit[]") + of 2201: return DbType(kind: DbTypeKind.dbArray, name: "refcursor[]") + of 2951: return DbType(kind: DbTypeKind.dbArray, name: "uuid[]") + of 3643: return DbType(kind: DbTypeKind.dbArray, name: "tsvector[]") + of 3645: return DbType(kind: DbTypeKind.dbArray, name: "tsquery[]") + of 3807: return DbType(kind: DbTypeKind.dbArray, name: "jsonb[]") + of 2949: return DbType(kind: DbTypeKind.dbArray, name: "txid_snapshot[]") + of 3905: return DbType(kind: DbTypeKind.dbArray, name: "int4range[]") + of 3907: return DbType(kind: DbTypeKind.dbArray, name: "numrange[]") + of 3909: return DbType(kind: DbTypeKind.dbArray, name: "tsrange[]") + of 3911: return DbType(kind: DbTypeKind.dbArray, name: "tstzrange[]") + of 3913: return DbType(kind: DbTypeKind.dbArray, name: "daterange[]") + of 3927: return DbType(kind: DbTypeKind.dbArray, name: "int8range[]") + of 2287: return DbType(kind: DbTypeKind.dbArray, name: "record[]") + + of 705: return DbType(kind: DbTypeKind.dbUnknown, name: "unknown") + else: return DbType(kind: DbTypeKind.dbUnknown, name: $oid) ## Query the system table pg_type to determine exactly which type is referenced. + +proc setColumnInfo(columns: var DbColumns; res: PPGresult; L: int32) = + setLen(columns, L) + for i in 0.. 0 + +doAssert dbCols[22].name == "point_col" +doAssert dbCols[22].typ.kind == DbTypeKind.dbPoint +doAssert dbCols[22].typ.name == "point" + +doAssert dbCols[23].name == "line_col" +doAssert dbCols[23].typ.kind == DbTypeKind.dbLine +doAssert dbCols[23].typ.name == "line" + +doAssert dbCols[24].name == "lseg_col" +doAssert dbCols[24].typ.kind == DbTypeKind.dbLseg +doAssert dbCols[24].typ.name == "lseg" + +doAssert dbCols[25].name == "box_col" +doAssert dbCols[25].typ.kind == DbTypeKind.dbBox +doAssert dbCols[25].typ.name == "box" + +doAssert dbCols[26].name == "path_col" +doAssert dbCols[26].typ.kind == DbTypeKind.dbPath +doAssert dbCols[26].typ.name == "path" + +doAssert dbCols[27].name == "polygon_col" +doAssert dbCols[27].typ.kind == DbTypeKind.dbPolygon +doAssert dbCols[27].typ.name == "polygon" + +doAssert dbCols[28].name == "circle_col" +doAssert dbCols[28].typ.kind == DbTypeKind.dbCircle +doAssert dbCols[28].typ.name == "circle" + +doAssert dbCols[29].name == "cidr_col" +doAssert dbCols[29].typ.kind == DbTypeKind.dbInet +doAssert dbCols[29].typ.name == "cidr" + +doAssert dbCols[30].name == "inet_col" +doAssert dbCols[30].typ.kind == DbTypeKind.dbInet +doAssert dbCols[30].typ.name == "inet" + +doAssert dbCols[31].name == "macaddr_col" +doAssert dbCols[31].typ.kind == DbTypeKind.dbMacAddress +doAssert dbCols[31].typ.name == "macaddr" + +doAssert dbCols[32].name == "bit_col" +doAssert dbCols[32].typ.kind == DbTypeKind.dbBit +doAssert dbCols[32].typ.name == "bit" + +doAssert dbCols[33].name == "varbit_col" +doAssert dbCols[33].typ.kind == DbTypeKind.dbBit +doAssert dbCols[33].typ.name == "bit" + +doAssert dbCols[34].name == "tsvector_col" +doAssert dbCols[34].typ.kind == DbTypeKind.dbVarchar +doAssert dbCols[34].typ.name == "tsvector" + +doAssert dbCols[35].name == "tsquery_col" +doAssert dbCols[35].typ.kind == DbTypeKind.dbVarchar +doAssert dbCols[35].typ.name == "tsquery" + +doAssert dbCols[36].name == "uuid_col" +doAssert dbCols[36].typ.kind == DbTypeKind.dbVarchar +doAssert dbCols[36].typ.name == "uuid" + +doAssert dbCols[37].name == "xml_col" +doAssert dbCols[37].typ.kind == DbTypeKind.dbXml +doAssert dbCols[37].typ.name == "xml" + +doAssert dbCols[38].name == "json_col" +doAssert dbCols[38].typ.kind == DbTypeKind.dbJson +doAssert dbCols[38].typ.name == "json" + +doAssert dbCols[39].name == "array_col" +doAssert dbCols[39].typ.kind == DbTypeKind.dbArray +doAssert dbCols[39].typ.name == "int4[]" + +doAssert dbCols[40].name == "custom_composite_col" +doAssert dbCols[40].typ.kind == DbTypeKind.dbUnknown +doAssert parseInt(dbCols[40].typ.name) > 0 + +doAssert dbCols[41].name == "range_col" +doAssert dbCols[41].typ.kind == DbTypeKind.dbComposite +doAssert dbCols[41].typ.name == "int4range" + echo("All tests succeeded!") db.close() + From ac9c2126e60e3890aabf6db20137330b980004df Mon Sep 17 00:00:00 2001 From: flyx Date: Mon, 13 Feb 2017 11:20:07 +0100 Subject: [PATCH 14/67] Added BiggestUInt (#5378) --- lib/pure/parseutils.nim | 24 ++++++++++++------------ lib/pure/strutils.nim | 2 +- lib/system.nim | 11 +++++++++++ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index fb7d72182d..8d53a0360a 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -250,18 +250,18 @@ proc parseInt*(s: string, number: var int, start = 0): int {. elif result != 0: number = int(res) -# overflowChecks doesn't work with uint64 -proc rawParseUInt(s: string, b: var uint64, start = 0): int = +# overflowChecks doesn't work with BiggestUInt +proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int = var - res = 0'u64 - prev = 0'u64 + res = 0.BiggestUInt + prev = 0.BiggestUInt i = start if s[i] == '+': inc(i) # Allow if s[i] in {'0'..'9'}: b = 0 while s[i] in {'0'..'9'}: prev = res - res = res * 10 + (ord(s[i]) - ord('0')).uint64 + res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt if prev > res: return 0 # overflowChecks emulation inc(i) @@ -269,13 +269,13 @@ proc rawParseUInt(s: string, b: var uint64, start = 0): int = b = res result = i - start -proc parseBiggestUInt*(s: string, number: var uint64, start = 0): int {. +proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {. rtl, extern: "npuParseBiggestUInt", noSideEffect.} = ## parses an unsigned integer starting at `start` and stores the value ## into `number`. ## Result is the number of processed chars or 0 if there is no integer ## or overflow detected. - var res: uint64 + var res: BiggestUInt # use 'res' for exception safety (don't write to 'number' in case of an # overflow exception): result = rawParseUInt(s, res, start) @@ -287,12 +287,12 @@ proc parseUInt*(s: string, number: var uint, start = 0): int {. ## into `number`. ## Result is the number of processed chars or 0 if there is no integer or ## overflow detected. - var res: uint64 + var res: BiggestUInt result = parseBiggestUInt(s, res, start) - if (sizeof(uint) <= 4) and - (res > 0xFFFF_FFFF'u64): - raise newException(OverflowError, "overflow") - elif result != 0: + when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4: + if res > 0xFFFF_FFFF'u64: + raise newException(OverflowError, "overflow") + if result != 0: number = uint(res) proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {. diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 235e66f6ad..9c205a54f2 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -939,7 +939,7 @@ proc parseUInt*(s: string): uint {.noSideEffect, procvar, if L != s.len or L == 0: raise newException(ValueError, "invalid unsigned integer: " & s) -proc parseBiggestUInt*(s: string): uint64 {.noSideEffect, procvar, +proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, procvar, rtl, extern: "nsuParseBiggestUInt".} = ## Parses a decimal unsigned integer value contained in `s`. ## diff --git a/lib/system.nim b/lib/system.nim index 13ca6eaf70..bab5369f11 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1512,6 +1512,17 @@ type ## compiler supports. Currently this is ``float64``, but it is ## platform-dependant in general. +when defined(JS): + type BiggestUInt* = uint32 + ## is an alias for the biggest unsigned integer type the Nim compiler + ## supports. Currently this is ``uint32`` for JS and ``uint64`` for other + ## targets. +else: + type BiggestUInt* = uint64 + ## is an alias for the biggest unsigned integer type the Nim compiler + ## supports. Currently this is ``uint32`` for JS and ``uint64`` for other + ## targets. + {.deprecated: [TAddress: ByteAddress].} when defined(windows): From 279e4b045133bad59e349520547e5220408b232e Mon Sep 17 00:00:00 2001 From: Anatoly Galiulin Date: Mon, 13 Feb 2017 19:35:40 +0700 Subject: [PATCH 15/67] Fixes #5382 --- lib/impure/re.nim | 2 +- tests/stdlib/tbug5382.nim | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/stdlib/tbug5382.nim diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 9d5d2bdd07..e00f91de17 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -290,7 +290,7 @@ proc find*(buf: cstring, pattern: Regex, matches: var openArray[string], for i in 1..int(res)-1: var a = rawMatches[i * 2] var b = rawMatches[i * 2 + 1] - if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b)-1) + if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b)) else: matches[i-1] = nil return rawMatches[0] diff --git a/tests/stdlib/tbug5382.nim b/tests/stdlib/tbug5382.nim new file mode 100644 index 0000000000..c86656d32b --- /dev/null +++ b/tests/stdlib/tbug5382.nim @@ -0,0 +1,11 @@ +discard """ + output: ''' +02 +''' +""" +import re + +let regexp = re"^\/([0-9]{2})\.html$" +var matches: array[1, string] +discard "/02.html".find(regexp, matches) +echo matches[0] From 6fa1dba515e514ea9a4ac5850b0188fb6cf95fbf Mon Sep 17 00:00:00 2001 From: Anatoly Galiulin Date: Mon, 13 Feb 2017 19:37:20 +0700 Subject: [PATCH 16/67] Add ``tearDownForeignThreadGc`` function (#5369) --- doc/backends.txt | 8 ++++ lib/system/gc_common.nim | 29 +++++++---- lib/system/threads.nim | 16 ++++++- tests/gc/foreign_thr.nim | 88 ++++++++++++++++++++++++++++++++++ tests/testament/categories.nim | 1 + 5 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 tests/gc/foreign_thr.nim diff --git a/doc/backends.txt b/doc/backends.txt index 5846cce9ba..6446103ed8 100644 --- a/doc/backends.txt +++ b/doc/backends.txt @@ -461,3 +461,11 @@ can then attach a GC to this thread via It is **not** safe to disable the garbage collector and enable it after the call from your background thread even if the code you are calling is short lived. + +Before the thread exits, you should tear down the thread's GC to prevent memory +leaks by calling + +.. code-block:: nim + + system.tearDownForeignThreadGc() + diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 269514ceb2..6ab6bd9208 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -128,13 +128,7 @@ iterator items(stack: ptr GcStack): ptr GcStack = yield s s = s.next -# There will be problems with GC in foreign threads if `threads` option is off or TLS emulation is enabled -const allowForeignThreadGc = compileOption("threads") and not compileOption("tlsEmulation") - -when allowForeignThreadGc: - var - localGcInitialized {.rtlThreadVar.}: bool - +when declared(threadType): proc setupForeignThreadGc*() {.gcsafe.} = ## Call this if you registered a callback that will be run from a thread not ## under your control. This has a cheap thread-local guard, so the GC for @@ -143,16 +137,33 @@ when allowForeignThreadGc: ## ## This function is available only when ``--threads:on`` and ``--tlsEmulation:off`` ## switches are used - if not localGcInitialized: - localGcInitialized = true + if threadType == ThreadType.None: initAllocator() var stackTop {.volatile.}: pointer setStackBottom(addr(stackTop)) initGC() + threadType = ThreadType.ForeignThread + + proc tearDownForeignThreadGc*() {.gcsafe.} = + ## Call this to tear down the GC, previously initialized by ``setupForeignThreadGc``. + ## If GC has not been previously initialized, or has already been torn down, the + ## call does nothing. + ## + ## This function is available only when ``--threads:on`` and ``--tlsEmulation:off`` + ## switches are used + if threadType != ThreadType.ForeignThread: + return + when declared(deallocOsPages): deallocOsPages() + threadType = ThreadType.None + when declared(gch): zeroMem(addr gch, sizeof(gch)) + else: template setupForeignThreadGc*() = {.error: "setupForeignThreadGc is available only when ``--threads:on`` and ``--tlsEmulation:off`` are used".} + template tearDownForeignThreadGc*() = + {.error: "tearDownForeignThreadGc is available only when ``--threads:on`` and ``--tlsEmulation:off`` are used".} + # ----------------- stack management -------------------------------------- # inspired from Smart Eiffel diff --git a/lib/system/threads.nim b/lib/system/threads.nim index e8b34bf2e4..6e58638e92 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -285,7 +285,19 @@ when useStackMaskHack: when not defined(useNimRtl): when not useStackMaskHack: #when not defined(createNimRtl): initStackBottom() - when declared(initGC): initGC() + when declared(initGC): + initGC() + when not emulatedThreadVars: + type ThreadType {.pure.} = enum + None = 0, + NimThread = 1, + ForeignThread = 2 + var + threadType {.rtlThreadVar.}: ThreadType + + threadType = ThreadType.NimThread + + when emulatedThreadVars: if nimThreadVarsSize() > sizeof(ThreadLocalStorage): @@ -442,6 +454,8 @@ proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) = # init the GC for refc/markandsweep setStackBottom(addr(p)) initGC() + when declared(threadType): + threadType = ThreadType.NimThread when declared(registerThread): thrd.stackBottom = addr(thrd) registerThread(thrd) diff --git a/tests/gc/foreign_thr.nim b/tests/gc/foreign_thr.nim new file mode 100644 index 0000000000..88ab951133 --- /dev/null +++ b/tests/gc/foreign_thr.nim @@ -0,0 +1,88 @@ +discard """ + output: ''' +Hello from thread +Hello from thread +Hello from thread +Hello from thread +''' + cmd: "nim $target --hints:on --threads:on --tlsEmulation:off $options $file" +""" +# Copied from stdlib +import strutils + +const + StackGuardSize = 4096 + ThreadStackMask = 1024*256*sizeof(int)-1 + ThreadStackSize = ThreadStackMask+1 - StackGuardSize + +type ThreadFunc = proc() {.thread.} + +when defined(posix): + import posix + + proc runInForeignThread(f: ThreadFunc) = + proc wrapper(p: pointer): pointer {.noconv.} = + let thr = cast[ThreadFunc](p) + setupForeignThreadGc() + thr() + tearDownForeignThreadGc() + setupForeignThreadGc() + thr() + tearDownForeignThreadGc() + result = nil + + var attrs {.noinit.}: PthreadAttr + doAssert pthread_attr_init(addr attrs) == 0 + doAssert pthread_attr_setstacksize(addr attrs, ThreadStackSize) == 0 + var tid: Pthread + doAssert pthread_create(addr tid, addr attrs, wrapper, f) == 0 + doAssert pthread_join(tid, nil) == 0 + +elif defined(windows): + import winlean + type + WinThreadProc = proc (x: pointer): int32 {.stdcall.} + + proc createThread(lpThreadAttributes: pointer, dwStackSize: DWORD, + lpStartAddress: WinThreadProc, + lpParameter: pointer, + dwCreationFlags: DWORD, + lpThreadId: var DWORD): Handle {. + stdcall, dynlib: "kernel32", importc: "CreateThread".} + + proc wrapper(p: pointer): int32 {.stdcall.} = + let thr = cast[ThreadFunc](p) + setupForeignThreadGc() + thr() + tearDownForeignThreadGc() + setupForeignThreadGc() + thr() + tearDownForeignThreadGc() + result = 0'i32 + + proc runInForeignThread(f: ThreadFunc) = + var dummyThreadId: DWORD + var h = createThread(nil, ThreadStackSize.int32, wrapper.WinThreadProc, cast[pointer](f), 0, dummyThreadId) + doAssert h != 0.Handle + doAssert waitForSingleObject(h, -1'i32) == 0.DWORD + +else: + {.fatal: "Unknown system".} + +proc runInNativeThread(f: ThreadFunc) = + proc wrapper(f: ThreadFunc) {.thread.} = + # These operations must be NOP + setupForeignThreadGc() + tearDownForeignThreadGc() + f() + f() + var thr: Thread[ThreadFunc] + createThread(thr, wrapper, f) + joinThread(thr) + +proc f {.thread.} = + var msg = "Hello " & "from thread" + echo msg + +runInForeignThread(f) +runInNativeThread(f) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 2dc8e33183..0685dd73a7 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -147,6 +147,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) = testSpec r, makeTest("tests/gc" / filename, options & " -d:release --gc:boehm", cat, actionRun) + testWithoutBoehm "foreign_thr" test "gcemscripten" test "growobjcrash" test "gcbench" From 9f142e199d7f79bbff552315d1657dd68fb3a387 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 13 Feb 2017 13:37:50 +0100 Subject: [PATCH 17/67] nimsuggest uses multithreading and full project recompiles --- compiler/modulegraphs.nim | 4 + compiler/passes.nim | 6 +- compiler/suggest.nim | 6 +- tools/nimsuggest/nimsuggest.nim | 227 ++++++++++++++++++++--- tools/nimsuggest/nimsuggest.nim.cfg | 3 + tools/nimsuggest/tests/twithin_macro.nim | 6 +- 6 files changed, 223 insertions(+), 29 deletions(-) diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index fb8f5cf04b..b86312209c 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -40,9 +40,13 @@ type # module dependencies. backend*: RootRef # minor hack so that a backend can extend this easily config*: ConfigRef + doStopCompile*: proc(): bool {.closure.} {.this: g.} +proc stopCompile*(g: ModuleGraph): bool {.inline.} = + result = doStopCompile != nil and doStopCompile() + proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph = result = ModuleGraph() initStrTable(result.packageSyms) diff --git a/compiler/passes.nim b/compiler/passes.nim index 3cc15147e3..783a7e13fc 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -171,6 +171,7 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind, proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, rd: PRodReader; cache: IdentCache): bool {.discardable.} = + if graph.stopCompile(): return true var p: TParsers a: TPassContextArray @@ -198,6 +199,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, processImplicits implicitIncludes, nkIncludeStmt, a, module while true: + if graph.stopCompile(): break var n = parseTopLevelStmt(p) if n.kind == nkEmpty: break if sfNoForward in module.flags: @@ -219,6 +221,8 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, else: openPassesCached(graph, a, module, rd) var n = loadInitSection(rd) - for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a) + for i in countup(0, sonsLen(n) - 1): + if graph.stopCompile(): break + processTopLevelStmtCached(n.sons[i], a) closePassesCached(a) result = true diff --git a/compiler/suggest.nim b/compiler/suggest.nim index aea979d56e..c228d1fa8d 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -28,7 +28,7 @@ type column*: int # Starts at 0 doc*: string # Not escaped (yet) symkind*: TSymKind - forth*: string # XXX TODO object on symkind + forth*: string # type quality*: range[0..100] # matching quality isGlobal*: bool # is a global variable tokenLen*: int @@ -88,7 +88,7 @@ proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo; when not defined(noDocgen): result.doc = s.extractDocComment -proc `$`(suggest: Suggest): string = +proc `$`*(suggest: Suggest): string = result = $suggest.section result.add(sep) if suggest.section == ideHighlight: @@ -131,7 +131,7 @@ proc suggestResult(s: Suggest) = if not isNil(suggestionResultHook): suggestionResultHook(s) else: - suggestWriteln($(s)) + suggestWriteln($s) proc filterSym(s: PSym): bool {.inline.} = result = s.kind != skModule diff --git a/tools/nimsuggest/nimsuggest.nim b/tools/nimsuggest/nimsuggest.nim index e11bb560c9..f6d4e98eae 100644 --- a/tools/nimsuggest/nimsuggest.nim +++ b/tools/nimsuggest/nimsuggest.nim @@ -180,7 +180,7 @@ proc executeEpc(cmd: IdeCmd, args: SexpNode; dirtyfile = args[3].getStr(nil) execute(cmd, file, dirtyfile, int(line), int(column), graph, cache) -proc returnEpc(socket: var Socket, uid: BiggestInt, s: SexpNode|string, +proc returnEpc(socket: Socket, uid: BiggestInt, s: SexpNode|string, return_symbol = "return") = let response = $convertSexp([newSSymbol(return_symbol), uid, s]) socket.send(toHex(len(response), 6)) @@ -208,6 +208,45 @@ template checkSanity(client, sizeHex, size, messageBuffer: typed) = if client.recv(messageBuffer, size) != size: raise newException(ValueError, "didn't get all the bytes") +var + requests: Channel[string] + results: Channel[Suggest] + +proc toStdout() {.gcsafe.} = + while true: + let res = results.recv() + case res.section + of ideNone: break + of ideChk: echo res.doc + else: echo res + +proc toSocket(stdoutSocket: Socket) {.gcsafe.} = + while true: + let res = results.recv() + case res.section + of ideNone: break + of ideChk: stdoutSocket.send(res.doc & "\c\L") + else: stdoutSocket.send($res & "\c\L") + +proc toEpc(client: Socket; uid: BiggestInt) {.gcsafe.} = + var list = newSList() + while true: + let res = results.recv() + case res.section + of ideNone: break + of ideChk: + returnEpc(client, uid, sexp(res.doc)) + else: + list.add sexp(res) + if gIdeCmd != ideChk: + returnEPC(client, uid, list) + +proc writelnHook(line: string) = + results.send(Suggest(section: ideChk, doc: line)) + +proc sugResultHook(s: Suggest) = + results.send(s) + template setVerbosity(level: typed) = gVerbosity = level gNotes = NotesVerbosity[gVerbosity] @@ -217,16 +256,108 @@ proc connectToNextFreePort(server: Socket, host: string): Port = let (_, port) = server.getLocalAddr result = port +type + ThreadParams = tuple[port: Port; address: string] + +proc replStdin(x: ThreadParams) {.thread.} = + if gEmitEof: + echo DummyEof + while true: + let line = readLine(stdin) + requests.send line + toStdout() + echo DummyEof + flushFile(stdout) + else: + echo Help + var line = "" + while readLineFromStdin("> ", line): + requests.send line + toStdout() + echo "" + flushFile(stdout) + +proc replTcp(x: ThreadParams) {.thread.} = + var server = newSocket() + server.bindAddr(x.port, x.address) + var inp = "".TaintedString + server.listen() + while true: + var stdoutSocket = newSocket() + accept(server, stdoutSocket) + + stdoutSocket.readLine(inp) + requests.send inp + toSocket(stdoutSocket) + stdoutSocket.send("\c\L") + stdoutSocket.close() + +proc replEpc(x: ThreadParams) {.thread.} = + var server = newSocket() + let port = connectToNextFreePort(server, "localhost") + server.listen() + echo port + + var client = newSocket() + # Wait for connection + accept(server, client) + while true: + var + sizeHex = "" + size = 0 + messageBuffer = "" + checkSanity(client, sizeHex, size, messageBuffer) + let + message = parseSexp($messageBuffer) + epcAPI = message[0].getSymbol + case epcAPI: + of "call": + let + uid = message[1].getNum + args = message[3] + + gIdeCmd = parseIdeCmd(message[2].getSymbol) + case gIdeCmd + of ideChk: + setVerbosity(1) + # Use full path because other emacs plugins depends it + gListFullPaths = true + incl(gGlobalOptions, optIdeDebug) + of ideSug, ideCon, ideDef, ideUse, ideDus, ideOutline, ideHighlight: + setVerbosity(0) + else: discard + requests.send messageBuffer + toEpc(client, uid) + of "methods": + returnEpc(client, message[1].getNum, listEPC()) + of "epc-error": + # an unhandled exception forces down the whole process anyway, so we + # use 'quit' here instead of 'raise' + quit("recieved epc error: " & $messageBuffer) + else: + let errMessage = case epcAPI + of "return", "return-error": + "no return expected" + else: + "unexpected call: " & epcAPI + quit errMessage + proc parseCmdLine(cmd: string; graph: ModuleGraph; cache: IdentCache) = + template sentinel() = + # send sentinel for the input reading thread: + results.send(Suggest(section: ideNone)) + template toggle(sw) = if sw in gGlobalOptions: excl(gGlobalOptions, sw) else: incl(gGlobalOptions, sw) + sentinel() return template err() = echo Help + sentinel() return var opc = "" @@ -260,8 +391,47 @@ proc parseCmdLine(cmd: string; graph: ModuleGraph; cache: IdentCache) = i += parseInt(cmd, col, i) execute(gIdeCmd, orig, dirtyfile, line, col-1, graph, cache) + sentinel() -proc serveStdin(graph: ModuleGraph; cache: IdentCache) = +proc recompileFullProject(graph: ModuleGraph; cache: IdentCache) = + resetSystemArtifacts() + #let graph = newGraph(oldgraph.config) + graph.resetAllModules() + compileProject(graph, cache) + +proc mainThread(graph: ModuleGraph; cache: IdentCache) = + if gLogging: + var it = searchPaths.head + while it != nil: + logStr(PStrEntry(it).data) + it = it.next + + msgs.writelnHook = writelnHook + suggestionResultHook = sugResultHook + graph.doStopCompile = proc (): bool = requests.peek() > 0 + var idle = 0 + while true: + let (hasData, req) = requests.tryRecv() + if hasData: + msgs.writelnHook = writelnHook + suggestionResultHook = sugResultHook + + parseCmdLine(req, graph, cache) + idle = 0 + else: + os.sleep 250 + idle += 1 + if idle == 20: + # we use some nimsuggest activity to enable a lazy recompile: + gIdeCmd = ideChk + msgs.writelnHook = proc (s: string) = discard + suggestionResultHook = proc (s: Suggest) = discard + recompileFullProject(graph, cache) + +var + inputThread: Thread[ThreadParams] + +proc serveStdin(graph: ModuleGraph; cache: IdentCache) {.deprecated.} = if gEmitEof: echo DummyEof while true: @@ -277,7 +447,7 @@ proc serveStdin(graph: ModuleGraph; cache: IdentCache) = echo "" flushFile(stdout) -proc serveTcp(graph: ModuleGraph; cache: IdentCache) = +proc serveTcp(graph: ModuleGraph; cache: IdentCache) {.deprecated.} = var server = newSocket() server.bindAddr(gPort, gAddress) var inp = "".TaintedString @@ -296,7 +466,7 @@ proc serveTcp(graph: ModuleGraph; cache: IdentCache) = stdoutSocket.send("\c\L") stdoutSocket.close() -proc serveEpc(server: Socket; graph: ModuleGraph; cache: IdentCache) = +proc serveEpc(server: Socket; graph: ModuleGraph; cache: IdentCache) {.deprecated.} = var client = newSocket() # Wait for connection accept(server, client) @@ -365,25 +535,38 @@ proc mainCommand(graph: ModuleGraph; cache: IdentCache) = # do not stop after the first error: msgs.gErrorMax = high(int) + open(requests) + open(results) + case gMode - of mstdin: - compileProject(graph, cache) - #modules.gFuzzyGraphChecking = false - serveStdin(graph, cache) - of mtcp: - # until somebody accepted the connection, produce no output (logging is too - # slow for big projects): - msgs.writelnHook = proc (msg: string) = discard - compileProject(graph, cache) - #modules.gFuzzyGraphChecking = false - serveTcp(graph, cache) - of mepc: - var server = newSocket() - let port = connectToNextFreePort(server, "localhost") - server.listen() - echo port - compileProject(graph, cache) - serveEpc(server, graph, cache) + of mstdin: createThread(inputThread, replStdin, (gPort, gAddress)) + of mtcp: createThread(inputThread, replTcp, (gPort, gAddress)) + of mepc: createThread(inputThread, replEpc, (gPort, gAddress)) + mainThread(graph, cache) + joinThread(inputThread) + close(requests) + close(results) + + when false: + case gMode + of mstdin: + compileProject(graph, cache) + #modules.gFuzzyGraphChecking = false + serveStdin(graph, cache) + of mtcp: + # until somebody accepted the connection, produce no output (logging is too + # slow for big projects): + msgs.writelnHook = proc (msg: string) = discard + compileProject(graph, cache) + #modules.gFuzzyGraphChecking = false + serveTcp(graph, cache) + of mepc: + var server = newSocket() + let port = connectToNextFreePort(server, "localhost") + server.listen() + echo port + compileProject(graph, cache) + serveEpc(server, graph, cache) proc processCmdLine*(pass: TCmdLinePass, cmd: string) = var p = parseopt.initOptParser(cmd) diff --git a/tools/nimsuggest/nimsuggest.nim.cfg b/tools/nimsuggest/nimsuggest.nim.cfg index 6525a206a0..2e14a4dd35 100644 --- a/tools/nimsuggest/nimsuggest.nim.cfg +++ b/tools/nimsuggest/nimsuggest.nim.cfg @@ -20,3 +20,6 @@ define:nimsuggest #define:booting #define:noDocgen --path:"$nim" +--threads:on +--noNimblePath +--path:"../../compiler" diff --git a/tools/nimsuggest/tests/twithin_macro.nim b/tools/nimsuggest/tests/twithin_macro.nim index d67984707b..7392dd605e 100644 --- a/tools/nimsuggest/tests/twithin_macro.nim +++ b/tools/nimsuggest/tests/twithin_macro.nim @@ -206,8 +206,8 @@ $nimsuggest --tester $file >sug $1 sug;;skField;;name;;string;;$file;;166;;6;;"";;100 sug;;skField;;age;;int;;$file;;167;;6;;"";;100 -sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int{.noSideEffect, gcsafe, locks: 0.};;$file;;169;;9;;"";;100 +sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int;;$file;;169;;9;;"";;100 sug;;skMacro;;twithin_macro.class;;proc (head: untyped, body: untyped): untyped{.gcsafe, locks: .};;$file;;4;;6;;"Iterates over the children of the NimNode ``n``.";;100 -sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string{.noSideEffect, gcsafe, locks: 0.};;$file;;168;;9;;"";;100 -sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string{.noSideEffect, gcsafe, locks: 0.};;$file;;184;;9;;"";;100* +sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string;;$file;;168;;9;;"";;100 +sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string;;$file;;184;;9;;"";;100* """ From 92665e6e9a74995bd108da5bf3668e2c09c8d79c Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Mon, 13 Feb 2017 19:38:30 +0700 Subject: [PATCH 18/67] Add hash proc for cstrings (#5386) --- lib/pure/hashes.nim | 10 ++++++++++ web/news/e031_version_0_16_2.rst | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 11af811493..17d1c64427 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -127,6 +127,15 @@ proc hash*(x: string): Hash = h = h !& ord(x[i]) result = !$h +proc hash*(x: cstring): Hash = + ## efficient hashing of null-terminated strings + var h: Hash = 0 + var i = 0 + while x[i] != 0.char: + h = h !& ord(x[i]) + inc i + result = !$h + proc hash*(sBuf: string, sPos, ePos: int): Hash = ## efficient hashing of a string buffer, from starting ## position `sPos` to ending position `ePos` @@ -239,6 +248,7 @@ proc hash*[A](x: set[A]): Hash = when isMainModule: doAssert( hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) ) + doAssert( hash("aa bb aaaa1234") == hash(cstring("aa bb aaaa1234")) ) doAssert( hashIgnoreCase("aa bb aaaa1234") == hash("aa bb aaaa1234") ) doAssert( hashIgnoreStyle("aa bb aaaa1234") == hashIgnoreCase("aa bb aaaa1234") ) let xx = @['H','e','l','l','o'] diff --git a/web/news/e031_version_0_16_2.rst b/web/news/e031_version_0_16_2.rst index 5ee40b772e..2d725028e4 100644 --- a/web/news/e031_version_0_16_2.rst +++ b/web/news/e031_version_0_16_2.rst @@ -18,7 +18,11 @@ Changes affecting backwards compatibility - The IO routines now raise ``EOFError`` for the "end of file" condition. ``EOFError`` is a subtype of ``IOError`` and so it's easier to distinguish between "error during read" and "error due to EOF". - +- A hash procedure has been added for ``cstring`` type in ``hashes`` module. + Previously, hash of a ``cstring`` would be calculated as a hash of the + pointer. Now the hash is calculated from the contents of the string, assuming + ``cstring`` is a null-terminated string. Equal ``string``s and ``cstring``s + produce equal hash value. Library Additions ----------------- From a336bf2395cc7915d669c2e3c0e870bf97f5401e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 13 Feb 2017 21:14:29 +0100 Subject: [PATCH 19/67] Fixes parseHeader("foo:") != ("foo", @[""]). Refs #5344. --- lib/pure/httpcore.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index d7f720f66f..aa8f1958d1 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -206,6 +206,8 @@ proc parseHeader*(line: string): tuple[key: string, value: seq[string]] = inc(i) # skip : if i < len(line): i += parseList(line, result.value, i) + elif result.key.len > 0: + result.value = @[""] else: result.value = @[] @@ -318,4 +320,6 @@ when isMainModule: let (key, value) = parseHeader("foobar: ") test = newHttpHeaders() test[key] = value - doAssert test["foobar"] == "" \ No newline at end of file + doAssert test["foobar"] == "" + + doAssert parseHeader("foobar:") == ("foobar", @[""]) \ No newline at end of file From bcecbc380fc1cdf89fe7f8fab5dca07afd49cdb1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 14 Feb 2017 12:49:38 +0100 Subject: [PATCH 20/67] make tests green again; disable periodic refresh for now --- tools/nimsuggest/nimsuggest.nim | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/tools/nimsuggest/nimsuggest.nim b/tools/nimsuggest/nimsuggest.nim index f6d4e98eae..afc90c0b4b 100644 --- a/tools/nimsuggest/nimsuggest.nim +++ b/tools/nimsuggest/nimsuggest.nim @@ -13,11 +13,11 @@ import strutils, os, parseopt, parseutils, sequtils, net, rdstdin, sexp # Do NOT import suggest. It will lead to wierd bugs with # suggestionResultHook, because suggest.nim is included by sigmatch. # So we import that one instead. -import compiler/options, compiler/commands, compiler/modules, compiler/sem, - compiler/passes, compiler/passaux, compiler/msgs, compiler/nimconf, - compiler/extccomp, compiler/condsyms, compiler/lists, - compiler/sigmatch, compiler/ast, compiler/scriptconfig, - compiler/idents, compiler/modulegraphs +import compiler / [options, commands, modules, sem, + passes, passaux, msgs, nimconf, + extccomp, condsyms, lists, + sigmatch, ast, scriptconfig, + idents, modulegraphs, compilerlog] when defined(windows): import winlean @@ -68,12 +68,6 @@ const type EUnexpectedCommand = object of Exception -proc logStr(line: string) = - var f: File - if open(f, getHomeDir() / "nimsuggest.log", fmAppend): - f.writeLine(line) - f.close() - proc parseQuoted(cmd: string; outp: var string; start: int): int = var i = start i += skipWhitespace(cmd, i) @@ -342,7 +336,7 @@ proc replEpc(x: ThreadParams) {.thread.} = "unexpected call: " & epcAPI quit errMessage -proc parseCmdLine(cmd: string; graph: ModuleGraph; cache: IdentCache) = +proc execCmd(cmd: string; graph: ModuleGraph; cache: IdentCache) = template sentinel() = # send sentinel for the input reading thread: results.send(Suggest(section: ideNone)) @@ -394,8 +388,8 @@ proc parseCmdLine(cmd: string; graph: ModuleGraph; cache: IdentCache) = sentinel() proc recompileFullProject(graph: ModuleGraph; cache: IdentCache) = + echo "recompiling full project" resetSystemArtifacts() - #let graph = newGraph(oldgraph.config) graph.resetAllModules() compileProject(graph, cache) @@ -416,12 +410,12 @@ proc mainThread(graph: ModuleGraph; cache: IdentCache) = msgs.writelnHook = writelnHook suggestionResultHook = sugResultHook - parseCmdLine(req, graph, cache) + execCmd(req, graph, cache) idle = 0 else: os.sleep 250 idle += 1 - if idle == 20: + if idle == 20 and false: # we use some nimsuggest activity to enable a lazy recompile: gIdeCmd = ideChk msgs.writelnHook = proc (s: string) = discard @@ -436,14 +430,14 @@ proc serveStdin(graph: ModuleGraph; cache: IdentCache) {.deprecated.} = echo DummyEof while true: let line = readLine(stdin) - parseCmdLine line, graph, cache + execCmd line, graph, cache echo DummyEof flushFile(stdout) else: echo Help var line = "" while readLineFromStdin("> ", line): - parseCmdLine line, graph, cache + execCmd line, graph, cache echo "" flushFile(stdout) @@ -461,7 +455,7 @@ proc serveTcp(graph: ModuleGraph; cache: IdentCache) {.deprecated.} = accept(server, stdoutSocket) stdoutSocket.readLine(inp) - parseCmdLine inp.string, graph, cache + execCmd inp.string, graph, cache stdoutSocket.send("\c\L") stdoutSocket.close() @@ -534,6 +528,9 @@ proc mainCommand(graph: ModuleGraph; cache: IdentCache) = # do not stop after the first error: msgs.gErrorMax = high(int) + # compile the project before showing any input so that we already + # can answer questions right away: + compileProject(graph, cache) open(requests) open(results) From 6cb0e5ad68a55a056fc754c814a744b4b449d205 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 14 Feb 2017 12:51:38 +0100 Subject: [PATCH 21/67] remove debug output --- compiler/semstmts.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5a59a62c0e..5a15f9f5a6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1317,7 +1317,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if not usePseudoGenerics and gIdeCmd in {ideSug, ideCon} and not cursorInProc(n.sons[bodyPos]): discard "speed up nimsuggest" - logStr "skipped " & s.name.s else: pushProcCon(c, s) if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics: From f0aef9f4e2bba8f87d3060d920f6a470450ce41b Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 14 Feb 2017 14:39:17 +0100 Subject: [PATCH 22/67] compile external .c files with the C compiler, not with C++; refs #5357 --- compiler/extccomp.nim | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 0f283b208b..1b068385af 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -566,16 +566,18 @@ proc needsExeExt(): bool {.inline.} = result = (optGenScript in gGlobalOptions and targetOS == osWindows) or (platform.hostOS == osWindows) -proc getCompilerExe(compiler: TSystemCC): string = - result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler - else: CC[compiler].compilerExe +proc getCompilerExe(compiler: TSystemCC; cfile: string): string = + result = if gCmd == cmdCompileToCpp and not cfile.endsWith(".c"): + CC[compiler].cppCompiler + else: + CC[compiler].compilerExe if result.len == 0: rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name) proc getLinkerExe(compiler: TSystemCC): string = result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler - else: compiler.getCompilerExe + else: compiler.getCompilerExe("") proc getCompileCFileCmd*(cfile: Cfile): string = var c = cCompiler @@ -596,7 +598,7 @@ proc getCompileCFileCmd*(cfile: Cfile): string = var options = cFileSpecificOptions(cfile.cname) var exe = getConfigVar(c, ".exe") - if exe.len == 0: exe = c.getCompilerExe + if exe.len == 0: exe = c.getCompilerExe(cfile.cname) if needsExeExt(): exe = addFileExt(exe, "exe") if optGenDynLib in gGlobalOptions and @@ -614,7 +616,7 @@ proc getCompileCFileCmd*(cfile: Cfile): string = compilePattern = joinPath(ccompilerpath, exe) else: includeCmd = "" - compilePattern = c.getCompilerExe + compilePattern = c.getCompilerExe(cfile.cname) var cf = if noAbsolutePaths(): extractFilename(cfile.cname) else: cfile.cname From 57874ed9b8f1fba887083013d277b0ac7f3c5f35 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 14 Feb 2017 14:39:53 +0100 Subject: [PATCH 23/67] C++ codegen: emit 'extern C' for importc'ed functions that we declare a prototype for --- compiler/ccgthreadvars.nim | 4 ++-- compiler/cgen.nim | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index 3efddbf307..505b69eabb 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -57,8 +57,8 @@ proc generateThreadLocalStorage(m: BModule) = proc generateThreadVarsSize(m: BModule) = if nimtv != nil: - let externc = if gCmd != cmdCompileToCpp and - sfCompileToCpp in m.module.flags: "extern \"C\"" + let externc = if gCmd == cmdCompileToCpp or + sfCompileToCpp in m.module.flags: "extern \"C\" " else: "" addf(m.s[cfsProcs], "$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n", diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 62ed9ad6e6..63a7cda0e1 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -715,10 +715,13 @@ proc genProcAux(m: BModule, prc: PSym) = add(generatedProc, ~"}$N") add(m.s[cfsProcs], generatedProc) -proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} = - result = sfCompileToCpp in m.module.flags and +proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} = + result = (sfCompileToCpp in m.module.flags and sfCompileToCpp notin sym.getModule().flags and - gCmd != cmdCompileToCpp + gCmd != cmdCompileToCpp) or ( + sym.flags * {sfImportc, sfInfixCall, sfCompilerProc} == {sfImportc} and + sym.magic == mNone and + gCmd == cmdCompileToCpp) proc genProcPrototype(m: BModule, sym: PSym) = useHeader(m, sym) @@ -732,7 +735,7 @@ proc genProcPrototype(m: BModule, sym: PSym) = var header = genProcHeader(m, sym) if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[cCompiler].props: header = "__declspec(noreturn) " & header - if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): + if sym.typ.callConv != ccInline and requiresExternC(m, sym): header = "extern \"C\" " & header if sfPure in sym.flags and hasAttribute in CC[cCompiler].props: header.add(" __attribute__((naked))") From 4a8257d99259ddf763bbcf3230545dec5380bbec Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 14 Feb 2017 21:07:28 +0100 Subject: [PATCH 24/67] Update bountysource sponsors. --- web/bountysource.nim.cfg | 1 + web/inactive_sponsors.csv | 33 +++++++++++------- web/sponsors.csv | 72 +++++++++++++++++++++------------------ 3 files changed, 60 insertions(+), 46 deletions(-) create mode 100644 web/bountysource.nim.cfg diff --git a/web/bountysource.nim.cfg b/web/bountysource.nim.cfg new file mode 100644 index 0000000000..521e21de41 --- /dev/null +++ b/web/bountysource.nim.cfg @@ -0,0 +1 @@ +-d:ssl diff --git a/web/inactive_sponsors.csv b/web/inactive_sponsors.csv index d466f3f310..6352bc194e 100644 --- a/web/inactive_sponsors.csv +++ b/web/inactive_sponsors.csv @@ -1,26 +1,40 @@ logo, name, url, this_month, all_time, since, level ,bogen,,0,1010,"Jul 23, 2016",1 ,mikra,,0,400,"Apr 28, 2016",1 -,linkmonitor,,0,180,"Jan 28, 2016",1 +,shkolnick-kun,,0,375,"Jul 6, 2016",1 +,"Chris Heller",,0,350,"May 19, 2016",1 +,linkmonitor,,0,280,"Jan 28, 2016",1 ,avsej,,0,110,"Jun 10, 2016",1 ,WilRubin,,0,100,"Aug 11, 2015",1 ,"Benny Luypaert",,0,100,"Apr 10, 2016",1 -,"Chris Heller",,0,100,"May 19, 2016",1 ,PhilipWitte,,0,100,"Aug 5, 2016",1 +,skunkiferous,,0,100,"Oct 2, 2016",1 +,"Jonathan Arnett",,0,90,"May 20, 2016",1 ,Boxifier,,0,75,"Apr 12, 2016",1 ,iolloyd,,0,75,"Apr 29, 2016",1 +,btbytes,,0,70,"Apr 6, 2016",1 ,rb01,,0,50,"May 4, 2016",1 +,barcharcraz,,0,50,"Jun 2, 2016",1 +,zachaysan,,0,50,"Jun 7, 2016",1 +,kunev,,0,50,"Dec 26, 2016",1 +,iboB,,0,50,"Jan 28, 2017",1 ,TedSinger,,0,45,"Apr 9, 2016",1 +,johnnovak,,0,45,"Apr 30, 2016",1 +,"Matthew Baulch",,0,40,"Jun 7, 2016",1 +,"Matthew Newton",,0,35,"Apr 20, 2016",1 ,martinbbjerregaard,,0,35,"Jun 9, 2016",1 ,RationalG,,0,30,"Jun 17, 2016",1 ,benbve,,0,30,"Jul 12, 2016",1 -,barcharcraz,,0,25,"Jun 2, 2016",1 +,multikatt,,0,30,"Nov 2, 2016",1 ,"Landon Bass",,0,25,"Jun 7, 2016",1 ,jimrichards,,0,25,"Jun 8, 2016",1 ,jjzazuet,,0,25,"Jul 10, 2016",1 -,moigagoo,,0,20,"May 13, 2016",1 ,kteza1,,0,20,"Jun 10, 2016",1 ,tomkeus,,0,20,"Sep 4, 2016",1 +,csoriano89,,0,20,"Sep 7, 2016",1 +,juanjux,,0,20,"Oct 29, 2016",1 +,zagfai,,0,20,"Nov 3, 2016",1 +,hellcoderz,,0,20,"Jan 24, 2017",1 ,mirek,,0,15,"Apr 9, 2016",1 ,DateinAsia,,0,15,"Jul 30, 2016",1 ,rickc,,0,15,"Jul 31, 2016",1 @@ -38,13 +52,6 @@ logo, name, url, this_month, all_time, since, level ,Blumenversand,,0,10,"Jul 21, 2016",1 ,cinnabardk,,0,10,"Aug 6, 2016",1 ,reddec,,0,10,"Aug 31, 2016",1 +,cupen,,0,10,"Nov 21, 2016",1 +,yay,,0,10,"Jan 25, 2017",1 ,niv,,0,5,"Apr 6, 2016",1 -,goniz,,0,5,"Apr 7, 2016",1 -,genunix,,0,5,"Apr 12, 2016",1 -,CynepHy6,,0,5,"Apr 14, 2016",1 -,ivanflorentin,,0,5,"May 3, 2016",1 -,stevenyhw,,0,5,"May 20, 2016",1 -,"Sanjay Singh",,0,5,"Jun 6, 2016",1 -,yuttie,,0,5,"Jun 7, 2016",1 -,hron,,0,5,"Jun 11, 2016",1 -,laszlowaty,,0,5,"Jun 17, 2016",1 diff --git a/web/sponsors.csv b/web/sponsors.csv index 0701575d59..7136808c6a 100644 --- a/web/sponsors.csv +++ b/web/sponsors.csv @@ -1,34 +1,40 @@ logo, name, url, this_month, all_time, since, level -assets/bountysource/secondspectrum.png,Second Spectrum,http://www.secondspectrum.com/,250,1250,"May 5, 2016",250 -assets/bountysource/xored.svg,"Xored Software, Inc.",http://xored.com/,250,1000,"Jun 20, 2016",250 -,shkolnick-kun,https://github.com/shkolnick-kun,75,225,"Jul 6, 2016",75 -,flyx,http://flyx.org,35,210,"Apr 7, 2016",75 -,"Yuriy Glukhov",,25,150,"Apr 6, 2016",25 -,endragor,https://github.com/endragor,25,150,"Apr 7, 2016",25 -,FedericoCeratto,http://firelet.net,25,150,"Apr 7, 2016",25 -,"Adrian Veith",,25,150,"Apr 20, 2016",25 -,skunkiferous,https://github.com/skunkiferous,100,100,"Oct 2, 2016",150 -,euantorano,http://euantorano.co.uk,25,100,"Jun 7, 2016",25 -,xxlabaza,https://github.com/xxlabaza,25,95,"Jun 17, 2016",25 -,btbytes,https://www.btbytes.com/,10,60,"Apr 6, 2016",10 -,niebaopeng,https://github.com/niebaopeng,10,50,"Apr 15, 2016",10 -,"Jonathan Arnett",,10,50,"May 20, 2016",10 -,swalf,https://github.com/swalf,5,45,"May 9, 2016",5 -,zolern,https://github.com/zolern,10,40,"Apr 15, 2016",10 -,"pyloor ",https://schwarz-weiss.cc/,10,40,"May 16, 2016",10 -,zachaysan,http://venn.lc,10,40,"Jun 7, 2016",10 -,"Matthew Baulch",,10,40,"Jun 7, 2016",10 -,"Oskari Timperi",,10,40,"Jun 8, 2016",10 -,"Handojo Goenadi",,5,35,"Apr 19, 2016",5 -,"Matthew Newton",,5,30,"Apr 20, 2016",5 -,johnnovak,http://www.johnnovak.net/,5,30,"Apr 29, 2016",5 -,RyanMarcus,http://rmarcus.info,5,15,"Jul 19, 2016",5 -,lenzenmi,https://github.com/lenzenmi,5,15,"Jul 28, 2016",5 -,cpunion,https://github.com/cpunion,10,10,"Sep 9, 2016",10 -,pandada8,https://github.com/pandada8,5,10,"Aug 12, 2016",5 -,abeaumont,http://alfredobeaumont.org/blog,5,10,"Aug 12, 2016",5 -,"Svend Knudsen",,1,6,"Apr 11, 2016",1 -,"Michael D. Sklaroff",,1,6,"Apr 27, 2016",1 -,csoriano89,https://github.com/csoriano89,5,5,"Sep 7, 2016",5 -,nicck,,1,2,"Aug 9, 2016",1 -,campbellr,,1,1,"Sep 4, 2016",1 +assets/bountysource/secondspectrum.png,Second Spectrum,http://www.secondspectrum.com/,250,2250,"May 5, 2016",250 +assets/bountysource/xored.svg,"Xored Software, Inc.",http://xored.com/,250,1000,250,2000,"Jun 20, 2016",250 +,Varriount,https://github.com/Varriount,250,750,"Nov 18, 2016",250 +,flyx,http://flyx.org,35,350,"Apr 7, 2016",75 +,"Yuriy Glukhov",,25,250,"Apr 6, 2016",25 +,endragor,https://github.com/endragor,25,250,"Apr 7, 2016",25 +,FedericoCeratto,http://firelet.net,25,250,"Apr 7, 2016",25 +,"Adrian Veith",,25,250,"Apr 20, 2016",25 +,euantorano,http://euantorano.co.uk,25,200,"Jun 7, 2016",25 +,xxlabaza,https://github.com/xxlabaza,25,170,"Jun 17, 2016",25 +,devted,https://github.com/devted,25,100,"Oct 19, 2016",25 +,"pyloor ",https://schwarz-weiss.cc/,10,95,"May 16, 2016",10 +,niebaopeng,https://github.com/niebaopeng,10,90,"Apr 15, 2016",10 +,zolern,https://github.com/zolern,10,80,"Apr 15, 2016",10 +,"Oskari Timperi",,10,80,"Jun 8, 2016",10 +,jcosborn,https://github.com/jcosborn,25,75,"Nov 21, 2016",25 +,swalf,https://github.com/swalf,5,65,"May 9, 2016",5 +,"Handojo Goenadi",,5,55,"Apr 19, 2016",5 +,cpunion,https://github.com/cpunion,10,50,"Sep 9, 2016",10 +,D-L,https://github.com/D-L,5,50,"Apr 7, 2016",5 +,moigagoo,http://sloth-ci.com,10,40,"May 13, 2016",10 +,enthus1ast,http://code0.xyz/,10,40,"Oct 28, 2016",10 +,RyanMarcus,http://rmarcus.info,5,35,"Jul 19, 2016",5 +,lenzenmi,https://github.com/lenzenmi,5,35,"Jul 28, 2016",5 +,"Christian Bagley",,10,30,"Oct 11, 2016",10 +,pandada8,https://github.com/pandada8,5,30,"Aug 12, 2016",5 +,abeaumont,http://alfredobeaumont.org/blog,5,30,"Aug 12, 2016",5 +,opendragon,http://www.opendragon.com,25,25,"Jan 18, 2017",25 +,"Eric Raible",,10,20,"Dec 23, 2016",10 +,zefciu,http://pythonista.net,10,20,"Dec 29, 2016",10 +,"Andrey ",https://github.com/Andrey,5,20,"Oct 10, 2016",5 +,syrol,https://github.com/syrol,5,10,"Dec 12, 2016",5 +,"Svend Knudsen",,1,10,"Apr 11, 2016",1 +,"Michael D. Sklaroff",,1,10,"Apr 27, 2016",1 +,nicck,,1,6,"Aug 9, 2016",1 +,cnygaard,,5,5,"Jan 17, 2017",5 +,Aldrog,,5,5,"Feb 11, 2017",5 +,mpachecofaulk55,,5,5,"Feb 11, 2017",5 +,campbellr,,1,5,"Sep 4, 2016",1 From 4c683e90ece19e0f9b2833daf4d4f783ab186718 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 14 Feb 2017 21:09:49 +0100 Subject: [PATCH 25/67] Fix rst parse problem in version 0.16.2 news. --- web/news/e031_version_0_16_2.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/news/e031_version_0_16_2.rst b/web/news/e031_version_0_16_2.rst index 2d725028e4..171e4cef12 100644 --- a/web/news/e031_version_0_16_2.rst +++ b/web/news/e031_version_0_16_2.rst @@ -21,8 +21,8 @@ Changes affecting backwards compatibility - A hash procedure has been added for ``cstring`` type in ``hashes`` module. Previously, hash of a ``cstring`` would be calculated as a hash of the pointer. Now the hash is calculated from the contents of the string, assuming - ``cstring`` is a null-terminated string. Equal ``string``s and ``cstring``s - produce equal hash value. + ``cstring`` is a null-terminated string. Equal ``string`` and ``cstring`` + values produce an equal hash value. Library Additions ----------------- From 20ccf417f6fd8bd1ed0741bc5ae9019f4099bffd Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 15 Feb 2017 12:26:28 +0100 Subject: [PATCH 26/67] get rid of debug output --- compiler/types.nim | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/types.nim b/compiler/types.nim index 8ea00e7e5e..b237753ae7 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1537,7 +1537,4 @@ proc typeMismatch*(n: PNode, formal, actual: PType) = msg.add "\n.tag effect is 'any tag allowed'" of efLockLevelsDiffer: msg.add "\nlock levels differ" - writeStackTrace() - debug actual.n - debug formal.n localError(n.info, errGenerated, msg) From 1189ae9b99eff08dc34f2d5338c65ca2096ca297 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 15 Feb 2017 12:26:53 +0100 Subject: [PATCH 27/67] renamed writelnHook to writelnToChannel --- tools/nimsuggest/nimsuggest.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/nimsuggest/nimsuggest.nim b/tools/nimsuggest/nimsuggest.nim index afc90c0b4b..3d95a79bff 100644 --- a/tools/nimsuggest/nimsuggest.nim +++ b/tools/nimsuggest/nimsuggest.nim @@ -235,7 +235,7 @@ proc toEpc(client: Socket; uid: BiggestInt) {.gcsafe.} = if gIdeCmd != ideChk: returnEPC(client, uid, list) -proc writelnHook(line: string) = +proc writelnToChannel(line: string) = results.send(Suggest(section: ideChk, doc: line)) proc sugResultHook(s: Suggest) = @@ -400,14 +400,14 @@ proc mainThread(graph: ModuleGraph; cache: IdentCache) = logStr(PStrEntry(it).data) it = it.next - msgs.writelnHook = writelnHook + msgs.writelnHook = writelnToChannel suggestionResultHook = sugResultHook graph.doStopCompile = proc (): bool = requests.peek() > 0 var idle = 0 while true: let (hasData, req) = requests.tryRecv() if hasData: - msgs.writelnHook = writelnHook + msgs.writelnHook = writelnToChannel suggestionResultHook = sugResultHook execCmd(req, graph, cache) From 55782205a4bcbe8584fbb96425ae530a302be15f Mon Sep 17 00:00:00 2001 From: Eugene Kabanov Date: Wed, 15 Feb 2017 14:18:45 +0200 Subject: [PATCH 28/67] Fix appveyor.yml shows green, when failed. (#5396) --- appveyor.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 87640b1923..ea98b8507e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,10 +7,7 @@ cache: # - i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z matrix: - fast_finish: true # set this flag to immediately finish build once one of the jobs fails. - allow_failures: - - platform: x64 -# - platform: x86 + fast_finish: true environment: matrix: From 95abf30fae3d1d91e1980fa9a5a46e7319201cd8 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 15 Feb 2017 15:35:15 +0100 Subject: [PATCH 29/67] compiler debug proc: also output node flags --- compiler/astalgo.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index affbdffd96..226d5ee42c 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -388,6 +388,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int; [istr, makeYamlString($n.kind)] addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) if maxRecDepth != 0: + addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)]) case n.kind of nkCharLit..nkUInt64Lit: addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)]) From 1811e51ff5dc0213a5abfd0f2bb32729f40c0344 Mon Sep 17 00:00:00 2001 From: araq Date: Wed, 15 Feb 2017 22:09:16 +0100 Subject: [PATCH 30/67] fixes #5392 --- lib/system/sysio.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index fa1bdbb4e2..7444661e37 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -215,7 +215,10 @@ proc rawFileSize(file: File): int = discard c_fseek(file, clong(oldPos), 0) proc endOfFile(f: File): bool = - result = c_feof(f) != 0 + var c = c_fgetc(f) + discard c_ungetc(c, f) + return c < 0'i32 + #result = c_feof(f) != 0 proc readAllFile(file: File, len: int): string = # We acquire the filesize beforehand and hope it doesn't change. From 5b5bd3811b5f6e7841128527cb098b23b373e7a6 Mon Sep 17 00:00:00 2001 From: araq Date: Wed, 15 Feb 2017 22:10:31 +0100 Subject: [PATCH 31/67] koch: don't build downloader tool, it is not ready --- koch.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/koch.nim b/koch.nim index 825b360a0a..109dcc3f1c 100644 --- a/koch.nim +++ b/koch.nim @@ -223,8 +223,9 @@ proc bundleWinTools() = copyExe("tools/finish".exe, "finish".exe) removeFile("tools/finish".exe) nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe") - nimexec(r"c --cc:vcc --app:gui -o:bin\downloader.exe -d:ssl --noNimblePath " & - r"--path:..\ui tools\downloader.nim") + when false: + nimexec(r"c --cc:vcc --app:gui -o:bin\downloader.exe -d:ssl --noNimblePath " & + r"--path:..\ui tools\downloader.nim") proc zip(args: string) = bundleNimbleSrc() From 97e26967f1f37a33edf6877cedfc9854fabab5eb Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 16 Feb 2017 00:43:14 +0100 Subject: [PATCH 32/67] fixes #5383 --- compiler/ast.nim | 3 +-- compiler/sem.nim | 15 +++++++++++++++ compiler/semdata.nim | 10 ++++++++++ compiler/semexprs.nim | 3 ++- compiler/seminst.nim | 7 ++++--- compiler/semstmts.nim | 1 + compiler/semtempl.nim | 2 +- compiler/semtypes.nim | 9 +++++---- compiler/transf.nim | 5 ++++- tests/template/tgensymregression.nim | 13 +++++++++++++ tests/template/tparams_gensymed.nim | 9 ++++----- 11 files changed, 60 insertions(+), 17 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 8fbec64cf1..4ea68dc996 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1541,8 +1541,7 @@ proc skipGenericOwner*(s: PSym): PSym = ## Generic instantiations are owned by their originating generic ## symbol. This proc skips such owners and goes straight to the owner ## of the generic itself (the module or the enclosing proc). - result = if s.kind in skProcKinds and {sfGenSym, sfFromGeneric} * s.flags == - {sfFromGeneric}: + result = if s.kind in skProcKinds and sfFromGeneric in s.flags: s.owner.owner else: s.owner diff --git a/compiler/sem.nim b/compiler/sem.nim index dbf2376357..961d9fa75e 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -168,6 +168,16 @@ proc commonType*(x, y: PType): PType = proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info) +proc getGenSym(c: PContext; s: PSym): PSym = + var it = c.p + while it != nil: + result = get(it, s) + if result != nil: + #echo "got from table ", result.name.s, " ", result.info + return result + it = it.next + result = s + proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii @@ -178,6 +188,11 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = if result.kind != kind: localError(n.info, "cannot use symbol of kind '" & $result.kind & "' as a '" & $kind & "'") + if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}: + # declarative context, so produce a fresh gensym: + result = copySym(result) + result.ast = n.sym.ast + put(c.p, n.sym, result) # when there is a nested proc inside a template, semtmpl # will assign a wrong owner during the first pass over the # template; we must fix it here: see #909 diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 20fd1d9be5..845efd25a0 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -39,6 +39,7 @@ type next*: PProcCon # used for stacking procedure contexts wasForwarded*: bool # whether the current proc has a separate header bracketExpr*: PNode # current bracket expression (for ^ support) + mapping*: TIdTable TInstantiationPair* = object genericSym*: PSym @@ -147,6 +148,15 @@ proc lastOptionEntry*(c: PContext): POptionEntry = proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next +proc put*(p: PProcCon; key, val: PSym) = + if p.mapping.data == nil: initIdTable(p.mapping) + #echo "put into table ", key.info + p.mapping.idTablePut(key, val) + +proc get*(p: PProcCon; key: PSym): PSym = + if p.mapping.data == nil: return nil + result = PSym(p.mapping.idTableGet(key)) + proc newOptionEntry*(): POptionEntry = new(result) result.options = gOptions diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 9972585c7b..542d7b4e39 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -922,7 +922,8 @@ proc readTypeParameter(c: PContext, typ: PType, return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info) #echo "came here: returned nil" -proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = +proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = + let s = getGenSym(c, sym) case s.kind of skConst: markUsed(n.info, s) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 9c57be0231..1a96b4bc60 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -106,15 +106,16 @@ proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) = #if n.kind == nkSym and sfGenSym in n.sym.flags: # if n.sym.owner != orig: # echo "symbol ", n.sym.name.s, " orig ", orig, " owner ", n.sym.owner - if n.kind == nkSym and {sfGenSym, sfFromGeneric} * n.sym.flags == {sfGenSym}: # and + if n.kind == nkSym and sfGenSym in n.sym.flags: # and # (n.sym.owner == orig or n.sym.owner.kind in {skPackage}): let s = n.sym var x = PSym(idTableGet(symMap, s)) - if x == nil: + if x != nil: + n.sym = x + when false: x = copySym(s, false) x.owner = owner idTablePut(symMap, s, x) - n.sym = x else: for i in 0 .. Date: Thu, 16 Feb 2017 01:43:12 +0100 Subject: [PATCH 33/67] make more tests green --- compiler/semfold.nim | 5 ++++- compiler/transf.nim | 10 ++++++---- tests/overload/tprefer_tygenericinst.nim | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 05e398c9a3..7a65462ec2 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -628,7 +628,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of {skProc, skMethod}: result = n of skType: - result = newSymNodeTypeDesc(s, n.info) + # XXX gensym'ed symbols can come here and cannot be resolved. This is + # dirty, but correct. + if s.typ != nil: + result = newSymNodeTypeDesc(s, n.info) of skGenericParam: if s.typ.kind == tyStatic: if s.typ.n != nil: diff --git a/compiler/transf.nim b/compiler/transf.nim index cbd1f15e34..2103d48bf9 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -869,10 +869,12 @@ proc transform(c: PTransf, n: PNode): PTransNode = else: result = transformSons(c, n) of nkIdentDefs, nkConstDef: - result = n.PTransNode - #transformSons(c, n) - let L = n.len-1 - result[L] = transform(c, n.sons[L]) + when true: + result = transformSons(c, n) + else: + result = n.PTransNode + let L = n.len-1 + result[L] = transform(c, n.sons[L]) # XXX comment handling really sucks: if importantComments(): PNode(result).comment = n.comment diff --git a/tests/overload/tprefer_tygenericinst.nim b/tests/overload/tprefer_tygenericinst.nim index 9787af06b9..56541c7e8b 100644 --- a/tests/overload/tprefer_tygenericinst.nim +++ b/tests/overload/tprefer_tygenericinst.nim @@ -19,7 +19,7 @@ when true: q(B()) # This call reported as ambiguous. # bug #2219 -template testPred(a: expr) = +template testPred(a: untyped) = block: type A = object of RootObj type B = object of A From 01c785e0aa2f2b7f36aa51c34bbedfbf2e74fb39 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 16 Feb 2017 10:39:40 +0100 Subject: [PATCH 34/67] make tests green again --- compiler/seminst.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 1a96b4bc60..acaade4949 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -112,10 +112,12 @@ proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) = var x = PSym(idTableGet(symMap, s)) if x != nil: n.sym = x - when false: + elif s.owner.kind == skPackage: + #echo "copied this ", s.name.s x = copySym(s, false) x.owner = owner idTablePut(symMap, s, x) + n.sym = x else: for i in 0 .. Date: Wed, 15 Feb 2017 15:35:15 +0100 Subject: [PATCH 35/67] compiler debug proc: also output node flags --- compiler/astalgo.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index affbdffd96..226d5ee42c 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -388,6 +388,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int; [istr, makeYamlString($n.kind)] addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) if maxRecDepth != 0: + addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)]) case n.kind of nkCharLit..nkUInt64Lit: addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)]) From 71026cec6e28d89677be0b5b3db4f8f79ee4bb3e Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 16 Feb 2017 00:43:14 +0100 Subject: [PATCH 36/67] fixes #5383 --- compiler/ast.nim | 3 +-- compiler/sem.nim | 15 +++++++++++++++ compiler/semdata.nim | 10 ++++++++++ compiler/semexprs.nim | 3 ++- compiler/seminst.nim | 7 ++++--- compiler/semstmts.nim | 1 + compiler/semtempl.nim | 2 +- compiler/semtypes.nim | 9 +++++---- compiler/transf.nim | 5 ++++- tests/template/tgensymregression.nim | 13 +++++++++++++ tests/template/tparams_gensymed.nim | 9 ++++----- 11 files changed, 60 insertions(+), 17 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 8fbec64cf1..4ea68dc996 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1541,8 +1541,7 @@ proc skipGenericOwner*(s: PSym): PSym = ## Generic instantiations are owned by their originating generic ## symbol. This proc skips such owners and goes straight to the owner ## of the generic itself (the module or the enclosing proc). - result = if s.kind in skProcKinds and {sfGenSym, sfFromGeneric} * s.flags == - {sfFromGeneric}: + result = if s.kind in skProcKinds and sfFromGeneric in s.flags: s.owner.owner else: s.owner diff --git a/compiler/sem.nim b/compiler/sem.nim index dbf2376357..961d9fa75e 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -168,6 +168,16 @@ proc commonType*(x, y: PType): PType = proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info) +proc getGenSym(c: PContext; s: PSym): PSym = + var it = c.p + while it != nil: + result = get(it, s) + if result != nil: + #echo "got from table ", result.name.s, " ", result.info + return result + it = it.next + result = s + proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii @@ -178,6 +188,11 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = if result.kind != kind: localError(n.info, "cannot use symbol of kind '" & $result.kind & "' as a '" & $kind & "'") + if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}: + # declarative context, so produce a fresh gensym: + result = copySym(result) + result.ast = n.sym.ast + put(c.p, n.sym, result) # when there is a nested proc inside a template, semtmpl # will assign a wrong owner during the first pass over the # template; we must fix it here: see #909 diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 20fd1d9be5..845efd25a0 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -39,6 +39,7 @@ type next*: PProcCon # used for stacking procedure contexts wasForwarded*: bool # whether the current proc has a separate header bracketExpr*: PNode # current bracket expression (for ^ support) + mapping*: TIdTable TInstantiationPair* = object genericSym*: PSym @@ -147,6 +148,15 @@ proc lastOptionEntry*(c: PContext): POptionEntry = proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next +proc put*(p: PProcCon; key, val: PSym) = + if p.mapping.data == nil: initIdTable(p.mapping) + #echo "put into table ", key.info + p.mapping.idTablePut(key, val) + +proc get*(p: PProcCon; key: PSym): PSym = + if p.mapping.data == nil: return nil + result = PSym(p.mapping.idTableGet(key)) + proc newOptionEntry*(): POptionEntry = new(result) result.options = gOptions diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 9972585c7b..542d7b4e39 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -922,7 +922,8 @@ proc readTypeParameter(c: PContext, typ: PType, return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info) #echo "came here: returned nil" -proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = +proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = + let s = getGenSym(c, sym) case s.kind of skConst: markUsed(n.info, s) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 9c57be0231..1a96b4bc60 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -106,15 +106,16 @@ proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) = #if n.kind == nkSym and sfGenSym in n.sym.flags: # if n.sym.owner != orig: # echo "symbol ", n.sym.name.s, " orig ", orig, " owner ", n.sym.owner - if n.kind == nkSym and {sfGenSym, sfFromGeneric} * n.sym.flags == {sfGenSym}: # and + if n.kind == nkSym and sfGenSym in n.sym.flags: # and # (n.sym.owner == orig or n.sym.owner.kind in {skPackage}): let s = n.sym var x = PSym(idTableGet(symMap, s)) - if x == nil: + if x != nil: + n.sym = x + when false: x = copySym(s, false) x.owner = owner idTablePut(symMap, s, x) - n.sym = x else: for i in 0 .. Date: Thu, 16 Feb 2017 11:15:27 +0100 Subject: [PATCH 37/67] fixes #5402 --- compiler/ccgexprs.nim | 9 ++++--- tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim | 26 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 95a7beada5..6f7e83c186 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -220,7 +220,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = optAsgnLoc(src, t, field), newflags) proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, - t: PNode) = + t: PNode, typ: PType) = if t == nil: return let newflags = if src.s == OnStatic: @@ -232,10 +232,11 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, case t.kind of nkSym: let field = t.sym + if field.loc.r == nil: fillObjectFields(p.module, typ) genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r), optAsgnLoc(src, field.typ, field.loc.r), newflags) of nkRecList: - for child in items(t): genOptAsgnObject(p, dest, src, newflags, child) + for child in items(t): genOptAsgnObject(p, dest, src, newflags, child, typ) else: discard proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = @@ -315,9 +316,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = genGenericAsgn(p, dest, src, flags) elif needsComplexAssignment(ty): if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4: - discard getTypeDesc(p.module, dest.t) + discard getTypeDesc(p.module, ty) internalAssert ty.n != nil - genOptAsgnObject(p, dest, src, flags, ty.n) + genOptAsgnObject(p, dest, src, flags, ty.n, ty) else: genGenericAsgn(p, dest, src, flags) else: diff --git a/tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim b/tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim new file mode 100644 index 0000000000..919dc3fc19 --- /dev/null +++ b/tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim @@ -0,0 +1,26 @@ +discard """ + output: '''false''' +""" + +# bug #5402 + +import lists + +type + Container[T] = ref object + obj: T + + ListOfContainers[T] = ref object + list: DoublyLinkedList[Container[T]] + +proc contains[T](this: ListOfContainers[T], obj: T): bool = + for item in this.list.items(): + if item.obj == obj: return true + return false + +proc newListOfContainers[T](): ListOfContainers[T] = + new(result) + result.list = initDoublyLinkedList[Container[T]]() + +let q = newListOfContainers[int64]() +echo q.contains(123) From 61181702d5cf68e4b7a97cac352b395d37ddb702 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 16 Feb 2017 11:35:15 +0100 Subject: [PATCH 38/67] fixes #5399 --- compiler/semfold.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 7a65462ec2..749deded11 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -659,7 +659,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode = localError(a.info, errCannotEvalXBecauseIncompletelyDefined, "sizeof") result = nil - elif skipTypes(a.typ, typedescInst).kind in + elif skipTypes(a.typ, typedescInst+{tyRange}).kind in IntegralTypes+NilableTypes+{tySet}: #{tyArray,tyObject,tyTuple}: result = newIntNodeT(getSize(a.typ), n) From 0440aea69158dfde7e315d547f8f2ed474a705c0 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 16 Feb 2017 21:30:54 +0100 Subject: [PATCH 39/67] fixes #5405 --- compiler/sem.nim | 10 ---------- compiler/semdata.nim | 20 ++++++++++++++++++++ compiler/sigmatch.nim | 2 ++ tests/template/tgensymregression.nim | 15 +++++++++++++++ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index 961d9fa75e..fc7736b079 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -168,16 +168,6 @@ proc commonType*(x, y: PType): PType = proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info) -proc getGenSym(c: PContext; s: PSym): PSym = - var it = c.p - while it != nil: - result = get(it, s) - if result != nil: - #echo "got from table ", result.name.s, " ", result.info - return result - it = it.next - result = s - proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 845efd25a0..77a530a150 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -157,6 +157,26 @@ proc get*(p: PProcCon; key: PSym): PSym = if p.mapping.data == nil: return nil result = PSym(p.mapping.idTableGet(key)) +proc getGenSym*(c: PContext; s: PSym): PSym = + if sfGenSym notin s.flags: return s + var it = c.p + while it != nil: + result = get(it, s) + if result != nil: + #echo "got from table ", result.name.s, " ", result.info + return result + it = it.next + result = s + +proc considerGenSyms*(c: PContext; n: PNode) = + if n.kind == nkSym: + let s = getGenSym(c, n.sym) + if n.sym != s: + n.sym = s + else: + for i in 0.. Date: Thu, 16 Feb 2017 22:50:21 +0100 Subject: [PATCH 40/67] fixes #5400 --- compiler/ccgstmts.nim | 7 +++++-- tests/errmsgs/tproper_stacktrace3.nim | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 tests/errmsgs/tproper_stacktrace3.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 45d675f64a..02119d63e1 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1103,8 +1103,8 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) = genAssignment(p, a, tmp, {}) proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = - genLineDir(p, e) if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags: + genLineDir(p, e) genGotoVar(p, e.sons[1]) elif not fieldDiscriminantCheckNeeded(p, e): var a: TLoc @@ -1114,8 +1114,11 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = initLocExpr(p, e.sons[0], a) if fastAsgn: incl(a.flags, lfNoDeepCopy) assert(a.t != nil) - loadInto(p, e.sons[0], e.sons[1], a) + let ri = e.sons[1] + genLineDir(p, ri) + loadInto(p, e.sons[0], ri, a) else: + genLineDir(p, e) asgnFieldDiscriminant(p, e) proc genStmts(p: BProc, t: PNode) = diff --git a/tests/errmsgs/tproper_stacktrace3.nim b/tests/errmsgs/tproper_stacktrace3.nim new file mode 100644 index 0000000000..c292fa0920 --- /dev/null +++ b/tests/errmsgs/tproper_stacktrace3.nim @@ -0,0 +1,23 @@ +discard """ + outputsub: '''tproper_stacktrace3.nim(21) main''' + exitcode: 1 +""" + +# bug #5400 + +type Container = object + val: int + +proc actualResolver(x: ptr Container): ptr Container = x + +template resolve(): untyped = actualResolver(db) + +proc myfail(): int = + doAssert false + +proc main() = + var db: ptr Container = nil + # actualResolver(db).val = myfail() # actualResolver is not included in stack trace. + resolve().val = myfail() # resolve template is included in stack trace. + +main() From 5d4ed1117de41e0907536437292688d77aa6f01b Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 16 Feb 2017 22:53:32 +0100 Subject: [PATCH 41/67] distros.nim: brew usually doesn't require 'sudo' --- lib/pure/distros.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index ff30f61341..8964976305 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -225,7 +225,7 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) = else: result = (" install " & p, true) else: - result = ("brew install " & p, true) + result = ("brew install " & p, false) proc foreignDep*(foreignPackageName: string) = ## Registers 'foreignPackageName' to the internal list of foreign deps. From 9534a5d6328e6e4df94d4a8f038a388dfdf56c49 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 16 Feb 2017 22:59:07 +0100 Subject: [PATCH 42/67] fixes #5391 --- compiler/trees.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/trees.nim b/compiler/trees.nim index 7208f7d7b4..79a460aa0e 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -38,7 +38,7 @@ proc exprStructuralEquivalent*(a, b: PNode; strictSymEquality=false): bool = # don't go nuts here: same symbol as string is enough: result = a.sym.name.id == b.sym.name.id of nkIdent: result = a.ident.id == b.ident.id - of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal + of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkEmpty, nkNilLit, nkType: result = true From bdd9f971e7b1f8c1fde54abdb3032ba697b059bd Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 16 Feb 2017 23:20:01 +0100 Subject: [PATCH 43/67] update code from a time when unsigned didn't exist --- compiler/trees.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/trees.nim b/compiler/trees.nim index 79a460aa0e..424fba14c7 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -62,7 +62,7 @@ proc sameTree*(a, b: PNode): bool = # don't go nuts here: same symbol as string is enough: result = a.sym.name.id == b.sym.name.id of nkIdent: result = a.ident.id == b.ident.id - of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal + of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkEmpty, nkNilLit, nkType: result = true From 5620e085637fb3b090ce05092a4258427cd3e41a Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 17 Feb 2017 00:00:39 +0100 Subject: [PATCH 44/67] minor documentation improvements --- doc/manual/pragmas.txt | 12 ++++++------ lib/pure/os.nim | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt index 2a276c2e7f..af955a3e09 100644 --- a/doc/manual/pragmas.txt +++ b/doc/manual/pragmas.txt @@ -1018,12 +1018,12 @@ the -d/--define option at compile time. The implementation currently provides the following possible options (various others may be added later). -=============== ============================================ -pragma description -=============== ============================================ -intdefine Reads in a build-time define as an integer -strdefine Reads in a build-time define as a string -=============== ============================================ +================= ============================================ +pragma description +================= ============================================ +`intdefine`:idx: Reads in a build-time define as an integer +`strdefine`:idx: Reads in a build-time define as a string +================= ============================================ .. code-block:: nim const FooBar {.intdefine.}: int = 5 diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 92e2958204..6bf776a442 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1185,7 +1185,7 @@ proc createHardlink*(src, dest: string) = proc parseCmdLine*(c: string): seq[string] {. noSideEffect, rtl, extern: "nos$1".} = - ## Splits a command line into several components; + ## Splits a `command line`:idx: into several components; ## This proc is only occasionally useful, better use the `parseopt` module. ## ## On Windows, it uses the following parsing rules From e9767d8809a0ff4df83ffff1836937db3c2885bf Mon Sep 17 00:00:00 2001 From: fenekku Date: Fri, 17 Feb 2017 02:26:49 -0500 Subject: [PATCH 45/67] Fix reverse on empty openArray (#5407) Reversing an empty `openArray` would raise a RangeError. For instance for `a: seq[int] = @[]`, we have `a.high` return `-1` but `-1` is not a `Natural`. Leaving the array as-is is the expected behaviour. --- lib/pure/algorithm.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 739cdc16bb..bc39f153bf 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -46,7 +46,7 @@ proc reverse*[T](a: var openArray[T], first, last: Natural) = proc reverse*[T](a: var openArray[T]) = ## reverses the array `a`. - reverse(a, 0, a.high) + reverse(a, 0, max(0, a.high)) proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] = ## returns the reverse of the array `a[first..last]`. From dd8cbf5fca7becf43b5cec07ecf7e579308e2e7a Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 17 Feb 2017 17:44:52 +0100 Subject: [PATCH 46/67] fixes #5404 --- compiler/ccgtypes.nim | 8 +++++++- tests/ccgbugs/tmangle_field.nim | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/ccgbugs/tmangle_field.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index e30fe5598b..29d4e23c97 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -24,7 +24,13 @@ proc isKeyword(w: PIdent): bool = proc mangleField(m: BModule; name: PIdent): string = result = mangle(name.s) - if isKeyword(name) or m.g.config.cppDefines.contains(result): + # fields are tricky to get right and thanks to generic types producing + # duplicates we can end up mangling the same field multiple times. However + # if we do so, the 'cppDefines' table might be modified in the meantime + # meaning we produce inconsistent field names (see bug #5404). + # Hence we do not check for ``m.g.config.cppDefines.contains(result)`` here + # anymore: + if isKeyword(name): result.add "_0" when false: diff --git a/tests/ccgbugs/tmangle_field.nim b/tests/ccgbugs/tmangle_field.nim new file mode 100644 index 0000000000..9e4012b8b1 --- /dev/null +++ b/tests/ccgbugs/tmangle_field.nim @@ -0,0 +1,16 @@ +discard """ +""" + +# bug #5404 + +import parseopt2 + +{.emit: """typedef struct { + int key; +} foo;""".} + +type foo* {.importc: "foo", nodecl.} = object + key* {.importc: "key".}: cint + +for kind, key, value in parseopt2.getopt(): + discard From 8f426b974a38d141205cac182d1883e1ecf8c9ce Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 17 Feb 2017 18:03:56 +0100 Subject: [PATCH 47/67] new feature: .used pragma to suppress declared-but-not-used warning --- compiler/pragmas.nim | 20 ++++++++++++-------- compiler/wordrecg.nim | 4 ++-- doc/manual/pragmas.txt | 20 ++++++++++++++++++++ tests/pragmas/tused.nim | 13 +++++++++++++ web/news/e031_version_0_16_2.rst | 4 ++++ 5 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 tests/pragmas/tused.nim diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 04dbd36128..1fe1c81d28 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -25,19 +25,19 @@ const wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl, wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, - wOverride, wConstructor, wExportNims} + wOverride, wConstructor, wExportNims, wUsed} converterPragmas* = procPragmas methodPragmas* = procPragmas+{wBase}-{wImportCpp} templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty, - wDelegator, wExportNims} + wDelegator, wExportNims, wUsed} macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc, wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator, - wExportNims} + wExportNims, wUsed} iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises, - wTags, wLocks, wGcSafe, wExportNims} + wTags, wLocks, wGcSafe, wExportNims, wUsed} exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, @@ -55,16 +55,16 @@ const wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow, wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef, wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, - wBorrow, wGcSafe, wExportNims, wPartial} + wBorrow, wGcSafe, wExportNims, wPartial, wUsed} fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, - wImportCpp, wImportObjC, wError, wGuard, wBitsize} + wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed} varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern, wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal, - wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims} + wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims, wUsed} constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims, - wIntDefine, wStrDefine} + wIntDefine, wStrDefine, wUsed} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect, wThread, wRaises, wLocks, wTags, wGcSafe} @@ -961,6 +961,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, sym.magic = mIntDefine of wStrDefine: sym.magic = mStrDefine + of wUsed: + noVal(it) + if sym == nil: invalidPragma(it) + else: sym.flags.incl sfUsed else: invalidPragma(it) else: invalidPragma(it) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index cf66b6358f..6072bd64c9 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -45,7 +45,7 @@ type wImportc, wExportc, wExportNims, wIncompleteStruct, wRequiresInit, wAlign, wNodecl, wPure, wSideeffect, wHeader, wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib, - wCompilerproc, wProcVar, wBase, + wCompilerproc, wProcVar, wBase, wUsed, wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wLink, wCompile, wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger, @@ -131,7 +131,7 @@ const "incompletestruct", "requiresinit", "align", "nodecl", "pure", "sideeffect", "header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib", - "compilerproc", "procvar", "base", + "compilerproc", "procvar", "base", "used", "fatal", "error", "warning", "hint", "line", "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", "link", "compile", "linksys", "deprecated", "varargs", diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt index af955a3e09..d30c37ff71 100644 --- a/doc/manual/pragmas.txt +++ b/doc/manual/pragmas.txt @@ -503,6 +503,26 @@ identifier that can be used to enable or disable it: This is often better than disabling all warnings at once. +used pragma +----------- + +Nim produces a warning for symbols that are not exported and not used either. +The ``used`` pragma can be attached to a symbol to suppress this warning. This +is particularly useful when the symbol was generated by a macro: + +.. code-block:: nim + template implementArithOps(T) = + proc echoAdd(a, b: T) {.used.} = + echo a + b + proc echoSub(a, b: T) {.used.} = + echo a - b + + # no warning produced for the unused 'echoSub' + implementArithOps(int) + echoAdd 3, 5 + + + experimental pragma ------------------- diff --git a/tests/pragmas/tused.nim b/tests/pragmas/tused.nim new file mode 100644 index 0000000000..f3126bd459 --- /dev/null +++ b/tests/pragmas/tused.nim @@ -0,0 +1,13 @@ +discard """ + output: '''8''' +""" + +template implementArithOps(T) = + proc echoAdd(a, b: T) {.used.} = + echo a + b + proc echoSub(a, b: T) {.used.} = + echo a - b + +# no warning produced for the unused 'echoSub' +implementArithOps(int) +echoAdd 3, 5 diff --git a/web/news/e031_version_0_16_2.rst b/web/news/e031_version_0_16_2.rst index 171e4cef12..785285eafe 100644 --- a/web/news/e031_version_0_16_2.rst +++ b/web/news/e031_version_0_16_2.rst @@ -66,6 +66,10 @@ these procedures. In the near future we will be converting all exception types to refs to remove the need for the ``newException`` template. +- A new pragma ``.used`` can be used for symbols to prevent +the "declared but not used" warning. More details can be found `here `_. + + Bugfixes -------- From 363b1c0a41e4b554c46d8aa5af5ad1ed31523628 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 17 Feb 2017 19:08:08 +0100 Subject: [PATCH 48/67] travis: first attempt to enable OSX tests --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.travis.yml b/.travis.yml index a3db0c58ed..ffb0033a39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,14 +2,24 @@ sudo: false language: c os: - linux + - osx dist: trusty +matrix: + allow_failures: + - os: osx + addons: apt: packages: - libcurl4-openssl-dev - libsdl1.2-dev - libgc-dev + brew: + packages: + - boehmgc + - node + before_script: - set -e - curl --out fasm-1.71.39.tgz https://nim-lang.org/download/fasm-1.71.39.tgz From 2adb4ce9eb7e8da0b6d219f6e501520f1c9f7743 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 19 Feb 2017 21:29:41 +0100 Subject: [PATCH 49/67] nimsuggest supports EPC protocol again; tester can test the EPC protocol --- tools/nimsuggest/nimsuggest.nim | 16 +++-- tools/nimsuggest/sexp.nim | 6 +- tools/nimsuggest/tester.nim | 120 +++++++++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 12 deletions(-) diff --git a/tools/nimsuggest/nimsuggest.nim b/tools/nimsuggest/nimsuggest.nim index 3d95a79bff..9e5538a15d 100644 --- a/tools/nimsuggest/nimsuggest.nim +++ b/tools/nimsuggest/nimsuggest.nim @@ -192,7 +192,7 @@ template sendEpc(results: typed, tdef, hook: untyped) = let res = sexp(results) if gLogging: logStr($res) - returnEPC(client, uid, res) + returnEpc(client, uid, res) template checkSanity(client, sizeHex, size, messageBuffer: typed) = if client.recv(sizeHex, 6) != 6: @@ -233,7 +233,7 @@ proc toEpc(client: Socket; uid: BiggestInt) {.gcsafe.} = else: list.add sexp(res) if gIdeCmd != ideChk: - returnEPC(client, uid, list) + returnEpc(client, uid, list) proc writelnToChannel(line: string) = results.send(Suggest(section: ideChk, doc: line)) @@ -303,8 +303,8 @@ proc replEpc(x: ThreadParams) {.thread.} = checkSanity(client, sizeHex, size, messageBuffer) let message = parseSexp($messageBuffer) - epcAPI = message[0].getSymbol - case epcAPI: + epcApi = message[0].getSymbol + case epcApi of "call": let uid = message[1].getNum @@ -320,16 +320,18 @@ proc replEpc(x: ThreadParams) {.thread.} = of ideSug, ideCon, ideDef, ideUse, ideDus, ideOutline, ideHighlight: setVerbosity(0) else: discard - requests.send messageBuffer + if gLogging: + logStr "MSG ARG: " & args.getStr + requests.send($gIdeCmd & " " & args.getStr) toEpc(client, uid) of "methods": - returnEpc(client, message[1].getNum, listEPC()) + returnEpc(client, message[1].getNum, listEpc()) of "epc-error": # an unhandled exception forces down the whole process anyway, so we # use 'quit' here instead of 'raise' quit("recieved epc error: " & $messageBuffer) else: - let errMessage = case epcAPI + let errMessage = case epcApi of "return", "return-error": "no return expected" else: diff --git a/tools/nimsuggest/sexp.nim b/tools/nimsuggest/sexp.nim index cf08111d71..61bba10bc8 100644 --- a/tools/nimsuggest/sexp.nim +++ b/tools/nimsuggest/sexp.nim @@ -561,16 +561,16 @@ proc toPretty(result: var string, node: SexpNode, indent = 2, ml = true, result.add(escapeJson(node.str)) of SInt: if lstArr: result.indent(currIndent) - result.add($node.num) + result.add(node.num) of SFloat: if lstArr: result.indent(currIndent) - result.add($node.fnum) + result.add(node.fnum) of SNil: if lstArr: result.indent(currIndent) result.add("nil") of SSymbol: if lstArr: result.indent(currIndent) - result.add($node.symbol) + result.add(node.symbol) of SList: if lstArr: result.indent(currIndent) if len(node.elems) != 0: diff --git a/tools/nimsuggest/tester.nim b/tools/nimsuggest/tester.nim index 156d3ddb97..a773b1b36c 100644 --- a/tools/nimsuggest/tester.nim +++ b/tools/nimsuggest/tester.nim @@ -3,7 +3,7 @@ # before 'nimsuggest' is invoked to ensure this token doesn't make a # crucial difference for Nim's parser. -import os, osproc, strutils, streams, re +import os, osproc, strutils, streams, re, sexp, net type Test = object @@ -133,6 +133,119 @@ proc smartCompare(pattern, x: string): bool = if pattern.contains('*'): result = match(x, re(escapeRe(pattern).replace("\\x2A","(.*)"), {})) +proc sendEpcStr(socket: Socket; cmd: string) = + let s = cmd.find(' ') + doAssert s > 0 + let cmd = "(call 567 " & cmd.substr(0, s) & escapeJson(cmd.substr(s+1)) & ")" + socket.send toHex(cmd.len, 6) + socket.send cmd + +proc recvEpc(socket: Socket): string = + var L = newStringOfCap(6) + if socket.recv(L, 6) != 6: + raise newException(ValueError, "recv A failed") + let x = parseHexInt(L) + result = newString(x) + if socket.recv(result, x) != x: + raise newException(ValueError, "recv B failed") + +proc sexpToAnswer(s: SexpNode): string = + result = "" + doAssert s.kind == SList + doAssert s.len >= 3 + let m = s[2] + if m.kind != SList: + echo s + doAssert m.kind == SList + for a in m: + doAssert a.kind == SList + var first = true + #s.section, + #s.symkind, + #s.qualifiedPath.map(newSString), + #s.filePath, + #s.forth, + #s.line, + #s.column, + #s.doc + if a.len >= 8: + let section = a[0].getStr + let symk = a[1].getStr + let qp = a[2] + let file = a[3].getStr + let typ = a[4].getStr + let line = a[5].getNum + let col = a[6].getNum + let doc = a[7].getStr.escapeJson + result.add section + result.add '\t' + result.add symk + result.add '\t' + var i = 0 + for aa in qp: + if i > 0: result.add '.' + result.add aa.getStr + inc i + result.add '\t' + result.add typ + result.add '\t' + result.add file + result.add '\t' + result.add line + result.add '\t' + result.add col + result.add '\t' + result.add doc + result.add '\t' + # for now Nim EPC does not return the quality + result.add "100" + result.add '\L' + +proc runEpcTest(filename: string): int = + let s = parseTest filename + for cmd in s.startup: + if not runCmd(cmd, s.dest): + quit "invalid command: " & cmd + let epccmd = s.cmd.replace("--tester", "--epc --v2") + let cl = parseCmdLine(epccmd) + var p = startProcess(command=cl[0], args=cl[1 .. ^1], + options={poStdErrToStdOut, poUsePath, + poInteractive, poDemon}) + let outp = p.outputStream + let inp = p.inputStream + var report = "" + var a = newStringOfCap(120) + try: + # read the port number: + if outp.readLine(a): + let port = parseInt(a) + var socket = newSocket() + socket.connect("localhost", Port(port)) + for req, resp in items(s.script): + if not runCmd(req, s.dest): + socket.sendEpcStr(req) + var answer = sexpToAnswer(parseSexp(socket.recvEpc())) + if resp != answer and not smartCompare(resp, answer): + report.add "\nTest failed: " & filename + var hasDiff = false + for i in 0..min(resp.len-1, answer.len-1): + if resp[i] != answer[i]: + report.add "\n Expected: " & resp.substr(i) + report.add "\n But got: " & answer.substr(i) + hasDiff = true + break + if not hasDiff: + report.add "\n Expected: " & resp + report.add "\n But got: " & answer + else: + raise newException(ValueError, "cannot read port number") + finally: + close(p) + if report.len > 0: + echo "==== EPC ========================================" + echo report + result = report.len + proc runTest(filename: string): int = let s = parseTest filename for cmd in s.startup: @@ -176,6 +289,7 @@ proc runTest(filename: string): int = inp.flush() close(p) if report.len > 0: + echo "==== STDIN ======================================" echo report result = report.len @@ -183,7 +297,9 @@ proc main() = var failures = 0 for x in walkFiles(getAppDir() / "tests/t*.nim"): echo "Test ", x - failures += runTest(expandFilename(x)) + let xx = expandFilename x + failures += runTest(xx) + failures += runEpcTest(xx) if failures > 0: quit 1 From 2df5a6f863065918c005207e0b8e9763e0e1aa8c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Feb 2017 06:18:59 +0100 Subject: [PATCH 50/67] nimsuggest: make all tests green --- tools/nimsuggest/nimsuggest.nim | 8 +++-- tools/nimsuggest/tester.nim | 57 ++++++++++++++++----------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/tools/nimsuggest/nimsuggest.nim b/tools/nimsuggest/nimsuggest.nim index 9e5538a15d..d78f512995 100644 --- a/tools/nimsuggest/nimsuggest.nim +++ b/tools/nimsuggest/nimsuggest.nim @@ -402,14 +402,18 @@ proc mainThread(graph: ModuleGraph; cache: IdentCache) = logStr(PStrEntry(it).data) it = it.next - msgs.writelnHook = writelnToChannel + proc wrHook(line: string) {.closure.} = + if gMode == mepc: discard + else: writelnToChannel(line) + + msgs.writelnHook = wrHook suggestionResultHook = sugResultHook graph.doStopCompile = proc (): bool = requests.peek() > 0 var idle = 0 while true: let (hasData, req) = requests.tryRecv() if hasData: - msgs.writelnHook = writelnToChannel + msgs.writelnHook = wrHook suggestionResultHook = sugResultHook execCmd(req, graph, cache) diff --git a/tools/nimsuggest/tester.nim b/tools/nimsuggest/tester.nim index a773b1b36c..4e12f329f4 100644 --- a/tools/nimsuggest/tester.nim +++ b/tools/nimsuggest/tester.nim @@ -176,7 +176,7 @@ proc sexpToAnswer(s: SexpNode): string = let typ = a[4].getStr let line = a[5].getNum let col = a[6].getNum - let doc = a[7].getStr.escapeJson + let doc = a[7].getStr.escape result.add section result.add '\t' result.add symk @@ -201,6 +201,20 @@ proc sexpToAnswer(s: SexpNode): string = result.add "100" result.add '\L' +proc doReport(filename, answer, resp: string; report: var string) = + if resp != answer and not smartCompare(resp, answer): + report.add "\nTest failed: " & filename + var hasDiff = false + for i in 0..min(resp.len-1, answer.len-1): + if resp[i] != answer[i]: + report.add "\n Expected: " & resp.substr(i) + report.add "\n But got: " & answer.substr(i) + hasDiff = true + break + if not hasDiff: + report.add "\n Expected: " & resp + report.add "\n But got: " & answer + proc runEpcTest(filename: string): int = let s = parseTest filename for cmd in s.startup: @@ -224,19 +238,10 @@ proc runEpcTest(filename: string): int = for req, resp in items(s.script): if not runCmd(req, s.dest): socket.sendEpcStr(req) - var answer = sexpToAnswer(parseSexp(socket.recvEpc())) - if resp != answer and not smartCompare(resp, answer): - report.add "\nTest failed: " & filename - var hasDiff = false - for i in 0..min(resp.len-1, answer.len-1): - if resp[i] != answer[i]: - report.add "\n Expected: " & resp.substr(i) - report.add "\n But got: " & answer.substr(i) - hasDiff = true - break - if not hasDiff: - report.add "\n Expected: " & resp - report.add "\n But got: " & answer + let sx = parseSexp(socket.recvEpc()) + if not req.startsWith("mod "): + let answer = sexpToAnswer(sx) + doReport(filename, answer, resp, report) else: raise newException(ValueError, "cannot read port number") finally: @@ -272,18 +277,7 @@ proc runTest(filename: string): int = if a == DummyEof: break answer.add a answer.add '\L' - if resp != answer and not smartCompare(resp, answer): - report.add "\nTest failed: " & filename - var hasDiff = false - for i in 0..min(resp.len-1, answer.len-1): - if resp[i] != answer[i]: - report.add "\n Expected: " & resp.substr(i) - report.add "\n But got: " & answer.substr(i) - hasDiff = true - break - if not hasDiff: - report.add "\n Expected: " & resp - report.add "\n But got: " & answer + doReport(filename, answer, resp, report) finally: inp.writeLine("quit") inp.flush() @@ -295,11 +289,16 @@ proc runTest(filename: string): int = proc main() = var failures = 0 - for x in walkFiles(getAppDir() / "tests/t*.nim"): - echo "Test ", x + when false: + let x = getAppDir() / "tests/twithin_macro.nim" let xx = expandFilename x - failures += runTest(xx) failures += runEpcTest(xx) + else: + for x in walkFiles(getAppDir() / "tests/t*.nim"): + echo "Test ", x + let xx = expandFilename x + failures += runTest(xx) + failures += runEpcTest(xx) if failures > 0: quit 1 From ce4587d7b721839ffa8ed4c9d1c2abd8f308f99d Mon Sep 17 00:00:00 2001 From: Fabian Keller Date: Mon, 20 Feb 2017 09:31:52 +0100 Subject: [PATCH 51/67] Enabled explicitly unknown lock levels (#5409) * enabled explicitly unknown lock levels * allowing "unknown" as locks pragma * added test case for locks pragma * updated docs on locks pragma --- compiler/pragmas.nim | 8 +++++++- doc/manual/locking.txt | 19 +++++++++++++++++++ tests/pragmas/tlocks.nim | 13 +++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/pragmas/tlocks.nim diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 1fe1c81d28..bcb0461f26 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -582,7 +582,13 @@ proc pragmaLocks(c: PContext, it: PNode): TLockLevel = if it.kind != nkExprColonExpr: invalidPragma(it) else: - if it[1].kind != nkNilLit: + case it[1].kind + of nkStrLit, nkRStrLit, nkTripleStrLit: + if it[1].strVal == "unknown": + result = UnknownLockLevel + else: + localError(it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")") + else: let x = expectIntLit(c, it) if x < 0 or x > MaxLockLevel: localError(it[1].info, "integer must be within 0.." & $MaxLockLevel) diff --git a/doc/manual/locking.txt b/doc/manual/locking.txt index c00efdd910..c1bd5ca462 100644 --- a/doc/manual/locking.txt +++ b/doc/manual/locking.txt @@ -198,3 +198,22 @@ This is essential so that procs can be called within a ``locks`` section: As usual ``locks`` is an inferred effect and there is a subtype relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}`` iff (M <= N). + +The ``locks`` pragma can also take the special value ``"unknown"``. This +is useful in the context of dynamic method dispatching. In the following +example, the compiler can infer a lock level of 0 for the ``base`` case. +However, one of the overloaded methods calls a procvar which is +potentially locking. Thus, the lock level of calling ``g.testMethod`` +cannot be inferred statically, leading to compiler warnings. By using +``{.locks: "unknown".}``, the base method can be marked explicitly as +having unknown lock level as well: + +.. code-block:: nim + type SomeBase* = ref object of RootObj + type SomeDerived* = ref object of SomeBase + memberProc*: proc () + + method testMethod(g: SomeBase) {.base, locks: "unknown".} = discard + method testMethod(g: SomeDerived) = + if g.memberProc != nil: + g.memberProc() diff --git a/tests/pragmas/tlocks.nim b/tests/pragmas/tlocks.nim new file mode 100644 index 0000000000..ba66a2dca2 --- /dev/null +++ b/tests/pragmas/tlocks.nim @@ -0,0 +1,13 @@ + +type SomeBase* = ref object of RootObj +type SomeDerived* = ref object of SomeBase + memberProc*: proc () + +method testMethod(g: SomeBase) {.base, locks: "unknown".} = discard +method testMethod(g: SomeDerived) = + if g.memberProc != nil: + g.memberProc() + +# ensure int literals still work +proc plain*() {.locks: 0.} = + discard From 1ec96d735355708bf2739d52d28374d91cd260a4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Feb 2017 09:54:20 +0100 Subject: [PATCH 52/67] nimsuggest: better logging for EPC mode --- tools/nimsuggest/nimsuggest.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/nimsuggest/nimsuggest.nim b/tools/nimsuggest/nimsuggest.nim index d78f512995..80ae58d953 100644 --- a/tools/nimsuggest/nimsuggest.nim +++ b/tools/nimsuggest/nimsuggest.nim @@ -403,8 +403,10 @@ proc mainThread(graph: ModuleGraph; cache: IdentCache) = it = it.next proc wrHook(line: string) {.closure.} = - if gMode == mepc: discard - else: writelnToChannel(line) + if gMode == mepc: + if gLogging: logStr(line) + else: + writelnToChannel(line) msgs.writelnHook = wrHook suggestionResultHook = sugResultHook From 2d28a626f2113d3712ea541bbc7686afe13d8d90 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 20 Feb 2017 11:51:17 +0100 Subject: [PATCH 53/67] nimsuggest: works with VS-Plugin again --- tools/nimsuggest/nimsuggest.nim | 22 ++++++++++++++++++++-- tools/nimsuggest/tester.nim | 17 +++++++++++------ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/tools/nimsuggest/nimsuggest.nim b/tools/nimsuggest/nimsuggest.nim index 80ae58d953..db8b905415 100644 --- a/tools/nimsuggest/nimsuggest.nim +++ b/tools/nimsuggest/nimsuggest.nim @@ -286,6 +286,23 @@ proc replTcp(x: ThreadParams) {.thread.} = stdoutSocket.send("\c\L") stdoutSocket.close() +proc argsToStr(x: SexpNode): string = + if x.kind != SList: return x.getStr + doAssert x.kind == SList + doAssert x.len >= 4 + let file = x[0].getStr + let line = x[1].getNum + let col = x[2].getNum + let dirty = x[3].getStr + result = x[0].getStr.escape + if dirty.len > 0: + result.add ';' + result.add dirty.escape + result.add ':' + result.add line + result.add ':' + result.add col + proc replEpc(x: ThreadParams) {.thread.} = var server = newSocket() let port = connectToNextFreePort(server, "localhost") @@ -320,9 +337,10 @@ proc replEpc(x: ThreadParams) {.thread.} = of ideSug, ideCon, ideDef, ideUse, ideDus, ideOutline, ideHighlight: setVerbosity(0) else: discard + let cmd = $gIdeCmd & " " & args.argsToStr if gLogging: - logStr "MSG ARG: " & args.getStr - requests.send($gIdeCmd & " " & args.getStr) + logStr "MSG CMD: " & cmd + requests.send(cmd) toEpc(client, uid) of "methods": returnEpc(client, message[1].getNum, listEpc()) diff --git a/tools/nimsuggest/tester.nim b/tools/nimsuggest/tester.nim index 4e12f329f4..c4542e089c 100644 --- a/tools/nimsuggest/tester.nim +++ b/tools/nimsuggest/tester.nim @@ -17,7 +17,7 @@ const template tpath(): untyped = getAppDir() / "tests" -proc parseTest(filename: string): Test = +proc parseTest(filename: string; epcMode=false): Test = const cursorMarker = "#[!]#" let nimsug = curDir & addFileExt("nimsuggest", ExeExt) result.dest = getTempDir() / extractFilename(filename) @@ -31,7 +31,10 @@ proc parseTest(filename: string): Test = for x in lines(filename): let marker = x.find(cursorMarker)+1 if marker > 0: - markers.add "\"" & filename & "\";\"" & result.dest & "\":" & $i & ":" & $marker + if epcMode: + markers.add "(\"" & filename & "\" " & $i & " " & $marker & " \"" & result.dest & "\")" + else: + markers.add "\"" & filename & "\";\"" & result.dest & "\":" & $i & ":" & $marker tmp.writeLine x.replace(cursorMarker, "") else: tmp.writeLine x @@ -136,9 +139,11 @@ proc smartCompare(pattern, x: string): bool = proc sendEpcStr(socket: Socket; cmd: string) = let s = cmd.find(' ') doAssert s > 0 - let cmd = "(call 567 " & cmd.substr(0, s) & escapeJson(cmd.substr(s+1)) & ")" - socket.send toHex(cmd.len, 6) - socket.send cmd + var args = cmd.substr(s+1) + if not args.startsWith("("): args = escapeJson(args) + let c = "(call 567 " & cmd.substr(0, s) & args & ")" + socket.send toHex(c.len, 6) + socket.send c proc recvEpc(socket: Socket): string = var L = newStringOfCap(6) @@ -216,7 +221,7 @@ proc doReport(filename, answer, resp: string; report: var string) = report.add "\n But got: " & answer proc runEpcTest(filename: string): int = - let s = parseTest filename + let s = parseTest(filename, true) for cmd in s.startup: if not runCmd(cmd, s.dest): quit "invalid command: " & cmd From 2ba374f9ab5f5ede0a4c67ab8339799108e3d720 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 21 Feb 2017 20:24:55 +0100 Subject: [PATCH 54/67] match json.toPretty style with NodeJS's stringify (#5406) --- lib/pure/json.nim | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 5e36a2aa1b..c7b581a856 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -952,7 +952,7 @@ proc newIndent(curr, indent: int, ml: bool): int = else: return indent proc nl(s: var string, ml: bool) = - if ml: s.add("\n") + s.add(if ml: "\n" else: " ") proc escapeJson*(s: string; result: var string) = ## Converts a string `s` to its JSON representation. @@ -986,15 +986,14 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, lstArr = false, currIndent = 0) = case node.kind of JObject: - if currIndent != 0 and not lstArr: result.nl(ml) - result.indent(currIndent) # Indentation + if lstArr: result.indent(currIndent) # Indentation if node.fields.len > 0: result.add("{") result.nl(ml) # New line var i = 0 for key, val in pairs(node.fields): if i > 0: - result.add(", ") + result.add(",") result.nl(ml) # New Line inc i # Need to indent more than { @@ -1030,7 +1029,7 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, result.nl(ml) for i in 0..len(node.elems)-1: if i > 0: - result.add(", ") + result.add(",") result.nl(ml) # New Line toPretty(result, node.elems[i], indent, ml, true, newIndent(currIndent, indent, ml)) From 311253ef2ffd63716ee69f4fd156462df26ae186 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 22 Feb 2017 16:27:24 +0100 Subject: [PATCH 55/67] nimsuggest: added --refresh command line option; added 'known' command; fixes 'chck' command for EPC --- compiler/options.nim | 4 +++- tools/nimsuggest/nimsuggest.nim | 40 ++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index 2295bbf931..97e142569f 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -100,7 +100,7 @@ type IdeCmd* = enum ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod, - ideHighlight, ideOutline + ideHighlight, ideOutline, ideKnown ConfigRef* = ref object ## eventually all global configuration should be moved here cppDefines*: HashSet[string] @@ -442,6 +442,7 @@ proc parseIdeCmd*(s: string): IdeCmd = of "mod": ideMod of "highlight": ideHighlight of "outline": ideOutline + of "known": ideKnown else: ideNone proc `$`*(c: IdeCmd): string = @@ -456,3 +457,4 @@ proc `$`*(c: IdeCmd): string = of ideNone: "none" of ideHighlight: "highlight" of ideOutline: "outline" + of ideKnown: "known" diff --git a/tools/nimsuggest/nimsuggest.nim b/tools/nimsuggest/nimsuggest.nim index db8b905415..f4d72b67e3 100644 --- a/tools/nimsuggest/nimsuggest.nim +++ b/tools/nimsuggest/nimsuggest.nim @@ -17,7 +17,7 @@ import compiler / [options, commands, modules, sem, passes, passaux, msgs, nimconf, extccomp, condsyms, lists, sigmatch, ast, scriptconfig, - idents, modulegraphs, compilerlog] + idents, modulegraphs, compilerlog, vm] when defined(windows): import winlean @@ -40,6 +40,7 @@ Options: --log enable verbose logging to nimsuggest.log file --v2 use version 2 of the protocol; more features and much faster + --refresh perform automatic refreshes to keep the analysis precise --tester implies --v2 and --stdin and outputs a line '""" & DummyEof & """' for the tester @@ -57,10 +58,11 @@ var gMode: Mode gEmitEof: bool # whether we write '!EOF!' dummy lines gLogging = false + gRefresh: bool const seps = {':', ';', ' ', '\t'} - Help = "usage: sug|con|def|use|dus|chk|mod|highlight|outline file.nim[;dirtyfile.nim]:line:col\n" & + Help = "usage: sug|con|def|use|dus|chk|mod|highlight|outline|known file.nim[;dirtyfile.nim]:line:col\n" & "type 'quit' to quit\n" & "type 'debug' to toggle debug mode on/off\n" & "type 'terse' to toggle terse mode on/off" @@ -144,7 +146,7 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int; gTrackPos = newLineInfo(dirtyIdx, line, col) gErrorCounter = 0 if suggestVersion < 2: - usageSym = nil + graph.usageSym = nil if not isKnownFile: graph.compileProject(cache) if suggestVersion == 2 and gIdeCmd in {ideUse, ideDus} and @@ -157,7 +159,7 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int; if gIdeCmd != ideMod: graph.compileProject(cache, modIdx) if gIdeCmd in {ideUse, ideDus}: - let u = if suggestVersion >= 2: graph.symFromInfo(gTrackPos) else: usageSym + let u = if suggestVersion >= 2: graph.symFromInfo(gTrackPos) else: graph.usageSym if u != nil: listUsages(u) else: @@ -212,6 +214,7 @@ proc toStdout() {.gcsafe.} = case res.section of ideNone: break of ideChk: echo res.doc + of ideKnown: echo res.quality == 1 else: echo res proc toSocket(stdoutSocket: Socket) {.gcsafe.} = @@ -220,6 +223,7 @@ proc toSocket(stdoutSocket: Socket) {.gcsafe.} = case res.section of ideNone: break of ideChk: stdoutSocket.send(res.doc & "\c\L") + of ideKnown: stdoutSocket.send($(res.quality == 1) & "\c\L") else: stdoutSocket.send($res & "\c\L") proc toEpc(client: Socket; uid: BiggestInt) {.gcsafe.} = @@ -229,11 +233,12 @@ proc toEpc(client: Socket; uid: BiggestInt) {.gcsafe.} = case res.section of ideNone: break of ideChk: - returnEpc(client, uid, sexp(res.doc)) + list.add sexp(res.doc) + of ideKnown: + list.add sexp(res.quality == 1) else: list.add sexp(res) - if gIdeCmd != ideChk: - returnEpc(client, uid, list) + returnEpc(client, uid, list) proc writelnToChannel(line: string) = results.send(Suggest(section: ideChk, doc: line)) @@ -391,6 +396,7 @@ proc execCmd(cmd: string; graph: ModuleGraph; cache: IdentCache) = of "quit": quit() of "debug": toggle optIdeDebug of "terse": toggle optIdeTerse + of "known": gIdeCmd = ideKnown else: err() var dirtyfile = "" var orig = "" @@ -404,14 +410,20 @@ proc execCmd(cmd: string; graph: ModuleGraph; cache: IdentCache) = i += skipWhile(cmd, seps, i) i += parseInt(cmd, col, i) - execute(gIdeCmd, orig, dirtyfile, line, col-1, graph, cache) + if gIdeCmd == ideKnown: + results.send(Suggest(section: ideKnown, quality: ord(fileInfoKnown(orig)))) + else: + execute(gIdeCmd, orig, dirtyfile, line, col-1, graph, cache) sentinel() proc recompileFullProject(graph: ModuleGraph; cache: IdentCache) = echo "recompiling full project" resetSystemArtifacts() + vm.globalCtx = nil graph.resetAllModules() + GC_fullcollect() compileProject(graph, cache) + echo "recompiled!" proc mainThread(graph: ModuleGraph; cache: IdentCache) = if gLogging: @@ -441,7 +453,7 @@ proc mainThread(graph: ModuleGraph; cache: IdentCache) = else: os.sleep 250 idle += 1 - if idle == 20 and false: + if idle == 20 and gRefresh: # we use some nimsuggest activity to enable a lazy recompile: gIdeCmd = ideChk msgs.writelnHook = proc (s: string) = discard @@ -609,16 +621,14 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) = of "epc": gMode = mepc gVerbosity = 0 # Port number gotta be first. - of "debug": - incl(gGlobalOptions, optIdeDebug) - of "v2": - suggestVersion = 2 + of "debug": incl(gGlobalOptions, optIdeDebug) + of "v2": suggestVersion = 2 of "tester": suggestVersion = 2 gMode = mstdin gEmitEof = true - of "log": - gLogging = true + of "log": gLogging = true + of "refresh": gRefresh = true else: processSwitch(pass, p) of cmdArgument: options.gProjectName = unixToNativePath(p.key) From 46efaf294bfc230d0259d89fd0fbd7f1418b7ac4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 22 Feb 2017 16:27:52 +0100 Subject: [PATCH 56/67] big compiler refactoring; avoid globals for multi method dispatcher generation --- compiler/cgen.nim | 4 +- compiler/cgmeth.nim | 50 ++++++------ compiler/docgen2.nim | 4 +- compiler/jsgen.nim | 8 +- compiler/lookups.nim | 2 +- compiler/modulegraphs.nim | 8 ++ compiler/msgs.nim | 9 +++ compiler/passaux.nim | 18 ----- compiler/passes.nim | 16 ++-- compiler/patterns.nim | 2 +- compiler/plugins/locals/locals.nim | 2 +- compiler/rodwrite.nim | 2 +- compiler/sem.nim | 18 ++--- compiler/semasgn.nim | 6 +- compiler/semcall.nim | 4 +- compiler/semdata.nim | 24 +++--- compiler/semdestruct.nim | 13 +-- compiler/semexprs.nim | 45 +++++------ compiler/semfields.nim | 2 +- compiler/seminst.nim | 6 +- compiler/semmagic.nim | 2 +- compiler/semstmts.nim | 125 +++++++++++++++-------------- compiler/semtempl.nim | 8 +- compiler/semtypes.nim | 16 ++-- compiler/sigmatch.nim | 6 +- compiler/suggest.nim | 18 ++--- compiler/transf.nim | 7 +- compiler/vm.nim | 5 +- tests/misc/parsecomb.nim | 10 +-- 29 files changed, 225 insertions(+), 215 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 63a7cda0e1..9db6b77740 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1366,7 +1366,7 @@ proc updateCachedModule(m: BModule) = cf.flags = {CfileFlag.Cached} addFileToCompile(cf) -proc myClose(b: PPassContext, n: PNode): PNode = +proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = result = n if b == nil or passes.skipCodegen(n): return var m = BModule(b) @@ -1378,7 +1378,7 @@ proc myClose(b: PPassContext, n: PNode): PNode = if sfMainModule in m.module.flags: incl m.flags, objHasKidsValid - var disp = generateMethodDispatchers() + var disp = generateMethodDispatchers(graph) for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym) genMainProc(m) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index eda80be30d..52fd8ab494 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -11,7 +11,7 @@ import intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys, - sempass2, strutils + sempass2, strutils, modulegraphs proc genConv(n: PNode, d: PType, downcast: bool): PNode = var dest = skipTypes(d, abstractPtrs) @@ -38,16 +38,18 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode = proc methodCall*(n: PNode): PNode = result = n # replace ordinary method by dispatcher method: - var disp = lastSon(result.sons[0].sym.ast).sym - assert sfDispatcher in disp.flags - result.sons[0].sym = disp - # change the arguments to up/downcasts to fit the dispatcher's parameters: - for i in countup(1, sonsLen(result)-1): - result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true) - -# save for incremental compilation: -var - gMethods: seq[tuple[methods: TSymSeq, dispatcher: PSym]] = @[] + let dispn = lastSon(result.sons[0].sym.ast) + if dispn.kind == nkSym: + let disp = dispn.sym + if sfDispatcher notin disp.flags: + localError(n.info, "'" & $result & "' lacks a dispatcher") + return + result.sons[0].sym = disp + # change the arguments to up/downcasts to fit the dispatcher's parameters: + for i in countup(1, sonsLen(result)-1): + result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true) + else: + localError(n.info, "'" & $result.sons[0] & "' lacks a dispatcher") type MethodResult = enum No, Invalid, Yes @@ -144,27 +146,27 @@ proc fixupDispatcher(meth, disp: PSym) = if disp.typ.lockLevel < meth.typ.lockLevel: disp.typ.lockLevel = meth.typ.lockLevel -proc methodDef*(s: PSym, fromCache: bool) = - let L = len(gMethods) +proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) = + let L = len(g.methods) var witness: PSym for i in countup(0, L - 1): - let disp = gMethods[i].dispatcher + let disp = g.methods[i].dispatcher case sameMethodBucket(disp, s) of Yes: - add(gMethods[i].methods, s) + add(g.methods[i].methods, s) attachDispatcher(s, lastSon(disp.ast)) fixupDispatcher(s, disp) #echo "fixup ", disp.name.s, " ", disp.id when useEffectSystem: checkMethodEffects(disp, s) - if sfBase in s.flags and gMethods[i].methods[0] != s: + if sfBase in s.flags and g.methods[i].methods[0] != s: # already exists due to forwarding definition? localError(s.info, "method is not a base") return of No: discard of Invalid: - if witness.isNil: witness = gMethods[i].methods[0] + if witness.isNil: witness = g.methods[i].methods[0] # create a new dispatcher: - add(gMethods, (methods: @[s], dispatcher: createDispatcher(s))) + add(g.methods, (methods: @[s], dispatcher: createDispatcher(s))) #echo "adding ", s.info #if fromCache: # internalError(s.info, "no method dispatcher found") @@ -258,12 +260,12 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym = disp = ret result.ast.sons[bodyPos] = disp -proc generateMethodDispatchers*(): PNode = +proc generateMethodDispatchers*(g: ModuleGraph): PNode = result = newNode(nkStmtList) - for bucket in countup(0, len(gMethods) - 1): + for bucket in countup(0, len(g.methods) - 1): var relevantCols = initIntSet() - for col in countup(1, sonsLen(gMethods[bucket].methods[0].typ) - 1): - if relevantCol(gMethods[bucket].methods, col): incl(relevantCols, col) - sortBucket(gMethods[bucket].methods, relevantCols) + for col in countup(1, sonsLen(g.methods[bucket].methods[0].typ) - 1): + if relevantCol(g.methods[bucket].methods, col): incl(relevantCols, col) + sortBucket(g.methods[bucket].methods, relevantCols) addSon(result, - newSymNode(genDispatcher(gMethods[bucket].methods, relevantCols))) + newSymNode(genDispatcher(g.methods[bucket].methods, relevantCols))) diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 9504ab52f4..118f1c7c53 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -33,11 +33,11 @@ template closeImpl(body: untyped) {.dirty.} = except IOError: discard -proc close(p: PPassContext, n: PNode): PNode = +proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = closeImpl: writeOutput(g.doc, g.module.filename, HtmlExt, useWarning) -proc closeJson(p: PPassContext, n: PNode): PNode = +proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = closeImpl: writeOutputJson(g.doc, g.module.filename, ".json", useWarning) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 29a72c86e3..b2d291d706 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2237,13 +2237,13 @@ proc myProcess(b: PPassContext, n: PNode): PNode = add(p.g.code, p.body) globals.unique = p.unique -proc wholeCode*(m: BModule): Rope = +proc wholeCode(graph: ModuleGraph; m: BModule): Rope = for prc in globals.forwarded: if not globals.generatedSyms.containsOrIncl(prc.id): var p = newProc(globals, m, nil, m.module.options) attachProc(p, prc) - var disp = generateMethodDispatchers() + var disp = generateMethodDispatchers(graph) for i in 0..sonsLen(disp)-1: let prc = disp.sons[i].sym if not globals.generatedSyms.containsOrIncl(prc.id): @@ -2277,7 +2277,7 @@ proc genClass(obj: PType; content: Rope; ext: string) = let outfile = changeFileExt(completeCFilePath($cls), ext) discard writeRopeIfNotEqual(result, outfile) -proc myClose(b: PPassContext, n: PNode): PNode = +proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = if passes.skipCodegen(n): return n result = myProcess(b, n) var m = BModule(b) @@ -2285,7 +2285,7 @@ proc myClose(b: PPassContext, n: PNode): PNode = let ext = if m.target == targetJS: "js" else: "php" let f = if globals.classes.len == 0: m.module.filename else: "nimsystem" - let code = wholeCode(m) + let code = wholeCode(graph, m) let outfile = if options.outFile.len > 0: if options.outFile.isAbsolute: options.outFile diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 19a4da07b7..089e69ff99 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -115,7 +115,7 @@ proc errorSym*(c: PContext, n: PNode): PSym = considerQuotedIdent(m) else: getIdent("err:" & renderTree(m)) - result = newSym(skError, ident, getCurrOwner(), n.info) + result = newSym(skError, ident, getCurrOwner(c), n.info) result.typ = errorType(c) incl(result.flags, sfDiscardable) # pretend it's imported from some unknown module to prevent cascading errors: diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index b86312209c..c081a099a3 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -41,6 +41,9 @@ type backend*: RootRef # minor hack so that a backend can extend this easily config*: ConfigRef doStopCompile*: proc(): bool {.closure.} + usageSym*: PSym # for nimsuggest + owners*: seq[PSym] + methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]] {.this: g.} @@ -58,6 +61,8 @@ proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph = result.config = newConfigRef() else: result.config = config + result.owners = @[] + result.methods = @[] proc resetAllModules*(g: ModuleGraph) = initStrTable(packageSyms) @@ -65,6 +70,9 @@ proc resetAllModules*(g: ModuleGraph) = modules = @[] importStack = @[] inclToMod = initTable[int32, int32]() + usageSym = nil + owners = @[] + methods = @[] proc getModule*(g: ModuleGraph; fileIdx: int32): PSym = if fileIdx >= 0 and fileIdx < modules.len: diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 49e4fa184a..a1ba82263a 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -567,6 +567,15 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo = if optEmbedOrigSrc in gGlobalOptions or true: result.lines = @[] +proc fileInfoKnown*(filename: string): bool = + var + canon: string + try: + canon = canonicalizePath(filename) + except: + canon = filename + result = filenameToIndexTbl.hasKey(canon) + proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 = var canon: string diff --git a/compiler/passaux.nim b/compiler/passaux.nim index eeaf129537..2065d58932 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -29,21 +29,3 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode = message(n.info, hintProcessing, $idgen.gFrontendId) const verbosePass* = makePass(open = verboseOpen, process = verboseProcess) - -proc cleanUp(c: PPassContext, n: PNode): PNode = - result = n - # we cannot clean up if dead code elimination is activated - if optDeadCodeElim in gGlobalOptions or n == nil: return - case n.kind - of nkStmtList: - for i in countup(0, sonsLen(n) - 1): discard cleanUp(c, n.sons[i]) - of nkProcDef, nkMethodDef: - if n.sons[namePos].kind == nkSym: - var s = n.sons[namePos].sym - if sfDeadCodeElim notin getModule(s).flags and not astNeeded(s): - s.ast.sons[bodyPos] = ast.emptyNode # free the memory - else: - discard - -const cleanupPass* = makePass(process = cleanUp, close = cleanUp) - diff --git a/compiler/passes.nim b/compiler/passes.nim index 783a7e13fc..abab599b6f 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -24,7 +24,7 @@ type TPassOpen* = proc (graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext {.nimcall.} TPassOpenCached* = proc (graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext {.nimcall.} - TPassClose* = proc (p: PPassContext, n: PNode): PNode {.nimcall.} + TPassClose* = proc (graph: ModuleGraph; p: PPassContext, n: PNode): PNode {.nimcall.} TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.} TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached, @@ -94,7 +94,7 @@ proc carryPass*(g: ModuleGraph; p: TPass, module: PSym; cache: IdentCache; m: TPassData): TPassData = var c = p.open(g, module, cache) result.input = p.process(c, m.input) - result.closeOutput = if p.close != nil: p.close(c, m.closeOutput) + result.closeOutput = if p.close != nil: p.close(g, c, m.closeOutput) else: m.closeOutput proc carryPasses*(g: ModuleGraph; nodes: PNode, module: PSym; @@ -121,10 +121,10 @@ proc openPassesCached(g: ModuleGraph; a: var TPassContextArray, module: PSym, else: a[i] = nil -proc closePasses(a: var TPassContextArray) = +proc closePasses(graph: ModuleGraph; a: var TPassContextArray) = var m: PNode = nil for i in countup(0, gPassesLen - 1): - if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m) + if not isNil(gPasses[i].close): m = gPasses[i].close(graph, a[i], m) a[i] = nil # free the memory here proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool = @@ -142,11 +142,11 @@ proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) = for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m) -proc closePassesCached(a: var TPassContextArray) = +proc closePassesCached(graph: ModuleGraph; a: var TPassContextArray) = var m: PNode = nil for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close): - m = gPasses[i].close(a[i], m) + m = gPasses[i].close(graph, a[i], m) a[i] = nil # free the memory here proc resolveMod(module, relativeTo: string): int32 = @@ -215,7 +215,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, elif not processTopLevelStmt(n, a): break closeParsers(p) if s.kind != llsStdIn: break - closePasses(a) + closePasses(graph, a) # id synchronization point for more consistent code generation: idSynchronizationPoint(1000) else: @@ -224,5 +224,5 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, for i in countup(0, sonsLen(n) - 1): if graph.stopCompile(): break processTopLevelStmtCached(n.sons[i], a) - closePassesCached(a) + closePassesCached(graph, a) result = true diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 09b8d33059..859fe2a818 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -289,7 +289,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode = # constraint not fulfilled: if not ok: return nil - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) if ctx.subMatch: assert m.len == 3 m.sons[1] = result diff --git a/compiler/plugins/locals/locals.nim b/compiler/plugins/locals/locals.nim index 8a3f67dd48..338e7bcac3 100644 --- a/compiler/plugins/locals/locals.nim +++ b/compiler/plugins/locals/locals.nim @@ -28,7 +28,7 @@ proc semLocals(c: PContext, n: PNode): PNode = it.typ.skipTypes({tyGenericInst, tyVar}).kind notin {tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}: - var field = newSym(skField, it.name, getCurrOwner(), n.info) + var field = newSym(skField, it.name, getCurrOwner(c), n.info) field.typ = it.typ.skipTypes({tyGenericInst, tyVar}) field.position = counter inc(counter) diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 4ce9e616ac..d61d817dd2 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -641,7 +641,7 @@ proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = rawAddInterfaceSym(w, module) result = w -proc myClose(c: PPassContext, n: PNode): PNode = +proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = result = process(c, n) var w = PRodWriter(c) writeRod(w) diff --git a/compiler/sem.nim b/compiler/sem.nim index fc7736b079..d73826965a 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -166,7 +166,7 @@ proc commonType*(x, y: PType): PType = result.addSonSkipIntLit(r) proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = - result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info) + result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii @@ -186,9 +186,9 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = # when there is a nested proc inside a template, semtmpl # will assign a wrong owner during the first pass over the # template; we must fix it here: see #909 - result.owner = getCurrOwner() + result.owner = getCurrOwner(c) else: - result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info) + result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule: # incl(result.flags, sfGlobal) @@ -376,7 +376,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, flags: TExprFlags = {}): PNode = pushInfoContext(nOrig.info) - markUsed(n.info, sym) + markUsed(n.info, sym, c.graph.usageSym) styleCheckUse(n.info, sym) if sym == c.p.owner: globalError(n.info, errRecursiveDependencyX, sym.name.s) @@ -434,7 +434,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = c.instTypeBoundOp = sigmatch.instTypeBoundOp pushProcCon(c, module) - pushOwner(c.module) + pushOwner(c, c.module) c.importTable = openScope(c) c.importTable.addSym(module) # a module knows itself if sfSystemModule in module.flags: @@ -450,7 +450,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext = result = myOpen(graph, module, rd.cache) - for m in items(rd.methods): methodDef(m, true) + for m in items(rd.methods): methodDef(graph, m, true) proc isImportSystemStmt(n: PNode): bool = if magicsys.systemModule == nil: return false @@ -502,7 +502,7 @@ proc recoverContext(c: PContext) = # faster than wrapping every stack operation in a 'try finally' block and # requires far less code. c.currentScope = c.topLevelScope - while getCurrOwner().kind != skModule: popOwner() + while getCurrOwner(c).kind != skModule: popOwner(c) while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next proc myProcess(context: PPassContext, n: PNode): PNode = @@ -523,7 +523,7 @@ proc myProcess(context: PPassContext, n: PNode): PNode = else: result = ast.emptyNode #if gCmd == cmdIdeTools: findSuggest(c, n) -proc myClose(context: PPassContext, n: PNode): PNode = +proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = var c = PContext(context) closeScope(c) # close module's scope rawCloseScope(c) # imported symbols; don't check for unused ones! @@ -533,7 +533,7 @@ proc myClose(context: PPassContext, n: PNode): PNode = addCodeForGenerics(c, result) if c.module.ast != nil: result.add(c.module.ast) - popOwner() + popOwner(c) popProcCon(c) const semPass* = makePass(myOpen, myOpenCached, myProcess, myClose) diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index c4dc136243..063157891c 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -105,7 +105,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = of attachedDestructor: let op = t.destructor if op != nil: - markUsed(c.info, op) + markUsed(c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add newDestructorCall(op, x) result = true @@ -123,14 +123,14 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = op = t.assignment if op == nil: op = liftBody(c.c, t, c.info) - markUsed(c.info, op) + markUsed(c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add newAsgnCall(c.c, op, x, y) result = true of attachedDeepCopy: let op = t.deepCopy if op != nil: - markUsed(c.info, op) + markUsed(c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add newDeepCopyCall(op, x, y) result = true diff --git a/compiler/semcall.nim b/compiler/semcall.nim index ae7bab89d4..fe73d60e6a 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -335,7 +335,7 @@ proc inferWithMetatype(c: PContext, formal: PType, proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = assert x.state == csMatch var finalCallee = x.calleeSym - markUsed(n.sons[0].info, finalCallee) + markUsed(n.sons[0].info, finalCallee, c.graph.usageSym) styleCheckUse(n.sons[0].info, finalCallee) assert finalCallee.ast != nil if x.hasFauxMatch: @@ -411,7 +411,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = let tm = typeRel(m, formal, arg, true) if tm in {isNone, isConvertible}: return nil var newInst = generateInstance(c, s, m.bindings, n.info) - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(newInst, n.info) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 77a530a150..93599f49fb 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -125,22 +125,20 @@ proc scopeDepth*(c: PContext): int {.inline.} = result = if c.currentScope != nil: c.currentScope.depthLevel else: 0 -var gOwners*: seq[PSym] = @[] - -proc getCurrOwner*(): PSym = +proc getCurrOwner*(c: PContext): PSym = # owner stack (used for initializing the # owner field of syms) # the documentation comment always gets # assigned to the current owner # BUGFIX: global array is needed! - result = gOwners[high(gOwners)] + result = c.graph.owners[^1] -proc pushOwner*(owner: PSym) = - add(gOwners, owner) +proc pushOwner*(c: PContext; owner: PSym) = + add(c.graph.owners, owner) -proc popOwner*() = - var length = len(gOwners) - if length > 0: setLen(gOwners, length - 1) +proc popOwner*(c: PContext) = + var length = len(c.graph.owners) + if length > 0: setLen(c.graph.owners, length - 1) else: internalError("popOwner") proc lastOptionEntry*(c: PContext): POptionEntry = @@ -226,7 +224,7 @@ proc addToLib*(lib: PLib, sym: PSym) = sym.annex = lib proc newTypeS*(kind: TTypeKind, c: PContext): PType = - result = newType(kind, getCurrOwner()) + result = newType(kind, getCurrOwner(c)) proc makePtrType*(c: PContext, baseType: PType): PType = result = newTypeS(tyPtr, c) @@ -245,7 +243,7 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType = proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = let typedesc = makeTypeDesc(c, typ) - let sym = newSym(skType, c.cache.idAnon, getCurrOwner(), info).linkTo(typedesc) + let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info).linkTo(typedesc) return newSymNode(sym, info) proc makeTypeFromExpr*(c: PContext, n: PNode): PType = @@ -255,7 +253,7 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType = proc newTypeWithSons*(c: PContext, kind: TTypeKind, sons: seq[PType]): PType = - result = newType(kind, getCurrOwner()) + result = newType(kind, getCurrOwner(c)) result.sons = sons proc makeStaticExpr*(c: PContext, n: PNode): PNode = @@ -326,7 +324,7 @@ proc errorNode*(c: PContext, n: PNode): PNode = proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) = dest.kind = kind - dest.owner = getCurrOwner() + dest.owner = getCurrOwner(c) dest.size = - 1 proc makeRangeType*(c: PContext; first, last: BiggestInt; diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim index a8873bbe2b..b09404b391 100644 --- a/compiler/semdestruct.nim +++ b/compiler/semdestruct.nim @@ -51,7 +51,7 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) = let destructableT = instantiateDestructor(c, t.sons[i]) if destructableT != nil: n.sons[bodyPos].addSon(newNode(nkCall, t.sym.info, @[ - useSym(destructableT.destructor), + useSym(destructableT.destructor, c.graph.usageSym), n.sons[paramsPos][1][0]])) proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode @@ -60,8 +60,8 @@ proc destroySym(c: PContext, field: PSym, holder: PNode): PNode = let destructableT = instantiateDestructor(c, field.typ) if destructableT != nil: result = newNode(nkCall, field.info, @[ - useSym(destructableT.destructor), - newNode(nkDotExpr, field.info, @[holder, useSym(field)])]) + useSym(destructableT.destructor, c.graph.usageSym), + newNode(nkDotExpr, field.info, @[holder, useSym(field, c.graph.usageSym)])]) proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode = var nonTrivialFields = 0 @@ -181,7 +181,8 @@ proc createDestructorCall(c: PContext, s: PSym): PNode = let destructableT = instantiateDestructor(c, varTyp) if destructableT != nil: let call = semStmt(c, newNode(nkCall, s.info, @[ - useSym(destructableT.destructor), useSym(s)])) + useSym(destructableT.destructor, c.graph.usageSym), + useSym(s, c.graph.usageSym)])) result = newNode(nkDefer, s.info, @[call]) proc insertDestructors(c: PContext, @@ -233,8 +234,8 @@ proc insertDestructors(c: PContext, tryStmt.addSon( newNode(nkFinally, info, @[ semStmt(c, newNode(nkCall, info, @[ - useSym(destructableT.destructor), - useSym(varId.sym)]))])) + useSym(destructableT.destructor, c.graph.usageSym), + useSym(varId.sym, c.graph.usageSym)]))])) result.outer = newNodeI(nkStmtList, info) varSection.sons.setLen(j+1) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 542d7b4e39..64787b82cf 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -12,10 +12,10 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, flags: TExprFlags = {}): PNode = - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) pushInfoContext(n.info) - result = evalTemplate(n, s, getCurrOwner(), efFromHlo in flags) + result = evalTemplate(n, s, getCurrOwner(c), efFromHlo in flags) if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags) popInfoContext() @@ -209,7 +209,7 @@ proc semConv(c: PContext, n: PNode): PNode = let it = op.sons[i] let status = checkConvertible(c, result.typ, it.typ) if status in {convOK, convNotNeedeed}: - markUsed(n.info, it.sym) + markUsed(n.info, it.sym, c.graph.usageSym) styleCheckUse(n.info, it.sym) markIndirect(c, it.sym) return it @@ -926,7 +926,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = let s = getGenSym(c, sym) case s.kind of skConst: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, @@ -950,20 +950,20 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = result = newSymNode(s, n.info) of skMacro: if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) else: result = semMacroExpr(c, n, n, s, flags) of skTemplate: if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) else: result = semTemplateExpr(c, n, s, flags) of skParam: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) if s.typ.kind == tyStatic and s.typ.n != nil: # XXX see the hack in sigmatch.nim ... @@ -985,7 +985,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if s.magic == mNimvm: localError(n.info, "illegal context for 'nimvm' magic") - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) # We cannot check for access to outer vars for example because it's still @@ -1003,7 +1003,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = n.typ = s.typ return n of skType: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) if s.typ.kind == tyStatic and s.typ.n != nil: return s.typ.n @@ -1025,7 +1025,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if f != nil and fieldVisible(c, f): # is the access to a public field or in the same module or in a friend? doAssert f == s - markUsed(n.info, f) + markUsed(n.info, f, c.graph.usageSym) styleCheckUse(n.info, f) result = newNodeIT(nkDotExpr, n.info, f.typ) result.add makeDeref(newSymNode(p.selfSym)) @@ -1038,11 +1038,11 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if ty.sons[0] == nil: break ty = skipTypes(ty.sons[0], skipPtrs) # old code, not sure if it's live code: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) else: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) @@ -1062,7 +1062,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = symChoice(c, n, s, scClosed) if result.kind == nkSym: result = semSym(c, n, s, flags) else: - markUsed(n.sons[1].info, s) + markUsed(n.sons[1].info, s, c.graph.usageSym) result = semSym(c, n, s, flags) styleCheckUse(n.sons[1].info, s) return @@ -1087,7 +1087,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = newSymNode(f) result.info = n.info result.typ = ty - markUsed(n.info, f) + markUsed(n.info, f, c.graph.usageSym) styleCheckUse(n.info, f) return of tyTypeParamsHolders: @@ -1120,7 +1120,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = if f != nil: if fieldVisible(c, f): # is the access to a public field or in the same module or in a friend? - markUsed(n.sons[1].info, f) + markUsed(n.sons[1].info, f, c.graph.usageSym) styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) # we now have the correct field @@ -1134,7 +1134,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = elif ty.kind == tyTuple and ty.n != nil: f = getSymFromList(ty.n, i) if f != nil: - markUsed(n.sons[1].info, f) + markUsed(n.sons[1].info, f, c.graph.usageSym) styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) @@ -1581,9 +1581,8 @@ proc getMagicSym(magic: TMagic): PSym = result = newSym(skProc, getIdent($magic), systemModule, gCodegenLineInfo) result.magic = magic -proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo, - owner = getCurrOwner()): PSym = - result = newSym(kind, c.cache.idAnon, owner, info) +proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym = + result = newSym(kind, c.cache.idAnon, getCurrOwner(c), info) result.flags = {sfGenSym} proc semExpandToAst(c: PContext, n: PNode): PNode = @@ -1592,7 +1591,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = if expandedSym.kind == skError: return n macroCall.sons[0] = newSymNode(expandedSym, macroCall.info) - markUsed(n.info, expandedSym) + markUsed(n.info, expandedSym, c.graph.usageSym) styleCheckUse(n.info, expandedSym) for i in countup(1, macroCall.len-1): @@ -1683,7 +1682,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # open a scope for temporary symbol inclusions: let oldScope = c.currentScope openScope(c) - let oldOwnerLen = len(gOwners) + let oldOwnerLen = len(c.graph.owners) let oldGenerics = c.generics let oldErrorOutputs = errorOutputs errorOutputs = {} @@ -1709,7 +1708,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = c.inGenericInst = oldInGenericInst c.p = oldProcCon msgs.setInfoContextLen(oldContextLen) - setLen(gOwners, oldOwnerLen) + setLen(c.graph.owners, oldOwnerLen) c.currentScope = oldScope errorOutputs = oldErrorOutputs msgs.gErrorCounter = oldErrorCount @@ -2108,7 +2107,7 @@ proc semBlock(c: PContext, n: PNode): PNode = if sfGenSym notin labl.flags: addDecl(c, labl) n.sons[0] = newSymNode(labl, n.sons[0].info) - suggestSym(n.sons[0].info, labl) + suggestSym(n.sons[0].info, labl, c.graph.usageSym) styleCheckDef(labl) n.sons[1] = semExpr(c, n.sons[1]) n.typ = n.sons[1].typ diff --git a/compiler/semfields.nim b/compiler/semfields.nim index 9d8cea862c..5ac1ad11a9 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -108,7 +108,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true") if trueSymbol == nil: localError(n.info, errSystemNeeds, "true") - trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info) + trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(c), n.info) trueSymbol.typ = getSysType(tyBool) result.sons[0] = newSymNode(trueSymbol, n.info) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index acaade4949..82d27cf100 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -61,7 +61,7 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses: continue let symKind = if q.typ.kind == tyStatic: skConst else: skType - var s = newSym(symKind, q.name, getCurrOwner(), q.info) + var s = newSym(symKind, q.name, getCurrOwner(c), q.info) s.flags = s.flags + {sfUsed, sfFromGeneric} var t = PType(idTableGet(pt, q.typ)) if t == nil: @@ -255,7 +255,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, incl(result.flags, sfFromGeneric) result.owner = fn result.ast = n - pushOwner(result) + pushOwner(c, result) openScope(c) let gp = n.sons[genericParamsPos] @@ -304,7 +304,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, popProcCon(c) popInfoContext() closeScope(c) # close scope for parameters - popOwner() + popOwner(c) c.currentScope = oldScope discard c.friendModules.pop() dec(c.instCounter) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index e72172c815..5eed1e7025 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -107,7 +107,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode = if t.sonsLen > 0: # This is either a type known to sem or a typedesc # param to a regular proc (again, known at instantiation) - result = evalTypeTrait(n[0], t, getCurrOwner()) + result = evalTypeTrait(n[0], t, getCurrOwner(c)) else: # a typedesc variable, pass unmodified to evals result = n diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 6a3793d737..0dfcdc0db5 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -35,7 +35,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = x.info = n.info incl(s.flags, sfUsed) n.sons[0] = x - suggestSym(x.info, s) + suggestSym(x.info, s, c.graph.usageSym) styleCheckUse(x.info, s) else: localError(n.info, errInvalidControlFlowX, s.name.s) @@ -366,11 +366,13 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = if isTopLevel(c): result = semIdentWithPragma(c, kind, n, {sfExported}) incl(result.flags, sfGlobal) + #if kind in {skVar, skLet}: + # echo "global variable here ", n.info, " ", result.name.s else: result = semIdentWithPragma(c, kind, n, {}) if result.owner.kind == skModule: incl(result.flags, sfGlobal) - suggestSym(n.info, result) + suggestSym(n.info, result, c.graph.usageSym) styleCheckDef(result) proc checkNilable(v: PSym) = @@ -621,7 +623,7 @@ proc semForVars(c: PContext, n: PNode): PNode = if iter.kind != tyTuple or length == 3: if length == 3: var v = symForVar(c, n.sons[0]) - if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal) + if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal) # BUGFIX: don't use `iter` here as that would strip away # the ``tyGenericInst``! See ``tests/compile/tgeneric.nim`` # for an example: @@ -635,7 +637,7 @@ proc semForVars(c: PContext, n: PNode): PNode = else: for i in countup(0, length - 3): var v = symForVar(c, n.sons[i]) - if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal) + if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal) v.typ = iter.sons[i] n.sons[i] = newSymNode(v) if sfGenSym notin v.flags and not isDiscardUnderscore(v): @@ -745,7 +747,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = # We have a generic type declaration here. In generic types, # symbol lookup needs to be done here. openScope(c) - pushOwner(s) + pushOwner(c, s) if s.magic == mNone: s.typ.kind = tyGenericBody # XXX for generic type aliases this is not correct! We need the # underlying Id really: @@ -769,11 +771,11 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = body.sym = s body.size = -1 # could not be computed properly s.typ.sons[sonsLen(s.typ) - 1] = body - popOwner() + popOwner(c) closeScope(c) elif a.sons[2].kind != nkEmpty: # process the type's body: - pushOwner(s) + pushOwner(c, s) var t = semTypeNode(c, a.sons[2], s.typ) if s.typ == nil: s.typ = t @@ -782,7 +784,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = assignType(s.typ, t) #debug s.typ s.ast = a - popOwner() + popOwner(c) let aa = a.sons[2] if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and aa.sons[0].kind == nkObjectTy: @@ -793,7 +795,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = internalAssert st.lastSon.sym == nil incl st.flags, tfRefsAnonObj let obj = newSym(skType, getIdent(s.name.s & ":ObjectType"), - getCurrOwner(), s.info) + getCurrOwner(c), s.info) obj.typ = st.lastSon st.lastSon.sym = obj @@ -927,7 +929,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) = proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) = if t != nil: - var s = newSym(skResult, getIdent"result", getCurrOwner(), info) + var s = newSym(skResult, getIdent"result", getCurrOwner(c), info) s.typ = t incl(s.flags, sfUsed) addParamOrResult(c, s, owner) @@ -1002,12 +1004,12 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = checkSonsLen(n, bodyPos + 1) var s: PSym if n[namePos].kind != nkSym: - s = newSym(skProc, c.cache.idAnon, getCurrOwner(), n.info) + s = newSym(skProc, c.cache.idAnon, getCurrOwner(c), n.info) s.ast = n n.sons[namePos] = newSymNode(s) else: s = n[namePos].sym - pushOwner(s) + pushOwner(c, s) openScope(c) var gp: PNode if n.sons[genericParamsPos].kind != nkEmpty: @@ -1047,7 +1049,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = else: localError(n.info, errImplOfXexpected, s.name.s) closeScope(c) # close scope for parameters - popOwner() + popOwner(c) result.typ = s.typ proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode = @@ -1081,7 +1083,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = params[i].sym.name.s) #params[i].sym.owner = s openScope(c) - pushOwner(s) + pushOwner(c, s) addParams(c, params, skProc) pushProcCon(c, s) addResult(c, n.typ.sons[0], n.info, skProc) @@ -1089,7 +1091,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) n.sons[bodyPos] = transformBody(c.module, semBody, s) popProcCon(c) - popOwner() + popOwner(c) closeScope(c) # alternative variant (not quite working): @@ -1193,6 +1195,42 @@ type import compilerlog +proc hasObjParam(s: PSym): bool = + var t = s.typ + for col in countup(1, sonsLen(t)-1): + if skipTypes(t.sons[col], skipPtrs).kind == tyObject: + return true + +proc finishMethod(c: PContext, s: PSym) = + if hasObjParam(s): + methodDef(c.graph, s, false) + +proc semMethodPrototype(c: PContext; s: PSym; n: PNode) = + if isGenericRoutine(s): + let tt = s.typ + var foundObj = false + # we start at 1 for now so that tparsecombnum continues to compile. + # XXX Revisit this problem later. + for col in countup(1, sonsLen(tt)-1): + let t = tt.sons[col] + if t != nil and t.kind == tyGenericInvocation: + var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst, + tyGenericInvocation, tyGenericBody, + tyAlias}) + if x.kind == tyObject and t.len-1 == n.sons[genericParamsPos].len: + foundObj = true + x.methods.safeAdd((col,s)) + if not foundObj: + message(n.info, warnDeprecated, "generic method not attachable to object type") + else: + # why check for the body? bug #2400 has none. Checking for sfForward makes + # no sense either. + # and result.sons[bodyPos].kind != nkEmpty: + if hasObjParam(s): + methodDef(c.graph, s, fromCache=false) + else: + localError(n.info, errXNeedsParamObjectType, "method") + proc semProcAux(c: PContext, n: PNode, kind: TSymKind, validPragmas: TSpecialWords, phase = stepRegisterSymbol): PNode = @@ -1207,7 +1245,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, assert phase == stepRegisterSymbol if n[namePos].kind == nkEmpty: - s = newSym(kind, c.cache.idAnon, getCurrOwner(), n.info) + s = newSym(kind, c.cache.idAnon, getCurrOwner(c), n.info) incl(s.flags, sfUsed) isAnon = true else: @@ -1224,7 +1262,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, return else: s = n[namePos].sym - s.owner = getCurrOwner() + s.owner = getCurrOwner(c) typeIsDetermined = s.typ == nil s.ast = n #s.scope = c.currentScope @@ -1233,7 +1271,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # where the proc was declared let oldScope = c.currentScope #c.currentScope = s.scope - pushOwner(s) + pushOwner(c, s) openScope(c) var gp: PNode if n.sons[genericParamsPos].kind != nkEmpty: @@ -1299,8 +1337,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if importantComments() and not isNil(proto.ast.comment): n.comment = proto.ast.comment proto.ast = n # needed for code generation - popOwner() - pushOwner(s) + popOwner(c) + pushOwner(c, s) s.options = gOptions if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) if s.name.s[0] in {'.', '('}: @@ -1317,6 +1355,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if not usePseudoGenerics and gIdeCmd in {ideSug, ideCon} and not cursorInProc(n.sons[bodyPos]): discard "speed up nimsuggest" + if s.kind == skMethod: semMethodPrototype(c, s, n) else: pushProcCon(c, s) if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics: @@ -1324,6 +1363,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, c.p.wasForwarded = proto != nil maybeAddResult(c, s, n) + if s.kind == skMethod: semMethodPrototype(c, s, n) + if lfDynamicLib notin s.loc.flags: # no semantic checking for importc: let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) @@ -1333,15 +1374,18 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, else: if s.typ.sons[0] != nil and kind != skIterator: addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info)) + openScope(c) n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos]) closeScope(c) fixupInstantiatedSymbols(c, s) + if s.kind == skMethod: semMethodPrototype(c, s, n) if sfImportc in s.flags: # so we just ignore the body after semantic checking for importc: n.sons[bodyPos] = ast.emptyNode popProcCon(c) else: + if s.kind == skMethod: semMethodPrototype(c, s, n) if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s) if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone: incl(s.flags, sfForward) @@ -1349,7 +1393,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, sideEffectsCheck(c, s) closeScope(c) # close scope for parameters # c.currentScope = oldScope - popOwner() + popOwner(c) if n.sons[patternPos].kind != nkEmpty: c.patterns.add(s) if isAnon: result.typ = s.typ @@ -1368,7 +1412,7 @@ proc semIterator(c: PContext, n: PNode): PNode = let isAnon = n[namePos].kind == nkEmpty if n[namePos].kind == nkSym: # gensym'ed iterators might need to become closure iterators: - n[namePos].sym.owner = getCurrOwner() + n[namePos].sym.owner = getCurrOwner(c) n[namePos].sym.kind = skIterator result = semProcAux(c, n, skIterator, iteratorPragmas) var s = result.sons[namePos].sym @@ -1395,46 +1439,9 @@ proc semIterator(c: PContext, n: PNode): PNode = proc semProc(c: PContext, n: PNode): PNode = result = semProcAux(c, n, skProc, procPragmas) -proc hasObjParam(s: PSym): bool = - var t = s.typ - for col in countup(1, sonsLen(t)-1): - if skipTypes(t.sons[col], skipPtrs).kind == tyObject: - return true - -proc finishMethod(c: PContext, s: PSym) = - if hasObjParam(s): - methodDef(s, false) - proc semMethod(c: PContext, n: PNode): PNode = if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method") result = semProcAux(c, n, skMethod, methodPragmas) - # macros can transform methods to nothing: - if namePos >= result.safeLen: return result - var s = result.sons[namePos].sym - if isGenericRoutine(s): - let tt = s.typ - var foundObj = false - # we start at 1 for now so that tparsecombnum continues to compile. - # XXX Revisit this problem later. - for col in countup(1, sonsLen(tt)-1): - let t = tt.sons[col] - if t != nil and t.kind == tyGenericInvocation: - var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst, - tyGenericInvocation, tyGenericBody, - tyAlias}) - if x.kind == tyObject and t.len-1 == result.sons[genericParamsPos].len: - foundObj = true - x.methods.safeAdd((col,s)) - if not foundObj: - message(n.info, warnDeprecated, "generic method not attachable to object type") - else: - # why check for the body? bug #2400 has none. Checking for sfForward makes - # no sense either. - # and result.sons[bodyPos].kind != nkEmpty: - if hasObjParam(s): - methodDef(s, fromCache=false) - else: - localError(n.info, errXNeedsParamObjectType, "method") proc semConverterDef(c: PContext, n: PNode): PNode = if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter") diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 8819f17cc1..843bef1a8d 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -60,7 +60,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode = # (s.kind notin routineKinds or s.magic != mNone): # for instance 'nextTry' is both in tables.nim and astalgo.nim ... result = newSymNode(s, n.info) - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) else: # semantic checking requires a type; ``fitNode`` deals with it # appropriately @@ -559,7 +559,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = styleCheckDef(s) # check parameter list: #s.scope = c.currentScope - pushOwner(s) + pushOwner(c, s) openScope(c) n.sons[namePos] = newSymNode(s, n.sons[namePos].info) if n.sons[pragmasPos].kind != nkEmpty: @@ -613,7 +613,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = # only parameters are resolved, no type checking is performed semIdeForTemplateOrGeneric(c, n.sons[bodyPos], ctx.cursorInBody) closeScope(c) - popOwner() + popOwner(c) s.ast = n result = n if n.sons[bodyPos].kind == nkEmpty: @@ -758,7 +758,7 @@ proc semPattern(c: PContext, n: PNode): PNode = ctx.toMixin = initIntSet() ctx.toInject = initIntSet() ctx.c = c - ctx.owner = getCurrOwner() + ctx.owner = getCurrOwner(c) result = flattenStmts(semPatternBody(ctx, n)) if result.kind in {nkStmtList, nkStmtListExpr}: if result.len == 1: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 440edd226f..97af2c5cc3 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -306,7 +306,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = else: result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) if result != nil: - markUsed(n.info, result) + markUsed(n.info, result, c.graph.usageSym) styleCheckUse(n.info, result) if result.kind == skParam and result.typ.kind == tyTypeDesc: # This is a typedesc param. is it already bound? @@ -608,7 +608,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, let rec = rectype.sym for i in countup(0, sonsLen(n)-3): var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported}) - suggestSym(n.sons[i].info, f) + suggestSym(n.sons[i].info, f, c.graph.usageSym) f.typ = typ f.position = pos if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and @@ -750,7 +750,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, return genericParams.sons[i].typ let owner = if typeClass.sym != nil: typeClass.sym - else: getCurrOwner() + else: getCurrOwner(c) var s = newSym(skType, finalTypId, owner, info) if typId == nil: s.flags.incl(sfAnon) s.linkTo(typeClass) @@ -850,7 +850,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, of tyGenericInst: if paramType.lastSon.kind == tyUserTypeClass: - var cp = copyType(paramType, getCurrOwner(), false) + var cp = copyType(paramType, getCurrOwner(c), false) cp.kind = tyUserTypeClassInst return addImplicitGeneric(cp) @@ -876,10 +876,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, result = liftingWalk(expanded, true) of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: - result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true)) + result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), true)) of tyGenericParam: - markUsed(info, paramType.sym) + markUsed(info, paramType.sym, c.graph.usageSym) styleCheckUse(info, paramType.sym) if tfWildcard in paramType.flags: paramType.flags.excl tfWildcard @@ -1267,7 +1267,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of mExpr: result = semTypeNode(c, n.sons[0], nil) if result != nil: - result = copyType(result, getCurrOwner(), false) + result = copyType(result, getCurrOwner(c), false) for i in countup(1, n.len - 1): result.rawAddSon(semTypeNode(c, n.sons[i], nil)) of mDistinct: @@ -1330,7 +1330,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = else: assignType(prev, t) result = prev - markUsed(n.info, n.sym) + markUsed(n.info, n.sym, c.graph.usageSym) styleCheckUse(n.info, n.sym) else: if s.kind != skError: localError(n.info, errTypeExpected) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 117b66cd8f..f2caab41f0 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -73,7 +73,7 @@ type const isNilConversion = isConvertible # maybe 'isIntConv' fits better? -proc markUsed*(info: TLineInfo, s: PSym) +proc markUsed*(info: TLineInfo, s: PSym; usageSym: var PSym) template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone @@ -1291,7 +1291,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, dest = generateTypeInstance(c, m.bindings, arg, dest) let fdest = typeRel(m, f, dest) if fdest in {isEqual, isGeneric}: - markUsed(arg.info, c.converters[i]) + markUsed(arg.info, c.converters[i], c.graph.usageSym) var s = newSymNode(c.converters[i]) s.typ = c.converters[i].typ s.info = arg.info @@ -1551,7 +1551,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, else: result = nil else: # only one valid interpretation found: - markUsed(arg.info, arg.sons[best].sym) + markUsed(arg.info, arg.sons[best].sym, m.c.graph.usageSym) styleCheckUse(arg.info, arg.sons[best].sym) result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best], argOrig) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index c228d1fa8d..9ae427583a 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -353,10 +353,10 @@ when defined(nimsuggest): s.allUsages.add(info) var - usageSym*: PSym + #usageSym*: PSym lastLineInfo*: TLineInfo -proc findUsages(info: TLineInfo; s: PSym) = +proc findUsages(info: TLineInfo; s: PSym; usageSym: var PSym) = if suggestVersion < 2: if usageSym == nil and isTracked(info, s.name.s.len): usageSym = s @@ -385,7 +385,7 @@ proc ensureIdx[T](x: var T, y: int) = proc ensureSeq[T](x: var seq[T]) = if x == nil: newSeq(x, 0) -proc suggestSym*(info: TLineInfo; s: PSym; isDecl=true) {.inline.} = +proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} = ## misnamed: should be 'symDeclared' when defined(nimsuggest): if suggestVersion == 2: @@ -395,20 +395,20 @@ proc suggestSym*(info: TLineInfo; s: PSym; isDecl=true) {.inline.} = s.addNoDup(info) if gIdeCmd == ideUse: - findUsages(info, s) + findUsages(info, s, usageSym) elif gIdeCmd == ideDef: findDefinition(info, s) elif gIdeCmd == ideDus and s != nil: if isTracked(info, s.name.s.len): suggestResult(symToSuggest(s, isLocal=false, $ideDef, 100)) - findUsages(info, s) + findUsages(info, s, usageSym) elif gIdeCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex: suggestResult(symToSuggest(s, isLocal=false, $ideHighlight, info, 100)) elif gIdeCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and isDecl: suggestResult(symToSuggest(s, isLocal=false, $ideOutline, info, 100)) -proc markUsed(info: TLineInfo; s: PSym) = +proc markUsed(info: TLineInfo; s: PSym; usageSym: var PSym) = incl(s.flags, sfUsed) if s.kind == skEnumField and s.owner != nil: incl(s.owner.flags, sfUsed) @@ -416,11 +416,11 @@ proc markUsed(info: TLineInfo; s: PSym) = if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s) if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s) when defined(nimsuggest): - suggestSym(info, s, false) + suggestSym(info, s, usageSym, false) -proc useSym*(sym: PSym): PNode = +proc useSym*(sym: PSym; usageSym: var PSym): PNode = result = newSymNode(sym) - markUsed(result.info, sym) + markUsed(result.info, sym, usageSym) proc safeSemExpr*(c: PContext, n: PNode): PNode = # use only for idetools support! diff --git a/compiler/transf.nim b/compiler/transf.nim index 2103d48bf9..98e221b56a 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -694,9 +694,10 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = # bugfix: check after 'transformSons' if it's still a method call: # use the dispatcher for the call: if s.sons[0].kind == nkSym and s.sons[0].sym.kind == skMethod: - let t = lastSon(s.sons[0].sym.ast) - if t.kind != nkSym or sfDispatcher notin t.sym.flags: - methodDef(s.sons[0].sym, false) + when false: + let t = lastSon(s.sons[0].sym.ast) + if t.kind != nkSym or sfDispatcher notin t.sym.flags: + methodDef(s.sons[0].sym, false) result = methodCall(s).PTransNode else: result = s.PTransNode diff --git a/compiler/vm.nim b/compiler/vm.nim index 5d47842813..6a9545193e 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1556,7 +1556,10 @@ proc myProcess(c: PPassContext, n: PNode): PNode = result = n oldErrorCount = msgs.gErrorCounter -const evalPass* = makePass(myOpen, nil, myProcess, myProcess) +proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = + myProcess(c, n) + +const evalPass* = makePass(myOpen, nil, myProcess, myClose) proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode, mode: TEvalMode): PNode = diff --git a/tests/misc/parsecomb.nim b/tests/misc/parsecomb.nim index 05fe97ad16..4ff2f65d22 100644 --- a/tests/misc/parsecomb.nim +++ b/tests/misc/parsecomb.nim @@ -29,10 +29,10 @@ method runInput[T, O](self: Parser[T, O], inp: Input[T]): Result[T, O] = # XXX: above needed for now, as without the `tmp` bit below, it compiles to invalid C. tmp(self)(inp) -method run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] = +proc run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] = self.runInput(Input[T](toks: toks, index: 0)) -method chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] = +proc chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] = result = proc (inp: Input[T]): Result[T, O2] = let r = self.runInput(inp) case r.kind: @@ -41,7 +41,7 @@ method chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2] of rkFailure: Result[T, O2](kind: rkFailure) -method skip[T](self: Input[T], n: int): Input[T] = +method skip[T](self: Input[T], n: int): Input[T] {.base.} = Input[T](toks: self.toks, index: self.index + n) proc pskip*[T](n: int): Parser[T, tuple[]] = @@ -69,11 +69,11 @@ proc `+`*[T, O](first: Parser[T, O], second: Parser[T, O]): Parser[T, O] = # end of primitives (definitions involving Parser(..)) -method map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] = +proc map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] = self.chain(proc (v: O1): Parser[T, O2] = unit[T, O2](p(v))) -method then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] = +proc then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] = self.chain(proc (v: O1): Parser[T, O2] = next) From 92c2a51bf763c16579da6b9e2ceaede5552bf5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Wed, 22 Feb 2017 17:33:12 +0100 Subject: [PATCH 57/67] removed compiler internal list implementation (#5371) --- compiler/ast.nim | 6 +- compiler/ccgexprs.nim | 2 +- compiler/ccgstmts.nim | 2 +- compiler/ccgutils.nim | 2 +- compiler/cgen.nim | 28 ++++---- compiler/cgendata.nim | 10 ++- compiler/commands.nim | 14 ++-- compiler/extccomp.nim | 37 ++++------ compiler/jsgen.nim | 2 +- compiler/lambdalifting.nim | 2 +- compiler/lists.nim | 117 ++++---------------------------- compiler/main.nim | 8 +-- compiler/nimblecmd.nim | 8 +-- compiler/nimeval.nim | 4 +- compiler/nimfix/nimfix.nim | 6 +- compiler/options.nim | 28 +++----- compiler/passes.nim | 2 +- compiler/pragmas.nim | 35 +++++----- compiler/renderer.nim | 2 +- compiler/scriptconfig.nim | 4 +- compiler/sem.nim | 2 +- compiler/semdata.nim | 19 +++--- compiler/semfold.nim | 2 +- compiler/transf.nim | 2 +- tools/nimsuggest/nimsuggest.nim | 8 +-- 25 files changed, 125 insertions(+), 227 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 4ea68dc996..66fbe577ca 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -10,7 +10,7 @@ # abstract syntax tree + symbol table import - msgs, hashes, nversion, options, strutils, securehash, ropes, idents, lists, + msgs, hashes, nversion, options, strutils, securehash, ropes, idents, intsets, idgen type @@ -736,13 +736,15 @@ type TLibKind* = enum libHeader, libDynamic - TLib* = object of lists.TListEntry # also misused for headers! + + TLib* = object # also misused for headers! kind*: TLibKind generated*: bool # needed for the backends: isOverriden*: bool name*: Rope path*: PNode # can be a string literal! + CompilesId* = int ## id that is used for the caching logic within ## ``system.compiles``. See the seminst module. TInstantiation* = object diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 6f7e83c186..e9c78b48bf 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -944,7 +944,7 @@ proc genEcho(p: BProc, n: PNode) = # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)`` # is threadsafe. internalAssert n.kind == nkBracket - discard lists.includeStr(p.module.headerFiles, "") + p.module.includeHeader("") var args: Rope = nil var a: TLoc for i in countup(0, n.len-1): diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 02119d63e1..e4f13c70b2 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -884,7 +884,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = # if not isEmptyType(t.typ) and d.k == locNone: getTemp(p, t.typ, d) - discard lists.includeStr(p.module.headerFiles, "") + p.module.includeHeader("") genLineDir(p, t) var safePoint = getTempName(p.module) if getCompilerProc("Exception") != nil: diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index d42f0438ff..a00ce35056 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -10,7 +10,7 @@ # This module declares some helpers for the C code generator. import - ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg, + ast, astalgo, ropes, hashes, strutils, types, msgs, wordrecg, platform, trees proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode = diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 63a7cda0e1..04f62d66fd 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -11,7 +11,7 @@ import ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets, - nversion, nimsets, msgs, securehash, bitsets, idents, lists, types, + nversion, nimsets, msgs, securehash, bitsets, idents, types, ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings, semparallel, tables, sets, ndi @@ -75,12 +75,13 @@ proc isSimpleConst(typ: PType): bool = proc useStringh(m: BModule) = if includesStringh notin m.flags: incl m.flags, includesStringh - discard lists.includeStr(m.headerFiles, "") + m.includeHeader("") proc useHeader(m: BModule, sym: PSym) = if lfHeader in sym.loc.flags: assert(sym.annex != nil) - discard lists.includeStr(m.headerFiles, getStr(sym.annex.path)) + let str = getStr(sym.annex.path) + m.includeHeader(str) proc cgsym(m: BModule, name: string): Rope @@ -594,15 +595,14 @@ proc cgsym(m: BModule, name: string): Rope = proc generateHeaders(m: BModule) = add(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl) - var it = PStrEntry(m.headerFiles.head) - while it != nil: - if it.data[0] == '#': - add(m.s[cfsHeaders], rope(it.data.replace('`', '"') & tnl)) - elif it.data[0] notin {'\"', '<'}: - addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it.data)]) + + for it in m.headerFiles: + if it[0] == '#': + add(m.s[cfsHeaders], rope(it.replace('`', '"') & tnl)) + elif it[0] notin {'\"', '<'}: + addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)]) else: - addf(m.s[cfsHeaders], "#include $1$N", [rope(it.data)]) - it = PStrEntry(it.next) + addf(m.s[cfsHeaders], "#include $1$N", [rope(it)]) add(m.s[cfsHeaders], "#undef linux" & tnl) proc initFrame(p: BProc, procname, filename: Rope): Rope = @@ -974,7 +974,7 @@ proc genMainProc(m: BModule) = else: nimMain = WinNimDllMain otherMain = WinCDllMain - discard lists.includeStr(m.headerFiles, "") + m.includeHeader("") elif optGenDynLib in gGlobalOptions: nimMain = PosixNimDllMain otherMain = PosixCDllMain @@ -1129,7 +1129,7 @@ proc initProcOptions(m: BModule): TOptions = proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule = new(result) result.tmpBase = rope("TM" & $hashOwner(module) & "_") - initLinkedList(result.headerFiles) + result.headerFiles = @[] result.declaredThings = initIntSet() result.declaredProtos = initIntSet() result.cfilename = filename @@ -1166,7 +1166,7 @@ proc nullify[T](arr: var T) = proc resetModule*(m: BModule) = # between two compilations in CAAS mode, we can throw # away all the data that was written to disk - initLinkedList(m.headerFiles) + m.headerFiles = @[] m.declaredProtos = initIntSet() m.forwTypeCache = initTable[SigHash, Rope]() m.initProc = newProc(nil, m) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 565399ead9..be087095f5 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -10,7 +10,7 @@ ## This module contains the data structures for the C code generation phase. import - ast, astalgo, ropes, passes, options, intsets, lists, platform, sighashes, + ast, astalgo, ropes, passes, options, intsets, platform, sighashes, tables, ndi from msgs import TLineInfo @@ -130,7 +130,7 @@ type forwTypeCache*: TypeCache # cache for forward declarations of types declaredThings*: IntSet # things we have declared in this .c file declaredProtos*: IntSet # prototypes we have declared in this .c file - headerFiles*: TLinkedList # needed headers to include + headerFiles*: seq[string] # needed headers to include typeInfoMarker*: TypeCache # needed for generating type information initProc*: BProc # code for init procedure postInitProc*: BProc # code to be executed after the init proc @@ -148,9 +148,13 @@ type g*: BModuleList ndi*: NdiFile +proc includeHeader*(this: BModule; header: string) = + if not this.headerFiles.contains header: + this.headerFiles.add header + proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} = # section in the current block - result = p.blocks[p.blocks.len - 1].sections[s] + result = p.blocks[^1].sections[s] proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} = # top level proc sections diff --git a/compiler/commands.nim b/compiler/commands.nim index 74503a414e..b75e953dea 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -26,8 +26,8 @@ bootSwitch(usedGoGC, defined(gogc), "--gc:go") bootSwitch(usedNoGC, defined(nogc), "--gc:none") import - os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, - wordrecg, parseutils, nimblecmd, idents, parseopt + os, msgs, options, nversion, condsyms, strutils, extccomp, platform, + wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") @@ -335,12 +335,14 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "excludepath": expectArg(switch, arg, pass, info) let path = processPath(arg, info) - lists.excludePath(options.searchPaths, path) - lists.excludePath(options.lazyPaths, path) + + options.searchPaths.keepItIf( cmpPaths(it, path) != 0 ) + options.lazyPaths.keepItIf( cmpPaths(it, path) != 0 ) + if (len(path) > 0) and (path[len(path) - 1] == DirSep): let strippedPath = path[0 .. (len(path) - 2)] - lists.excludePath(options.searchPaths, strippedPath) - lists.excludePath(options.lazyPaths, strippedPath) + options.searchPaths.keepItIf( cmpPaths(it, strippedPath) != 0 ) + options.lazyPaths.keepItIf( cmpPaths(it, strippedPath) != 0 ) of "nimcache": expectArg(switch, arg, pass, info) options.nimcacheDir = processPath(arg, info, true) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 1b068385af..dab643d50f 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -13,7 +13,7 @@ # nim files. import - lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, + ropes, os, strutils, osproc, platform, condsyms, options, msgs, securehash, streams #from debuginfo import writeDebugInfo @@ -390,8 +390,8 @@ type CfileList = seq[Cfile] var - externalToLink: TLinkedList # files to link in addition to the file - # we compiled + externalToLink: seq[string] = @[] # files to link in addition to the file + # we compiled linkOptionsCmd: string = "" compileOptionsCmd: seq[string] = @[] linkOptions: string = "" @@ -486,11 +486,10 @@ proc resetCompilationLists* = # when the module is loaded/unloaded it adds/removes its items # That's because we still need to hash check the external files # Maybe we can do that in checkDep on the other hand? - initLinkedList(externalToLink) + externalToLink.setLen 0 proc addExternalFileToLink*(filename: string) = - prependStr(externalToLink, filename) - # BUGFIX: was ``appendStr`` + externalToLink.insert(filename, 0) proc execWithEcho(cmd: string, msg = hintExecuting): int = rawMessage(msg, cmd) @@ -527,9 +526,6 @@ proc noAbsolutePaths: bool {.inline.} = # `optGenMapping` is included here for niminst. result = gGlobalOptions * {optGenScript, optGenMapping} != {} -proc add(s: var string, many: openArray[string]) = - s.add many.join - proc cFileSpecificOptions(cfilename: string): string = result = compileOptions for option in compileOptionsCmd: @@ -560,7 +556,7 @@ proc getLinkOptions: string = for linkedLib in items(cLinkedLibs): result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell) for libDir in items(cLibs): - result.add([CC[cCompiler].linkDirCmd, libDir.quoteShell]) + result.add(join([CC[cCompiler].linkDirCmd, libDir.quoteShell])) proc needsExeExt(): bool {.inline.} = result = (optGenScript in gGlobalOptions and targetOS == osWindows) or @@ -611,7 +607,7 @@ proc getCompileCFileCmd*(cfile: Cfile): string = includeCmd = CC[c].includeCmd & quoteShell(libpath) for includeDir in items(cIncludes): - includeCmd.add([CC[c].includeCmd, includeDir.quoteShell]) + includeCmd.add(join([CC[c].includeCmd, includeDir.quoteShell])) compilePattern = joinPath(ccompilerpath, exe) else: @@ -786,14 +782,12 @@ proc callCCompiler*(projectfile: string) = rawMessage(errExecutionOfProgramFailed, cmds.join()) if optNoLinking notin gGlobalOptions: # call the linker: - var it = PStrEntry(externalToLink.head) var objfiles = "" - while it != nil: - let objFile = if noAbsolutePaths(): it.data.extractFilename else: it.data + for it in externalToLink: + let objFile = if noAbsolutePaths(): it.extractFilename else: it add(objfiles, ' ') add(objfiles, quoteShell( addFileExt(objFile, CC[cCompiler].objExt))) - it = PStrEntry(it.next) for x in toCompile: add(objfiles, ' ') add(objfiles, quoteShell(x.obj)) @@ -836,15 +830,14 @@ proc writeJsonBuildInstructions*(projectfile: string) = else: lit "],\L" - proc linkfiles(f: File; buf, objfiles: var string; toLink: TLinkedList) = - var it = PStrEntry(toLink.head) - while it != nil: - let objfile = addFileExt(it.data, CC[cCompiler].objExt) - str objfile + proc linkfiles(f: File; buf, objfiles: var string; toLink: seq[string]) = + for i, it in toLink: + let objfile = addFileExt(it, CC[cCompiler].objExt) + str(objfile) add(objfiles, ' ') add(objfiles, quoteShell(objfile)) - it = PStrEntry(it.next) - if it == nil: + + if i == toLink.high: lit "\L" else: lit ",\L" diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 29a72c86e3..7d40fe44a7 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -31,7 +31,7 @@ implements the required case distinction. import ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options, - nversion, nimsets, msgs, securehash, bitsets, idents, lists, types, os, + nversion, nimsets, msgs, securehash, bitsets, idents, types, os, times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils, intsets, cgmeth, lowerings diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 8d4badb4e0..cd2ccfe53c 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -10,7 +10,7 @@ # This include file implements lambda lifting for the transformator. import - intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, + intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os, idents, renderer, types, magicsys, rodread, lowerings, tables discard """ diff --git a/compiler/lists.nim b/compiler/lists.nim index 27e3733425..bfd0522047 100644 --- a/compiler/lists.nim +++ b/compiler/lists.nim @@ -7,113 +7,22 @@ # distribution, for details about the copyright. # -# This module implements a generic doubled linked list. -# TODO Remove this and replace it with something sensible +# This module is deprecated, don't use it. +# TODO Remove this + import os -type - PListEntry* = ref TListEntry - TListEntry* = object of RootObj - prev*, next*: PListEntry - TStrEntry* = object of TListEntry - data*: string +static: + echo "WARNING: imported deprecated module compiler/lists.nim, use seq ore lists from the standard library" - PStrEntry* = ref TStrEntry - TLinkedList* = object # for the "find" operation: - head*, tail*: PListEntry - counter*: int +proc appendStr*(list: var seq[string]; data: string) {.deprecated.} = + # just use system.add + list.add(data) - TCompareProc* = proc (entry: PListEntry, closure: pointer): bool {.nimcall.} - -proc initLinkedList*(list: var TLinkedList) = - list.counter = 0 - list.head = nil - list.tail = nil - -proc append*(list: var TLinkedList, entry: PListEntry) = - inc(list.counter) - entry.next = nil - entry.prev = list.tail - if list.tail != nil: - assert(list.tail.next == nil) - list.tail.next = entry - list.tail = entry - if list.head == nil: list.head = entry - -proc contains*(list: TLinkedList, data: string): bool = - var it = list.head - while it != nil: - if PStrEntry(it).data == data: - return true - it = it.next - -proc newStrEntry(data: string): PStrEntry = - new(result) - result.data = data - -proc appendStr*(list: var TLinkedList, data: string) = - append(list, newStrEntry(data)) - -proc includeStr*(list: var TLinkedList, data: string): bool = - if contains(list, data): return true - appendStr(list, data) # else: add to list - -proc prepend*(list: var TLinkedList, entry: PListEntry) = - inc(list.counter) - entry.prev = nil - entry.next = list.head - if list.head != nil: - assert(list.head.prev == nil) - list.head.prev = entry - list.head = entry - if list.tail == nil: list.tail = entry - -proc prependStr*(list: var TLinkedList, data: string) = - prepend(list, newStrEntry(data)) - -proc insertBefore*(list: var TLinkedList, pos, entry: PListEntry) = - assert(pos != nil) - if pos == list.head: - prepend(list, entry) +proc includeStr(list: var seq[string]; data: string): bool {.deprecated.} = + if list.contains(data): + result = true else: - inc(list.counter) - entry.next = pos - entry.prev = pos.prev - if pos.prev != nil: pos.prev.next = entry - pos.prev = entry + result = false + list.add data -proc remove*(list: var TLinkedList, entry: PListEntry) = - dec(list.counter) - if entry == list.tail: - list.tail = entry.prev - if entry == list.head: - list.head = entry.next - if entry.next != nil: entry.next.prev = entry.prev - if entry.prev != nil: entry.prev.next = entry.next - -proc bringToFront*(list: var TLinkedList, entry: PListEntry) = - when true: - list.remove entry - list.prepend entry - else: - if entry == list.head: return - if entry == list.tail: list.tail = entry.prev - if entry.next != nil: entry.next.prev = entry.prev - if entry.prev != nil: entry.prev.next = entry.next - entry.prev = nil - entry.next = list.head - list.head = entry - -proc excludePath*(list: var TLinkedList, data: string) = - var it = list.head - while it != nil: - let nxt = it.next - if cmpPaths(PStrEntry(it).data, data) == 0: - remove(list, it) - it = nxt - -proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry = - result = list.head - while result != nil: - if fn(result, closure): return - result = result.next diff --git a/compiler/main.nim b/compiler/main.nim index 2acb7620c6..5f86e61881 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -15,7 +15,7 @@ import wordrecg, sem, semdata, idents, passes, docgen, extccomp, cgen, jsgen, json, nversion, platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, - docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists, + docgen2, service, parser, modules, ccgutils, sigmatch, ropes, modulegraphs from magicsys import systemModule, resetSysTypes @@ -151,7 +151,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = # In "nim serve" scenario, each command must reset the registered passes clearPasses() gLastCmdTime = epochTime() - appendStr(searchPaths, options.libpath) + searchPaths.add(options.libpath) when false: # gProjectFull.len != 0: # current path is always looked first for modules prependStr(searchPaths, gProjectPath) @@ -229,7 +229,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = for s in definedSymbolNames(): definedSymbols.elems.add(%s) var libpaths = newJArray() - for dir in iterSearchPath(searchPaths): libpaths.elems.add(%dir) + for dir in searchPaths: libpaths.elems.add(%dir) var dumpdata = % [ (key: "version", val: %VersionAsString), @@ -245,7 +245,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = for s in definedSymbolNames(): msgWriteln(s, {msgStdout, msgSkipHook}) msgWriteln("-- end of list --", {msgStdout, msgSkipHook}) - for it in iterSearchPath(searchPaths): msgWriteln(it) + for it in searchPaths: msgWriteln(it) of "check": gCmd = cmdCheck commandCheck(graph, cache) diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 9c5c17287d..e6466fc246 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -9,11 +9,11 @@ ## Implements some helper procs for Nimble (Nim's package manager) support. -import parseutils, strutils, strtabs, os, options, msgs, lists +import parseutils, strutils, strtabs, os, options, msgs proc addPath*(path: string, info: TLineInfo) = - if not contains(options.searchPaths, path): - lists.prependStr(options.searchPaths, path) + if not options.searchPaths.contains(path): + options.searchPaths.insert(path, 0) proc versionSplitPos(s: string): int = result = s.len-2 @@ -61,7 +61,7 @@ iterator chosen(packages: StringTableRef): string = proc addNimblePath(p: string, info: TLineInfo) = if not contains(options.searchPaths, p): message(info, hintPath, p) - lists.prependStr(options.lazyPaths, p) + options.lazyPaths.insert(p, 0) proc addPathRec(dir: string, info: TLineInfo) = var packages = newStringTable(modeStyleInsensitive) diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index 2872bdade5..aca03fc16d 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -10,7 +10,7 @@ ## exposes the Nim VM to clients. import ast, modules, passes, passaux, condsyms, - options, nimconf, lists, sem, semdata, llstream, vm, modulegraphs, idents + options, nimconf, sem, semdata, llstream, vm, modulegraphs, idents proc execute*(program: string) = passes.gIncludeFile = includeModule @@ -25,7 +25,7 @@ proc execute*(program: string) = registerPass(semPass) registerPass(evalPass) - appendStr(searchPaths, options.libpath) + searchPaths.add options.libpath var graph = newModuleGraph() var cache = newIdentCache() var m = makeStdinModule(graph) diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim index 4afb169121..a97d88078e 100644 --- a/compiler/nimfix/nimfix.nim +++ b/compiler/nimfix/nimfix.nim @@ -13,7 +13,7 @@ import strutils, os, parseopt import compiler/[options, commands, modules, sem, passes, passaux, nimfix/pretty, msgs, nimconf, - extccomp, condsyms, lists, + extccomp, condsyms, modulegraphs, idents] const Usage = """ @@ -39,10 +39,10 @@ proc mainCommand = registerPass verbosePass registerPass semPass gCmd = cmdPretty - appendStr(searchPaths, options.libpath) + searchPaths.add options.libpath if gProjectFull.len != 0: # current path is always looked first for modules - prependStr(searchPaths, gProjectPath) + searchPaths.insert(gProjectPath, 0) compileProject(newModuleGraph(), newIdentCache()) pretty.overwriteFiles() diff --git a/compiler/options.nim b/compiler/options.nim index 2295bbf931..7fd7129e5e 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -8,7 +8,7 @@ # import - os, lists, strutils, strtabs, osproc, sets + os, strutils, strtabs, osproc, sets const hasTinyCBackend* = defined(tinyc) @@ -129,7 +129,8 @@ var gExitcode*: int8 gCmd*: TCommands = cmdNone # the command gSelectedGC* = gcRefc # the selected GC - searchPaths*, lazyPaths*: TLinkedList + searchPaths*: seq[string] = @[] + lazyPaths*: seq[string] = @[] outFile*: string = "" docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \ # The string uses the formatting variables `path` and `line`. @@ -267,9 +268,7 @@ proc removeTrailingDirSep*(path: string): string = proc disableNimblePath*() = gNoNimblePath = true - lazyPaths.head = nil - lazyPaths.tail = nil - lazyPaths.counter = 0 + lazyPaths.setLen(0) include packagehandling @@ -336,27 +335,22 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = result = joinPath(subdir, tail) #echo "completeGeneratedFilePath(", f, ") = ", result -iterator iterSearchPath*(searchPaths: TLinkedList): string = - var it = PStrEntry(searchPaths.head) - while it != nil: - yield it.data - it = PStrEntry(it.next) - proc rawFindFile(f: string): string = - for it in iterSearchPath(searchPaths): + for it in searchPaths: result = joinPath(it, f) if existsFile(result): return result.canonicalizePath result = "" proc rawFindFile2(f: string): string = - var it = PStrEntry(lazyPaths.head) - while it != nil: - result = joinPath(it.data, f) + for i, it in lazyPaths: + result = joinPath(it, f) if existsFile(result): - bringToFront(lazyPaths, it) + # bring to front + for j in countDown(i,1): + swap(lazyPaths[j], lazyPaths[j-1]) + return result.canonicalizePath - it = PStrEntry(it.next) result = "" template patchModule() {.dirty.} = diff --git a/compiler/passes.nim b/compiler/passes.nim index 3cc15147e3..328826f82e 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -11,7 +11,7 @@ # `TPass` interface. import - strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, + strutils, options, ast, astalgo, llstream, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, nimsets, syntaxes, times, rodread, idgen, modulegraphs diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index bcb0461f26..4476dab720 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -11,7 +11,7 @@ import os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer, - wordrecg, ropes, options, strutils, lists, extccomp, math, magicsys, trees, + wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees, rodread, types, lookups const @@ -218,20 +218,19 @@ proc processCallConv(c: PContext, n: PNode) = var sw = whichKeyword(n.sons[1].ident) case sw of FirstCallConv..LastCallConv: - POptionEntry(c.optionStack.tail).defaultCC = wordToCallConv(sw) + c.optionStack[^1].defaultCC = wordToCallConv(sw) else: localError(n.info, errCallConvExpected) else: localError(n.info, errCallConvExpected) proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib = - var it = PLib(c.libs.head) - while it != nil: - if it.kind == kind: - if trees.exprStructuralEquivalent(it.path, path): return it - it = PLib(it.next) + for it in c.libs: + if it.kind == kind and trees.exprStructuralEquivalent(it.path, path): + return it + result = newLib(kind) result.path = path - append(c.libs, result) + c.libs.add result if path.kind in {nkStrLit..nkTripleStrLit}: result.isOverriden = options.isDynlibOverride(path.strVal) @@ -254,7 +253,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) = if (sym == nil) or (sym.kind == skModule): let lib = getLib(c, libDynamic, expectDynlibNode(c, n)) if not lib.isOverriden: - POptionEntry(c.optionStack.tail).dynlib = lib + c.optionStack[^1].dynlib = lib else: if n.kind == nkExprColonExpr: var lib = getLib(c, libDynamic, expectDynlibNode(c, n)) @@ -350,12 +349,12 @@ proc processPush(c: PContext, n: PNode, start: int) = if n.sons[start-1].kind == nkExprColonExpr: localError(n.info, errGenerated, "':' after 'push' not supported") var x = newOptionEntry() - var y = POptionEntry(c.optionStack.tail) + var y = c.optionStack[^1] x.options = gOptions x.defaultCC = y.defaultCC x.dynlib = y.dynlib x.notes = gNotes - append(c.optionStack, x) + c.optionStack.add(x) for i in countup(start, sonsLen(n) - 1): if processOption(c, n.sons[i]): # simply store it somewhere: @@ -365,12 +364,12 @@ proc processPush(c: PContext, n: PNode, start: int) = #localError(n.info, errOptionExpected) proc processPop(c: PContext, n: PNode) = - if c.optionStack.counter <= 1: + if c.optionStack.len <= 1: localError(n.info, errAtPopWithoutPush) else: - gOptions = POptionEntry(c.optionStack.tail).options - gNotes = POptionEntry(c.optionStack.tail).notes - remove(c.optionStack, c.optionStack.tail) + gOptions = c.optionStack[^1].options + gNotes = c.optionStack[^1].notes + c.optionStack.setLen(c.optionStack.len - 1) proc processDefine(c: PContext, n: PNode) = if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent): @@ -977,8 +976,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, proc implicitPragmas*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = if sym != nil and sym.kind != skModule: - var it = POptionEntry(c.optionStack.head) - while it != nil: + for it in c.optionStack: let o = it.otherPragmas if not o.isNil: pushInfoContext(n.info) @@ -986,11 +984,10 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode, if singlePragma(c, sym, o, i, validPragmas): internalError(n.info, "implicitPragmas") popInfoContext() - it = it.next.POptionEntry if lfExportLib in sym.loc.flags and sfExportc notin sym.flags: localError(n.info, errDynlibRequiresExportc) - var lib = POptionEntry(c.optionStack.tail).dynlib + var lib = c.optionStack[^1].dynlib if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and sfImportc in sym.flags and lib != nil: incl(sym.loc.flags, lfDynamicLib) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 1602988ddc..5ce8414d60 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -10,7 +10,7 @@ # This module implements the renderer of the standard Nim representation. import - lexer, options, idents, strutils, ast, msgs, lists + lexer, options, idents, strutils, ast, msgs type TRenderFlag* = enum diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 9e94f1c19e..0c31eadbeb 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -12,7 +12,7 @@ import ast, modules, idents, passes, passaux, condsyms, - options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs, + options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs, os, times, osproc, wordrecg, strtabs, modulegraphs # we support 'cmpIgnoreStyle' natively for efficiency: @@ -153,7 +153,7 @@ proc runNimScript*(cache: IdentCache; scriptName: string; registerPass(semPass) registerPass(evalPass) - appendStr(searchPaths, options.libpath) + searchPaths.add(options.libpath) var m = graph.makeModule(scriptName) incl(m.flags, sfMainModule) diff --git a/compiler/sem.nim b/compiler/sem.nim index fc7736b079..59d726b43d 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -10,7 +10,7 @@ # This module implements the semantic checking pass. import - ast, strutils, hashes, lists, options, lexer, astalgo, trees, treetab, + ast, strutils, hashes, options, lexer, astalgo, trees, treetab, wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math, magicsys, parser, nversion, nimsets, semfold, importer, procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch, diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 77a530a150..b501ec4404 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -10,15 +10,14 @@ ## This module contains the data structures for the semantic checking phase. import - strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab, + strutils, intsets, options, lexer, ast, astalgo, trees, treetab, wordrecg, ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef, modulegraphs type - TOptionEntry* = object of lists.TListEntry # entries to put on a - # stack for pragma parsing + TOptionEntry* = object # entries to put on a stack for pragma parsing options*: TOptions defaultCC*: TCallingConvention dynlib*: PLib @@ -79,10 +78,10 @@ type inGenericInst*: int # > 0 if we are instantiating a generic converters*: TSymSeq # sequence of converters patterns*: TSymSeq # sequence of pattern matchers - optionStack*: TLinkedList + optionStack*: seq[POptionEntry] symMapping*: TIdTable # every gensym'ed symbol needs to be mapped # to some new symbol in a generic instantiation - libs*: TLinkedList # all libs used by this module + libs*: seq[PLib] # all libs used by this module semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}): PNode {.nimcall.} @@ -133,7 +132,7 @@ proc getCurrOwner*(): PSym = # the documentation comment always gets # assigned to the current owner # BUGFIX: global array is needed! - result = gOwners[high(gOwners)] + result = gOwners[^1] proc pushOwner*(owner: PSym) = add(gOwners, owner) @@ -144,7 +143,7 @@ proc popOwner*() = else: internalError("popOwner") proc lastOptionEntry*(c: PContext): POptionEntry = - result = POptionEntry(c.optionStack.tail) + result = c.optionStack[^1] proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next @@ -187,9 +186,9 @@ proc newOptionEntry*(): POptionEntry = proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext = new(result) result.ambiguousSymbols = initIntSet() - initLinkedList(result.optionStack) - initLinkedList(result.libs) - append(result.optionStack, newOptionEntry()) + result.optionStack = @[] + result.libs = @[] + result.optionStack.add(newOptionEntry()) result.module = module result.friendModules = @[module] result.converters = @[] diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 749deded11..58239d23e7 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -11,7 +11,7 @@ # and evaluation phase import - strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times, + strutils, options, ast, astalgo, trees, treetab, nimsets, times, nversion, platform, math, msgs, os, condsyms, idents, renderer, types, commands, magicsys, saturate diff --git a/compiler/transf.nim b/compiler/transf.nim index 2103d48bf9..e14985145f 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -19,7 +19,7 @@ # * transforms 'defer' into a 'try finally' statement import - intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, + intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os, idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread, lambdalifting, sempass2, lowerings, lookups diff --git a/tools/nimsuggest/nimsuggest.nim b/tools/nimsuggest/nimsuggest.nim index e11bb560c9..7891f73e55 100644 --- a/tools/nimsuggest/nimsuggest.nim +++ b/tools/nimsuggest/nimsuggest.nim @@ -295,16 +295,14 @@ proc serveTcp(graph: ModuleGraph; cache: IdentCache) = stdoutSocket.send("\c\L") stdoutSocket.close() - + proc serveEpc(server: Socket; graph: ModuleGraph; cache: IdentCache) = var client = newSocket() # Wait for connection accept(server, client) if gLogging: - var it = searchPaths.head - while it != nil: - logStr(PStrEntry(it).data) - it = it.next + for it in searchPaths: + logStr(it) msgs.writelnHook = proc (line: string) = logStr(line) while true: From 22789a0bfc326ae6a292679b4e9d9eb2a295c26a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 23 Feb 2017 19:47:09 +0100 Subject: [PATCH 58/67] fixes #5419 --- compiler/semgnrc.nim | 6 +++++- lib/core/macros.nim | 2 ++ tests/template/mgensym_generic_cross_module.nim | 14 ++++++++++++++ tests/template/tgensym_generic_cross_module.nim | 14 ++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/template/mgensym_generic_cross_module.nim create mode 100644 tests/template/tgensym_generic_cross_module.nim diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index bc80c41ad1..9c05ab2f96 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -174,7 +174,11 @@ proc semGenericStmt(c: PContext, n: PNode, # XXX for example: ``result.add`` -- ``add`` needs to be looked up here... var dummy: bool result = fuzzyLookup(c, n, flags, ctx, dummy) - of nkEmpty, nkSym..nkNilLit: + of nkSym: + let a = n.sym + let b = getGenSym(c, a) + if b != a: n.sym = b + of nkEmpty, succ(nkSym)..nkNilLit: # see tests/compile/tgensymgeneric.nim: # We need to open the gensym'ed symbol again so that the instantiation # creates a fresh copy; but this is wrong the very first reason for gensym diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 3adf4670dd..83776f16ba 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -742,6 +742,8 @@ proc `$`*(node: NimNode): string {.compileTime.} = result = $node.symbol of nnkOpenSymChoice, nnkClosedSymChoice: result = $node[0] + of nnkAccQuoted: + result = $node[0] else: badNodeKind node.kind, "$" diff --git a/tests/template/mgensym_generic_cross_module.nim b/tests/template/mgensym_generic_cross_module.nim new file mode 100644 index 0000000000..80b681db46 --- /dev/null +++ b/tests/template/mgensym_generic_cross_module.nim @@ -0,0 +1,14 @@ + +template makeDomElement(x: untyped, name: string = nil) = + const tag {.gensym.} = if name == nil: astToStr(x) else: name + + proc x*(p: int|float) = + echo tag, p + + proc x*(p: string|cstring) = + echo tag, p + +#proc wrappedUp[T](x: T) = +# mixin foo, bar +makeDomElement(foo, "foo") +makeDomElement(bar) diff --git a/tests/template/tgensym_generic_cross_module.nim b/tests/template/tgensym_generic_cross_module.nim new file mode 100644 index 0000000000..856ab676da --- /dev/null +++ b/tests/template/tgensym_generic_cross_module.nim @@ -0,0 +1,14 @@ +discard """ + output: '''foo55 +foo8.0 +fooaha +bar7''' +""" +# bug #5419 +import mgensym_generic_cross_module + +foo(55) +foo 8.0 +foo "aha" +bar 7 + From 2d546ca0ac80486b8f31e389ef19e4d65093a1fa Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 24 Feb 2017 00:32:03 +0100 Subject: [PATCH 59/67] fixes #5417 --- compiler/ccgstmts.nim | 2 +- compiler/semexprs.nim | 2 +- compiler/semstmts.nim | 1 + compiler/semtempl.nim | 12 +++++++----- tests/template/tgensym_label.nim | 18 ++++++++++++++++++ 5 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 tests/template/tgensym_label.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index e4f13c70b2..3a861ebd4e 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -540,7 +540,7 @@ proc genBreakStmt(p: BProc, t: PNode) = # named break? assert(t.sons[0].kind == nkSym) var sym = t.sons[0].sym - assert(sym.loc.k == locOther) + doAssert(sym.loc.k == locOther) idx = sym.position-1 else: # an unnamed 'break' can only break a loop after 'transf' pass: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 542d7b4e39..d9a5f6c503 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2107,7 +2107,7 @@ proc semBlock(c: PContext, n: PNode): PNode = var labl = newSymG(skLabel, n.sons[0], c) if sfGenSym notin labl.flags: addDecl(c, labl) - n.sons[0] = newSymNode(labl, n.sons[0].info) + n.sons[0] = newSymNode(labl, n.sons[0].info) suggestSym(n.sons[0].info, labl) styleCheckDef(labl) n.sons[1] = semExpr(c, n.sons[1]) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index e2b0f4b7a7..282d4da887 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -30,6 +30,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = of nkIdent: s = lookUp(c, n.sons[0]) of nkSym: s = n.sons[0].sym else: illFormedAst(n) + s = getGenSym(c, s) if s.kind == skLabel and s.owner.id == c.p.owner.id: var x = newSymNode(s) x.info = n.info diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 8819f17cc1..420e361167 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -384,11 +384,13 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = checkSonsLen(n, 2) openScope(c) if n.sons[0].kind != nkEmpty: - # labels are always 'gensym'ed: - let s = newGenSym(skLabel, n.sons[0], c) - addPrelimDecl(c.c, s) - styleCheckDef(s) - n.sons[0] = newSymNode(s, n.sons[0].info) + addLocalDecl(c, n.sons[0], skLabel) + when false: + # labels are always 'gensym'ed: + let s = newGenSym(skLabel, n.sons[0], c) + addPrelimDecl(c.c, s) + styleCheckDef(s) + n.sons[0] = newSymNode(s, n.sons[0].info) n.sons[1] = semTemplBody(c, n.sons[1]) closeScope(c) of nkTryStmt: diff --git a/tests/template/tgensym_label.nim b/tests/template/tgensym_label.nim new file mode 100644 index 0000000000..fd3b0a1ee9 --- /dev/null +++ b/tests/template/tgensym_label.nim @@ -0,0 +1,18 @@ + +# bug #5417 +import macros + +macro genBody: untyped = + let sbx = genSym(nskLabel, "test") + when true: + result = quote do: + block `sbx`: + break `sbx` + else: + template foo(s1, s2) = + block s1: + break s2 + result = getAst foo(sbx, sbx) + +proc test() = + genBody() From e8ad59fdc497843e712583cba03cfd1809124bfb Mon Sep 17 00:00:00 2001 From: Fabian Keller Date: Fri, 24 Feb 2017 09:48:38 +0100 Subject: [PATCH 60/67] Bugfix/double newlines in stderr (#5426) --- lib/system.nim | 1 + tests/osproc/ta.nim | 3 --- tests/osproc/ta_in.nim | 5 +++++ tests/osproc/ta_out.nim | 16 ++++++++++++++++ tests/osproc/tstdin.nim | 2 +- tests/osproc/tstdout.nim | 29 +++++++++++++++++++++++++++++ 6 files changed, 52 insertions(+), 4 deletions(-) delete mode 100644 tests/osproc/ta.nim create mode 100644 tests/osproc/ta_in.nim create mode 100644 tests/osproc/ta_out.nim create mode 100644 tests/osproc/tstdout.nim diff --git a/lib/system.nim b/lib/system.nim index bab5369f11..6388e278e1 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2743,6 +2743,7 @@ when not defined(JS): #and not defined(nimscript): # we use binary mode on Windows: c_setmode(c_fileno(stdin), O_BINARY) c_setmode(c_fileno(stdout), O_BINARY) + c_setmode(c_fileno(stderr), O_BINARY) when defined(endb): proc endbStep() diff --git a/tests/osproc/ta.nim b/tests/osproc/ta.nim deleted file mode 100644 index 5ebcc7f142..0000000000 --- a/tests/osproc/ta.nim +++ /dev/null @@ -1,3 +0,0 @@ -import strutils -let x = stdin.readLine() -echo x.parseInt + 5 diff --git a/tests/osproc/ta_in.nim b/tests/osproc/ta_in.nim new file mode 100644 index 0000000000..b46890f6ea --- /dev/null +++ b/tests/osproc/ta_in.nim @@ -0,0 +1,5 @@ +# This file is prefixed with an "a", because other tests +# depend on it and it must be compiled first. +import strutils +let x = stdin.readLine() +echo x.parseInt + 5 diff --git a/tests/osproc/ta_out.nim b/tests/osproc/ta_out.nim new file mode 100644 index 0000000000..f7091a7f6a --- /dev/null +++ b/tests/osproc/ta_out.nim @@ -0,0 +1,16 @@ +# This file is prefixed with an "a", because other tests +# depend on it and it must be compiled first. +stdout.writeLine("to stdout") +stdout.flushFile() +stdout.writeLine("to stdout") +stdout.flushFile() + +stderr.writeLine("to stderr") +stderr.flushFile() +stderr.writeLine("to stderr") +stderr.flushFile() + +stdout.writeLine("to stdout") +stdout.flushFile() +stdout.writeLine("to stdout") +stdout.flushFile() diff --git a/tests/osproc/tstdin.nim b/tests/osproc/tstdin.nim index b491c25000..d94c34192d 100644 --- a/tests/osproc/tstdin.nim +++ b/tests/osproc/tstdin.nim @@ -4,7 +4,7 @@ discard """ """ import osproc, os, streams -const filename = when defined(Windows): "ta.exe" else: "ta" +const filename = when defined(Windows): "ta_in.exe" else: "ta_in" doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename) diff --git a/tests/osproc/tstdout.nim b/tests/osproc/tstdout.nim new file mode 100644 index 0000000000..0cb5bd9c08 --- /dev/null +++ b/tests/osproc/tstdout.nim @@ -0,0 +1,29 @@ +discard """ + output: '''-------------------------------------- +to stdout +to stdout +to stderr +to stderr +to stdout +to stdout +-------------------------------------- +''' +""" +import osproc, os, streams + +const filename = when defined(Windows): "ta_out.exe" else: "ta_out" + +doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename) + +var p = startProcess(filename, getCurrentDir() / "tests" / "osproc", + options={poStdErrToStdOut}) + +let outputStream = p.outputStream +var x = newStringOfCap(120) +var output = "" +while outputStream.readLine(x.TaintedString): + output.add(x & "\n") + +echo "--------------------------------------" +stdout.write output +echo "--------------------------------------" From f8914cc3b002916c2b9a9cc548eae610d14ef666 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 24 Feb 2017 13:02:36 +0100 Subject: [PATCH 61/67] fixes a multimethod regression --- compiler/cgmeth.nim | 15 +++++++++------ compiler/semstmts.nim | 13 +++++++++++++ tests/metatype/tautonotgeneric.nim | 13 +++++++++++-- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 52fd8ab494..3a945ae0ac 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -35,15 +35,18 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode = else: result = n +proc getDispatcher*(s: PSym): PSym = + ## can return nil if is has no dispatcher. + let dispn = lastSon(s.ast) + if dispn.kind == nkSym: + let disp = dispn.sym + if sfDispatcher in disp.flags: result = disp + proc methodCall*(n: PNode): PNode = result = n # replace ordinary method by dispatcher method: - let dispn = lastSon(result.sons[0].sym.ast) - if dispn.kind == nkSym: - let disp = dispn.sym - if sfDispatcher notin disp.flags: - localError(n.info, "'" & $result & "' lacks a dispatcher") - return + let disp = getDispatcher(result.sons[0].sym) + if disp != nil: result.sons[0].sym = disp # change the arguments to up/downcasts to fit the dispatcher's parameters: for i in countup(1, sonsLen(result)-1): diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5ecba3ab07..c28dbf82f5 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1443,6 +1443,19 @@ proc semProc(c: PContext, n: PNode): PNode = proc semMethod(c: PContext, n: PNode): PNode = if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method") result = semProcAux(c, n, skMethod, methodPragmas) + # macros can transform converters to nothing: + if namePos >= result.safeLen: return result + var s = result.sons[namePos].sym + # we need to fix the 'auto' return type for the dispatcher here (see tautonotgeneric + # test case): + let disp = getDispatcher(s) + # auto return type? + if disp != nil and disp.typ.sons[0] != nil and disp.typ.sons[0].kind == tyExpr: + let ret = s.typ.sons[0] + disp.typ.sons[0] = ret + if disp.ast[resultPos].kind == nkSym: + if isEmptyType(ret): disp.ast.sons[resultPos] = emptyNode + else: disp.ast[resultPos].sym.typ = ret proc semConverterDef(c: PContext, n: PNode): PNode = if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter") diff --git a/tests/metatype/tautonotgeneric.nim b/tests/metatype/tautonotgeneric.nim index a55ae488e6..f0d6932f9e 100644 --- a/tests/metatype/tautonotgeneric.nim +++ b/tests/metatype/tautonotgeneric.nim @@ -1,15 +1,24 @@ discard """ - output: "wof!" + output: '''wof! +wof!''' """ # bug #1659 type Animal = ref object {.inheritable.} type Dog = ref object of Animal -method say(a: Animal): auto = "wat!" +method say(a: Animal): auto {.base.} = "wat!" method say(a: Dog): auto = "wof!" proc saySomething(a: Animal): auto = a.say() + +method ec(a: Animal): auto {.base.} = echo "wat!" +method ec(a: Dog): auto = echo "wof!" + +proc ech(a: Animal): auto = a.ec() + + var a = Dog() echo saySomething(a) +ech a From b7a1cad4a494ed86793af73119812f0a7e4d808f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 24 Feb 2017 13:05:58 +0100 Subject: [PATCH 62/67] make tests green again --- compiler/semasgn.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 063157891c..70765d0878 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -248,6 +248,7 @@ proc addParam(procType: PType; param: PSym) = proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym = var a: TLiftCtx a.info = info + a.c = c let body = newNodeI(nkStmtList, info) result = newSym(skProc, getIdent":lifted=", typ.owner, info) a.fn = result From 8ebc8697736acf2c7828fbe2dcb57c54ad48f760 Mon Sep 17 00:00:00 2001 From: Ivan Koster Date: Fri, 24 Feb 2017 15:43:31 +0100 Subject: [PATCH 63/67] Remove unnecessary colon in unittest.nim code example --- lib/pure/unittest.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index cdca02ed79..01af0f8395 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -24,7 +24,7 @@ ## echo "run before each test" ## ## teardown: -## echo "run after each test": +## echo "run after each test" ## ## test "essential truths": ## # give up and stop if this fails From fa98edc78cf990f2437288af87a9180847f94ed4 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 24 Feb 2017 15:52:52 +0100 Subject: [PATCH 64/67] another attempt to make test green again --- compiler/cgmeth.nim | 12 ++++++++++-- tests/{metatype => method}/tautonotgeneric.nim | 0 tools/nimsuggest/nimsuggest.nim | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) rename tests/{metatype => method}/tautonotgeneric.nim (100%) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 3a945ae0ac..1d7f5a6e10 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -60,8 +60,8 @@ type proc sameMethodBucket(a, b: PSym): MethodResult = if a.name.id != b.name.id: return if sonsLen(a.typ) != sonsLen(b.typ): - return # check for return type: - if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]): return + return + for i in countup(1, sonsLen(a.typ) - 1): var aa = a.typ.sons[i] var bb = b.typ.sons[i] @@ -89,6 +89,14 @@ proc sameMethodBucket(a, b: PSym): MethodResult = return No else: return No + if result == Yes: + # check for return type: + if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]): + if b.typ.sons[0] != nil and b.typ.sons[0].kind == tyExpr: + # infer 'auto' from the base to make it consistent: + b.typ.sons[0] = a.typ.sons[0] + else: + return No proc attachDispatcher(s: PSym, dispatcher: PNode) = var L = s.ast.len-1 diff --git a/tests/metatype/tautonotgeneric.nim b/tests/method/tautonotgeneric.nim similarity index 100% rename from tests/metatype/tautonotgeneric.nim rename to tests/method/tautonotgeneric.nim diff --git a/tools/nimsuggest/nimsuggest.nim b/tools/nimsuggest/nimsuggest.nim index 57d343ae40..137ac4219f 100644 --- a/tools/nimsuggest/nimsuggest.nim +++ b/tools/nimsuggest/nimsuggest.nim @@ -423,7 +423,7 @@ proc recompileFullProject(graph: ModuleGraph; cache: IdentCache) = graph.resetAllModules() GC_fullcollect() compileProject(graph, cache) - echo "recompiled!" + echo GC_getStatistics() proc mainThread(graph: ModuleGraph; cache: IdentCache) = if gLogging: From 469a7d258ce256ea22b3df3fe40fb7ec0ef129ef Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Fri, 24 Feb 2017 14:58:02 +0000 Subject: [PATCH 65/67] Add warning about log flushing. Related to #3269 (#5424) --- lib/pure/logging.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 5544a4b3f4..65724f75a6 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -46,6 +46,8 @@ ## ## **Warning:** The global list of handlers is a thread var, this means that ## the handlers must be re-added in each thread. +## **Warning:** When logging on disk or console, only error and fatal messages +## are flushed out immediately. Use flushFile() where needed. import strutils, times when not defined(js): From 4af2c26c918239fa79f7523e923b5bbceaafc272 Mon Sep 17 00:00:00 2001 From: Dennis Felsing Date: Fri, 24 Feb 2017 16:48:22 +0100 Subject: [PATCH 66/67] Make toHex work for uints (#5423) --- lib/pure/strutils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 9c205a54f2..9c9da92c61 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -898,7 +898,7 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect, proc toHex*[T](x: T): string = ## Shortcut for ``toHex(x, T.sizeOf * 2)`` - toHex(x, T.sizeOf * 2) + toHex(BiggestInt(x), T.sizeOf * 2) proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect, rtl, extern: "nsuIntToStr".} = From d878c4c1b46a938e6d593218284d80faa386d849 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Sat, 25 Feb 2017 02:20:16 +0200 Subject: [PATCH 67/67] Listen on ipv6 --- lib/pure/asynchttpserver.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index a558d9d7ee..672eb34a0f 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -31,7 +31,7 @@ ## ## waitFor server.serve(Port(8080), cb) -import tables, asyncnet, asyncdispatch, parseutils, uri, strutils +import tables, asyncnet, asyncdispatch, parseutils, uri, strutils, nativesockets import httpcore export httpcore except parseHeader @@ -241,7 +241,7 @@ proc serve*(server: AsyncHttpServer, port: Port, ## specified address and port. ## ## When a request is made by a client the specified callback will be called. - server.socket = newAsyncSocket() + server.socket = newAsyncSocket(AF_INET6) if server.reuseAddr: server.socket.setSockOpt(OptReuseAddr, true) if server.reusePort: