diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 2c9ff103c..000000000 --- a/.gitattributes +++ /dev/null @@ -1,9 +0,0 @@ -# Avoids changelog conflicts by assuming additions-only, which is by far the common case. -# In the rare case where branch b1 rebases against branch b2 and both branches -# modified the same changelog entry, you'll end up with that changelog entry -# duplicated, which is easily identifiable and fixable. -/changelog.md merge=union - -# bug https://github.com/dom96/choosenim/issues/256 for WSL CRLF -*.sh text eol=lf -/config/build_config.txt text eol=lf diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index dc771dd31..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: 'araq' # Replace with a single Patreon username -open_collective: 'nim' # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: 'https://nim-lang.org/donate.html' # Replace with a single custom sponsorship URL diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 8406f607f..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: "Bug Report" -description: "Create a new bug report. Have you found an unexpected behavior? Use this form." -title: "Think about the title, twice." -labels: ["unconfirmed"] -body: - -- type: markdown - attributes: - value: | - - **Please provide a minimal code example that reproduces the Bug!** :bug: - Reports with a reproducible example and descriptive detailed information will likely receive fixes faster. - -- type: textarea - id: description - attributes: - label: Description - description: | - Use DETAILED DESCRIPTIVE information about the problem. - Here, you go into more details about your Bug report. This section can be a few paragraphs long. - placeholder: Bug reports with reproducible code and detailed information will be fixed faster. - validations: - required: true - -- type: textarea - id: nim-version - attributes: - label: Nim Version - description: Copy and paste the output of `nim -v` on the command line. For development versions, make sure to include the commit hash. - validations: - required: true - -- type: textarea - id: current-logs - attributes: - label: Current Output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. - placeholder: Bug reports with reproducible code and detailed information will be fixed faster. - render: text - -- type: textarea - id: expected-logs - attributes: - label: Expected Output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. - placeholder: Bug reports with reproducible code and detailed information will be fixed faster. - render: text - -- type: textarea - id: possible-solution - attributes: - label: Possible Solution - description: Propose a possible solution. - validations: - required: false - -- type: textarea - id: extra-info - attributes: - label: Additional Information - description: Any additional relevant information. - validations: - required: false - -- type: markdown - attributes: - value: | - - Thanks for your contributions!, your Bug report will receive feedback from the community soon... - - Please check whether the problem still exists in the devel branch, see [rebuilding the compiler](https://nim-lang.github.io/Nim/intern.html#rebuilding-the-compiler). - - Consider writing a PR targetting devel branch after filing this, see [contributing](https://nim-lang.github.io/Nim/contributing.html). - - If it's a pre-existing compiler bug, see [Debugging the compiler](https://nim-lang.github.io/Nim/intern.html#debugging-the-compiler) - which should give more context on a compiler crash. - - If it's a regression, you can help us by identifying which version introduced the bug, - see [Bisecting for regressions](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions), - or at least try known past releases (eg `choosenim 1.2.0`). - - [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 0187064b5..000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,10 +0,0 @@ -contact_links: - - name: Forum - url: https://forum.nim-lang.org - about: Please ask and answer questions here. - - name: Discord - url: https://discord.gg/nim - about: Please ask and answer questions here. - - name: Stack Overflow - url: https://stackoverflow.com/questions/tagged/nim-lang - about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index 5cb458626..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: "Feature request" -description: "Create a new Feature Request. Do you want to suggest a new feature? Use this form." -title: "Think about the title, twice." -labels: ["unconfirmed"] -body: - -- type: markdown - attributes: - value: | - - Please provide a minimal code example that illustrates the basic idea behind your feature request. - Reports with full repro code and descriptive detailed information will likely receive feedback faster. - - There is a separate repository for the detailed RFCs and proposals: https://github.com/nim-lang/RFCs. - If you have a simple feature request, you can post it here using this form, - but bear in mind that adding new features to the language is currently a low priority. - -- type: textarea - id: summary - attributes: - label: Summary - description: | - Use DETAILED DESCRIPTIVE information about the feature request. - Here, you go into more details about your ideas. This section can be a few paragraphs long. - placeholder: Short summary of your proposed feature. - validations: - required: true - -- type: textarea - id: description - attributes: - label: Description - description: Describe your solution, what problem does it fix? - validations: - required: true - -- type: textarea - id: alternatives - attributes: - label: Alternatives - description: Are there any alternatives you've considered? - validations: - required: false - -- type: textarea - id: Examples - attributes: - label: Examples - description: Provide examples for your feature request here. - placeholder: Example code here. - -- type: textarea - id: incompatibility - attributes: - label: Backwards Compatibility - description: If your Feature Request introduces backward-incompatible changes, describe them and propose how to deal with them. - validations: - required: false - -- type: textarea - id: links - attributes: - label: Links - description: Please copy and paste any relevant links to projects, issues, discussions, technical documentations, code samples, etc. - validations: - required: false - -- type: markdown - attributes: - value: | - - Thanks for your contributions!, your ideas will receive feedback from the community soon... - - **Remember to :star: Star the Nim project on GitHub!.** - - Consider writing a PR targetting devel branch after filing this, see [contributing](https://nim-lang.github.io/Nim/contributing.html). - - [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html) diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index c175f64a0..000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,69 +0,0 @@ -# Configuration for probot-stale - https://github.com/probot/stale - -# Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 365 - -# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. -# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 30 - -# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) -onlyLabels: [] - -# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable -exemptLabels: - - ARC - - bounty - - Codegen - - Crash - - Generics - - High Priority - - Macros - - Next release - - Showstopper - - Static[T] - -# Set to true to ignore issues in a project (defaults to false) -exemptProjects: false - -# Set to true to ignore issues in a milestone (defaults to false) -exemptMilestones: false - -# Set to true to ignore issues with an assignee (defaults to false) -exemptAssignees: false - -# Label to use when marking as stale -staleLabel: stale - -# Comment to post when marking as stale. Set to `false` to disable -markComment: > - This pull request has been automatically marked as stale because it has not had - recent activity. - If you think it is still a valid PR, please rebase it on the latest devel; - otherwise it will be closed. Thank you for your contributions. - -# Comment to post when removing the stale label. -# unmarkComment: > -# Your comment here. - -# Comment to post when closing a stale Issue or Pull Request. -# closeComment: > -# Your comment here. - -# Limit the number of actions per hour, from 1-30. Default is 30 -limitPerRun: 20 - -# Limit to only `issues` or `pulls` -only: pulls - -# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': -# pulls: -# daysUntilStale: 30 -# markComment: > -# This pull request has been automatically marked as stale because it has not had -# recent activity. It will be closed if no further activity occurs. Thank you -# for your contributions. - -# issues: -# exemptLabels: -# - confirmed diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml deleted file mode 100644 index cde30e5fa..000000000 --- a/.github/workflows/ci_docs.yml +++ /dev/null @@ -1,118 +0,0 @@ -name: Nim Docs CI -on: - push: - paths: - - 'compiler/docgen.nim' - - 'compiler/renderverbatim.nim' - - 'config/nimdoc.cfg' - - 'doc/**.rst' - - 'doc/**.md' - - 'doc/nimdoc.css' - - 'lib/**.nim' - - 'nimdoc/testproject/expected/testproject.html' - - 'tools/dochack/dochack.nim' - - 'tools/kochdocs.nim' - - '.github/workflows/ci_docs.yml' - - 'koch.nim' - - pull_request: - # Run only on changes on these files. - paths: - - 'compiler/docgen.nim' - - 'compiler/renderverbatim.nim' - - 'config/nimdoc.cfg' - - 'doc/**.rst' - - 'doc/**.md' - - 'doc/nimdoc.css' - - 'lib/**.nim' - - 'nimdoc/testproject/expected/testproject.html' - - 'tools/dochack/dochack.nim' - - 'tools/kochdocs.nim' - - '.github/workflows/ci_docs.yml' - - 'koch.nim' - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - build: - strategy: - fail-fast: false - matrix: - target: [linux, windows, osx] - include: - - target: linux - os: ubuntu-20.04 - - target: windows - os: windows-2019 - - target: osx - os: macos-11 - - name: ${{ matrix.target }} - runs-on: ${{ matrix.os }} - timeout-minutes: 60 # refs bug #18178 - - steps: - - name: 'Checkout' - uses: actions/checkout@v3 - with: - fetch-depth: 2 - - - name: 'Install build dependencies (macOS)' - if: runner.os == 'macOS' - run: brew install make - - - name: 'Install build dependencies (Windows)' - if: runner.os == 'Windows' - shell: bash - run: | - set -e - . ci/funs.sh - nimInternalInstallDepsWindows - echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - - - name: 'Add build binaries to PATH' - shell: bash - run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - - - name: 'System information' - shell: bash - run: . ci/funs.sh && nimCiSystemInfo - - - name: 'Build csourcesAny (posix)' - # this would work on windows and other CI use this on windows, - # but we ensure here that `ci/build_autogen.bat` keeps working on windows. - if: runner.os != 'Windows' - shell: bash - run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc - # was previously using caching via `actions/cache@v1` but this wasn't - # used in other CI pipelines and it's unclear the added complexity - # was worth the saving; can be revisited if needed. - - - name: 'Build csourcesAny (windows)' - if: runner.os == 'Windows' - shell: cmd - run: ci/build_autogen.bat - - - name: 'Build koch' - shell: bash - run: nim c koch - - - name: 'Build the real compiler' - shell: bash - run: ./koch boot -d:release - - - name: 'Build documentation' - shell: bash - run: ./koch doc --git.commit:devel - - - name: 'Publish documentation to Github Pages' - if: | - github.event_name == 'push' && github.ref == 'refs/heads/devel' && - matrix.target == 'linux' - uses: crazy-max/ghaction-github-pages@v3 - with: - build_dir: doc/html - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml deleted file mode 100644 index 0bec4cc21..000000000 --- a/.github/workflows/ci_packages.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Packages CI -on: - pull_request: - push: - branches: - - 'devel' - - 'version-2-0' - - 'version-1-6' - - 'version-1-2' - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - build: - strategy: - fail-fast: false - matrix: - os: [ubuntu-20.04, macos-11] - cpu: [amd64] - batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num` - name: '${{ matrix.os }} (batch: ${{ matrix.batch }})' - runs-on: ${{ matrix.os }} - timeout-minutes: 60 # refs bug #18178 - env: - NIM_TEST_PACKAGES: "1" - NIM_TESTAMENT_BATCH: ${{ matrix.batch }} - steps: - - name: 'Checkout' - uses: actions/checkout@v3 - with: - fetch-depth: 2 - - - name: 'Install node.js 16.x' - uses: actions/setup-node@v3 - with: - node-version: '16.x' - - - name: 'Install dependencies (Linux amd64)' - if: runner.os == 'Linux' && matrix.cpu == 'amd64' - run: | - sudo apt-fast update -qq - DEBIAN_FRONTEND='noninteractive' \ - sudo apt-fast install --no-install-recommends -yq \ - libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \ - valgrind libc6-dbg libblas-dev xorg-dev - - name: 'Install dependencies (macOS)' - if: runner.os == 'macOS' - run: brew install boehmgc make sfml gtk+3 - - name: 'Install dependencies (Windows)' - if: runner.os == 'Windows' - shell: bash - run: | - set -e - . ci/funs.sh - nimInternalInstallDepsWindows - echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - - - name: 'Add build binaries to PATH' - shell: bash - run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - - - name: 'System information' - shell: bash - run: . ci/funs.sh && nimCiSystemInfo - - - name: 'Build csourcesAny' - shell: bash - run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}' - - - name: 'koch, Run CI' - shell: bash - run: . ci/funs.sh && nimInternalBuildKochAndRunCI diff --git a/.github/workflows/ci_publish.yml b/.github/workflows/ci_publish.yml deleted file mode 100644 index d6b628d8c..000000000 --- a/.github/workflows/ci_publish.yml +++ /dev/null @@ -1,90 +0,0 @@ -name: Tracking orc-booting compiler memory usage - -on: - pull_request_target: - types: [closed] - - -jobs: - build: - if: github.event.pull_request.merged == true - strategy: - fail-fast: false - matrix: - os: [ubuntu-20.04] - cpu: [amd64] - name: '${{ matrix.os }}' - runs-on: ${{ matrix.os }} - steps: - - name: 'Checkout' - uses: actions/checkout@v3 - with: - fetch-depth: 2 - - - name: 'Install node.js 16.x' - uses: actions/setup-node@v3 - with: - node-version: '16.x' - - - name: 'Install dependencies (Linux amd64)' - if: runner.os == 'Linux' && matrix.cpu == 'amd64' - run: | - sudo apt-fast update -qq - DEBIAN_FRONTEND='noninteractive' \ - sudo apt-fast install --no-install-recommends -yq \ - libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \ - valgrind libc6-dbg libblas-dev xorg-dev - - name: 'Install dependencies (macOS)' - if: runner.os == 'macOS' - run: brew install boehmgc make sfml gtk+3 - - name: 'Install dependencies (Windows)' - if: runner.os == 'Windows' - shell: bash - run: | - set -e - . ci/funs.sh - nimInternalInstallDepsWindows - echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}" - - - name: 'Add build binaries to PATH' - shell: bash - run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" - - - name: 'System information' - shell: bash - run: . ci/funs.sh && nimCiSystemInfo - - - name: 'Build csourcesAny' - shell: bash - run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}' - - - name: 'Build koch' - shell: bash - run: nim c koch - - - name: 'Build Nim' - shell: bash - run: ./koch boot -d:release -d:nimStrictMode --lib:lib - - - name: 'Action' - shell: bash - run: nim c -r -d:release ci/action.nim - - - name: 'Comment' - uses: actions/github-script@v6 - with: - script: | - const fs = require('fs'); - - try { - const data = fs.readFileSync('ci/nimcache/results.txt', 'utf8'); - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: data - }) - } catch (err) { - console.error(err); - } - diff --git a/.gitignore b/.gitignore index d0c4558df..fc090130b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,17 +3,15 @@ !*.* # Cache -nimcache*/ -rnimcache*/ -dnimcache*/ +nimcache/ +rnimcache/ +dnimcache/ *.o !/icons/*.o *.obj *.ilk -*.exp *.pdb -*.lib *.dll *.exe *.so @@ -21,7 +19,6 @@ dnimcache*/ *.zip *.iss *.log -*.pdb mapping.txt tags @@ -30,10 +27,10 @@ deinstall.sh doc/html/ doc/*.html -doc/pdf +doc/*.pdf doc/*.idx /web/upload -/build/* +build/* bin/* # iOS specific wildcards. @@ -43,70 +40,24 @@ bin/* *.perspectivev3 *.swp .DS_Store -.tags project.xcworkspace/ xcuserdata/ # Generated files. /compile.json -/compiler/nim.dot +/compiler/nimrod.dot /reject.json /run.json -/tools/dochack/dochack.js -*.json -/pkgstemp/**/* -# for `nim doc foo.nim` -/*.html -lib/**/*.html -#/testresults.html #covered by /*.html - +/testresults.html /testresults.json testament.db -/tests/**/*.json -/tests/**/*.js - /csources -/csources_v1 -/csources_v2 - -/dist/ -# /lib/fusion # fusion is now unbundled; `git status` should reveal if it's there so users can act on it +dist/ # Private directories and files (IDEs) .*/ ~* -# testament cruft; TODO: generate these in a gitignore'd dir (./build) in the first place. +# testament cruft testresults/ test.txt -/test.ini - -tweeter.db -tweeter_test.db - -/tests/megatest.nim -/tests/ic/*_temp.nim -/tests/navigator/*_temp.nim - - -/outputExpected.txt -/outputGotten.txt -/t15148.txt -/tests/vm/tfile_rw.txt - -/lib/pure/*.js - -!/.builds/ - -!/.github - -# ignore debug dirs generated by dsymutil on OSX -*.dSYM - -# for `nim c -r nimdoc/tester` etc; this can be in multiple places -htmldocs - -## these are not needed anymore unless checkout old older versions -nimdoc.out.css -# except here: -!/nimdoc/testproject/expected/* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 31908d223..c37b4c8d4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,4 @@ -# xxx unused, out of date - -image: ubuntu:18.04 +image: ubuntu:16.04 stages: - pre-build @@ -55,8 +53,9 @@ test-windows: <<: *win_set_path_def script: - call ci\deps.bat - - nim c testament\tester - - testament\tester.exe all + - nim c --taintMode:on tests\testament\tester + - tests\testament\tester.exe --pedantic all tags: - windows - fast + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..5a091d0c7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,55 @@ +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 + - libsfml-dev + +before_install: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install boehmgc; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install sfml; fi + +before_script: + - set -e + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then unset -f cd; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then shell_session_update() { :; }; fi + - git clone --depth 1 https://github.com/nim-lang/csources.git + - cd csources + - sh build.sh + - cd .. + - export PATH=$(pwd)/bin${PATH:+:$PATH} +script: + - nim c koch + - ./koch boot + - ./koch boot -d:release + - ./koch nimble + - nim e tests/test_nimscript.nims + - nimble install zip -y + - nimble install opengl + - nimble install sdl1 + - nimble install jester@#head + - nimble install niminst + - nim c --taintMode:on -d:nimCoroutines tests/testament/tester + - tests/testament/tester --pedantic all -d:nimCoroutines + - nim c -o:bin/nimpretty nimpretty/nimpretty.nim + - nim c -r nimpretty/tester.nim + - ./koch web + - ./koch csource + - ./koch nimsuggest +# - nim c -r nimsuggest/tester + - ( ! grep -F '.. code-block' -l -r --include '*.html' --exclude contributing.html --exclude docgen.html --exclude tut2.html ) + - ( ! grep -F '..code-block' -l -r --include '*.html' --exclude contributing.html --exclude docgen.html --exclude tut2.html ) diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..daa1d4e48 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,64 @@ +version: '{build}' + +cache: +- x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z +- sqlite-dll-win64-x64-3160200.zip +# - i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + +matrix: + fast_finish: true + +environment: + matrix: + - MINGW_DIR: mingw64 + MINGW_URL: https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.9.2/threads-win32/seh/x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z/download + MINGW_ARCHIVE: x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z + SQLITE_URL: http://www.sqlite.org/2017/sqlite-dll-win64-x64-3160200.zip + SQLITE_ARCHIVE: sqlite-dll-win64-x64-3160200.zip + platform: x64 + # - MINGW_DIR: mingw32 + # MINGW_URL: https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/4.9.2/threads-win32/dwarf/i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z/download + # MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + # SQLITE_URL: http://www.sqlite.org/2017/sqlite-dll-win32-x86-3160200.zip + # SQLITE_ARCHIVE: sqlite-dll-win32-x86-3160200.zip + # platform: x86 + +install: + - ps: Install-Product node 8 # node 8 or later is required to test js async stuff + - MKDIR %CD%\DIST + - MKDIR %CD%\DIST\PCRE + - nuget install pcre -Verbosity quiet -Version 8.33.0.1 -OutputDirectory %CD%\DIST\PCRE + - IF not exist "%SQLITE_ARCHIVE%" appveyor DownloadFile "%SQLITE_URL%" -FileName "%SQLITE_ARCHIVE%" + - 7z x -y "%SQLITE_ARCHIVE%" -o"%CD%\DIST"> nul + - IF not exist "%MINGW_ARCHIVE%" appveyor DownloadFile "%MINGW_URL%" -FileName "%MINGW_ARCHIVE%" + - 7z x -y "%MINGW_ARCHIVE%" -o"%CD%\DIST"> nul + - SET PATH=%CD%\DIST\%MINGW_DIR%\BIN;%CD%\BIN;%PATH% + - IF "%PLATFORM%" == "x64" ( copy C:\OpenSSL-Win64\libeay32.dll %CD%\BIN\libeay64.dll & copy C:\OpenSSL-Win64\libeay32.dll %CD%\BIN\libeay32.dll & copy C:\OpenSSL-Win64\libssl32.dll %CD%\BIN\libssl64.dll & copy C:\OpenSSL-Win64\libssl32.dll %CD%\BIN\libssl32.dll ) + ELSE ( copy C:\OpenSSL-Win32\libeay32.dll %CD%\BIN\libeay32.dll & copy C:\OpenSSL-Win32\libssl32.dll %CD%\BIN\libssl32.dll ) + - IF "%PLATFORM%" == "x64" ( copy %CD%\DIST\sqlite3.dll %CD%\BIN\sqlite3_64.dll ) ELSE ( copy %CD%\DIST\sqlite3.dll %CD%\BIN\sqlite3_32.dll ) + - IF "%PLATFORM%" == "x64" ( copy %CD%\DIST\PCRE\pcre.redist.8.33.0.1\build\native\bin\v100\x64\Release\dynamic\utf8\pcre8.dll %CD%\bin\pcre64.dll ) ELSE ( copy %CD%\DIST\PCRE\pcre.redist.8.33.0.1\build\native\bin\v100\Win32\Release\dynamic\utf8\pcre8.dll %CD%\bin\pcre32.dll ) + - git clone --depth 1 https://github.com/nim-lang/csources + - cd csources + - IF "%PLATFORM%" == "x64" ( build64.bat ) else ( build.bat ) + - cd .. + +build_script: + - bin\nim c koch + - koch boot -d:release + - koch nimble + - nim e tests/test_nimscript.nims + - nim c -o:bin/nimpretty.exe nimpretty/nimpretty.nim + - nim c -r nimpretty/tester.nim + - nimble install zip -y + - nimble install opengl + - nimble install sdl1 + - nimble install jester@#head + - nimble install niminst + - nim c --taintMode:on -d:nimCoroutines tests/testament/tester + +test_script: + - tests\testament\tester --pedantic all -d:nimCoroutines +# - koch csource +# - koch zip + +deploy: off diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index d034e3b9b..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,168 +0,0 @@ -trigger: - branches: - include: - - 'devel' - - 'version-*' -pr: - branches: - include: - - '*' - -variables: -- name: skipci - value: false - -jobs: -- job: packages - - timeoutInMinutes: 90 # default `60` led to lots of cancelled jobs; use 0 for unlimited (may be undesirable) - - strategy: - matrix: - Linux_amd64: - vmImage: 'ubuntu-20.04' - CPU: amd64 - # regularly breaks, refs bug #17325 - Linux_i386: - # on 'ubuntu-16.04' (not supported anymore anyways) it errored with: - # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed - vmImage: 'ubuntu-18.04' - CPU: i386 - OSX_amd64: - vmImage: 'macOS-11' - CPU: amd64 - OSX_amd64_cpp: - vmImage: 'macOS-11' - CPU: amd64 - NIM_COMPILE_TO_CPP: true - Windows_amd64_batch0_3: - vmImage: 'windows-2019' - CPU: amd64 - # see also: `NIM_TEST_PACKAGES` - NIM_TESTAMENT_BATCH: "0_3" - Windows_amd64_batch1_3: - vmImage: 'windows-2019' - CPU: amd64 - NIM_TESTAMENT_BATCH: "1_3" - Windows_amd64_batch2_3: - vmImage: 'windows-2019' - CPU: amd64 - NIM_TESTAMENT_BATCH: "2_3" - - pool: - vmImage: $(vmImage) - - workspace: - clean: all - - steps: - - bash: git config --global core.autocrlf false - displayName: 'Disable auto conversion to CRLF by git (Windows-only)' - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - - - checkout: self - fetchDepth: 2 # see D20210329T004830 - - - bash: | - set -e - . ci/funs.sh - if nimIsCiSkip; then - echo '##vso[task.setvariable variable=skipci]true' - fi - displayName: 'Check whether to skip CI' - - - task: NodeTool@0 - inputs: - versionSpec: '16.x' - displayName: 'Install node.js 16.x' - condition: and(succeeded(), eq(variables['skipci'], 'false')) - - - bash: | - set -e - . ci/funs.sh - echo_run sudo apt-fast update -qq - DEBIAN_FRONTEND='noninteractive' \ - echo_run sudo apt-fast install --no-install-recommends -yq \ - libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg - displayName: 'Install dependencies (amd64 Linux)' - condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64')) - - - bash: | - set -e - . ci/funs.sh - echo_run sudo dpkg --add-architecture i386 - # Downgrade llvm: - # - llvm has to be downgraded to have 32bit version installed for sfml. - - cat << EOF | sudo tee /etc/apt/preferences.d/pin-to-rel - Package: libllvm6.0 - Pin: origin "azure.archive.ubuntu.com" - Pin-Priority: 1001 - EOF - - # echo_run sudo apt-fast update -qq - echo_run sudo apt-fast update -qq || echo "failed, see bug #17343" - # `:i386` (e.g. in `libffi-dev:i386`) is needed otherwise you may get: - # `could not load: libffi.so` during dynamic loading. - DEBIAN_FRONTEND='noninteractive' \ - echo_run sudo apt-fast install --no-install-recommends --allow-downgrades -yq \ - g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \ - libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386 libffi-dev:i386 - - cat << EOF > bin/gcc - #!/bin/bash - - exec $(which gcc) -m32 "\$@" - EOF - - cat << EOF > bin/g++ - #!/bin/bash - - exec $(which g++) -m32 "\$@" - EOF - - echo_run chmod 755 bin/gcc - echo_run chmod 755 bin/g++ - - displayName: 'Install dependencies (i386 Linux)' - condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386')) - - - bash: brew install boehmgc make sfml - displayName: 'Install dependencies (OSX)' - condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Darwin')) - - - bash: | - set -e - . ci/funs.sh - nimInternalInstallDepsWindows - echo_run echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/dist/mingw64/bin' - - displayName: 'Install dependencies (Windows)' - condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Windows_NT')) - - - bash: echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/bin' - condition: and(succeeded(), eq(variables['skipci'], 'false')) - displayName: 'Add build binaries to PATH' - - - bash: . ci/funs.sh && nimCiSystemInfo - condition: and(succeeded(), eq(variables['skipci'], 'false')) - displayName: 'System information' - - - bash: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu=$(CPU) - condition: and(succeeded(), eq(variables['skipci'], 'false')) - displayName: 'Build csourcesAny' - - # this could be revived if performance justifies it (needs a few updates) - # - task: Cache@2 - # inputs: - # key: 'csourcesAny | "$(Agent.OS)" | $(CPU) | $(csources_version)' - # path: $(nim_csources) - # condition: and(succeeded(), eq(variables['skipci'], 'false')) - # displayName: 'Restore built csourcesAny' - - - bash: . ci/funs.sh && nimInternalBuildKochAndRunCI - # would could also show on failure: echo '##vso[task.complete result=Failed]' - condition: and(succeeded(), eq(variables['skipci'], 'false')) - displayName: 'koch, Run CI' - env: - SYSTEM_ACCESSTOKEN: $(System.AccessToken) diff --git a/bin/nim-gdb b/bin/nim-gdb deleted file mode 100755 index d4d60e432..000000000 --- a/bin/nim-gdb +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -# Exit if anything fails -set -e - -which nim > /dev/null || (echo "nim not in PATH"; exit 1) -which gdb > /dev/null || (echo "gdb not in PATH"; exit 1) -which readlink > /dev/null || (echo "readlink not in PATH."; exit 1) - -if [[ $(uname -s) == Darwin || $(uname -s) == *BSD ]]; then - NIM_SYSROOT=$(dirname $(dirname $(readlink -f $(which nim)))) -else - NIM_SYSROOT=$(dirname $(dirname $(readlink -e $(which nim)))) -fi - -# Find out where the pretty printer Python module is -GDB_PYTHON_MODULE_PATH="$NIM_SYSROOT/tools/debug/nim-gdb.py" - -# Run GDB with the additional arguments that load the pretty printers -# Set the environment variable `NIM_GDB` to overwrite the call to a -# different/specific command (defaults to `gdb`). -NIM_GDB="${NIM_GDB:-gdb}" -# exec replaces the new process of bash with gdb. It is always good to -# have fewer processes. -exec "${NIM_GDB}" -eval-command="source $GDB_PYTHON_MODULE_PATH" "$@" diff --git a/bin/nim-gdb.bat b/bin/nim-gdb.bat deleted file mode 100644 index b5537dd9d..000000000 --- a/bin/nim-gdb.bat +++ /dev/null @@ -1,14 +0,0 @@ -@echo off -for %%i in (nim.exe) do (set NIM_BIN=%%~dp$PATH:i) - -for %%i in ("%NIM_BIN%\..\") do (set NIM_ROOT=%%~fi) - -set @GDB_PYTHON_MODULE_PATH=%NIM_ROOT%\tools\debug\nim-gdb.py -set @NIM_GDB=gdb.exe - -@echo source %@GDB_PYTHON_MODULE_PATH%> wingdbcommand.txt -%@NIM_GDB% --command="wingdbcommand.txt" %* -del wingdbcommand.txt /f /q - -EXIT /B %ERRORLEVEL% -@echo on diff --git a/build_all.bat b/build_all.bat deleted file mode 100644 index ef4a5f6a4..000000000 --- a/build_all.bat +++ /dev/null @@ -1,29 +0,0 @@ -@echo off -rem DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` -rem Build development version of the compiler; can be rerun safely -rem bare bones version of ci/funs.sh adapted for windows. - -rem Read in some common shared variables (shared with other tools), -rem see https://stackoverflow.com/questions/3068929/how-to-read-file-contents-into-a-variable-in-a-batch-file -for /f "delims== tokens=1,2" %%G in (config/build_config.txt) do set %%G=%%H -SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe -echo "building from csources: %nim_csources%" - -if not exist %nim_csourcesDir% ( - git clone -q --depth 1 -b %nim_csourcesBranch% %nim_csourcesUrl% %nim_csourcesDir% -) - -if not exist %nim_csources% ( - cd %nim_csourcesDir% - git checkout %nim_csourcesHash% - echo "%PROCESSOR_ARCHITECTURE%" - if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( - SET ARCH=64 - ) - CALL build.bat - cd .. - copy /y bin\nim.exe %nim_csources% -) - bin\nim.exe c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch - koch boot -d:release --skipUserCfg --skipParentCfg --hints:off - koch tools --skipUserCfg --skipParentCfg --hints:off diff --git a/build_all.sh b/build_all.sh deleted file mode 100755 index 83848f41a..000000000 --- a/build_all.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -# DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` - -# build development version of the compiler; can be rerun safely. -# arguments can be passed, e.g.: -# CC=gcc ucpu=amd64 uos=darwin - -set -u # error on undefined variables -set -e # exit on first error - -. ci/funs.sh -nimBuildCsourcesIfNeeded "$@" - -echo_run bin/nim c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch -echo_run ./koch boot -d:release --skipUserCfg --skipParentCfg --hints:off -echo_run ./koch tools --skipUserCfg --skipParentCfg --hints:off - diff --git a/changelog.md b/changelog.md index 2db577d0b..7c5c70ecf 100644 --- a/changelog.md +++ b/changelog.md @@ -1,31 +1,191 @@ -# v2.2.0 - yyyy-mm-dd +## v0.19.X - XX/XX/2018 + +### Changes affecting backwards compatibility + +- The stdlib module ``future`` has been renamed to ``sugar``. +- ``macros.callsite`` is now deprecated. Since the introduction of ``varargs`` + parameters this became unnecessary. +- Anonymous tuples with a single element can now be written as ``(1,)`` with a + trailing comma. The underlying AST is ``nnkTupleConst(newLit 1)`` for this + example. ``nnkTupleConstr`` is a new node kind your macros need to be able + to deal with! +- Indexing into a ``cstring`` for the JS target is now mapped + to ``charCodeAt``. +- Assignments that would "slice" an object into its supertype are now prevented + at runtime. Use ``ref object`` with inheritance rather than ``object`` with + inheritance to prevent this issue. +- The ``not nil`` type annotation now has to be enabled explicitly + via ``{.experimental: "notnil"}`` as we are still not pleased with how this + feature works with Nim's containers. +- The parser now warns about inconsistent spacing around binary operators as + these can easily be confused with unary operators. This warning will likely + become an error in the future. -## Changes affecting backward compatibility +#### Breaking changes in the standard library + +- ``re.split`` for empty regular expressions now yields every character in + the string which is what other programming languages chose to do. +- The returned tuple of ``system.instantiationInfo`` now has a third field + containing the column of the instantiation. + +- ``cookies.setCookie`` no longer assumes UTC for the expiration date. +- ``strutils.formatEng`` does not distinguish between ``nil`` and ``""`` + strings anymore for its ``unit`` parameter. Instead the space is controlled + by a new parameter ``useUnitSpace``. + +- ``proc `-`*(a, b: Time): int64`` in the ``times`` module has changed return type + to ``times.Duration`` in order to support higher time resolutions. + The proc is no longer deprecated. +- ``posix.Timeval.tv_sec`` has changed type to ``posix.Time``. + +- ``math.`mod` `` for floats now behaves the same as ``mod`` for integers + (previously it used floor division like Python). Use ``math.floorMod`` for the old behavior. + +- For string inputs, ``unicode.isUpper`` and ``unicode.isLower`` now require a + second mandatory parameter ``skipNonAlpha``. + +- For string inputs, ``strutils.isUpperAscii`` and ``strutils.isLowerAscii`` now + require a second mandatory parameter ``skipNonAlpha``. + +- The procs ``parseHexInt`` and ``parseOctInt`` now fail on empty strings + and strings containing only valid prefixes, e.g. "0x" for hex integers. -## Standard library additions and changes +#### Breaking changes in the compiler -[//]: # "Changes:" +- The undocumented ``#? braces`` parsing mode was removed. +- The undocumented PHP backend was removed. + +### Library additions + +- ``re.split`` now also supports the ``maxsplit`` parameter for consistency + with ``strutils.split``. +- Added ``system.toOpenArray`` in order to support zero-copy slicing + operations. This is currently not yet available for the JavaScript target. +- Added ``getCurrentDir``, ``findExe``, ``cpDir`` and ``mvDir`` procs to + ``nimscript``. +- The ``times`` module now supports up to nanosecond time resolution when available. +- Added the type ``times.Duration`` for representing fixed durations of time. +- Added the proc ``times.convert`` for converting between different time units, + e.g days to seconds. +- Added the proc ``algorithm.binarySearch[T, K]`` with the ```cmp``` parameter. +- Added the proc ``algorithm.upperBound``. +- Added inverse hyperbolic functions, ``math.arcsinh``, ``math.arccosh`` and ``math.arctanh`` procs. +- Added cotangent, secant and cosecant procs ``math.cot``, ``math.sec`` and ``math.csc``; and their hyperbolic, inverse and inverse hyperbolic functions, ``math.coth``, ``math.sech``, ``math.csch``, ``math.arccot``, ``math.arcsec``, ``math.arccsc``, ``math.arccoth``, ``math.arcsech`` and ``math.arccsch`` procs. +- Added the procs ``math.floorMod`` and ``math.floorDiv`` for floor based integer division. +- Added the procs ``rationals.`div```, ``rationals.`mod```, ``rationals.floorDiv`` and ``rationals.floorMod`` for rationals. +- Added the proc ``math.prod`` for product of elements in openArray. +- Added the proc ``parseBinInt`` to parse a binary integer from a string, which returns the value. +- ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt`` +- Added the proc ``flush`` for memory mapped files. +- Added the ``MemMapFileStream``. + +### Library changes + +- ``macros.astGenRepr``, ``macros.lispRepr`` and ``macros.treeRepr`` + now escapes the content of string literals consistently. +- ``macros.NimSym`` and ``macros.NimIdent`` is now deprecated in favor + of the more general ``NimNode``. +- ``macros.getImpl`` now includes the pragmas of types, instead of omitting them. +- ``macros.hasCustomPragma`` and ``macros.getCustomPragmaVal`` now + also support ``ref`` and ``ptr`` types, pragmas on types and variant + fields. +- ``system.SomeReal`` is now called ``SomeFloat`` for consistency and + correctness. +- ``algorithm.smartBinarySearch`` and ``algorithm.binarySearch`` is + now joined in ``binarySearch``. ``smartbinarySearch`` is now + deprecated. +- The `terminal` module now exports additional procs for generating ANSI color + codes as strings. +- Added the parameter ``val`` for the ``CritBitTree[int].inc`` proc. +- An exception raised from a ``test`` block of ``unittest`` now shows its type in + error message. +- The ``compiler/nimeval`` API was rewritten to simplify the "compiler as an + API". Using the Nim compiler and its VM as a scripting engine has never been + easier. See ``tests/compilerapi/tcompilerapi.nim`` for an example of how to + use the Nim VM in a native Nim application. +- Added the parameter ``val`` for the ``CritBitTree[T].incl`` proc. +- The proc ``tgamma`` was renamed to ``gamma``. ``tgamma`` is deprecated. +- The ``pegs`` module now exports getters for the fields of its ``Peg`` and ``NonTerminal`` + object types. ``Peg``s with child nodes now have the standard ``items`` and ``pairs`` + iterators. + +### Language additions + +- Dot calls combined with explicit generic instantiations can now be written + as ``x.y[:z]`` which is transformed into ``y[z](x)`` by the parser. +- ``func`` is now an alias for ``proc {.noSideEffect.}``. +- In order to make ``for`` loops and iterators more flexible to use Nim now + supports so called "for-loop macros". See + the `manual `_ for more details. +- the `typedesc` special type has been renamed to just `type`. +- `static` and `type` are now also modifiers similar to `ref` and `ptr`. + They denote the special types `static[T]` and `type[T]`. +- Forcing compile-time evaluation with `static` now supports specifying + the desired target type (as a concrete type or as a type class) +- The `type` operator now supports checking that the supplied expression + matches an expected type constraint. + +### Language changes + +- The `importcpp` pragma now allows importing the listed fields of generic + C++ types. Support for numeric parameters have also been added through + the use of `static[T]` types. + (#6415) + +- Native C++ exceptions can now be imported with `importcpp` pragma. + Imported exceptions can be raised and caught just like Nim exceptions. + More details in language manual. + +- ``nil`` for strings/seqs is finally gone. Instead the default value for + these is ``"" / @[]``. + +- Accessing the binary zero terminator in Nim's native strings + is now invalid. Internally a Nim string still has the trailing zero for + zero-copy interoperability with ``cstring``. Compile your code with the + new switch ``--laxStrings:on`` if you need a transition period. + +- The command syntax now supports keyword arguments after the first comma. + +- Thread-local variables can now be declared inside procs. This implies all + the effects of the `global` pragma. + +- Nim now supports `except` clause in the export statement. + +- Range float types, example `range[0.0 .. Inf]`. More details in language manual. + +### Tool changes + +- ``jsondoc2`` has been renamed ``jsondoc``, similar to how ``doc2`` was renamed + ``doc``. The old ``jsondoc`` can still be invoked with ``jsondoc0``. + +### Compiler changes + +- The VM's instruction count limit was raised to 1 billion instructions in + order to support more complex computations at compile-time. + +- Support for hot code reloading has been implemented for the JavaScript + target. To use it, compile your code with `--hotCodeReloading:on` and use a + helper library such as LiveReload or BrowserSync. + +- A new compiler option `--cppCompileToNamespace` puts the generated C++ code + into the namespace "Nim" in order to avoid naming conflicts with existing + C++ code. This is done for all Nim code - internal and exported. + +- Added ``macros.getProjectPath`` and ``ospaths.putEnv`` procs to Nim's virtual + machine. + +- The ``deadCodeElim`` option is now always turned on and the switch has no + effect anymore, but is recognized for backwards compatibility. + +- ``experimental`` is now a pragma / command line switch that can enable specific + language extensions, it is not an all-or-nothing switch anymore. + +- Nintendo Switch was added as a new platform target. See [the compiler user guide](https://nim-lang.org/docs/nimc.html) + for more info. + +- Compiler switch ``--uniqueMain`` was added. See [the compiler user guide](https://nim-lang.org/docs/nimc.html#linking-a-nim-generated-static-library-in-nim) for more info. -[//]: # "Additions:" -- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes. - -[//]: # "Deprecations:" - - -[//]: # "Removals:" - - -## Language changes - - - -## Compiler changes - - - - -## Tool changes - +### Bugfixes diff --git a/changelogs/changelog_0_18_1.md b/changelogs/changelog_0_18_1.md deleted file mode 100644 index d0b7fd8ee..000000000 --- a/changelogs/changelog_0_18_1.md +++ /dev/null @@ -1,663 +0,0 @@ -## v0.18.0 - 01/03/2018 - -### Changes affecting backwards compatibility - -#### Breaking changes in the standard library - -- The ``[]`` proc for strings now raises an ``IndexError`` exception when - the specified slice is out of bounds. See issue - [#6223](https://github.com/nim-lang/Nim/issues/6223) for more details. - You can use ``substr(str, start, finish)`` to get the old behaviour back, - see [this commit](https://github.com/nim-lang/nimbot/commit/98cc031a27ea89947daa7f0bb536bcf86462941f) for an example. - -- ``strutils.split`` and ``strutils.rsplit`` with an empty string and a - separator now returns that empty string. - See issue [#4377](https://github.com/nim-lang/Nim/issues/4377). - -- Arrays of char cannot be converted to ``cstring`` anymore, pointers to - arrays of char can! This means ``$`` for arrays can finally exist - in ``system.nim`` and do the right thing. This means ``$myArrayOfChar`` changed - its behaviour! Compile with ``-d:nimNoArrayToString`` to see where to fix your - code. - -- `reExtended` is no longer default for the `re` constructor in the `re` - module. - -- The behavior of ``$`` has been changed for all standard library collections. The - collection-to-string implementations now perform proper quoting and escaping of - strings and chars. - -- `newAsyncSocket` taking an `AsyncFD` now runs `setBlocking(false)` on the - fd. - -- ``mod`` and bitwise ``and`` do not produce ``range`` subtypes anymore. This - turned out to be more harmful than helpful and the language is simpler - without this special typing rule. - -- ``formatFloat``/``formatBiggestFloat`` now support formatting floats with zero - precision digits. The previous ``precision = 0`` behavior (default formatting) - is now available via ``precision = -1``. - -- Moved from stdlib into Nimble packages: - - [``basic2d``](https://github.com/nim-lang/basic2d) - _deprecated: use ``glm``, ``arraymancer``, ``neo``, or another package instead_ - - [``basic3d``](https://github.com/nim-lang/basic3d) - _deprecated: use ``glm``, ``arraymancer``, ``neo``, or another package instead_ - - [``gentabs``](https://github.com/lcrees/gentabs) - - [``libuv``](https://github.com/lcrees/libuv) - - [``numeric``](https://github.com/lcrees/polynumeric) - - [``poly``](https://github.com/lcrees/polynumeric) - - [``pdcurses``](https://github.com/lcrees/pdcurses) - - [``romans``](https://github.com/lcrees/romans) - - [``libsvm``](https://github.com/nim-lang/libsvm_legacy) - - [``joyent_http_parser``](https://github.com/nim-lang/joyent_http_parser) - -- Proc [toCountTable](https://nim-lang.org/docs/tables.html#toCountTable,openArray[A]) - now produces a `CountTable` with values correspoding to the number of occurrences - of the key in the input. It used to produce a table with all values set to `1`. - - Counting occurrences in a sequence used to be: - - ```nim - let mySeq = @[1, 2, 1, 3, 1, 4] - var myCounter = initCountTable[int]() - - for item in mySeq: - myCounter.inc item - ``` - - Now, you can simply do: - - ```nim - let - mySeq = @[1, 2, 1, 3, 1, 4] - myCounter = mySeq.toCountTable() - ``` - -- If you use ``--dynlibOverride:ssl`` with OpenSSL 1.0.x, you now have to - define ``openssl10`` symbol (``-d:openssl10``). By default OpenSSL 1.1.x is - assumed. - -- ``newNativeSocket`` is now named ``createNativeSocket``. - -- ``newAsyncNativeSocket`` is now named ``createAsyncNativeSocket`` - and it no longer raises an OS error but returns an ``osInvalidSocket`` when - creation fails. - -- The ``securehash`` module is now deprecated. Instead import ``std / sha1``. - -- The ``readPasswordFromStdin`` proc has been moved from the ``rdstdin`` - to the ``terminal`` module, thus it does not depend on linenoise anymore. - -#### Breaking changes in the compiler - -- ``\n`` is now only the single line feed character like in most - other programming languages. The new platform specific newline escape sequence is - written as ``\p``. This change only affects the Windows platform. - -- The overloading rules changed slightly so that constrained generics are - preferred over unconstrained generics. (Bug #6526) - -- We changed how array accesses "from backwards" like ``a[^1]`` or ``a[0..^1]`` are - implemented. These are now implemented purely in ``system.nim`` without compiler - support. There is a new "heterogeneous" slice type ``system.HSlice`` that takes 2 - generic parameters which can be ``BackwardsIndex`` indices. ``BackwardsIndex`` is - produced by ``system.^``. - This means if you overload ``[]`` or ``[]=`` you need to ensure they also work - with ``system.BackwardsIndex`` (if applicable for the accessors). - -- The parsing rules of ``if`` expressions were changed so that multiple - statements are allowed in the branches. We found few code examples that - now fail because of this change, but here is one: - -```nim -t[ti] = if exp_negative: '-' else: '+'; inc(ti) -``` - -This now needs to be written as: - -```nim -t[ti] = (if exp_negative: '-' else: '+'); inc(ti) -``` - -- The experimental overloading of the dot ``.`` operators now take - an ``untyped``` parameter as the field name, it used to be - a ``static[string]``. You can use ``when defined(nimNewDot)`` to make - your code work with both old and new Nim versions. - See [special-operators](https://nim-lang.org/docs/manual.html#special-operators) - for more information. - -- ``yield`` (or ``await`` which is mapped to ``yield``) never worked reliably - in an array, seq or object constructor and is now prevented at compile-time. - -### Library additions - -- **Added ``sequtils.mapLiterals`` for easier construction of array and tuple literals.** - -- Added ``system.runnableExamples`` to make examples in Nim's documentation easier - to write and test. The examples are tested as the last step of - ``nim doc``. - -- Implemented ``getIoHandler`` proc in the ``asyncdispatch`` module that allows - you to retrieve the underlying IO Completion Port or ``Selector[AsyncData]`` - object in the specified dispatcher. - -- For string formatting / interpolation a new module - called [strformat](https://nim-lang.org/docs/strformat.html) has been added - to the stdlib. - -- The `ReadyKey` type in the selectors module now contains an ``errorCode`` - field to help distinguish between ``Event.Error`` events. - -- Implemented an `accept` proc that works on a `SocketHandle` in - ``nativesockets``. - -- Added ``algorithm.rotateLeft``. - -- Added ``typetraits.$`` as an alias for ``typetraits.name``. - -- Added ``system.getStackTraceEntries`` that allows you to access the stack - trace in a structured manner without string parsing. - -- Added ``parseutils.parseSaturatedNatural``. - -- Added ``macros.unpackVarargs``. - -- Added support for asynchronous programming for the JavaScript backend using - the `asyncjs` module. - -- Added true color support for some terminals. Example: -```nim -import colors, terminal - -const Nim = "Efficient and expressive programming." - -var - fg = colYellow - bg = colBlue - int = 1.0 - -enableTrueColors() - -for i in 1..15: - styledEcho bgColor, bg, fgColor, fg, Nim, resetStyle - int -= 0.01 - fg = intensity(fg, int) - -setForegroundColor colRed -setBackgroundColor colGreen -styledEcho "Red on Green.", resetStyle -``` - -### Library changes - -- ``echo`` now works with strings that contain ``\0`` (the binary zero is not - shown) and ``nil`` strings are equal to empty strings. - -- JSON: Deprecated `getBVal`, `getFNum`, and `getNum` in favour of - `getBool`, `getFloat`, `getBiggestInt`. A new `getInt` procedure was also - added. - -- ``rationals.toRational`` now uses an algorithm based on continued fractions. - This means its results are more precise and it can't run into an infinite loop - anymore. - -- ``os.getEnv`` now takes an optional ``default`` parameter that tells ``getEnv`` - what to return if the environment variable does not exist. - -- The ``random`` procs in ``random.nim`` have all been deprecated. Instead use - the new ``rand`` procs. The module now exports the state of the random - number generator as type ``Rand`` so multiple threads can easily use their - own random number generators that do not require locking. For more information - about this rename see issue [#6934](https://github.com/nim-lang/Nim/issues/6934) - -- ``writeStackTrace`` is now proclaimed to have no IO effect (even though it does) - so that it is more useful for debugging purposes. - -- ``db_mysql`` module: ``DbConn`` is now a ``distinct`` type that doesn't expose the - details of the underlying ``PMySQL`` type. - -- ``parseopt2`` is now deprecated, use ``parseopt`` instead. - -### Language additions - -- It is now possible to forward declare object types so that mutually - recursive types can be created across module boundaries. See - [package level objects](https://nim-lang.org/docs/manual.html#package-level-objects) - for more information. - -- Added support for casting between integers of same bitsize in VM (compile time and nimscript). - This allows to, among other things, reinterpret signed integers as unsigned. - -- Custom pragmas are now supported using pragma ``pragma``, please see language - manual for details. - -- Standard library modules can now also be imported via the ``std`` pseudo-directory. - This is useful in order to distinguish between standard library and nimble package - imports: - - ```nim - import std / [strutils, os, osproc] - import someNimblePackage / [strutils, os] - ``` - -### Language changes - -- The **unary** ``<`` is now deprecated, for ``.. <`` use ``..<`` for other usages - use the ``pred`` proc. - -- Bodies of ``for`` loops now get their own scope: - -```nim -# now compiles: -for i in 0..4: - let i = i + 1 - echo i -``` - -- To make Nim even more robust the system iterators ``..`` and ``countup`` - now only accept a single generic type ``T``. This means the following code - doesn't die with an "out of range" error anymore: - -```nim -var b = 5.Natural -var a = -5 -for i in a..b: - echo i -``` - -- ``atomic`` and ``generic`` are no longer keywords in Nim. ``generic`` used to be - an alias for ``concept``, ``atomic`` was not used for anything. - -- The memory manager now uses a variant of the TLSF algorithm that has much - better memory fragmentation behaviour. According - to [http://www.gii.upv.es/tlsf/](http://www.gii.upv.es/tlsf/) the maximum - fragmentation measured is lower than 25%. As a nice bonus ``alloc`` and - ``dealloc`` became O(1) operations. - -- The compiler is now more consistent in its treatment of ambiguous symbols: - Types that shadow procs and vice versa are marked as ambiguous (bug #6693). - -- codegenDecl pragma now works for the JavaScript backend. It returns an empty - string for function return type placeholders. - -- Extra semantic checks for procs with noreturn pragma: return type is not allowed, - statements after call to noreturn procs are no longer allowed. - -- Noreturn proc calls and raising exceptions branches are now skipped during common type - deduction in ``if`` and ``case`` expressions. The following code snippets now compile: - ```nim - import strutils - let str = "Y" - let a = case str: - of "Y": true - of "N": false - else: raise newException(ValueError, "Invalid boolean") - let b = case str: - of nil, "": raise newException(ValueError, "Invalid boolean") - elif str.startsWith("Y"): true - elif str.startsWith("N"): false - else: false - let c = if str == "Y": true - elif str == "N": false - else: - echo "invalid bool" - quit("this is the end") - ``` - -- Pragmas now support call syntax, for example: ``{.exportc"myname".}`` and - ``{.exportc("myname").}`` - -- The ``deprecated`` pragma now supports a user-definable warning message for procs. - - ```nim - proc bar {.deprecated: "use foo instead".} = - return - - bar() - ``` - -### Tool changes - -- The ``nim doc`` command is now an alias for ``nim doc2``, the second version of - the documentation generator. The old version 1 can still be accessed - via the new ``nim doc0`` command. - -- Nim's ``rst2html`` command now supports the testing of code snippets via an RST - extension that we called ``:test:``:: - - ```rst - .. code-block:: nim - :test: - # shows how the 'if' statement works - if true: echo "yes" - ``` - -### Compiler changes - -### Bugfixes - -- Fixed "ReraiseError when using try/except within finally block" - ([#5871](https://github.com/nim-lang/Nim/issues/5871)) -- Fixed "Range type inference leads to counter-intuitive behvaiour" - ([#5854](https://github.com/nim-lang/Nim/issues/5854)) -- Fixed "JSON % operator can fail in extern procs with dynamic types" - ([#6385](https://github.com/nim-lang/Nim/issues/6385)) -- Fixed ""intVal is not accessible" in VM" - ([#6083](https://github.com/nim-lang/Nim/issues/6083)) -- Fixed "Add excl for OrderedSet" - ([#2467](https://github.com/nim-lang/Nim/issues/2467)) -- Fixed "newSeqOfCap actually doesn't reserve memory" - ([#6403](https://github.com/nim-lang/Nim/issues/6403)) -- Fixed "[Regression] Nim segfaults" - ([#6435](https://github.com/nim-lang/Nim/issues/6435)) -- Fixed "Seq assignment is slower than expected" - ([#6433](https://github.com/nim-lang/Nim/issues/6433)) -- Fixed "json module issues with empty dicts and lists" - ([#6438](https://github.com/nim-lang/Nim/issues/6438)) -- Fixed "mingw installed via finish.exe fails to link if Nim located in path with whitespace" - ([#6452](https://github.com/nim-lang/Nim/issues/6452)) -- Fixed "unittest.check does not perform short-circuit evaluation" - ([#5784](https://github.com/nim-lang/Nim/issues/5784)) -- Fixed "Error while concatenating an array of chars." - ([#5861](https://github.com/nim-lang/Nim/issues/5861)) -- Fixed "range initialization: [ProveInit] hint: Cannot prove that" - ([#6474](https://github.com/nim-lang/Nim/issues/6474)) -- Fixed "scanf can call procs with side-effects multiple times" - ([#6487](https://github.com/nim-lang/Nim/issues/6487)) -- Fixed "gcsafe detection problem" - ([#5620](https://github.com/nim-lang/Nim/issues/5620)) -- Fixed "C++ codegen: `mitems` generates invalid code." - ([#4910](https://github.com/nim-lang/Nim/issues/4910)) -- Fixed "strange runtime behavior on macOS" - ([#6496](https://github.com/nim-lang/Nim/issues/6496)) -- Fixed "stdtmpl: invalid indentation after a line ending in question mark" - ([#5070](https://github.com/nim-lang/Nim/issues/5070)) -- Fixed "Windows: NAN troubles on c backend" - ([#6511](https://github.com/nim-lang/Nim/issues/6511)) -- Fixed "lib/nim/system/cellsets.nim(33, 31) Error: type mismatch while attempting to compile for 16bit CPUs" - ([#3558](https://github.com/nim-lang/Nim/issues/3558)) -- Fixed "Can't compile dynlib with ``-d:useNimRtl`` and ``--threads:on``" - ([#5143](https://github.com/nim-lang/Nim/issues/5143)) -- Fixed "var s = @[0,1,2,...] can generate thousand of single assignments in C code" - ([#5007](https://github.com/nim-lang/Nim/issues/5007)) -- Fixed "`echo` discards everything after a null character" - ([#1137](https://github.com/nim-lang/Nim/issues/1137)) -- Fixed "Turn off reExtended by default" - ([#5627](https://github.com/nim-lang/Nim/issues/5627)) -- Fixed "Bad Links in docs/backends.html" - ([#5914](https://github.com/nim-lang/Nim/issues/5914)) -- Fixed "Index out of bounds error in db_postgres when executing non parameter-substituted queries containing "?"" - ([#6571](https://github.com/nim-lang/Nim/issues/6571)) -- Fixed "Please add pipe2 support to posix stdlib" - ([#6553](https://github.com/nim-lang/Nim/issues/6553)) -- Fixed "Return semantics vary depending on return style" - ([#6422](https://github.com/nim-lang/Nim/issues/6422)) -- Fixed "parsecsv.open reports SIGSEGV when calling 'open' on missing file" - ([#6148](https://github.com/nim-lang/Nim/issues/6148)) -- Fixed "VCC: Nim generates non-compilable code for system.nim" - ([#6606](https://github.com/nim-lang/Nim/issues/6606)) -- Fixed "Generic subtype matches worse than a generic" - ([#6526](https://github.com/nim-lang/Nim/issues/6526)) -- Fixed "formatFloat inconsistent scientific notation" - ([#6589](https://github.com/nim-lang/Nim/issues/6589)) -- Fixed "Generated c code calls function twice" - ([#6292](https://github.com/nim-lang/Nim/issues/6292)) -- Fixed "Range type inference leads to counter-intuitive behvaiour" - ([#5854](https://github.com/nim-lang/Nim/issues/5854)) -- Fixed "New backward indexing is too limited" - ([#6631](https://github.com/nim-lang/Nim/issues/6631)) -- Fixed "Table usage in a macro (SIGSEGV: Illegal storage access.)" - ([#1860](https://github.com/nim-lang/Nim/issues/1860)) -- Fixed "Incorrect deprecation error" - ([#6634](https://github.com/nim-lang/Nim/issues/6634)) -- Fixed "Wrong indices in arrays not starting with 0" - ([#6675](https://github.com/nim-lang/Nim/issues/6675)) -- Fixed "if expressions" - ([#6609](https://github.com/nim-lang/Nim/issues/6609)) -- Fixed "BackwardsIndex: converter + `[]` + unrelated type[^1]: lib/system.nim(3536, 3) Error" - ([#6692](https://github.com/nim-lang/Nim/issues/6692)) -- Fixed "BackwardsIndex: converter + `[]` + unrelated type[^1]: lib/system.nim(3536, 3) Error" - ([#6692](https://github.com/nim-lang/Nim/issues/6692)) -- Fixed "js backend 0.17.3: array bounds check for non zero based arrays is buggy" - ([#6532](https://github.com/nim-lang/Nim/issues/6532)) -- Fixed "HttpClient's new API doesn't work through a proxy for https URLs" - ([#6685](https://github.com/nim-lang/Nim/issues/6685)) -- Fixed "isServing isn't declared and isn't compiling" - ([#6707](https://github.com/nim-lang/Nim/issues/6707)) -- Fixed "[Regression] value out of range" - ([#6710](https://github.com/nim-lang/Nim/issues/6710)) - -- Fixed "Error when using `multisync` macro" - ([#6708](https://github.com/nim-lang/Nim/issues/6708)) - -- Fixed "formatFloat inconsistent scientific notation" - ([#6589](https://github.com/nim-lang/Nim/issues/6589)) -- Fixed "Using : (constructor arguments) for passing values to functions with default arguments causes a compiler crash." - ([#6765](https://github.com/nim-lang/Nim/issues/6765)) -- Fixed "In-place object initialization leads to vcc incompatible code" - ([#6757](https://github.com/nim-lang/Nim/issues/6757)) -- Fixed "Improve parseCookies doc" - ([#5721](https://github.com/nim-lang/Nim/issues/5721)) -- Fixed "Parser regression with nested do notation inside conditional" - ([#6166](https://github.com/nim-lang/Nim/issues/6166)) -- Fixed "Request for better error message" - ([#6776](https://github.com/nim-lang/Nim/issues/6776)) -- Fixed "Testament tester does not execute test with `exitcode` only" - ([#6775](https://github.com/nim-lang/Nim/issues/6775)) -- Fixed "JS integer division off by one" - ([#6753](https://github.com/nim-lang/Nim/issues/6753)) -- Fixed "Regression: cannot prove not nil" - ([#5781](https://github.com/nim-lang/Nim/issues/5781)) -- Fixed "SIGSEGV: Illegal storage access. (Attempt to read from nil?) in generic proc" - ([#6073](https://github.com/nim-lang/Nim/issues/6073)) -- Fixed "Request for better error message" - ([#6776](https://github.com/nim-lang/Nim/issues/6776)) -- Fixed "Nim #head: sorting via reference hangs compiler" - ([#6724](https://github.com/nim-lang/Nim/issues/6724)) -- Fixed "Cannot cast pointer to char in cpp" - ([#5979](https://github.com/nim-lang/Nim/issues/5979)) -- Fixed "asynchttpserver replies with several errors on single request" - ([#6386](https://github.com/nim-lang/Nim/issues/6386)) -- Fixed "object variants superclass trigger bad codegen" - ([#5521](https://github.com/nim-lang/Nim/issues/5521)) -- Fixed "JS integer division off by one" - ([#6753](https://github.com/nim-lang/Nim/issues/6753)) -- Fixed "js backend compiler crash with tables indexed by certain types" - ([#6568](https://github.com/nim-lang/Nim/issues/6568)) -- Fixed "Jsgen bug with is" - ([#6445](https://github.com/nim-lang/Nim/issues/6445)) -- Fixed "Subrange definition with ..<" - ([#6788](https://github.com/nim-lang/Nim/issues/6788)) -- Fixed "fields not initialized: array with enum index type as object field." - ([#6682](https://github.com/nim-lang/Nim/issues/6682)) -- Fixed "Can not delete data in table when table's data type is kind of "not nil"" - ([#6555](https://github.com/nim-lang/Nim/issues/6555)) -- Fixed "tables.nim: Cannot prove that 'n' is initialized" - ([#6121](https://github.com/nim-lang/Nim/issues/6121)) -- Fixed "issues with 'not nil' applied to a closure proc" - ([#6489](https://github.com/nim-lang/Nim/issues/6489)) -- Fixed "`not nil` not working in some cases" - ([#4686](https://github.com/nim-lang/Nim/issues/4686)) -- Fixed "Cannot prove '@[v]' is not nil" - ([#3993](https://github.com/nim-lang/Nim/issues/3993)) - -- Fixed "Feature: support TCP_NODELAY in net.sockets" - ([#6795](https://github.com/nim-lang/Nim/issues/6795)) -- Fixed "Code that makes the compiler throw an error message and then hangs" - ([#6820](https://github.com/nim-lang/Nim/issues/6820)) -- Fixed "Code that makes the compiler throw an error message and then hangs" - ([#6820](https://github.com/nim-lang/Nim/issues/6820)) -- Fixed "Inconsistent behavior with sequence and string slicing" - ([#6223](https://github.com/nim-lang/Nim/issues/6223)) -- Fixed "Wrong behavior of "split" (proc and iterator)" - ([#4377](https://github.com/nim-lang/Nim/issues/4377)) -- Fixed "[Documentation] Invalid module name: [foo, bar]" - ([#6831](https://github.com/nim-lang/Nim/issues/6831)) -- Fixed "The destructor is not called for temporary objects" - ([#4214](https://github.com/nim-lang/Nim/issues/4214)) -- Fixed "Destructors does not work with implicit items iterator in for loop" - ([#985](https://github.com/nim-lang/Nim/issues/985)) -- Fixed "Error in template when using the type of the parameter inside it" - ([#6756](https://github.com/nim-lang/Nim/issues/6756)) -- Fixed "should json.to() respect parent attributes?" - ([#5856](https://github.com/nim-lang/Nim/issues/5856)) -- Fixed "json 'to' macro can not marshalize into tuples" - ([#6095](https://github.com/nim-lang/Nim/issues/6095)) -- Fixed "json.to fails with seq[T]" - ([#6604](https://github.com/nim-lang/Nim/issues/6604)) -- Fixed "json.to() is not worth using compared to marshal.to[T]" - ([#5848](https://github.com/nim-lang/Nim/issues/5848)) -- Fixed "Memory not being released in time, running out of memory" - ([#6031](https://github.com/nim-lang/Nim/issues/6031)) -- Fixed "[Regression] Bad C codegen for generic code" - ([#6889](https://github.com/nim-lang/Nim/issues/6889)) -- Fixed "rollingFileLogger deletes file on every start." - ([#6264](https://github.com/nim-lang/Nim/issues/6264)) -- Fixed "Remove/deprecate securehash module." - ([#6033](https://github.com/nim-lang/Nim/issues/6033)) -- Fixed "[bug or not] object construction for seq[T] failed without space after colon" - ([#5999](https://github.com/nim-lang/Nim/issues/5999)) -- Fixed "issues with the random module" - ([#4726](https://github.com/nim-lang/Nim/issues/4726)) -- Fixed "Reassigning local var to seq of objects results in nil element in Object's seq field" - ([#668](https://github.com/nim-lang/Nim/issues/668)) -- Fixed "Compilation error with "newseq[string]"" - ([#6726](https://github.com/nim-lang/Nim/issues/6726)) -- Fixed "await inside array/dict literal produces invalid code - Part 2" - ([#6626](https://github.com/nim-lang/Nim/issues/6626)) -- Fixed "terminal.eraseline() gives OverflowError on Windows" - ([#6931](https://github.com/nim-lang/Nim/issues/6931)) -- Fixed "[Regression] `sequtils.any` conflicts with `system.any`" - ([#6932](https://github.com/nim-lang/Nim/issues/6932)) -- Fixed "C++ codegen: `mitems` generates invalid code." - ([#4910](https://github.com/nim-lang/Nim/issues/4910)) -- Fixed "seq.mitems produces invalid cpp codegen" - ([#6892](https://github.com/nim-lang/Nim/issues/6892)) -- Fixed "Concepts regression" - ([#6108](https://github.com/nim-lang/Nim/issues/6108)) -- Fixed "Generic iterable concept with array crashes compiler" - ([#6277](https://github.com/nim-lang/Nim/issues/6277)) -- Fixed "C code generation "‘a’ is a pointer; did you mean to use ‘->’?"" - ([#6462](https://github.com/nim-lang/Nim/issues/6462)) -- Fixed "`--NimblePath` fails if a `-` in path which is not followed by a number" - ([#6949](https://github.com/nim-lang/Nim/issues/6949)) -- Fixed ""not registered in the selector" in asyncfile.close() for something that clearly was registered" - ([#6906](https://github.com/nim-lang/Nim/issues/6906)) -- Fixed "strange frexp behavior" - ([#6353](https://github.com/nim-lang/Nim/issues/6353)) - -- Fixed "noreturn branches of case statements shouldn't contribute to type" - ([#6885](https://github.com/nim-lang/Nim/issues/6885)) -- Fixed "Type inference for 'if' statements changed" - ([#6980](https://github.com/nim-lang/Nim/issues/6980)) -- Fixed "newest asyncdispatch recursion" - ([#6100](https://github.com/nim-lang/Nim/issues/6100)) -- Fixed "Ambiguous identifier between set type and proc" - ([#6965](https://github.com/nim-lang/Nim/issues/6965)) - -- Fixed "Inconsistent behavior with sequence and string slicing" - ([#6223](https://github.com/nim-lang/Nim/issues/6223)) - -- Fixed "Unsupported OpenSSL library imported dynamically" - ([#5000](https://github.com/nim-lang/Nim/issues/5000)) -- Fixed "`nim check` segfaults" - ([#6972](https://github.com/nim-lang/Nim/issues/6972)) -- Fixed "GC deadlock" - ([#6988](https://github.com/nim-lang/Nim/issues/6988)) -- Fixed "Create a seq without memory initialization" - ([#6401](https://github.com/nim-lang/Nim/issues/6401)) -- Fixed "Fix bug for getch on Windows while using the arrow keys" - ([#6966](https://github.com/nim-lang/Nim/issues/6966)) -- Fixed "runnableExamples doesn't work in templates" - ([#7018](https://github.com/nim-lang/Nim/issues/7018)) -- Fixed "runnableExamples doesn't work with untyped statement blocks" - ([#7019](https://github.com/nim-lang/Nim/issues/7019)) - -- Fixed "Critical bug in parseBiggestFloat" - ([#7060](https://github.com/nim-lang/Nim/issues/7060)) -- Fixed "[RFC] strformat.% should be gone" - ([#7078](https://github.com/nim-lang/Nim/issues/7078)) -- Fixed "compiler crash on simple macro" - ([#7093](https://github.com/nim-lang/Nim/issues/7093)) -- Fixed "Make newlines sane again" - ([#7089](https://github.com/nim-lang/Nim/issues/7089)) -- Fixed "JS - Unicode enum string representation issue" - ([#6741](https://github.com/nim-lang/Nim/issues/6741)) -- Fixed "Strange behaviour of 0.17.3 (working ok in 0.17.2)" - ([#6989](https://github.com/nim-lang/Nim/issues/6989)) -- Fixed "Strange behaviour of 0.17.3 (working ok in 0.17.2)" - ([#6989](https://github.com/nim-lang/Nim/issues/6989)) -- Fixed "Compiler crash: try expression with infix as" - ([#7116](https://github.com/nim-lang/Nim/issues/7116)) -- Fixed "nimsuggest crash" - ([#7140](https://github.com/nim-lang/Nim/issues/7140)) -- Fixed "[RFC] Reintroduce readChar" - ([#7072](https://github.com/nim-lang/Nim/issues/7072)) -- Fixed "Copyright line needs updating" - ([#7129](https://github.com/nim-lang/Nim/issues/7129)) -- Fixed "-0.0 doesn't result in negative zero in VM" - ([#7079](https://github.com/nim-lang/Nim/issues/7079)) -- Fixed "Windows large filesize" - ([#7121](https://github.com/nim-lang/Nim/issues/7121)) -- Fixed "Securehash is not parsimonious with MD5 and other hash modules" - ([#6961](https://github.com/nim-lang/Nim/issues/6961)) -- Fixed "os.findExe() shouldn't look in current directory on posix, unless exe has a /" - ([#6939](https://github.com/nim-lang/Nim/issues/6939)) -- Fixed "`compiles(...)` with `fatal` pragma causes compiler to exit early" - ([#7080](https://github.com/nim-lang/Nim/issues/7080)) -- Fixed "NPE when compile macro that returns concrete value" - ([#5450](https://github.com/nim-lang/Nim/issues/5450)) -- Fixed "Using a variable of type `int | float` causes internal compiler error" - ([#6946](https://github.com/nim-lang/Nim/issues/6946)) -- Fixed "Unsigned integers could not be used as array indexes." - ([#7153](https://github.com/nim-lang/Nim/issues/7153)) -- Fixed "countdown with uint causes underflow" - ([#4220](https://github.com/nim-lang/Nim/issues/4220)) -- Fixed "Inconsistent method call syntax" - ([#7200](https://github.com/nim-lang/Nim/issues/7200)) -- Fixed "Impossible to create an empty const array" - ([#6853](https://github.com/nim-lang/Nim/issues/6853)) -- Fixed "Strange UINT handling" - ([#3985](https://github.com/nim-lang/Nim/issues/3985)) -- Fixed "Bad codegen when passing arg that is part of return value destination" - ([#6960](https://github.com/nim-lang/Nim/issues/6960)) -- Fixed "No info about gcsafety in error message when global var is accessed in async proc" - ([#6186](https://github.com/nim-lang/Nim/issues/6186)) -- Fixed "Resolving package vs. local import ambiguities" - ([#2819](https://github.com/nim-lang/Nim/issues/2819)) -- Fixed "Internal error with type() operator" - ([#3711](https://github.com/nim-lang/Nim/issues/3711)) -- Fixed "newAsyncSocket should raise an OS error plus other inconsistencies" - ([#4995](https://github.com/nim-lang/Nim/issues/4995)) -- Fixed "mapLiterals fails with negative values" - ([#7215](https://github.com/nim-lang/Nim/issues/7215)) -- Fixed "fmWrite doesn't truncate file with openAsync, unlike open()" - ([#5531](https://github.com/nim-lang/Nim/issues/5531)) -- Fixed "Move libsvm to an external nimble module" - ([#5786](https://github.com/nim-lang/Nim/issues/5786)) -- Fixed "Prevent acceptAddr gotcha with newSocket" - ([#7227](https://github.com/nim-lang/Nim/issues/7227)) -- Fixed "strtabs.getOrDefault is inconsistent with tables.getOrDefault" - ([#4265](https://github.com/nim-lang/Nim/issues/4265)) - -- Fixed "Code falling through into exception handler when no exception thrown." - ([#7232](https://github.com/nim-lang/Nim/issues/7232)) -- Fixed "the new generic inference rules are broken" - ([#7247](https://github.com/nim-lang/Nim/issues/7247)) -- Fixed "Odd `..<` regression" - ([#6992](https://github.com/nim-lang/Nim/issues/6992)) -- Fixed "Different proc type inferred from default parameter" - ([#4659](https://github.com/nim-lang/Nim/issues/4659)) -- Fixed "Different proc type inferred from default parameter" - ([#4659](https://github.com/nim-lang/Nim/issues/4659)) -- Fixed "Testament sometimes ignores test failures" - ([#7236](https://github.com/nim-lang/Nim/issues/7236)) -- Fixed "New Allocator Fails On >=4GB Requests" - ([#7120](https://github.com/nim-lang/Nim/issues/7120)) -- Fixed "User pragmas hide effect specifications from sempass2" - ([#7216](https://github.com/nim-lang/Nim/issues/7216)) -- Fixed "C++: SIGABRT instead of IndexError for out-of-bounds" - ([#6512](https://github.com/nim-lang/Nim/issues/6512)) -- Fixed "An uncaught exception in cpp mode doesn't show the exception name/msg" - ([#6431](https://github.com/nim-lang/Nim/issues/6431)) diff --git a/changelogs/changelog_0_19_0.md b/changelogs/changelog_0_19_0.md deleted file mode 100644 index 45cefe933..000000000 --- a/changelogs/changelog_0_19_0.md +++ /dev/null @@ -1,253 +0,0 @@ -## v0.19.X - XX/XX/2018 - -### Changes affecting backwards compatibility - -- The stdlib module ``future`` has been renamed to ``sugar``. -- ``macros.callsite`` is now deprecated. Since the introduction of ``varargs`` - parameters this became unnecessary. -- Anonymous tuples with a single element can now be written as ``(1,)`` with a - trailing comma. The underlying AST is ``nnkTupleConstr(newLit 1)`` for this - example. ``nnkTupleConstr`` is a new node kind your macros need to be able - to deal with! -- Indexing into a ``cstring`` for the JS target is now mapped - to ``charCodeAt``. -- Assignments that would "slice" an object into its supertype are now prevented - at runtime. Use ``ref object`` with inheritance rather than ``object`` with - inheritance to prevent this issue. -- The ``not nil`` type annotation now has to be enabled explicitly - via ``{.experimental: "notnil".}`` as we are still not pleased with how this - feature works with Nim's containers. -- The parser now warns about inconsistent spacing around binary operators as - these can easily be confused with unary operators. This warning will likely - become an error in the future. -- The ``'c`` and ``'C'`` suffix for octal literals is now deprecated to - bring the language in line with the standard library (e.g. ``parseOct``). -- The dot style for import paths (e.g ``import path.to.module`` instead of - ``import path/to/module``) has been deprecated. - -#### Breaking changes in the standard library - -- ``re.split`` for empty regular expressions now yields every character in - the string which is what other programming languages chose to do. -- The returned tuple of ``system.instantiationInfo`` now has a third field - containing the column of the instantiation. - -- ``cookies.setCookie`` no longer assumes UTC for the expiration date. -- ``strutils.formatEng`` does not distinguish between ``nil`` and ``""`` - strings anymore for its ``unit`` parameter. Instead the space is controlled - by a new parameter ``useUnitSpace``. - -- The ``times.parse`` and ``times.format`` procs have been rewritten. - The proc signatures are the same so it should generally not break anything. - However, the new implementation is a bit stricter, which is a breaking change. - For example ``parse("2017-01-01 foo", "yyyy-MM-dd")`` will now raise an error. - -- ``proc `-`*(a, b: Time): int64`` in the ``times`` module has changed return type - to ``times.Duration`` in order to support higher time resolutions. - The proc is no longer deprecated. - -- The ``times.Timezone`` is now an immutable ref-type that must be initialized - with an explicit constructor (``newTimezone``). - -- ``posix.Timeval.tv_sec`` has changed type to ``posix.Time``. - -- ``math.`mod` `` for floats now behaves the same as ``mod`` for integers - (previously it used floor division like Python). Use ``math.floorMod`` for the old behavior. - -- For string inputs, ``unicode.isUpper`` and ``unicode.isLower`` now require a - second mandatory parameter ``skipNonAlpha``. - -- For string inputs, ``strutils.isUpperAscii`` and ``strutils.isLowerAscii`` now - require a second mandatory parameter ``skipNonAlpha``. - -- ``osLastError`` is now marked with ``sideEffect`` -- The procs ``parseHexInt`` and ``parseOctInt`` now fail on empty strings - and strings containing only valid prefixes, e.g. "0x" for hex integers. - -- ``terminal.setCursorPos`` and ``terminal.setCursorXPos`` now work correctly - with 0-based coordinates on POSIX (previously, you needed to use - 1-based coordinates on POSIX for correct behaviour; the Windows behaviour - was always correct). - -- ``lineInfoObj`` now returns absolute path instead of project path. - It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc. - -- ``net.sendTo`` no longer returns an int and now raises an ``OSError``. -- `threadpool`'s `await` and derivatives have been renamed to `blockUntil` - to avoid confusions with `await` from the `async` macro. - - -#### Breaking changes in the compiler - -- The undocumented ``#? braces`` parsing mode was removed. -- The undocumented PHP backend was removed. -- The default location of ``nimcache`` for the native code targets was - changed. Read [the compiler user guide](https://nim-lang.org/docs/nimc.html#generated-c-code-directory) - for more information. - -### Library additions - -- ``re.split`` now also supports the ``maxsplit`` parameter for consistency - with ``strutils.split``. -- Added ``system.toOpenArray`` in order to support zero-copy slicing - operations. This is currently not yet available for the JavaScript target. -- Added ``getCurrentDir``, ``findExe``, ``cpDir`` and ``mvDir`` procs to - ``nimscript``. -- The ``times`` module now supports up to nanosecond time resolution when available. -- Added the type ``times.Duration`` for representing fixed durations of time. -- Added the proc ``times.convert`` for converting between different time units, - e.g days to seconds. -- Added the proc ``algorithm.binarySearch[T, K]`` with the ```cmp``` parameter. -- Added the proc ``algorithm.upperBound``. -- Added inverse hyperbolic functions, ``math.arcsinh``, ``math.arccosh`` and ``math.arctanh`` procs. -- Added cotangent, secant and cosecant procs ``math.cot``, ``math.sec`` and ``math.csc``; and their hyperbolic, inverse and inverse hyperbolic functions, ``math.coth``, ``math.sech``, ``math.csch``, ``math.arccot``, ``math.arcsec``, ``math.arccsc``, ``math.arccoth``, ``math.arcsech`` and ``math.arccsch`` procs. -- Added the procs ``math.floorMod`` and ``math.floorDiv`` for floor based integer division. -- Added the procs ``rationals.`div```, ``rationals.`mod```, ``rationals.floorDiv`` and ``rationals.floorMod`` for rationals. -- Added the proc ``math.prod`` for product of elements in openArray. -- Added the proc ``parseBinInt`` to parse a binary integer from a string, which returns the value. -- ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt``. -- Added the proc ``flush`` for memory mapped files. -- Added the ``MemMapFileStream``. -- Added a simple interpreting event parser template ``eventParser`` to the ``pegs`` module. -- Added ``macros.copyLineInfo`` to copy lineInfo from other node. -- Added ``system.ashr`` an arithmetic right shift for integers. - -### Library changes - -- ``macros.astGenRepr``, ``macros.lispRepr`` and ``macros.treeRepr`` - now escapes the content of string literals consistently. -- ``macros.NimSym`` and ``macros.NimIdent`` is now deprecated in favor - of the more general ``NimNode``. -- ``macros.getImpl`` now includes the pragmas of types, instead of omitting them. -- ``macros.hasCustomPragma`` and ``macros.getCustomPragmaVal`` now - also support ``ref`` and ``ptr`` types, pragmas on types and variant - fields. -- ``system.SomeReal`` is now called ``SomeFloat`` for consistency and - correctness. -- ``algorithm.smartBinarySearch`` and ``algorithm.binarySearch`` is - now joined in ``binarySearch``. ``smartbinarySearch`` is now - deprecated. -- The `terminal` module now exports additional procs for generating ANSI color - codes as strings. -- Added the parameter ``val`` for the ``CritBitTree[int].inc`` proc. -- An exception raised from a ``test`` block of ``unittest`` now shows its type in - error message. -- The ``compiler/nimeval`` API was rewritten to simplify the "compiler as an - API". Using the Nim compiler and its VM as a scripting engine has never been - easier. See ``tests/compilerapi/tcompilerapi.nim`` for an example of how to - use the Nim VM in a native Nim application. -- Added the parameter ``val`` for the ``CritBitTree[T].incl`` proc. -- The proc ``tgamma`` was renamed to ``gamma``. ``tgamma`` is deprecated. -- The ``pegs`` module now exports getters for the fields of its ``Peg`` and ``NonTerminal`` - object types. ``Peg``s with child nodes now have the standard ``items`` and ``pairs`` - iterators. -- The ``accept`` socket procedure defined in the ``net`` module can now accept - a nil socket. - -### Language additions - -- Dot calls combined with explicit generic instantiations can now be written - as ``x.y[:z]`` which is transformed into ``y[z](x)`` by the parser. -- ``func`` is now an alias for ``proc {.noSideEffect.}``. -- In order to make ``for`` loops and iterators more flexible to use Nim now - supports so called "for-loop macros". See - the [manual](manual.html#macros-for-loop-macros) for more details. - This feature enables a Python-like generic ``enumerate`` implementation. - -- Case statements can now be rewritten via macros. See the [manual](manual.html#macros-case-statement-macros) for more information. - This feature enables custom pattern matchers. - - -- the `typedesc` special type has been renamed to just `type`. -- `static` and `type` are now also modifiers similar to `ref` and `ptr`. - They denote the special types `static[T]` and `type[T]`. -- Forcing compile-time evaluation with `static` now supports specifying - the desired target type (as a concrete type or as a type class) -- The `type` operator now supports checking that the supplied expression - matches an expected type constraint. - -### Language changes - -- The `importcpp` pragma now allows importing the listed fields of generic - C++ types. Support for numeric parameters have also been added through - the use of `static[T]` types. - (#6415) - -- Native C++ exceptions can now be imported with `importcpp` pragma. - Imported exceptions can be raised and caught just like Nim exceptions. - More details in language manual. - -- ``nil`` for strings/seqs is finally gone. Instead the default value for - these is ``"" / @[]``. Use ``--nilseqs:on`` for a transition period. - -- Accessing the binary zero terminator in Nim's native strings - is now invalid. Internally a Nim string still has the trailing zero for - zero-copy interoperability with ``cstring``. Compile your code with the - new switch ``--laxStrings:on`` if you need a transition period. - -- The command syntax now supports keyword arguments after the first comma. - -- Thread-local variables can now be declared inside procs. This implies all - the effects of the ``global`` pragma. - -- Nim now supports the ``except`` clause in the export statement. - -- Range float types, example ``range[0.0 .. Inf]``. More details in language manual. -- The ``{.this.}`` pragma has been deprecated. It never worked within generics and - we found the resulting code harder to read than the more explicit ``obj.field`` - syntax. -- "Memory regions" for pointer types have been deprecated, they were hardly used - anywhere. Note that this has **nothing** to do with the ``--gc:regions`` switch - of managing memory. - -- The exception hierarchy was slightly reworked, ``SystemError`` was renamed to - ``CatchableError`` and is the new base class for any exception that is guaranteed to - be catchable. This change should have minimal impact on most existing Nim code. - - -### Tool changes - -- ``jsondoc2`` has been renamed ``jsondoc``, similar to how ``doc2`` was renamed - ``doc``. The old ``jsondoc`` can still be invoked with ``jsondoc0``. - -### Compiler changes - -- The VM's instruction count limit was raised to 3 million instructions in - order to support more complex computations at compile-time. - -- Support for hot code reloading has been implemented for the JavaScript - target. To use it, compile your code with `--hotCodeReloading:on` and use a - helper library such as LiveReload or BrowserSync. - -- A new compiler option `--cppCompileToNamespace` puts the generated C++ code - into the namespace "Nim" in order to avoid naming conflicts with existing - C++ code. This is done for all Nim code - internal and exported. - -- Added ``macros.getProjectPath`` and ``os.putEnv`` procs to Nim's virtual - machine. - -- The ``deadCodeElim`` option is now always turned on and the switch has no - effect anymore, but is recognized for backwards compatibility. - -- ``experimental`` is now a pragma / command line switch that can enable specific - language extensions, it is not an all-or-nothing switch anymore. - -- Nintendo Switch was added as a new platform target. See [the compiler user guide](https://nim-lang.org/docs/nimc.html) - for more info. - -- macros.bindSym now capable to accepts not only literal string or string constant expression. - bindSym enhancement make it also can accepts computed string or ident node inside macros / - compile time functions / static blocks. Only in templates / regular code it retains it's old behavior. - This new feature can be accessed via {.experimental: "dynamicBindSym".} pragma/switch. - -- On Posix systems the global system wide configuration is now put under ``/etc/nim/nim.cfg``, - it used to be ``/etc/nim.cfg``. Usually it does not exist, however. - -- On Posix systems the user configuration is now looked under ``$XDG_CONFIG_HOME/nim/nim.cfg`` - (if ``XDG_CONFIG_HOME`` is not defined, then under ``~/.config/nim/nim.cfg``). It used to be - ``$XDG_CONFIG_DIR/nim.cfg`` (and ``~/.config/nim.cfg``). - - Similarly, on Windows, the user configuration is now looked under ``%APPDATA%/nim/nim.cfg``. - This used to be ``%APPDATA%/nim.cfg``. - -### Bugfixes diff --git a/changelogs/changelog_0_20_0.md b/changelogs/changelog_0_20_0.md deleted file mode 100644 index 9ddfd36dc..000000000 --- a/changelogs/changelog_0_20_0.md +++ /dev/null @@ -1,294 +0,0 @@ -## v0.20.0 - 2019-06-06 - - -### Changes affecting backwards compatibility - -- `shr` is now sign preserving. Use `-d:nimOldShiftRight` to enable - the old behavior globally. - -- The ``isLower``, ``isUpper`` family of procs in strutils/unicode - operating on **strings** have been - deprecated since it was unclear what these do. Note that the much more - useful procs that operate on ``char`` or ``Rune`` are not affected. - -- `strutils.editDistance` has been deprecated, - use `editdistance.editDistance` or `editdistance.editDistanceAscii` - instead. - -- The OpenMP parallel iterator \``||`\` now supports any `#pragma omp directive` - and not just `#pragma omp parallel for`. See - [OpenMP documentation](https://www.openmp.org/wp-content/uploads/OpenMP-4.5-1115-CPP-web.pdf). - - The default annotation is `parallel for`, if you used OpenMP without annotation - the change is transparent, if you used annotations you will have to prefix - your previous annotations with `parallel for`. - - Furthermore, an overload with positive stepping is available. - -- The `unchecked` pragma was removed, instead use `system.UncheckedArray`. - -- The undocumented ``#? strongSpaces`` parsing mode has been removed. - -- The `not` operator is now always a unary operator, this means that code like - ``assert not isFalse(3)`` compiles. - -- `getImpl` on a `var` or `let` symbol will now return the full `IdentDefs` - tree from the symbol declaration instead of just the initializer portion. - -- Methods are now ordinary "single" methods, only the first parameter is - used to select the variant at runtime. For backwards compatibility - use the new `--multimethods:on` switch. - -- Generic methods are now deprecated; they never worked well. - -- Compile time checks for integer and float conversions are now stricter. - For example, `const x = uint32(-1)` now gives a compile time error instead - of being equivalent to `const x = 0xFFFFFFFF'u32`. - -- Using `typed` as the result type in templates/macros now means - "expression with a type". The old meaning of `typed` is preserved - as `void` or no result type at all. - -- A bug allowed `macro foo(): int = 123` to compile even though a - macro has to return a `NimNode`. This has been fixed. - -- With the exception of `uint` and `uint64`, conversion to unsigned types - are now range checked during runtime. - -- Macro arguments of type `typedesc` are now passed to the macro as - `NimNode` like every other type except `static`. Use `typed` for a - behavior that is identical in new and old - Nim. See the RFC [Pass typedesc as NimNode to macros](https://github.com/nim-lang/RFCs/issues/148) - for more details. - - -#### Breaking changes in the standard library - -- `osproc.execProcess` now also takes a `workingDir` parameter. - -- `std/sha1.secureHash` now accepts `openArray[char]`, not `string`. (Former - successful matches should keep working, though former failures will not.) - -- `options.UnpackError` is no longer a ref type and inherits from `system.Defect` - instead of `system.ValueError`. - -- `system.ValueError` now inherits from `system.CatchableError` instead of `system.Defect`. - -- The procs `parseutils.parseBiggestInt`, `parseutils.parseInt`, - `parseutils.parseBiggestUInt` and `parseutils.parseUInt` now raise a - `ValueError` when the parsed integer is outside of the valid range. - Previously they sometimes raised an `OverflowError` and sometimes they - returned `0`. - -- The procs `parseutils.parseBin`, `parseutils.parseOct` and `parseutils.parseHex` - were not clearing their `var` parameter `number` and used to push its value to - the left when storing the parsed string into it. Now they always set the value - of the parameter to `0` before storing the result of the parsing, unless the - string to parse is not valid (then the value of `number` is not changed). - -- `streams.StreamObject` now restricts its fields to only raise `system.Defect`, - `system.IOError` and `system.OSError`. - This change only affects custom stream implementations. - -- nre's `RegexMatch.{captureBounds,captures}[]` no longer return `Option` or - `nil`/`""`, respectively. Use the newly added `n in p.captures` method to - check if a group is captured, otherwise you'll receive an exception. - -- nre's `RegexMatch.{captureBounds,captures}.toTable` no longer accept a - default parameter. Instead uncaptured entries are left empty. Use - `Table.getOrDefault()` if you need defaults. - -- nre's `RegexMatch.captures.{items,toSeq}` now returns an `Option[string]` - instead of a `string`. With the removal of `nil` strings, this is the only - way to indicate a missing match. Inside your loops, instead - of `capture == ""` or `capture == nil`, use `capture.isSome` to check if a capture is - present, and `capture.get` to get its value. - -- nre's `replace()` no longer throws `ValueError` when the replacement string - has missing captures. It instead throws `KeyError` for named captures, and - `IndexError` for unnamed captures. This is consistent with - `RegexMatch.{captureBounds,captures}[]`. - -- `splitFile` now correctly handles edge cases, see #10047. - -- `isNil` is no longer false for undefined in the JavaScript backend: - now it's true for both nil and undefined. - Use `isNull` or `isUndefined` if you need exact equality: - `isNil` is consistent with `===`, `isNull` and `isUndefined` with `==`. - -- several deprecated modules were removed: `ssl`, `matchers`, `httpserver`, - `unsigned`, `actors`, `parseurl` - -- two poorly documented and not used modules (`subexes`, `scgi`) were moved to - graveyard (they are available as Nimble packages) - -- procs `string.add(int)` and `string.add(float)` which implicitly convert - ints and floats to string have been deprecated. - Use `string.addInt(int)` and `string.addFloat(float)` instead. - -- ``case object`` branch transitions via ``system.reset`` are deprecated. - Compile your code with ``-d:nimOldCaseObjects`` for a transition period. - -- base64 module: The default parameter `newLine` for the `encode` procs - was changed from `"\13\10"` to the empty string `""`. - - -#### Breaking changes in the compiler - -- The compiler now implements the "generic symbol prepass" for `when` statements - in generics, see bug #8603. This means that code like this does not compile - anymore: - -```nim -proc enumToString*(enums: openArray[enum]): string = - # typo: 'e' instead 'enums' - when e.low.ord >= 0 and e.high.ord < 256: - result = newString(enums.len) - else: - result = newString(enums.len * 2) -``` - -- ``discard x`` is now illegal when `x` is a function symbol. - -- Implicit imports via ``--import: module`` in a config file are now restricted - to the main package. - - -### Library additions - -- There is a new stdlib module `std/editdistance` as a replacement for the - deprecated `strutils.editDistance`. - -- There is a new stdlib module `std/wordwrap` as a replacement for the - deprecated `strutils.wordwrap`. - -- Added `split`, `splitWhitespace`, `size`, `alignLeft`, `align`, - `strip`, `repeat` procs and iterators to `unicode.nim`. - -- Added `or` for `NimNode` in `macros`. - -- Added `system.typeof` for more control over how `type` expressions - can be deduced. - -- Added `macros.isInstantiationOf` for checking if the proc symbol - is instantiation of generic proc symbol. - -- Added the parameter ``isSorted`` for the ``sequtils.deduplicate`` proc. - -- There is a new stdlib module `std/diff` to compute the famous "diff" - of two texts by line. - -- Added `os.relativePath`. - -- Added `parseopt.remainingArgs`. - -- Added `os.getCurrentCompilerExe` (implemented as `getAppFilename` at CT), - can be used to retrieve the currently executing compiler. - -- Added `xmltree.toXmlAttributes`. - -- Added ``std/sums`` module for fast summation functions. - -- Added `Rusage`, `getrusage`, `wait4` to the posix interface. - -- Added the `posix_utils` module. - -- Added `system.default`. - -- Added `sequtils.items` for closure iterators, allows closure iterators - to be used by the `mapIt`, `filterIt`, `allIt`, `anyIt`, etc. - - -### Library changes - -- The string output of `macros.lispRepr` proc has been tweaked - slightly. The `dumpLisp` macro in this module now outputs an - indented proper Lisp, devoid of commas. - -- Added `macros.signatureHash` that returns a stable identifier - derived from the signature of a symbol. - -- In `strutils` empty strings now no longer matched as substrings - anymore. - -- The `Complex` type is now a generic object and not a tuple anymore. - -- The `ospaths` module is now deprecated, use `os` instead. Note that - `os` is available in a NimScript environment but unsupported - operations produce a compile-time error. - -- The `parseopt` module now supports a new flag `allowWhitespaceAfterColon` - (default value: true) that can be set to `false` for better Posix - interoperability. (Bug #9619.) - -- `os.joinPath` and `os.normalizePath` handle edge cases like ``"a/b/../../.."`` - differently. - -- `securehash` was moved to `lib/deprecated`. - -- The switch ``-d:useWinAnsi`` is not supported anymore. - -- In `times` module, procs `format` and `parse` accept a new optional - `DateTimeLocale` argument for formatting/parsing dates in other languages. - - -### Language additions - -- Vm support for float32<->int32 and float64<->int64 casts was added. -- There is a new pragma block `noSideEffect` that works like - the `gcsafe` pragma block. -- added `os.getCurrentProcessId`. -- User defined pragmas are now allowed in the pragma blocks. -- Pragma blocks are no longer eliminated from the typed AST tree to preserve - pragmas for further analysis by macros. -- Custom pragmas are now supported for `var` and `let` symbols. -- Tuple unpacking is now supported for constants and for loop variables. -- Case object branches can be initialized with a runtime discriminator if - possible discriminator values are constrained within a case statement. - -### Language changes - -- The standard extension for SCF (source code filters) files was changed from - ``.tmpl`` to ``.nimf``, - it's more recognizable and allows tools like Github to recognize it as Nim, - see [#9647](https://github.com/nim-lang/Nim/issues/9647). - The previous extension will continue to work. - -- Pragma syntax is now consistent. Previous syntax where type pragmas did not - follow the type name is now deprecated. Also pragma before generic parameter - list is deprecated to be consistent with how pragmas are used with a proc. See - [#8514](https://github.com/nim-lang/Nim/issues/8514) and - [#1872](https://github.com/nim-lang/Nim/issues/1872) for further details. - -- Hash sets and tables are initialized by default. The explicit `initHashSet`, - `initTable`, etc. are not needed anymore. - - -### Tool changes - -- `jsondoc` now includes a `moduleDescription` field with the module - description. `jsondoc0` shows comments as its own objects as shown in the - documentation. -- `nimpretty`: --backup now defaults to `off` instead of `on` and the flag was - undocumented; use `git` instead of relying on backup files. -- `koch` now defaults to build the latest *stable* Nimble version unless you - explicitly ask for the latest master version via `--latest`. - - -### Compiler changes - -- The deprecated `fmod` proc is now unavailable on the VM. -- A new `--outdir` option was added. -- The compiled JavaScript file for the project produced by executing `nim js` - will no longer be placed in the nimcache directory. -- The `--hotCodeReloading` has been implemented for the native targets. - The compiler also provides a new more flexible API for handling the - hot code reloading events in the code. -- The compiler now supports a ``--expandMacro:macroNameHere`` switch - for easy introspection into what a macro expands into. -- The `-d:release` switch now does not disable runtime checks anymore. - For a release build that also disables runtime checks - use `-d:release -d:danger` or simply `-d:danger`. - - -### Bugfixes diff --git a/changelogs/changelog_0_20_2.md b/changelogs/changelog_0_20_2.md deleted file mode 100644 index 4f09ae3c5..000000000 --- a/changelogs/changelog_0_20_2.md +++ /dev/null @@ -1,55 +0,0 @@ -# v0.20.2 - 2019-07-17 - - -## Changes affecting backwards compatibility - -- All `strutils.rfind` procs now take `start` and `last` like `strutils.find` - with the same data slice/index meaning. This is backwards compatible for - calls *not* changing the `rfind` `start` parameter from its default. (#11487) - - In the unlikely case that you were using `rfind X, start=N`, or `rfind X, N`, - then you need to change that to `rfind X, last=N` or `rfind X, 0, N`. (This - should minimize gotchas porting code from other languages like Python or C++.) - -- On Windows stderr/stdout/stdin are not opened as binary files anymore. Use the switch - `-d:nimBinaryStdFiles` for a transition period. - -### Breaking changes in the standard library - -- Mac OS X / BSD: TSa_Family is now the ``uint8`` type, so type - conversions like ``x.sin_family = uint16 toInt(nativesockets.AF_INET)`` - need to be changed into ``x.sin_family = TSa_Family toInt(nativesockets.AF_INET)``. - - -### Breaking changes in the compiler - - -## Library additions - -- `toOpenArray` is now available for the JS target. - -## Library changes - -- Fix async IO operations stalling even after socket is closed. (#11232) - -- More informative error message for `streams.openFileStream`. (#11438) - - -## Language additions - - -## Language changes - - -### Tool changes - - -### Compiler changes - -- Better error message for IndexError for empty containers. (#11476) - -- Fix regression in semfold for old right shift. (#11477) - -- Fix for passing tuples as static params to macros. (#11423) - -## Bugfixes diff --git a/changelogs/changelog_1_0_0.md b/changelogs/changelog_1_0_0.md deleted file mode 100644 index 5a9185ecb..000000000 --- a/changelogs/changelog_1_0_0.md +++ /dev/null @@ -1,138 +0,0 @@ -# v1.0 - 2019-09-23 - - -## Changes affecting backwards compatibility - -- The switch ``-d:nimBinaryStdFiles`` does not exist anymore. Instead - stdin/stdout/stderr are binary files again. This change only affects - Windows. - -- On Windows console applications the code-page is set at program startup - to UTF-8. Use the new switch `-d:nimDontSetUtf8CodePage` to disable this - feature. - -- The language definition and compiler are now stricter about ``gensym``'ed - symbols in hygienic templates. See the section in the - [manual](https://nim-lang.org/docs/manual.html#templates-hygiene-in-templates) - for further details. Use the compiler switch `--oldgensym:on` for a - transition period. - - -### Breaking changes in the standard library - -- We removed `unicode.Rune16` without any deprecation period as the name - was wrong (see the [RFC](https://github.com/nim-lang/RFCs/issues/151) for details) - and we didn't find any usages of it in the wild. If you still need it, add this - piece of code to your project: -```nim -type - Rune16* = distinct int16 -``` - -- `exportc` now uses C instead of C++ mangling with `nim cpp`, matching behavior - of `importc`, see #10578. - Use the new `exportcpp` to mangle as C++ when using `nim cpp`. - - -### Breaking changes in the compiler - -- A bug allowing `int` to be implicitly converted to range types of smaller size - (e.g `range[0'i8..10'i8]`) has been fixed. - - - -## Library additions - -- `encodings.getCurrentEncoding` now distinguishes between the console's - encoding and the OS's encoding. This distinction is only meaningful on - Windows. -- Added `system.getOsFileHandle` which is usually more useful - than `system.getFileHandle`. This distinction is only meaningful on - Windows. -- Added a `json.parseJsonFragments` iterator that can be used to speedup - JSON processing substantially when there are JSON fragments separated - by whitespace. - - - -## Library changes - -- Added `os.delEnv` and `nimscript.delEnv`. (#11466) - -- Enabled Oid usage in hashtables. (#11472) - -- Added `unsafeColumnAt` procs, that return unsafe cstring from InstantRow. (#11647) - -- Make public `Sha1Digest` and `Sha1State` types and `newSha1State`, - `update` and `finalize` procedures from `sha1` module. (#11694) - -- Added the `std/monotimes` module which implements monotonic timestamps. - -- Consistent error handling of two `exec` overloads. (#10967) - -- Officially the following modules now have an unstable API: - - std/varints - - core/allocators - - core/hotcodereloading - - asyncstreams - - base64 - - browsers - - collections/rtarrays - - collections/sharedlist - - collections/sharedtable - - concurrency/atomics - - concurrency/cpuload - - concurrency/threadpool - - coro - - endians - - httpcore - - parsesql - - pathnorm - - reservedmem - - typetraits - - Every other stdlib module is API stable with respect to version 1. - - - -## Language additions - -- Inline iterators returning `lent T` types are now supported, similarly to - iterators returning `var T`: -```nim -iterator myitems[T](x: openarray[T]): lent T -iterator mypairs[T](x: openarray[T]): tuple[idx: int, val: lent T] -``` - -- Added an `importjs` pragma that can now be used instead of `importcpp` - and `importc` to import symbols from JavaScript. `importjs` for routines always - takes a "pattern" for maximum flexibility. - - - -## Language changes - -- `uint64` is now finally a regular ordinal type. This means `high(uint64)` compiles - and yields the correct value. - - -### Tool changes - -- The Nim compiler now does not recompile the Nim project via ``nim c -r`` if - no dependent Nim file changed. This feature can be overridden by - the ``--forceBuild`` command line option. -- The Nim compiler now warns about unused module imports. You can use a - top level ``{.used.}`` pragma in the module that you want to be importable - without producing this warning. -- The "testament" testing tool's name was changed - from `tester` to `testament` and is generally available as a tool to run Nim - tests automatically. - - -### Compiler changes - -- VM can now cast integer type arbitrarily. (#11459) - - - -## Bugfixes diff --git a/changelogs/changelog_1_0_2.md b/changelogs/changelog_1_0_2.md deleted file mode 100644 index aa01c503f..000000000 --- a/changelogs/changelog_1_0_2.md +++ /dev/null @@ -1,56 +0,0 @@ -# v1.0.2 - 2019-10-23 - - -## Bugfixes - -* fixes the --verbosity:2 regression -* Fixed "Fail to compile a file twice under Windows (v1.0 bug)." [#12242](https://github.com/nim-lang/Nim/issues/12242) -* fix nimpretty removing space before pragma -* JS: gensym is stricter for 'this' -* Fixed "VM Assertion Error with newruntime" [#12294](https://github.com/nim-lang/Nim/issues/12294) -* Fixed "Assertion error when running `nim check` on compiler/nim.nim" [#12281](https://github.com/nim-lang/Nim/issues/12281) -* Fixed "Compiler crash with empty array and generic instantiation with int as parameter" [#12264](https://github.com/nim-lang/Nim/issues/12264) -* Fixed "Regression in JS backend codegen "Error: request to generate code for .compileTime proc"" [#12240](https://github.com/nim-lang/Nim/issues/12240) -* Fix how `relativePath` handle case sensitiviy -* Fixed "SIGSEGV in compiler when using generic types and seqs" [#12336](https://github.com/nim-lang/Nim/issues/12336) -* Fixed "[1.0.0] weird interaction between `import os` and casting integer to char on macosx trigger bad codegen" [#12291](https://github.com/nim-lang/Nim/issues/12291) -* VM: no special casing for big endian machines -* Fixed "`internal error: environment misses` with a simple template inside one of Jester macros" [#12323](https://github.com/nim-lang/Nim/issues/12323) -* nimsuggest: fix tcp socket leak -* nimsuggest: fix tcp socket leak for epc backend -* Fixed "`writeFile` and `write(f, str)` skip null bytes on Windows" [#12315](https://github.com/nim-lang/Nim/issues/12315) -* Fixed "Crash in intsets symmetric_difference" [#12366](https://github.com/nim-lang/Nim/issues/12366) -* Fixed "[regression] VM crash when dealing with var param of a proc result" [#12244](https://github.com/nim-lang/Nim/issues/12244) -* fixes a koch regression that made 'koch boot --listcmd' not work anymore -* Fixed "[regression] inconsistent signed int `mod` operator between runtime, compiletime, and semfold" [#12332](https://github.com/nim-lang/Nim/issues/12332) -* Fixed "Boehm disables interior pointer checking" [#12286](https://github.com/nim-lang/Nim/issues/12286) -* Fixes semCustomPragma when nkSym -* Fixed yield in nkCheckedFieldExpr -* Fixed "`randomize()` from `random` not working on JS" [#12418](https://github.com/nim-lang/Nim/issues/12418) -* Fixed "Compiler crash with invalid object variant" [#12379](https://github.com/nim-lang/Nim/issues/12379) -* fix type's case in random.nim -* Fixed "Update docs with a better way to signal unimplemented methods" [#10804](https://github.com/nim-lang/Nim/issues/10804) -* Fixed "Nim language manual, push pragma is not explained well" [#10824](https://github.com/nim-lang/Nim/issues/10824) -* Fixed "[regression] Importing more than one module with same name from different packages produce bad codegen" [#12420](https://github.com/nim-lang/Nim/issues/12420) -* Namespace unittest enums to avoid name conflicts -* Fixed "VM checks unsigned integers for overflow." [#12310](https://github.com/nim-lang/Nim/issues/12310) -* Fixed "line directive is not generated for first line of function definition" [#12426](https://github.com/nim-lang/Nim/issues/12426) - - - -## Documentation improvements - -* threadpool: fix link in docs (#12258) -* Fix spellings (#12277) -* fix #12278, don't expose internal PCRE documentation -* Fixed "Documentation of quitprocs is wrong" [#12279(https://github.com/nim-lang/Nim/issues/12279) -* Fix typo in docs -* Fix reference to parseSpec proc in readme -* [doc/tut1] removed discard discussion in comments -* Documentation improvements around the db interface -* Easier build instructions for windows - just run `build_all.bat`. -* fix a few dead links and a missing sentence in documentation -* Macro docs additions -* Updated the code example in the os module to use better grammar. -* Mention "lambdas" and `=>` in the manual -* Better documentation on Garbage Collector diff --git a/changelogs/changelog_1_2_0.md b/changelogs/changelog_1_2_0.md deleted file mode 100644 index 1f76df0b4..000000000 --- a/changelogs/changelog_1_2_0.md +++ /dev/null @@ -1,535 +0,0 @@ -# v1.2.0 - 2020-04-02 - - -## Standard library additions and changes -- Added overloaded `strformat.fmt` macro that use specified characters as - delimiter instead of '{' and '}'. -- Added new procs in `tables.nim`: `OrderedTable.pop`, `CountTable.del`, - `CountTable.pop`, `Table.pop`. -- Added `strtabs.clear` overload that reuses the existing mode. -- Added `browsers.osOpen` const alias for the operating system specific *"open"* command. -- Added `sugar.dup` for turning in-place algorithms like `sort` and `shuffle` - into operations that work on a copy of the data and return the mutated copy, - like the existing `sorted` does. -- Added `sugar.collect` that does comprehension for seq/set/table collections. -- Added `sugar.capture` for capturing some local loop variables when creating a - closure. This is an enhanced version of `closureScope`. -- Added `typetraits.tupleLen` to get number of elements of a tuple/type tuple, - and `typetraits.get` to get the ith element of a type tuple. -- Added `typetraits.genericParams` to return a tuple of generic params from a - generic instantiation. -- `options` now treats `proc` like other pointer types, meaning `nil` proc variables - are converted to `None`. -- Added `os.normalizePathEnd` for additional path sanitization. -- Added `times.fromUnixFloat,toUnixFloat`, sub-second resolution versions of - `fromUnix`,`toUnixFloat`. -- Added `wrapnils` module for chains of field-access and indexing where the LHS - can be nil. This simplifies code by reducing need for if-else branches around - intermediate maybe nil values. E.g. `echo ?.n.typ.kind`. -- Added `minIndex`, `maxIndex` and `unzip` to the `sequtils` module. -- Added `os.isRelativeTo` to tell whether a path is relative to another. -- Added `resetOutputFormatters` to `unittest`. -- Added `expectIdent` to the `macros` module. -- Added `os.isValidFilename` that returns `true` if `filename` argument is valid - for cross-platform use. -- Added `times.isLeapDay`. -- `base64` adds URL-Safe Base64, implements RFC-4648 Section-7. -- Added a new module, `std / compilesettings` for querying the compiler about - diverse configuration settings. -- Added `net.getPeerCertificates` and `asyncnet.getPeerCertificates` for - retrieving the verified certificate chain of the peer we are connected to - through an SSL-wrapped `Socket`/`AsyncSocket`. -- Added `browsers.openDefaultBrowser` without URL, implements IETF RFC-6694 Section-3. -- Added `jsconsole.trace`, `jsconsole.table`, `jsconsole.exception` for JavaScript target. -- Added `distinctBase` overload for values: `assert 12.MyInt.distinctBase == 12` -- Added new module `std/stackframes`, in particular `setFrameMsg`, which enables - custom runtime annotation of stackframes, see #13351 for examples. - Turn on/off via `--stackTraceMsgs:on/off`. -- Added `sequtils.countIt`, allowing for counting items using a predicate. -- Added a `with` macro for easy function chaining that's available everywhere, - there is no need to concern your APIs with returning the first argument - to enable "chaining", instead use the dedicated macro `with` that - was designed for it. For example: - -```nim -import std/with - -type - Foo = object - col, pos: string - -proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b) -proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y) - -var f: Foo -with(f, setColor(2, 3, 4), setPosition(0.0, 1.0)) -echo f -``` - -- `macros.newLit` now works for ref object types. -- `macro pragmas` can now be used in type sections. -- 5 new pragmas were added to Nim in order to make the upcoming tooling more - convenient to use. Nim compiler checks these pragmas for syntax but otherwise - ignores them. The pragmas are `requires`, `ensures`, `assume`, `assert`, `invariant`. -- `system.writeFile` has been overloaded to also support `openarray[byte]`. -- `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` - and only returns once all pending async operations are guaranteed to have completed. -- `sequtils.zip` now returns a sequence of anonymous tuples i.e. those tuples - now do not have fields named "a" and "b". -- `distinctBase` has been moved from `sugar` to `typetraits` and now it is - implemented as compiler type trait instead of macro. `distinctBase` in sugar - module is now deprecated. -- `CountTable.mget` has been removed from `tables.nim`. It didn't work, and it - was an oversight to be included in v1.0. -- `tables.merge(CountTable, CountTable): CountTable` has been removed. - It didn't work well together with the existing inplace version of the same proc - (`tables.merge(var CountTable, CountTable)`). - It was an oversight to be included in v1.0. -- `asyncdispatch.drain` now consistently uses the passed timeout value for all - iterations of the event loop, and not just the first iteration. - This is more consistent with the other asyncdispatch APIs, and allows - `asyncdispatch.drain` to be more efficient. -- `base64.encode` and `base64.decode` were made faster by about 50%. -- `htmlgen` adds [MathML](https://wikipedia.org/wiki/MathML) support - (ISO 40314). -- `macros.eqIdent` is now invariant to export markers and backtick quotes. -- `htmlgen.html` allows `lang` in the `` tag and common valid attributes. -- `macros.basename` and `basename=` got support for `PragmaExpr`, - so that an expression like `MyEnum {.pure.}` is handled correctly. -- `httpclient.maxredirects` changed from `int` to `Natural`, because negative values - serve no purpose whatsoever. -- `httpclient.newHttpClient` and `httpclient.newAsyncHttpClient` added `headers` - argument to set initial HTTP Headers, instead of a hardcoded empty `newHttpHeader()`. -- `parseutils.parseUntil` has now a different behaviour if the `until` parameter is - empty. This was required for intuitive behaviour of the strscans module - (see bug #13605). -- `strutils.formatFloat` with `precision = 0` has the same behavior in all - backends, and it is compatible with Python's behavior, - e.g. `formatFloat(3.14159, precision = 0)` is now `3`, not `3.`. -- `times.parse` now only uses input to compute its result, and not `now`: - `parse("2020", "YYYY", utc())` is now `2020-01-01T00:00:00Z` instead of - `2020-03-02T00:00:00Z` if run on 03-02; it also doesn't crash anymore when - used on 29th, 30th, 31st of each month. -- `httpcore.==(string, HttpCode)` is now deprecated due to lack of practical - usage. The `$` operator can be used to obtain the string form of `HttpCode` - for comparison if desired. -- `std/oswalkdir` was buggy, it's now deprecated and reuses `std/os` procs. -- `os.walkDir` and `os.walkDirRec` now have new flag, `checkDir` (default: false). - If it is set to true, it will throw if input dir is invalid instead of a noop - (which is the default behaviour, as it was before this change), - `os.walkDirRec` only throws if top-level dir is invalid, but ignores errors for - subdirs, otherwise it would be impossible to resume iteration. -- The `FD` variant of `selector.unregister` for `ioselector_epoll` and - `ioselector_select` now properly handle the `Event.User` select event type. -- `joinPath` path normalization when `/` is the first argument works correctly: - `assert "/" / "/a" == "/a"`. Fixed the edge case: `assert "" / "" == ""`. -- `xmltree` now adds indentation consistently to child nodes for any number - of children nodes. -- `os.splitPath()` behavior synchronized with `os.splitFile()` to return "/" - as the dir component of `/root_sub_dir` instead of the empty string. -- The deprecated `lc` macro has been removed from `sugar`. It is now replaced - with the more powerful `collect` macro. -- `os.relativePath("foo", "foo")` is now `"."`, not `""`, as `""` means invalid - path and shouldn't be conflated with `"."`; use `-d:nimOldRelativePathBehavior` - to restore the old behavior. -- `os.joinPath(a, b)` now honors trailing slashes in `b` (or `a` if `b` = ""). -- `base64.encode` no longer supports `lineLen` and `newLine`. - Use `base64.encodeMime` instead. - - -### Breaking changes - -- `net.newContext` now performs SSL Certificate checking on Linux and OSX. - Define `nimDisableCertificateValidation` to disable it globally. - - - -## Language changes - -- An `align` pragma can now be used for variables and object fields, similar - to the `alignas` declaration modifier in C/C++. -- The `=sink` type bound operator is now optional. The compiler can now use a - combination of `=destroy` and `copyMem` to move objects efficiently. -- Unsigned integer operators have been fixed to allow promotion of the first operand. -- Conversions to unsigned integers are unchecked at runtime, imitating earlier Nim - versions. The documentation was improved to acknowledge this special case. - See https://github.com/nim-lang/RFCs/issues/175 for more details. -- There is a new syntax for lvalue references: `var b {.byaddr.} = expr` enabled by - `import std/decls`. -- `var a {.foo.}: MyType = expr` now lowers to `foo(a, MyType, expr)` for - non-builtin pragmas, enabling things like lvalue references (see `decls.byaddr`). - - - -## Compiler changes - -- The generated JS code uses spaces, instead of mixing spaces and tabs. -- The Nim compiler now supports the ``--asm`` command option for easier - inspection of the produced assembler code. -- The Nim compiler now supports a new pragma called ``.localPassc`` to - pass specific compiler options to the C(++) backend for the C(++) file - that was produced from the current Nim module. -- The compiler now inferes "sink parameters". To disable this for a specific routine, - annotate it with `.nosinks`. To disable it for a section of code, use - `{.push sinkInference: off.}`...`{.pop.}`. -- The compiler now supports a new switch `--panics:on` that turns runtime - errors like `IndexError` or `OverflowError` into fatal errors that **cannot** - be caught via Nim's `try` statement. `--panics:on` can improve the - runtime efficiency and code size of your program significantly. -- The compiler now warns about inheriting directly from `system.Exception` as - this is **very bad** style. You should inherit from `ValueError`, `IOError`, - `OSError` or from a different specific exception type that inherits from - `CatchableError` and cannot be confused with a `Defect`. -- The error reporting for Nim's effect system has been improved. -- Implicit conversions for `const` behave correctly now, meaning that code like - `const SOMECONST = 0.int; procThatTakesInt32(SOMECONST)` will be illegal now. - Simply write `const SOMECONST = 0` instead. -- The `{.dynlib.}` pragma is now required for exporting symbols when making - shared objects on POSIX and macOS, which make it consistent with the behavior - on Windows. -- The compiler is now more strict about type conversions concerning proc - types: Type conversions cannot be used to hide `.raise` effects or side - effects, instead a `cast` must be used. With the flag `--useVersion:1.0` the - old behaviour is emulated. -- The Nim compiler now implements a faster way to detect overflows based - on GCC's `__builtin_sadd_overflow` family of functions. (Clang also - supports these). Some versions of GCC lack this feature and unfortunately - we cannot detect this case reliably. So if you get compilation errors like - "undefined reference to `__builtin_saddll_overflow`" compile your programs - with `-d:nimEmulateOverflowChecks`. - - - - -## Bugfixes - -- Fixed "`nimgrep --nocolor` is ignored on posix; should be instead: `--nimgrep --color=[auto]|true|false`" - ([#7591](https://github.com/nim-lang/Nim/issues/7591)) -- Fixed "Runtime index on const array (of converted obj) causes C-compiler error" - ([#10514](https://github.com/nim-lang/Nim/issues/10514)) -- Fixed "windows x86 with vcc compile error with "asmNoStackFrame"" - ([#12298](https://github.com/nim-lang/Nim/issues/12298)) -- Fixed "[TODO] regression: Error: Locks requires --threads:on option" - ([#12330](https://github.com/nim-lang/Nim/issues/12330)) -- Fixed "Add --cc option to --help or --fullhelp output" - ([#12010](https://github.com/nim-lang/Nim/issues/12010)) -- Fixed "questionable `csize` definition in `system.nim`" - ([#12187](https://github.com/nim-lang/Nim/issues/12187)) -- Fixed "os.getAppFilename() returns incorrect results on OpenBSD" - ([#12389](https://github.com/nim-lang/Nim/issues/12389)) -- Fixed "HashSet[uint64] slow insertion depending on values" - ([#11764](https://github.com/nim-lang/Nim/issues/11764)) -- Fixed "Differences between compiling 'classic call syntax' vs 'method call syntax' ." - ([#12453](https://github.com/nim-lang/Nim/issues/12453)) -- Fixed "c -d:nodejs --> SIGSEGV: Illegal storage access" - ([#12502](https://github.com/nim-lang/Nim/issues/12502)) -- Fixed "Closure iterator crashes on --newruntime due to "dangling references"" - ([#12443](https://github.com/nim-lang/Nim/issues/12443)) -- Fixed "No `=destroy` for elements of closure environments other than for latest devel --gc:destructors" - ([#12577](https://github.com/nim-lang/Nim/issues/12577)) -- Fixed "strutils:formatBiggestFloat() gives different results in JS mode" - ([#8242](https://github.com/nim-lang/Nim/issues/8242)) -- Fixed "Regression (devel): the new `csize_t` definition isn't consistently used, nor tested thoroughly..." - ([#12597](https://github.com/nim-lang/Nim/issues/12597)) -- Fixed "tables.take() is defined only for `Table` and missed for other table containers" - ([#12519](https://github.com/nim-lang/Nim/issues/12519)) -- Fixed "`pthread_key_t` errors on OpenBSD" - ([#12135](https://github.com/nim-lang/Nim/issues/12135)) -- Fixed "newruntime: simple seq pop at ct results in compile error" - ([#12644](https://github.com/nim-lang/Nim/issues/12644)) -- Fixed "[Windows] finish.exe C:\Users\\.nimble\bin is not in your PATH environment variable." - ([#12319](https://github.com/nim-lang/Nim/issues/12319)) -- Fixed "Error with strformat + asyncdispatch + const" - ([#12612](https://github.com/nim-lang/Nim/issues/12612)) -- Fixed "MultipartData needs $" - ([#11863](https://github.com/nim-lang/Nim/issues/11863)) -- Fixed "Nim stdlib style issues with --styleCheck:error" - ([#12687](https://github.com/nim-lang/Nim/issues/12687)) -- Fixed "new $nimbleDir path substitution yields unexpected search paths" - ([#12767](https://github.com/nim-lang/Nim/issues/12767)) -- Fixed "Regression: inlined procs now get multiple rounds of destructor injection" - ([#12766](https://github.com/nim-lang/Nim/issues/12766)) -- Fixed "newruntime: compiler generates defective code" - ([#12669](https://github.com/nim-lang/Nim/issues/12669)) -- Fixed "broken windows modules path handling because of 'os.relativePath' breaking changes" - ([#12734](https://github.com/nim-lang/Nim/issues/12734)) -- Fixed "for loop tuple syntax not rendered correctly" - ([#12740](https://github.com/nim-lang/Nim/issues/12740)) -- Fixed "Crash when trying to use `type.name[0]`" - ([#12804](https://github.com/nim-lang/Nim/issues/12804)) -- Fixed "Enums should be considered Trivial types in Atomics" - ([#12812](https://github.com/nim-lang/Nim/issues/12812)) -- Fixed "Produce static/const initializations for variables when possible" - ([#12216](https://github.com/nim-lang/Nim/issues/12216)) -- Fixed "Assigning descriminator field leads to internal assert with --gc:destructors" - ([#12821](https://github.com/nim-lang/Nim/issues/12821)) -- Fixed "nimsuggest `use` command does not return all instances of symbol" - ([#12832](https://github.com/nim-lang/Nim/issues/12832)) -- Fixed "@[] is a problem for --gc:destructors" - ([#12820](https://github.com/nim-lang/Nim/issues/12820)) -- Fixed "Codegen ICE in allPathsAsgnResult" - ([#12827](https://github.com/nim-lang/Nim/issues/12827)) -- Fixed "seq[Object with ref and destructor type] doesn't work in old runtime" - ([#12882](https://github.com/nim-lang/Nim/issues/12882)) -- Fixed "Destructor not invoked because it is instantiated too late, old runtime" - ([#12883](https://github.com/nim-lang/Nim/issues/12883)) -- Fixed "The collect macro does not handle if/case correctly" - ([#12874](https://github.com/nim-lang/Nim/issues/12874)) -- Fixed "allow typed/untyped params in magic procs (even if not in stdlib)" - ([#12911](https://github.com/nim-lang/Nim/issues/12911)) -- Fixed "ARC/newruntime memory corruption" - ([#12899](https://github.com/nim-lang/Nim/issues/12899)) -- Fixed "tasyncclosestall.nim still flaky test: Address already in use" - ([#12919](https://github.com/nim-lang/Nim/issues/12919)) -- Fixed "newruntime and computed goto: variables inside the loop are in generated code uninitialised" - ([#12785](https://github.com/nim-lang/Nim/issues/12785)) -- Fixed "osx: dsymutil needs to be called for debug builds to keep debug info" - ([#12735](https://github.com/nim-lang/Nim/issues/12735)) -- Fixed "codegen ICE with ref objects, gc:destructors" - ([#12826](https://github.com/nim-lang/Nim/issues/12826)) -- Fixed "mutable iterator cannot yield named tuples" - ([#12945](https://github.com/nim-lang/Nim/issues/12945)) -- Fixed "parsecfg stores "\r\n" line breaks just as "\n"" - ([#12970](https://github.com/nim-lang/Nim/issues/12970)) -- Fixed "db_postgres.getValue issues warning when no rows found" - ([#12973](https://github.com/nim-lang/Nim/issues/12973)) -- Fixed "ARC: Unpacking tuple with seq causes segfault" - ([#12989](https://github.com/nim-lang/Nim/issues/12989)) -- Fixed "ARC/newruntime: strutils.join on seq with only empty strings causes segfault" - ([#12965](https://github.com/nim-lang/Nim/issues/12965)) -- Fixed "regression (1.0.4): `{.push exportc.}` wrongly affects generic instantiations, causing codegen errors" - ([#12985](https://github.com/nim-lang/Nim/issues/12985)) -- Fixed "cdt, crash with --gc:arc, works fine with default gc" - ([#12978](https://github.com/nim-lang/Nim/issues/12978)) -- Fixed "ARC: No indexError thrown on out-of-bound seq access, SIGSEGV instead" - ([#12961](https://github.com/nim-lang/Nim/issues/12961)) -- Fixed "ARC/async: Returning in a try-block results in wrong codegen" - ([#12956](https://github.com/nim-lang/Nim/issues/12956)) -- Fixed "asm keyword is generating wrong output C code when --cc:tcc" - ([#12988](https://github.com/nim-lang/Nim/issues/12988)) -- Fixed "Destructor not invoked" - ([#13026](https://github.com/nim-lang/Nim/issues/13026)) -- Fixed "ARC/newruntime: Adding inherited var ref object to seq with base type causes segfault" - ([#12964](https://github.com/nim-lang/Nim/issues/12964)) -- Fixed "Style check error with JS compiler target" - ([#13032](https://github.com/nim-lang/Nim/issues/13032)) -- Fixed "regression(1.0.4): undeclared identifier: 'readLines'; plus another regression and bug" - ([#13013](https://github.com/nim-lang/Nim/issues/13013)) -- Fixed "regression(1.04) `invalid pragma: since` with nim js" - ([#12996](https://github.com/nim-lang/Nim/issues/12996)) -- Fixed "Sink to MemMove optimization in injectdestructors" - ([#13002](https://github.com/nim-lang/Nim/issues/13002)) -- Fixed "--gc:arc: `catch` doesn't work with exception subclassing" - ([#13072](https://github.com/nim-lang/Nim/issues/13072)) -- Fixed "nim c --gc:arc --exceptions:{setjmp,goto} incorrectly handles raise; `nim cpp --gc:arc` is ok" - ([#13070](https://github.com/nim-lang/Nim/issues/13070)) -- Fixed "typetraits feature request - get subtype of a generic type" - ([#6454](https://github.com/nim-lang/Nim/issues/6454)) -- Fixed "CountTable inconsistencies between keys() and len() after setting value to 0" - ([#12813](https://github.com/nim-lang/Nim/issues/12813)) -- Fixed "{.align.} pragma is not applied if there is a generic field" - ([#13122](https://github.com/nim-lang/Nim/issues/13122)) -- Fixed "ARC, finalizer, allow rebinding the same function multiple times" - ([#13112](https://github.com/nim-lang/Nim/issues/13112)) -- Fixed "`nim doc` treats `export localSymbol` incorrectly" - ([#13100](https://github.com/nim-lang/Nim/issues/13100)) -- Fixed "--gc:arc SIGSEGV (double free?)" - ([#13119](https://github.com/nim-lang/Nim/issues/13119)) -- Fixed "codegen bug with arc" - ([#13105](https://github.com/nim-lang/Nim/issues/13105)) -- Fixed "symbols not defined in the grammar" - ([#10665](https://github.com/nim-lang/Nim/issues/10665)) -- Fixed "[JS] Move is not defined" - ([#9674](https://github.com/nim-lang/Nim/issues/9674)) -- Fixed "[TODO] pathutils.`/` can return invalid AbsoluteFile" - ([#13121](https://github.com/nim-lang/Nim/issues/13121)) -- Fixed "regression(1.04) `nim doc main.nim` generates broken html (no css)" - ([#12998](https://github.com/nim-lang/Nim/issues/12998)) -- Fixed "Wrong supportsCopyMem on string in type section" - ([#13095](https://github.com/nim-lang/Nim/issues/13095)) -- Fixed "Arc, finalizer, out of memory" - ([#13157](https://github.com/nim-lang/Nim/issues/13157)) -- Fixed "`--genscript` messes up nimcache and future nim invocations" - ([#13144](https://github.com/nim-lang/Nim/issues/13144)) -- Fixed "--gc:arc with --exceptions:goto for "nim c" generate invalid c code" - ([#13186](https://github.com/nim-lang/Nim/issues/13186)) -- Fixed "[regression] duplicate member `_i1` codegen bug" - ([#13195](https://github.com/nim-lang/Nim/issues/13195)) -- Fixed "RTree investigations with valgrind for --gc:arc" - ([#13110](https://github.com/nim-lang/Nim/issues/13110)) -- Fixed "relativePath("foo", ".") returns wrong path" - ([#13211](https://github.com/nim-lang/Nim/issues/13211)) -- Fixed "asyncftpclient - problem with welcome.msg" - ([#4684](https://github.com/nim-lang/Nim/issues/4684)) -- Fixed "Unclear error message, lowest priority" - ([#13256](https://github.com/nim-lang/Nim/issues/13256)) -- Fixed "Channel messages are corrupted" - ([#13219](https://github.com/nim-lang/Nim/issues/13219)) -- Fixed "Codegen bug with exportc and case objects" - ([#13281](https://github.com/nim-lang/Nim/issues/13281)) -- Fixed "[bugfix] fix #11590: c compiler warnings silently ignored, giving undefined behavior" - ([#11591](https://github.com/nim-lang/Nim/issues/11591)) -- Fixed "[CI] tnetdial flaky test" - ([#13132](https://github.com/nim-lang/Nim/issues/13132)) -- Fixed "Cross-Compiling with -d:mingw fails to locate compiler under OSX" - ([#10717](https://github.com/nim-lang/Nim/issues/10717)) -- Fixed "`nim doc --project` broken with imports below main project file or duplicate names" - ([#13150](https://github.com/nim-lang/Nim/issues/13150)) -- Fixed "regression: isNamedTuple(MyGenericTuple[int]) is false, should be true" - ([#13349](https://github.com/nim-lang/Nim/issues/13349)) -- Fixed "--gc:arc codegen bug copying objects bound to C structs with missing C struct fields" - ([#13269](https://github.com/nim-lang/Nim/issues/13269)) -- Fixed "write requires conversion to string" - ([#13182](https://github.com/nim-lang/Nim/issues/13182)) -- Fixed "Some remarks to stdlib documentation" - ([#13352](https://github.com/nim-lang/Nim/issues/13352)) -- Fixed "a `check` in unittest generated by template doesn't show actual value" - ([#6736](https://github.com/nim-lang/Nim/issues/6736)) -- Fixed "Implicit return with case expression fails with 'var' return." - ([#3339](https://github.com/nim-lang/Nim/issues/3339)) -- Fixed "Segfault with closure on arc" - ([#13314](https://github.com/nim-lang/Nim/issues/13314)) -- Fixed "[Macro] Crash on malformed case statement with multiple else" - ([#13255](https://github.com/nim-lang/Nim/issues/13255)) -- Fixed "regression: `echo 'discard' | nim c -r -` generates a file '-' ; `-` should be treated specially" - ([#13374](https://github.com/nim-lang/Nim/issues/13374)) -- Fixed "on OSX, debugging (w gdb or lldb) a nim program crashes at the 1st call to `execCmdEx`" - ([#9634](https://github.com/nim-lang/Nim/issues/9634)) -- Fixed "Internal error in getTypeDescAux" - ([#13378](https://github.com/nim-lang/Nim/issues/13378)) -- Fixed "gc:arc mode breaks tuple let" - ([#13368](https://github.com/nim-lang/Nim/issues/13368)) -- Fixed "Nim compiler hangs for certain C/C++ compiler errors" - ([#8648](https://github.com/nim-lang/Nim/issues/8648)) -- Fixed "htmlgen does not support `data-*` attributes" - ([#13444](https://github.com/nim-lang/Nim/issues/13444)) -- Fixed "[gc:arc] setLen will cause string not to be null-terminated." - ([#13457](https://github.com/nim-lang/Nim/issues/13457)) -- Fixed "joinPath("", "") is "/" ; should be """ - ([#13455](https://github.com/nim-lang/Nim/issues/13455)) -- Fixed "[CI] flaky test on windows: tests/osproc/texitcode.nim" - ([#13449](https://github.com/nim-lang/Nim/issues/13449)) -- Fixed "Casting to float32 on NimVM is broken" - ([#13479](https://github.com/nim-lang/Nim/issues/13479)) -- Fixed "`--hints:off` doesn't work (doesn't override ~/.config/nim.cfg)" - ([#8312](https://github.com/nim-lang/Nim/issues/8312)) -- Fixed "joinPath("", "") is "/" ; should be """ - ([#13455](https://github.com/nim-lang/Nim/issues/13455)) -- Fixed "tables.values is broken" - ([#13496](https://github.com/nim-lang/Nim/issues/13496)) -- Fixed "global user config can override project specific config" - ([#9405](https://github.com/nim-lang/Nim/issues/9405)) -- Fixed "Non deterministic macros and id consistency problem" - ([#12627](https://github.com/nim-lang/Nim/issues/12627)) -- Fixed "try expression doesn't work with return on expect branch" - ([#13490](https://github.com/nim-lang/Nim/issues/13490)) -- Fixed "CI will break every 4 years on feb 28: times doesn't handle leap years properly" - ([#13543](https://github.com/nim-lang/Nim/issues/13543)) -- Fixed "[minor] `nimgrep --word` doesn't work with operators (eg misses `1 +% 2`)" - ([#13528](https://github.com/nim-lang/Nim/issues/13528)) -- Fixed "`as` is usable as infix operator but its existence and precedence are not documented" - ([#13409](https://github.com/nim-lang/Nim/issues/13409)) -- Fixed "JSON unmarshalling drops seq's items" - ([#13531](https://github.com/nim-lang/Nim/issues/13531)) -- Fixed "os.joinPath returns wrong path when head ends '\' or '/' and tail starts '..'." - ([#13579](https://github.com/nim-lang/Nim/issues/13579)) -- Fixed "Block-local types with the same name lead to bad codegen (sighashes regression)" - ([#5170](https://github.com/nim-lang/Nim/issues/5170)) -- Fixed "tuple codegen error" - ([#12704](https://github.com/nim-lang/Nim/issues/12704)) -- Fixed "newHttpHeaders does not accept repeated headers" - ([#13573](https://github.com/nim-lang/Nim/issues/13573)) -- Fixed "regression: --incremental:on fails on simplest example" - ([#13319](https://github.com/nim-lang/Nim/issues/13319)) -- Fixed "strscan can't get value of last element in format" - ([#13605](https://github.com/nim-lang/Nim/issues/13605)) -- Fixed "hashes_examples crashes with "Bus Error" (unaligned access) on sparc64" - ([#12508](https://github.com/nim-lang/Nim/issues/12508)) -- Fixed "gc:arc bug with re-used `seq[T]`" - ([#13596](https://github.com/nim-lang/Nim/issues/13596)) -- Fixed "`raise CatchableError` is broken with --gc:arc when throwing inside a proc" - ([#13599](https://github.com/nim-lang/Nim/issues/13599)) -- Fixed "cpp --gc:arc --exceptions:goto fails to raise with discard" - ([#13436](https://github.com/nim-lang/Nim/issues/13436)) -- Fixed "terminal doesn't compile with -d:useWinAnsi" - ([#13607](https://github.com/nim-lang/Nim/issues/13607)) -- Fixed "Parsing "sink ptr T" - region needs to be an object type" - ([#12757](https://github.com/nim-lang/Nim/issues/12757)) -- Fixed "gc:arc + threads:on + closures compilation error" - ([#13519](https://github.com/nim-lang/Nim/issues/13519)) -- Fixed "[ARC] segmentation fault" - ([#13240](https://github.com/nim-lang/Nim/issues/13240)) -- Fixed "times.toDateTime buggy on 29th, 30th and 31th of each month" - ([#13558](https://github.com/nim-lang/Nim/issues/13558)) -- Fixed "Deque misbehaves on VM" - ([#13310](https://github.com/nim-lang/Nim/issues/13310)) -- Fixed "Nimscript listFiles should throw exception when path is not found" - ([#12676](https://github.com/nim-lang/Nim/issues/12676)) -- Fixed "koch boot fails if even an empty config.nims is present in ~/.config/nims/ [devel regression]" - ([#13633](https://github.com/nim-lang/Nim/issues/13633)) -- Fixed "nim doc generates lots of false positive LockLevel warnings" - ([#13218](https://github.com/nim-lang/Nim/issues/13218)) -- Fixed "Arrays are passed by copy to iterators, causing crashes, unnecessary allocations and slowdowns" - ([#12747](https://github.com/nim-lang/Nim/issues/12747)) -- Fixed "Range types always uses signed integer as a base type" - ([#13646](https://github.com/nim-lang/Nim/issues/13646)) -- Fixed "Generate c code cannot compile with recent devel version" - ([#13645](https://github.com/nim-lang/Nim/issues/13645)) -- Fixed "[regression] VM: Error: cannot convert -1 to uint64" - ([#13661](https://github.com/nim-lang/Nim/issues/13661)) -- Fixed "Spurious raiseException(Exception) detected" - ([#13654](https://github.com/nim-lang/Nim/issues/13654)) -- Fixed "gc:arc memory leak" - ([#13659](https://github.com/nim-lang/Nim/issues/13659)) -- Fixed "Error: cannot convert -1 to uint (inside tuples)" - ([#13671](https://github.com/nim-lang/Nim/issues/13671)) -- Fixed "strformat issue with --gc:arc" - ([#13622](https://github.com/nim-lang/Nim/issues/13622)) -- Fixed "astToStr doesn't work inside generics" - ([#13524](https://github.com/nim-lang/Nim/issues/13524)) -- Fixed "oswalkdir.walkDirRec wont return folders" - ([#11458](https://github.com/nim-lang/Nim/issues/11458)) -- Fixed "`echo 'echo 1' | nim c -r -` silently gives wrong results (nimBetterRun not updated for stdin)" - ([#13412](https://github.com/nim-lang/Nim/issues/13412)) -- Fixed "gc:arc destroys the global variable accidentally." - ([#13691](https://github.com/nim-lang/Nim/issues/13691)) -- Fixed "[minor] sigmatch errors should be sorted, for reproducible errors" - ([#13538](https://github.com/nim-lang/Nim/issues/13538)) -- Fixed "Exception when converting csize to clong" - ([#13698](https://github.com/nim-lang/Nim/issues/13698)) -- Fixed "ARC: variables are no copied on the thread spawn causing crashes" - ([#13708](https://github.com/nim-lang/Nim/issues/13708)) -- Fixed "Illegal distinct seq causes compiler crash" - ([#13720](https://github.com/nim-lang/Nim/issues/13720)) -- Fixed "cyclic seq definition crashes the compiler" - ([#13715](https://github.com/nim-lang/Nim/issues/13715)) -- Fixed "Iterator with openArray parameter make the argument evaluated many times" - ([#13417](https://github.com/nim-lang/Nim/issues/13417)) -- Fixed "net/asyncnet: Unable to access peer's certificate chain" - ([#13299](https://github.com/nim-lang/Nim/issues/13299)) -- Fixed "Accidentally "SIGSEGV: Illegal storage access" error after arc optimizations (#13325)" - ([#13709](https://github.com/nim-lang/Nim/issues/13709)) -- Fixed "Base64 Regression" - ([#13722](https://github.com/nim-lang/Nim/issues/13722)) -- Fixed "A regression (?) with --gc:arc and repr" - ([#13731](https://github.com/nim-lang/Nim/issues/13731)) -- Fixed "Internal compiler error when using the new variable pragmas" - ([#13737](https://github.com/nim-lang/Nim/issues/13737)) -- Fixed "bool conversion produces vcc 2019 warning at cpp compilation stage" - ([#13744](https://github.com/nim-lang/Nim/issues/13744)) -- Fixed "Compiler "does not detect" a type recursion error in the wrong code, remaining frozen" - ([#13763](https://github.com/nim-lang/Nim/issues/13763)) -- Fixed "[minor] regression: `Foo[0.0] is Foo[-0.0]` is now false" - ([#13730](https://github.com/nim-lang/Nim/issues/13730)) -- Fixed "`nim doc` - only whitespace on first line causes segfault" - ([#13631](https://github.com/nim-lang/Nim/issues/13631)) -- Fixed "hashset regression" - ([#13794](https://github.com/nim-lang/Nim/issues/13794)) -- Fixed "`os.getApplFreebsd` could return incorrect paths in the case of a long path" - ([#13806](https://github.com/nim-lang/Nim/issues/13806)) -- Fixed "Destructors are not inherited" - ([#13810](https://github.com/nim-lang/Nim/issues/13810)) -- Fixed "io.readLines AssertionError on devel" - ([#13829](https://github.com/nim-lang/Nim/issues/13829)) -- Fixed "exceptions:goto accidentally reset the variable during exception handling" - ([#13782](https://github.com/nim-lang/Nim/issues/13782)) diff --git a/changelogs/changelog_1_4_0.md b/changelogs/changelog_1_4_0.md deleted file mode 100644 index 77f66ffde..000000000 --- a/changelogs/changelog_1_4_0.md +++ /dev/null @@ -1,874 +0,0 @@ -# v1.4.0 - 2020-10-16 - - - -## Standard library additions and changes - -- Added some enhancements to `std/jsonutils` module. - * Added a possibility to deserialize JSON arrays directly to `HashSet` and - `OrderedSet` types and respectively to serialize those types to JSON arrays - via `jsonutils.fromJson` and `jsonutils.toJson` procedures. - * Added a possibility to deserialize JSON `null` objects to Nim option objects - and respectively to serialize Nim option object to JSON object if `isSome` - or to JSON null object if `isNone` via `jsonutils.fromJson` and - `jsonutils.toJson` procedures. - * Added a `Joptions` parameter to `jsonutils.fromJson` currently - containing two boolean options `allowExtraKeys` and `allowMissingKeys`. - - If `allowExtraKeys` is `true` Nim's object to which the JSON is parsed is - not required to have a field for every JSON key. - - If `allowMissingKeys` is `true` Nim's object to which JSON is parsed is - allowed to have fields without corresponding JSON keys. -- Added `bindParams`, `bindParam` to `db_sqlite` for binding parameters into a `SqlPrepared` statement. -- Added `tryInsert`,`insert` procs to `db_*` libs which accept primary key column name. -- Added `xmltree.newVerbatimText` support create `style`'s,`script`'s text. -- `uri` module now implements RFC-2397. -- Added [DOM Parser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser) - to the `dom` module for the JavaScript target. -- The default hash for `Ordinal` has changed to something more bit-scrambling. - `import hashes; proc hash(x: myInt): Hash = hashIdentity(x)` recovers the old - one in an instantiation context while `-d:nimIntHash1` recovers it globally. -- `deques.peekFirst` and `deques.peekLast` now have `var Deque[T] -> var T` overloads. -- File handles created from high-level abstractions in the stdlib will no longer - be inherited by child processes. In particular, these modules are affected: - `asyncdispatch`, `asyncnet`, `system`, `nativesockets`, `net` and `selectors`. - - For `asyncdispatch`, `asyncnet`, `net` and `nativesockets`, an `inheritable` - flag has been added to all `proc`s that create sockets, allowing the user to - control whether the resulting socket is inheritable. This flag is provided to - ease the writing of multi-process servers, where sockets inheritance is - desired. - - For a transition period, define `nimInheritHandles` to enable file handle - inheritance by default. This flag does **not** affect the `selectors` module - due to the differing semantics between operating systems. - - `asyncdispatch.setInheritable`, `system.setInheritable` and - `nativesockets.setInheritable` are also introduced for setting file handle or - socket inheritance. Not all platforms have these `proc`s defined. - -- The file descriptors created for internal bookkeeping by `ioselector_kqueue` - and `ioselector_epoll` will no longer be leaked to child processes. - -- `strutils.formatFloat` with `precision = 0` has been restored to the version - 1 behaviour that produces a trailing dot, e.g. `formatFloat(3.14159, precision = 0)` - is now `3.`, not `3`. -- Added `commonPrefixLen` to `critbits`. - -- `relativePath(rel, abs)` and `relativePath(abs, rel)` used to silently give wrong results - (see #13222); instead they now use `getCurrentDir` to resolve those cases, - and this can now throw in edge cases where `getCurrentDir` throws. - `relativePath` also now works for js with `-d:nodejs`. - -- JavaScript and NimScript standard library changes: `streams.StringStream` is - now supported in JavaScript, with the limitation that any buffer `pointer`s - used must be castable to `ptr string`, any incompatible pointer type will not - work. The `lexbase` and `streams` modules used to fail to compile on - NimScript due to a bug, but this has been fixed. - - The following modules now compile on both JS and NimScript: `parsecsv`, - `parsecfg`, `parsesql`, `xmlparser`, `htmlparser` and `ropes`. Additionally - supported for JS is `cstrutils.startsWith` and `cstrutils.endsWith`, for - NimScript: `json`, `parsejson`, `strtabs` and `unidecode`. - -- Added `streams.readStr` and `streams.peekStr` overloads to - accept an existing string to modify, which avoids memory - allocations, similar to `streams.readLine` (#13857). - -- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom` UDP functionality. - -- `dollars.$` now works for unsigned ints with `nim js`. - -- Improvements to the `bitops` module, including bitslices, non-mutating versions - of the original masking functions, `mask`/`masked`, and varargs support for - `bitand`, `bitor`, and `bitxor`. - -- `sugar.=>` and `sugar.->` changes: Previously `(x, y: int)` was transformed - into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` for consistency - with regular proc definitions (although you cannot use semicolons). - - Pragmas and using a name are now allowed on the lefthand side of `=>`. Here - is an example of these changes: - ```nim - import sugar - - foo(x, y: int) {.noSideEffect.} => x + y - - # is transformed into - - proc foo(x: int, y: int): auto {.noSideEffect.} = x + y - ``` - -- The fields of `times.DateTime` are now private, and are accessed with getters and deprecated setters. - -- The `times` module now handles the default value for `DateTime` more consistently. - Most procs raise an assertion error when given - an uninitialized `DateTime`, the exceptions are `==` and `$` (which returns `"Uninitialized DateTime"`). - The proc `times.isInitialized` has been added which can be used to check if - a `DateTime` has been initialized. - -- Fix a bug where calling `close` on io streams in `osproc.startProcess` was a noop and led to - hangs if a process had both reads from stdin and writes (e.g. to stdout). - -- The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`. -- The callback that is assigned to `system.onUnhandledException` must now be `.gcsafe`. - -- `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env` - parameters. - -- Added a `ssl_config` module containing lists of secure ciphers as recommended by - [Mozilla OpSec](https://wiki.mozilla.org/Security/Server_Side_TLS) - -- `net.newContext` now defaults to the list of ciphers targeting - ["Intermediate compatibility"](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29) - per Mozilla's recommendation instead of `ALL`. This change should protect - users from the use of weak and insecure ciphers while still provides - adequate compatibility with the majority of the Internet. - -- A new module `std/jsonutils` with hookable `jsonTo,toJson,fromJson` operations for json - serialization/deserialization of custom types was added. - -- A new proc `heapqueue.find[T](heap: HeapQueue[T], x: T): int` to get index of element ``x`` - was added. -- Added `rstgen.rstToLatex` a convenience proc for `renderRstToOut` and `initRstGenerator`. -- Added `os.normalizeExe`. -- `macros.newLit` now preserves named vs unnamed tuples. -- Added `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution. -- Added `typetraits.elementType` to get the element type of an iterable. -- `typetraits.$` changes: `$(int,)` is now `"(int,)"` instead of `"(int)"`; - `$tuple[]` is now `"tuple[]"` instead of `"tuple"`; - `$((int, float), int)` is now `"((int, float), int)"` instead of `"(tuple of (int, float), int)"` -- Added `macros.extractDocCommentsAndRunnables` helper. - -- `strformat.fmt` and `strformat.&` support `specifier =`. `fmt"{expr=}"` now - expands to `fmt"expr={expr}"`. -- Deprecations: instead of `os.existsDir` use `dirExists`, instead of `os.existsFile` use `fileExists`. - -- Added the `jsre` module, [Regular Expressions for the JavaScript target.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions). -- Made `maxLines` argument `Positive` in `logging.newRollingFileLogger`, - because negative values will result in a new file being created for each logged - line which doesn't make sense. -- Changed `log` in `logging` to use proper log level for JavaScript, - e.g. `debug` uses `console.debug`, `info` uses `console.info`, `warn` uses `console.warn`, etc. -- Tables, HashSets, SharedTables and deques don't require anymore that the passed - initial size must be a power of two - this is done internally. - Proc `rightSize` for Tables and HashSets is deprecated, as it is not needed anymore. - `CountTable.inc` takes `val: int` again not `val: Positive`; i.e. it can "count down" again. -- Removed deprecated symbols from `macros` module, some of which were deprecated already in `0.15`. -- Removed `sugar.distinctBase`, deprecated since `0.19`. Use `typetraits.distinctBase`. -- `asyncdispatch.PDispatcher.handles` is exported so that an external low-level libraries can access it. - -- `std/with`, `sugar.dup` now support object field assignment expressions: - ```nim - import std/with - - type Foo = object - x, y: int - - var foo = Foo() - with foo: - x = 10 - y = 20 - - echo foo - ``` - -- Proc `math.round` is no longer deprecated. The advice to use `strformat` instead - cannot be applied to every use case. The limitations and the (lack of) reliability - of `round` are well documented. - -- Added `getprotobyname` to `winlean`. Added `getProtoByname` to `nativesockets` which returns a protocol code - from the database that matches the protocol `name`. - -- Added missing attributes and methods to `dom.Navigator` like `deviceMemory`, `onLine`, `vibrate()`, etc. - -- Added `strutils.indentation` and `strutils.dedent` which enable indented string literals: - ```nim - import strutils - echo dedent """ - This - is - cool! - """ - ``` - -- Added `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname. - -- Added `readLines(p: Process)` to `osproc`. - -- Added the below `toX` procs for collections. The usage is similar to procs such as - `sets.toHashSet` and `tables.toTable`. Previously, it was necessary to create the - respective empty collection and add items manually. - * `critbits.toCritBitTree`, which creates a `CritBitTree` from an `openArray` of - items or an `openArray` of pairs. - * `deques.toDeque`, which creates a `Deque` from an `openArray`. - * `heapqueue.toHeapQueue`, which creates a `HeapQueue` from an `openArray`. - * `intsets.toIntSet`, which creates an `IntSet` from an `openArray`. - -- Added `progressInterval` argument to `asyncftpclient.newAsyncFtpClient` to control the interval - at which progress callbacks are called. - -- Added `os.copyFileToDir`. - -## Language changes - -- The `=destroy` hook no longer has to reset its target, as the compiler now automatically inserts - `wasMoved` calls where needed. -- The `=` hook is now called `=copy` for clarity. The old name `=` is still available so there - is no need to update your code. This change was backported to 1.2 too so you can use the - more readable `=copy` without loss of compatibility. - -- In the newruntime it is now allowed to assign to the discriminator field - without restrictions as long as the case object doesn't have a custom destructor. - The discriminator value doesn't have to be a constant either. If you have a - custom destructor for a case object and you do want to freely assign discriminator - fields, it is recommended to refactor the object into 2 objects like this: - - ```nim - type - MyObj = object - case kind: bool - of true: y: ptr UncheckedArray[float] - of false: z: seq[int] - - proc `=destroy`(x: MyObj) = - if x.kind and x.y != nil: - deallocShared(x.y) - ``` - Refactor into: - ```nim - type - MySubObj = object - val: ptr UncheckedArray[float] - MyObj = object - case kind: bool - of true: y: MySubObj - of false: z: seq[int] - - proc `=destroy`(x: MySubObj) = - if x.val != nil: - deallocShared(x.val) - ``` -- `getImpl` on enum type symbols now returns field syms instead of idents. This helps - with writing typed macros. The old behavior for backwards compatibility can be restored - with `--useVersion:1.0`. -- The typed AST for proc headers will now have the arguments be syms instead of idents. - This helps with writing typed macros. The old behaviour for backwards compatibility can - be restored with `--useVersion:1.0`. -- ``let`` statements can now be used without a value if declared with - ``importc``/``importcpp``/``importjs``/``importobjc``. -- The keyword `from` is now usable as an operator. -- Exceptions inheriting from `system.Defect` are no longer tracked with - the `.raises: []` exception tracking mechanism. This is more consistent with the - built-in operations. The following always used to compile (and still does): - ```nim - proc mydiv(a, b): int {.raises: [].} = - a div b # can raise an DivByZeroDefect - ``` - - Now also this compiles: - ```nim - proc mydiv(a, b): int {.raises: [].} = - if b == 0: raise newException(DivByZeroDefect, "division by zero") - else: result = a div b - ``` - - The reason for this is that `DivByZeroDefect` inherits from `Defect` and - with `--panics:on` `Defects` become unrecoverable errors. - -- Added the `thiscall` calling convention as specified by Microsoft, mostly for hooking purposes. -- Deprecated the `{.unroll.}` pragma, because it was always ignored by the compiler anyway. -- Removed the deprecated `strutils.isNilOrWhitespace`. -- Removed the deprecated `sharedtables.initSharedTable`. -- Removed the deprecated `asyncdispatch.newAsyncNativeSocket`. -- Removed the deprecated `dom.releaseEvents` and `dom.captureEvents`. - -- Removed `sharedlist.initSharedList`, was deprecated and produces undefined behaviour. - -- There is a new experimental feature called "strictFuncs" which makes the definition of - `.noSideEffect` stricter. [See here](manual_experimental.html#stricts-funcs) - for more information. - -- "for-loop macros" (see [the manual](manual.html#macros-for-loop-macros)) are no longer - an experimental feature. In other words, you don't have to write pragma - `{.experimental: "forLoopMacros".}` if you want to use them. - -- Added the ``.noalias`` pragma. It is mapped to C's ``restrict`` keyword for the increased - performance this keyword can enable. - -- `items` no longer compiles with enums with holes as its behavior was error prone, see #14004. -- `system.deepcopy` has to be enabled explicitly for `--gc:arc` and `--gc:orc` via - `--deepcopy:on`. - -- Added the `std/effecttraits` module for introspection of the inferred effects. - We hope this enables `async` macros that are precise about the possible exceptions that - can be raised. -- The pragma blocks `{.gcsafe.}: ...` and `{.noSideEffect.}: ...` can now also be - written as `{.cast(gcsafe).}: ...` and `{.cast(noSideEffect).}: ...`. This is the new - preferred way of writing these, emphasizing their unsafe nature. - - -## Compiler changes - -- Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. -- The `define` and `undef` pragmas have been de-deprecated. -- New command: `nim r main.nim [args...]` which compiles and runs main.nim, and implies `--usenimcache` - so that the output is saved to $nimcache/main$exeExt, using the same logic as `nim c -r` to - avoid recompilations when sources don't change. - Example: - ```bash - nim r compiler/nim.nim --help # only compiled the first time - echo 'import os; echo getCurrentCompilerExe()' | nim r - # this works too - nim r compiler/nim.nim --fullhelp # no recompilation - nim r --nimcache:/tmp main # binary saved to /tmp/main - ``` -- `--hint:processing` is now supported and means `--hint:processing:on` - (likewise with other hints and warnings), which is consistent with all other bool flags. - (since 1.3.3). -- `nim doc -r main` and `nim rst2html -r main` now call `openDefaultBrowser`. -- Added the new hint `--hint:msgOrigin` will show where a compiler msg (hint|warning|error) - was generated; this helps in particular when it's non obvious where it came from - either because multiple locations generate the same message, or because the - message involves runtime formatting. -- Added the new flag `--backend:js|c|cpp|objc` (or -b:js etc), to change the backend; can be - used with any command (e.g. nim r, doc, check etc); safe to re-assign. -- Added the new flag `--doccmd:cmd` to pass additional flags for runnableExamples, - e.g.: `--doccmd:-d:foo --threads` - use `--doccmd:skip` to skip runnableExamples and rst test snippets. -- Added the new flag `--usenimcache` to output binary files to nimcache. -- `runnableExamples "-b:cpp -r:off": code` is now supported, allowing to override - how an example is compiled and run, for example to change the backend. -- `nim doc` now outputs under `$projectPath/htmldocs` when `--outdir` is unspecified - (with or without `--project`); passing `--project` now automatically generates - an index and enables search. - See [docgen](docgen.html#introduction-quick-start) for details. -- Removed the `--oldNewlines` switch. -- Removed the `--laxStrings` switch for mutating the internal zero terminator on strings. -- Removed the `--oldast` switch. -- Removed the `--oldgensym` switch. -- `$getType(untyped)` is now "untyped" instead of "expr", `$getType(typed)` is - now "typed" instead of "stmt". -- Sink inference is now disabled per default and has to enabled explicitly via - `--sinkInference:on`. *Note*: For the standard library sink inference remains - enabled. This change is most relevant for the `--gc:arc`, `--gc:orc` memory - management modes. - - -## Tool changes - -- `nimsuggest` now returns both the forward declaration and the - implementation location upon a `def` query. Previously the behavior was - to return the forward declaration only. - - -## Bugfixes - -- Fixed "repr() not available for uint{,8,16,32,64} under --gc:arc" - ([#13872](https://github.com/nim-lang/Nim/issues/13872)) -- Fixed "Critical: 1 completed Future, multiple await: Only 1 await will be awakened (the last one)" - ([#13889](https://github.com/nim-lang/Nim/issues/13889)) -- Fixed "crash on openarray interator with argument in stmtListExpr" - ([#13739](https://github.com/nim-lang/Nim/issues/13739)) -- Fixed "Some compilers on Windows don't work" - ([#13910](https://github.com/nim-lang/Nim/issues/13910)) -- Fixed "httpclient hangs if it recieves an HTTP 204 (No Content)" - ([#13894](https://github.com/nim-lang/Nim/issues/13894)) -- Fixed ""distinct uint64" type corruption on 32-bit, when using {.borrow.} operators" - ([#13902](https://github.com/nim-lang/Nim/issues/13902)) -- Fixed "Regression: impossible to use typed pragmas with proc types" - ([#13909](https://github.com/nim-lang/Nim/issues/13909)) -- Fixed "openssl wrapper corrupts stack on OpenSSL 1.1.1f + Android" - ([#13903](https://github.com/nim-lang/Nim/issues/13903)) -- Fixed "C compile error with --gc:arc on version 1.2.0 "unknown type name 'TGenericSeq'" - ([#13863](https://github.com/nim-lang/Nim/issues/13863)) -- Fixed "var return type for proc doesn't work at c++ backend" - ([#13848](https://github.com/nim-lang/Nim/issues/13848)) -- Fixed "TimeFormat() should raise an error but craches at compilation time" - ([#12864](https://github.com/nim-lang/Nim/issues/12864)) -- Fixed "gc:arc cannot fully support threadpool with FlowVar" - ([#13781](https://github.com/nim-lang/Nim/issues/13781)) -- Fixed "simple 'var openarray[char]' assignment crash when the openarray source is a local string and using gc:arc" - ([#14003](https://github.com/nim-lang/Nim/issues/14003)) -- Fixed "Cant use expressions with `when` in `type` sections." - ([#14007](https://github.com/nim-lang/Nim/issues/14007)) -- Fixed "`for a in MyEnum` gives incorrect results with enum with holes" - ([#14001](https://github.com/nim-lang/Nim/issues/14001)) -- Fixed "Trivial crash" - ([#12741](https://github.com/nim-lang/Nim/issues/12741)) -- Fixed "Enum with holes cannot be used as Table index" - ([#12834](https://github.com/nim-lang/Nim/issues/12834)) -- Fixed "spawn proc that uses typedesc crashes the compiler" - ([#14014](https://github.com/nim-lang/Nim/issues/14014)) -- Fixed "Docs Search `Results` box styling is not Dark Mode Friendly" - ([#13972](https://github.com/nim-lang/Nim/issues/13972)) -- Fixed "--gc:arc -d:useSysAssert undeclared identifier `cstderr` with newSeq" - ([#14038](https://github.com/nim-lang/Nim/issues/14038)) -- Fixed "issues in the manual" - ([#12486](https://github.com/nim-lang/Nim/issues/12486)) -- Fixed "Annoying warning: inherit from a more precise exception type like ValueError, IOError or OSError [InheritFromException]" - ([#14052](https://github.com/nim-lang/Nim/issues/14052)) -- Fixed "relativePath("foo", "/") and relativePath("/", "foo") is wrong" - ([#13222](https://github.com/nim-lang/Nim/issues/13222)) -- Fixed "[regression] `parseEnum` does not work anymore for enums with holes" - ([#14030](https://github.com/nim-lang/Nim/issues/14030)) -- Fixed "Exception types in the stdlib should inherit from `CatchableError` or `Defect`, not `Exception`" - ([#10288](https://github.com/nim-lang/Nim/issues/10288)) -- Fixed "Make debugSend and debugRecv procs public in smtp.nim" - ([#12189](https://github.com/nim-lang/Nim/issues/12189)) -- Fixed "xmltree need add raw text, when add style element" - ([#14064](https://github.com/nim-lang/Nim/issues/14064)) -- Fixed "raises requirement does not propagate to derived methods" - ([#8481](https://github.com/nim-lang/Nim/issues/8481)) -- Fixed "tests/stdlib/tgetaddrinfo.nim fails on NetBSD" - ([#14091](https://github.com/nim-lang/Nim/issues/14091)) -- Fixed "tests/niminaction/Chapter8/sdl/sdl_test.nim fails on NetBSD" - ([#14088](https://github.com/nim-lang/Nim/issues/14088)) -- Fixed "Incorrect escape sequence for example in jsffi library documentation" - ([#14110](https://github.com/nim-lang/Nim/issues/14110)) -- Fixed "HCR: Can not link exported const, in external library" - ([#13915](https://github.com/nim-lang/Nim/issues/13915)) -- Fixed "Cannot import std/unidecode" - ([#14112](https://github.com/nim-lang/Nim/issues/14112)) -- Fixed "macOS: dsymutil should not be called on static libraries" - ([#14132](https://github.com/nim-lang/Nim/issues/14132)) -- Fixed "nim jsondoc -o:doc.json filename.nim fails when sequences without a type are used" - ([#14066](https://github.com/nim-lang/Nim/issues/14066)) -- Fixed "algorithm.sortedByIt template corrupts tuple input under --gc:arc" - ([#14079](https://github.com/nim-lang/Nim/issues/14079)) -- Fixed "Invalid C code with lvalue conversion" - ([#14160](https://github.com/nim-lang/Nim/issues/14160)) -- Fixed "strformat: doc example fails" - ([#14054](https://github.com/nim-lang/Nim/issues/14054)) -- Fixed "Nim doc fail to run for nim 1.2.0 (nim 1.0.4 is ok)" - ([#13986](https://github.com/nim-lang/Nim/issues/13986)) -- Fixed "Exception when converting csize to clong" - ([#13698](https://github.com/nim-lang/Nim/issues/13698)) -- Fixed "[Documentation] overloading using named arguments works but is not documented" - ([#11932](https://github.com/nim-lang/Nim/issues/11932)) -- Fixed "import os + use of existsDir/dirExists/existsFile/fileExists/findExe in config.nims causes "ambiguous call' error" - ([#14142](https://github.com/nim-lang/Nim/issues/14142)) -- Fixed "import os + use of existsDir/dirExists/existsFile/fileExists/findExe in config.nims causes "ambiguous call' error" - ([#14142](https://github.com/nim-lang/Nim/issues/14142)) -- Fixed "runnableExamples doc gen crashes compiler with `except Exception as e` syntax" - ([#14177](https://github.com/nim-lang/Nim/issues/14177)) -- Fixed "[ARC] Segfault with cyclic references (?)" - ([#14159](https://github.com/nim-lang/Nim/issues/14159)) -- Fixed "Semcheck regression when accessing a static parameter in proc" - ([#14136](https://github.com/nim-lang/Nim/issues/14136)) -- Fixed "iterator walkDir doesn't work with -d:useWinAnsi" - ([#14201](https://github.com/nim-lang/Nim/issues/14201)) -- Fixed "cas is wrong for tcc" - ([#14151](https://github.com/nim-lang/Nim/issues/14151)) -- Fixed "proc execCmdEx doesn't work with -d:useWinAnsi" - ([#14203](https://github.com/nim-lang/Nim/issues/14203)) -- Fixed "Use -d:nimEmulateOverflowChecks by default?" - ([#14209](https://github.com/nim-lang/Nim/issues/14209)) -- Fixed "Old sequences with destructor objects bug" - ([#14217](https://github.com/nim-lang/Nim/issues/14217)) -- Fixed "[ARC] ICE when changing the discriminant of a return value" - ([#14244](https://github.com/nim-lang/Nim/issues/14244)) -- Fixed "[ARC] ICE with static objects" - ([#14236](https://github.com/nim-lang/Nim/issues/14236)) -- Fixed "[ARC] "internal error: environment misses: a" in a finalizer" - ([#14243](https://github.com/nim-lang/Nim/issues/14243)) -- Fixed "[ARC] compile failure using repr with object containing `ref seq[string]`" - ([#14270](https://github.com/nim-lang/Nim/issues/14270)) -- Fixed "[ARC] implicit move on last use happening on non-last use" - ([#14269](https://github.com/nim-lang/Nim/issues/14269)) -- Fixed "[ARC] Compiler crash with a recursive non-ref object variant" - ([#14294](https://github.com/nim-lang/Nim/issues/14294)) -- Fixed "htmlparser.parseHtml behaves differently using --gc:arc or --gc:orc" - ([#13946](https://github.com/nim-lang/Nim/issues/13946)) -- Fixed "Invalid return value of openProcess is NULL rather than INVALID_HANDLE_VALUE(-1) in windows" - ([#14289](https://github.com/nim-lang/Nim/issues/14289)) -- Fixed "ARC codegen bug with inline iterators" - ([#14219](https://github.com/nim-lang/Nim/issues/14219)) -- Fixed "Building koch on OpenBSD fails unless the Nim directory is in `$PATH`" - ([#13758](https://github.com/nim-lang/Nim/issues/13758)) -- Fixed "[gc:arc] case object assignment SIGSEGV: destroy not called for primitive type " - ([#14312](https://github.com/nim-lang/Nim/issues/14312)) -- Fixed "Crash when using thread and --gc:arc " - ([#13881](https://github.com/nim-lang/Nim/issues/13881)) -- Fixed "Getting "Warning: Cannot prove that 'result' is initialized" for an importcpp'd proc with `var T` return type" - ([#14314](https://github.com/nim-lang/Nim/issues/14314)) -- Fixed "`nim cpp -r --gc:arc` segfaults on caught AssertionError" - ([#13071](https://github.com/nim-lang/Nim/issues/13071)) -- Fixed "tests/async/tasyncawait.nim is recently very flaky" - ([#14320](https://github.com/nim-lang/Nim/issues/14320)) -- Fixed "Documentation nonexistent quitprocs module" - ([#14331](https://github.com/nim-lang/Nim/issues/14331)) -- Fixed "SIGSEV encountered when creating threads in a loop w/ --gc:arc" - ([#13935](https://github.com/nim-lang/Nim/issues/13935)) -- Fixed "nim-gdb is missing from all released packages" - ([#13104](https://github.com/nim-lang/Nim/issues/13104)) -- Fixed "sysAssert error with gc:arc on 3 line program" - ([#13862](https://github.com/nim-lang/Nim/issues/13862)) -- Fixed "compiler error with inline async proc and pragma" - ([#13998](https://github.com/nim-lang/Nim/issues/13998)) -- Fixed "[ARC] Compiler crash when adding to a seq[ref Object]" - ([#14333](https://github.com/nim-lang/Nim/issues/14333)) -- Fixed "nimvm: sysFatal: unhandled exception: 'sons' is not accessible using discriminant 'kind' of type 'TNode' [FieldError]" - ([#14340](https://github.com/nim-lang/Nim/issues/14340)) -- Fixed "[Regression] karax events are not firing " - ([#14350](https://github.com/nim-lang/Nim/issues/14350)) -- Fixed "odbcsql module has some wrong integer types" - ([#9771](https://github.com/nim-lang/Nim/issues/9771)) -- Fixed "db_sqlite needs sqlPrepared" - ([#13559](https://github.com/nim-lang/Nim/issues/13559)) -- Fixed "[Regression] `createThread` is not GC-safe" - ([#14370](https://github.com/nim-lang/Nim/issues/14370)) -- Fixed "Broken example on hot code reloading" - ([#14380](https://github.com/nim-lang/Nim/issues/14380)) -- Fixed "runnableExamples block with `except` on specified error fails with `nim doc`" - ([#12746](https://github.com/nim-lang/Nim/issues/12746)) -- Fixed "compiler as a library: findNimStdLibCompileTime fails to find system.nim" - ([#12293](https://github.com/nim-lang/Nim/issues/12293)) -- Fixed "5 bugs with importcpp exceptions" - ([#14369](https://github.com/nim-lang/Nim/issues/14369)) -- Fixed "Docs shouldn't collapse pragmas inside runnableExamples/code blocks" - ([#14174](https://github.com/nim-lang/Nim/issues/14174)) -- Fixed "Bad codegen/emit for hashes.hiXorLo in some contexts." - ([#14394](https://github.com/nim-lang/Nim/issues/14394)) -- Fixed "Boehm GC does not scan thread-local storage" - ([#14364](https://github.com/nim-lang/Nim/issues/14364)) -- Fixed "RVO not exception safe" - ([#14126](https://github.com/nim-lang/Nim/issues/14126)) -- Fixed "runnableExamples that are only compiled" - ([#10731](https://github.com/nim-lang/Nim/issues/10731)) -- Fixed "`foldr` raises IndexError when called on sequence" - ([#14404](https://github.com/nim-lang/Nim/issues/14404)) -- Fixed "moveFile does not overwrite destination file" - ([#14057](https://github.com/nim-lang/Nim/issues/14057)) -- Fixed "doc2 outputs in current work dir" - ([#6583](https://github.com/nim-lang/Nim/issues/6583)) -- Fixed "[docgen] proc doc comments silently omitted after 1st runnableExamples" - ([#9227](https://github.com/nim-lang/Nim/issues/9227)) -- Fixed "`nim doc --project` shows '@@/' instead of '../' for relative paths to submodules" - ([#14448](https://github.com/nim-lang/Nim/issues/14448)) -- Fixed "re, nre have wrong `start` semantics" - ([#14284](https://github.com/nim-lang/Nim/issues/14284)) -- Fixed "runnableExamples should preserve source code doc comments, strings, and (maybe) formatting" - ([#8871](https://github.com/nim-lang/Nim/issues/8871)) -- Fixed "`nim doc ..` fails when runnableExamples uses `$` [devel] [regression]" - ([#14485](https://github.com/nim-lang/Nim/issues/14485)) -- Fixed "`items` is 20%~30% slower than iteration via an index" - ([#14421](https://github.com/nim-lang/Nim/issues/14421)) -- Fixed "ARC: unreliable setLen " - ([#14495](https://github.com/nim-lang/Nim/issues/14495)) -- Fixed "lent is unsafe: after #14447 you can modify variables with "items" loop for sequences" - ([#14498](https://github.com/nim-lang/Nim/issues/14498)) -- Fixed "`var op = fn()` wrongly gives warning `ObservableStores` with `object of RootObj` type" - ([#14514](https://github.com/nim-lang/Nim/issues/14514)) -- Fixed "Compiler assertion" - ([#14562](https://github.com/nim-lang/Nim/issues/14562)) -- Fixed "Can't get `ord` of a value of a Range type in the JS backend " - ([#14570](https://github.com/nim-lang/Nim/issues/14570)) -- Fixed "js: can't take addr of param (including implicitly via `lent`)" - ([#14576](https://github.com/nim-lang/Nim/issues/14576)) -- Fixed "{.noinit.} ignored in for loop -> bad codegen for non-movable types" - ([#14118](https://github.com/nim-lang/Nim/issues/14118)) -- Fixed "generic destructor gives: `Error: unresolved generic parameter`" - ([#14315](https://github.com/nim-lang/Nim/issues/14315)) -- Fixed "Memory leak with arc gc" - ([#14568](https://github.com/nim-lang/Nim/issues/14568)) -- Fixed "escape analysis broken with `lent`" - ([#14557](https://github.com/nim-lang/Nim/issues/14557)) -- Fixed "`wrapWords` seems to ignore linebreaks when wrapping, leaving breaks in the wrong place" - ([#14579](https://github.com/nim-lang/Nim/issues/14579)) -- Fixed "`lent` gives wrong results with -d:release" - ([#14578](https://github.com/nim-lang/Nim/issues/14578)) -- Fixed "Nested await expressions regression: `await a(await expandValue())` doesnt compile" - ([#14279](https://github.com/nim-lang/Nim/issues/14279)) -- Fixed "windows CI docs fails with strange errors" - ([#14545](https://github.com/nim-lang/Nim/issues/14545)) -- Fixed "[CI] tests/async/tioselectors.nim flaky test for freebsd + OSX CI" - ([#13166](https://github.com/nim-lang/Nim/issues/13166)) -- Fixed "seq.setLen sometimes doesn't zero memory" - ([#14655](https://github.com/nim-lang/Nim/issues/14655)) -- Fixed "`nim dump` is roughly 100x slower in 1.3 versus 1.2" - ([#14179](https://github.com/nim-lang/Nim/issues/14179)) -- Fixed "Regression: devel docgen cannot generate document for method" - ([#14691](https://github.com/nim-lang/Nim/issues/14691)) -- Fixed "recently flaky tests/async/t7758.nim" - ([#14685](https://github.com/nim-lang/Nim/issues/14685)) -- Fixed "Bind no longer working in generic procs." - ([#11811](https://github.com/nim-lang/Nim/issues/11811)) -- Fixed "The pegs module doesn't work with generics!" - ([#14718](https://github.com/nim-lang/Nim/issues/14718)) -- Fixed "Defer is not properly working for asynchronous procedures." - ([#13899](https://github.com/nim-lang/Nim/issues/13899)) -- Fixed "Add an ARC test with threads in a loop" - ([#14690](https://github.com/nim-lang/Nim/issues/14690)) -- Fixed "[goto exceptions] {.noReturn.} pragma is not detected in a case expression" - ([#14458](https://github.com/nim-lang/Nim/issues/14458)) -- Fixed "[exceptions:goto] C compiler error with dynlib pragma calling a proc" - ([#14240](https://github.com/nim-lang/Nim/issues/14240)) -- Fixed "Cannot borrow var float64 in infix assignment" - ([#14440](https://github.com/nim-lang/Nim/issues/14440)) -- Fixed "lib/pure/memfiles.nim: compilation error with --taintMode:on" - ([#14760](https://github.com/nim-lang/Nim/issues/14760)) -- Fixed "newWideCString allocates a multiple of the memory needed" - ([#14750](https://github.com/nim-lang/Nim/issues/14750)) -- Fixed "Nim source archive install: 'install.sh' fails with error: cp: cannot stat 'bin/nim-gdb': No such file or directory" - ([#14748](https://github.com/nim-lang/Nim/issues/14748)) -- Fixed "`nim cpp -r tests/exception/t9657` hangs" - ([#10343](https://github.com/nim-lang/Nim/issues/10343)) -- Fixed "Detect tool fails on FreeBSD" - ([#14715](https://github.com/nim-lang/Nim/issues/14715)) -- Fixed "compiler crash: `findUnresolvedStatic` " - ([#14802](https://github.com/nim-lang/Nim/issues/14802)) -- Fixed "seq namespace (?) regression" - ([#4796](https://github.com/nim-lang/Nim/issues/4796)) -- Fixed "Possible out of bounds string access in std/colors parseColor and isColor" - ([#14839](https://github.com/nim-lang/Nim/issues/14839)) -- Fixed "compile error on latest devel with orc and ssl" - ([#14647](https://github.com/nim-lang/Nim/issues/14647)) -- Fixed "[minor] `$` wrong for type tuple" - ([#13432](https://github.com/nim-lang/Nim/issues/13432)) -- Fixed "Documentation missing on devel asyncftpclient" - ([#14846](https://github.com/nim-lang/Nim/issues/14846)) -- Fixed "nimpretty is confused with a trailing comma in enum definition" - ([#14401](https://github.com/nim-lang/Nim/issues/14401)) -- Fixed "Output arguments get ignored when compiling with --app:staticlib" - ([#12745](https://github.com/nim-lang/Nim/issues/12745)) -- Fixed "[ARC] destructive move destroys the object too early" - ([#14396](https://github.com/nim-lang/Nim/issues/14396)) -- Fixed "highlite.getNextToken() crashes if the buffer string is "echo "\""" - ([#14830](https://github.com/nim-lang/Nim/issues/14830)) -- Fixed "Memory corruption with --gc:arc with a seq of objects with an empty body." - ([#14472](https://github.com/nim-lang/Nim/issues/14472)) -- Fixed "Stropped identifiers don't work as field names in tuple literals" - ([#14911](https://github.com/nim-lang/Nim/issues/14911)) -- Fixed "Please revert my commit" - ([#14930](https://github.com/nim-lang/Nim/issues/14930)) -- Fixed "[ARC] C compiler error with inline iterators and imports" - ([#14864](https://github.com/nim-lang/Nim/issues/14864)) -- Fixed "AsyncHttpClient segfaults with gc:orc, possibly memory corruption" - ([#14402](https://github.com/nim-lang/Nim/issues/14402)) -- Fixed "[ARC] Template with a block evaluating to a GC'd value results in a compiler crash" - ([#14899](https://github.com/nim-lang/Nim/issues/14899)) -- Fixed "[ARC] Weird issue with if expressions and templates" - ([#14900](https://github.com/nim-lang/Nim/issues/14900)) -- Fixed "xmlparser does not compile on devel" - ([#14805](https://github.com/nim-lang/Nim/issues/14805)) -- Fixed "returning lent T from a var T param gives codegen errors or SIGSEGV" - ([#14878](https://github.com/nim-lang/Nim/issues/14878)) -- Fixed "[ARC] Weird issue with if expressions and templates" - ([#14900](https://github.com/nim-lang/Nim/issues/14900)) -- Fixed "threads:on + gc:orc + unittest = C compiler errors" - ([#14865](https://github.com/nim-lang/Nim/issues/14865)) -- Fixed "mitems, mpairs doesn't work at compile time anymore" - ([#12129](https://github.com/nim-lang/Nim/issues/12129)) -- Fixed "strange result from executing code in const expression" - ([#10465](https://github.com/nim-lang/Nim/issues/10465)) -- Fixed "Same warning printed 3 times" - ([#11009](https://github.com/nim-lang/Nim/issues/11009)) -- Fixed "type alias for generic typeclass doesn't work" - ([#4668](https://github.com/nim-lang/Nim/issues/4668)) -- Fixed "exceptions:goto Bug devel codegen lvalue NIM_FALSE=NIM_FALSE" - ([#14925](https://github.com/nim-lang/Nim/issues/14925)) -- Fixed "the --useVersion:1.0 no longer works in devel" - ([#14912](https://github.com/nim-lang/Nim/issues/14912)) -- Fixed "template declaration of iterator doesn't compile" - ([#4722](https://github.com/nim-lang/Nim/issues/4722)) -- Fixed "Compiler crash on type inheritance with static generic parameter and equality check" - ([#12571](https://github.com/nim-lang/Nim/issues/12571)) -- Fixed "Nim crashes while handling a cast in async circumstances." - ([#13815](https://github.com/nim-lang/Nim/issues/13815)) -- Fixed "[ARC] Internal compiler error when calling an iterator from an inline proc " - ([#14383](https://github.com/nim-lang/Nim/issues/14383)) -- Fixed ""Cannot instantiate" error when template uses generic type" - ([#5926](https://github.com/nim-lang/Nim/issues/5926)) -- Fixed "Different raises behaviour for newTerminal between Linux and Windows" - ([#12759](https://github.com/nim-lang/Nim/issues/12759)) -- Fixed "Expand on a type (that defines a proc type) in error message " - ([#6608](https://github.com/nim-lang/Nim/issues/6608)) -- Fixed "unittest require quits program with an exit code of 0" - ([#14475](https://github.com/nim-lang/Nim/issues/14475)) -- Fixed "Range type: Generics vs concrete type, semcheck difference." - ([#8426](https://github.com/nim-lang/Nim/issues/8426)) -- Fixed "[Macro] Type mismatch when parameter name is the same as a field" - ([#13253](https://github.com/nim-lang/Nim/issues/13253)) -- Fixed "Generic instantiation failure when converting a sequence of circular generic types to strings" - ([#10396](https://github.com/nim-lang/Nim/issues/10396)) -- Fixed "initOptParser ignores argument after value option with empty value." - ([#13086](https://github.com/nim-lang/Nim/issues/13086)) -- Fixed "[ARC] proc with both explicit and implicit return results in a C compiler error" - ([#14985](https://github.com/nim-lang/Nim/issues/14985)) -- Fixed "Alias type forgets implicit generic params depending on order" - ([#14990](https://github.com/nim-lang/Nim/issues/14990)) -- Fixed "[ARC] sequtils.insert has different behaviour between ARC/refc" - ([#14994](https://github.com/nim-lang/Nim/issues/14994)) -- Fixed "The documentation for "hot code reloading" references a non-existent npm package" - ([#13621](https://github.com/nim-lang/Nim/issues/13621)) -- Fixed "existsDir deprecated but breaking `dir` undeclared" - ([#15006](https://github.com/nim-lang/Nim/issues/15006)) -- Fixed "uri.decodeUrl crashes on incorrectly formatted input" - ([#14082](https://github.com/nim-lang/Nim/issues/14082)) -- Fixed "testament incorrectly reports time for tests, leading to wrong conclusions" - ([#14822](https://github.com/nim-lang/Nim/issues/14822)) -- Fixed "Calling peekChar with Stream returned from osproc.outputStream generate runtime error" - ([#14906](https://github.com/nim-lang/Nim/issues/14906)) -- Fixed "localPassC pragma should come *after* other flags" - ([#14194](https://github.com/nim-lang/Nim/issues/14194)) -- Fixed ""Could not load" dynamic library at runtime because of hidden dependency" - ([#2408](https://github.com/nim-lang/Nim/issues/2408)) -- Fixed "--gc:arc generate invalid code for {.global.} (`«nimErr_» in NIM_UNLIKELY`)" - ([#14480](https://github.com/nim-lang/Nim/issues/14480)) -- Fixed "Using `^` from stdlib/math along with converters gives a match for types that aren't SomeNumber" - ([#15033](https://github.com/nim-lang/Nim/issues/15033)) -- Fixed "[ARC] Weird exception behaviour from doAssertRaises" - ([#15026](https://github.com/nim-lang/Nim/issues/15026)) -- Fixed "[ARC] Compiler crash declaring a finalizer proc directly in 'new'" - ([#15044](https://github.com/nim-lang/Nim/issues/15044)) -- Fixed "[ARC] C compiler error when creating a var of a const seq" - ([#15036](https://github.com/nim-lang/Nim/issues/15036)) -- Fixed "code with named arguments in proc of winim/com can not been compiled" - ([#15056](https://github.com/nim-lang/Nim/issues/15056)) -- Fixed "javascript backend produces javascript code with syntax error in object syntax" - ([#14534](https://github.com/nim-lang/Nim/issues/14534)) -- Fixed "--gc:arc should be ignored in JS mode." - ([#14684](https://github.com/nim-lang/Nim/issues/14684)) -- Fixed "arc: C compilation error with imported global code using a closure iterator" - ([#12990](https://github.com/nim-lang/Nim/issues/12990)) -- Fixed "[ARC] Crash when modifying a string with mitems iterator" - ([#15052](https://github.com/nim-lang/Nim/issues/15052)) -- Fixed "[ARC] SIGSEGV when calling a closure as a tuple field in a seq" - ([#15038](https://github.com/nim-lang/Nim/issues/15038)) -- Fixed "pass varargs[seq[T]] to iterator give empty seq " - ([#12576](https://github.com/nim-lang/Nim/issues/12576)) -- Fixed "Compiler crashes when using string as object variant selector with else branch" - ([#14189](https://github.com/nim-lang/Nim/issues/14189)) -- Fixed "JS compiler error related to implicit return and return var type" - ([#11354](https://github.com/nim-lang/Nim/issues/11354)) -- Fixed "`nkRecWhen` causes internalAssert in semConstructFields" - ([#14698](https://github.com/nim-lang/Nim/issues/14698)) -- Fixed "Memory leaks with async (closure iterators?) under ORC" - ([#15076](https://github.com/nim-lang/Nim/issues/15076)) -- Fixed "strutil.insertSep() fails on negative numbers" - ([#11352](https://github.com/nim-lang/Nim/issues/11352)) -- Fixed "Constructing a uint64 range on a 32-bit machine leads to incorrect codegen" - ([#14616](https://github.com/nim-lang/Nim/issues/14616)) -- Fixed "heapqueue pushpop() proc doesn't compile" - ([#14139](https://github.com/nim-lang/Nim/issues/14139)) -- Fixed "[ARC] SIGSEGV when trying to swap in a literal/const string" - ([#15112](https://github.com/nim-lang/Nim/issues/15112)) -- Fixed "Defer and --gc:arc" - ([#15071](https://github.com/nim-lang/Nim/issues/15071)) -- Fixed "internal error: compiler/semobjconstr.nim(324, 20) example" - ([#15111](https://github.com/nim-lang/Nim/issues/15111)) -- Fixed "[ARC] Sequence "disappears" with a table inside of a table with an object variant" - ([#15122](https://github.com/nim-lang/Nim/issues/15122)) -- Fixed "[ARC] SIGSEGV with tuple assignment caused by cursor inference" - ([#15130](https://github.com/nim-lang/Nim/issues/15130)) -- Fixed "Issue with --gc:arc at compile time" - ([#15129](https://github.com/nim-lang/Nim/issues/15129)) -- Fixed "Writing an empty string to an AsyncFile raises an IndexDefect" - ([#15148](https://github.com/nim-lang/Nim/issues/15148)) -- Fixed "Compiler is confused about call convention of function with nested closure" - ([#5688](https://github.com/nim-lang/Nim/issues/5688)) -- Fixed "Nil check on each field fails in generic function" - ([#15101](https://github.com/nim-lang/Nim/issues/15101)) -- Fixed "{.nimcall.} convention won't avoid the creation of closures" - ([#8473](https://github.com/nim-lang/Nim/issues/8473)) -- Fixed "smtp.nim(161, 40) Error: type mismatch: got but expected 'SslContext = void'" - ([#15177](https://github.com/nim-lang/Nim/issues/15177)) -- Fixed "[strscans] scanf doesn't match a single character with $+ if it's the end of the string" - ([#15064](https://github.com/nim-lang/Nim/issues/15064)) -- Fixed "Crash and incorrect return values when using readPasswordFromStdin on Windows." - ([#15207](https://github.com/nim-lang/Nim/issues/15207)) -- Fixed "Possible capture error with fieldPairs and genericParams" - ([#15221](https://github.com/nim-lang/Nim/issues/15221)) -- Fixed "The StmtList processing of template parameters can lead to unexpected errors" - ([#5691](https://github.com/nim-lang/Nim/issues/5691)) -- Fixed "[ARC] C compiler error when passing a var openArray to a sink openArray" - ([#15035](https://github.com/nim-lang/Nim/issues/15035)) -- Fixed "Inconsistent unsigned -> signed RangeDefect usage across integer sizes" - ([#15210](https://github.com/nim-lang/Nim/issues/15210)) -- Fixed "toHex results in RangeDefect exception when used with large uint64" - ([#15257](https://github.com/nim-lang/Nim/issues/15257)) -- Fixed "Arc sink arg crash" - ([#15238](https://github.com/nim-lang/Nim/issues/15238)) -- Fixed "SQL escape in db_mysql is not enough" - ([#15219](https://github.com/nim-lang/Nim/issues/15219)) -- Fixed "Mixing 'return' with expressions is allowed in 1.2" - ([#15280](https://github.com/nim-lang/Nim/issues/15280)) -- Fixed "os.getFileInfo() causes ICE with --gc:arc on Windows" - ([#15286](https://github.com/nim-lang/Nim/issues/15286)) -- Fixed "[ARC] Sequence "disappears" with a table inside of a table with an object variant" - ([#15122](https://github.com/nim-lang/Nim/issues/15122)) -- Fixed "Documentation regression jsre module missing" - ([#15183](https://github.com/nim-lang/Nim/issues/15183)) -- Fixed "CountTable.smallest/largest() on empty table either asserts or gives bogus answer" - ([#15021](https://github.com/nim-lang/Nim/issues/15021)) -- Fixed "[Regression] Parser regression" - ([#15305](https://github.com/nim-lang/Nim/issues/15305)) -- Fixed "[ARC] SIGSEGV with tuple unpacking caused by cursor inference" - ([#15147](https://github.com/nim-lang/Nim/issues/15147)) -- Fixed "LwIP/FreeRTOS compile error - missing SIGPIPE and more " - ([#15302](https://github.com/nim-lang/Nim/issues/15302)) -- Fixed "Memory leaks with async (closure iterators?) under ORC" - ([#15076](https://github.com/nim-lang/Nim/issues/15076)) -- Fixed "Bug compiling with --gc:arg or --gc:orc" - ([#15325](https://github.com/nim-lang/Nim/issues/15325)) -- Fixed "memory corruption in tmarshall.nim" - ([#9754](https://github.com/nim-lang/Nim/issues/9754)) -- Fixed "typed macros break generic proc definitions" - ([#15326](https://github.com/nim-lang/Nim/issues/15326)) -- Fixed "nim doc2 ignores --docSeeSrcUrl parameter" - ([#6071](https://github.com/nim-lang/Nim/issues/6071)) -- Fixed "The decodeData Iterator from cgi module crash" - ([#15369](https://github.com/nim-lang/Nim/issues/15369)) -- Fixed "|| iterator generates invalid code when compiling with --debugger:native" - ([#9710](https://github.com/nim-lang/Nim/issues/9710)) -- Fixed "Wrong number of variables" - ([#15360](https://github.com/nim-lang/Nim/issues/15360)) -- Fixed "Coercions with distinct types should traverse pointer modifiers transparently." - ([#7165](https://github.com/nim-lang/Nim/issues/7165)) -- Fixed "Error with distinct generic TableRef" - ([#6060](https://github.com/nim-lang/Nim/issues/6060)) -- Fixed "Support images in nim docgen" - ([#6430](https://github.com/nim-lang/Nim/issues/6430)) -- Fixed "Regression. Double sem check for procs." - ([#15389](https://github.com/nim-lang/Nim/issues/15389)) -- Fixed "uri.nim url with literal ipv6 address is printed wrong, and cannot parsed again" - ([#15333](https://github.com/nim-lang/Nim/issues/15333)) -- Fixed "[ARC] Object variant gets corrupted with cursor inference" - ([#15361](https://github.com/nim-lang/Nim/issues/15361)) -- Fixed "`nim doc ..` compiler crash (regression 0.19.6 => 1.0)" - ([#14474](https://github.com/nim-lang/Nim/issues/14474)) -- Fixed "cannot borrow result; what it borrows from is potentially mutated" - ([#15403](https://github.com/nim-lang/Nim/issues/15403)) -- Fixed "memory corruption for seq.add(seq) with gc:arc and d:useMalloc " - ([#14983](https://github.com/nim-lang/Nim/issues/14983)) -- Fixed "DocGen HTML output appears improperly when encountering text immediately after/before inline monospace; in some cases won't compile" - ([#11537](https://github.com/nim-lang/Nim/issues/11537)) -- Fixed "Deepcopy in arc crashes" - ([#15405](https://github.com/nim-lang/Nim/issues/15405)) -- Fixed "pop pragma takes invalid input" - ([#15430](https://github.com/nim-lang/Nim/issues/15430)) -- Fixed "tests/stdlib/tgetprotobyname fails on NetBSD" - ([#15452](https://github.com/nim-lang/Nim/issues/15452)) -- Fixed "defer doesnt work with block, break and await" - ([#15243](https://github.com/nim-lang/Nim/issues/15243)) -- Fixed "tests/stdlib/tssl failing on NetBSD" - ([#15493](https://github.com/nim-lang/Nim/issues/15493)) -- Fixed "strictFuncs doesn't seem to catch simple ref mutation" - ([#15508](https://github.com/nim-lang/Nim/issues/15508)) -- Fixed "Sizeof of case object is incorrect. Showstopper" - ([#15516](https://github.com/nim-lang/Nim/issues/15516)) -- Fixed "[ARC] Internal error when trying to use a parallel for loop" - ([#15512](https://github.com/nim-lang/Nim/issues/15512)) -- Fixed "[ARC] Type-bound assign op is not being generated" - ([#15510](https://github.com/nim-lang/Nim/issues/15510)) -- Fixed "[ARC] Crash when adding openArray proc argument to a local seq" - ([#15511](https://github.com/nim-lang/Nim/issues/15511)) -- Fixed "VM: const case object gets some fields zeroed out at runtime" - ([#13081](https://github.com/nim-lang/Nim/issues/13081)) -- Fixed "regression(1.2.6 => devel): VM: const case object field access gives: 'sons' is not accessible" - ([#15532](https://github.com/nim-lang/Nim/issues/15532)) -- Fixed "Csources: huge size increase (x2.3) in 0.20" - ([#12027](https://github.com/nim-lang/Nim/issues/12027)) -- Fixed "Out of date error message for GC options" - ([#15547](https://github.com/nim-lang/Nim/issues/15547)) -- Fixed "dbQuote additional escape regression" - ([#15560](https://github.com/nim-lang/Nim/issues/15560)) diff --git a/changelogs/changelog_1_6_0.md b/changelogs/changelog_1_6_0.md deleted file mode 100644 index 4a1047d20..000000000 --- a/changelogs/changelog_1_6_0.md +++ /dev/null @@ -1,957 +0,0 @@ -# v1.6.0 - 2021-10-14 - - - -# Major new features - -With so many new features, pinpointing the most salient ones is a subjective exercise, -but here are a select few: - - -## `iterable[T]` - -The `iterable[T]` type class was added to match called iterators, -which solves a number of long-standing issues related to iterators. -Example: - -```nim -iterator iota(n: int): int = - for i in 0.. response.json()) - .then((json: JsObject) => console.log(json)) - .catch((err: Error) => console.log("Request Failed", err)) -discard fn() -``` - - -## New `std/tasks` module - -Provides basic primitives for creating parallel programs. -Example: -```nim -import std/tasks -var num = 0 -proc hello(a: int) = num+=a - -let b = toTask hello(13) # arguments must be isolated, see `std/isolation` -b.invoke() -assert num == 13 -b.invoke() # can be called again -assert num == 26 -``` - - -## New module: `std/genasts` - -Provides an API `genAst` that avoids the problems inherent with `quote do` and can -be used as a replacement. -Example showing how this could be used for writing a simplified version of `unittest.check`: -```nim -import std/[genasts, macros, strutils] -macro check2(cond: bool): untyped = - assert cond.kind == nnkInfix, "$# not implemented" % $cond.kind - result = genAst(cond, s = repr(cond), lhs = cond[1], rhs = cond[2]): - # each local symbol we access must be explicitly captured - if not cond: - doAssert false, "'$#'' failed: lhs: '$#', rhs: '$#'" % [s, $lhs, $rhs] -let a = 3 -check2 a*2 == a+3 -if false: check2 a*2 < a+1 # would error with: 'a * 2 < a + 1'' failed: lhs: '6', rhs: '4' -``` - -See PR [#17426](https://github.com/nim-lang/Nim/pull/17426) for details. - - -## New module: `std/setutils` - -- Added `setutils.toSet` that can take any iterable and convert it to a built-in `set`, - if the iterable yields a built-in settable type. -- Added `setutils.fullSet` which returns a full built-in `set` for a valid type. -- Added `setutils.complement` which returns the complement of a built-in `set`. -- Added `setutils.[]=`. - - -## New module: `std/enumutils` - -- Added `genEnumCaseStmt` macro that generates - case statement to parse string to enum. -- Added `items` for enums with holes. -- Added `symbolName` to return the `enum` symbol name ignoring the human-readable name. -- Added `symbolRank` to return the index in which an `enum` member is listed in an enum. - - -## `system` - -- Added `system.prepareMutation` for better support of low - level `moveMem`, `copyMem` operations for `gc:orc`'s copy-on-write string - implementation. -- `system.addEscapedChar` now renders `\r` as `\r` instead of `\c`, to be compatible - with most other languages. -- Added `cmpMem` to `system`. -- `doAssertRaises` now correctly handles foreign exceptions. -- `addInt` now supports unsigned integers. - -Compatibility notes: -- `system.delete` had surprising behavior when the index passed to it was out of - bounds (it would delete the last entry then). Compile with `-d:nimStrictDelete` so - that an index error is produced instead. Be aware however that your code might depend on - this quirky behavior so a review process is required on your part before you can - use `-d:nimStrictDelete`. To make this review easier, use the `-d:nimAuditDelete` - switch, which pretends that `system.delete` is deprecated so that it is easier - to see where it was used in your code. - `-d:nimStrictDelete` will become the default in upcoming versions. -- `cuchar` is now deprecated as it aliased `char` where arguably it should have aliased `uint8`. - Please use `char` or `uint8` instead. -- `repr` now doesn't insert trailing newlines; the previous behavior was very inconsistent, - see [#16034](https://github.com/nim-lang/Nim/pull/16034). - Use `-d:nimLegacyReprWithNewline` for the previous behavior. - `repr` now also renders ASTs correctly for user defined literals, setters, `do`, etc. -- Deprecated `any`. See RFC [#281](https://github.com/nim-lang/RFCs/issues/281). -- The unary slice `..b` was deprecated, use `0..b` instead. - - -## `std/math` - -- Added `almostEqual` for comparing two float values using a machine epsilon. -- Added `clamp` which allows using a `Slice` to clamp to a value. -- Added `ceilDiv` for integer division that rounds up. -- Added `isNaN`. -- Added `copySign`. -- Added `euclDiv` and `euclMod`. -- Added `signbit`. -- Added `frexp` overload procs. Deprecated `c_frexp`, use `frexp` instead. - -Compatibility notes: -- `math.round` now rounds "away from zero" in the JS backend, which is consistent - with other backends. See [#9125](https://github.com/nim-lang/Nim/pull/9125). - Use `-d:nimLegacyJsRound` for the previous behavior. - - -## Random number generators: `std/random`, `std/sysrand`, `std/oids` - -- Added `std/sysrand` module (see details above). -- Added `randState` template that exposes the default random number generator. - Useful for library authors. -- Added `initRand()` overload with no argument which uses the current time as a seed. -- `initRand(seed)` now allows `seed == 0`. -- Fixed overflow bugs. -- Fix `initRand` to avoid random number sequences overlapping, refs - [#18744](https://github.com/nim-lang/Nim/pull/18744). -- `std/oids` now uses `std/random`. - -Compatibility notes: -- Deprecated `std/mersenne`. -- `random.initRand(seed)` now produces non-skewed values for the first call to - `rand()` after initialization with a small (< 30000) seed. - Use `-d:nimLegacyRandomInitRand` to restore previous behavior for a transition - time, see PR [#17467](https://github.com/nim-lang/Nim/pull/17467). - - -## `std/json`, `std/jsonutils` - -- With `-d:nimPreviewJsonutilsHoleyEnum`, `jsonutils` now can serialize/deserialize - holey enums as regular enums (via `ord`) instead of as strings. - It is expected that this behavior becomes the new default in upcoming versions. - `toJson` now serializes `JsonNode` as is via reference (without a deep copy) - instead of treating `JsonNode` as a regular ref object, - this can be customized via `jsonNodeMode`. -- `std/json` and `std/jsonutils` now serialize `NaN`, `Inf`, `-Inf` as strings, - so that `%[NaN, -Inf]` is the string `["nan","-inf"]` instead of `[nan,-inf]` - which was invalid JSON. -- `std/json` can now handle integer literals and floating point literals of - arbitrary length and precision. - Numbers that do not fit the underlying `BiggestInt` or `BiggestFloat` fields are - kept as string literals and one can use external BigNum libraries to handle these. - The `parseFloat` family of functions also has now optional `rawIntegers` and - `rawFloats` parameters that can be used to enforce that all integer or float - literals remain in the "raw" string form so that client code can easily treat - small and large numbers uniformly. -- Added `BackwardsIndex` overload for `JsonNode`. -- `json.%`,`json.to`, `jsonutils.fromJson`,`jsonutils.toJson` now work with `uint|uint64` - instead of raising (as in 1.4) or giving wrong results (as in 1.2). -- `std/jsonutils` now handles `cstring` (including as Table key), and `set`. -- Added `jsonutils.jsonTo` overload with `opt = Joptions()` param. -- `jsonutils.toJson` now supports customization via `ToJsonOptions`. -- `std/json`, `std/jsonutils` now support round-trip serialization when - `-d:nimPreviewFloatRoundtrip` is used. - - -## `std/typetraits`, `std/compilesettings` - -- `distinctBase` now is identity instead of error for non distinct types. -- `distinctBase` now allows controlling whether to be recursive or not. -- Added `enumLen` to return the number of elements in an enum. -- Added `HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes. -- Added `hasClosure`. -- Added `pointerBase` to return `T` for `ref T | ptr T`. -- Added `compilesettings.SingleValueSetting.libPath`. - - -## networking: `std/net`, `std/asyncnet`, `std/htmlgen`, `std/httpclient`, `std/asyncdispatch`, `std/asynchttpserver`, `std/httpcore` - -- Fixed buffer overflow bugs in `std/net`. -- Exported `sslHandle` from `std/net` and `std/asyncnet`. -- Added `hasDataBuffered` to `std/asyncnet`. -- Various functions in `std/httpclient` now accept `url` of type `Uri`. - Moreover, the `request` function's `httpMethod` argument of type `string` was - deprecated in favor of `HttpMethod` `enum` type; see - [#15919](https://github.com/nim-lang/Nim/pull/15919). -- Added `asyncdispatch.activeDescriptors` that returns the number of currently - active async event handles/file descriptors. -- Added `getPort` to `std/asynchttpserver` to resolve OS-assigned `Port(0)`; - this is usually recommended instead of hardcoding ports which can lead to - "Address already in use" errors. -- Fixed premature garbage collection in `std/asyncdispatch`, when a stacktrace - override is in place. -- Added `httpcore.is1xx` and missing HTTP codes. -- Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals). - -Compatibility notes: -- On Windows, the SSL library now checks for valid certificates. - For this purpose it uses the `cacert.pem` file, which was extracted - from `https://curl.se/ca/cacert.pem`. Besides - the OpenSSL DLLs (e.g. `libssl-1_1-x64.dll`, `libcrypto-1_1-x64.dll`) you - now also need to ship `cacert.pem` with your `.exe` file. - - -## `std/hashes` - -- `hashes.hash` can now support `object` and `ref` (can be overloaded in user code), - if `-d:nimPreviewHashRef` is used. It is expected that this behavior - becomes the new default in upcoming versions. -- `hashes.hash(proc|ptr|ref|pointer)` now calls `hash(int)` and honors `-d:nimIntHash1`. - `hashes.hash(closure)` has also been improved. - - -## OS: `std/os`, `std/io`, `std/socketstream`, `std/linenoise`, `std/tempfiles` - -- `os.FileInfo` (returned by `getFileInfo`) now contains `blockSize`, - determining preferred I/O block size for this file object. -- Added `os.getCacheDir()` to return platform specific cache directory. -- Improved `os.getTempDir()`, see PR [#16914](https://github.com/nim-lang/Nim/pull/16914). -- Added `os.isAdmin` to tell whether the caller's process is a member of the - Administrators local group (on Windows) or a root (on POSIX). -- Added optional `options` argument to `copyFile`, `copyFileToDir`, and - `copyFileWithPermissions`. By default, on non-Windows OSes, symlinks are - followed (copy files symlinks point to); on Windows, `options` argument is - ignored and symlinks are skipped. -- On non-Windows OSes, `copyDir` and `copyDirWithPermissions` copy symlinks as - symlinks (instead of skipping them as it was before); on Windows symlinks are - skipped. -- On non-Windows OSes, `moveFile` and `moveDir` move symlinks as symlinks - (instead of skipping them sometimes as it was before). -- Added optional `followSymlinks` argument to `setFilePermissions`. -- Added a simpler to use `io.readChars` overload. -- Added `socketstream` module that wraps sockets in the stream interface. -- Added experimental `linenoise.readLineStatus` to get line and status (e.g. ctrl-D or ctrl-C). - - -## Environment variable handling - -- Empty environment variable values are now supported across OS's and backends. -- Environment variable APIs now work in multithreaded scenarios, by delegating to - direct OS calls instead of trying to keep track of the environment. -- `putEnv`, `delEnv` now work at compile time. -- NodeJS backend now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `existsEnv`. - -Compatibility notes: -- `std/os`: `putEnv` now raises if the first argument contains a `=`. - - -## POSIX - -- On POSIX systems, the default signal handlers used for Nim programs (it's - used for printing the stacktrace on fatal signals) will now re-raise the - signal for the OS default handlers to handle. - This lets the OS perform its default actions, which might include core - dumping (on select signals) and notifying the parent process about the cause - of termination. -- On POSIX systems, we now ignore `SIGPIPE` signals, use `-d:nimLegacySigpipeHandler` - for previous behavior. -- Added `posix_utils.osReleaseFile` to get system identification from `os-release` - file on Linux and the BSDs. - ([link](https://www.freedesktop.org/software/systemd/man/os-release.html)) -- Removed undefined behavior for `posix.open`. - - -## `std/prelude` - -- `std/strformat` is now part of `include std/prelude`. -- Added `std/sequtils` import to `std/prelude`. -- `std/prelude` now works with the JS target. -- `std/prelude` can now be used via `include std/prelude`, but `include prelude` still works. - - -## String manipulation: `std/strformat`, `std/strbasics` - -- Added support for parenthesized expressions. -- Added support for const strings instead of just string literals. -- Added `std/strbasics` for high-performance string operations. -- Added `strip`, `setSlice`, `add(a: var string, b: openArray[char])`. - - -## `std/wrapnils` - -- `std/wrapnils` doesn't use `experimental:dotOperators` anymore, avoiding - issues like bug [#13063](https://github.com/nim-lang/Nim/issues/13063) - (which affected error messages) for modules importing `std/wrapnils`. -- Added `??.` macro which returns an `Option`. -- `std/wrapnils` can now be used to protect against `FieldDefect` errors in - case objects, generates optimal code (no overhead compared to manual - if-else branches), and preserves lvalue semantics which allows modifying - an expression. - - -## Containers: `std/algorithm`, `std/lists`, `std/sequtils`, `std/options`, `std/packedsets` - -- Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` - iterators (it never worked reliably). -- Added `algorithm.merge`. -- In `std/lists`: renamed `append` to `add` and retained `append` as an alias; - added `prepend` and `prependMoved` analogously to `add` and `addMoved`; - added `remove` for `SinglyLinkedList`s. -- Added new operations for singly- and doubly linked lists: `lists.toSinglyLinkedList` - and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements - shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes - its argument, `addMoved`, is also supplied. - See PRs [#16362](https://github.com/nim-lang/Nim/pull/16362), - [#16536](https://github.com/nim-lang/Nim/pull/16536). -- New module: `std/packedsets`. - Generalizes `std/intsets`, see PR [#15564](https://github.com/nim-lang/Nim/pull/15564). - -Compatibility notes: -- Deprecated `sequtils.delete` and added an overload taking a `Slice` that raises - a defect if the slice is out of bounds, likewise with `strutils.delete`. -- Deprecated `proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T]` - in `std/algorithm`. -- `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"` - and `$none(int)` to `"none(int)"` instead of `"None[int]"`. - - -## `std/times` - -- Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time - zone offsets without colons, e.g. `UTC+7 -> +0700`. -- Added `dateTime` and deprecated `initDateTime`. - - -## `std/macros` and AST - -- New module `std/genasts`, see description above. -- The required name of case statement macros for the experimental - `caseStmtMacros` feature has changed from `match` to `` `case` ``. -- Tuple expressions are now parsed consistently as - `nnkTupleConstr` node. Will affect macros expecting nodes to be of `nnkPar`. -- In `std/macros`, `treeRepr,lispRepr,astGenRepr` now represent SymChoice nodes - in a collapsed way. - Use `-d:nimLegacyMacrosCollapseSymChoice` to get the previous behavior. -- Made custom op in `macros.quote` work for all statements. - - -## `std/sugar` - -- Added `sugar.dumpToString` which improves on `sugar.dump`. -- Added an overload for the `collect` macro that infers the container type based - on the syntax of the last expression. Works with std seqs, tables and sets. - -Compatibility notes: -- Removed support for named procs in `sugar.=>`. - - -## Parsing: `std/parsecfg`, `std/strscans`, `std/uri` - -- Added `sections` iterator in `parsecfg`. -- `strscans.scanf` now supports parsing single characters. -- Added `strscans.scanTuple` which uses `strscans.scanf` internally, - returning a tuple which can be unpacked for easier usage of `scanf`. -- Added `decodeQuery` to `std/uri`. -- `parseopt.initOptParser` has been made available and `parseopt` has been - added back to `std/prelude` for all backends. Previously `initOptParser` was - unavailable if the `std/os` module did not have `paramCount` or `paramStr`, - but the use of these in `initOptParser` were conditionally to the runtime - arguments passed to it, so `initOptParser` has been changed to raise - `ValueError` when the real command line is not available. `parseopt` was - previously excluded from `std/prelude` for JS, as it could not be imported. - -Compatibility notes: -- Changed the behavior of `uri.decodeQuery` when there are unencoded `=` - characters in the decoded values. Prior versions would raise an error. This is - no longer the case to comply with the HTML spec and other languages' - implementations. Old behavior can be obtained with - `-d:nimLegacyParseQueryStrict`. `cgi.decodeData` which uses the same - underlying code is also updated the same way. - - -## JS stdlib changes - -- Added `std/jsbigints` module, which provides arbitrary precision integers for the JS target. -- Added `setCurrentException` for the JS backend. -- `writeStackTrace` is available in the JS backend now. -- Added `then`, `catch` to `std/asyncjs` for promise pipelining, for now hidden - behind `-d:nimExperimentalAsyncjsThen`. -- Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) - wrapper for the JS target. -- Added `std/jsheaders` module [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) - wrapper for the JS target. -- Added `std/jsformdata` module [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) - wrapper for the JS target. -- Added `jscore.debugger` to [call any available debugging functionality, such as breakpoints](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger). -- Added `jsconsole.dir`, `jsconsole.dirxml`, `jsconsole.timeStamp`. -- Added dollar `$` and `len` for `jsre.RegExp`. -- Added `jsconsole.jsAssert` for the JS target. -- Added `**` to `std/jsffi`. -- Added `copyWithin` [for `seq` and `array` for JS targets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin). -- In `std/dom`, `Interval` is now a `ref object`, same as `Timeout`. - Definitions of `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` were updated. -- Added `dom.scrollIntoView` proc with options. -- Added `dom.setInterval`, `dom.clearInterval` overloads. -- Merged `std/dom_extensions` into the `std/dom` module, - as it was a module with a single line, see RFC [#413](https://github.com/nim-lang/RFCs/issues/413). -- `$` now gives more correct results on the JS backend. - - -## JS compiler changes - -- `cstring` doesn't support the `[]=` operator anymore in the JS backend. -- Array literals now use JS typed arrays when the corresponding JS typed array exists, - for example `[byte(1), 2, 3]` generates `new Uint8Array([1, 2, 3])`. - - -## VM and nimscript backend - -- VM now supports `addr(mystring[ind])` (index + index assignment). -- `nimscript` now handles `except Exception as e`. -- `nil` dereference is not allowed at compile time. `cast[ptr int](nil)[]` is rejected at compile time. -- `static[T]` now works better, refs [#17590](https://github.com/nim-lang/Nim/pull/17590), - [#15853](https://github.com/nim-lang/Nim/pull/15853). -- `distinct T` conversions now work in VM. -- `items(cstring)` now works in VM. -- Fix `addr`, `len`, `high` in VM ([#16002](https://github.com/nim-lang/Nim/pull/16002), - [#16610](https://github.com/nim-lang/Nim/pull/16610)). -- `std/cstrutils` now works in VM. - - -## OS/platform-specific notes - -- Support for Apple silicon/M1. -- Support for 32-bit RISC-V, refs [#16231](https://github.com/nim-lang/Nim/pull/16231). -- Support for armv8l, refs [#18901](https://github.com/nim-lang/Nim/pull/18901). -- Support for CROSSOS, refs [#18889](https://github.com/nim-lang/Nim/pull/18889). -- The allocator for Nintendo Switch, which was nonfunctional because - of breaking changes in libnx, was removed, in favor of the new `-d:nimAllocPagesViaMalloc` option. -- Allow reading parameters when compiling for Nintendo Switch. -- `--nimcache` now correctly works in a cross-compilation setting. -- Cross compilation targeting Windows was improved. -- This now works from macOS/Linux: `nim r -d:mingw main` - - - -## Performance / memory optimizations - -- The comment field in PNode AST was moved to a side channel, reducing overall - memory usage during compilation by a factor 1.25x -- `std/jsonutils` deserialization is now up to 20x faster. -- `os.copyFile` is now 2.5x faster on macOS, by using `copyfile` from `copyfile.h`; - use `-d:nimLegacyCopyFile` for macOS < 10.5. -- Float to string conversion is now 10x faster thanks to the Dragonbox algorithm, - with `-d:nimPreviewFloatRoundtrip`. -- `newSeqWith` is 3x faster. -- CI now supports batching (making Windows CI 2.3X faster). -- Sets now uses the optimized `countSetBits` proc, see PR - [#17334](https://github.com/nim-lang/Nim/pull/17334). - - -## Debugging - -- You can now enable/disable VM tracing in user code via `vmutils.vmTrace`. -- `koch tools` now builds `bin/nim_dbg` which allows easy access to a debug version - of Nim without recompiling. -- Added new module `compiler/debugutils` to help with debugging Nim compiler. -- Renamed `-d:nimCompilerStackraceHints` to `-d:nimCompilerStacktraceHints` and - used it in more contexts; this flag which works in tandem with `--stackTraceMsgs` - to show user code context in compiler stacktraces. - - -## Type system - -- `typeof(voidStmt)` now works and returns `void`. -- `enum` values can now be overloaded. This needs to be enabled - via `{.experimental: "overloadableEnums".}`. We hope that this feature allows - for the development of more fluent (less ugly) APIs. - See RFC [#373](https://github.com/nim-lang/RFCs/issues/373) for more details. -- A type conversion from one `enum` type to another now produces an `[EnumConv]` warning. - You should use `ord` (or `cast`, but the compiler won't help, if you misuse it) instead. - ```nim - type A = enum a1, a2 - type B = enum b1, b2 - echo a1.B # produces a warning - echo a1.ord.B # produces no warning - ``` -- A dangerous implicit conversion to `cstring` now triggers a `[CStringConv]` warning. - This warning will become an error in future versions! Use an explicit conversion - like `cstring(x)` in order to silence the warning. -- There is a new warning for *any* type conversion to `enum` that can be enabled via - `.warning[AnyEnumConv]:on` or `--warning:AnyEnumConv:on`. -- Reusing a type name in a different scope now works, refs [#17710](https://github.com/nim-lang/Nim/pull/17710). -- Fixed implicit and explicit generics in procedures, refs [#18808](https://github.com/nim-lang/Nim/pull/18808). - - -## New-style concepts - -Example: -```nim -type - Comparable = concept # no T, an atom - proc cmp(a, b: Self): int -``` -The new design does not rely on `system.compiles` and may compile faster. -See PR [#15251](https://github.com/nim-lang/Nim/pull/15251) -and RFC [#168](https://github.com/nim-lang/RFCs/issues/168) for details. - - -## Lexical / syntactic - -- Nim now supports a small subset of Unicode operators as operator symbols. - The supported symbols are: "∙ ∘ × ★ ⊗ ⊘ ⊙ ⊛ ⊠ ⊡ ∩ ∧ ⊓ ± ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔". - To enable this feature, use `--experimental:unicodeOperators`. Note that due - to parser limitations you **cannot** enable this feature via a - pragma `{.experimental: "unicodeOperators".}` reliably, you need to enable - it via the command line or in a configuration file. -- `var a {.foo.} = expr` now works inside templates (except when `foo` is overloaded). - - -## Compiler messages, error messages, hints, warnings - -- Significant improvement to error messages involving effect mismatches, - see PRs [#18384](https://github.com/nim-lang/Nim/pull/18384), - [#18418](https://github.com/nim-lang/Nim/pull/18418). -- Added `--declaredLocs` to show symbol declaration location in error messages. -- Added `--spellSuggest` to show spelling suggestions on typos. -- Added `--processing:dots|filenames|off` which customizes `hintProcessing`; - `--processing:filenames` shows which include/import modules are being compiled as an import stack. -- `FieldDefect` messages now shows discriminant value + lineinfo, in all backends (C, JS, VM) -- Added `--hintAsError` with similar semantics as `--warningAsError`. -- Added `--unitsep:on|off` to control whether to add ASCII unit separator `\31` - before a newline for every generated message (potentially multiline), - so tooling can tell when messages start and end. -- Added `--filenames:abs|canonical|legacyRelProj` which replaces `--listFullPaths:on|off` -- `--hint:all:on|off` is now supported to select or deselect all hints; it - differs from `--hints:on|off` which acts as a (reversible) gate. - Likewise with `--warning:all:on|off`. -- The style checking of the compiler now supports a `--styleCheck:usages` switch. - This switch enforces that every symbol is written as it was declared, not enforcing - the official Nim style guide. To be enabled, this has to be combined either - with `--styleCheck:error` or `--styleCheck:hint`. -- Type mismatch errors now show more context, use `-d:nimLegacyTypeMismatch` for - previous behavior. -- `typedesc[Foo]` now renders as such instead of `type Foo` in compiler messages. -- `runnableExamples` now show originating location in stacktraces on failure. -- `SuccessX` message now shows more useful information. -- New `DuplicateModuleImport` warning; improved `UnusedImport` and - `XDeclaredButNotUsed` accuracy. - -Compatibility notes: -- `--hint:CC` now prints to stderr (like all other hints) instead of stdout. - - -## Building and running Nim programs, configuration system - -- JSON build instructions are now generated in `$nimcache/outFileBasename.json` - instead of `$nimcache/projectName.json`. This allows avoiding recompiling a - given project compiled with different options if the output file differs. -- `--usenimcache` (implied by `nim r main`) now generates an output file that includes - a hash of some of the compilation options, which allows caching generated binaries: - ```bash - nim r main # recompiles - nim r -d:foo main # recompiles - nim r main # uses cached binary - nim r main arg1 arg2 # likewise (runtime arguments are irrelevant) - ``` -- `nim r` now supports cross compilation from unix to windows when specifying - `-d:mingw` by using Wine, e.g.: - `nim r --eval:'import os; echo "a" / "b"'` prints `a\b`. -- `nim` can compile version 1.4.0 as follows: - `nim c --lib:lib --stylecheck:off -d:nimVersion140 compiler/nim`. - `-d:nimVersion140` is not needed for bootstrapping, only for building 1.4.0 from devel. -- `nim e` now accepts arbitrary file extensions for the nimscript file, - although `.nims` is still the preferred extension in general. -- The configuration subsystem now allows for `-d:release` and `-d:danger` to work as expected. - The downside is that these defines now have custom logic that doesn't apply for - other defines. - - -## Multithreading - -- TLS: macOS now uses native TLS (`--tlsEmulation:off`). TLS now works with - `importcpp` non-POD types; such types must use `.cppNonPod` and - `--tlsEmulation:off`should be used. -- Added `unsafeIsolate` and `extract` to `std/isolation`. -- Added `std/tasks`, see description above. - - -## Memory management - -- `--gc:arc` now bootstraps (PR [#17342](https://github.com/nim-lang/Nim/pull/17342)). -- Lots of improvements to `gc:arc`, `gc:orc`, see PR - [#15697](https://github.com/nim-lang/Nim/pull/15697), - [#16849](https://github.com/nim-lang/Nim/pull/16849), - [#17993](https://github.com/nim-lang/Nim/pull/17993). -- `--gc:orc` is now 10% faster than previously for common workloads. - If you have trouble with its changed behavior, compile with `-d:nimOldOrc`. -- The `--gc:orc` algorithm was refined so that custom container types can participate in the - cycle collection process. See the documentation of `=trace` for more details. -- On embedded devices `malloc` can now be used instead of `mmap` via `-d:nimAllocPagesViaMalloc`. - This is only supported for `--gc:orc` or `--gc:arc`. - -Compatibility notes: -- `--newruntime` and `--refchecks` are deprecated, - use `--gc:arc`, `--gc:orc`, or `--gc:none` as appropriate instead. - - -## Docgen - -- docgen: RST files can now use single backticks instead of double backticks and - correctly render in both `nim rst2html` (as before) as well as common tools rendering - RST directly (e.g. GitHub). - This is done by adding the `default-role:: code` directive inside the RST file - (which is now handled by `nim rst2html`). -- Source+Edit links now appear on top of every docgen'd page when - `nim doc --git.url:url ...` is given. -- Latex doc generation is revised: output `.tex` files should be compiled - by `xelatex` (not by `pdflatex` as before). Now default Latex settings - provide support for Unicode and better avoid margin overflows. - The minimum required version is TeXLive 2018 (or an equivalent MikTeX version). -- The RST parser now supports footnotes, citations, admonitions, and short style - references with symbols. -- The RST parser now supports Markdown table syntax. - Known limitations: - - cell alignment is not supported, i.e. alignment annotations in a delimiter - row (`:---`, `:--:`, `---:`) are ignored - - every table row must start with `|`, e.g. `| cell 1 | cell 2 |`. -- Implemented `doc2tex` compiler command which converts documentation in - `.nim` files to Latex. -- docgen now supports syntax highlighting for inline code. -- docgen now supports same-line doc comments: - ```nim - func fn*(a: int): int = 42 ## Doc comment - ``` -- docgen now renders `deprecated` and other pragmas. -- `runnableExamples` now works with templates and nested templates. -- `runnableExamples: "-r:off"` now works for examples that should compile but not run. -- `runnableExamples` now renders code verbatim, and produces correct code in all cases. -- docgen now shows correct, canonical import paths in docs. -- docgen now shows all routines in sidebar, and the proc signature is now shown in sidebar. - - -## Effects and checks - -- Significant improvement to error messages involving effect mismatches -- There is a new `cast` section `{.cast(uncheckedAssign).}: body` that disables some - compiler checks regarding `case objects`. This allows serialization libraries - to avoid ugly, non-portable solutions. See RFC - [#407](https://github.com/nim-lang/RFCs/issues/407) for more details. - -Compatibility notes: -- Fixed effect tracking for borrowed procs (see [#18882](https://github.com/nim-lang/Nim/pull/18882)). - One consequence is that, under some circumstances, Nim could previously permit a procedure with side effects to be written with `func` - you may need to change some occurrences of `func` to `proc`. - To illustrate, Nim versions before 1.6.0 compile the below without error - ```nim - proc print(s: string) = - echo s - - type - MyString = distinct string - - proc print(s: MyString) {.borrow.} - - func foo(s: MyString) = - print(s) - ``` - but Nim 1.6.0 produces the error - ``` - Error: 'foo' can have side effects - ``` - similar to how we expect that - ```nim - func print(s: string) = - echo s - ``` - produces - ``` - Error: 'print' can have side effects - ``` - - -## Tools - -- Major improvements to `nimgrep`, see PR [#15612 -](https://github.com/nim-lang/Nim/pull/15612). -- `fusion` is now un-bundled from Nim, `./koch fusion` will - install it via Nimble at a fixed hash. -- `testament`: added `nimoutFull: bool` spec to compare full output of compiler - instead of a subset; many bugfixes to testament. - - -## Misc/cleanups - -- Deprecated `TaintedString` and `--taintmode`. -- Deprecated `--nilseqs` which is now a noop. -- Added `-d:nimStrictMode` in CI in several places to ensure code doesn't have - certain hints/warnings. -- Removed `.travis.yml`, `appveyor.yml.disabled`, `.github/workflows/ci.yml.disabled`. -- `[skip ci]` now works in azure and CI pipelines, see detail in PR - [#17561](https://github.com/nim-lang/Nim/pull/17561). diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md deleted file mode 100644 index cbe755478..000000000 --- a/changelogs/changelog_2_0_0.md +++ /dev/null @@ -1,367 +0,0 @@ -# v2.0.0 - yyyy-mm-dd - - -## Changes affecting backward compatibility -- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response. It follows Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `ValueError`. - -- `addr` is now available for all addressable locations, - `unsafeAddr` is now deprecated and an alias for `addr`. - -- Certain definitions from the default `system` module have been moved to - the following new modules: - - - `std/syncio` - - `std/assertions` - - `std/formatfloat` - - `std/objectdollar` - - `std/widestrs` - - `std/typedthreads` - - `std/sysatomics` - - In the future, these definitions will be removed from the `system` module, - and their respective modules will have to be imported to use them. - Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option - may be used. - -- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated - symbols in the `system` module: - - Aliases with `Error` suffix to exception types that have a `Defect` suffix - (see [exceptions](https://nim-lang.github.io/Nim/exceptions.html)): - `ArithmeticError`, `DivByZeroError`, `OverflowError`, - `AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`, - `FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`, - `ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`, - `FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`, - `DeadThreadError`, `NilAccessError` - - `addQuitProc`, replaced by `exitprocs.addExitProc` - - Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32` - - `TaintedString`, formerly a distinct alias to `string` - - `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to - `ptr int32`, `ptr int64`, `ptr float32`, `ptr float64` - -- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in - in the `system` module. - -- Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore. - -- The `gc:v2` option is removed. - -- The `mainmodule` and `m` options are removed. - -- The `threads:on` option is now the default. - -- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via - `experimental:flexibleOptionalParams`. - -- Automatic dereferencing (experimental feature) is removed. - -- The `Math.trunc` polyfill for targeting Internet Explorer was - previously included in most JavaScript output files. - Now, it is only included with `-d:nimJsMathTruncPolyfill`. - If you are targeting Internet Explorer, you may choose to enable this option - or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma). - Nim uses `Math.trunc` for the division and modulo operators for integers. - -- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and -`sink` for optimization purposes. - -- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises. - -- The `{.this.}` pragma, deprecated since 0.19, has been removed. -- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead. - ```nim - type Foo = distinct ptr int - - # Before: - var x: Foo = nil - # After: - var x: Foo = Foo(nil) - ``` -- Removed two type pragma syntaxes deprecated since 0.20, namely - `type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`. - -- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent - with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`. - This decision was made with the assumption that the old syntax was used rarely; - if your code used the old syntax, please be aware of this change. - -- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators - are no longer experimental. - -- Removed the `nimIncrSeqV3` define. - -- `macros.getImpl` for `const` symbols now returns the full definition node - (as `nnkConstDef`) rather than the AST of the constant value. - -- Lock levels are deprecated, now a noop. - -- ORC is now the default memory management strategy. Use - `--mm:refc` for a transition period. - -- `strictEffects` are no longer experimental. - Use `legacy:laxEffects` to keep backward compatibility. - -- The `gorge`/`staticExec` calls will now return a descriptive message in the output - if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`. - -- Pointer to `cstring` conversion now triggers a `[PtrToCstringConv]` warning. - This warning will become an error in future versions! Use a `cast` operation - like `cast[cstring](x)` instead. - -- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`. - -- Redefining templates with the same signature was previously - allowed to support certain macro code. To do this explicitly, the - `{.redefine.}` pragma has been added. Note that this is only for templates. - Implicit redefinition of templates is now deprecated and will give an error in the future. - -- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead. - -- Several Standard libraries are moved to nimble packages, use `nimble` to install them: - - `std/punycode` => `punycode` - - `std/asyncftpclient` => `asyncftpclient` - - `std/smtp` => `smtp` - - `std/db_common` => `db_connector/db_common` - - `std/db_sqlite` => `db_connector/db_sqlite` - - `std/db_mysql` => `db_connector/db_mysql` - - `std/db_postgres` => `db_connector/db_postgres` - - `std/db_odbc` => `db_connector/db_odbc` - -- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of - `foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`. - This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead. - -- If no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered. - -- The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection. - -- Underscores (`_`) as routine parameters are now ignored and cannot be used in the routine body. - The following code now does not compile: - - ```nim - proc foo(_: int): int = _ + 1 - echo foo(1) - ``` - - Instead, the following code now compiles: - - ```nim - proc foo(_, _: int): int = 123 - echo foo(1, 2) - ``` -- Underscores (`_`) as generic parameters are not supported and cannot be used. - Generics that use `_` as parameters will no longer compile requires you to replace `_` with something else: - - ```nim - proc foo[_](t: typedesc[_]): string = "BAR" # Can not compile - proc foo[T](t: typedesc[T]): string = "BAR" # Can compile - ``` - -- - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages. - -## Standard library additions and changes - -[//]: # "Changes:" -- OpenSSL 3 is now supported. -- `macros.parseExpr` and `macros.parseStmt` now accept an optional - filename argument for more informative errors. -- Module `colors` expanded with missing colors from the CSS color standard. - `colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard. -- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)). -- The `md5` module now works at compile time and in JavaScript. -- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef` to support `const` tables. -- `strutils.find` now uses and defaults to `last = -1` for whole string searches, - making limiting it to just the first char (`last = 0`) valid. -- `random.rand` now works with `Ordinal`s. -- Undeprecated `os.isvalidfilename`. -- `std/oids` now uses `int64` to store time internally (before it was int32). -- `std/uri.Uri` dollar `$` improved, precalculates the `string` result length from the `Uri`. -- `std/uri.Uri.isIpv6` is now exported. -- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2. - - -- `std/net.IpAddress` dollar `$` improved, uses a fixed capacity for the `string` result based from the `IpAddressFamily`. -- `std/jsfetch.newFetchOptions` now has default values for all parameters -- `std/jsformdata` now accepts `Blob` data type. - -- `std/sharedlist` and `std/sharedtables` are now deprecated, see RFC [#433](https://github.com/nim-lang/RFCs/issues/433). - -- New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall. - - This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17. - - On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall. - - When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be: - ```sh - $ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details - $ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8 - $ sh build.sh # per unix install instructions - $ bin/nim c koch # per unix install instructions - $ ./koch boot -d:release # per unix install instructions - $ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall - ``` - - This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular). - -[//]: # "Additions:" -- Added ISO 8601 week date utilities in `times`: - - Added `IsoWeekRange`, a range type for weeks in a week-based year. - - Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year. - - Added a `initDateTime` overload to create a datetime from an ISO week date. - - Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime. - - Added `getIsoWeeksInYear` to return the number of weeks in a week-based year. -- Added new modules which were part of `std/os`: - - Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. - - Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`. - - Added `std/cmdline` for reading command line parameters. -- Added `sep` parameter in `std/uri` to specify the query separator. -- Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) - and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) - in `jscore` for JavaScript targets. -- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`. -- Added `complex.sgn` for obtaining the phase of complex numbers. -- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`, - `after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`, - `hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`, - `replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`, - `toggleAttribute`, and `matches` to `std/dom`. -- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices) -- Added `capacity` for `string` and `seq` to return the current capacity, see https://github.com/nim-lang/RFCs/issues/460 -- Added `openArray[char]` overloads for `std/parseutils` allowing more code reuse. -- Added `openArray[char]` overloads for `std/unicode` allowing more code reuse. -- Added `safe` parameter to `base64.encodeMime`. - -[//]: # "Deprecations:" -- Deprecated `selfExe` for Nimscript. -- Deprecated `std/sums`. -- Deprecated `std/base64.encode` for collections of arbitrary integer element type. - Now only `byte` and `char` are supported. - -[//]: # "Removals:" -- Removed deprecated module `parseopt2`. -- Removed deprecated module `sharedstrings`. -- Removed deprecated module `dom_extensions`. -- Removed deprecated module `LockFreeHash`. -- Removed deprecated module `events`. -- Removed deprecated `oids.oidToString`. -- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`. -- Removed deprecated `jsre.test` and `jsre.toString`. -- Removed deprecated `math.c_frexp`. -- Removed deprecated `` httpcore.`==` ``. -- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types. -- Removed deprecated `osproc.poDemon`, symbol with typo. -- Removed deprecated `tables.rightSize`. - - -- Removed deprecated `posix.CLONE_STOPPED`. - - -## Language changes - -- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) supports the definition of forbidden tags by the `.forbids` pragma - which can be used to disable certain effects in proc types. -- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental, - meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. -- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed - for the right-hand side of type definitions in type sections. Previously - they would error with "invalid indentation". - -- Compile-time define changes: - - `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`. - In the command line, this is defined as `-d:a.b.c`. Older versions can - use accents as in ``defined(`a.b.c`)`` to access such defines. - - [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas) - now support a string argument for qualified define names. - - ```nim - # -d:package.FooBar=42 - const FooBar {.intdefine: "package.FooBar".}: int = 5 - echo FooBar # 42 - ``` - - This was added to help disambiguate similar define names for different packages. - In older versions, this could only be achieved with something like the following: - - ```nim - const FooBar = block: - const `package.FooBar` {.intdefine.}: int = 5 - `package.FooBar` - ``` - - A generic `define` pragma for constants has been added that interprets - the value of the define based on the type of the constant value. - See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-define-pragma) - for a list of supported types. - -- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes: - - Templates now accept macro pragmas. - - Macro pragmas for var/let/const sections have been redesigned in a way that works - similarly to routine macro pragmas. The new behavior is documented in the - [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas). - - Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`, - allowing multiple type definitions to be injected in place of the original type definition. - - ```nim - import macros - macro multiply(amount: static int, s: untyped): untyped = - let name = $s[0].basename - result = newNimNode(nnkTypeSection) - for i in 1 .. amount: - result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2])) - type - Foo = object - Bar {.multiply: 3.} = object - x, y, z: int - Baz = object - # becomes - type - Foo = object - Bar1 = object - x, y, z: int - Bar2 = object - x, y, z: int - Bar3 = object - x, y, z: int - Baz = object - ``` - -- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference) - has been implemented for a variety of basic cases. For example, code like the following now compiles: - - ```nim - let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")] - ``` - -- `cstring` is now accepted as a selector in `case` statements, removing the - need to convert to `string`. On the JS backend, this is translated directly - to a `switch` statement. - -- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters). -- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`. - -- IBM Z architecture and macOS m1 arm64 architecture are supported. - -- `=wasMoved` can be overridden by users. - -## Compiler changes - -- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the - reality better. (Nim moved away from all techniques based on "tracing".) - -- Defines the `gcRefc` symbol which allows writing specific code for the refc GC. - -- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`, - without requiring `-d:nimVersion140` which is now a noop. - -- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package. - -- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and - related functions produced on the backend. This prevents conflicts with other Nim - static libraries. - -- When compiling for Release the flag `-fno-math-errno` is used for GCC. - - -## Tool changes - -- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`). diff --git a/changelogs/changelog_X_XX_X.md b/changelogs/changelog_X_XX_X.md deleted file mode 100644 index 524599b11..000000000 --- a/changelogs/changelog_X_XX_X.md +++ /dev/null @@ -1,23 +0,0 @@ -# v1.xx.x - yyyy-mm-dd - -This is an example file. -The changes should go to changelog.md! - -## Changes affecting backward compatibility - -- `foo` now behaves differently, use `-d:nimLegacyFoo` for previous behavior. - -## Standard library additions and changes - -- Added `example.exampleProc`. - -- Changed `example.foo` to take additional `bar` parameter. - -## Language changes - - -## Compiler changes - - -## Tool changes - diff --git a/changelogs/readme.md b/changelogs/readme.md deleted file mode 100644 index 3ff1e1b7b..000000000 --- a/changelogs/readme.md +++ /dev/null @@ -1,61 +0,0 @@ -# Update changelog -After each release, call: -``` -git mv changelog.md changelogs/changelog_0_19_0.md # use correct version -cp changelogs/changelog_X_XX_X.md changelog.md -git add changelog.md -``` - -## Recent changelogs are saved here (with their git history) - -## Older changelogs are stored in https://github.com/nim-lang/website - -## source files: -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2009-12-21-version-086-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2010-03-14-version-088-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2010-10-20-version-0810-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2011-07-10-version-0812-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2012-02-09-version-0814-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2012-09-23-version-090-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2013-05-20-version-092-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2014-04-21-version-094-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2014-10-19-version-096-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2014-12-29-version-0102-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2015-04-30-version-0110-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2015-05-04-version-0112-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2015-10-27-version-0120-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2016-01-18-version-0130-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2016-06-07-version-0140-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2016-06-09-version-0142-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2016-09-30-version-0150-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2016-10-23-version-0152-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2017-01-08-version-0160-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2017-05-17-version-0170-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2017-09-07-version-0172-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2018-03-01-version-0180-released.md -* https://github.com/nim-lang/website/blob/master/jekyll/_posts/2018-09-26-version-0190-released.md - -## urls: -* https://nim-lang.org/blog/2009/12/21/version-086-released.html -* https://nim-lang.org/blog/2010/03/14/version-088-released.html -* https://nim-lang.org/blog/2010/10/20/version-0810-released.html -* https://nim-lang.org/blog/2011/07/10/version-0812-released.html -* https://nim-lang.org/blog/2012/02/09/version-0814-released.html -* https://nim-lang.org/blog/2012/09/23/version-090-released.html -* https://nim-lang.org/blog/2013/05/20/version-092-released.html -* https://nim-lang.org/blog/2014/04/21/version-094-released.html -* https://nim-lang.org/blog/2014/10/19/version-096-released.html -* https://nim-lang.org/blog/2014/12/29/version-0102-released.html -* https://nim-lang.org/blog/2015/04/30/version-0110-released.html -* https://nim-lang.org/blog/2015/05/04/version-0112-released.html -* https://nim-lang.org/blog/2015/10/27/version-0120-released.html -* https://nim-lang.org/blog/2016/01/18/version-0130-released.html -* https://nim-lang.org/blog/2016/06/07/version-0140-released.html -* https://nim-lang.org/blog/2016/06/09/version-0142-released.html -* https://nim-lang.org/blog/2016/09/30/version-0150-released.html -* https://nim-lang.org/blog/2016/10/23/version-0152-released.html -* https://nim-lang.org/blog/2017/01/08/version-0160-released.html -* https://nim-lang.org/blog/2017/05/17/version-0170-released.html -* https://nim-lang.org/blog/2017/09/07/version-0172-released.html -* https://nim-lang.org/blog/2018/03/01/version-0180-released.html -* https://nim-lang.org/blog/2018/09/26/version-0190-released.html diff --git a/ci/action.nim b/ci/action.nim deleted file mode 100644 index 5d3a50fda..000000000 --- a/ci/action.nim +++ /dev/null @@ -1,26 +0,0 @@ -import std/[strutils, os, osproc, parseutils, strformat] - - -proc main() = - var msg = "" - const cmd = "./koch boot --gc:orc -d:release" - - let (output, exitCode) = execCmdEx(cmd) - - doAssert exitCode == 0, output - - let start = rfind(output, "Hint: mm") - doAssert parseUntil(output, msg, "; proj", start) > 0, output - - let (commitHash, _) = execCmdEx("""git log --format="%H" -n 1""") - - let welcomeMessage = fmt"""Thanks for your hard work on this PR! -The lines below are statistics of the Nim compiler built from {commitHash} - -{msg} -""" - createDir "ci/nimcache" - writeFile "ci/nimcache/results.txt", welcomeMessage - -when isMainModule: - main() diff --git a/ci/build.bat b/ci/build.bat new file mode 100644 index 000000000..cdce8d3d2 --- /dev/null +++ b/ci/build.bat @@ -0,0 +1,14 @@ +REM Some debug info +echo "Running on %CI_RUNNER_ID% (%CI_RUNNER_DESCRIPTION%) with tags %CI_RUNNER_TAGS%." +gcc -v + +git clone --depth 1 https://github.com/nim-lang/csources.git +cd csources +call build64.bat +cd .. +set PATH=%CD%\bin;%PATH% +nim -v +nim c koch +koch.exe boot +copy bin/nim bin/nimd +koch.exe boot -d:release diff --git a/ci/build.sh b/ci/build.sh new file mode 100644 index 000000000..6321fffba --- /dev/null +++ b/ci/build.sh @@ -0,0 +1,15 @@ +sh ci/deps.sh + +# Build from C sources. +git clone --depth 1 https://github.com/nim-lang/csources.git +cd csources +sh build.sh +cd .. +# Add Nim to the PATH +export PATH=$(pwd)/bin${PATH:+:$PATH} +# Bootstrap. +nim -v +nim c koch +./koch boot +cp bin/nim bin/nimd +./koch boot -d:release diff --git a/ci/build_autogen.bat b/ci/build_autogen.bat deleted file mode 100644 index 0b6ca566e..000000000 --- a/ci/build_autogen.bat +++ /dev/null @@ -1,26 +0,0 @@ -@echo off -rem DO NO EDIT DIRECTLY! auto-generated by `nim r tools/ci_generate.nim` -rem Build development version of the compiler; can be rerun safely -rem bare bones version of ci/funs.sh adapted for windows. - -rem Read in some common shared variables (shared with other tools), -rem see https://stackoverflow.com/questions/3068929/how-to-read-file-contents-into-a-variable-in-a-batch-file -for /f "delims== tokens=1,2" %%G in (config/build_config.txt) do set %%G=%%H -SET nim_csources=bin\nim_csources_%nim_csourcesHash%.exe -echo "building from csources: %nim_csources%" - -if not exist %nim_csourcesDir% ( - git clone -q --depth 1 -b %nim_csourcesBranch% %nim_csourcesUrl% %nim_csourcesDir% -) - -if not exist %nim_csources% ( - cd %nim_csourcesDir% - git checkout %nim_csourcesHash% - echo "%PROCESSOR_ARCHITECTURE%" - if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( - SET ARCH=64 - ) - CALL build.bat - cd .. - copy /y bin\nim.exe %nim_csources% -) diff --git a/ci/deps.bat b/ci/deps.bat new file mode 100644 index 000000000..bda1fe14f --- /dev/null +++ b/ci/deps.bat @@ -0,0 +1,4 @@ +nim e install_nimble.nims +nim e tests/test_nimscript.nims +nimble update +nimble install -y zip opengl sdl1 jester@#head niminst diff --git a/ci/deps.sh b/ci/deps.sh new file mode 100644 index 000000000..f0f831a2a --- /dev/null +++ b/ci/deps.sh @@ -0,0 +1,16 @@ +# Some debug info +echo "Running on $CI_RUNNER_ID ($CI_RUNNER_DESCRIPTION) with tags $CI_RUNNER_TAGS." + +# Packages +apt-get update -qq +apt-get install -y -qq build-essential git libcurl4-openssl-dev libsdl1.2-dev libgc-dev nodejs + +gcc -v + +export PATH=$(pwd)/bin${PATH:+:$PATH} + +# Nimble deps +nim e install_nimble.nims +nim e tests/test_nimscript.nims +nimble update +nimble install zip opengl sdl1 jester@#head niminst diff --git a/ci/funs.sh b/ci/funs.sh deleted file mode 100644 index 8e7f8faf7..000000000 --- a/ci/funs.sh +++ /dev/null @@ -1,143 +0,0 @@ -# Utilities used in CI pipelines and tooling to avoid duplication. -# Avoid top-level statements. -# Prefer nim scripts whenever possible. -# functions starting with `_` are considered internal, less stable. - -echo_run () { - # echo's a command before running it, which helps understanding logs - echo "" - echo "cmd: $@" # in azure we could also use this: echo '##[section]"$@"' - "$@" -} - -nimGetLastCommit() { - git log --no-merges -1 --pretty=format:"%s" -} - -nimIsCiSkip(){ - # D20210329T004830:here refs https://github.com/microsoft/azure-pipelines-agent/issues/2944 - # `--no-merges` is needed to avoid merge commits which occur for PR's. - # $(Build.SourceVersionMessage) is not helpful - # nor is `github.event.head_commit.message` for github actions. - # Note: `[skip ci]` is now handled automatically for github actions, see https://github.blog/changelog/2021-02-08-github-actions-skip-pull-request-and-push-workflows-with-skip-ci/ - commitMsg=$(nimGetLastCommit) - echo commitMsg: "$commitMsg" - if [[ $commitMsg == *"[skip ci]"* ]]; then - echo "skipci: true" - return 0 - else - echo "skipci: false" - return 1 - fi -} - -nimInternalInstallDepsWindows(){ - echo_run mkdir dist - echo_run curl -L https://nim-lang.org/download/mingw64.7z -o dist/mingw64.7z - echo_run curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip - echo_run 7z x dist/mingw64.7z -odist - echo_run 7z x dist/dlls.zip -obin -} - -nimInternalBuildKochAndRunCI(){ - echo_run nim c koch - if ! echo_run ./koch runCI; then - echo_run echo "runCI failed" - echo_run nim r tools/ci_testresults.nim - return 1 - fi -} - -nimDefineVars(){ - . config/build_config.txt - nim_csources=bin/nim_csources_$nim_csourcesHash -} - -_nimNumCpu(){ - # linux: $(nproc) - # FreeBSD | macOS: $(sysctl -n hw.ncpu) - # OpenBSD: $(sysctl -n hw.ncpuonline) - # windows: $NUMBER_OF_PROCESSORS ? - echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1) -} - -_nimBuildCsourcesIfNeeded(){ - # if some systems cannot use make or gmake, we could add support for calling `build.sh` - # but this is slower (not parallel jobs) and would require making build.sh - # understand the arguments passed to the makefile (e.g. `CC=gcc ucpu=amd64 uos=darwin`), - # instead of `--cpu amd64 --os darwin`. - unamestr=$(uname) - # uname values: https://en.wikipedia.org/wiki/Uname - if [ "$unamestr" = 'FreeBSD' ]; then - makeX=gmake - elif [ "$unamestr" = 'OpenBSD' ]; then - makeX=gmake - elif [ "$unamestr" = 'NetBSD' ]; then - makeX=gmake - elif [ "$unamestr" = 'CROSSOS' ]; then - makeX=gmake - elif [ "$unamestr" = 'SunOS' ]; then - makeX=gmake - else - makeX=make - fi - nCPU=$(_nimNumCpu) - echo_run which $makeX - # parallel jobs (5X faster on 16 cores: 10s instead of 50s) - echo_run $makeX -C $nim_csourcesDir -j $((nCPU + 2)) -l $nCPU "$@" - # keep $nim_csources in case needed to investigate bootstrap issues - # without having to rebuild - echo_run cp bin/nim $nim_csources -} - -nimCiSystemInfo(){ - nimDefineVars - echo_run eval echo '$'nim_csources - echo_run pwd - echo_run date - echo_run uname -a - echo_run git log --no-merges -1 --pretty=oneline - echo_run eval echo '$'PATH - echo_run gcc -v - echo_run node -v - echo_run make -v -} - -nimCsourcesHash(){ - nimDefineVars - echo $nim_csourcesHash -} - -nimBuildCsourcesIfNeeded(){ - # goal: allow cachine each tagged version independently - # to avoid rebuilding, so that tools like `git bisect` - # can grab a cached past version without rebuilding. - nimDefineVars - ( - set -e - # avoid polluting caller scope with internal variable definitions. - if test -f "$nim_csources"; then - echo "$nim_csources exists." - else - if test -d "$nim_csourcesDir"; then - echo "$nim_csourcesDir exists." - else - # Note: using git tags would allow fetching just what's needed, unlike git hashes, e.g. - # via `git clone -q --depth 1 --branch $tag $nim_csourcesUrl`. - echo_run git clone -q --depth 1 -b $nim_csourcesBranch \ - $nim_csourcesUrl "$nim_csourcesDir" - # old `git` versions don't support -C option, using `cd` explicitly: - echo_run cd "$nim_csourcesDir" - echo_run git checkout $nim_csourcesHash - echo_run cd "$OLDPWD" - # if needed we could also add: `git reset --hard $nim_csourcesHash` - fi - _nimBuildCsourcesIfNeeded "$@" - fi - - echo_run rm -f bin/nim - # fixes bug #17913, but it's unclear why it's needed, maybe specific to MacOS Big Sur 11.3 on M1 arch? - echo_run cp $nim_csources bin/nim - echo_run $nim_csources -v - ) -} diff --git a/ci/nsis_build.bat b/ci/nsis_build.bat new file mode 100644 index 000000000..4e9d0d67c --- /dev/null +++ b/ci/nsis_build.bat @@ -0,0 +1,59 @@ +REM - Run the full testsuite; tests\testament\tester all + +REM - Uncomment the list of changes in news.txt +REM - write a news ticker entry +REM - Update the version + +REM - Generate the full docs; koch web0 +REM - Generate the installers; +REM - Update the version in system.nim +REM - Test the installers +REM - Tag the release +REM - Merge devel into master +REM - Update csources + +set NIMVER=%1 + +Rem Build -docs file: +koch web0 +cd web\upload +7z a -tzip docs-%NIMVER%.zip *.html +move /y docs-%NIMVER%.zip download +cd ..\.. + +Rem Build csources +koch csources -d:release || exit /b + +rem Grab C sources and nimsuggest +git clone --depth 1 https://github.com/nim-lang/csources.git + +set PATH=%CD%\bin;%PATH% + +ReM Build Win32 version: + +set PATH=C:\Users\araq\projects\mingw32\bin;%PATH% +cd csources +call build.bat +cd .. +ReM Rebuilding koch is necessary because it uses its pointer size to determine +ReM which mingw link to put in the NSIS installer. +nim c --out:koch_temp koch || exit /b +koch_temp boot -d:release || exit /b +koch_temp nsis -d:release || exit /b +koch_temp zip -d:release || exit /b +dir build +move /y build\nim_%NIMVER%.exe build\nim-%NIMVER%_x32.exe || exit /b +move /y build\nim-%NIMVER%.zip build\nim-%NIMVER%_x32.zip || exit /b + + +ReM Build Win64 version: +set PATH=C:\Users\araq\projects\mingw64\bin;%PATH% +cd csources +call build64.bat +cd .. +nim c --out:koch_temp koch || exit /b +koch_temp boot -d:release || exit /b +koch_temp nsis -d:release || exit /b +koch_temp zip -d:release || exit /b +move /y build\nim_%NIMVER%.exe build\nim-%NIMVER%_x64.exe || exit /b +move /y build\nim-%NIMVER%.zip build\nim-%NIMVER%_x64.zip || exit /b diff --git a/compiler.nimble b/compiler.nimble new file mode 100644 index 000000000..5929df3ec --- /dev/null +++ b/compiler.nimble @@ -0,0 +1,9 @@ + +version = system.NimVersion +author = "Andreas Rumpf" +description = "Compiler package providing the compiler sources as a library." +license = "MIT" + +installDirs = @["compiler"] + +requires "nim >= 0.14.0" diff --git a/compiler/aliasanalysis.nim b/compiler/aliasanalysis.nim deleted file mode 100644 index f14b81524..000000000 --- a/compiler/aliasanalysis.nim +++ /dev/null @@ -1,128 +0,0 @@ - -import ast - -import std / assertions - -const - PathKinds0* = {nkDotExpr, nkCheckedFieldExpr, - nkBracketExpr, nkDerefExpr, nkHiddenDeref, - nkAddr, nkHiddenAddr, - nkObjDownConv, nkObjUpConv} - PathKinds1* = {nkHiddenStdConv, nkHiddenSubConv} - -proc skipConvDfa*(n: PNode): PNode = - result = n - while true: - case result.kind - of nkObjDownConv, nkObjUpConv: - result = result[0] - of PathKinds1: - result = result[1] - else: break - -proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = - var n = orig - while true: - case n.kind - of PathKinds0 - {nkHiddenDeref, nkDerefExpr}: - n = n[0] - of PathKinds1: - n = n[1] - of nkHiddenDeref, nkDerefExpr: - # We "own" sinkparam[].loc but not ourVar[].location as it is a nasty - # pointer indirection. - # bug #14159, we cannot reason about sinkParam[].location as it can - # still be shared for tyRef. - n = n[0] - return n.kind == nkSym and n.sym.owner == owner and - (n.sym.typ.skipTypes(abstractInst-{tyOwned}).kind in {tyOwned}) - else: break - # XXX Allow closure deref operations here if we know - # the owner controlled the closure allocation? - result = n.kind == nkSym and n.sym.owner == owner and - {sfGlobal, sfThread, sfCursor} * n.sym.flags == {} and - (n.sym.kind != skParam or isSinkParam(n.sym)) # or n.sym.typ.kind == tyVar) - # Note: There is a different move analyzer possible that checks for - # consume(param.key); param.key = newValue for all paths. Then code like - # - # let splited = split(move self.root, x) - # self.root = merge(splited.lower, splited.greater) - # - # could be written without the ``move self.root``. However, this would be - # wrong! Then the write barrier for the ``self.root`` assignment would - # free the old data and all is lost! Lesson: Don't be too smart, trust the - # lower level C++ optimizer to specialize this code. - -type AliasKind* = enum - yes, no, maybe - -proc aliases*(obj, field: PNode): AliasKind = - # obj -> field: - # x -> x: true - # x -> x.f: true - # x.f -> x: false - # x.f -> x.f: true - # x.f -> x.v: false - # x -> x[]: true - # x[] -> x: false - # x -> x[0]: true - # x[0] -> x: false - # x[0] -> x[0]: true - # x[0] -> x[1]: false - # x -> x[i]: true - # x[i] -> x: false - # x[i] -> x[i]: maybe; Further analysis could make this return true when i is a runtime-constant - # x[i] -> x[j]: maybe; also returns maybe if only one of i or j is a compiletime-constant - template collectImportantNodes(result, n) = - var result: seq[PNode] - var n = n - while true: - case n.kind - of PathKinds0 - {nkDotExpr, nkBracketExpr, nkDerefExpr, nkHiddenDeref}: - n = n[0] - of PathKinds1: - n = n[1] - of nkDotExpr, nkBracketExpr, nkDerefExpr, nkHiddenDeref: - result.add n - n = n[0] - of nkSym: - result.add n - break - else: return no - - collectImportantNodes(objImportantNodes, obj) - collectImportantNodes(fieldImportantNodes, field) - - # If field is less nested than obj, then it cannot be part of/aliased by obj - if fieldImportantNodes.len < objImportantNodes.len: return no - - result = yes - for i in 1..objImportantNodes.len: - # We compare the nodes leading to the location of obj and field - # with each other. - # We continue until they diverge, in which case we return no, or - # until we reach the location of obj, in which case we do not need - # to look further, since field must be part of/aliased by obj now. - # If we encounter an element access using an index which is a runtime value, - # we simply return maybe instead of yes; should further nodes not diverge. - let currFieldPath = fieldImportantNodes[^i] - let currObjPath = objImportantNodes[^i] - - if currFieldPath.kind != currObjPath.kind: - return no - - case currFieldPath.kind - of nkSym: - if currFieldPath.sym != currObjPath.sym: return no - of nkDotExpr: - if currFieldPath[1].sym != currObjPath[1].sym: return no - of nkDerefExpr, nkHiddenDeref: - discard - of nkBracketExpr: - if currFieldPath[1].kind in nkLiterals and currObjPath[1].kind in nkLiterals: - if currFieldPath[1].intVal != currObjPath[1].intVal: - return no - else: - result = maybe - else: assert false # unreachable - diff --git a/compiler/aliases.nim b/compiler/aliases.nim index 4b50fdb28..f79210dd7 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -10,10 +10,7 @@ ## Simple alias analysis for the HLO and the code generators. import - ast, astalgo, types, trees, intsets - -when defined(nimPreviewSlimSystem): - import std/assertions + ast, astalgo, types, trees, intsets, msgs type TAnalysisResult* = enum @@ -25,17 +22,17 @@ proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult = result = arNo case n.kind of nkRecList: - for i in 0..= 2 and b.len >= 2: + if len(a) >= 2 and len(b) >= 2: # array accesses: if result == arYes and isDeepConstExpr(a[1]) and isDeepConstExpr(b[1]): # we know it's the same array and we have 2 constant indexes; @@ -194,14 +186,4 @@ proc isPartOf*(a, b: PNode): TAnalysisResult = if res != arNo: result = res if res == arYes: break - of nkCallKinds: - result = arNo - for i in 1.. 0: - result = isPartOf(a, b[0]) else: discard diff --git a/compiler/ast.nim b/compiler/ast.nim index f93c8d910..6302c21b9 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -10,27 +10,26 @@ # abstract syntax tree + symbol table import - lineinfos, hashes, options, ropes, idents, int128, tables -from strutils import toLowerAscii - -when defined(nimPreviewSlimSystem): - import std/assertions - -export int128 + lineinfos, hashes, nversion, options, strutils, std / sha1, ropes, idents, + intsets, idgen type TCallingConvention* = enum - ccNimCall = "nimcall" # nimcall, also the default - ccStdCall = "stdcall" # procedure is stdcall - ccCDecl = "cdecl" # cdecl - ccSafeCall = "safecall" # safecall - ccSysCall = "syscall" # system call - ccInline = "inline" # proc should be inlined - ccNoInline = "noinline" # proc should not be inlined - ccFastCall = "fastcall" # fastcall (pass parameters in registers) - ccThisCall = "thiscall" # thiscall (parameters are pushed right-to-left) - ccClosure = "closure" # proc has a closure - ccNoConvention = "noconv" # needed for generating proper C procs sometimes + ccDefault, # proc has no explicit calling convention + ccStdCall, # procedure is stdcall + ccCDecl, # cdecl + ccSafeCall, # safecall + ccSysCall, # system call + ccInline, # proc should be inlined + ccNoInline, # proc should not be inlined + ccFastCall, # fastcall (pass parameters in registers) + ccClosure, # proc has a closure + ccNoConvention # needed for generating proper C procs sometimes + +const + CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall", + "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", + "closure", "noconv"] type TNodeKind* = enum # order is extremely important, because ranges are used @@ -185,7 +184,7 @@ type nkStmtListExpr, # a statement list followed by an expr; this is used # to allow powerful multi-line templates nkBlockExpr, # a statement block ending in an expr; this is used - # to allow powerful multi-line templates that open a + # to allowe powerful multi-line templates that open a # temporary scope nkStmtListType, # a statement list ending in a type; for macros nkBlockType, # a statement block ending in a type; for macros @@ -207,31 +206,28 @@ type nkPtrTy, # ``ptr T`` nkVarTy, # ``var T`` nkConstTy, # ``const T`` - nkOutTy, # ``out T`` + nkMutableTy, # ``mutable T`` nkDistinctTy, # distinct type nkProcTy, # proc type nkIteratorTy, # iterator type - nkSinkAsgn, # '=sink(x, y)' + nkSharedTy, # 'shared T' + # we use 'nkPostFix' for the 'not nil' addition nkEnumTy, # enum body nkEnumFieldDef, # `ident = expr` in an enumeration nkArgList, # argument list nkPattern, # a special pattern; used for matching - nkHiddenTryStmt, # a hidden try statement + nkReturnToken, # token used for interpretation nkClosure, # (prc, env)-pair (internally used for code gen) nkGotoState, # used for the state machine (for iterators) nkState, # give a label to a code section (for iterators) nkBreakState, # special break statement for easier code generation nkFuncDef, # a func nkTupleConstr # a tuple constructor - nkError # erroneous AST node - nkModuleRef # for .rod file support: A (moduleId, itemId) pair - nkReplayAction # for .rod file support: A replay action - nkNilRodNode # for .rod file support: a 'nil' PNode TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # 49 flags! + TSymFlag* = enum # already 33 flags! sfUsed, # read access of sym (for warnings) or simply used sfExported, # symbol is exported from module sfFromGeneric, # symbol is instantiation of a generic; this is needed @@ -240,11 +236,8 @@ type sfGlobal, # symbol is at global scope sfForward, # symbol is forward declared - sfWasForwarded, # symbol had a forward declaration - # (implies it's too dangerous to patch its type signature) sfImportc, # symbol is external; imported sfExportc, # symbol is exported (under a specified name) - sfMangleCpp, # mangle as cpp (combines with `sfExportc`) sfVolatile, # variable is volatile sfRegister, # variable should be placed in a register sfPure, # object is "pure" that means it has no type-information @@ -259,20 +252,14 @@ type # *OR*: a proc is indirectly called (used as first class) sfCompilerProc, # proc is a compiler proc, that is a C proc that is # needed for the code generator - sfEscapes # param escapes - # currently unimplemented + sfProcvar, # proc can be passed to a proc var sfDiscriminant, # field is a discriminant in a record/object - sfRequiresInit, # field must be initialized during construction sfDeprecated, # symbol is deprecated sfExplain, # provide more diagnostics when this symbol is used sfError, # usage of symbol should trigger a compile-time error sfShadowed, # a symbol that was shadowed in some inner scope sfThread, # proc will run as a thread # variable is a thread variable - sfCppNonPod, # tells compiler to treat such types as non-pod's, so that - # `thread_local` is used instead of `__thread` for - # {.threadvar.} + `--threads`. Only makes sense for importcpp types. - # This has a performance impact so isn't set by default. sfCompileTime, # proc can be evaluated at compile time sfConstructor, # proc is a C++ constructor sfDispatcher, # copied method symbol is the dispatcher @@ -283,39 +270,17 @@ type sfNamedParamCall, # symbol needs named parameter call syntax in target # language; for interfacing with Objective C sfDiscardable, # returned value may be discarded implicitly - sfOverriden, # proc is overridden - sfCallsite # A flag for template symbols to tell the - # compiler it should use line information from - # the calling side of the macro, not from the - # implementation. + sfOverriden, # proc is overriden sfGenSym # symbol is 'gensym'ed; do not add to symbol table - sfNonReloadable # symbol will be left as-is when hot code reloading is on - - # meaning that it won't be renamed and/or changed in any way - sfGeneratedOp # proc is a generated '='; do not inject destructors in it - # variable is generated closure environment; requires early - # destruction for --newruntime. - sfTemplateParam # symbol is a template parameter - sfCursor # variable/field is a cursor, see RFC 177 for details - sfInjectDestructors # whether the proc needs the 'injectdestructors' transformation - sfNeverRaises # proc can never raise an exception, not even OverflowDefect - # or out-of-memory - sfSystemRaisesDefect # proc in the system can raise defects - sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally' - sfSingleUsedTemp # For temporaries that we know will only be used once - sfNoalias # 'noalias' annotation, means C's 'restrict' - sfEffectsDelayed # an 'effectsDelayed' parameter - sfGeneratedType # A anonymous generic type that is generated by the compiler for - # objects that do not have generic parameters in case one of the - # object fields has one. - # - # This is disallowed but can cause the typechecking to go into - # an infinite loop, this flag is used as a sentinel to stop it. TSymFlags* = set[TSymFlag] const sfNoInit* = sfMainModule # don't generate code to init the variable + sfImmediate* = sfDispatcher + # macro or template is immediately expanded + # without considering any possible overloads sfAllUntyped* = sfVolatile # macro or template is immediately expanded \ # in a generic context @@ -328,6 +293,10 @@ const # the compiler will avoid printing such names # in user messages. + sfHoisted* = sfForward + # an expression was hoised to an anonymous variable. + # the flag is applied to the var/let symbol + sfNoForward* = sfRegister # forward declarations are not required (per module) sfReorder* = sfForward @@ -338,10 +307,10 @@ const sfExperimental* = sfOverriden # module uses the .experimental switch sfGoto* = sfOverriden # var is used for 'goto' code generation sfWrittenTo* = sfBorrow # param is assigned to - # currently unimplemented + sfEscapes* = sfProcvar # param escapes sfBase* = sfDiscriminant + sfIsSelf* = sfOverriden # param is 'self' sfCustomPragma* = sfRegister # symbol is custom pragma template - sfTemplateRedefinition* = sfExportc # symbol is a redefinition of an earlier template const # getting ready for the future expr/stmt merge @@ -350,14 +319,10 @@ const nkEffectList* = nkArgList # hacks ahead: an nkEffectList is a node with 4 children: exceptionEffects* = 0 # exceptions at position 0 - requiresEffects* = 1 # 'requires' annotation - ensuresEffects* = 2 # 'ensures' annotation + usesEffects* = 1 # read effects at position 1 + writeEffects* = 2 # write effects at position 2 tagEffects* = 3 # user defined tag ('gc', 'time' etc.) - pragmasEffects* = 4 # not an effect, but a slot for pragmas in proc type - forbiddenEffects* = 5 # list of illegal effects - effectListLen* = 6 # list of effects list - nkLastBlockStmts* = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt} - # these must be last statements in a block + effectListLen* = 4 # list of effects list type TTypeKind* = enum # order is important! @@ -368,7 +333,7 @@ type # (apparently something with bootstrapping) # if you need to add a type, they can apparently be reused tyNone, tyBool, tyChar, - tyEmpty, tyAlias, tyNil, tyUntyped, tyTyped, tyTypeDesc, + tyEmpty, tyAlias, tyNil, tyExpr, tyStmt, tyTypeDesc, tyGenericInvocation, # ``T[a, b]`` for types to invoke tyGenericBody, # ``T[a, b, body]`` last parameter is the body tyGenericInst, # ``T[a, b, realInstance]`` instantiated generic type @@ -391,15 +356,13 @@ type tySequence, tyProc, tyPointer, tyOpenArray, - tyString, tyCstring, tyForward, + tyString, tyCString, tyForward, tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers tyFloat, tyFloat32, tyFloat64, tyFloat128, tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64, - tyOwned, tySink, tyLent, + tyOptAsRef, tySink, tyLent, tyVarargs, - tyUncheckedArray - # An array with boundaries [0,+∞] - + tyUnused, tyProxy # used as errornous type (for idetools) tyBuiltInTypeClass @@ -447,17 +410,15 @@ type # instantiation and prior to this it has the potential to # be any type. - tyConcept - # new style concept. + tyOpt + # Builtin optional type tyVoid # now different from tyEmpty, hurray! - tyIterable static: # remind us when TTypeKind stops to fit in a single 64-bit word - # assert TTypeKind.high.ord <= 63 - discard + assert TTypeKind.high.ord <= 63 const tyPureObject* = tyTuple @@ -471,13 +432,8 @@ const tyUserTypeClass, tyUserTypeClassInst, tyAnd, tyOr, tyNot, tyAnything} - tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyUntyped} + tyTypeClasses + tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses tyUserTypeClasses* = {tyUserTypeClass, tyUserTypeClassInst} - # consider renaming as `tyAbstractVarRange` - abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, - tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} - abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, - tyInferred, tySink, tyOwned} # xxx what about tyStatic? type TTypeKinds* = set[TTypeKind] @@ -499,27 +455,21 @@ type nfExplicitCall # x.y() was used instead of x.y nfExprCall # this is an attempt to call a regular expression nfIsRef # this node is a 'ref' node; used for the VM - nfIsPtr # this node is a 'ptr' node; used for the VM nfPreventCg # this node should be ignored by the codegen nfBlockArg # this a stmtlist appearing in a call (e.g. a do block) nfFromTemplate # a top-level node returned from a template nfDefaultParam # an automatically inserter default parameter nfDefaultRefsParam # a default param value references another parameter # the flag is applied to proc default values and to calls - nfExecuteOnReload # A top-level statement that will be executed during reloads - nfLastRead # this node is a last read - nfFirstWrite # this node is a first write - nfHasComment # node has a comment - nfUseDefaultField # node has a default value (object constructor) TNodeFlags* = set[TNodeFlag] - TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46) + TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that) tfVarargs, # procedure has C styled varargs # tyArray type represeting a varargs list tfNoSideEffect, # procedure type does not allow side effects tfFinal, # is the object final? tfInheritable, # is the object inheritable? - tfHasOwned, # type contains an 'owned' type and must be moved + tfAcyclic, # type is acyclic (for GC optimization) tfEnumHasHoles, # enum cannot be mapped into a range tfShallow, # type can be shallow copied on assignment tfThread, # proc type is marked as ``thread``; alias for ``gcsafe`` @@ -543,11 +493,9 @@ type tfIterator, # type is really an iterator, not a tyProc tfPartial, # type is declared as 'partial' tfNotNil, # type cannot be 'nil' - tfRequiresInit, # type constains a "not nil" constraint somewhere or - # a `requiresInit` field, so the default zero init - # is not appropriate - tfNeedsFullInit, # object type marked with {.requiresInit.} - # all fields must be initialized + + tfNeedsInit, # type constains a "not nil" constraint somewhere or some + # other type so that it requires initialization tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode tfHasMeta, # type contains "wildcard" sub-types such as generic params # or other type classes @@ -557,7 +505,6 @@ type tfGenericTypeParam tfImplicitTypeParam tfInferrableStatic - tfConceptMatchedTypeSym tfExplicit # for typedescs, marks types explicitly prefixed with the # `type` operator (e.g. type int) tfWildcard # consider a proc like foo[T, I](x: Type[T, I]) @@ -569,20 +516,9 @@ type tfTriggersCompileTime # uses the NimNode type which make the proc # implicitly '.compiletime' tfRefsAnonObj # used for 'ref object' and 'ptr object' - tfCovariant # covariant generic param mimicking a ptr type - tfWeakCovariant # covariant generic param mimicking a seq/array type + tfCovariant # covariant generic param mimicing a ptr type + tfWeakCovariant # covariant generic param mimicing a seq/array type tfContravariant # contravariant generic param - tfCheckedForDestructor # type was checked for having a destructor. - # If it has one, t.destructor is not nil. - tfAcyclic # object type was annotated as .acyclic - tfIncompleteStruct # treat this type as if it had sizeof(pointer) - tfCompleteStruct - # (for importc types); type is fully specified, allowing to compute - # sizeof, alignof, offsetof at CT - tfExplicitCallConv - tfIsConstructor - tfEffectSystemWorkaround - tfIsOutParam TTypeFlags* = set[TTypeFlag] @@ -624,80 +560,85 @@ type const routineKinds* = {skProc, skFunc, skMethod, skIterator, skConverter, skMacro, skTemplate} - ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub, skAlias} + routineKinds - + tfIncompleteStruct* = tfVarargs + tfUncheckedArray* = tfVarargs tfUnion* = tfNoSideEffect tfGcSafe* = tfThread tfObjHasKids* = tfEnumHasHoles + tfOldSchoolExprStmt* = tfVarargs # for now used to distinguish \ + # 'varargs[expr]' from 'varargs[untyped]'. Eventually 'expr' will be + # deprecated and this mess can be cleaned up. tfReturnsNew* = tfInheritable skError* = skUnknown -var - eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam} - ## type flags that are essential for type equality. - ## This is now a variable because for emulation of version:1.0 we - ## might exclude {tfGcSafe, tfNoSideEffect}. + # type flags that are essential for type equality: + eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr} type TMagic* = enum # symbols that require compiler magic: mNone, - mDefined, mDeclared, mDeclaredInScope, mCompiles, mArrGet, mArrPut, mAsgn, - mLow, mHigh, mSizeOf, mAlignOf, mOffsetOf, mTypeTrait, - mIs, mOf, mAddr, mType, mTypeOf, - mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic, + mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn, + mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mType, mTypeOf, + mRoof, mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic, mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst, - mInc, mDec, mOrd, + mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mNewSeqOfCap, mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq, + mXLenStr, mXLenSeq, mIncl, mExcl, mCard, mChr, mGCref, mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mSucc, mPred, mAddF64, mSubF64, mMulF64, mDivF64, - mShrI, mShlI, mAshrI, mBitandI, mBitorI, mBitxorI, + mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, + mMinF64, mMaxF64, mAddU, mSubU, mMulU, mDivU, mModU, mEqI, mLeI, mLtI, mEqF64, mLeF64, mLtF64, mLeU, mLtU, + mLeU64, mLtU64, mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, - mEqRef, mLePtr, mLtPtr, + mEqRef, mEqUntracedRef, mLePtr, mLtPtr, mXor, mEqCString, mEqProc, mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, - mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, - mIntToStr, mInt64ToStr, mFloatToStr, # for compiling nimStdlibVersion < 1.5.1 (not bootstrapping) - mCStrToStr, + mUnaryPlusF64, mUnaryMinusF64, mAbsF64, + mZe8ToI, mZe8ToI64, + mZe16ToI, mZe16ToI64, + mZe32ToI64, mZeIToI64, + mToU8, mToU16, mToU32, + mToFloat, mToBiggestFloat, + mToInt, mToBiggestInt, + mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, - mImplies, mIff, mExists, mForall, mOld, mEqStr, mLeStr, mLtStr, - mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, + mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mSlice, mDotDot, # this one is only necessary to give nice compile time warnings mFields, mFieldPairs, mOmpParFor, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mInSet, mRepr, mExit, + mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mIsPartOf, mAstToStr, mParallel, - mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq, + mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mNewStringOfCap, mParseBiggestFloat, - mMove, mWasMoved, mDestroy, mTrace, - mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset, - mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, + mReset, + mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, - mOrdinal, mIterableType, + mOrdinal, mInt, mInt8, mInt16, mInt32, mInt64, mUInt, mUInt8, mUInt16, mUInt32, mUInt64, mFloat, mFloat32, mFloat64, mFloat128, mBool, mChar, mString, mCstring, - mPointer, mNil, mExpr, mStmt, mTypeDesc, - mVoidType, mPNimrodNode, mSpawn, mDeepCopy, + mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, + mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy, mIsMainModule, mCompileDate, mCompileTime, mProcCall, mCpuEndian, mHostOS, mHostCPU, mBuildOS, mBuildCPU, mAppType, + mNaN, mInf, mNegInf, mCompileOption, mCompileOptionArg, mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind, mNSymKind, @@ -706,73 +647,59 @@ type mNctPut, mNctLen, mNctGet, mNctHasNext, mNctNext, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, - mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetStrVal, mNLineInfo, - mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mNSigHash, mNSizeOf, - mNBindSym, mNCallSite, + mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo, + mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, + mNBindSym, mLocals, mNCallSite, mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym, mNHint, mNWarning, mNError, - mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2, - mNimvm, mIntDefine, mStrDefine, mBoolDefine, mGenericDefine, mRunnableExamples, - mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf, - mSymIsInstantiationOf, mNodeId, mPrivateAccess, mZeroDefault - + mInstantiationInfo, mGetTypeInfo, + mNimvm, mIntDefine, mStrDefine, mRunnableExamples, + mException, mBuiltinType +# things that we can evaluate safely at compile time, even if not asked for it: const - # things that we can evaluate safely at compile time, even if not asked for it: - ctfeWhitelist* = {mNone, mSucc, + ctfeWhitelist* = {mNone, mUnaryLt, mSucc, mPred, mInc, mDec, mOrd, mLengthOpenArray, - mLengthStr, mLengthArray, mLengthSeq, - mArrGet, mArrPut, mAsgn, mDestroy, + mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq, + mArrGet, mArrPut, mAsgn, mIncl, mExcl, mCard, mChr, mAddI, mSubI, mMulI, mDivI, mModI, mAddF64, mSubF64, mMulF64, mDivF64, mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, + mMinF64, mMaxF64, mAddU, mSubU, mMulU, mDivU, mModU, mEqI, mLeI, mLtI, mEqF64, mLeF64, mLtF64, mLeU, mLtU, + mLeU64, mLtU64, mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, - mEqRef, mEqProc, mLePtr, mLtPtr, mEqCString, mXor, + mEqRef, mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, - mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, - mIntToStr, mInt64ToStr, mFloatToStr, - mCStrToStr, + mUnaryPlusF64, mUnaryMinusF64, mAbsF64, + mZe8ToI, mZe8ToI64, + mZe16ToI, mZe16ToI64, + mZe32ToI64, mZeIToI64, + mToU8, mToU16, mToU32, + mToFloat, mToBiggestFloat, + mToInt, mToBiggestInt, + mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, mAnd, mOr, mEqStr, mLeStr, mLtStr, - mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, + mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mInSet, mRepr, mOpenArrayToSeq} - - generatedMagics* = {mNone, mIsolate, mFinished, mOpenArrayToSeq} - ## magics that are generated as normal procs in the backend + mInRange, mInSet, mRepr, + mCopyStr, mCopyStrLast} + # magics that require special semantic checking and + # thus cannot be overloaded (also documented in the spec!): + SpecialSemMagics* = { + mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf, + mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr} type - ItemId* = object - module*: int32 - item*: int32 - -proc `$`*(x: ItemId): string = - "(module: " & $x.module & ", item: " & $x.item & ")" - -proc `==`*(a, b: ItemId): bool {.inline.} = - a.item == b.item and a.module == b.module - -proc hash*(x: ItemId): Hash = - var h: Hash = hash(x.module) - h = h !& hash(x.item) - result = !$h - - -type - TIdObj* {.acyclic.} = object of RootObj - itemId*: ItemId - PIdObj* = ref TIdObj - PNode* = ref TNode TNodeSeq* = seq[PNode] PType* = ref TType @@ -796,12 +723,12 @@ type ident*: PIdent else: sons*: TNodeSeq - when defined(nimsuggest): - endInfo*: TLineInfo + comment*: string + TSymSeq* = seq[PSym] TStrTable* = object # a table[PIdent] of PSym counter*: int - data*: seq[PSym] + data*: TSymSeq # -------------- backend information ------------------------------- TLocKind* = enum @@ -818,7 +745,7 @@ type locOther # location is something other TLocFlag* = enum lfIndirect, # backend introduced a pointer - lfFullExternalName, # only used when 'conf.cmd == cmdNimfix': Indicates + lfFullExternalName, # only used when 'conf.cmd == cmdPretty': Indicates # that the symbol has been imported via 'importc: "fullname"' and # no format string. lfNoDeepCopy, # no need for a deep copy @@ -828,14 +755,12 @@ type lfHeader, # include header file for symbol lfImportCompilerProc, # ``importc`` of a compilerproc lfSingleUse # no location yet and will only be used once - lfEnforceDeref # a copyMem is required to dereference if this a - # ptr array due to C array limitations. - # See #1181, #6422, #11171 - lfPrepareForMutation # string location is about to be mutated (V2) TStorageLoc* = enum OnUnknown, # location is unknown (stack, heap or static) OnStatic, # in a static section OnStack, # location is on hardware stack + OnStackShadowDup, # location is on the stack but also replicated + # on the shadow stack OnHeap # location is on heap or global # (reference counting needed) TLocFlags* = set[TLocFlag] @@ -845,6 +770,7 @@ type flags*: TLocFlags # location's flags lode*: PNode # Node where the location came from; can be faked r*: Rope # rope value of location (code generators) + dup*: Rope # duplicated location for precise stack scans # ---------------- end of backend information ------------------------------ @@ -852,7 +778,6 @@ type libHeader, libDynamic TLib* = object # also misused for headers! - # keep in sync with PackedLib kind*: TLibKind generated*: bool # needed for the backends: isOverriden*: bool @@ -869,33 +794,43 @@ type PInstantiation* = ref TInstantiation - TScope* {.acyclic.} = object + TScope* = object depthLevel*: int symbols*: TStrTable parent*: PScope - allowPrivateAccess*: seq[PSym] # # enable access to private fields PScope* = ref TScope PLib* = ref TLib - TSym* {.acyclic.} = object of TIdObj # Keep in sync with PackedSym + TSym* {.acyclic.} = object of TIdObj # proc and type instantiations are cached in the generic symbol case kind*: TSymKind + of skType, skGenericParam: + typeInstCache*: seq[PType] of routineKinds: - #procInstCache*: seq[PInstantiation] - gcUnsafetyReason*: PSym # for better error messages regarding gcsafe - transformedBody*: PNode # cached body after transf pass + procInstCache*: seq[PInstantiation] + gcUnsafetyReason*: PSym # for better error messages wrt gcsafe + #scope*: PScope # the scope where the proc was defined + of skModule, skPackage: + # modules keep track of the generic symbols they use from other modules. + # this is because in incremental compilation, when a module is about to + # be replaced with a newer version, we must decrement the usage count + # of all previously used generics. + # For 'import as' we copy the module symbol but shallowCopy the 'tab' + # and set the 'usedGenerics' to ... XXX gah! Better set module.name + # instead? But this doesn't work either. --> We need an skModuleAlias? + # No need, just leave it as skModule but set the owner accordingly and + # check for the owner when touching 'usedGenerics'. + usedGenerics*: seq[PInstantiation] + tab*: TStrTable # interface table for modules of skLet, skVar, skField, skForVar: guard*: PSym bitsize*: int - alignment*: int # for alignment else: nil magic*: TMagic typ*: PType name*: PIdent info*: TLineInfo - when defined(nimsuggest): - endInfo*: TLineInfo owner*: PSym flags*: TSymFlags ast*: PNode # syntax tree of proc, iterator, etc.: @@ -910,20 +845,18 @@ type position*: int # used for many different things: # for enum fields its position; # for fields its offset - # for parameters its position (starting with 0) + # for parameters its position # for a conditional: # 1 iff the symbol is defined, else 0 # (or not in symbol table) # for modules, an unique index corresponding # to the module's fileIdx # for variables a slot index for the evaluator + # for routines a superop-ID offset*: int # offset of record field loc*: TLoc annex*: PLib # additional fields (seldom used, so we use a - # reference to another object to save space) - when hasFFI: - cname*: string # resolved C declaration name in importc decl, e.g.: - # proc fun() {.importc: "$1aux".} => cname = funaux + # reference to another object to safe space) constraint*: PNode # additional constraints like 'lit|result'; also # misused for the codegenDecl pragma in the hope # it won't cause problems @@ -933,20 +866,11 @@ type allUsages*: seq[TLineInfo] TTypeSeq* = seq[PType] - - TTypeAttachedOp* = enum ## as usual, order is important here - attachedWasMoved, - attachedDestructor, - attachedAsgn, - attachedSink, - attachedTrace, - attachedDeepCopy - + TLockLevel* = distinct int16 TType* {.acyclic.} = object of TIdObj # \ # types are identical iff they have the # same id; there may be multiple copies of a type # in memory! - # Keep in sync with PackedType kind*: TTypeKind # kind of type callConv*: TCallingConvention # for procs flags*: TTypeFlags # flags of the type @@ -955,7 +879,7 @@ type # for range types a nkRange node # for record types a nkRecord node # for enum types a list of symbols - # if kind == tyInt: it is an 'int literal(x)' type + # for tyInt it can be the int literal # for procs and tyGenericBody, it's the # formal param list # for concepts, the concept body @@ -963,15 +887,20 @@ type owner*: PSym # the 'owner' of the type sym*: PSym # types have the sym associated with them # it is used for converting types to strings + destructor*: PSym # destructor. warning: nil here may not necessary + # mean that there is no destructor. + # see instantiateDestructor in semdestruct.nim + deepCopy*: PSym # overriden 'deepCopy' operation + assignment*: PSym # overriden '=' operation + sink*: PSym # overriden '=sink' operation + methods*: seq[(int,PSym)] # attached methods size*: BiggestInt # the size of the type in bytes # -1 means that the size is unkwown align*: int16 # the type's alignment requirements - paddingAtEnd*: int16 # + lockLevel*: TLockLevel # lock level as required for deadlock checking loc*: TLoc typeInst*: PType # for generic instantiations the tyGenericInst that led to this # type. - uniqueId*: ItemId # due to a design mistake, we need to keep the real ID here as it - # is required by the --incremental:on mode. TPair* = object key*, val*: RootRef @@ -1015,45 +944,13 @@ type TImplication* = enum impUnknown, impNo, impYes -template nodeId(n: PNode): int = cast[int](n) - -type Gconfig = object - # we put comments in a side channel to avoid increasing `sizeof(TNode)`, which - # reduces memory usage given that `PNode` is the most allocated type by far. - comments: Table[int, string] # nodeId => comment - useIc*: bool - -var gconfig {.threadvar.}: Gconfig - -proc setUseIc*(useIc: bool) = gconfig.useIc = useIc - -proc comment*(n: PNode): string = - if nfHasComment in n.flags and not gconfig.useIc: - # IC doesn't track comments, see `packed_ast`, so this could fail - result = gconfig.comments[n.nodeId] - -proc `comment=`*(n: PNode, a: string) = - let id = n.nodeId - if a.len > 0: - # if needed, we could periodically cleanup gconfig.comments when its size increases, - # to ensure only live nodes (and with nfHasComment) have an entry in gconfig.comments; - # for compiling compiler, the waste is very small: - # num calls to newNodeImpl: 14984160 (num of PNode allocations) - # size of gconfig.comments: 33585 - # num of nodes with comments that were deleted and hence wasted: 3081 - n.flags.incl nfHasComment - gconfig.comments[id] = a - elif nfHasComment in n.flags: - n.flags.excl nfHasComment - gconfig.comments.del(id) - # BUGFIX: a module is overloadable so that a proc can have the # same name as an imported module. This is necessary because of # the poor naming choices in the standard library. const OverloadableSyms* = {skProc, skFunc, skMethod, skIterator, - skConverter, skModule, skTemplate, skMacro, skEnumField} + skConverter, skModule, skTemplate, skMacro} GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody, tyGenericParam} @@ -1067,21 +964,21 @@ const tyBool, tyChar, tyEnum, tyArray, tyObject, tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tyLent, tySequence, tyProc, tyPointer, - tyOpenArray, tyString, tyCstring, tyInt..tyInt64, tyFloat..tyFloat128, + tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128, tyUInt..tyUInt64} IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64, - tyFloat..tyFloat128, tyUInt..tyUInt64} # weird name because it contains tyFloat + tyFloat..tyFloat128, tyUInt..tyUInt64} ConstantDataTypes*: TTypeKinds = {tyArray, tySet, tyTuple, tySequence} - NilableTypes*: TTypeKinds = {tyPointer, tyCstring, tyRef, tyPtr, - tyProc, tyError} # TODO - PtrLikeKinds*: TTypeKinds = {tyPointer, tyPtr} # for VM + NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence, + tyProc, tyString, tyError} + ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType, + skIterator, + skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias} PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfDotSetter, nfDotField, - nfIsRef, nfIsPtr, nfPreventCg, nfLL, - nfFromTemplate, nfDefaultRefsParam, - nfExecuteOnReload, nfLastRead, - nfFirstWrite, nfUseDefaultField} + nfIsRef, nfPreventCg, nfLL, + nfFromTemplate, nfDefaultRefsParam} namePos* = 0 patternPos* = 1 # empty except for term rewriting macros genericParamsPos* = 2 @@ -1090,9 +987,7 @@ const miscPos* = 5 # used for undocumented and hacky stuff bodyPos* = 6 # position of body; use rodread.getBody() instead! resultPos* = 7 - dispatcherPos* = 8 - - nfAllFieldsSet* = nfBase2 + dispatcherPos* = 8 # caution: if method has no 'result' it can be position 7! nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit, nkHiddenCallConv} @@ -1104,9 +999,7 @@ const nkFloatLiterals* = {nkFloatLit..nkFloat128Lit} nkLambdaKinds* = {nkLambda, nkDo} declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef} - routineDefs* = declarativeDefs + {nkMacroDef, nkTemplateDef} procDefs* = nkLambdaKinds + declarativeDefs - callableDefs* = nkLambdaKinds + routineDefs nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice} nkStrKinds* = {nkStrLit..nkTripleStrLit} @@ -1115,92 +1008,36 @@ const skProcKinds* = {skProc, skFunc, skTemplate, skMacro, skIterator, skMethod, skConverter} - defaultSize = -1 - defaultAlignment = -1 - defaultOffset* = -1 - -proc getPIdent*(a: PNode): PIdent {.inline.} = - ## Returns underlying `PIdent` for `{nkSym, nkIdent}`, or `nil`. - # xxx consider whether also returning the 1st ident for {nkOpenSymChoice, nkClosedSymChoice} - # which may simplify code. - case a.kind - of nkSym: a.sym.name - of nkIdent: a.ident - else: nil - -const - moduleShift = when defined(cpu32): 20 else: 24 - -template id*(a: PIdObj): int = - let x = a - (x.itemId.module.int shl moduleShift) + x.itemId.item.int - -type - IdGenerator* = ref object # unfortunately, we really need the 'shared mutable' aspect here. - module*: int32 - symId*: int32 - typeId*: int32 - sealed*: bool - -const - PackageModuleId* = -3'i32 - -proc idGeneratorFromModule*(m: PSym): IdGenerator = - assert m.kind == skModule - result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0) - -proc nextSymId*(x: IdGenerator): ItemId {.inline.} = - assert(not x.sealed) - inc x.symId - result = ItemId(module: x.module, item: x.symId) - -proc nextTypeId*(x: IdGenerator): ItemId {.inline.} = - assert(not x.sealed) - inc x.typeId - result = ItemId(module: x.module, item: x.typeId) - -when false: - proc nextId*(x: IdGenerator): ItemId {.inline.} = - inc x.item - result = x[] - -when false: - proc storeBack*(dest: var IdGenerator; src: IdGenerator) {.inline.} = - assert dest.ItemId.module == src.ItemId.module - if dest.ItemId.item > src.ItemId.item: - echo dest.ItemId.item, " ", src.ItemId.item, " ", src.ItemId.module - assert dest.ItemId.item <= src.ItemId.item - dest = src - var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things +#var +# gMainPackageId*: int proc isCallExpr*(n: PNode): bool = result = n.kind in nkCallKinds proc discardSons*(father: PNode) -type Indexable = PNode | PType - -proc len*(n: Indexable): int {.inline.} = - result = n.sons.len +proc len*(n: PNode): int {.inline.} = + if isNil(n.sons): result = 0 + else: result = len(n.sons) proc safeLen*(n: PNode): int {.inline.} = ## works even for leaves. - if n.kind in {nkNone..nkNilLit}: result = 0 - else: result = n.len + if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0 + else: result = len(n.sons) proc safeArrLen*(n: PNode): int {.inline.} = ## works for array-like objects (strings passed as openArray in VM). - if n.kind in {nkStrLit..nkTripleStrLit}: result = n.strVal.len + if n.kind in {nkStrLit..nkTripleStrLit}:result = len(n.strVal) elif n.kind in {nkNone..nkFloat128Lit}: result = 0 - else: result = n.len + else: result = len(n) -proc add*(father, son: Indexable) = +proc add*(father, son: PNode) = assert son != nil - father.sons.add(son) + if isNil(father.sons): father.sons = @[] + add(father.sons, son) -proc addAllowNil*(father, son: Indexable) {.inline.} = - father.sons.add(son) +type Indexable = PNode | PType template `[]`*(n: Indexable, i: int): Indexable = n.sons[i] template `[]=`*(n: Indexable, i: int; x: Indexable) = n.sons[i] = x @@ -1208,77 +1045,17 @@ template `[]=`*(n: Indexable, i: int; x: Indexable) = n.sons[i] = x template `[]`*(n: Indexable, i: BackwardsIndex): Indexable = n[n.len - i.int] template `[]=`*(n: Indexable, i: BackwardsIndex; x: Indexable) = n[n.len - i.int] = x -proc getDeclPragma*(n: PNode): PNode = - ## return the `nkPragma` node for declaration `n`, or `nil` if no pragma was found. - ## Currently only supports routineDefs + {nkTypeDef}. - case n.kind - of routineDefs: - if n[pragmasPos].kind != nkEmpty: result = n[pragmasPos] - of nkTypeDef: - #[ - type F3*{.deprecated: "x3".} = int - - TypeSection - TypeDef - PragmaExpr - Postfix - Ident "*" - Ident "F3" - Pragma - ExprColonExpr - Ident "deprecated" - StrLit "x3" - Empty - Ident "int" - ]# - if n[0].kind == nkPragmaExpr: - result = n[0][1] - else: - # support as needed for `nkIdentDefs` etc. - result = nil - if result != nil: - assert result.kind == nkPragma, $(result.kind, n.kind) - -proc extractPragma*(s: PSym): PNode = - ## gets the pragma node of routine/type/var/let/const symbol `s` - if s.kind in routineKinds: - result = s.ast[pragmasPos] - elif s.kind in {skType, skVar, skLet, skConst}: - if s.ast != nil and s.ast.len > 0: - if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1: - # s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma] - result = s.ast[0][1] - assert result == nil or result.kind == nkPragma - -proc skipPragmaExpr*(n: PNode): PNode = - ## if pragma expr, give the node the pragmas are applied to, - ## otherwise give node itself - if n.kind == nkPragmaExpr: - result = n[0] - else: - result = n - -proc setInfoRecursive*(n: PNode, info: TLineInfo) = - ## set line info recursively - if n != nil: - for i in 0.. 0: - newSeq(result.sons, children) - setIdMaybe() - -proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = - ## new node with line info, type, and no children - result = newNode(kind) - result.info = info - result.typ = typ - proc newTree*(kind: TNodeKind; children: varargs[PNode]): PNode = result = newNode(kind) if children.len > 0: result.info = children[0].info result.sons = @children -proc newTreeI*(kind: TNodeKind; info: TLineInfo; children: varargs[PNode]): PNode = - result = newNodeI(kind, info) - if children.len > 0: - result.info = children[0].info - result.sons = @children - -proc newTreeIT*(kind: TNodeKind; info: TLineInfo; typ: PType; children: varargs[PNode]): PNode = - result = newNodeIT(kind, info, typ) - if children.len > 0: - result.info = children[0].info - result.sons = @children - template previouslyInferred*(t: PType): PType = if t.sons.len > 1: t.lastSon else: nil -when false: - import tables, strutils - var x: CountTable[string] - - addQuitProc proc () {.noconv.} = - for k, v in pairs(x): - echo k - echo v - -proc newSym*(symKind: TSymKind, name: PIdent, id: ItemId, owner: PSym, +proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym, info: TLineInfo; options: TOptions = {}): PSym = # generates a symbol and initializes the hash field too - result = PSym(name: name, kind: symKind, flags: {}, info: info, itemId: id, - options: options, owner: owner, offset: defaultOffset) - when false: - if id.module == 48 and id.item == 39: - writeStackTrace() - echo "kind ", symKind, " ", name.s - if owner != nil: echo owner.name.s - -proc astdef*(s: PSym): PNode = - # get only the definition (initializer) portion of the ast - if s.ast != nil and s.ast.kind in {nkIdentDefs, nkConstDef}: - s.ast[2] - else: - s.ast + new(result) + result.name = name + result.kind = symKind + result.flags = {} + result.info = info + result.options = options + result.owner = owner + result.offset = -1 + result.id = getID() + when debugIds: + registerId(result) + #if result.id == 93289: + # writeStacktrace() + # MessageOut(name.s & " has id: " & toString(result.id)) proc isMetaType*(t: PType): bool = return t.kind in tyMetaTypes or @@ -1399,21 +1132,24 @@ const # for all kind of hash tables: proc copyStrTable*(dest: var TStrTable, src: TStrTable) = dest.counter = src.counter - setLen(dest.data, src.data.len) - for i in 0..high(src.data): dest.data[i] = src.data[i] + if isNil(src.data): return + setLen(dest.data, len(src.data)) + for i in countup(0, high(src.data)): dest.data[i] = src.data[i] proc copyIdTable*(dest: var TIdTable, src: TIdTable) = dest.counter = src.counter - newSeq(dest.data, src.data.len) - for i in 0..high(src.data): dest.data[i] = src.data[i] + if isNil(src.data): return + newSeq(dest.data, len(src.data)) + for i in countup(0, high(src.data)): dest.data[i] = src.data[i] proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) = dest.counter = src.counter - setLen(dest.data, src.data.len) - for i in 0..high(src.data): dest.data[i] = src.data[i] + if isNil(src.data): return + setLen(dest.data, len(src.data)) + for i in countup(0, high(src.data)): dest.data[i] = src.data[i] proc discardSons*(father: PNode) = - father.sons = @[] + father.sons = nil proc withInfo*(n: PNode, info: TLineInfo): PNode = n.info = info @@ -1436,51 +1172,58 @@ proc newSymNode*(sym: PSym, info: TLineInfo): PNode = result.typ = sym.typ result.info = info +proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode = + new(result) + result.kind = kind + result.info = info + when defined(useNodeIds): + result.id = gNodeId + if result.id == nodeIdToDebug: + echo "KIND ", result.kind + writeStackTrace() + inc gNodeId + +proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode = + new(result) + result.kind = kind + result.info = info + if children > 0: + newSeq(result.sons, children) + when defined(useNodeIds): + result.id = gNodeId + if result.id == nodeIdToDebug: + echo "KIND ", result.kind + writeStackTrace() + inc gNodeId + +proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[], + typ: PType = nil): PNode = + new(result) + result.kind = kind + result.info = info + result.typ = typ + # XXX use shallowCopy here for ownership transfer: + result.sons = sons + when defined(useNodeIds): + result.id = gNodeId + if result.id == nodeIdToDebug: + echo "KIND ", result.kind + writeStackTrace() + inc gNodeId + +proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = + result = newNode(kind) + result.info = info + result.typ = typ + proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode = result = newNode(kind) result.intVal = intVal -proc newIntNode*(kind: TNodeKind, intVal: Int128): PNode = - result = newNode(kind) - result.intVal = castToInt64(intVal) - -proc lastSon*(n: Indexable): Indexable = n.sons[^1] - -proc skipTypes*(t: PType, kinds: TTypeKinds): PType = - ## Used throughout the compiler code to test whether a type tree contains or - ## doesn't contain a specific type/types - it is often the case that only the - ## last child nodes of a type tree need to be searched. This is a really hot - ## path within the compiler! - result = t - while result.kind in kinds: result = lastSon(result) - -proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode = - let kind = skipTypes(typ, abstractVarRange).kind - case kind - of tyInt: result = newNode(nkIntLit) - of tyInt8: result = newNode(nkInt8Lit) - of tyInt16: result = newNode(nkInt16Lit) - of tyInt32: result = newNode(nkInt32Lit) - of tyInt64: result = newNode(nkInt64Lit) - of tyChar: result = newNode(nkCharLit) - of tyUInt: result = newNode(nkUIntLit) - of tyUInt8: result = newNode(nkUInt8Lit) - of tyUInt16: result = newNode(nkUInt16Lit) - of tyUInt32: result = newNode(nkUInt32Lit) - of tyUInt64: result = newNode(nkUInt64Lit) - of tyBool, tyEnum: - # XXX: does this really need to be the kind nkIntLit? - result = newNode(nkIntLit) - of tyStatic: # that's a pre-existing bug, will fix in another PR - result = newNode(nkIntLit) - else: doAssert false, $kind - result.intVal = intVal +proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode = + result = newIntNode(kind, intVal) result.typ = typ -proc newIntTypeNode*(intVal: Int128, typ: PType): PNode = - # XXX: introduce range check - newIntTypeNode(castToInt64(intVal), typ) - proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode = result = newNode(kind) result.floatVal = floatVal @@ -1493,6 +1236,11 @@ proc newStrNode*(strVal: string; info: TLineInfo): PNode = result = newNodeI(nkStrLit, info) result.strVal = strVal +proc addSon*(father, son: PNode) = + assert son != nil + if isNil(father.sons): father.sons = @[] + add(father.sons, son) + proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode, params, name, pattern, genericParams, @@ -1502,34 +1250,54 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode, pragmas, exceptions, body] const - AttachedOpToStr*: array[TTypeAttachedOp, string] = [ - "=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy"] + UnspecifiedLockLevel* = TLockLevel(-1'i16) + MaxLockLevel* = 1000'i16 + UnknownLockLevel* = TLockLevel(1001'i16) -proc `$`*(s: PSym): string = - if s != nil: - result = s.name.s & "@" & $s.id - else: - result = "" +proc `$`*(x: TLockLevel): string = + if x.ord == UnspecifiedLockLevel.ord: result = "" + elif x.ord == UnknownLockLevel.ord: result = "" + else: result = $int16(x) -proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType = - result = PType(kind: kind, owner: owner, size: defaultSize, - align: defaultAlignment, itemId: id, - uniqueId: id) +proc newType*(kind: TTypeKind, owner: PSym): PType = + new(result) + result.kind = kind + result.owner = owner + result.size = - 1 + result.align = 2 # default alignment + result.id = getID() + result.lockLevel = UnspecifiedLockLevel + when debugIds: + registerId(result) when false: - if result.itemId.module == 55 and result.itemId.item == 2: + if result.id == 205734: echo "KNID ", kind writeStackTrace() - proc mergeLoc(a: var TLoc, b: TLoc) = - if a.k == low(typeof(a.k)): a.k = b.k - if a.storage == low(typeof(a.storage)): a.storage = b.storage - a.flags.incl b.flags + if a.k == low(a.k): a.k = b.k + if a.storage == low(a.storage): a.storage = b.storage + a.flags = a.flags + b.flags if a.lode == nil: a.lode = b.lode - if a.r == "": a.r = b.r + if a.r == nil: a.r = b.r -proc newSons*(father: Indexable, length: int) = - setLen(father.sons, length) +proc newSons*(father: PNode, length: int) = + if isNil(father.sons): + newSeq(father.sons, length) + else: + setLen(father.sons, length) + +proc newSons*(father: PType, length: int) = + if isNil(father.sons): + newSeq(father.sons, length) + else: + setLen(father.sons, length) + +proc sonsLen*(n: PType): int = n.sons.len +proc len*(n: PType): int = n.sons.len +proc sonsLen*(n: PNode): int = n.sons.len +proc lastSon*(n: PNode): PNode = n.sons[^1] +proc lastSon*(n: PType): PType = n.sons[^1] proc assignType*(dest, src: PType) = dest.kind = src.kind @@ -1538,52 +1306,67 @@ proc assignType*(dest, src: PType) = dest.n = src.n dest.size = src.size dest.align = src.align + dest.destructor = src.destructor + dest.deepCopy = src.deepCopy + dest.sink = src.sink + dest.assignment = src.assignment + dest.lockLevel = src.lockLevel # this fixes 'type TLock = TSysLock': if src.sym != nil: if dest.sym != nil: - dest.sym.flags.incl src.sym.flags-{sfUsed, sfExported} + dest.sym.flags = dest.sym.flags + (src.sym.flags-{sfExported}) if dest.sym.annex == nil: dest.sym.annex = src.sym.annex mergeLoc(dest.sym.loc, src.sym.loc) else: dest.sym = src.sym - newSons(dest, src.len) - for i in 0..= nkNone and n.kind <= nkNilLit proc isEmptyType*(t: PType): bool {.inline.} = - ## 'void' and 'typed' types are often equivalent to 'nil' these days: - result = t == nil or t.kind in {tyVoid, tyTyped} + ## 'void' and 'stmt' types are often equivalent to 'nil' these days: + result = t == nil or t.kind in {tyVoid, tyStmt} proc makeStmtList*(n: PNode): PNode = if n.kind == nkStmtList: @@ -1954,78 +1667,57 @@ proc makeStmtList*(n: PNode): PNode = proc skipStmtList*(n: PNode): PNode = if n.kind in {nkStmtList, nkStmtListExpr}: - for i in 0..` and - ## returned. Otherwise ``typ`` is simply returned as-is. - result = typ - if typ.kind != kind: - result = newType(kind, nextTypeId(idgen), typ.owner) - rawAddSon(result, typ) - -proc toRef*(typ: PType; idgen: IdGenerator): PType = +proc toRef*(typ: PType): PType = ## If ``typ`` is a tyObject then it is converted into a `ref ` and ## returned. Otherwise ``typ`` is simply returned as-is. result = typ - if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject: - result = newType(tyRef, nextTypeId(idgen), typ.owner) + if typ.kind == tyObject: + result = newType(tyRef, typ.owner) rawAddSon(result, typ) proc toObject*(typ: PType): PType = ## If ``typ`` is a tyRef then its immediate son is returned (which in many ## cases should be a ``tyObject``). ## Otherwise ``typ`` is simply returned as-is. - let t = typ.skipTypes({tyAlias, tyGenericInst}) - if t.kind == tyRef: t.lastSon - else: typ - -proc toObjectFromRefPtrGeneric*(typ: PType): PType = - #[ - See also `toObject`. - Finds the underlying `object`, even in cases like these: - type - B[T] = object f0: int - A1[T] = ref B[T] - A2[T] = ref object f1: int - A3 = ref object f2: int - A4 = object f3: int - ]# result = typ - while true: - case result.kind - of tyGenericBody: result = result.lastSon - of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0] - # automatic dereferencing is deep, refs #18298. - else: break - assert result.sym != nil + if result.kind == tyRef: + result = result.lastSon + +proc isException*(t: PType): bool = + # check if `y` is object type and it inherits from Exception + assert(t != nil) + + if t.kind != tyObject: + return false + + var base = t + while base != nil: + if base.sym != nil and base.sym.magic == mException: + return true + base = base.lastSon + return false proc isImportedException*(t: PType; conf: ConfigRef): bool = - assert t != nil - - if conf.exc != excCpp: + assert(t != nil) + if optNoCppExceptions in conf.globalOptions: return false let base = t.skipTypes({tyAlias, tyPtr, tyDistinct, tyGenericInst}) - if base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}: + if base.sym != nil and sfCompileToCpp in base.sym.flags: result = true proc isInfixAs*(n: PNode): bool = return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as" -proc skipColon*(n: PNode): PNode = - result = n - if n.kind == nkExprColonExpr: - result = n[1] - proc findUnresolvedStatic*(n: PNode): PNode = - # n.typ == nil: see issue #14802 - if n.kind == nkSym and n.typ != nil and n.typ.kind == tyStatic and n.typ.n == nil: + if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil: return n for son in n: @@ -2038,104 +1730,14 @@ when false: proc containsNil*(n: PNode): bool = # only for debugging if n.isNil: return true - for i in 0.. 0)) - -proc toHumanStrImpl[T](kind: T, num: static int): string = - result = $kind - result = result[num..^1] - result[0] = result[0].toLowerAscii - -proc toHumanStr*(kind: TSymKind): string = - ## strips leading `sk` - result = toHumanStrImpl(kind, 2) - -proc toHumanStr*(kind: TTypeKind): string = - ## strips leading `tk` - result = toHumanStrImpl(kind, 2) - -proc skipAddr*(n: PNode): PNode {.inline.} = - (if n.kind == nkHiddenAddr: n[0] else: n) - -proc isNewStyleConcept*(n: PNode): bool {.inline.} = - assert n.kind == nkTypeClassTy - result = n[0].kind == nkEmpty - -proc isOutParam*(t: PType): bool {.inline.} = tfIsOutParam in t.flags - -const - nodesToIgnoreSet* = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit, - nkTypeSection, nkProcDef, nkConverterDef, - nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, - nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt, - nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, - nkTypeOfExpr, nkMixinStmt, nkBindStmt} +template getBody*(s: PSym): PNode = s.ast[bodyPos] diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 4e09fab02..f474ca65e 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -12,14 +12,9 @@ # the data structures here are used in various places of the compiler. import - ast, hashes, intsets, options, lineinfos, ropes, idents, rodutils, + ast, hashes, intsets, strutils, options, lineinfos, ropes, idents, rodutils, msgs -import strutils except addf - -when defined(nimPreviewSlimSystem): - import std/assertions - proc hashNode*(p: RootRef): Hash proc treeToYaml*(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope # Convert a tree into its YAML representation; this is used by the @@ -29,55 +24,46 @@ proc typeToYaml*(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = proc symToYaml*(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): Rope +when declared(echo): + # these are for debugging only: They are not really deprecated, but I want + # the warning so that release versions do not contain debugging statements: + proc debug*(n: PSym; conf: ConfigRef = nil) {.deprecated.} + proc debug*(n: PType; conf: ConfigRef = nil) {.deprecated.} + proc debug*(n: PNode; conf: ConfigRef = nil) {.deprecated.} -# these are for debugging only: They are not really deprecated, but I want -# the warning so that release versions do not contain debugging statements: -proc debug*(n: PSym; conf: ConfigRef = nil) {.exportc: "debugSym", deprecated.} -proc debug*(n: PType; conf: ConfigRef = nil) {.exportc: "debugType", deprecated.} -proc debug*(n: PNode; conf: ConfigRef = nil) {.exportc: "debugNode", deprecated.} - -proc typekinds*(t: PType) {.deprecated.} = - var t = t - var s = "" - while t != nil and t.len > 0: - s.add $t.kind - s.add " " - t = t.lastSon - echo s - -template debug*(x: PSym|PType|PNode) {.deprecated.} = - when compiles(c.config): - debug(c.config, x) - elif compiles(c.graph.config): - debug(c.graph.config, x) - else: - error() - -template debug*(x: auto) {.deprecated.} = - echo x - -template mdbg*: bool {.deprecated.} = - when compiles(c.graph): - c.module.fileIdx == c.graph.config.projectMainIdx - elif compiles(c.module): - c.module.fileIdx == c.config.projectMainIdx - elif compiles(c.c.module): - c.c.module.fileIdx == c.c.config.projectMainIdx - elif compiles(m.c.module): - m.c.module.fileIdx == m.c.config.projectMainIdx - elif compiles(cl.c.module): - cl.c.module.fileIdx == cl.c.config.projectMainIdx - elif compiles(p): - when compiles(p.lex): - p.lex.fileIdx == p.lex.config.projectMainIdx + template debug*(x: PSym|PType|PNode) {.deprecated.} = + when compiles(c.config): + debug(c.config, x) + elif compiles(c.graph.config): + debug(c.graph.config, x) else: - p.module.module.fileIdx == p.config.projectMainIdx - elif compiles(m.module.fileIdx): - m.module.fileIdx == m.config.projectMainIdx - elif compiles(L.fileIdx): - L.fileIdx == L.config.projectMainIdx - else: - error() + error() + + template debug*(x: auto) {.deprecated.} = + echo x + + template mdbg*: bool {.deprecated.} = + when compiles(c.graph): + c.module.fileIdx == c.graph.config.projectMainIdx + elif compiles(c.module): + c.module.fileIdx == c.config.projectMainIdx + elif compiles(c.c.module): + c.c.module.fileIdx == c.c.config.projectMainIdx + elif compiles(m.c.module): + m.c.module.fileIdx == m.c.config.projectMainIdx + elif compiles(cl.c.module): + cl.c.module.fileIdx == cl.c.config.projectMainIdx + elif compiles(p): + when compiles(p.lex): + p.lex.fileIdx == p.lex.config.projectMainIdx + else: + p.module.module.fileIdx == p.config.projectMainIdx + elif compiles(m.module.fileIdx): + m.module.fileIdx == m.config.projectMainIdx + elif compiles(L.fileIdx): + L.fileIdx == L.config.projectMainIdx + else: + error() # --------------------------- ident tables ---------------------------------- proc idTableGet*(t: TIdTable, key: PIdObj): RootRef @@ -91,6 +77,7 @@ proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode) # --------------------------------------------------------------------------- +proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym proc lookupInRecord*(n: PNode, field: PIdent): PSym proc mustRehash*(length, counter: int): bool proc nextTry*(h, maxHash: Hash): Hash {.inline.} @@ -115,22 +102,22 @@ proc iiTablePut*(t: var TIITable, key, val: int) # implementation -proc skipConvCastAndClosure*(n: PNode): PNode = +proc skipConvAndClosure*(n: PNode): PNode = result = n while true: case result.kind of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64, nkClosure: - result = result[0] - of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast: - result = result[1] + result = result.sons[0] + of nkHiddenStdConv, nkHiddenSubConv, nkConv: + result = result.sons[1] else: break proc sameValue*(a, b: PNode): bool = result = false case a.kind of nkCharLit..nkUInt64Lit: - if b.kind in {nkCharLit..nkUInt64Lit}: result = getInt(a) == getInt(b) + if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal of nkFloatLit..nkFloat64Lit: if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal of nkStrLit..nkTripleStrLit: @@ -144,8 +131,8 @@ proc leValue*(a, b: PNode): bool = # a <= b? result = false case a.kind - of nkCharLit..nkUInt64Lit: - if b.kind in {nkCharLit..nkUInt64Lit}: result = getInt(a) <= getInt(b) + of nkCharLit..nkUInt32Lit: + if b.kind in {nkCharLit..nkUInt32Lit}: result = a.intVal <= b.intVal of nkFloatLit..nkFloat64Lit: if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal of nkStrLit..nkTripleStrLit: @@ -165,17 +152,17 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym = result = nil case n.kind of nkRecList: - for i in 0.. 0 and a[alen] != '`': dec(alen) - if alen <= 0: alen = a.len - - var i = 1 - var j = 1 - while true: - while i < alen and a[i] == '_': inc i - while j < b.len and b[j] == '_': inc j - var aa = if i < alen: toLowerAscii(a[i]) else: '\0' - var bb = if j < b.len: toLowerAscii(b[j]) else: '\0' - if aa != bb: return false - - # the characters are identical: - if i >= alen: - # both cursors at the end: - if j >= b.len: return true - # not yet at the end of 'b': - return false - elif j >= b.len: - return false - inc i - inc j - -proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym = - ## Named parameters are special because a named parameter can be - ## gensym'ed and then they have '\`' suffix that we need to - ## ignore, see compiler / evaltempl.nim, snippet: - ## ``` - ## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id), - ## if c.instLines: actual.info else: templ.info) - ## ``` - for i in 1.. 0: add(result, ",") + addf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]]) + inc(i, 2) + addf(result, "$N$1}", [rspaces(indent)]) + proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet, indent: int, maxRecDepth: int): Rope = if n == nil: result = rope("null") elif containsOrIncl(marker, n.id): - result = "\"$1\"" % [rope(n.name.s)] + result = "\"$1 @$2\"" % [rope(n.name.s), rope( + strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))] else: var ast = treeToYamlAux(conf, n.ast, marker, indent + 2, maxRecDepth - 1) - #rope("typ"), typeToYamlAux(conf, n.typ, marker, - # indent + 2, maxRecDepth - 1), - let istr = rspaces(indent + 2) - result = rope("{") - result.addf("$N$1\"kind\": $2", [istr, makeYamlString($n.kind)]) - result.addf("$N$1\"name\": $2", [istr, makeYamlString(n.name.s)]) - result.addf("$N$1\"typ\": $2", [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth - 1)]) - if conf != nil: - # if we don't pass the config, we probably don't care about the line info - result.addf("$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)]) - if card(n.flags) > 0: - result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)]) - result.addf("$N$1\"magic\": $2", [istr, makeYamlString($n.magic)]) - result.addf("$N$1\"ast\": $2", [istr, ast]) - result.addf("$N$1\"options\": $2", [istr, flagsToStr(n.options)]) - result.addf("$N$1\"position\": $2", [istr, rope(n.position)]) - result.addf("$N$1\"k\": $2", [istr, makeYamlString($n.loc.k)]) - result.addf("$N$1\"storage\": $2", [istr, makeYamlString($n.loc.storage)]) - if card(n.loc.flags) > 0: - result.addf("$N$1\"flags\": $2", [istr, makeYamlString($n.loc.flags)]) - result.addf("$N$1\"r\": $2", [istr, n.loc.r]) - result.addf("$N$1\"lode\": $2", [istr, treeToYamlAux(conf, n.loc.lode, marker, indent + 2, maxRecDepth - 1)]) - result.addf("$N$1}", [rspaces(indent)]) + result = ropeConstr(indent, [rope("kind"), + makeYamlString($n.kind), + rope("name"), makeYamlString(n.name.s), + rope("typ"), typeToYamlAux(conf, n.typ, marker, + indent + 2, maxRecDepth - 1), + rope("info"), lineInfoToStr(conf, n.info), + rope("flags"), flagsToStr(n.flags), + rope("magic"), makeYamlString($n.magic), + rope("ast"), ast, rope("options"), + flagsToStr(n.options), rope("position"), + rope(n.position)]) proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int, maxRecDepth: int): Rope = - var sonsRope: Rope if n == nil: - sonsRope = rope("null") + result = rope("null") elif containsOrIncl(marker, n.id): - sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope( - strutils.toHex(cast[int](n), sizeof(n) * 2))] + result = "\"$1 @$2\"" % [rope($n.kind), rope( + strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))] else: - if n.len > 0: - sonsRope = rope("[") - for i in 0.. 0: sonsRope.add(",") - sonsRope.addf("$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n[i], + if sonsLen(n) > 0: + result = rope("[") + for i in countup(0, sonsLen(n) - 1): + if i > 0: add(result, ",") + addf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(conf, n.sons[i], marker, indent + 4, maxRecDepth - 1)]) - sonsRope.addf("$N$1]", [rspaces(indent + 2)]) + addf(result, "$N$1]", [rspaces(indent + 2)]) else: - sonsRope = rope("null") - - let istr = rspaces(indent + 2) - result = rope("{") - result.addf("$N$1\"kind\": $2", [istr, makeYamlString($n.kind)]) - result.addf("$N$1\"sym\": $2", [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth - 1)]) - result.addf("$N$1\"n\": $2", [istr, treeToYamlAux(conf, n.n, marker, indent + 2, maxRecDepth - 1)]) - if card(n.flags) > 0: - result.addf("$N$1\"flags\": $2", [istr, flagsToStr(n.flags)]) - result.addf("$N$1\"callconv\": $2", [istr, makeYamlString($n.callConv)]) - result.addf("$N$1\"size\": $2", [istr, rope(n.size)]) - result.addf("$N$1\"align\": $2", [istr, rope(n.align)]) - result.addf("$N$1\"sons\": $2", [istr, sonsRope]) + result = rope("null") + result = ropeConstr(indent, [rope("kind"), + makeYamlString($n.kind), + rope("sym"), symToYamlAux(conf, n.sym, marker, + indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(conf, n.n, marker, + indent + 2, maxRecDepth - 1), rope("flags"), flagsToStr(n.flags), + rope("callconv"), + makeYamlString(CallingConvToStr[n.callConv]), + rope("size"), rope(n.size), + rope("align"), rope(n.align), + rope("sons"), result]) proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int, maxRecDepth: int): Rope = @@ -362,35 +306,37 @@ proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int, var istr = rspaces(indent + 2) result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)] if maxRecDepth != 0: - if conf != nil: - result.addf(",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)]) + addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)]) case n.kind of nkCharLit..nkInt64Lit: - result.addf(",$N$1\"intVal\": $2", [istr, rope(n.intVal)]) + addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)]) of nkFloatLit, nkFloat32Lit, nkFloat64Lit: - result.addf(",$N$1\"floatVal\": $2", + addf(result, ",$N$1\"floatVal\": $2", [istr, rope(n.floatVal.toStrMaxPrecision)]) of nkStrLit..nkTripleStrLit: - result.addf(",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) + if n.strVal.isNil: + addf(result, ",$N$1\"strVal\": null", [istr]) + else: + addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) of nkSym: - result.addf(",$N$1\"sym\": $2", + addf(result, ",$N$1\"sym\": $2", [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth)]) of nkIdent: if n.ident != nil: - result.addf(",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)]) + addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)]) else: - result.addf(",$N$1\"ident\": null", [istr]) + addf(result, ",$N$1\"ident\": null", [istr]) else: - if n.len > 0: - result.addf(",$N$1\"sons\": [", [istr]) - for i in 0.. 0: result.add(",") - result.addf("$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n[i], + if sonsLen(n) > 0: + addf(result, ",$N$1\"sons\": [", [istr]) + for i in countup(0, sonsLen(n) - 1): + if i > 0: add(result, ",") + addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(conf, n.sons[i], marker, indent + 4, maxRecDepth - 1)]) - result.addf("$N$1]", [istr]) - result.addf(",$N$1\"typ\": $2", + addf(result, "$N$1]", [istr]) + addf(result, ",$N$1\"typ\": $2", [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth)]) - result.addf("$N$1}", [rspaces(indent)]) + addf(result, "$N$1}", [rspaces(indent)]) proc treeToYaml(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope = var marker = initIntSet() @@ -404,268 +350,94 @@ proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1 var marker = initIntSet() result = symToYamlAux(conf, n, marker, indent, maxRecDepth) -import tables - -const backrefStyle = "\e[90m" -const enumStyle = "\e[34m" -const numberStyle = "\e[33m" -const stringStyle = "\e[32m" -const resetStyle = "\e[0m" - -type - DebugPrinter = object - conf: ConfigRef - visited: Table[pointer, int] - renderSymType: bool - indent: int - currentLine: int - firstItem: bool - useColor: bool - res: string - -proc indentMore(this: var DebugPrinter) = - this.indent += 2 - -proc indentLess(this: var DebugPrinter) = - this.indent -= 2 - -proc newlineAndIndent(this: var DebugPrinter) = - this.res.add "\n" - this.currentLine += 1 - for i in 0.." - if this.useColor: - this.res.add resetStyle - return + result = rope($n.kind) + if n.sym != nil: + add(result, " ") + add(result, n.sym.name.s) + if n.kind in IntegralTypes and n.n != nil: + add(result, ", node: ") + add(result, debugTree(conf, n.n, 2, maxRecDepth-1, renderType=true)) + if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0: + add(result, "(") + for i in countup(0, sonsLen(n) - 1): + if i > 0: add(result, ", ") + if n.sons[i] == nil: + add(result, "null") + else: + add(result, debugType(conf, n.sons[i], maxRecDepth-1)) + if n.kind == tyObject and n.n != nil: + add(result, ", node: ") + add(result, debugTree(conf, n.n, 2, maxRecDepth-1, renderType=true)) + add(result, ")") -proc value(this: var DebugPrinter; value: PType) -proc value(this: var DebugPrinter; value: PNode) -proc value(this: var DebugPrinter; value: PSym) = - earlyExit(this, value) - - this.openCurly - this.key("kind") - this.value(value.kind) - this.key("name") - this.value(value.name.s) - this.key("id") - this.value(value.id) - if value.kind in {skField, skEnumField, skParam}: - this.key("position") - this.value(value.position) - - if card(value.flags) > 0: - this.key("flags") - this.value(value.flags) - - if this.renderSymType and value.typ != nil: - this.key "typ" - this.value(value.typ) - - this.closeCurly - -proc value(this: var DebugPrinter; value: PType) = - earlyExit(this, value) - - this.openCurly - this.key "kind" - this.value value.kind - - this.key "id" - this.value value.id - - if value.sym != nil: - this.key "sym" - this.value value.sym - #this.value value.sym.name.s - - if card(value.flags) > 0: - this.key "flags" - this.value value.flags - - if value.kind in IntegralTypes and value.n != nil: - this.key "n" - this.value value.n - - if value.len > 0: - this.key "sons" - this.openBracket - for i in 0.. 0: - this.key "comment" - this.value value.comment - when defined(useNodeIds): - this.key "id" - this.value value.id - if this.conf != nil: - this.key "info" - this.value $lineInfoToStr(this.conf, value.info) - if value.flags != {}: - this.key "flags" - this.value value.flags - - if value.typ != nil: - this.key "typ" - this.value value.typ.kind +proc debugTree(conf: ConfigRef; n: PNode, indent: int, maxRecDepth: int; + renderType=false): Rope = + if n == nil: + result = rope("null") else: - this.key "typ" - this.value "nil" + var istr = rspaces(indent + 2) + result = "{$N$1\"kind\": $2" % + [istr, makeYamlString($n.kind)] + when defined(useNodeIds): + addf(result, ",$N$1\"id\": $2", [istr, rope(n.id)]) + addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(conf, 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)]) + of nkFloatLit, nkFloat32Lit, nkFloat64Lit: + addf(result, ",$N$1\"floatVal\": $2", + [istr, rope(n.floatVal.toStrMaxPrecision)]) + of nkStrLit..nkTripleStrLit: + if n.strVal.isNil: + addf(result, ",$N$1\"strVal\": null", [istr]) + else: + addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) + of nkSym: + addf(result, ",$N$1\"sym\": $2_$3", + [istr, rope(n.sym.name.s), rope(n.sym.id)]) + # [istr, symToYaml(n.sym, indent, maxRecDepth), + # rope(n.sym.id)]) + if renderType and n.sym.typ != nil: + addf(result, ",$N$1\"typ\": $2", [istr, debugType(conf, n.sym.typ, 2)]) + of nkIdent: + if n.ident != nil: + addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)]) + else: + addf(result, ",$N$1\"ident\": null", [istr]) + else: + if sonsLen(n) > 0: + addf(result, ",$N$1\"sons\": [", [istr]) + for i in countup(0, sonsLen(n) - 1): + if i > 0: add(result, ",") + addf(result, "$N$1$2", [rspaces(indent + 4), debugTree(conf, n.sons[i], + indent + 4, maxRecDepth - 1, renderType)]) + addf(result, "$N$1]", [istr]) + addf(result, "$N$1}", [rspaces(indent)]) - case value.kind - of nkCharLit..nkUInt64Lit: - this.key "intVal" - this.value value.intVal - of nkFloatLit, nkFloat32Lit, nkFloat64Lit: - this.key "floatVal" - this.value value.floatVal.toStrMaxPrecision - of nkStrLit..nkTripleStrLit: - this.key "strVal" - this.value value.strVal - of nkSym: - this.key "sym" - this.value value.sym - #this.value value.sym.name.s - of nkIdent: - if value.ident != nil: - this.key "ident" - this.value value.ident.s - else: - if this.renderSymType and value.typ != nil: - this.key "typ" - this.value value.typ - if value.len > 0: - this.key "sons" - this.openBracket - for i in 0..= 0: swap data[h], data[favPos] -proc symTabReplaceRaw(data: var seq[PSym], prevSym: PSym, newSym: PSym) = +proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) = assert prevSym.name.h == newSym.name.h var h: Hash = prevSym.name.h and high(data) while data[h] != nil: @@ -753,22 +542,21 @@ proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) = symTabReplaceRaw(t.data, prevSym, newSym) proc strTableEnlarge(t: var TStrTable) = - var n: seq[PSym] - newSeq(n, t.data.len * GrowthFactor) - for i in 0..high(t.data): + var n: TSymSeq + newSeq(n, len(t.data) * GrowthFactor) + for i in countup(0, high(t.data)): if t.data[i] != nil: strTableRawInsert(n, t.data[i]) swap(t.data, n) proc strTableAdd*(t: var TStrTable, n: PSym) = - if mustRehash(t.data.len, t.counter): strTableEnlarge(t) + if mustRehash(len(t.data), t.counter): strTableEnlarge(t) strTableRawInsert(t.data, n) inc(t.counter) -proc strTableInclReportConflict*(t: var TStrTable, n: PSym; - onConflictKeepOld = false): PSym = - # if `t` has a conflicting symbol (same identifier as `n`), return it - # otherwise return `nil`. Incl `n` to `t` unless `onConflictKeepOld = true` - # and a conflict was found. +proc strTableIncl*(t: var TStrTable, n: PSym; onConflictKeepOld=false): bool {.discardable.} = + # returns true if n is already in the string table: + # It is essential that `n` is written nevertheless! + # This way the newest redefinition is picked by the semantic analyses! assert n.name != nil var h: Hash = n.name.h and high(t.data) var replaceSlot = -1 @@ -780,26 +568,21 @@ proc strTableInclReportConflict*(t: var TStrTable, n: PSym; # So it is possible the very same sym is added multiple # times to the symbol table which we allow here with the 'it == n' check. if it.name.id == n.name.id: - if it == n: return nil + if it == n: return false replaceSlot = h h = nextTry(h, high(t.data)) if replaceSlot >= 0: - result = t.data[replaceSlot] # found it if not onConflictKeepOld: t.data[replaceSlot] = n # overwrite it with newer definition! - return result # but return the old one - elif mustRehash(t.data.len, t.counter): + return true # found it + elif mustRehash(len(t.data), t.counter): strTableEnlarge(t) strTableRawInsert(t.data, n) else: assert(t.data[h] == nil) t.data[h] = n inc(t.counter) - result = nil - -proc strTableIncl*(t: var TStrTable, n: PSym; - onConflictKeepOld = false): bool {.discardable.} = - result = strTableInclReportConflict(t, n, onConflictKeepOld) != nil + result = false proc strTableGet*(t: TStrTable, name: PIdent): PSym = var h: Hash = name.h and high(t.data) @@ -816,21 +599,16 @@ type name*: PIdent proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym = - # hot spots var h = ti.h and high(tab.data) var start = h - var p {.cursor.} = tab.data[h] - while p != nil: - if p.name.id == ti.name.id: break + result = tab.data[h] + while result != nil: + if result.name.id == ti.name.id: break h = nextTry(h, high(tab.data)) if h == start: - p = nil + result = nil break - p = tab.data[h] - if p != nil: - result = p # increase the count - else: - result = nil + result = tab.data[h] ti.h = nextTry(h, high(tab.data)) proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym = @@ -897,7 +675,7 @@ iterator items*(tab: TStrTable): PSym = s = nextIter(it, tab) proc hasEmptySlot(data: TIdPairSeq): bool = - for h in 0..high(data): + for h in countup(0, high(data)): if data[h].key == nil: return true result = false @@ -950,9 +728,9 @@ proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) = assert(t.data[index].key != nil) t.data[index].val = val else: - if mustRehash(t.data.len, t.counter): - newSeq(n, t.data.len * GrowthFactor) - for i in 0..high(t.data): + if mustRehash(len(t.data), t.counter): + newSeq(n, len(t.data) * GrowthFactor) + for i in countup(0, high(t.data)): if t.data[i].key != nil: idTableRawInsert(n, t.data[i].key, t.data[i].val) assert(hasEmptySlot(n)) @@ -961,7 +739,7 @@ proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) = inc(t.counter) iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] = - for i in 0..high(t.data): + for i in 0 .. high(t.data): if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val) proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int = @@ -979,6 +757,10 @@ proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode = if index >= 0: result = t.data[index].val else: result = nil +proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode = + if not isNil(t.data): + result = idNodeTableGet(t, key) + proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) = var h: Hash h = key.id and high(data) @@ -995,24 +777,28 @@ proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) = assert(t.data[index].key != nil) t.data[index].val = val else: - if mustRehash(t.data.len, t.counter): + if mustRehash(len(t.data), t.counter): var n: TIdNodePairSeq - newSeq(n, t.data.len * GrowthFactor) - for i in 0..high(t.data): + newSeq(n, len(t.data) * GrowthFactor) + for i in countup(0, high(t.data)): if t.data[i].key != nil: idNodeTableRawInsert(n, t.data[i].key, t.data[i].val) swap(t.data, n) idNodeTableRawInsert(t.data, key, val) inc(t.counter) +proc idNodeTablePutLazy*(t: var TIdNodeTable, key: PIdObj, val: PNode) = + if isNil(t.data): initIdNodeTable(t) + idNodeTablePut(t, key, val) + iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] = - for i in 0..high(t.data): + for i in 0 .. high(t.data): if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val) proc initIITable(x: var TIITable) = x.counter = 0 newSeq(x.data, StartSize) - for i in 0.. 0: - result.add ", " - result.add sym.name.s - -proc isDiscriminantField*(n: PNode): bool = - if n.kind == nkCheckedFieldExpr: sfDiscriminant in n[0][1].sym.flags - elif n.kind == nkDotExpr: sfDiscriminant in n[1].sym.flags - else: false diff --git a/compiler/astmsgs.nim b/compiler/astmsgs.nim deleted file mode 100644 index a9027126a..000000000 --- a/compiler/astmsgs.nim +++ /dev/null @@ -1,39 +0,0 @@ -# this module avoids ast depending on msgs or vice versa -import std/strutils -import options, ast, msgs - -proc typSym*(t: PType): PSym = - result = t.sym - if result == nil and t.kind == tyGenericInst: # this might need to be refined - result = t[0].sym - -proc addDeclaredLoc*(result: var string, conf: ConfigRef; sym: PSym) = - result.add " [$1 declared in $2]" % [sym.kind.toHumanStr, toFileLineCol(conf, sym.info)] - -proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; sym: PSym) = - if optDeclaredLocs in conf.globalOptions and sym != nil: - addDeclaredLoc(result, conf, sym) - -proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) = - # xxx figure out how to resolve `tyGenericParam`, e.g. for - # proc fn[T](a: T, b: T) = discard - # fn(1.1, "a") - let typ = typ.skipTypes(abstractInst + {tyStatic, tySequence, tyArray, tySet, tyUserTypeClassInst, tyVar, tyRef, tyPtr} - {tyRange}) - result.add " [$1" % typ.kind.toHumanStr - if typ.sym != nil: - result.add " declared in " & toFileLineCol(conf, typ.sym.info) - result.add "]" - -proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; typ: PType) = - if optDeclaredLocs in conf.globalOptions: addDeclaredLoc(result, conf, typ) - -template quoteExpr*(a: string): untyped = - ## can be used for quoting expressions in error msgs. - "'" & a & "'" - -proc genFieldDefect*(conf: ConfigRef, field: string, disc: PSym): string = - let obj = disc.owner.name.s # `types.typeToString` might be better, eg for generics - result = "field '$#' is not accessible for type '$#'" % [field, obj] - if optDeclaredLocs in conf.globalOptions: - result.add " [discriminant declared in $#]" % toFileLineCol(conf, disc.info) - result.add " using '$# = " % disc.name.s diff --git a/compiler/backendpragmas.nim b/compiler/backendpragmas.nim deleted file mode 100644 index b18644810..000000000 --- a/compiler/backendpragmas.nim +++ /dev/null @@ -1,25 +0,0 @@ -import pragmas, options, ast, trees - -proc pushBackendOption(optionsStack: var seq[TOptions], options: var TOptions) = - optionsStack.add options - -proc popBackendOption(optionsStack: var seq[TOptions], options: var TOptions) = - options = optionsStack[^1] - optionsStack.setLen(optionsStack.len-1) - -proc processPushBackendOption*(optionsStack: var seq[TOptions], options: var TOptions, - n: PNode, start: int) = - pushBackendOption(optionsStack, options) - for i in start..= 0) - x[int(elem.divElemSize)] = x[int(elem.divElemSize)] or - (One shl elem.modElemSize) + x[int(elem div ElemSize)] = x[int(elem div ElemSize)] or + toU8(int(1 shl (elem mod ElemSize))) -proc bitSetExcl*(x: var TBitSet, elem: BiggestInt) = - x[int(elem.divElemSize)] = x[int(elem.divElemSize)] and - not(One shl elem.modElemSize) +proc bitSetExcl(x: var TBitSet, elem: BiggestInt) = + x[int(elem div ElemSize)] = x[int(elem div ElemSize)] and + not toU8(int(1 shl (elem mod ElemSize))) -proc bitSetInit*(b: var TBitSet, length: int) = +proc bitSetInit(b: var TBitSet, length: int) = newSeq(b, length) -proc bitSetUnion*(x: var TBitSet, y: TBitSet) = - for i in 0..high(x): x[i] = x[i] or y[i] +proc bitSetUnion(x: var TBitSet, y: TBitSet) = + for i in countup(0, high(x)): x[i] = x[i] or y[i] -proc bitSetDiff*(x: var TBitSet, y: TBitSet) = - for i in 0..high(x): x[i] = x[i] and not y[i] +proc bitSetDiff(x: var TBitSet, y: TBitSet) = + for i in countup(0, high(x)): x[i] = x[i] and not y[i] -proc bitSetSymDiff*(x: var TBitSet, y: TBitSet) = - for i in 0..high(x): x[i] = x[i] xor y[i] +proc bitSetSymDiff(x: var TBitSet, y: TBitSet) = + for i in countup(0, high(x)): x[i] = x[i] xor y[i] -proc bitSetIntersect*(x: var TBitSet, y: TBitSet) = - for i in 0..high(x): x[i] = x[i] and y[i] +proc bitSetIntersect(x: var TBitSet, y: TBitSet) = + for i in countup(0, high(x)): x[i] = x[i] and y[i] -proc bitSetEquals*(x, y: TBitSet): bool = - for i in 0..high(x): +proc bitSetEquals(x, y: TBitSet): bool = + for i in countup(0, high(x)): if x[i] != y[i]: return false result = true -proc bitSetContains*(x, y: TBitSet): bool = - for i in 0..high(x): - if (x[i] and not y[i]) != Zero: +proc bitSetContains(x, y: TBitSet): bool = + for i in countup(0, high(x)): + if (x[i] and not y[i]) != int8(0): return false result = true # Number of set bits for all values of int8 -const populationCount: array[uint8, uint8] = block: - var arr: array[uint8, uint8] +const populationCount: array[low(int8)..high(int8), int8] = block: + var arr: array[low(int8)..high(int8), int8] - proc countSetBits(x: uint8): uint8 = + proc countSetBits(x: int8): int8 = return - ( x and 0b00000001'u8) + - ((x and 0b00000010'u8) shr 1) + - ((x and 0b00000100'u8) shr 2) + - ((x and 0b00001000'u8) shr 3) + - ((x and 0b00010000'u8) shr 4) + - ((x and 0b00100000'u8) shr 5) + - ((x and 0b01000000'u8) shr 6) + - ((x and 0b10000000'u8) shr 7) + ( x and 0b00000001'i8) + + ((x and 0b00000010'i8) shr 1) + + ((x and 0b00000100'i8) shr 2) + + ((x and 0b00001000'i8) shr 3) + + ((x and 0b00010000'i8) shr 4) + + ((x and 0b00100000'i8) shr 5) + + ((x and 0b01000000'i8) shr 6) + + ((x and 0b10000000'i8) shr 7) + - - for it in low(uint8)..high(uint8): - arr[it] = countSetBits(cast[uint8](it)) + for it in low(int8)..high(int8): + arr[it] = countSetBits(it) arr -proc bitSetCard*(x: TBitSet): BiggestInt = +proc bitSetCard(x: TBitSet): BiggestInt = for it in x: - result.inc int(populationCount[it]) + result.inc populationCount[it] diff --git a/compiler/btrees.nim b/compiler/btrees.nim index c79442249..6cd6e51f4 100644 --- a/compiler/btrees.nim +++ b/compiler/btrees.nim @@ -10,16 +10,13 @@ ## BTree implementation with few features, but good enough for the ## Nim compiler's needs. -when defined(nimPreviewSlimSystem): - import std/assertions - const M = 512 # max children per B-tree node = M-1 # (must be even and greater than 2) Mhalf = M div 2 type - Node[Key, Val] {.acyclic.} = ref object + Node[Key, Val] = ref object entries: int keys: array[M, Key] case isInternal: bool @@ -40,38 +37,35 @@ template eq(a, b): bool = cmp(a, b) == 0 proc getOrDefault*[Key, Val](b: BTree[Key, Val], key: Key): Val = var x = b.root while x.isInternal: - for j in 0..') + +proc encodeType(w: PRodWriter, t: PType, result: var string) = + if t == nil: + # nil nodes have to be stored too: + result.add("[]") + return + # we need no surrounding [] here because the type is in a line of its own + if t.kind == tyForward: internalError("encodeType: tyForward") + # for the new rodfile viewer we use a preceding [ so that the data section + # can easily be disambiguated: + add(result, '[') + encodeVInt(ord(t.kind), result) + add(result, '+') + encodeVInt(t.id, result) + if t.n != nil: + encodeNode(w, unknownLineInfo(), t.n, result) + if t.flags != {}: + add(result, '$') + encodeVInt(cast[int32](t.flags), result) + if t.callConv != low(t.callConv): + add(result, '?') + encodeVInt(ord(t.callConv), result) + if t.owner != nil: + add(result, '*') + encodeVInt(t.owner.id, result) + pushSym(w, t.owner) + if t.sym != nil: + add(result, '&') + encodeVInt(t.sym.id, result) + pushSym(w, t.sym) + if t.size != - 1: + add(result, '/') + encodeVBiggestInt(t.size, result) + if t.align != 2: + add(result, '=') + encodeVInt(t.align, result) + encodeLoc(w, t.loc, result) + for i in countup(0, sonsLen(t) - 1): + if t.sons[i] == nil: + add(result, "^()") + else: + add(result, '^') + encodeVInt(t.sons[i].id, result) + pushType(w, t.sons[i]) + +proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) = + add(result, '|') + encodeVInt(ord(lib.kind), result) + add(result, '|') + encodeStr($lib.name, result) + add(result, '|') + encodeNode(w, info, lib.path, result) + +proc encodeSym(w: PRodWriter, s: PSym, result: var string) = + if s == nil: + # nil nodes have to be stored too: + result.add("{}") + return + # we need no surrounding {} here because the symbol is in a line of its own + encodeVInt(ord(s.kind), result) + result.add('+') + encodeVInt(s.id, result) + result.add('&') + encodeStr(s.name.s, result) + if s.typ != nil: + result.add('^') + encodeVInt(s.typ.id, result) + pushType(w, s.typ) + result.add('?') + if s.info.col != -1'i16: encodeVInt(s.info.col, result) + result.add(',') + if s.info.line != -1'i16: encodeVInt(s.info.line, result) + result.add(',') + encodeVInt(fileIdx(w, toFilename(s.info)), result) + if s.owner != nil: + result.add('*') + encodeVInt(s.owner.id, result) + pushSym(w, s.owner) + if s.flags != {}: + result.add('$') + encodeVInt(cast[int32](s.flags), result) + if s.magic != mNone: + result.add('@') + encodeVInt(ord(s.magic), result) + if s.options != w.options: + result.add('!') + encodeVInt(cast[int32](s.options), result) + if s.position != 0: + result.add('%') + encodeVInt(s.position, result) + if s.offset != - 1: + result.add('`') + encodeVInt(s.offset, result) + encodeLoc(w, s.loc, result) + if s.annex != nil: encodeLib(w, s.annex, s.info, result) + if s.constraint != nil: + add(result, '#') + encodeNode(w, unknownLineInfo(), s.constraint, result) + # lazy loading will soon reload the ast lazily, so the ast needs to be + # the last entry of a symbol: + if s.ast != nil: + # we used to attempt to save space here by only storing a dummy AST if + # it is not necessary, but Nim's heavy compile-time evaluation features + # make that unfeasible nowadays: + encodeNode(w, s.info, s.ast, result) + + +proc createDb() = + db.exec(sql""" + create table if not exists Module( + id integer primary key, + name varchar(256) not null, + fullpath varchar(256) not null, + interfHash varchar(256) not null, + fullHash varchar(256) not null, + + created timestamp not null default (DATETIME('now')) + );""") + + db.exec(sql""" + create table if not exists Backend( + id integer primary key, + strongdeps varchar(max) not null, + weakdeps varchar(max) not null, + header varchar(max) not null, + code varchar(max) not null + ) + + create table if not exists Symbol( + id integer primary key, + module integer not null, + backend integer not null, + name varchar(max) not null, + data varchar(max) not null, + created timestamp not null default (DATETIME('now')), + + foreign key (module) references Module(id), + foreign key (backend) references Backend(id) + );""") + + db.exec(sql""" + create table if not exists Type( + id integer primary key, + module integer not null, + name varchar(max) not null, + data varchar(max) not null, + created timestamp not null default (DATETIME('now')), + + foreign key (module) references module(id) + );""") + + diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 48e7fd290..2f9cc822b 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -9,531 +9,273 @@ # # included from cgen.nim -proc canRaiseDisp(p: BProc; n: PNode): bool = - # we assume things like sysFatal cannot raise themselves - if n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}: - result = false - elif optPanics in p.config.globalOptions or - (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags and - sfSystemRaisesDefect notin n.sym.flags): - # we know we can be strict: - result = canRaise(n) - else: - # we have to be *very* conservative: - result = canRaiseConservative(n) - -proc preventNrvo(p: BProc; dest, le, ri: PNode): bool = - proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool = - var n = le - while true: - # do NOT follow nkHiddenDeref here! - case n.kind - of nkSym: - # we don't own the location so it escapes: - if n.sym.owner != p.prc: - return true - elif inTryStmt and sfUsedInFinallyOrExcept in n.sym.flags: - # it is also an observable store if the location is used - # in 'except' or 'finally' - return true - return false - of nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv, - nkCheckedFieldExpr: - n = n[0] - of nkHiddenStdConv, nkHiddenSubConv, nkConv: - n = n[1] - else: - # cannot analyse the location; assume the worst - return true - +proc leftAppearsOnRightSide(le, ri: PNode): bool = if le != nil: - for i in 1.. 0): - message(p.config, le.info, warnObservableStores, $le) - # bug #19613 prevent dangerous aliasing too: - if dest != nil and dest != le: - for i in 1.. 0: - skipped = true - q = q.lastSon + let q = skipConv(n) if getMagic(q) == mSlice: # magic: pass slice to openArray: - if skipped: - q = skipConv(n) - while q.kind == nkStmtListExpr and q.len > 0: - for i in 0..Field0, $1->Field1" % [rdLoc(a)] - else: - result.add "$1.Field0, $1.Field1" % [rdLoc(a)] - else: - result.add "$1, $1Len_0" % [rdLoc(a)] - of tyString, tySequence: - let ntyp = skipTypes(n.typ, abstractInst) - if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and - optSeqDestructors in p.config.globalOptions: - linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - if ntyp.kind in {tyVar} and not compileToCpp(p.module): - var t: TLoc - t.r = "(*$1)" % [a.rdLoc] - result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" % - [a.rdLoc, lenExpr(p, t), dataField(p), - dataFieldAccessor(p, "*" & a.rdLoc)] - else: - result.add "($4) ? ($1$3) : NIM_NIL, $2" % - [a.rdLoc, lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)] + var b, c: TLoc + initLocExpr(p, q[1], a) + initLocExpr(p, q[2], b) + initLocExpr(p, q[3], c) + # but first produce the required index checks: + if optBoundsCheck in p.options: + genBoundsCheck(p, a, b, c) + let ty = skipTypes(a.t, abstractVar+{tyPtr}) + case ty.kind of tyArray: - result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))] + let first = firstOrd(p.config, ty) + if first == 0: + result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)] + else: + result = "($1)+(($2)-($4)), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first)] + of tyOpenArray, tyVarargs: + result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)] + of tyString, tySequence: + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): + result = "(*$1)->data+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)] + else: + result = "$1->data+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)] + else: + internalError(p.config, "openArrayLoc: " & typeToString(a.t)) + else: + initLocExpr(p, n, a) + case skipTypes(a.t, abstractVar).kind + of tyOpenArray, tyVarargs: + result = "$1, $1Len_0" % [rdLoc(a)] + of tyString, tySequence: + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): + result = "(*$1)->data, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p)] + else: + result = "$1->data, ($1 ? $1->$2 : 0)" % [a.rdLoc, lenField(p)] + of tyArray: + result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))] of tyPtr, tyRef: case lastSon(a.t).kind of tyString, tySequence: - var t: TLoc - t.r = "(*$1)" % [a.rdLoc] - result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" % - [a.rdLoc, lenExpr(p, t), dataField(p), - dataFieldAccessor(p, "*" & a.rdLoc)] + result = "(*$1)->data, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p)] of tyArray: - result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))] + result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))] else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) -proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc = - # Bug https://github.com/status-im/nimbus-eth2/issues/1549 - # Aliasing is preferred over stack overflows. - # Also don't regress for non ARC-builds, too risky. - if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcOrc} and - getSize(p.config, a.lode.typ) < 1024: - getTemp(p, a.lode.typ, result, needsInit=false) - genAssignment(p, result, a, {}) - else: - result = a - -proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc = - getTemp(p, a.lode.typ, result, needsInit=false) - genAssignment(p, result, a, {}) - -proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} = +proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} = var a: TLoc - initLocExpr(p, n[0], a) - appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc]) + initLocExpr(p, n.sons[0], a) + result = "($1 ? $1->data : (NCSTRING)\"\")" % [a.rdLoc] -proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) = +proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope = var a: TLoc if n.kind == nkStringToCString: - genArgStringToCString(p, n, result, needsTmp) + result = genArgStringToCString(p, n) elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: - var n = if n.kind != nkHiddenAddr: n else: n[0] - openArrayLoc(p, param.typ, n, result) - elif ccgIntroducedPtr(p.config, param, call[0].typ[0]): + var n = if n.kind != nkHiddenAddr: n else: n.sons[0] + result = openArrayLoc(p, n) + elif ccgIntroducedPtr(p.config, param): initLocExpr(p, n, a) - if n.kind in {nkCharLit..nkNilLit}: - addAddrLoc(p.config, literalsNeedsTmp(p, a), result) - else: - addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result) - elif p.module.compileToCpp and param.typ.kind in {tyVar} and + result = addrLoc(p.config, a) + elif p.module.compileToCpp and param.typ.kind == tyVar and n.kind == nkHiddenAddr: - initLocExprSingleUse(p, n[0], a) + initLocExprSingleUse(p, n.sons[0], a) # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still # means '*T'. See posix.nim for lots of examples that do that in the wild. - let callee = call[0] + let callee = call.sons[0] if callee.kind == nkSym and - {sfImportc, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportc} and + {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}: - addAddrLoc(p.config, a, result) + result = addrLoc(p.config, a) else: - addRdLoc(a, result) + result = rdLoc(a) else: initLocExprSingleUse(p, n, a) - addRdLoc(withTmpIfNeeded(p, a, needsTmp), result) - #assert result != nil + result = rdLoc(a) -proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) = +proc genArgNoParam(p: BProc, n: PNode): Rope = var a: TLoc if n.kind == nkStringToCString: - genArgStringToCString(p, n, result, needsTmp) + result = genArgStringToCString(p, n) else: initLocExprSingleUse(p, n, a) - addRdLoc(withTmpIfNeeded(p, a, needsTmp), result) + result = rdLoc(a) -import aliasanalysis - -proc potentialAlias(n: PNode, potentialWrites: seq[PNode]): bool = - for p in potentialWrites: - if p.aliases(n) != no or n.aliases(p) != no: - return true - -proc skipTrivialIndirections(n: PNode): PNode = - result = n - while true: - case result.kind - of nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr, nkObjDownConv, nkObjUpConv: - result = result[0] - of nkHiddenStdConv, nkHiddenSubConv: - result = result[1] - else: break - -proc getPotentialWrites(n: PNode; mutate: bool; result: var seq[PNode]) = - case n.kind: - of nkLiterals, nkIdent, nkFormalParams: discard - of nkSym: - if mutate: result.add n - of nkAsgn, nkFastAsgn, nkSinkAsgn: - getPotentialWrites(n[0], true, result) - getPotentialWrites(n[1], mutate, result) - of nkAddr, nkHiddenAddr: - getPotentialWrites(n[0], true, result) - of nkBracketExpr, nkDotExpr, nkCheckedFieldExpr: - getPotentialWrites(n[0], mutate, result) - of nkCallKinds: - case n.getMagic: - of mIncl, mExcl, mInc, mDec, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mAddr, mNew, mNewFinalize, mWasMoved, mDestroy, mReset: - getPotentialWrites(n[1], true, result) - for i in 2.. 1: pl.add(", ") + let rawProc = getRawProcType(p, typ) + let callPattern = if tfIterator in typ.flags: PatIter else: PatProc + if typ.sons[0] != nil: + if isInvalidReturnType(p.config, typ.sons[0]): + if sonsLen(ri) > 1: add(pl, ~", ") # beware of 'result = p(result)'. We may need to allocate a temporary: - if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri): + if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri): # Great, we can use 'd': if d.k == locNone: - getTemp(p, typ[0], d, needsInit=true) + getTemp(p, typ.sons[0], d, needsInit=true) elif d.k notin {locTemp} and not hasNoInit(ri): # reset before pass as 'result' var: discard "resetLoc(p, d)" - pl.add(addrLoc(p.config, d)) + add(pl, addrLoc(p.config, d)) genCallPattern() else: var tmp: TLoc - getTemp(p, typ[0], tmp, needsInit=true) - pl.add(addrLoc(p.config, tmp)) + getTemp(p, typ.sons[0], tmp, needsInit=true) + add(pl, addrLoc(p.config, tmp)) genCallPattern() - if canRaise: raiseExit(p) genAssignment(p, d, tmp, {}) # no need for deep copying - elif isHarmlessStore(p, canRaise, d): - if d.k == locNone: getTemp(p, typ[0], d) - assert(d.t != nil) # generate an assignment to d: - var list: TLoc - initLoc(list, locCall, d.lode, OnUnknown) - if tfIterator in typ.flags: - list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc] - else: - list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc] - genAssignment(p, d, list, {}) # no need for deep copying - if canRaise: raiseExit(p) else: - var tmp: TLoc - getTemp(p, typ[0], tmp) + if d.k == locNone: getTemp(p, typ.sons[0], d) assert(d.t != nil) # generate an assignment to d: var list: TLoc initLoc(list, locCall, d.lode, OnUnknown) - if tfIterator in typ.flags: - list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc] - else: - list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc] - genAssignment(p, tmp, list, {}) - if canRaise: raiseExit(p) - genAssignment(p, d, tmp, {}) + list.r = callPattern % [op.r, pl, pl.addComma, rawProc] + genAssignment(p, d, list, {}) # no need for deep copying else: genCallPattern() - if canRaise: raiseExit(p) -proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; - argsCounter: var int) = - if i < typ.len: +proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = + if i < sonsLen(typ): # 'var T' is 'T&' in C++. This means we ignore the request of # any nkHiddenAddr when it's a 'var T'. - let paramType = typ.n[i] + let paramType = typ.n.sons[i] assert(paramType.kind == nkSym) if paramType.typ.isCompileTimeOnly: - discard - elif typ[i].kind in {tyVar} and ri[i].kind == nkHiddenAddr: - if argsCounter > 0: result.add ", " - genArgNoParam(p, ri[i][0], result) - inc argsCounter + result = nil + elif typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr: + result = genArgNoParam(p, ri.sons[i][0]) else: - if argsCounter > 0: result.add ", " - genArgNoParam(p, ri[i], result) #, typ.n[i].sym) - inc argsCounter + result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym) else: if tfVarargs notin typ.flags: localError(p.config, ri.info, "wrong argument count") + result = nil else: - if argsCounter > 0: result.add ", " - genArgNoParam(p, ri[i], result) - inc argsCounter + result = genArgNoParam(p, ri.sons[i]) discard """ Dot call syntax in C++ @@ -577,99 +319,99 @@ proc skipAddrDeref(node: PNode): PNode = var isAddr = false case n.kind of nkAddr, nkHiddenAddr: - n = n[0] + n = n.sons[0] isAddr = true of nkDerefExpr, nkHiddenDeref: - n = n[0] + n = n.sons[0] else: return n - if n.kind == nkObjDownConv: n = n[0] + if n.kind == nkObjDownConv: n = n.sons[0] if isAddr and n.kind in {nkDerefExpr, nkHiddenDeref}: - result = n[0] + result = n.sons[0] elif n.kind in {nkAddr, nkHiddenAddr}: - result = n[0] + result = n.sons[0] else: result = node -proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope) = +proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = # for better or worse c2nim translates the 'this' argument to a 'var T'. # However manual wrappers may also use 'ptr T'. In any case we support both # for convenience. - internalAssert p.config, i < typ.len - assert(typ.n[i].kind == nkSym) + internalAssert p.config, i < sonsLen(typ) + assert(typ.n.sons[i].kind == nkSym) # if the parameter is lying (tyVar) and thus we required an additional deref, # skip the deref: var ri = ri[i] while ri.kind == nkObjDownConv: ri = ri[0] - let t = typ[i].skipTypes({tyGenericInst, tyAlias, tySink}) - if t.kind in {tyVar}: + let t = typ.sons[i].skipTypes({tyGenericInst, tyAlias, tySink}) + if t.kind == tyVar: let x = if ri.kind == nkHiddenAddr: ri[0] else: ri if x.typ.kind == tyPtr: - genArgNoParam(p, x, result) + result = genArgNoParam(p, x) result.add("->") elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr: - genArgNoParam(p, x[0], result) + result = genArgNoParam(p, x[0]) result.add("->") else: - genArgNoParam(p, x, result) + result = genArgNoParam(p, x) result.add(".") elif t.kind == tyPtr: if ri.kind in {nkAddr, nkHiddenAddr}: - genArgNoParam(p, ri[0], result) + result = genArgNoParam(p, ri[0]) result.add(".") else: - genArgNoParam(p, ri, result) + result = genArgNoParam(p, ri) result.add("->") else: ri = skipAddrDeref(ri) if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0] - genArgNoParam(p, ri, result) #, typ.n[i].sym) + result = genArgNoParam(p, ri) #, typ.n.sons[i].sym) result.add(".") -proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Rope) = +proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope = var i = 0 var j = 1 while i < pat.len: case pat[i] of '@': - var argsCounter = 0 - for k in j..= start: - result.add(substr(pat, start, i - 1)) + add(result, substr(pat, start, i - 1)) proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = var op: TLoc - initLocExpr(p, ri[0], op) + initLocExpr(p, ri.sons[0], op) # getUniqueType() is too expensive here: - var typ = skipTypes(ri[0].typ, abstractInst) + var typ = skipTypes(ri.sons[0].typ, abstractInst) assert(typ.kind == tyProc) - assert(typ.len == typ.n.len) + var length = sonsLen(ri) + assert(sonsLen(typ) == sonsLen(typ.n)) # don't call '$' here for efficiency: - let pat = $ri[0].sym.loc.r - internalAssert p.config, pat.len > 0 + let pat = ri.sons[0].sym.loc.r.data + internalAssert p.config, pat != nil if pat.contains({'#', '(', '@', '\''}): - var pl = newRopeAppender() - genPatternCall(p, ri, pat, typ, pl) + var pl = genPatternCall(p, ri, pat, typ) # simpler version of 'fixupCall' that works with the pl+params combination: - var typ = skipTypes(ri[0].typ, abstractInst) - if typ[0] != nil: + var typ = skipTypes(ri.sons[0].typ, abstractInst) + if typ.sons[0] != nil: if p.module.compileToCpp and lfSingleUse in d.flags: # do not generate spurious temporaries for C++! For C we're better off # with them to prevent undefined behaviour and because the codegen @@ -703,130 +445,116 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = d.r = pl excl d.flags, lfSingleUse else: - if d.k == locNone: getTemp(p, typ[0], d) + if d.k == locNone: getTemp(p, typ.sons[0], d) assert(d.t != nil) # generate an assignment to d: var list: TLoc initLoc(list, locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying else: - pl.add(";\n") + add(pl, ~";$n") line(p, cpsStmts, pl) else: - var pl = newRopeAppender() - var argsCounter = 0 + var pl: Rope = nil + #var param = typ.n.sons[1].sym if 1 < ri.len: - genThisArg(p, ri, 1, typ, pl) - pl.add(op.r) - var params = newRopeAppender() - for i in 2.. 0 + let pat = ri.sons[0].sym.loc.r.data + internalAssert p.config, pat != nil var start = 3 if ' ' in pat: start = 1 - pl.add(op.r) - if ri.len > 1: - pl.add(": ") - genArg(p, ri[1], typ.n[1].sym, ri, pl) + add(pl, op.r) + if length > 1: + add(pl, ~": ") + add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri)) start = 2 else: - if ri.len > 1: - genArg(p, ri[1], typ.n[1].sym, ri, pl) - pl.add(" ") - pl.add(op.r) - if ri.len > 2: - pl.add(": ") - genArg(p, ri[2], typ.n[2].sym, ri, pl) - for i in start..= typ.len: + if length > 1: + add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri)) + add(pl, ~" ") + add(pl, op.r) + if length > 2: + add(pl, ~": ") + add(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri)) + for i in countup(start, length-1): + assert(sonsLen(typ) == sonsLen(typ.n)) + if i >= sonsLen(typ): internalError(p.config, ri.info, "varargs for objective C method?") - assert(typ.n[i].kind == nkSym) - var param = typ.n[i].sym - pl.add(" ") - pl.add(param.name.s) - pl.add(": ") - genArg(p, ri[i], param, ri, pl) - if typ[0] != nil: - if isInvalidReturnType(p.config, typ): - if ri.len > 1: pl.add(" ") + assert(typ.n.sons[i].kind == nkSym) + var param = typ.n.sons[i].sym + add(pl, ~" ") + add(pl, param.name.s) + add(pl, ~": ") + add(pl, genArg(p, ri.sons[i], param, ri)) + if typ.sons[0] != nil: + if isInvalidReturnType(p.config, typ.sons[0]): + if sonsLen(ri) > 1: add(pl, ~" ") # beware of 'result = p(result)'. We always allocate a temporary: if d.k in {locTemp, locNone}: # We already got a temp. Great, special case it: - if d.k == locNone: getTemp(p, typ[0], d, needsInit=true) - pl.add("Result: ") - pl.add(addrLoc(p.config, d)) - pl.add("];\n") + if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true) + add(pl, ~"Result: ") + add(pl, addrLoc(p.config, d)) + add(pl, ~"];$n") line(p, cpsStmts, pl) else: var tmp: TLoc - getTemp(p, typ[0], tmp, needsInit=true) - pl.add(addrLoc(p.config, tmp)) - pl.add("];\n") + getTemp(p, typ.sons[0], tmp, needsInit=true) + add(pl, addrLoc(p.config, tmp)) + add(pl, ~"];$n") line(p, cpsStmts, pl) genAssignment(p, d, tmp, {}) # no need for deep copying else: - pl.add("]") - if d.k == locNone: getTemp(p, typ[0], d) + add(pl, ~"]") + if d.k == locNone: getTemp(p, typ.sons[0], d) assert(d.t != nil) # generate an assignment to d: var list: TLoc initLoc(list, locCall, ri, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying else: - pl.add("];\n") + add(pl, ~"];$n") line(p, cpsStmts, pl) -proc notYetAlive(n: PNode): bool {.inline.} = - let r = getRoot(n) - result = r != nil and r.loc.lode == nil - -proc isInactiveDestructorCall(p: BProc, e: PNode): bool = - #[ Consider this example. - - var :tmpD_3281815 - try: - if true: - return - let args_3280013 = - wasMoved_3281816(:tmpD_3281815) - `=_3280036`(:tmpD_3281815, [1]) - :tmpD_3281815 - finally: - `=destroy_3280027`(args_3280013) - - We want to return early but the 'finally' section is traversed before - the 'let args = ...' statement. We exploit this to generate better - code for 'return'. ]# - result = e.len == 2 and e[0].kind == nkSym and - e[0].sym.name.s == "=destroy" and notYetAlive(e[1].skipAddr) +proc genCall(p: BProc, e: PNode, d: var TLoc) = + if e.sons[0].typ.skipTypes({tyGenericInst, tyAlias, tySink}).callConv == ccClosure: + genClosureCall(p, nil, e, d) + elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags: + genInfixCall(p, nil, e, d) + elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags: + genNamedParamCall(p, e, d) + else: + genPrefixCall(p, nil, e, d) + postStmtActions(p) proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = - if p.withinBlockLeaveActions > 0 and isInactiveDestructorCall(p, ri): - return - if ri[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: + if ri.sons[0].typ.skipTypes({tyGenericInst, tyAlias, tySink}).callConv == ccClosure: genClosureCall(p, le, ri, d) - elif ri[0].kind == nkSym and sfInfixCall in ri[0].sym.flags: + elif ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags: genInfixCall(p, le, ri, d) - elif ri[0].kind == nkSym and sfNamedParamCall in ri[0].sym.flags: + elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags: genNamedParamCall(p, ri, d) else: genPrefixCall(p, le, ri, d) - -proc genCall(p: BProc, e: PNode, d: var TLoc) = genAsgnCall(p, nil, e, d) + postStmtActions(p) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a64a42219..56dd0dea2 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -9,153 +9,125 @@ # included from cgen.nim -when defined(nimCompilerStacktraceHints): - import std/stackframes - -proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode, - result: var Rope; count: var int; - isConst: bool, info: TLineInfo) - # -------------------------- constant expressions ------------------------ -proc rdSetElemLoc(conf: ConfigRef; a: TLoc, typ: PType; result: var Rope) - -proc int64Literal(i: BiggestInt; result: var Rope) = +proc int64Literal(i: BiggestInt): Rope = if i > low(int64): - result.add "IL64($1)" % [rope(i)] + result = "IL64($1)" % [rope(i)] else: - result.add "(IL64(-9223372036854775807) - IL64(1))" + result = ~"(IL64(-9223372036854775807) - IL64(1))" -proc uint64Literal(i: uint64; result: var Rope) = result.add rope($i & "ULL") +proc uint64Literal(i: uint64): Rope = rope($i & "ULL") -proc intLiteral(i: BiggestInt; result: var Rope) = +proc intLiteral(i: BiggestInt): Rope = if i > low(int32) and i <= high(int32): - result.add rope(i) + result = rope(i) elif i == low(int32): # Nim has the same bug for the same reasons :-) - result.add "(-2147483647 -1)" + result = ~"(-2147483647 -1)" elif i > low(int64): - result.add "IL64($1)" % [rope(i)] + result = "IL64($1)" % [rope(i)] else: - result.add "(IL64(-9223372036854775807) - IL64(1))" + result = ~"(IL64(-9223372036854775807) - IL64(1))" -proc intLiteral(i: Int128; result: var Rope) = - intLiteral(toInt64(i), result) - -proc genLiteral(p: BProc, n: PNode, ty: PType; result: var Rope) = +proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = + if ty == nil: internalError(p.config, n.info, "genLiteral: ty is nil") case n.kind of nkCharLit..nkUInt64Lit: - var k: TTypeKind - if ty != nil: - k = skipTypes(ty, abstractVarRange).kind - else: - case n.kind - of nkCharLit: k = tyChar - of nkUInt64Lit: k = tyUInt64 - of nkInt64Lit: k = tyInt64 - else: k = tyNil # don't go into the case variant that uses 'ty' - case k + case skipTypes(ty, abstractVarRange).kind of tyChar, tyNil: - intLiteral(n.intVal, result) + result = intLiteral(n.intVal) of tyBool: - if n.intVal != 0: result.add "NIM_TRUE" - else: result.add "NIM_FALSE" - of tyInt64: int64Literal(n.intVal, result) - of tyUInt64: uint64Literal(uint64(n.intVal), result) + if n.intVal != 0: result = ~"NIM_TRUE" + else: result = ~"NIM_FALSE" + of tyInt64: result = int64Literal(n.intVal) + of tyUInt64: result = uint64Literal(uint64(n.intVal)) else: - result.add "((" - result.add getTypeDesc(p.module, ty) - result.add ")" - intLiteral(n.intVal, result) - result.add ")" + result = "(($1) $2)" % [getTypeDesc(p.module, + ty), intLiteral(n.intVal)] of nkNilLit: - let k = if ty == nil: tyPointer else: skipTypes(ty, abstractVarRange).kind - if k == tyProc and skipTypes(ty, abstractVarRange).callConv == ccClosure: + let t = skipTypes(ty, abstractVarRange) + if t.kind == tyProc and t.callConv == ccClosure: let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) - let tmpName = p.module.tmpBase & rope(id) + result = p.module.tmpBase & rope(id) if id == p.module.labels: # not found in cache: inc(p.module.labels) - p.module.s[cfsStrData].addf( + addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n", - [getTypeDesc(p.module, ty), tmpName]) - result.add tmpName - elif k in {tyPointer, tyNil, tyProc}: - result.add rope("NIM_NIL") + [getTypeDesc(p.module, ty), result]) else: - result.add "(($1) NIM_NIL)" % [getTypeDesc(p.module, ty)] + result = rope("NIM_NIL") of nkStrLit..nkTripleStrLit: - let k = if ty == nil: tyString - else: skipTypes(ty, abstractVarRange + {tyStatic, tyUserTypeClass, tyUserTypeClassInst}).kind - case k + case skipTypes(ty, abstractVarRange + {tyStatic}).kind of tyNil: - genNilStringLiteral(p.module, n.info, result) + result = genNilStringLiteral(p.module, n.info) of tyString: - # with the new semantics for not 'nil' strings, we can map "" to nil and + # with the new semantics for 'nil' strings, we can map "" to nil and # save tons of allocations: - if n.strVal.len == 0 and optSeqDestructors notin p.config.globalOptions: - genNilStringLiteral(p.module, n.info, result) - else: - genStringLiteral(p.module, n, result) + #if n.strVal.len == 0: result = genNilStringLiteral(p.module, n.info) + #else: + result = genStringLiteral(p.module, n) else: - result.add makeCString(n.strVal) + if n.strVal.isNil: result = rope("NIM_NIL") + else: result = makeCString(n.strVal) of nkFloatLit, nkFloat64Lit: - if ty.kind == tyFloat32: - result.add rope(n.floatVal.float32.toStrMaxPrecision) - else: - result.add rope(n.floatVal.toStrMaxPrecision) + result = rope(n.floatVal.toStrMaxPrecision) of nkFloat32Lit: - result.add rope(n.floatVal.float32.toStrMaxPrecision) + result = rope(n.floatVal.toStrMaxPrecision("f")) else: internalError(p.config, n.info, "genLiteral(" & $n.kind & ')') + result = nil -proc genLiteral(p: BProc, n: PNode; result: var Rope) = - genLiteral(p, n, n.typ, result) +proc genLiteral(p: BProc, n: PNode): Rope = + result = genLiteral(p, n, n.typ) -proc bitSetToWord(s: TBitSet, size: int): BiggestUInt = +proc bitSetToWord(s: TBitSet, size: int): BiggestInt = result = 0 - for j in 0.. 8: - var res = "{\n" - for i in 0.. 8: + result = "{$n" % [] + for i in countup(0, size - 1): + if i < size - 1: + # not last iteration? + if (i + 1) mod 8 == 0: frmt = "0x$1,$n" + else: frmt = "0x$1, " + else: + frmt = "0x$1}$n" + addf(result, frmt, [rope(toHex(ze64(cs[i]), 2))]) + else: + result = intLiteral(bitSetToWord(cs, size)) + # result := rope('0x' + ToHex(bitSetToWord(cs, size), size * 2)) + +proc genSetNode(p: BProc, n: PNode): Rope = + var cs: TBitSet var size = int(getSize(p.config, n.typ)) - let cs = toBitSet(p.config, n) + toBitSet(p.config, n, cs) if size > 8: let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) - let tmpName = p.module.tmpBase & rope(id) + result = p.module.tmpBase & rope(id) if id == p.module.labels: # not found in cache: inc(p.module.labels) - p.module.s[cfsStrData].addf("static NIM_CONST $1 $2 = ", - [getTypeDesc(p.module, n.typ), tmpName]) - genRawSetData(cs, size, p.module.s[cfsStrData]) - p.module.s[cfsStrData].addf(";$n", []) - result.add tmpName + addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n", + [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)]) else: - genRawSetData(cs, size, result) + result = genRawSetData(cs, size) proc getStorageLoc(n: PNode): TStorageLoc = - ## deadcode case n.kind of nkSym: case n.sym.kind @@ -169,16 +141,16 @@ proc getStorageLoc(n: PNode): TStorageLoc = else: result = OnUnknown else: result = OnUnknown of nkDerefExpr, nkHiddenDeref: - case n[0].typ.kind + case n.sons[0].typ.kind of tyVar, tyLent: result = OnUnknown of tyPtr: result = OnStack of tyRef: result = OnHeap else: doAssert(false, "getStorageLoc") of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv: - result = getStorageLoc(n[0]) + result = getStorageLoc(n.sons[0]) else: result = OnUnknown -proc canMove(p: BProc, n: PNode; dest: TLoc): bool = +proc canMove(n: PNode): bool = # for now we're conservative here: if n.kind == nkBracket: # This needs to be kept consistent with 'const' seq code @@ -186,26 +158,40 @@ proc canMove(p: BProc, n: PNode; dest: TLoc): bool = if not isDeepConstExpr(n) or n.len == 0: if skipTypes(n.typ, abstractVarRange).kind == tySequence: return true - elif n.kind in nkStrKinds and n.strVal.len == 0: - # Empty strings are codegen'd as NIM_NIL so it's just a pointer copy - return true result = n.kind in nkCallKinds - #if not result and dest.k == locTemp: - # return true - #if result: # echo n.info, " optimized ", n # result = false -proc genRefAssign(p: BProc, dest, src: TLoc) = - if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config): - linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) +proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = + if dest.storage == OnStack or not usesNativeGC(p.config): + linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) elif dest.storage == OnHeap: - linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n", - [addrLoc(p.config, dest), rdLoc(src)]) + # location is on heap + # now the writer barrier is inlined for performance: + # + # if afSrcIsNotNil in flags: + # UseMagic(p.module, 'nimGCref') + # lineF(p, cpsStmts, 'nimGCref($1);$n', [rdLoc(src)]) + # elif afSrcIsNil notin flags: + # UseMagic(p.module, 'nimGCref') + # lineF(p, cpsStmts, 'if ($1) nimGCref($1);$n', [rdLoc(src)]) + # if afDestIsNotNil in flags: + # UseMagic(p.module, 'nimGCunref') + # lineF(p, cpsStmts, 'nimGCunref($1);$n', [rdLoc(dest)]) + # elif afDestIsNil notin flags: + # UseMagic(p.module, 'nimGCunref') + # lineF(p, cpsStmts, 'if ($1) nimGCunref($1);$n', [rdLoc(dest)]) + # lineF(p, cpsStmts, '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]) + if canFormAcycle(dest.t): + linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n", + addrLoc(p.config, dest), rdLoc(src)) + else: + linefmt(p, cpsStmts, "#asgnRefNoCycle((void**) $1, $2);$n", + addrLoc(p.config, dest), rdLoc(src)) else: linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", - [addrLoc(p.config, dest), rdLoc(src)]) + addrLoc(p.config, dest), rdLoc(src)) proc asgnComplexity(n: PNode): int = if n != nil: @@ -220,7 +206,7 @@ proc asgnComplexity(n: PNode): int = else: discard proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc = - assert field != "" + assert field != nil result.k = locField result.storage = a.storage result.lode = lodeTyp t @@ -235,8 +221,8 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: flags let t = skipTypes(dest.t, abstractInst).getUniqueType() - for i in 0.. $3){ #raiseOverflow(); ", - [result, first, last]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - result + linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n", + result, intLiteral(firstOrd(p.config, t)), intLiteral(lastOrd(p.config, t))) proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = const prc: array[mAddI..mPred, string] = [ - "nimAddInt", "nimSubInt", - "nimMulInt", "nimDivInt", "nimModInt", - "nimAddInt", "nimSubInt" - ] + "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n", + "$# = #mulInt($#, $#);$n", "$# = #divInt($#, $#);$n", + "$# = #modInt($#, $#);$n", + "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n"] prc64: array[mAddI..mPred, string] = [ - "nimAddInt64", "nimSubInt64", - "nimMulInt64", "nimDivInt64", "nimModInt64", - "nimAddInt64", "nimSubInt64" - ] - opr: array[mAddI..mPred, string] = ["+", "-", "*", "/", "%", "+", "-"] + "$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n", + "$# = #mulInt64($#, $#);$n", "$# = #divInt64($#, $#);$n", + "$# = #modInt64($#, $#);$n", + "$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n"] + opr: array[mAddI..mPred, string] = [ + "($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)", + "($#)($# / $#)", "($#)($# % $#)", + "($#)($# + $#)", "($#)($# - $#)"] var a, b: TLoc - assert(e[1].typ != nil) - assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + assert(e.sons[1].typ != nil) + assert(e.sons[2].typ != nil) + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) # skipping 'range' is correct here as we'll generate a proper range check # later via 'chckRange' let t = e.typ.skipTypes(abstractRange) if optOverflowCheck notin p.options: - let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)] + let res = opr[m] % [getTypeDesc(p.module, e.typ), rdLoc(a), rdLoc(b)] putIntoDest(p, d, e, res) else: - # we handle div by zero here so that we know that the compilerproc's - # result is only for overflows. - var needsOverflowCheck = true - if m in {mDivI, mModI}: - var canBeZero = true - if e[2].kind in {nkIntLit..nkUInt64Lit}: - canBeZero = e[2].intVal == 0 - if e[2].kind in {nkIntLit..nkInt64Lit}: - needsOverflowCheck = e[2].intVal == -1 - if canBeZero: - linefmt(p, cpsStmts, "if ($1 == 0){ #raiseDivByZero(); ", [rdLoc(b)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt(p, cpsStmts, "}$n", []) - if needsOverflowCheck: - let res = binaryArithOverflowRaw(p, t, a, b, - if t.kind == tyInt64: prc64[m] else: prc[m]) - putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res]) - else: - let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)] - putIntoDest(p, d, e, res) + let res = binaryArithOverflowRaw(p, t, a, b, + if t.kind == tyInt64: prc64[m] else: prc[m]) + putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res]) proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = + const + opr: array[mUnaryMinusI..mAbsI, string] = [ + mUnaryMinusI: "((NI$2)-($1))", + mUnaryMinusI64: "-($1)", + mAbsI: "($1 > 0? ($1) : -($1))"] var a: TLoc t: PType - assert(e[1].typ != nil) - initLocExpr(p, e[1], a) + assert(e.sons[1].typ != nil) + initLocExpr(p, e.sons[1], a) t = skipTypes(e.typ, abstractRange) if optOverflowCheck in p.options: - var first = newRopeAppender() - intLiteral(firstOrd(p.config, t), first) - linefmt(p, cpsStmts, "if ($1 == $2){ #raiseOverflow(); ", - [rdLoc(a), first]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - case m - of mUnaryMinusI: - putIntoDest(p, d, e, "((NI$2)-($1))" % [rdLoc(a), rope(getSize(p.config, t) * 8)]) - of mUnaryMinusI64: - putIntoDest(p, d, e, "-($1)" % [rdLoc(a)]) - of mAbsI: - putIntoDest(p, d, e, "($1 > 0? ($1) : -($1))" % [rdLoc(a)]) - else: - assert(false, $m) + linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n", + rdLoc(a), intLiteral(firstOrd(p.config, t))) + putIntoDest(p, d, e, opr[m] % [rdLoc(a), rope(getSize(p.config, t) * 8)]) proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = + const + binArithTab: array[mAddF64..mXor, string] = [ + "(($4)($1) + ($4)($2))", # AddF64 + "(($4)($1) - ($4)($2))", # SubF64 + "(($4)($1) * ($4)($2))", # MulF64 + "(($4)($1) / ($4)($2))", # DivF64 + + "($4)((NU$5)($1) >> (NU$3)($2))", # ShrI + "($4)((NU$3)($1) << (NU$3)($2))", # ShlI + "($4)($1 & $2)", # BitandI + "($4)($1 | $2)", # BitorI + "($4)($1 ^ $2)", # BitxorI + "(($1 <= $2) ? $1 : $2)", # MinI + "(($1 >= $2) ? $1 : $2)", # MaxI + "(($1 <= $2) ? $1 : $2)", # MinF64 + "(($1 >= $2) ? $1 : $2)", # MaxF64 + "($4)((NU$3)($1) + (NU$3)($2))", # AddU + "($4)((NU$3)($1) - (NU$3)($2))", # SubU + "($4)((NU$3)($1) * (NU$3)($2))", # MulU + "($4)((NU$3)($1) / (NU$3)($2))", # DivU + "($4)((NU$3)($1) % (NU$3)($2))", # ModU + "($1 == $2)", # EqI + "($1 <= $2)", # LeI + "($1 < $2)", # LtI + "($1 == $2)", # EqF64 + "($1 <= $2)", # LeF64 + "($1 < $2)", # LtF64 + "((NU$3)($1) <= (NU$3)($2))", # LeU + "((NU$3)($1) < (NU$3)($2))", # LtU + "((NU64)($1) <= (NU64)($2))", # LeU64 + "((NU64)($1) < (NU64)($2))", # LtU64 + "($1 == $2)", # EqEnum + "($1 <= $2)", # LeEnum + "($1 < $2)", # LtEnum + "((NU8)($1) == (NU8)($2))", # EqCh + "((NU8)($1) <= (NU8)($2))", # LeCh + "((NU8)($1) < (NU8)($2))", # LtCh + "($1 == $2)", # EqB + "($1 <= $2)", # LeB + "($1 < $2)", # LtB + "($1 == $2)", # EqRef + "($1 == $2)", # EqPtr + "($1 <= $2)", # LePtr + "($1 < $2)", # LtPtr + "($1 != $2)"] # Xor var a, b: TLoc s, k: BiggestInt - assert(e[1].typ != nil) - assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + assert(e.sons[1].typ != nil) + assert(e.sons[2].typ != nil) + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) # BUGFIX: cannot use result-type here, as it may be a boolean s = max(getSize(p.config, a.t), getSize(p.config, b.t)) * 8 k = getSize(p.config, a.t) * 8 - - template applyFormat(frmt: untyped) = - putIntoDest(p, d, e, frmt % [ - rdLoc(a), rdLoc(b), rope(s), - getSimpleTypeDesc(p.module, e.typ), rope(k)] - ) - - case op - of mAddF64: applyFormat("(($4)($1) + ($4)($2))") - of mSubF64: applyFormat("(($4)($1) - ($4)($2))") - of mMulF64: applyFormat("(($4)($1) * ($4)($2))") - of mDivF64: applyFormat("(($4)($1) / ($4)($2))") - of mShrI: applyFormat("($4)((NU$5)($1) >> (NU$3)($2))") - of mShlI: applyFormat("($4)((NU$3)($1) << (NU$3)($2))") - of mAshrI: applyFormat("($4)((NI$3)($1) >> (NU$3)($2))") - of mBitandI: applyFormat("($4)($1 & $2)") - of mBitorI: applyFormat("($4)($1 | $2)") - of mBitxorI: applyFormat("($4)($1 ^ $2)") - of mMinI: applyFormat("(($1 <= $2) ? $1 : $2)") - of mMaxI: applyFormat("(($1 >= $2) ? $1 : $2)") - of mAddU: applyFormat("($4)((NU$3)($1) + (NU$3)($2))") - of mSubU: applyFormat("($4)((NU$3)($1) - (NU$3)($2))") - of mMulU: applyFormat("($4)((NU$3)($1) * (NU$3)($2))") - of mDivU: applyFormat("($4)((NU$3)($1) / (NU$3)($2))") - of mModU: applyFormat("($4)((NU$3)($1) % (NU$3)($2))") - of mEqI: applyFormat("($1 == $2)") - of mLeI: applyFormat("($1 <= $2)") - of mLtI: applyFormat("($1 < $2)") - of mEqF64: applyFormat("($1 == $2)") - of mLeF64: applyFormat("($1 <= $2)") - of mLtF64: applyFormat("($1 < $2)") - of mLeU: applyFormat("((NU$3)($1) <= (NU$3)($2))") - of mLtU: applyFormat("((NU$3)($1) < (NU$3)($2))") - of mEqEnum: applyFormat("($1 == $2)") - of mLeEnum: applyFormat("($1 <= $2)") - of mLtEnum: applyFormat("($1 < $2)") - of mEqCh: applyFormat("((NU8)($1) == (NU8)($2))") - of mLeCh: applyFormat("((NU8)($1) <= (NU8)($2))") - of mLtCh: applyFormat("((NU8)($1) < (NU8)($2))") - of mEqB: applyFormat("($1 == $2)") - of mLeB: applyFormat("($1 <= $2)") - of mLtB: applyFormat("($1 < $2)") - of mEqRef: applyFormat("($1 == $2)") - of mLePtr: applyFormat("($1 <= $2)") - of mLtPtr: applyFormat("($1 < $2)") - of mXor: applyFormat("($1 != $2)") - else: - assert(false, $op) + putIntoDest(p, d, e, + binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s), + getSimpleTypeDesc(p.module, e.typ), rope(k)]) proc genEqProc(p: BProc, e: PNode, d: var TLoc) = var a, b: TLoc - assert(e[1].typ != nil) - assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) - if a.t.skipTypes(abstractInstOwned).callConv == ccClosure: + assert(e.sons[1].typ != nil) + assert(e.sons[2].typ != nil) + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + if a.t.skipTypes(abstractInst).callConv == ccClosure: putIntoDest(p, d, e, "($1.ClP_0 == $2.ClP_0 && $1.ClE_0 == $2.ClE_0)" % [rdLoc(a), rdLoc(b)]) else: putIntoDest(p, d, e, "($1 == $2)" % [rdLoc(a), rdLoc(b)]) proc genIsNil(p: BProc, e: PNode, d: var TLoc) = - let t = skipTypes(e[1].typ, abstractRange) + let t = skipTypes(e.sons[1].typ, abstractRange) if t.kind == tyProc and t.callConv == ccClosure: unaryExpr(p, e, d, "($1.ClP_0 == 0)") else: unaryExpr(p, e, d, "($1 == 0)") proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = + const + unArithTab: array[mNot..mToBiggestInt, string] = ["!($1)", # Not + "$1", # UnaryPlusI + "($3)((NU$2) ~($1))", # BitnotI + "$1", # UnaryPlusF64 + "-($1)", # UnaryMinusF64 + "($1 < 0? -($1) : ($1))", # AbsF64; BUGFIX: fabs() makes problems + # for Tiny C, so we don't use it + "(($3)(NU)(NU8)($1))", # mZe8ToI + "(($3)(NU64)(NU8)($1))", # mZe8ToI64 + "(($3)(NU)(NU16)($1))", # mZe16ToI + "(($3)(NU64)(NU16)($1))", # mZe16ToI64 + "(($3)(NU64)(NU32)($1))", # mZe32ToI64 + "(($3)(NU64)(NU)($1))", # mZeIToI64 + "(($3)(NU8)(NU)($1))", # ToU8 + "(($3)(NU16)(NU)($1))", # ToU16 + "(($3)(NU32)(NU64)($1))", # ToU32 + "((double) ($1))", # ToFloat + "((double) ($1))", # ToBiggestFloat + "float64ToInt32($1)", # ToInt + "float64ToInt64($1)"] # ToBiggestInt var a: TLoc t: PType - assert(e[1].typ != nil) - initLocExpr(p, e[1], a) + assert(e.sons[1].typ != nil) + initLocExpr(p, e.sons[1], a) t = skipTypes(e.typ, abstractRange) - - template applyFormat(frmt: untyped) = - putIntoDest(p, d, e, frmt % [rdLoc(a), rope(getSize(p.config, t) * 8), + putIntoDest(p, d, e, + unArithTab[op] % [rdLoc(a), rope(getSize(p.config, t) * 8), getSimpleTypeDesc(p.module, e.typ)]) - case op - of mNot: - applyFormat("!($1)") - of mUnaryPlusI: - applyFormat("$1") - of mBitnotI: - applyFormat("($3)((NU$2) ~($1))") - of mUnaryPlusF64: - applyFormat("$1") - of mUnaryMinusF64: - applyFormat("-($1)") - else: - assert false, $op proc isCppRef(p: BProc; typ: PType): bool {.inline.} = result = p.module.compileToCpp and - skipTypes(typ, abstractInstOwned).kind in {tyVar} and - tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags + skipTypes(typ, abstractInst).kind == tyVar and + tfVarIsPtr notin skipTypes(typ, abstractInst).flags -proc derefBlock(p: BProc, e: PNode, d: var TLoc) = - # We transform (block: x)[] to (block: x[]) - let e0 = e[0] - var n = shallowCopy(e0) - n.typ = e.typ - for i in 0 ..< e0.len - 1: - n[i] = e0[i] - n[e0.len-1] = newTreeIT(nkHiddenDeref, e.info, e.typ, e0[e0.len-1]) - expr p, n, d - -proc genDeref(p: BProc, e: PNode, d: var TLoc) = - if e.kind == nkHiddenDeref and e[0].kind in {nkBlockExpr, nkBlockStmt}: - # bug #20107. Watch out to not deref the pointer too late. - derefBlock(p, e, d) - return - - let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0])) - if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags: +proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = + let mt = mapType(p.config, e.sons[0].typ) + if mt in {ctArray, ctPtrToArray} and not enforceDeref: # XXX the amount of hacks for C's arrays is incredible, maybe we should # simply wrap them in a struct? --> Losing auto vectorization then? - expr(p, e[0], d) - if e[0].typ.skipTypes(abstractInstOwned).kind == tyRef: + #if e[0].kind != nkBracketExpr: + # message(e.info, warnUser, "CAME HERE " & renderTree(e)) + expr(p, e.sons[0], d) + if e.sons[0].typ.skipTypes(abstractInst).kind == tyRef: d.storage = OnHeap else: var a: TLoc - var typ = e[0].typ + var typ = e.sons[0].typ if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass: typ = typ.lastSon - typ = typ.skipTypes(abstractInstOwned) - if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr: + typ = typ.skipTypes(abstractInst) + if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e.sons[0].kind == nkHiddenAddr: initLocExprSingleUse(p, e[0][0], d) return else: - initLocExprSingleUse(p, e[0], a) + initLocExprSingleUse(p, e.sons[0], a) if d.k == locNone: # dest = *a; <-- We do not know that 'dest' is on the heap! # It is completely wrong to set 'd.storage' here, unless it's not yet @@ -804,51 +705,40 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = else: internalError(p.config, e.info, "genDeref " & $typ.kind) elif p.module.compileToCpp: - if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and + if typ.kind == tyVar and tfVarIsPtr notin typ.flags and e.kind == nkHiddenDeref: putIntoDest(p, d, e, rdLoc(a), a.storage) return - if mt == ctPtrToArray and lfEnforceDeref in d.flags: + if enforceDeref and mt == ctPtrToArray: # we lie about the type for better C interop: 'ptr array[3,T]' is # translated to 'ptr T', but for deref'ing this produces wrong code. # See tmissingderef. So we get rid of the deref instead. The codegen # ends up using 'memcpy' for the array assignment, # so the '&' and '*' cancel out: - putIntoDest(p, d, e, rdLoc(a), a.storage) + putIntoDest(p, d, lodeTyp(a.t.sons[0]), rdLoc(a), a.storage) else: putIntoDest(p, d, e, "(*$1)" % [rdLoc(a)], a.storage) -proc cowBracket(p: BProc; n: PNode) = - if n.kind == nkBracketExpr and optSeqDestructors in p.config.globalOptions: - let strCandidate = n[0] - if strCandidate.typ.skipTypes(abstractInst).kind == tyString: - var a: TLoc - initLocExpr(p, strCandidate, a) - linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - -proc cow(p: BProc; n: PNode) {.inline.} = - if n.kind == nkHiddenAddr: cowBracket(p, n[0]) - proc genAddr(p: BProc, e: PNode, d: var TLoc) = # careful 'addr(myptrToArray)' needs to get the ampersand: - if e[0].typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr}: + if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}: var a: TLoc - initLocExpr(p, e[0], a) + initLocExpr(p, e.sons[0], a) putIntoDest(p, d, e, "&" & a.r, a.storage) #Message(e.info, warnUser, "HERE NEW &") - elif mapType(p.config, e[0].typ, mapTypeChooser(e[0])) == ctArray or isCppRef(p, e.typ): - expr(p, e[0], d) + elif mapType(p.config, e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ): + expr(p, e.sons[0], d) else: var a: TLoc - initLocExpr(p, e[0], a) + initLocExpr(p, e.sons[0], a) putIntoDest(p, d, e, addrLoc(p.config, a), a.storage) template inheritLocation(d: var TLoc, a: TLoc) = if d.k == locNone: d.storage = a.storage proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc) = - initLocExpr(p, e[0], a) - if e[1].kind != nkSym: internalError(p.config, e.info, "genRecordFieldAux") + initLocExpr(p, e.sons[0], a) + if e.sons[1].kind != nkSym: internalError(p.config, e.info, "genRecordFieldAux") d.inheritLocation(a) discard getTypeDesc(p.module, a.t) # fill the record's fields.loc @@ -856,22 +746,22 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) = var a: TLoc i: int - initLocExpr(p, e[0], a) - let tupType = a.t.skipTypes(abstractInst+{tyVar}) + initLocExpr(p, e.sons[0], a) + let tupType = a.t.skipTypes(abstractInst) assert tupType.kind == tyTuple d.inheritLocation(a) discard getTypeDesc(p.module, a.t) # fill the record's fields.loc var r = rdLoc(a) - case e[1].kind - of nkIntLit..nkUInt64Lit: i = int(e[1].intVal) + case e.sons[1].kind + of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal) else: internalError(p.config, e.info, "genTupleElem") - r.addf(".Field$1", [rope(i)]) + addf(r, ".Field$1", [rope(i)]) putIntoDest(p, d, e, r, a.storage) proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope; resTyp: ptr PType = nil): PSym = var ty = ty - assert r != "" + assert r != nil while ty != nil: ty = ty.skipTypes(skipPtrs) assert(ty.kind in {tyTuple, tyObject}) @@ -879,232 +769,144 @@ proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope; if result != nil: if resTyp != nil: resTyp[] = ty break - if not p.module.compileToCpp: r.add(".Sup") - ty = ty[0] + if not p.module.compileToCpp: add(r, ".Sup") + ty = ty.sons[0] if result == nil: internalError(p.config, field.info, "genCheckedRecordField") proc genRecordField(p: BProc, e: PNode, d: var TLoc) = var a: TLoc genRecordFieldAux(p, e, d, a) var r = rdLoc(a) - var f = e[1].sym - let ty = skipTypes(a.t, abstractInstOwned + tyUserTypeClasses) + var f = e.sons[1].sym + let ty = skipTypes(a.t, abstractInst + tyUserTypeClasses) if ty.kind == tyTuple: # we found a unique tuple type which lacks field information # so we use Field$i - r.add ".Field" - r.add rope(f.position) + addf(r, ".Field$1", [rope(f.position)]) putIntoDest(p, d, e, r, a.storage) else: var rtyp: PType let field = lookupFieldAgain(p, ty, f, r, addr rtyp) - if field.loc.r == "" and rtyp != nil: fillObjectFields(p.module, rtyp) - if field.loc.r == "": internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty)) - r.add "." - r.add field.loc.r + if field.loc.r == nil and rtyp != nil: fillObjectFields(p.module, rtyp) + if field.loc.r == nil: internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty)) + addf(r, ".$1", [field.loc.r]) putIntoDest(p, d, e, r, a.storage) - r.freeze proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = var test, u, v: TLoc - for i in 1..= 0: + if firstOrd(p.config, ty) == 0: if (firstOrd(p.config, b.t) < firstOrd(p.config, ty)) or (lastOrd(p.config, b.t) > lastOrd(p.config, ty)): - var last = newRopeAppender() - intLiteral(lastOrd(p.config, ty), last) - linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)){ #raiseIndexError2($1, $2); ", - [rdCharLoc(b), last]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] + linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError();$n", + rdCharLoc(b), intLiteral(lastOrd(p.config, ty))) else: - var last = newRopeAppender() - intLiteral(lastOrd(p.config, ty), last) - linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3){ #raiseIndexError3($1, $2, $3); ", - [rdCharLoc(b), first, last]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n", + rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty))) else: let idx = getOrdValue(y) if idx < firstOrd(p.config, ty) or idx > lastOrd(p.config, ty): - localError(p.config, x.info, formatErrorIndexBound(idx, firstOrd(p.config, ty), lastOrd(p.config, ty))) + localError(p.config, x.info, "index out of bounds") d.inheritLocation(a) putIntoDest(p, d, n, - ropecg(p.module, "$1[($2)- $3]", [rdLoc(a), rdCharLoc(b), first]), a.storage) + ropecg(p.module, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage) proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc initLocExpr(p, x, a) initLocExpr(p, y, b) + var ty = skipTypes(a.t, abstractVarRange) inheritLocation(d, a) putIntoDest(p, d, n, - ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) + ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage) proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = let ty = skipTypes(arr.t, abstractVarRange) case ty.kind of tyOpenArray, tyVarargs: - if reifiedOpenArray(arr.lode): - linefmt(p, cpsStmts, - "if ($2-$1 != -1 && " & - "($1 < 0 || $1 >= $3.Field1 || $2 < 0 || $2 >= $3.Field1)){ #raiseIndexError4($1, $2, $3.Field1); ", - [rdLoc(a), rdLoc(b), rdLoc(arr)]) - else: - linefmt(p, cpsStmts, - "if ($2-$1 != -1 && ($1 < 0 || $1 >= $3Len_0 || $2 < 0 || $2 >= $3Len_0))" & - "{ #raiseIndexError4($1, $2, $3Len_0); ", - [rdLoc(a), rdLoc(b), rdLoc(arr)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - of tyArray: - var first = newRopeAppender() - intLiteral(firstOrd(p.config, ty), first) - var last = newRopeAppender() - intLiteral(lastOrd(p.config, ty), last) linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)){ #raiseIndexError(); ", - [rdCharLoc(a), rdCharLoc(b), first, last]) - - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))) #raiseIndexError();$n", + rdLoc(a), rdLoc(b), rdLoc(arr)) + of tyArray: + let first = intLiteral(firstOrd(p.config, ty)) + if tfUncheckedArray notin ty.flags: + linefmt(p, cpsStmts, + "if ($2-$1 != -1 && " & + "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n", + rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty))) of tySequence, tyString: linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "($1 < 0 || $1 >= $3 || $2 < 0 || $2 >= $3)){ #raiseIndexError4($1, $2, $3); ", - [rdLoc(a), rdLoc(b), lenExpr(p, arr)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + "(!$3 || (NU)($1) >= (NU)($3->$4) || (NU)($2) >= (NU)($3->$4))) #raiseIndexError();$n", + rdLoc(a), rdLoc(b), rdLoc(arr), lenField(p)) else: discard proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc initLocExpr(p, x, a) - initLocExpr(p, y, b) - if not reifiedOpenArray(x): - # emit range check: - if optBoundsCheck in p.options: - linefmt(p, cpsStmts, "if ($1 < 0 || $1 >= $2Len_0){ #raiseIndexError2($1,$2Len_0-1); ", - [rdCharLoc(b), rdLoc(a)]) # BUGFIX: ``>=`` and not ``>``! - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - inheritLocation(d, a) - putIntoDest(p, d, n, - ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) - else: - if optBoundsCheck in p.options: - linefmt(p, cpsStmts, "if ($1 < 0 || $1 >= $2.Field1){ #raiseIndexError2($1,$2.Field1-1); ", - [rdCharLoc(b), rdLoc(a)]) # BUGFIX: ``>=`` and not ``>``! - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - inheritLocation(d, a) - putIntoDest(p, d, n, - ropecg(p.module, "$1.Field0[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) + initLocExpr(p, y, b) # emit range check: + if optBoundsCheck in p.options: + linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError();$n", + rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``! + inheritLocation(d, a) + putIntoDest(p, d, n, + ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage) proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -1114,51 +916,30 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check: if optBoundsCheck in p.options: - linefmt(p, cpsStmts, - "if ($1 < 0 || $1 >= $2){ #raiseIndexError2($1,$2-1); ", - [rdCharLoc(b), lenExpr(p, a)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options): + linefmt(p, cpsStmts, + "if (!$2 || (NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", + rdLoc(b), rdLoc(a), lenField(p)) + else: + linefmt(p, cpsStmts, + "if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", + rdLoc(b), rdLoc(a), lenField(p)) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: - a.r = ropecg(p.module, "(*$1)", [a.r]) - - if lfPrepareForMutation in d.flags and ty.kind == tyString and - optSeqDestructors in p.config.globalOptions: - linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) + a.r = ropecg(p.module, "(*$1)", a.r) putIntoDest(p, d, n, - ropecg(p.module, "$1$3[$2]", [rdLoc(a), rdCharLoc(b), dataField(p)]), a.storage) + ropecg(p.module, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.storage) proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) = - var ty = skipTypes(n[0].typ, abstractVarRange + tyUserTypeClasses) + var ty = skipTypes(n.sons[0].typ, abstractVarRange + tyUserTypeClasses) if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) case ty.kind - of tyUncheckedArray: genUncheckedArrayElem(p, n, n[0], n[1], d) - of tyArray: genArrayElem(p, n, n[0], n[1], d) - of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, n[0], n[1], d) - of tySequence, tyString: genSeqElem(p, n, n[0], n[1], d) - of tyCstring: genCStringElem(p, n, n[0], n[1], d) + of tyArray: genArrayElem(p, n, n.sons[0], n.sons[1], d) + of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, n.sons[0], n.sons[1], d) + of tySequence, tyString: genSeqElem(p, n, n.sons[0], n.sons[1], d) + of tyCString: genCStringElem(p, n, n.sons[0], n.sons[1], d) of tyTuple: genTupleElem(p, n, d) else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')') - discard getTypeDesc(p.module, n.typ) - -proc isSimpleExpr(n: PNode): bool = - # calls all the way down --> can stay expression based - case n.kind - of nkCallKinds, nkDotExpr, nkPar, nkTupleConstr, - nkObjConstr, nkBracket, nkCurly, nkHiddenDeref, nkDerefExpr, nkHiddenAddr, - nkHiddenStdConv, nkHiddenSubConv, nkConv, nkAddr: - for c in n: - if not isSimpleExpr(c): return false - result = true - of nkStmtListExpr: - for i in 0.. 0: - args.add(", ") - case detectStrVersion(p.module) - of 2: - args.add(ropecg(p.module, "Genode::Cstring($1.p->data, $1.len)", [a.rdLoc])) - else: - args.add(ropecg(p.module, "Genode::Cstring($1->data, $1->len)", [a.rdLoc])) + addf(args, ", $1? ($1)->data:\"\"", [rdLoc(a)]) p.module.includeHeader("") - p.module.includeHeader("") - linefmt(p, cpsStmts, """Genode::log($1);$n""", [args]) + linefmt(p, cpsStmts, """Genode::log(""$1);$n""", args) else: if n.len == 0: - linefmt(p, cpsStmts, "#echoBinSafe(NIM_NIL, $1);$n", [n.len]) + linefmt(p, cpsStmts, "#echoBinSafe(NIM_NIL, $1);$n", n.len.rope) else: var a: TLoc initLocExpr(p, n, a) - linefmt(p, cpsStmts, "#echoBinSafe($1, $2);$n", [a.rdLoc, n.len]) + linefmt(p, cpsStmts, "#echoBinSafe($1, $2);$n", a.rdLoc, n.len.rope) when false: p.module.includeHeader("") linefmt(p, cpsStmts, "printf($1$2);$n", - makeCString(repeat("%s", n.len) & "\L"), [args]) - linefmt(p, cpsStmts, "fflush(stdout);$n", []) + makeCString(repeat("%s", n.len) & "\L"), args) + linefmt(p, cpsStmts, "fflush(stdout);$n") proc gcUsage(conf: ConfigRef; n: PNode) = if conf.selectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree) -proc strLoc(p: BProc; d: TLoc): Rope = - if optSeqDestructors in p.config.globalOptions: - result = byRefLoc(p, d) - else: - result = rdLoc(d) - proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = # - # s = "Hello " & name & ", how do you feel?" & 'z' + # s = 'Hello ' & name & ', how do you feel?' & 'z' # # # { @@ -1282,23 +1033,22 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = var a, tmp: TLoc getTemp(p, e.typ, tmp) var L = 0 - var appends: Rope = "" - var lens: Rope = "" - for i in 0..$2 : 0) + ", [rdLoc(a), lenField(p)]) + add(appends, ropecg(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a))) + linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L)) + add(p.s(cpsStmts), appends) if d.k == locNone: d = tmp else: @@ -1307,7 +1057,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = # - # s &= "Hello " & name & ", how do you feel?" & 'z' + # s &= 'Hello ' & name & ', how do you feel?' & 'z' # // BUG: what if s is on the left side too? # # { @@ -1318,239 +1068,158 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = # appendChar(s, 'z'); # } var - a, dest, call: TLoc + a, dest: TLoc appends, lens: Rope assert(d.k == locNone) var L = 0 - initLocExpr(p, e[1], dest) - for i in 0..$2 : 0) + ", [rdLoc(a), lenField(p)]) + add(appends, ropecg(p.module, "#appendString($1, $2);$n", + rdLoc(dest), rdLoc(a))) + linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", + rdLoc(dest), lens, rope(L)) + add(p.s(cpsStmts), appends) + gcUsage(p.config, e) proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq &= x --> # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq->data[seq->len-1] = x; - var a, b, dest, tmpL, call: TLoc - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) - let seqType = skipTypes(e[1].typ, {tyVar}) - initLoc(call, locCall, e, OnHeap) - if not p.module.compileToCpp: - const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)" - call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), - getTypeDesc(p.module, e[1].typ), - genTypeInfoV1(p.module, seqType, e.info)]) - else: - const seqAppendPattern = "($2) #incrSeqV3($1, $3)" - call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), - getTypeDesc(p.module, e[1].typ), - genTypeInfoV1(p.module, seqType, e.info)]) - # emit the write barrier if required, but we can always move here, so - # use 'genRefAssign' for the seq. - genRefAssign(p, a, call) + let seqAppendPattern = if not p.module.compileToCpp: + "$1 = ($2) #incrSeqV3(&($1)->Sup, $3);$n" + else: + "$1 = ($2) #incrSeqV3($1, $3);$n" + var a, b, dest, tmpL: TLoc + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + let seqType = skipTypes(e.sons[1].typ, {tyVar}) + lineCg(p, cpsStmts, seqAppendPattern, [ + rdLoc(a), + getTypeDesc(p.module, e.sons[1].typ), + genTypeInfo(p.module, seqType, e.info)]) #if bt != b.t: # echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t) - initLoc(dest, locExpr, e[2], OnHeap) + initLoc(dest, locExpr, e.sons[2], OnHeap) getIntTemp(p, tmpL) - lineCg(p, cpsStmts, "$1 = $2->$3++;$n", [tmpL.r, rdLoc(a), lenField(p)]) - dest.r = ropecg(p.module, "$1$3[$2]", [rdLoc(a), tmpL.r, dataField(p)]) - genAssignment(p, dest, b, {needToCopy}) + lineCg(p, cpsStmts, "$1 = $2->$3++;$n", tmpL.r, rdLoc(a), lenField(p)) + dest.r = ropecg(p.module, "$1->data[$2]", rdLoc(a), tmpL.r) + genAssignment(p, dest, b, {needToCopy, afDestIsNil}) gcUsage(p.config, e) proc genReset(p: BProc, n: PNode) = var a: TLoc - initLocExpr(p, n[1], a) - specializeReset(p, a) - when false: - linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", - [addrLoc(p.config, a), - genTypeInfoV1(p.module, skipTypes(a.t, {tyVar}), n.info)]) + initLocExpr(p, n.sons[1], a) + linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", + addrLoc(p.config, a), + genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)) -proc genDefault(p: BProc; n: PNode; d: var TLoc) = - if d.k == locNone: getTemp(p, n.typ, d, needsInit=true) - else: resetLoc(p, d) - -proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = +proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) = var sizeExpr = sizeExpr let typ = a.t var b: TLoc initLoc(b, locExpr, a.lode, OnHeap) - let refType = typ.skipTypes(abstractInstOwned) + let refType = typ.skipTypes(abstractInst) assert refType.kind == tyRef let bt = refType.lastSon - if sizeExpr == "": - sizeExpr = "sizeof($1)" % [getTypeDesc(p.module, bt)] - - if optTinyRtti in p.config.globalOptions: - if needsInit: - b.r = ropecg(p.module, "($1) #nimNewObj($2, NIM_ALIGNOF($3))", - [getTypeDesc(p.module, typ), sizeExpr, getTypeDesc(p.module, bt)]) + if sizeExpr.isNil: + sizeExpr = "sizeof($1)" % + [getTypeDesc(p.module, bt)] + let args = [getTypeDesc(p.module, typ), + genTypeInfo(p.module, typ, a.lode.info), + sizeExpr] + if a.storage == OnHeap and usesNativeGC(p.config): + # use newObjRC1 as an optimization + if canFormAcycle(a.t): + linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc) else: - b.r = ropecg(p.module, "($1) #nimNewObjUninit($2, NIM_ALIGNOF($3))", - [getTypeDesc(p.module, typ), sizeExpr, getTypeDesc(p.module, bt)]) - genAssignment(p, a, b, {}) + linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", a.rdLoc) + b.r = ropecg(p.module, "($1) #newObjRC1($2, $3)", args) + linefmt(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc) else: - let ti = genTypeInfoV1(p.module, typ, a.lode.info) - let op = getAttachedOp(p.module.g.graph, bt, attachedDestructor) - if op != nil and not isTrivialProc(p.module.g.graph, op): - # the prototype of a destructor is ``=destroy(x: var T)`` and that of a - # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling - # convention at least: - if op.typ == nil or op.typ.callConv != ccNimCall: - localError(p.module.config, a.lode.info, - "the destructor that is turned into a finalizer needs " & - "to have the 'nimcall' calling convention") - var f: TLoc - initLocExpr(p, newSymNode(op), f) - p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) - - if a.storage == OnHeap and usesWriteBarrier(p.config): - if canFormAcycle(a.t): - linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [a.rdLoc]) - else: - linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", [a.rdLoc]) - if p.config.selectedGC == gcGo: - # newObjRC1() would clash with unsureAsgnRef() - which is used by gcGo to - # implement the write barrier - b.r = ropecg(p.module, "($1) #newObj($2, $3)", [getTypeDesc(p.module, typ), ti, sizeExpr]) - linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", - [addrLoc(p.config, a), b.rdLoc]) - else: - # use newObjRC1 as an optimization - b.r = ropecg(p.module, "($1) #newObjRC1($2, $3)", [getTypeDesc(p.module, typ), ti, sizeExpr]) - linefmt(p, cpsStmts, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) - else: - b.r = ropecg(p.module, "($1) #newObj($2, $3)", [getTypeDesc(p.module, typ), ti, sizeExpr]) - genAssignment(p, a, b, {}) - # set the object type: - genObjectInit(p, cpsStmts, bt, a, constructRefObj) + b.r = ropecg(p.module, "($1) #newObj($2, $3)", args) + genAssignment(p, a, b, {}) # set the object type: + genObjectInit(p, cpsStmts, bt, a, false) proc genNew(p: BProc, e: PNode) = var a: TLoc - initLocExpr(p, e[1], a) + initLocExpr(p, e.sons[1], a) # 'genNew' also handles 'unsafeNew': if e.len == 3: var se: TLoc - initLocExpr(p, e[2], se) - rawGenNew(p, a, se.rdLoc, needsInit = true) + initLocExpr(p, e.sons[2], se) + rawGenNew(p, a, se.rdLoc) else: - rawGenNew(p, a, "", needsInit = true) + rawGenNew(p, a, nil) gcUsage(p.config, e) -proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = +proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) = let seqtype = skipTypes(dest.t, abstractVarRange) + let args = [getTypeDesc(p.module, seqtype), + genTypeInfo(p.module, seqtype, dest.lode.info), length] var call: TLoc initLoc(call, locExpr, dest.lode, OnHeap) - if dest.storage == OnHeap and usesWriteBarrier(p.config): + if dest.storage == OnHeap and usesNativeGC(p.config): if canFormAcycle(dest.t): - linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [dest.rdLoc]) + linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc) else: - linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", [dest.rdLoc]) - if not lenIsZero: - if p.config.selectedGC == gcGo: - # we need the write barrier - call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype), - genTypeInfoV1(p.module, seqtype, dest.lode.info), length]) - linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", [addrLoc(p.config, dest), call.rdLoc]) - else: - call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", [getTypeDesc(p.module, seqtype), - genTypeInfoV1(p.module, seqtype, dest.lode.info), length]) - linefmt(p, cpsStmts, "$1 = $2;$n", [dest.rdLoc, call.rdLoc]) + linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", dest.rdLoc) + call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args) + linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc) else: - if lenIsZero: - call.r = rope"NIM_NIL" - else: - call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype), - genTypeInfoV1(p.module, seqtype, dest.lode.info), length]) + call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args) genAssignment(p, dest, call, {}) proc genNewSeq(p: BProc, e: PNode) = var a, b: TLoc - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) - if optSeqDestructors in p.config.globalOptions: - let seqtype = skipTypes(e[1].typ, abstractVarRange) - linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", - [a.rdLoc, b.rdLoc, - getTypeDesc(p.module, seqtype.lastSon), - getSeqPayloadType(p.module, seqtype)]) - else: - let lenIsZero = e[2].kind == nkIntLit and e[2].intVal == 0 - genNewSeqAux(p, a, b.rdLoc, lenIsZero) - gcUsage(p.config, e) + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + genNewSeqAux(p, a, b.rdLoc) + gcUsage(p.config, e) proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = let seqtype = skipTypes(e.typ, abstractVarRange) var a: TLoc - initLocExpr(p, e[1], a) - if optSeqDestructors in p.config.globalOptions: - if d.k == locNone: getTemp(p, e.typ, d, needsInit=false) - linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", - [d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon), - getSeqPayloadType(p.module, seqtype), - ]) - else: - putIntoDest(p, d, e, ropecg(p.module, - "($1)#nimNewSeqOfCap($2, $3)", [ - getTypeDesc(p.module, seqtype), - genTypeInfoV1(p.module, seqtype, e.info), a.rdLoc])) - gcUsage(p.config, e) - -proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) = - let t = n.typ - discard getTypeDesc(p.module, t) # so that any fields are initialized - let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) - fillLoc(d, locData, n, p.module.tmpBase & rope(id), OnStatic) - if id == p.module.labels: - # expression not found in the cache: - inc(p.module.labels) - p.module.s[cfsData].addf("static NIM_CONST $1 $2 = ", [getTypeDesc(p.module, t), d.r]) - genBracedInit(p, n, isConst = true, t, p.module.s[cfsData]) - p.module.s[cfsData].addf(";$n", []) + initLocExpr(p, e.sons[1], a) + putIntoDest(p, d, e, ropecg(p.module, + "($1)#nimNewSeqOfCap($2, $3)", [ + getTypeDesc(p.module, seqtype), + genTypeInfo(p.module, seqtype, e.info), a.rdLoc])) + gcUsage(p.config, e) +proc genConstExpr(p: BProc, n: PNode): Rope proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr: - rawConstExpr(p, n, d) + let t = n.typ + discard getTypeDesc(p.module, t) # so that any fields are initialized + let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) + fillLoc(d, locData, n, p.module.tmpBase & rope(id), OnStatic) + if id == p.module.labels: + # expression not found in the cache: + inc(p.module.labels) + addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", + [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)]) result = true else: result = false proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = - #echo renderTree e, " ", e.isDeepConstExpr + #echo rendertree e, " ", e.isDeepConstExpr # inheritance in C++ does not allow struct initialization so # we skip this step here: - if not p.module.compileToCpp and optSeqDestructors notin p.config.globalOptions: - # disabled optimization: it is wrong for C++ and now also - # causes trouble for --gc:arc, see bug #13240 - #[ - var box: seq[Thing] - for i in 0..3: - box.add Thing(s1: "121") # pass by sink can mutate Thing. - ]# + if not p.module.compileToCpp: if handleConstExpr(p, e, d): return - var t = e.typ.skipTypes(abstractInstOwned) + var t = e.typ.skipTypes(abstractInst) let isRef = t.kind == tyRef # check if we need to construct the object in a temporary @@ -1565,8 +1234,8 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = getTemp(p, t, tmp) r = rdLoc(tmp) if isRef: - rawGenNew(p, tmp, "", needsInit = nfAllFieldsSet notin e.flags) - t = t.lastSon.skipTypes(abstractInstOwned) + rawGenNew(p, tmp, nil) + t = t.lastSon.skipTypes(abstractInst) r = "(*$1)" % [r] gcUsage(p.config, e) else: @@ -1576,25 +1245,25 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = r = rdLoc(d) discard getTypeDesc(p.module, t) let ty = getUniqueType(t) - for i in 1..data[$2]", rdLoc(dest[]), intLiteral(i)) arr.storage = OnHeap # we know that sequences are on the heap expr(p, n[i], arr) gcUsage(p.config, n) @@ -1641,45 +1299,36 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = var elem, a, arr: TLoc - if n[1].kind == nkBracket: - n[1].typ = n.typ - genSeqConstr(p, n[1], d) + if n.sons[1].kind == nkBracket: + n.sons[1].typ = n.typ + genSeqConstr(p, n.sons[1], d) return if d.k == locNone: getTemp(p, n.typ, d) - initLocExpr(p, n[1], a) # generate call to newSeq before adding the elements per hand: - let L = toInt(lengthOrd(p.config, n[1].typ)) - if optSeqDestructors in p.config.globalOptions: - let seqtype = n.typ - linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", - [rdLoc d, L, getTypeDesc(p.module, seqtype.lastSon), - getSeqPayloadType(p.module, seqtype)]) - else: - var lit = newRopeAppender() - intLiteral(L, lit) - genNewSeqAux(p, d, lit, L == 0) + let L = int(lengthOrd(p.config, n.sons[1].typ)) + genNewSeqAux(p, d, intLiteral(L)) + initLocExpr(p, n.sons[1], a) # bug #5007; do not produce excessive C source code: if L < 10: - for i in 0..data[$2]", rdLoc(d), intLiteral(i)) elem.storage = OnHeap # we know that sequences are on the heap - initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n[1].typ, abstractInst)), a.storage) - arr.r = ropecg(p.module, "$1[$2]", [rdLoc(a), lit]) - genAssignment(p, elem, arr, {needToCopy}) + initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage) + arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), intLiteral(i)) + genAssignment(p, elem, arr, {afDestIsNil, needToCopy}) else: var i: TLoc - getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) - linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", [i.r, L]) + getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) + let oldCode = p.s(cpsStmts) + linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", i.r, L.rope) initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap) - elem.r = ropecg(p.module, "$1$3[$2]", [rdLoc(d), rdLoc(i), dataField(p)]) + elem.r = ropecg(p.module, "$1->data[$2]", rdLoc(d), rdLoc(i)) elem.storage = OnHeap # we know that sequences are on the heap - initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n[1].typ, abstractInst)), a.storage) - arr.r = ropecg(p.module, "$1[$2]", [rdLoc(a), rdLoc(i)]) - genAssignment(p, elem, arr, {needToCopy}) + initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage) + arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), rdLoc(i)) + genAssignment(p, elem, arr, {afDestIsNil, needToCopy}) lineF(p, cpsStmts, "}$n", []) @@ -1688,84 +1337,71 @@ proc genNewFinalize(p: BProc, e: PNode) = a, b, f: TLoc refType, bt: PType ti: Rope - refType = skipTypes(e[1].typ, abstractVarRange) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], f) + refType = skipTypes(e.sons[1].typ, abstractVarRange) + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], f) initLoc(b, locExpr, a.lode, OnHeap) - ti = genTypeInfo(p.config, p.module, refType, e.info) - p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) + ti = genTypeInfo(p.module, refType, e.info) + addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [ getTypeDesc(p.module, refType), ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))]) genAssignment(p, a, b, {}) # set the object type: bt = skipTypes(refType.lastSon, abstractRange) - genObjectInit(p, cpsStmts, bt, a, constructRefObj) + genObjectInit(p, cpsStmts, bt, a, false) gcUsage(p.config, e) -proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo; result: var Rope) = - if optTinyRtti in p.config.globalOptions: - let token = $genDisplayElem(MD5Digest(hashType(dest, p.config))) - appcg(p.module, result, "#isObjDisplayCheck($#.m_type, $#, $#)", [a, getObjDepth(dest), token]) +proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope = + # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we + # have to call it here first: + let ti = genTypeInfo(p.module, dest, info) + if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and + tfObjHasKids notin dest.flags): + result = "$1.m_type == $2" % [a, ti] else: - # unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we - # have to call it here first: - let ti = genTypeInfoV1(p.module, dest, info) - if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and - tfObjHasKids notin dest.flags): - result.add "$1.m_type == $2" % [a, ti] - else: - cgsym(p.module, "TNimType") - inc p.module.labels - let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope - p.module.s[cfsVars].addf("static TNimType* $#[2];$n", [cache]) - appcg(p.module, result, "#isObjWithCache($#.m_type, $#, $#)", [a, ti, cache]) + discard cgsym(p.module, "TNimType") + inc p.module.labels + let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope + addf(p.module.s[cfsVars], "static TNimType* $#[2];$n", [cache]) + result = ropecg(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache) + when false: + # former version: + result = ropecg(p.module, "#isObj($1.m_type, $2)", + a, genTypeInfo(p.module, dest, info)) proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = var a: TLoc initLocExpr(p, x, a) var dest = skipTypes(typ, typedescPtrs) var r = rdLoc(a) - var nilCheck: Rope = "" - var t = skipTypes(a.t, abstractInstOwned) + var nilCheck: Rope = nil + var t = skipTypes(a.t, abstractInst) while t.kind in {tyVar, tyLent, tyPtr, tyRef}: if t.kind notin {tyVar, tyLent}: nilCheck = r if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: - r = ropecg(p.module, "(*$1)", [r]) - t = skipTypes(t.lastSon, typedescInst+{tyOwned}) + r = ropecg(p.module, "(*$1)", r) + t = skipTypes(t.lastSon, typedescInst) discard getTypeDesc(p.module, t) if not p.module.compileToCpp: - while t.kind == tyObject and t[0] != nil: - r.add(".Sup") - t = skipTypes(t[0], skipPtrs) + while t.kind == tyObject and t.sons[0] != nil: + add(r, ~".Sup") + t = skipTypes(t.sons[0], skipPtrs) if isObjLackingTypeField(t): globalError(p.config, x.info, "no 'of' operator available for pure objects") - - var ro = newRopeAppender() - genOfHelper(p, dest, r, x.info, ro) - var ofExpr = newRopeAppender() - ofExpr.add "(" - if nilCheck != "": - ofExpr.add "(" - ofExpr.add nilCheck - ofExpr.add ") && (" - ofExpr.add ro - ofExpr.add "))" + if nilCheck != nil: + r = ropecg(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r, x.info)) else: - ofExpr.add ro - ofExpr.add ")" - - putIntoDest(p, d, x, ofExpr, a.storage) + r = ropecg(p.module, "($1)", genOfHelper(p, dest, r, x.info)) + putIntoDest(p, d, x, r, a.storage) proc genOf(p: BProc, n: PNode, d: var TLoc) = - genOf(p, n[1], n[2].typ, d) + genOf(p, n.sons[1], n.sons[2].typ, d) proc genRepr(p: BProc, e: PNode, d: var TLoc) = - if optTinyRtti in p.config.globalOptions: - localError(p.config, e.info, "'repr' is not available for --newruntime") var a: TLoc - initLocExpr(p, e[1], a) - var t = skipTypes(e[1].typ, abstractVarRange) + initLocExpr(p, e.sons[1], a) + var t = skipTypes(e.sons[1].typ, abstractVarRange) case t.kind of tyInt..tyInt64, tyUInt..tyUInt64: putIntoDest(p, d, e, @@ -1779,141 +1415,86 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = of tyEnum, tyOrdinal: putIntoDest(p, d, e, ropecg(p.module, "#reprEnum((NI)$1, $2)", [ - rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage) + rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage) of tyString: putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage) of tySet: putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [ - addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), a.storage) + addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]), a.storage) of tyOpenArray, tyVarargs: var b: TLoc - case skipTypes(a.t, abstractVarRange).kind + case a.t.kind of tyOpenArray, tyVarargs: putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage) of tyString, tySequence: putIntoDest(p, b, e, - "($4) ? ($1$3) : NIM_NIL, $2" % - [rdLoc(a), lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)], - a.storage) + "$1->data, ($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)], a.storage) of tyArray: putIntoDest(p, b, e, "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))], a.storage) - else: internalError(p.config, e[0].info, "genRepr()") + else: internalError(p.config, e.sons[0].info, "genRepr()") putIntoDest(p, d, e, ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b), - genTypeInfoV1(p.module, elemType(t), e.info)]), a.storage) - of tyCstring, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence: + genTypeInfo(p.module, elemType(t), e.info)]), a.storage) + of tyCString, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence: putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)", [ - rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage) + rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage) of tyEmpty, tyVoid: localError(p.config, e.info, "'repr' doesn't support 'void' type") else: putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)", - [addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), + [addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]), a.storage) gcUsage(p.config, e) -proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope; result: var Rope; enforceV1 = false) = - var derefs = rdLoc(a) - var t = skipTypes(a.t, abstractInst) - while t.kind in {tyVar, tyLent, tyPtr, tyRef}: - if t.kind notin {tyVar, tyLent}: nilCheck = derefs - if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: - derefs = "(*$1)" % [derefs] - t = skipTypes(t.lastSon, abstractInst) - result.add derefs - discard getTypeDesc(p.module, t) - if not p.module.compileToCpp: - while t.kind == tyObject and t[0] != nil: - result.add(".Sup") - t = skipTypes(t[0], skipPtrs) - result.add ".m_type" - if optTinyRtti in p.config.globalOptions and enforceV1: - result.add "->typeInfoV1" - proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) = - cgsym(p.module, "TNimType") - let t = e[1].typ - # ordinary static type information - putIntoDest(p, d, e, genTypeInfoV1(p.module, t, e.info)) + let t = e.sons[1].typ + putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info)) -proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) = - let t = e[1].typ - if isFinal(t) or e[0].sym.name.s != "getDynamicTypeInfo": - # ordinary static type information - putIntoDest(p, d, e, genTypeInfoV2(p.module, t, e.info)) - else: - var a: TLoc - initLocExpr(p, e[1], a) - var nilCheck = "" - # use the dynamic type stored at offset 0: - var rt = newRopeAppender() - rdMType(p, a, nilCheck, rt) - putIntoDest(p, d, e, rt) - -proc genAccessTypeField(p: BProc; e: PNode; d: var TLoc) = +proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) = var a: TLoc - initLocExpr(p, e[1], a) - var nilCheck = "" - # use the dynamic type stored at offset 0: - var rt = newRopeAppender() - rdMType(p, a, nilCheck, rt) - putIntoDest(p, d, e, rt) - -template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) = - var a: TLoc - initLocExpr(p, n[1], a) + initLocExpr(p, n.sons[1], a) a.r = ropecg(p.module, frmt, [rdLoc(a)]) - a.flags.excl lfIndirect # this flag should not be propagated here (not just for HCR) if d.k == locNone: getTemp(p, n.typ, d) genAssignment(p, d, a, {}) gcUsage(p.config, n) proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = - var a = e[1] - if a.kind == nkHiddenAddr: a = a[0] + var a = e.sons[1] + if a.kind == nkHiddenAddr: a = a.sons[0] var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses) case typ.kind of tyOpenArray, tyVarargs: - # Bug #9279, len(toOpenArray()) has to work: - if a.kind in nkCallKinds and a[0].kind == nkSym and a[0].sym.magic == mSlice: - # magic: pass slice to openArray: - var m: TLoc - var b, c: TLoc - initLocExpr(p, a[1], m) - initLocExpr(p, a[2], b) - initLocExpr(p, a[3], c) - if optBoundsCheck in p.options: - genBoundsCheck(p, m, b, c) - if op == mHigh: - putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)", [rdLoc(b), rdLoc(c)])) - else: - putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)])) - else: - if not reifiedOpenArray(a): - if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)") - else: unaryExpr(p, e, d, "$1Len_0") - else: - if op == mHigh: unaryExpr(p, e, d, "($1.Field1-1)") - else: unaryExpr(p, e, d, "$1.Field1") - of tyCstring: - if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)") - else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)") + if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)") + else: unaryExpr(p, e, d, "$1Len_0") + of tyCString: + useStringh(p.module) + if op == mHigh: unaryExpr(p, e, d, "($1 ? (strlen($1)-1) : -1)") + else: unaryExpr(p, e, d, "($1 ? strlen($1) : 0)") of tyString: - var a: TLoc - initLocExpr(p, e[1], a) - var x = lenExpr(p, a) - if op == mHigh: x = "($1-1)" % [x] - putIntoDest(p, d, e, x) + if not p.module.compileToCpp: + if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)") + else: unaryExpr(p, e, d, "($1 ? $1->Sup.len : 0)") + else: + if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)") + else: unaryExpr(p, e, d, "($1 ? $1->len : 0)") of tySequence: - # we go through a temporary here because people write bullshit code. var a, tmp: TLoc initLocExpr(p, e[1], a) getIntTemp(p, tmp) - var x = lenExpr(p, a) - if op == mHigh: x = "($1-1)" % [x] - lineCg(p, cpsStmts, "$1 = $2;$n", [tmp.r, x]) + var frmt: FormatStr + if not p.module.compileToCpp: + if op == mHigh: + frmt = "$1 = ($2 ? ($2->Sup.len-1) : -1);$n" + else: + frmt = "$1 = ($2 ? $2->Sup.len : 0);$n" + else: + if op == mHigh: + frmt = "$1 = ($2 ? ($2->len-1) : -1);$n" + else: + frmt = "$1 = ($2 ? $2->len : 0);$n" + lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a)) putIntoDest(p, d, e, tmp.r) of tyArray: # YYY: length(sideeffect) is optimized away incorrectly? @@ -1921,87 +1502,48 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ))) else: internalError(p.config, e.info, "genArrayLen()") -proc makePtrType(baseType: PType; idgen: IdGenerator): PType = - result = newType(tyPtr, nextTypeId idgen, baseType.owner) - addSonSkipIntLit(result, baseType, idgen) - -proc makeAddr(n: PNode; idgen: IdGenerator): PNode = - if n.kind == nkHiddenAddr: - result = n - else: - result = newTree(nkHiddenAddr, n) - result.typ = makePtrType(n.typ, idgen) - proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = - if optSeqDestructors in p.config.globalOptions: - e[1] = makeAddr(e[1], p.module.idgen) - genCall(p, e, d) - return - var a, b, call: TLoc + var a, b: TLoc assert(d.k == locNone) - var x = e[1] + var x = e.sons[1] if x.kind in {nkAddr, nkHiddenAddr}: x = x[0] initLocExpr(p, x, a) - initLocExpr(p, e[2], b) - let t = skipTypes(e[1].typ, {tyVar}) + initLocExpr(p, e.sons[2], b) + let t = skipTypes(e.sons[1].typ, {tyVar}) + let setLenPattern = if not p.module.compileToCpp: + "$1 = ($3) #setLengthSeqV2(&($1)->Sup, $4, $2);$n" + else: + "$1 = ($3) #setLengthSeqV2($1, $4, $2);$n" - initLoc(call, locCall, e, OnHeap) - if not p.module.compileToCpp: - const setLenPattern = "($3) #setLengthSeqV2(&($1)->Sup, $4, $2)" - call.r = ropecg(p.module, setLenPattern, [ + lineCg(p, cpsStmts, setLenPattern, [ rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), - genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)]) - - else: - const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2)" - call.r = ropecg(p.module, setLenPattern, [ - rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), - genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)]) - - genAssignment(p, a, call, {}) + genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)]) gcUsage(p.config, e) proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = - if optSeqDestructors in p.config.globalOptions: - binaryStmtAddr(p, e, d, "setLengthStrV2") - else: - var a, b, call: TLoc - if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr") - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) - - initLoc(call, locCall, e, OnHeap) - call.r = ropecg(p.module, "#setLengthStr($1, $2)", [ - rdLoc(a), rdLoc(b)]) - genAssignment(p, a, call, {}) - gcUsage(p.config, e) + binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n") + gcUsage(p.config, e) proc genSwap(p: BProc, e: PNode, d: var TLoc) = # swap(a, b) --> # temp = a # a = b # b = temp - cowBracket(p, e[1]) - cowBracket(p, e[2]) var a, b, tmp: TLoc - getTemp(p, skipTypes(e[1].typ, abstractVar), tmp) - initLocExpr(p, e[1], a) # eval a - initLocExpr(p, e[2], b) # eval b + getTemp(p, skipTypes(e.sons[1].typ, abstractVar), tmp) + initLocExpr(p, e.sons[1], a) # eval a + initLocExpr(p, e.sons[2], b) # eval b genAssignment(p, tmp, a, {}) genAssignment(p, a, b, {}) genAssignment(p, b, tmp, {}) -proc rdSetElemLoc(conf: ConfigRef; a: TLoc, typ: PType; result: var Rope) = +proc rdSetElemLoc(conf: ConfigRef; a: TLoc, setType: PType): Rope = # read a location of an set element; it may need a subtraction operation # before the set operation - result.add "(" - result.add rdCharLoc(a) - let setType = typ.skipTypes(abstractPtrs) + result = rdCharLoc(a) assert(setType.kind == tySet) if firstOrd(conf, setType) != 0: - result.add " - " - result.add rope(firstOrd(conf, setType)) - result.add ")" + result = "($1- $2)" % [result, rope(firstOrd(conf, setType))] proc fewCmps(conf: ConfigRef; s: PNode): bool = # this function estimates whether it is better to emit code @@ -2012,110 +1554,98 @@ proc fewCmps(conf: ConfigRef; s: PNode): bool = elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}: result = true # better not emit the set if int is basetype! else: - result = s.len <= 8 # 8 seems to be a good value + result = sonsLen(s) <= 8 # 8 seems to be a good value -template binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) = - var elem = newRopeAppender() - rdSetElemLoc(p.config, b, a.t, elem) - putIntoDest(p, d, e, frmt % [rdLoc(a), elem]) +proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) = + putIntoDest(p, d, e, frmt % [rdLoc(a), rdSetElemLoc(p.config, b, a.t)]) proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) = - case int(getSize(p.config, skipTypes(e[1].typ, abstractVar))) - of 1: binaryExprIn(p, e, a, b, d, "(($1 &((NU8)1<<((NU)($2)&7U)))!=0)") - of 2: binaryExprIn(p, e, a, b, d, "(($1 &((NU16)1<<((NU)($2)&15U)))!=0)") - of 4: binaryExprIn(p, e, a, b, d, "(($1 &((NU32)1<<((NU)($2)&31U)))!=0)") + case int(getSize(p.config, skipTypes(e.sons[1].typ, abstractVar))) + of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&7U)))!=0)") + of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&15U)))!=0)") + of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1U<<((NU)($2)&31U)))!=0)") of 8: binaryExprIn(p, e, a, b, d, "(($1 &((NU64)1<<((NU)($2)&63U)))!=0)") else: binaryExprIn(p, e, a, b, d, "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)") -template binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) = +proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) = var a, b: TLoc assert(d.k == locNone) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) - var elem = newRopeAppender() - rdSetElemLoc(p.config, b, a.t, elem) - lineF(p, cpsStmts, frmt, [rdLoc(a), elem]) + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + lineF(p, cpsStmts, frmt, [rdLoc(a), rdSetElemLoc(p.config, b, a.t)]) proc genInOp(p: BProc, e: PNode, d: var TLoc) = var a, b, x, y: TLoc - if (e[1].kind == nkCurly) and fewCmps(p.config, e[1]): + if (e.sons[1].kind == nkCurly) and fewCmps(p.config, e.sons[1]): # a set constructor but not a constant set: # do not emit the set, but generate a bunch of comparisons; and if we do # so, we skip the unnecessary range check: This is a semantical extension # that code now relies on. :-/ XXX - let ea = if e[2].kind in {nkChckRange, nkChckRange64}: - e[2][0] + let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}: + e.sons[2].sons[0] else: - e[2] + e.sons[2] initLocExpr(p, ea, a) initLoc(b, locExpr, e, OnUnknown) - if e[1].len > 0: + var length = sonsLen(e.sons[1]) + if length > 0: b.r = rope("(") - for i in 0..= $2 && $1 <= $3", + initLocExpr(p, it.sons[0], x) + initLocExpr(p, it.sons[1], y) + addf(b.r, "$1 >= $2 && $1 <= $3", [rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)]) else: initLocExpr(p, it, x) - b.r.addf("$1 == $2", [rdCharLoc(a), rdCharLoc(x)]) - if i < e[1].len - 1: b.r.add(" || ") - b.r.add(")") + addf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)]) + if i < length - 1: add(b.r, " || ") + add(b.r, ")") else: # handle the case of an empty set b.r = rope("0") putIntoDest(p, d, e, b.r) else: - assert(e[1].typ != nil) - assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + assert(e.sons[1].typ != nil) + assert(e.sons[2].typ != nil) + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) genInExprAux(p, e, a, b, d) proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = const - lookupOpr: array[mLeSet..mMinusSet, string] = [ + lookupOpr: array[mLeSet..mSymDiffSet, string] = [ "for ($1 = 0; $1 < $2; $1++) { $n" & - " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & - " if (!$3) break;}$n", - "for ($1 = 0; $1 < $2; $1++) { $n" & - " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & - " if (!$3) break;}$n" & - "if ($3) $3 = (#nimCmpMem($4, $5, $2) != 0);$n", - "&", - "|", - "& ~"] + " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & + " if (!$3) break;}$n", "for ($1 = 0; $1 < $2; $1++) { $n" & + " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & " if (!$3) break;}$n" & + "if ($3) $3 = (memcmp($4, $5, $2) != 0);$n", + "&", "|", "& ~", "^"] var a, b, i: TLoc - var setType = skipTypes(e[1].typ, abstractVar) + var setType = skipTypes(e.sons[1].typ, abstractVar) var size = int(getSize(p.config, setType)) case size of 1, 2, 4, 8: case op of mIncl: - case size - of 1: binaryStmtInExcl(p, e, d, "$1 |= ((NU8)1)<<(($2) & 7);$n") - of 2: binaryStmtInExcl(p, e, d, "$1 |= ((NU16)1)<<(($2) & 15);$n") - of 4: binaryStmtInExcl(p, e, d, "$1 |= ((NU32)1)<<(($2) & 31);$n") - of 8: binaryStmtInExcl(p, e, d, "$1 |= ((NU64)1)<<(($2) & 63);$n") - else: assert(false, $size) + var ts = "NU" & $(size * 8) + binaryStmtInExcl(p, e, d, + "$1 |= ((" & ts & ")1)<<(($2)%(sizeof(" & ts & ")*8));$n") of mExcl: - case size - of 1: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU8)1) << (($2) & 7));$n") - of 2: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU16)1) << (($2) & 15));$n") - of 4: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU32)1) << (($2) & 31));$n") - of 8: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU64)1) << (($2) & 63));$n") - else: assert(false, $size) + var ts = "NU" & $(size * 8) + binaryStmtInExcl(p, e, d, "$1 &= ~(((" & ts & ")1) << (($2) % (sizeof(" & + ts & ")*8)));$n") of mCard: if size <= 4: unaryExprChar(p, e, d, "#countBits32($1)") else: unaryExprChar(p, e, d, "#countBits64($1)") - of mLtSet: binaryExprChar(p, e, d, "((($1 & ~ $2)==0)&&($1 != $2))") + of mLtSet: binaryExprChar(p, e, d, "(($1 & ~ $2 ==0)&&($1 != $2))") of mLeSet: binaryExprChar(p, e, d, "(($1 & ~ $2)==0)") of mEqSet: binaryExpr(p, e, d, "($1 == $2)") of mMulSet: binaryExpr(p, e, d, "($1 & $2)") of mPlusSet: binaryExpr(p, e, d, "($1 | $2)") of mMinusSet: binaryExpr(p, e, d, "($1 & ~ $2)") + of mSymDiffSet: binaryExpr(p, e, d, "($1 ^ $2)") of mInSet: genInOp(p, e, d) else: internalError(p.config, e.info, "genSetOp()") @@ -2123,34 +1653,23 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = case op of mIncl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] |=(1U<<($2&7U));$n") of mExcl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] &= ~(1U<<($2&7U));$n") - of mCard: - var a: TLoc - initLocExpr(p, e[1], a) - putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [addrLoc(p.config, a), size])) + of mCard: unaryExprChar(p, e, d, "#cardSet($1, " & $size & ')') of mLtSet, mLeSet: - getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) - if d.k == locNone: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyBool), d) - if op == mLtSet: - linefmt(p, cpsStmts, lookupOpr[mLtSet], - [rdLoc(i), size, rdLoc(d), rdLoc(a), rdLoc(b)]) - else: - linefmt(p, cpsStmts, lookupOpr[mLeSet], - [rdLoc(i), size, rdLoc(d), rdLoc(a), rdLoc(b)]) + getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + if d.k == locNone: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyBool), d) + lineF(p, cpsStmts, lookupOpr[op], + [rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b)]) of mEqSet: - var a, b: TLoc - assert(e[1].typ != nil) - assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) - putIntoDest(p, d, e, ropecg(p.module, "(#nimCmpMem($1, $2, $3)==0)", [a.rdCharLoc, b.rdCharLoc, size])) - of mMulSet, mPlusSet, mMinusSet: + useStringh(p.module) + binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)") + of mMulSet, mPlusSet, mMinusSet, mSymDiffSet: # we inline the simple for loop for better code generation: - getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) - if d.k == locNone: getTemp(p, setType, d) + getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + if d.k == locNone: getTemp(p, a.t, d) lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) $n" & " $3[$1] = $4[$1] $6 $5[$1];$n", [ @@ -2164,35 +1683,25 @@ proc genOrd(p: BProc, e: PNode, d: var TLoc) = proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = const - ValueTypes = {tyTuple, tyObject, tyArray, tyOpenArray, tyVarargs, tyUncheckedArray} + ValueTypes = {tyTuple, tyObject, tyArray, tyOpenArray, tyVarargs} # we use whatever C gives us. Except if we have a value-type, we need to go # through its address: var a: TLoc - initLocExpr(p, e[1], a) - let etyp = skipTypes(e.typ, abstractRange+{tyOwned}) - let srcTyp = skipTypes(e[1].typ, abstractRange) + initLocExpr(p, e.sons[1], a) + let etyp = skipTypes(e.typ, abstractRange) if etyp.kind in ValueTypes and lfIndirect notin a.flags: putIntoDest(p, d, e, "(*($1*) ($2))" % [getTypeDesc(p.module, e.typ), addrLoc(p.config, a)], a.storage) - elif etyp.kind == tyProc and etyp.callConv == ccClosure and srcTyp.callConv != ccClosure: + elif etyp.kind == tyProc and etyp.callConv == ccClosure: putIntoDest(p, d, e, "(($1) ($2))" % [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)], a.storage) else: + let srcTyp = skipTypes(e.sons[1].typ, abstractRange) # C++ does not like direct casts from pointer to shorter integral types if srcTyp.kind in {tyPtr, tyPointer} and etyp.kind in IntegralTypes: putIntoDest(p, d, e, "(($1) (ptrdiff_t) ($2))" % [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage) - elif optSeqDestructors in p.config.globalOptions and etyp.kind in {tySequence, tyString}: - putIntoDest(p, d, e, "(*($1*) (&$2))" % - [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage) - elif etyp.kind == tyBool and srcTyp.kind in IntegralTypes: - putIntoDest(p, d, e, "(($1) != 0)" % [rdCharLoc(a)], a.storage) else: - if etyp.kind == tyPtr: - # generates the definition of structs for casts like cast[ptr object](addr x)[] - let internalType = etyp.skipTypes({tyPtr}) - if internalType.kind == tyObject: - discard getTypeDesc(p.module, internalType) putIntoDest(p, d, e, "(($1) ($2))" % [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage) @@ -2200,7 +1709,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) = const ValueTypes = {tyFloat..tyFloat128, tyTuple, tyObject, tyArray} let destt = skipTypes(e.typ, abstractRange) - srct = skipTypes(e[1].typ, abstractRange) + srct = skipTypes(e.sons[1].typ, abstractRange) if destt.kind in ValueTypes or srct.kind in ValueTypes: # 'cast' and some float type involved? --> use a union. inc(p.labels) @@ -2208,84 +1717,50 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) = var tmp: TLoc tmp.r = "LOC$1.source" % [lbl] linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n", - [getTypeDesc(p.module, e[1].typ), getTypeDesc(p.module, e.typ), lbl]) + getTypeDesc(p.module, e.sons[1].typ), getTypeDesc(p.module, e.typ), lbl) tmp.k = locExpr tmp.lode = lodeTyp srct tmp.storage = OnStack tmp.flags = {} - expr(p, e[1], tmp) + expr(p, e.sons[1], tmp) putIntoDest(p, d, e, "LOC$#.dest" % [lbl], tmp.storage) else: # I prefer the shorter cast version for pointer types -> generate less # C code; plus it's the right thing to do for closures: genSomeCast(p, e, d) -proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = +proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) = var a: TLoc var dest = skipTypes(n.typ, abstractVar) - initLocExpr(p, n[0], a) - if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and - checkUnsignedConversions notin p.config.legacyFeatures): - discard "no need to generate a check because it was disabled" + # range checks for unsigned turned out to be buggy and annoying: + if optRangeCheck notin p.options or dest.skipTypes({tyRange}).kind in + {tyUInt..tyUInt64}: + initLocExpr(p, n.sons[0], a) + putIntoDest(p, d, n, "(($1) ($2))" % + [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage) else: - let n0t = n[0].typ - - # emit range check: - if n0t.kind in {tyUInt, tyUInt64}: - var first = newRopeAppender() - genLiteral(p, n[1], dest, first) - var last = newRopeAppender() - genLiteral(p, n[2], dest, last) - linefmt(p, cpsStmts, "if ($1 > ($5)($3)){ #raiseRangeErrorNoArgs(); ", - [rdCharLoc(a), first, last, - raiser, getTypeDesc(p.module, n0t)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - else: - let raiser = - case skipTypes(n.typ, abstractVarRange).kind - of tyUInt..tyUInt64, tyChar: "raiseRangeErrorU" - of tyFloat..tyFloat128: "raiseRangeErrorF" - else: "raiseRangeErrorI" - cgsym(p.module, raiser) - - let boundaryCast = - if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64}: - "(NI64)" - else: - "" - var first = newRopeAppender() - genLiteral(p, n[1], dest, first) - var last = newRopeAppender() - genLiteral(p, n[2], dest, last) - linefmt(p, cpsStmts, "if ($5($1) < $2 || $5($1) > $3){ $4($1, $2, $3); ", - [rdCharLoc(a), first, last, - raiser, boundaryCast]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - putIntoDest(p, d, n, "(($1) ($2))" % - [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage) + initLocExpr(p, n.sons[0], a) + putIntoDest(p, d, lodeTyp dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [ + getTypeDesc(p.module, dest), rdCharLoc(a), + genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest), + rope(magic)]), a.storage) proc genConv(p: BProc, e: PNode, d: var TLoc) = let destType = e.typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink}) - if sameBackendType(destType, e[1].typ): - expr(p, e[1], d) + if sameBackendType(destType, e.sons[1].typ): + expr(p, e.sons[1], d) else: genSomeCast(p, e, d) proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) = var a: TLoc - initLocExpr(p, n[0], a) - putIntoDest(p, d, n, - ropecg(p.module, "#nimToCStringConv($1)", [rdLoc(a)]), -# "($1 ? $1->data : (NCSTRING)\"\")" % [a.rdLoc], + initLocExpr(p, n.sons[0], a) + putIntoDest(p, d, n, "($1 ? $1->data : (NCSTRING)\"\")" % [rdLoc(a)], a.storage) proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = var a: TLoc - initLocExpr(p, n[0], a) + initLocExpr(p, n.sons[0], a) putIntoDest(p, d, n, ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]), a.storage) @@ -2293,16 +1768,16 @@ proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = var x: TLoc - var a = e[1] - var b = e[2] + var a = e.sons[1] + var b = e.sons[2] if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "": - initLocExpr(p, e[2], x) + initLocExpr(p, e.sons[2], x) putIntoDest(p, d, e, - ropecg(p.module, "($1 == 0)", [lenExpr(p, x)])) + ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p))) elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "": - initLocExpr(p, e[1], x) + initLocExpr(p, e.sons[1], x) putIntoDest(p, d, e, - ropecg(p.module, "($1 == 0)", [lenExpr(p, x)])) + ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p))) else: binaryExpr(p, e, d, "#eqStrings($1, $2)") @@ -2310,126 +1785,24 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) = if {optNaNCheck, optInfCheck} * p.options != {}: const opr: array[mAddF64..mDivF64, string] = ["+", "-", "*", "/"] var a, b: TLoc - assert(e[1].typ != nil) - assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + assert(e.sons[1].typ != nil) + assert(e.sons[2].typ != nil) + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) putIntoDest(p, d, e, ropecg(p.module, "(($4)($2) $1 ($4)($3))", - [opr[m], rdLoc(a), rdLoc(b), - getSimpleTypeDesc(p.module, e[1].typ)])) + rope(opr[m]), rdLoc(a), rdLoc(b), + getSimpleTypeDesc(p.module, e[1].typ))) if optNaNCheck in p.options: - linefmt(p, cpsStmts, "if ($1 != $1){ #raiseFloatInvalidOp(); ", [rdLoc(d)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + linefmt(p, cpsStmts, "#nanCheck($1);$n", rdLoc(d)) if optInfCheck in p.options: - linefmt(p, cpsStmts, "if ($1 != 0.0 && $1*0.5 == $1) { #raiseFloatOverflow($1); ", [rdLoc(d)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - + linefmt(p, cpsStmts, "#infCheck($1);$n", rdLoc(d)) else: binaryArith(p, e, d, m) -proc skipAddr(n: PNode): PNode = - result = if n.kind in {nkAddr, nkHiddenAddr}: n[0] else: n - -proc genWasMoved(p: BProc; n: PNode) = - var a: TLoc - let n1 = n[1].skipAddr - if p.withinBlockLeaveActions > 0 and notYetAlive(n1): - discard - else: - initLocExpr(p, n1, a) - resetLoc(p, a) - #linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", - # [addrLoc(p.config, a), getTypeDesc(p.module, a.t)]) - -proc genMove(p: BProc; n: PNode; d: var TLoc) = - var a: TLoc - initLocExpr(p, n[1].skipAddr, a) - if n.len == 4: - # generated by liftdestructors: - var src: TLoc - initLocExpr(p, n[2], src) - linefmt(p, cpsStmts, "if ($1.p != $2.p) {", [rdLoc(a), rdLoc(src)]) - genStmts(p, n[3]) - linefmt(p, cpsStmts, "}$n$1.len = $2.len; $1.p = $2.p;$n", [rdLoc(a), rdLoc(src)]) - else: - if d.k == locNone: getTemp(p, n.typ, d) - genAssignment(p, d, a, {}) - resetLoc(p, a) - -proc genDestroy(p: BProc; n: PNode) = - if optSeqDestructors in p.config.globalOptions: - let arg = n[1].skipAddr - let t = arg.typ.skipTypes(abstractInst) - case t.kind - of tyString: - var a: TLoc - initLocExpr(p, arg, a) - if optThreads in p.config.globalOptions: - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #deallocShared($1.p);$n" & - "}$n", [rdLoc(a)]) - else: - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #dealloc($1.p);$n" & - "}$n", [rdLoc(a)]) - of tySequence: - var a: TLoc - initLocExpr(p, arg, a) - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" & - "}$n", - [rdLoc(a), getTypeDesc(p.module, t.lastSon)]) - else: discard "nothing to do" - else: - let t = n[1].typ.skipTypes(abstractVar) - let op = getAttachedOp(p.module.g.graph, t, attachedDestructor) - if op != nil and getBody(p.module.g.graph, op).len != 0: - internalError(p.config, n.info, "destructor turned out to be not trivial") - discard "ignore calls to the default destructor" - -proc genDispose(p: BProc; n: PNode) = - when false: - let elemType = n[1].typ.skipTypes(abstractVar).lastSon - - var a: TLoc - initLocExpr(p, n[1].skipAddr, a) - - if isFinal(elemType): - if elemType.destructor != nil: - var destroyCall = newNodeI(nkCall, n.info) - genStmts(p, destroyCall) - lineFmt(p, cpsStmts, "#nimRawDispose($1, NIM_ALIGNOF($2))", [rdLoc(a), getTypeDesc(p.module, elemType)]) - else: - # ``nimRawDisposeVirtual`` calls the ``finalizer`` which is the same as the - # destructor, but it uses the runtime type. Afterwards the memory is freed: - lineCg(p, cpsStmts, ["#nimDestroyAndDispose($#)", rdLoc(a)]) - -proc genSlice(p: BProc; e: PNode; d: var TLoc) = - let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon, - prepareForMutation = e[1].kind == nkHiddenDeref and - e[1].typ.skipTypes(abstractInst).kind == tyString and - p.config.selectedGC in {gcArc, gcOrc}) - if d.k == locNone: getTemp(p, e.typ, d) - linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y]) - when false: - localError(p.config, e.info, "invalid context for 'toOpenArray'; " & - "'toOpenArray' is only valid within a call expression") - -proc genEnumToStr(p: BProc, e: PNode, d: var TLoc) = - let t = e[1].typ.skipTypes(abstractInst+{tyRange}) - let toStrProc = getToStringProc(p.module.g.graph, t) - # XXX need to modify this logic for IC. - var n = copyTree(e) - n[0] = newSymNode(toStrProc) - expr(p, n, d) - proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = case op of mOr, mAnd: genAndOr(p, e, d, op) - of mNot..mUnaryMinusF64: unaryArith(p, e, d, op) + of mNot..mToBiggestInt: unaryArith(p, e, d, op) of mUnaryMinusI..mAbsI: unaryArithOverflow(p, e, d, op) of mAddF64..mDivF64: binaryFloatArith(p, e, d, op) of mShrI..mXor: binaryArith(p, e, d, op) @@ -2437,47 +1810,36 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mAddI..mPred: binaryArithOverflow(p, e, d, op) of mRepr: genRepr(p, e, d) of mGetTypeInfo: genGetTypeInfo(p, e, d) - of mGetTypeInfoV2: genGetTypeInfoV2(p, e, d) of mSwap: genSwap(p, e, d) + of mUnaryLt: + if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)") + else: unaryExpr(p, e, d, "#subInt($1, 1)") of mInc, mDec: - const opr: array[mInc..mDec, string] = ["+=", "-="] - const fun64: array[mInc..mDec, string] = ["nimAddInt64", "nimSubInt64"] - const fun: array[mInc..mDec, string] = ["nimAddInt","nimSubInt"] - let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange, tyDistinct}) + const opr: array[mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"] + const fun64: array[mInc..mDec, string] = ["$# = #addInt64($#, $#);$n", + "$# = #subInt64($#, $#);$n"] + const fun: array[mInc..mDec, string] = ["$# = #addInt($#, $#);$n", + "$# = #subInt($#, $#);$n"] + let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange}) if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}: binaryStmt(p, e, d, opr[op]) else: var a, b: TLoc - assert(e[1].typ != nil) - assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + assert(e.sons[1].typ != nil) + assert(e.sons[2].typ != nil) + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) - let ranged = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyDistinct}) + let ranged = skipTypes(e.sons[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent}) let res = binaryArithOverflowRaw(p, ranged, a, b, if underlying.kind == tyInt64: fun64[op] else: fun[op]) - - putIntoDest(p, a, e[1], "($#)($#)" % [ + putIntoDest(p, a, e.sons[1], "($#)($#)" % [ getTypeDesc(p.module, ranged), res]) of mConStrStr: genStrConcat(p, e, d) - of mAppendStrCh: - if optSeqDestructors in p.config.globalOptions: - binaryStmtAddr(p, e, d, "nimAddCharV1") - else: - var dest, b, call: TLoc - initLoc(call, locCall, e, OnHeap) - initLocExpr(p, e[1], dest) - initLocExpr(p, e[2], b) - call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)]) - genAssignment(p, dest, call, {}) + of mAppendStrCh: binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n") of mAppendStrStr: genStrAppend(p, e, d) - of mAppendSeqElem: - if optSeqDestructors in p.config.globalOptions: - e[1] = makeAddr(e[1], p.module.idgen) - genCall(p, e, d) - else: - genSeqElemAppend(p, e, d) + of mAppendSeqElem: genSeqElemAppend(p, e, d) of mEqStr: genStrEquals(p, e, d) of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)") of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)") @@ -2486,130 +1848,70 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mInt64ToStr: genDollar(p, e, d, "#nimInt64ToStr($1)") of mBoolToStr: genDollar(p, e, d, "#nimBoolToStr($1)") of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)") - of mFloatToStr: - if e[1].typ.skipTypes(abstractInst).kind == tyFloat32: - genDollar(p, e, d, "#nimFloat32ToStr($1)") - else: - genDollar(p, e, d, "#nimFloatToStr($1)") + of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)") of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)") - of mStrToStr, mUnown: expr(p, e[1], d) - of generatedMagics: genCall(p, e, d) - of mEnumToStr: - if optTinyRtti in p.config.globalOptions: - genEnumToStr(p, e, d) - else: - genRepr(p, e, d) + of mStrToStr: expr(p, e.sons[1], d) + of mEnumToStr: genRepr(p, e, d) of mOf: genOf(p, e, d) of mNew: genNew(p, e) - of mNewFinalize: - if optTinyRtti in p.config.globalOptions: - var a: TLoc - initLocExpr(p, e[1], a) - rawGenNew(p, a, "", needsInit = true) - gcUsage(p.config, e) - else: - genNewFinalize(p, e) - of mNewSeq: - if optSeqDestructors in p.config.globalOptions: - e[1] = makeAddr(e[1], p.module.idgen) - genCall(p, e, d) - else: - genNewSeq(p, e) + of mNewFinalize: genNewFinalize(p, e) + of mNewSeq: genNewSeq(p, e) of mNewSeqOfCap: genNewSeqOfCap(p, e, d) of mSizeOf: - let t = e[1].typ.skipTypes({tyTypeDesc}) - putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, skVar)]) - of mAlignOf: - let t = e[1].typ.skipTypes({tyTypeDesc}) - putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, skVar)]) - of mOffsetOf: - var dotExpr: PNode - if e[1].kind == nkDotExpr: - dotExpr = e[1] - elif e[1].kind == nkCheckedFieldExpr: - dotExpr = e[1][0] - else: - internalError(p.config, e.info, "unknown ast") - let t = dotExpr[0].typ.skipTypes({tyTypeDesc}) - let tname = getTypeDesc(p.module, t, skVar) - let member = - if t.kind == tyTuple: - "Field" & rope(dotExpr[1].sym.position) - else: dotExpr[1].sym.loc.r - putIntoDest(p,d,e, "((NI)offsetof($1, $2))" % [tname, member]) + let t = e.sons[1].typ.skipTypes({tyTypeDesc}) + putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)]) of mChr: genSomeCast(p, e, d) of mOrd: genOrd(p, e, d) of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray: genArrayLen(p, e, d, op) - of mGCref: unaryStmt(p, e, d, "if ($1) { #nimGCref($1); }$n") - of mGCunref: unaryStmt(p, e, d, "if ($1) { #nimGCunref($1); }$n") + of mXLenStr: + if not p.module.compileToCpp: + unaryExpr(p, e, d, "($1->Sup.len)") + else: + unaryExpr(p, e, d, "$1->len") + of mXLenSeq: + # see 'taddhigh.nim' for why we need to use a temporary here: + var a, tmp: TLoc + initLocExpr(p, e[1], a) + getIntTemp(p, tmp) + var frmt: FormatStr + if not p.module.compileToCpp: + frmt = "$1 = $2->Sup.len;$n" + else: + frmt = "$1 = $2->len;$n" + lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a)) + putIntoDest(p, d, e, tmp.r) + of mGCref: unaryStmt(p, e, d, "#nimGCref($1);$n") + of mGCunref: unaryStmt(p, e, d, "#nimGCunref($1);$n") of mSetLengthStr: genSetLengthStr(p, e, d) of mSetLengthSeq: genSetLengthSeq(p, e, d) of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet, mInSet: genSetOp(p, e, d, op) - of mNewString, mNewStringOfCap, mExit, mParseBiggestFloat: - var opr = e[0].sym - # Why would anyone want to set nodecl to one of these hardcoded magics? - # - not sure, and it wouldn't work if the symbol behind the magic isn't - # somehow forward-declared from some other usage, but it is *possible* + of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit, + mParseBiggestFloat: + var opr = e.sons[0].sym if lfNoDecl notin opr.loc.flags: - let prc = magicsys.getCompilerProc(p.module.g.graph, $opr.loc.r) - assert prc != nil, $opr.loc.r - # HACK: - # Explicitly add this proc as declared here so the cgsym call doesn't - # add a forward declaration - without this we could end up with the same - # 2 forward declarations. That happens because the magic symbol and the original - # one that shall be used have different ids (even though a call to one is - # actually a call to the other) so checking into m.declaredProtos with the 2 different ids doesn't work. - # Why would 2 identical forward declarations be a problem? - # - in the case of hot code-reloading we generate function pointers instead - # of forward declarations and in C++ it is an error to redefine a global - let wasDeclared = containsOrIncl(p.module.declaredProtos, prc.id) - # Make the function behind the magic get actually generated - this will - # not lead to a forward declaration! The genCall will lead to one. - cgsym(p.module, $opr.loc.r) - # make sure we have pointer-initialising code for hot code reloading - if not wasDeclared and p.hcrOn: - p.module.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n", - [mangleDynLibProc(prc), getTypeDesc(p.module, prc.loc.t), getModuleDllPath(p.module, prc)]) + discard cgsym(p.module, $opr.loc.r) genCall(p, e, d) - of mDefault, mZeroDefault: genDefault(p, e, d) of mReset: genReset(p, e) of mEcho: genEcho(p, e[1].skipConv) of mArrToSeq: genArrToSeq(p, e, d) of mNLen..mNError, mSlurp..mQuoteAst: - localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e[0].sym.name.s)) + localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e.sons[0].sym.name.s)) of mSpawn: - when defined(leanCompiler): - p.config.quitOrRaise "compiler built without support for the 'spawn' statement" - else: - let n = spawn.wrapProcForSpawn(p.module.g.graph, p.module.idgen, p.module.module, e, e.typ, nil, nil) - expr(p, n, d) + let n = lowerings.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil) + expr(p, n, d) of mParallel: - when defined(leanCompiler): - p.config.quitOrRaise "compiler built without support for the 'parallel' statement" - else: - let n = semparallel.liftParallel(p.module.g.graph, p.module.idgen, p.module.module, e) - expr(p, n, d) + let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e) + expr(p, n, d) of mDeepCopy: - if p.config.selectedGC in {gcArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions: - localError(p.config, e.info, - "for --gc:arc|orc 'deepcopy' support has to be enabled with --deepcopy:on") - var a, b: TLoc let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1] initLocExpr(p, x, a) - initLocExpr(p, e[2], b) + initLocExpr(p, e.sons[2], b) genDeepCopy(p, a, b) of mDotDot, mEqCString: genCall(p, e, d) - of mWasMoved: genWasMoved(p, e) - of mMove: genMove(p, e, d) - of mDestroy: genDestroy(p, e) - of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0") - of mAccessTypeField: genAccessTypeField(p, e, d) - of mSlice: genSlice(p, e, d) - of mTrace: discard "no code to generate" else: when defined(debugMagics): echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind @@ -2618,62 +1920,49 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = # example: { a..b, c, d, e, f..g } # we have to emit an expression of the form: - # nimZeroMem(tmp, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c); + # memset(tmp, 0, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c); # incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g); var a, b, idx: TLoc if nfAllConst in e.flags: - var elem = newRopeAppender() - genSetNode(p, e, elem) - putIntoDest(p, d, e, elem) + putIntoDest(p, d, e, genSetNode(p, e)) else: if d.k == locNone: getTemp(p, e.typ, d) if getSize(p.config, e.typ) > 8: # big set: - linefmt(p, cpsStmts, "#nimZeroMem($1, sizeof($2));$n", + useStringh(p.module) + lineF(p, cpsStmts, "memset($1, 0, sizeof($2));$n", [rdLoc(d), getTypeDesc(p.module, e.typ)]) for it in e.sons: if it.kind == nkRange: - getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), idx) # our counter - initLocExpr(p, it[0], a) - initLocExpr(p, it[1], b) - var aa = newRopeAppender() - rdSetElemLoc(p.config, a, e.typ, aa) - var bb = newRopeAppender() - rdSetElemLoc(p.config, b, e.typ, bb) + getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter + initLocExpr(p, it.sons[0], a) + initLocExpr(p, it.sons[1], b) lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" & "$2[(NU)($1)>>3] |=(1U<<((NU)($1)&7U));$n", [rdLoc(idx), rdLoc(d), - aa, bb]) + rdSetElemLoc(p.config, a, e.typ), rdSetElemLoc(p.config, b, e.typ)]) else: initLocExpr(p, it, a) - var aa = newRopeAppender() - rdSetElemLoc(p.config, a, e.typ, aa) lineF(p, cpsStmts, "$1[(NU)($2)>>3] |=(1U<<((NU)($2)&7U));$n", - [rdLoc(d), aa]) + [rdLoc(d), rdSetElemLoc(p.config, a, e.typ)]) else: # small set var ts = "NU" & $(getSize(p.config, e.typ) * 8) lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(d)]) for it in e.sons: if it.kind == nkRange: - getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), idx) # our counter - initLocExpr(p, it[0], a) - initLocExpr(p, it[1], b) - var aa = newRopeAppender() - rdSetElemLoc(p.config, a, e.typ, aa) - var bb = newRopeAppender() - rdSetElemLoc(p.config, b, e.typ, bb) - + getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter + initLocExpr(p, it.sons[0], a) + initLocExpr(p, it.sons[1], b) lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" & - "$2 |=(($5)(1)<<(($1)%(sizeof($5)*8)));$n", [ - rdLoc(idx), rdLoc(d), aa, bb, rope(ts)]) + "$2 |=((" & ts & ")(1)<<(($1)%(sizeof(" & ts & ")*8)));$n", [ + rdLoc(idx), rdLoc(d), rdSetElemLoc(p.config, a, e.typ), + rdSetElemLoc(p.config, b, e.typ)]) else: initLocExpr(p, it, a) - var aa = newRopeAppender() - rdSetElemLoc(p.config, a, e.typ, aa) lineF(p, cpsStmts, - "$1 |=(($3)(1)<<(($2)%(sizeof($3)*8)));$n", - [rdLoc(d), aa, rope(ts)]) + "$1 |=((" & ts & ")(1)<<(($2)%(sizeof(" & ts & ")*8)));$n", + [rdLoc(d), rdSetElemLoc(p.config, a, e.typ)]) proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = var rec: TLoc @@ -2681,60 +1970,55 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = let t = n.typ discard getTypeDesc(p.module, t) # so that any fields are initialized if d.k == locNone: getTemp(p, t, d) - for i in 0.. 0: exprOrStmt - if frameName != "": - p.s(cpsStmts).add deinitFrameNoDebug(p, frameName) + if frameName != nil: + add p.s(cpsStmts), deinitFrameNoDebug(p, frameName) proc genStmtListExpr(p: BProc, n: PNode, d: var TLoc) = genStmtListExprImpl: - expr(p, n[^1], d) + expr(p, n[n.len - 1], d) proc genStmtList(p: BProc, n: PNode) = genStmtListExprImpl: - genStmts(p, n[^1]) - -from parampatterns import isLValue + genStmts(p, n[n.len - 1]) proc upConv(p: BProc, n: PNode, d: var TLoc) = var a: TLoc - initLocExpr(p, n[0], a) + initLocExpr(p, n.sons[0], a) let dest = skipTypes(n.typ, abstractPtrs) if optObjCheck in p.options and not isObjLackingTypeField(dest): - var nilCheck = "" - var r = newRopeAppender() - rdMType(p, a, nilCheck, r) - if optTinyRtti in p.config.globalOptions: - let checkFor = $getObjDepth(dest) - let token = $genDisplayElem(MD5Digest(hashType(dest, p.config))) - if nilCheck != "": - linefmt(p, cpsStmts, "if ($1 && !#isObjDisplayCheck($2, $3, $4)){ #raiseObjectConversionError(); ", - [nilCheck, r, checkFor, token]) - else: - linefmt(p, cpsStmts, "if (!#isObjDisplayCheck($1, $2, $3)){ #raiseObjectConversionError(); ", - [r, checkFor, token]) + var r = rdLoc(a) + var nilCheck: Rope = nil + var t = skipTypes(a.t, abstractInst) + while t.kind in {tyVar, tyLent, tyPtr, tyRef}: + if t.kind notin {tyVar, tyLent}: nilCheck = r + if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: + r = "(*$1)" % [r] + t = skipTypes(t.lastSon, abstractInst) + discard getTypeDesc(p.module, t) + if not p.module.compileToCpp: + while t.kind == tyObject and t.sons[0] != nil: + add(r, ".Sup") + t = skipTypes(t.sons[0], skipPtrs) + if nilCheck != nil: + linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n", + nilCheck, r, genTypeInfo(p.module, dest, n.info)) else: - let checkFor = genTypeInfoV1(p.module, dest, n.info) - if nilCheck != "": - linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); ", - [nilCheck, r, checkFor]) - else: - linefmt(p, cpsStmts, "if (!#isObj($1, $2)){ #raiseObjectConversionError(); ", - [r, checkFor]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] - - if n[0].typ.kind != tyObject: - if n.isLValue: - putIntoDest(p, d, n, - "(*(($1*) (&($2))))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) - else: - putIntoDest(p, d, n, + linefmt(p, cpsStmts, "#chckObj($1.m_type, $2);$n", + r, genTypeInfo(p.module, dest, n.info)) + if n.sons[0].typ.kind != tyObject: + putIntoDest(p, d, n, "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) else: putIntoDest(p, d, n, "(*($1*) ($2))" % [getTypeDesc(p.module, dest), addrLoc(p.config, a)], a.storage) proc downConv(p: BProc, n: PNode, d: var TLoc) = - var arg = n[0] - while arg.kind == nkObjDownConv: arg = arg[0] - - let dest = skipTypes(n.typ, abstractPtrs) - let src = skipTypes(arg.typ, abstractPtrs) - discard getTypeDesc(p.module, src) - let isRef = skipTypes(arg.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent} - if isRef and d.k == locNone and n.typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr} and n.isLValue: - # it can happen that we end up generating '&&x->Sup' here, so we pack - # the '&x->Sup' into a temporary and then those address is taken - # (see bug #837). However sometimes using a temporary is not correct: - # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test - # this by ensuring the destination is also a pointer: - var a: TLoc - initLocExpr(p, arg, a) - putIntoDest(p, d, n, - "(*(($1*) (&($2))))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) - elif p.module.compileToCpp: - # C++ implicitly downcasts for us - expr(p, arg, d) + if p.module.compileToCpp: + discard getTypeDesc(p.module, skipTypes(n[0].typ, abstractPtrs)) + expr(p, n.sons[0], d) # downcast does C++ for us else: + var dest = skipTypes(n.typ, abstractPtrs) + + var arg = n.sons[0] + while arg.kind == nkObjDownConv: arg = arg.sons[0] + + var src = skipTypes(arg.typ, abstractPtrs) + discard getTypeDesc(p.module, src) var a: TLoc initLocExpr(p, arg, a) - var r = rdLoc(a) & (if isRef: "->Sup" else: ".Sup") - for i in 2..abs(inheritanceDiff(dest, src)): r.add(".Sup") - putIntoDest(p, d, n, if isRef: "&" & r else: r, a.storage) + var r = rdLoc(a) + let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar, tyLent} + if isRef: + add(r, "->Sup") + else: + add(r, ".Sup") + for i in countup(2, abs(inheritanceDiff(dest, src))): add(r, ".Sup") + if isRef: + # it can happen that we end up generating '&&x->Sup' here, so we pack + # the '&x->Sup' into a temporary and then those address is taken + # (see bug #837). However sometimes using a temporary is not correct: + # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test + # this by ensuring the destination is also a pointer: + if d.k == locNone and skipTypes(n.typ, abstractInst).kind in {tyRef, tyPtr, tyVar, tyLent}: + getTemp(p, n.typ, d) + linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r) + else: + r = "&" & r + putIntoDest(p, d, n, r, a.storage) + else: + putIntoDest(p, d, n, r, a.storage) proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = let t = n.typ @@ -2845,10 +2127,8 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = if id == p.module.labels: # expression not found in the cache: inc(p.module.labels) - p.module.s[cfsData].addf("static NIM_CONST $1 $2 = ", - [getTypeDesc(p.module, t, skConst), tmp]) - genBracedInit(p, n, isConst = true, t, p.module.s[cfsData]) - p.module.s[cfsData].addf(";$n", []) + addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", + [getTypeDesc(p.module, t), tmp, genConstExpr(p, n)]) if d.k == locNone: fillLoc(d, locData, n, tmp, OnStatic) @@ -2859,74 +2139,14 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = if t.kind notin {tySequence, tyString}: d.storage = OnStatic -proc genConstSetup(p: BProc; sym: PSym): bool = - let m = p.module - useHeader(m, sym) - if sym.loc.k == locNone: - fillBackendName(p.module, sym) - fillLoc(sym.loc, locData, sym.astdef, OnStatic) - if m.hcrOn: incl(sym.loc.flags, lfIndirect) - result = lfNoDecl notin sym.loc.flags - -proc genConstHeader(m, q: BModule; p: BProc, sym: PSym) = - if sym.loc.r == "": - if not genConstSetup(p, sym): return - assert(sym.loc.r != "", $sym.name.s & $sym.itemId) - if m.hcrOn: - m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]); - m.initProc.procSec(cpsLocals).addf( - "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, - getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(q, sym)]) - else: - let headerDecl = "extern NIM_CONST $1 $2;$n" % - [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r] - m.s[cfsData].add(headerDecl) - if sfExportc in sym.flags and p.module.g.generatedHeader != nil: - p.module.g.generatedHeader.s[cfsData].add(headerDecl) - -proc genConstDefinition(q: BModule; p: BProc; sym: PSym) = - # add a suffix for hcr - will later init the global pointer with this data - let actualConstName = if q.hcrOn: sym.loc.r & "_const" else: sym.loc.r - var data = newRopeAppender() - data.addf("N_LIB_PRIVATE NIM_CONST $1 $2 = ", - [getTypeDesc(q, sym.typ), actualConstName]) - genBracedInit(q.initProc, sym.astdef, isConst = true, sym.typ, data) - data.addf(";$n", []) - q.s[cfsData].add data - if q.hcrOn: - # generate the global pointer with the real name - q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(q, sym.loc.t, skVar), sym.loc.r]) - # register it (but ignore the boolean result of hcrRegisterGlobal) - q.initProc.procSec(cpsLocals).addf( - "\thcrRegisterGlobal($1, \"$2\", sizeof($3), NULL, (void**)&$2);$n", - [getModuleDllPath(q, sym), sym.loc.r, rdLoc(sym.loc)]) - # always copy over the contents of the actual constant with the _const - # suffix ==> this means that the constant is reloadable & updatable! - q.initProc.procSec(cpsLocals).add(ropecg(q, - "\t#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n", - [sym.loc.r, actualConstName, rdLoc(sym.loc)])) - -proc genConstStmt(p: BProc, n: PNode) = - # This code is only used in the new DCE implementation. - assert useAliveDataFromDce in p.module.flags - let m = p.module - for it in n: - if it[0].kind == nkSym: - let sym = it[0].sym - if not isSimpleConst(sym.typ) and sym.itemId.item in m.alive and genConstSetup(p, sym): - genConstDefinition(m, p, sym) - proc expr(p: BProc, n: PNode, d: var TLoc) = - when defined(nimCompilerStacktraceHints): - setFrameMsg p.config$n.info & " " & $n.kind p.currLineInfo = n.info - case n.kind of nkSym: var sym = n.sym case sym.kind of skMethod: - if useAliveDataFromDce in p.module.flags or {sfDispatcher, sfForward} * sym.flags != {}: + if {sfDispatcher, sfForward} * sym.flags != {}: # we cannot produce code for the dispatcher yet: fillProcLoc(p.module, n) genProcPrototype(p.module, sym) @@ -2939,23 +2159,13 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if sfCompileTime in sym.flags: localError(p.config, n.info, "request to generate code for .compileTime proc: " & sym.name.s) - if useAliveDataFromDce in p.module.flags and sym.typ.callConv != ccInline: - fillProcLoc(p.module, n) - genProcPrototype(p.module, sym) - else: - genProc(p.module, sym) - if sym.loc.r == "" or sym.loc.lode == nil: + genProc(p.module, sym) + if sym.loc.r == nil or sym.loc.lode == nil: internalError(p.config, n.info, "expr: proc not init " & sym.name.s) putLocIntoDest(p, d, sym.loc) of skConst: if isSimpleConst(sym.typ): - var lit = newRopeAppender() - genLiteral(p, sym.astdef, sym.typ, lit) - putIntoDest(p, d, n, lit, OnStatic) - elif useAliveDataFromDce in p.module.flags: - genConstHeader(p.module, p.module, p, sym) - assert((sym.loc.r != "") and (sym.loc.t != nil)) - putLocIntoDest(p, d, sym.loc) + putIntoDest(p, d, n, genLiteral(p, sym.ast, sym.typ), OnStatic) else: genComplexConst(p, sym, d) of skEnumField: @@ -2966,10 +2176,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of skVar, skForVar, skResult, skLet: if {sfGlobal, sfThread} * sym.flags != {}: genVarPrototype(p.module, n) - if sfCompileTime in sym.flags: - genSingleVar(p, sym, n, astdef(sym)) - - if sym.loc.r == "" or sym.loc.t == nil: + if sym.loc.r == nil or sym.loc.t == nil: #echo "FAILED FOR PRCO ", p.prc.name.s #echo renderTree(p.prc.ast, {renderIds}) internalError p.config, n.info, "expr: var not init " & sym.name.s & "_" & $sym.id @@ -2982,19 +2189,13 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = else: putLocIntoDest(p, d, sym.loc) of skTemp: - when false: - # this is more harmful than helpful. - if sym.loc.r == "": - # we now support undeclared 'skTemp' variables for easier - # transformations in other parts of the compiler: - assignLocalVar(p, n) - if sym.loc.r == "" or sym.loc.t == nil: + if sym.loc.r == nil or sym.loc.t == nil: #echo "FAILED FOR PRCO ", p.prc.name.s #echo renderTree(p.prc.ast, {renderIds}) internalError(p.config, n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id) putLocIntoDest(p, d, sym.loc) of skParam: - if sym.loc.r == "" or sym.loc.t == nil: + if sym.loc.r == nil or sym.loc.t == nil: # echo "FAILED FOR PRCO ", p.prc.name.s # debug p.prc.typ.n # echo renderTree(p.prc.ast, {renderIds}) @@ -3003,21 +2204,16 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = else: internalError(p.config, n.info, "expr(" & $sym.kind & "); unknown symbol") of nkNilLit: if not isEmptyType(n.typ): - var lit = newRopeAppender() - genLiteral(p, n, lit) - putIntoDest(p, d, n, lit) + putIntoDest(p, d, n, genLiteral(p, n)) of nkStrLit..nkTripleStrLit: - var lit = newRopeAppender() - genLiteral(p, n, lit) - putDataIntoDest(p, d, n, lit) - of nkIntLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkCharLit: - var lit = newRopeAppender() - genLiteral(p, n, lit) - putIntoDest(p, d, n, lit) + putDataIntoDest(p, d, n, genLiteral(p, n)) + of nkIntLit..nkUInt64Lit, + nkFloatLit..nkFloat128Lit, nkCharLit: + putIntoDest(p, d, n, genLiteral(p, n)) of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: - genLineDir(p, n) # may be redundant, it is generated in fixupCall as well - let op = n[0] + genLineDir(p, n) + let op = n.sons[0] if n.typ.isNil: # discard the value: var a: TLoc @@ -3033,9 +2229,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = genCall(p, n, d) of nkCurly: if isDeepConstExpr(n) and n.len != 0: - var lit = newRopeAppender() - genSetNode(p, n, lit) - putIntoDest(p, d, n, lit) + putIntoDest(p, d, n, genSetNode(p, n)) else: genSetConstr(p, n, d) of nkBracket: @@ -3046,25 +2240,14 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = else: genArrayConstr(p, n, d) of nkPar, nkTupleConstr: - if n.typ != nil and n.typ.kind == tyProc and n.len == 2: - genClosure(p, n, d) - elif isDeepConstExpr(n) and n.len != 0: + if isDeepConstExpr(n) and n.len != 0: exprComplexConst(p, n, d) else: genTupleConstr(p, n, d) of nkObjConstr: genObjConstr(p, n, d) of nkCast: genCast(p, n, d) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d) - of nkHiddenAddr: - if n[0].kind == nkDerefExpr: - # addr ( deref ( x )) --> x - var x = n[0][0] - if n.typ.skipTypes(abstractVar).kind != tyOpenArray: - x.typ = n.typ - expr(p, x, d) - return - genAddr(p, n, d) - of nkAddr: genAddr(p, n, d) + of nkHiddenAddr, nkAddr: genAddr(p, n, d) of nkBracketExpr: genBracketExpr(p, n, d) of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d) of nkDotExpr: genRecordField(p, n, d) @@ -3075,16 +2258,18 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkIfExpr, nkIfStmt: genIf(p, n, d) of nkWhen: # This should be a "when nimvm" node. - expr(p, n[1][0], d) + expr(p, n.sons[1].sons[0], d) of nkObjDownConv: downConv(p, n, d) of nkObjUpConv: upConv(p, n, d) - of nkChckRangeF, nkChckRange64, nkChckRange: genRangeChck(p, n, d) + of nkChckRangeF: genRangeChck(p, n, d, "chckRangeF") + of nkChckRange64: genRangeChck(p, n, d, "chckRange64") + of nkChckRange: genRangeChck(p, n, d, "chckRange") of nkStringToCString: convStrToCStr(p, n, d) of nkCStringToString: convCStrToStr(p, n, d) of nkLambdaKinds: - var sym = n[namePos].sym + var sym = n.sons[namePos].sym genProc(p.module, sym) - if sym.loc.r == "" or sym.loc.lode == nil: + if sym.loc.r == nil or sym.loc.lode == nil: internalError(p.config, n.info, "expr: proc not init " & sym.name.s) putLocIntoDest(p, d, sym.loc) of nkClosure: genClosure(p, n, d) @@ -3092,20 +2277,15 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkEmpty: discard of nkWhileStmt: genWhileStmt(p, n) of nkVarSection, nkLetSection: genVarStmt(p, n) - of nkConstSection: - if useAliveDataFromDce in p.module.flags: - genConstStmt(p, n) - # else: consts generated lazily on use + of nkConstSection: discard # consts generated lazily on use of nkForStmt: internalError(p.config, n.info, "for statement not eliminated") of nkCaseStmt: genCase(p, n, d) of nkReturnStmt: genReturnStmt(p, n) of nkBreakStmt: genBreakStmt(p, n) of nkAsgn: - cow(p, n[1]) if nfPreventCg notin n.flags: genAsgn(p, n, fastAsgn=false) - of nkFastAsgn, nkSinkAsgn: - cow(p, n[1]) + of nkFastAsgn: if nfPreventCg notin n.flags: # transf is overly aggressive with 'nkFastAsgn', so we work around here. # See tests/run/tcnstseq3 for an example that would fail otherwise. @@ -3115,17 +2295,21 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if ex.kind != nkEmpty: genLineDir(p, n) var a: TLoc - initLocExprSingleUse(p, ex, a) - line(p, cpsStmts, "(void)(" & a.r & ");\L") + if ex.kind in nkCallKinds and (ex[0].kind != nkSym or + ex[0].sym.magic == mNone): + # bug #6037: do not assign to a temp in C++ mode: + incl a.flags, lfSingleUse + genCall(p, ex, a) + if lfSingleUse notin a.flags: + line(p, cpsStmts, a.r & ";\L") + else: + initLocExpr(p, ex, a) of nkAsmStmt: genAsmStmt(p, n) - of nkTryStmt, nkHiddenTryStmt: - case p.config.exc - of excGoto: - genTryGoto(p, n, d) - of excCpp: + of nkTryStmt: + if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions: genTryCpp(p, n, d) else: - genTrySetjmp(p, n, d) + genTry(p, n, d) of nkRaiseStmt: genRaiseStmt(p, n) of nkTypeSection: # we have to emit the type information for object types here to support @@ -3136,341 +2320,174 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard of nkPragma: genPragma(p, n) - of nkPragmaBlock: - var inUncheckedAssignSection = 0 - let pragmaList = n[0] - for pi in pragmaList: - if whichPragma(pi) == wCast: - case whichPragma(pi[1]) - of wUncheckedAssign: - inUncheckedAssignSection = 1 - else: - discard - - inc p.inUncheckedAssignSection, inUncheckedAssignSection - expr(p, n.lastSon, d) - dec p.inUncheckedAssignSection, inUncheckedAssignSection - + of nkPragmaBlock: expr(p, n.lastSon, d) of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef: - if n[genericParamsPos].kind == nkEmpty: - var prc = n[namePos].sym - if useAliveDataFromDce in p.module.flags: - if p.module.alive.contains(prc.itemId.item) and - prc.magic in generatedMagics: - genProc(p.module, prc) - elif prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags: + if n.sons[genericParamsPos].kind == nkEmpty: + var prc = n.sons[namePos].sym + # due to a bug/limitation in the lambda lifting, unused inner procs + # are not transformed correctly. We work around this issue (#411) here + # by ensuring it's no inner proc (owner is a module): + if prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags: if ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or (prc.kind == skMethod): - # due to a bug/limitation in the lambda lifting, unused inner procs - # are not transformed correctly. We work around this issue (#411) here - # by ensuring it's no inner proc (owner is a module). - # Generate proc even if empty body, bugfix #11651. - genProc(p.module, prc) + # we have not only the header: + if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags: + genProc(p.module, prc) of nkParForStmt: genParForStmt(p, n) of nkState: genState(p, n) - of nkGotoState: - # simply never set it back to 0 here from here on... - inc p.splitDecls - genGotoState(p, n) + of nkGotoState: genGotoState(p, n) of nkBreakState: genBreakState(p, n, d) - of nkMixinStmt, nkBindStmt: discard else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind") -proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Rope) = - var t = skipTypes(typ, abstractRange+{tyOwned}-{tyTypeDesc}) +proc genNamedConstExpr(p: BProc, n: PNode): Rope = + if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1]) + else: result = genConstExpr(p, n) + +proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = + var t = skipTypes(typ, abstractRange-{tyTypeDesc}) case t.kind - of tyBool: result.add rope"NIM_FALSE" - of tyEnum, tyChar, tyInt..tyInt64, tyUInt..tyUInt64: result.add rope"0" - of tyFloat..tyFloat128: result.add rope"0.0" - of tyCstring, tyVar, tyLent, tyPointer, tyPtr, tyUntyped, - tyTyped, tyTypeDesc, tyStatic, tyRef, tyNil: - result.add rope"NIM_NIL" - of tyString, tySequence: - if optSeqDestructors in p.config.globalOptions: - result.add "{0, NIM_NIL}" - else: - result.add "NIM_NIL" + of tyBool: result = rope"NIM_FALSE" + of tyEnum, tyChar, tyInt..tyInt64, tyUInt..tyUInt64: result = rope"0" + of tyFloat..tyFloat128: result = rope"0.0" + of tyCString, tyString, tyVar, tyLent, tyPointer, tyPtr, tySequence, tyExpr, + tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil: + result = rope"NIM_NIL" of tyProc: if t.callConv != ccClosure: - result.add "NIM_NIL" + result = rope"NIM_NIL" else: - result.add "{NIM_NIL, NIM_NIL}" + result = rope"{NIM_NIL, NIM_NIL}" of tyObject: - var count = 0 - result.add "{" - getNullValueAuxT(p, t, t, t.n, nil, result, count, true, info) - result.add "}" + if not isObjLackingTypeField(t) and not p.module.compileToCpp: + result = "{{$1}}" % [genTypeInfo(p.module, t, info)] + else: + result = rope"{}" of tyTuple: - result.add "{" - if p.vccAndC and t.len == 0: - result.add "0" - for i in 0.. 0: result.add ", " - getDefaultValue(p, t[i], info, result) + result.add getDefaultValue(p, typ.sons[i], info) result.add "}" - of tyArray: - result.add "{" - for i in 0.. 0: result.add ", " - getDefaultValue(p, t.sons[1], info, result) - result.add "}" - #result = rope"{}" - of tyOpenArray, tyVarargs: - result.add "{NIM_NIL, 0}" + of tyArray: result = rope"{}" of tySet: - if mapSetType(p.config, t) == ctArray: result.add "{}" - else: result.add "0" + if mapType(p.config, t) == ctArray: result = rope"{}" + else: result = rope"0" else: globalError(p.config, info, "cannot create null element for: " & $t.kind) -proc caseObjDefaultBranch(obj: PNode; branch: Int128): int = - for i in 1 ..< obj.len: - for j in 0 .. obj[i].len - 2: - if obj[i][j].kind == nkRange: - let x = getOrdValue(obj[i][j][0]) - let y = getOrdValue(obj[i][j][1]) - if branch >= x and branch <= y: - return i - elif getOrdValue(obj[i][j]) == branch: - return i - if obj[i].len == 1: - # else branch - return i - assert(false, "unreachable") - -proc isEmptyCaseObjectBranch(n: PNode): bool = - for it in n: - if it.kind == nkSym and not isEmptyType(it.sym.typ): return false - return true - -proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode, - result: var Rope; count: var int; - isConst: bool, info: TLineInfo) = +proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; count: var int) = case obj.kind of nkRecList: for it in obj.sons: - getNullValueAux(p, t, it, constOrNil, result, count, isConst, info) + getNullValueAux(p, t, it, cons, result, count) of nkRecCase: - getNullValueAux(p, t, obj[0], constOrNil, result, count, isConst, info) - if count > 0: result.add ", " - var branch = Zero - if constOrNil != nil: - ## find kind value, default is zero if not specified - for i in 1.. 0: result.add ", " inc count let field = obj.sym - if constOrNil != nil: - for i in 1.. 0: result.add ",\n" - if it.kind == nkExprColonExpr: genBracedInit(p, it[1], isConst, it[0].typ, result) - else: genBracedInit(p, it, isConst, it.typ, result) - result.add("}\n") +proc genConstSimpleList(p: BProc, n: PNode): Rope = + var length = sonsLen(n) + result = rope("{") + let t = n.typ.skipTypes(abstractInst) + for i in countup(0, length - 2): + addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])]) + if length > 0: + add(result, genNamedConstExpr(p, n.sons[length - 1])) + addf(result, "}$n", []) -proc genConstTuple(p: BProc, n: PNode; isConst: bool; tup: PType; result: var Rope) = - result.add "{" - if p.vccAndC and n.len == 0: - result.add "0" - for i in 0.. 0: result.add ",\n" - if it.kind == nkExprColonExpr: genBracedInit(p, it[1], isConst, tup[i], result) - else: genBracedInit(p, it, isConst, tup[i], result) - result.add("}\n") - -proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool; result: var Rope) = +proc genConstSeq(p: BProc, n: PNode, t: PType): Rope = var data = "{{$1, $1 | NIM_STRLIT_FLAG}" % [n.len.rope] - let base = t.skipTypes(abstractInst)[0] if n.len > 0: # array part needs extra curlies: data.add(", {") - for i in 0.. 0: data.addf(",$n", []) - genBracedInit(p, n[i], isConst, base, data) + data.add genConstExpr(p, n.sons[i]) data.add("}") data.add("}") - let tmpName = getTempName(p.module) + result = getTempName(p.module) + let base = t.skipTypes(abstractInst).sons[0] - appcg(p.module, cfsStrData, - "static $5 struct {$n" & + appcg(p.module, cfsData, + "NIM_CONST struct {$n" & " #TGenericSeq Sup;$n" & " $1 data[$2];$n" & "} $3 = $4;$n", [ - getTypeDesc(p.module, base), n.len, tmpName, data, - if isConst: "NIM_CONST" else: ""]) + getTypeDesc(p.module, base), n.len.rope, result, data]) - result.add "(($1)&$2)" % [getTypeDesc(p.module, t), tmpName] + result = "(($1)&$2)" % [getTypeDesc(p.module, t), result] -proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool; result: var Rope) = - let base = t.skipTypes(abstractInst)[0] - var data = rope"{" - for i in 0.. 0: data.addf(",$n", []) - genBracedInit(p, n[i], isConst, base, data) - data.add("}") - - let payload = getTempName(p.module) - - appcg(p.module, cfsStrData, - "static $5 struct {$n" & - " NI cap; $1 data[$2];$n" & - "} $3 = {$2 | NIM_STRLIT_FLAG, $4};$n", [ - getTypeDesc(p.module, base), n.len, payload, data, - if isConst: "const" else: ""]) - result.add "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload] - -proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; result: var Rope) = +proc genConstExpr(p: BProc, n: PNode): Rope = case n.kind of nkHiddenStdConv, nkHiddenSubConv: - genBracedInit(p, n[1], isConst, n.typ, result) + result = genConstExpr(p, n.sons[1]) + of nkCurly: + var cs: TBitSet + toBitSet(p.config, n, cs) + result = genRawSetData(cs, int(getSize(p.config, n.typ))) + of nkBracket, nkPar, nkTupleConstr, nkClosure: + var t = skipTypes(n.typ, abstractInst) + if t.kind == tySequence: + result = genConstSeq(p, n, n.typ) + elif t.kind == tyProc and t.callConv == ccClosure and not n.sons.isNil and + n.sons[0].kind == nkNilLit and n.sons[1].kind == nkNilLit: + # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL} + # this behaviour is needed since closure_var = nil must be + # expanded to {NIM_NIL,NIM_NIL} + # in VM closures are initialized with nkPar(nkNilLit, nkNilLit) + # leading to duplicate code like this: + # "{NIM_NIL,NIM_NIL}, {NIM_NIL,NIM_NIL}" + result = ~"{NIM_NIL,NIM_NIL}" + else: + result = genConstSimpleList(p, n) + of nkObjConstr: + result = genConstObjConstr(p, n) else: - var ty = tyNone - var typ: PType = nil - if optionalType == nil: - if n.kind in nkStrKinds: - ty = tyString - else: - internalError(p.config, n.info, "node has no type") - else: - typ = skipTypes(optionalType, abstractInstOwned + {tyStatic}) - ty = typ.kind - case ty - of tySet: - let cs = toBitSet(p.config, n) - genRawSetData(cs, int(getSize(p.config, n.typ)), result) - of tySequence: - if optSeqDestructors in p.config.globalOptions: - genConstSeqV2(p, n, typ, isConst, result) - else: - genConstSeq(p, n, typ, isConst, result) - of tyProc: - if typ.callConv == ccClosure and n.safeLen > 1 and n[1].kind == nkNilLit: - # n.kind could be: nkClosure, nkTupleConstr and maybe others; `n.safeLen` - # guards against the case of `nkSym`, refs bug #14340. - # Conversion: nimcall -> closure. - # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL} - # this behaviour is needed since closure_var = nil must be - # expanded to {NIM_NIL,NIM_NIL} - # in VM closures are initialized with nkPar(nkNilLit, nkNilLit) - # leading to duplicate code like this: - # "{NIM_NIL,NIM_NIL}, {NIM_NIL,NIM_NIL}" - if n[0].kind == nkNilLit: - result.add "{NIM_NIL,NIM_NIL}" - else: - var d: TLoc - initLocExpr(p, n[0], d) - result.add "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, typ, clHalfWithEnv), rdLoc(d)] - else: - var d: TLoc - initLocExpr(p, n, d) - result.add rdLoc(d) - of tyArray, tyVarargs: - genConstSimpleList(p, n, isConst, result) - of tyTuple: - genConstTuple(p, n, isConst, typ, result) - of tyOpenArray: - if n.kind != nkBracket: - internalError(p.config, n.info, "const openArray expression is not an array construction") - - var data = newRopeAppender() - genConstSimpleList(p, n, isConst, data) - - let payload = getTempName(p.module) - let ctype = getTypeDesc(p.module, typ[0]) - let arrLen = n.len - appcg(p.module, cfsStrData, - "static $5 $1 $3[$2] = $4;$n", [ - ctype, arrLen, payload, data, - if isConst: "const" else: ""]) - result.add "{($1*)&$2, $3}" % [ctype, payload, rope arrLen] - - of tyObject: - genConstObjConstr(p, n, isConst, result) - of tyString, tyCstring: - if optSeqDestructors in p.config.globalOptions and n.kind != nkNilLit and ty == tyString: - genStringLiteralV2Const(p.module, n, isConst, result) - else: - var d: TLoc - initLocExpr(p, n, d) - result.add rdLoc(d) - else: - var d: TLoc - initLocExpr(p, n, d) - result.add rdLoc(d) + var d: TLoc + initLocExpr(p, n, d) + result = rdLoc(d) diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim index cbef6771f..cfe71375e 100644 --- a/compiler/ccgliterals.nim +++ b/compiler/ccgliterals.nim @@ -7,8 +7,6 @@ # distribution, for details about the copyright. # -# included from cgen.nim - ## This include file contains the logic to produce constant string ## and seq literals. The code here is responsible that ## ``const x = ["a", "b"]`` works without hidden runtime creation code. @@ -21,7 +19,7 @@ template detectVersion(field, corename) = if core == nil or core.kind != skConst: m.g.field = 1 else: - m.g.field = toInt(ast.getInt(core.astdef)) + m.g.field = int ast.getInt(core.ast) result = m.g.field proc detectStrVersion(m: BModule): int = @@ -32,87 +30,62 @@ proc detectSeqVersion(m: BModule): int = # ----- Version 1: GC'ed strings and seqs -------------------------------- -proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) = - cgsym(m, "TGenericSeq") - let tmp = getTempName(m) - result.add tmp - m.s[cfsStrData].addf("STRING_LITERAL($1, $2, $3);$n", - [tmp, makeCString(s), rope(s.len)]) +proc genStringLiteralDataOnlyV1(m: BModule, s: string): Rope = + discard cgsym(m, "TGenericSeq") + result = getTempName(m) + addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n", + [result, makeCString(s), rope(len(s))]) -proc genStringLiteralV1(m: BModule; n: PNode; result: var Rope) = +proc genStringLiteralV1(m: BModule; n: PNode): Rope = if s.isNil: - appcg(m, result, "((#NimStringDesc*) NIM_NIL)", []) + result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", []) else: let id = nodeTableTestOrSet(m.dataCache, n, m.labels) if id == m.labels: # string literal not found in the cache: - appcg(m, result, "((#NimStringDesc*) &", []) - genStringLiteralDataOnlyV1(m, n.strVal, result) - result.add ")" + result = ropecg(m, "((#NimStringDesc*) &$1)", + [genStringLiteralDataOnlyV1(m, n.strVal)]) else: - appcg(m, result, "((#NimStringDesc*) &$1$2)", - [m.tmpBase, id]) + result = ropecg(m, "((#NimStringDesc*) &$1$2)", + [m.tmpBase, rope(id)]) # ------ Version 2: destructor based strings and seqs ----------------------- -proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) = - m.s[cfsStrData].addf("static $4 struct {$n" & - " NI cap; NIM_CHAR data[$2+1];$n" & - "} $1 = { $2 | NIM_STRLIT_FLAG, $3 };$n", - [result, rope(s.len), makeCString(s), - rope(if isConst: "const" else: "")]) +proc genStringLiteralDataOnlyV2(m: BModule, s: string): Rope = + result = getTempName(m) + addf(m.s[cfsData], " static const NIM_CHAR $1[$2] = $3;$n", + [result, rope(len(s)+1), makeCString(s)]) -proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Rope) = +proc genStringLiteralV2(m: BModule; n: PNode): Rope = let id = nodeTableTestOrSet(m.dataCache, n, m.labels) if id == m.labels: - let pureLit = getTempName(m) - genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst) - let tmp = getTempName(m) - result.add tmp - cgsym(m, "NimStrPayload") - cgsym(m, "NimStringV2") # string literal not found in the cache: - m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n", - [tmp, rope(n.strVal.len), pureLit, rope(if isConst: "const" else: "")]) + let pureLit = genStringLiteralDataOnlyV2(m, n.strVal) + result = getTempName(m) + addf(m.s[cfsData], "static const #NimStringV2 $1 = {$2, $2, $3};$n", + [result, rope(len(n.strVal)+1), pureLit]) else: - let tmp = getTempName(m) - result.add tmp - m.s[cfsStrData].addf("static $4 NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n", - [tmp, rope(n.strVal.len), m.tmpBase & rope(id), - rope(if isConst: "const" else: "")]) - -proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Rope) = - let id = nodeTableTestOrSet(m.dataCache, n, m.labels) - var pureLit: Rope - if id == m.labels: - pureLit = getTempName(m) - cgsym(m, "NimStrPayload") - cgsym(m, "NimStringV2") - # string literal not found in the cache: - genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst) - else: - pureLit = m.tmpBase & rope(id) - result.addf "{$1, (NimStrPayload*)&$2}", [rope(n.strVal.len), pureLit] + result = m.tmpBase & rope(id) # ------ Version selector --------------------------------------------------- -proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo; - isConst: bool; result: var Rope) = +proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope = case detectStrVersion(m) - of 0, 1: genStringLiteralDataOnlyV1(m, s, result) - of 2: - let tmp = getTempName(m) - genStringLiteralDataOnlyV2(m, s, tmp, isConst) - result.add tmp + of 0, 1: result = genStringLiteralDataOnlyV1(m, s) + of 2: result = genStringLiteralDataOnlyV2(m, s) else: localError(m.config, info, "cannot determine how to produce code for string literal") -proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Rope) = - appcg(m, result, "((#NimStringDesc*) NIM_NIL)", []) +proc genStringLiteralFromData(m: BModule; data: Rope; info: TLineInfo): Rope = + result = ropecg(m, "((#NimStringDesc*) &$1)", + [data]) -proc genStringLiteral(m: BModule; n: PNode; result: var Rope) = +proc genNilStringLiteral(m: BModule; info: TLineInfo): Rope = + result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", []) + +proc genStringLiteral(m: BModule; n: PNode): Rope = case detectStrVersion(m) - of 0, 1: genStringLiteralV1(m, n, result) - of 2: genStringLiteralV2(m, n, isConst = true, result) + of 0, 1: result = genStringLiteralV1(m, n) + of 2: result = genStringLiteralV2(m, n) else: localError(m.config, n.info, "cannot determine how to produce code for string literal") diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim new file mode 100644 index 000000000..664f89b73 --- /dev/null +++ b/compiler/ccgmerge.nim @@ -0,0 +1,296 @@ +# +# +# The Nim Compiler +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements the merge operation of 2 different C files. This +## is needed for incremental compilation. + +import + ast, astalgo, ropes, options, strutils, nimlexbase, msgs, cgendata, rodutils, + intsets, platform, llstream, tables, sighashes + +# Careful! Section marks need to contain a tabulator so that they cannot +# be part of C string literals. + +const + CFileSectionNames: array[TCFileSection, string] = [ + cfsMergeInfo: "", + cfsHeaders: "NIM_merge_HEADERS", + cfsForwardTypes: "NIM_merge_FORWARD_TYPES", + cfsTypes: "NIM_merge_TYPES", + cfsSeqTypes: "NIM_merge_SEQ_TYPES", + cfsFieldInfo: "NIM_merge_FIELD_INFO", + cfsTypeInfo: "NIM_merge_TYPE_INFO", + cfsProcHeaders: "NIM_merge_PROC_HEADERS", + cfsVars: "NIM_merge_VARS", + cfsData: "NIM_merge_DATA", + cfsProcs: "NIM_merge_PROCS", + cfsInitProc: "NIM_merge_INIT_PROC", + cfsTypeInit1: "NIM_merge_TYPE_INIT1", + cfsTypeInit2: "NIM_merge_TYPE_INIT2", + cfsTypeInit3: "NIM_merge_TYPE_INIT3", + cfsDebugInit: "NIM_merge_DEBUG_INIT", + cfsDynLibInit: "NIM_merge_DYNLIB_INIT", + cfsDynLibDeinit: "NIM_merge_DYNLIB_DEINIT", + ] + CProcSectionNames: array[TCProcSection, string] = [ + cpsLocals: "NIM_merge_PROC_LOCALS", + cpsInit: "NIM_merge_PROC_INIT", + cpsStmts: "NIM_merge_PROC_BODY" + ] + NimMergeEndMark = "/*\tNIM_merge_END:*/" + +proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope = + if compilationCachePresent(conf): + result = nil + add(result, "\n/*\t") + add(result, CFileSectionNames[fs]) + add(result, ":*/\n") + +proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope = + if compilationCachePresent(conf): + result = rope(NimMergeEndMark & "\n") + +proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope = + if compilationCachePresent(conf): + result = rope(nil) + add(result, "\n/*\t") + add(result, CProcSectionNames[ps]) + add(result, ":*/\n") + +proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope = + if compilationCachePresent(conf): + result = rope(NimMergeEndMark & "\n") + +proc writeTypeCache(a: TypeCache, s: var string) = + var i = 0 + for id, value in pairs(a): + if i == 10: + i = 0 + s.add('\L') + else: + s.add(' ') + encodeStr($id, s) + s.add(':') + encodeStr($value, s) + inc i + s.add('}') + +proc writeIntSet(a: IntSet, s: var string) = + var i = 0 + for x in items(a): + if i == 10: + i = 0 + s.add('\L') + else: + s.add(' ') + encodeVInt(x, s) + inc i + s.add('}') + +proc genMergeInfo*(m: BModule): Rope = + if not compilationCachePresent(m.config): return nil + var s = "/*\tNIM_merge_INFO:\n" + s.add("typeCache:{") + writeTypeCache(m.typeCache, s) + s.add("declared:{") + writeIntSet(m.declaredThings, s) + when false: + s.add("typeInfo:{") + writeIntSet(m.typeInfoMarker, s) + s.add("labels:") + encodeVInt(m.labels, s) + s.add(" flags:") + encodeVInt(cast[int](m.flags), s) + s.add("\n*/") + result = s.rope + +template `^`(pos: int): untyped = L.buf[pos] + +proc skipWhite(L: var TBaseLexer) = + var pos = L.bufpos + while true: + case ^pos + of CR: pos = nimlexbase.handleCR(L, pos) + of LF: pos = nimlexbase.handleLF(L, pos) + of ' ': inc pos + else: break + L.bufpos = pos + +proc skipUntilCmd(L: var TBaseLexer) = + var pos = L.bufpos + while true: + case ^pos + of CR: pos = nimlexbase.handleCR(L, pos) + of LF: pos = nimlexbase.handleLF(L, pos) + of '\0': break + of '/': + if ^(pos+1) == '*' and ^(pos+2) == '\t': + inc pos, 3 + break + inc pos + else: inc pos + L.bufpos = pos + +proc atEndMark(buf: cstring, pos: int): bool = + var s = 0 + while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s + result = s == NimMergeEndMark.len + +proc readVerbatimSection(L: var TBaseLexer): Rope = + var pos = L.bufpos + var buf = L.buf + var r = newStringOfCap(30_000) + while true: + case buf[pos] + of CR: + pos = nimlexbase.handleCR(L, pos) + buf = L.buf + r.add('\L') + of LF: + pos = nimlexbase.handleLF(L, pos) + buf = L.buf + r.add('\L') + of '\0': + doAssert(false, "ccgmerge: expected: " & NimMergeEndMark) + break + else: + if atEndMark(buf, pos): + inc pos, NimMergeEndMark.len + break + r.add(buf[pos]) + inc pos + L.bufpos = pos + result = r.rope + +proc readKey(L: var TBaseLexer, result: var string) = + var pos = L.bufpos + var buf = L.buf + setLen(result, 0) + while buf[pos] in IdentChars: + result.add(buf[pos]) + inc pos + if buf[pos] != ':': doAssert(false, "ccgmerge: ':' expected") + L.bufpos = pos + 1 # skip ':' + +proc newFakeType(id: int): PType = + new(result) + result.id = id + +proc readTypeCache(L: var TBaseLexer, result: var TypeCache) = + if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected") + inc L.bufpos + while ^L.bufpos != '}': + skipWhite(L) + var key = decodeStr(L.buf, L.bufpos) + if ^L.bufpos != ':': doAssert(false, "ccgmerge: ':' expected") + inc L.bufpos + var value = decodeStr(L.buf, L.bufpos) + # XXX implement me + when false: + idTablePut(result, newFakeType(key), value.rope) + inc L.bufpos + +proc readIntSet(L: var TBaseLexer, result: var IntSet) = + if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected") + inc L.bufpos + while ^L.bufpos != '}': + skipWhite(L) + var key = decodeVInt(L.buf, L.bufpos) + result.incl(key) + inc L.bufpos + +proc processMergeInfo(L: var TBaseLexer, m: BModule) = + var k = newStringOfCap("typeCache".len) + while true: + skipWhite(L) + if ^L.bufpos == '*' and ^(L.bufpos+1) == '/': + inc(L.bufpos, 2) + break + readKey(L, k) + case k + of "typeCache": readTypeCache(L, m.typeCache) + of "declared": readIntSet(L, m.declaredThings) + of "typeInfo": + when false: readIntSet(L, m.typeInfoMarker) + of "labels": m.labels = decodeVInt(L.buf, L.bufpos) + of "flags": + m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0) + else: doAssert(false, "ccgmerge: unknown key: " & k) + +when not defined(nimhygiene): + {.pragma: inject.} + +template withCFile(cfilename: string, body: untyped) = + var s = llStreamOpen(cfilename, fmRead) + if s == nil: return + var L {.inject.}: TBaseLexer + openBaseLexer(L, s) + var k {.inject.} = newStringOfCap("NIM_merge_FORWARD_TYPES".len) + while true: + skipUntilCmd(L) + if ^L.bufpos == '\0': break + body + closeBaseLexer(L) + +proc readMergeInfo*(cfilename: string, m: BModule) = + ## reads the merge meta information into `m`. + withCFile(cfilename): + readKey(L, k) + if k == "NIM_merge_INFO": + processMergeInfo(L, m) + break + +type + TMergeSections = object + f: TCFileSections + p: TCProcSections + +proc readMergeSections(cfilename: string, m: var TMergeSections) = + ## reads the merge sections into `m`. + withCFile(cfilename): + readKey(L, k) + if k == "NIM_merge_INFO": + discard + elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/': + inc(L.bufpos, 2) + # read back into section + skipWhite(L) + var verbatim = readVerbatimSection(L) + skipWhite(L) + var sectionA = CFileSectionNames.find(k) + if sectionA > 0 and sectionA <= high(TCFileSection).int: + m.f[TCFileSection(sectionA)] = verbatim + else: + var sectionB = CProcSectionNames.find(k) + if sectionB >= 0 and sectionB <= high(TCProcSection).int: + m.p[TCProcSection(sectionB)] = verbatim + else: + doAssert(false, "ccgmerge: unknown section: " & k) + else: + doAssert(false, "ccgmerge: '*/' expected") + +proc mergeRequired*(m: BModule): bool = + for i in cfsHeaders..cfsProcs: + if m.s[i] != nil: + #echo "not empty: ", i, " ", m.s[i] + return true + for i in low(TCProcSection)..high(TCProcSection): + if m.initProc.s(i) != nil: + #echo "not empty: ", i, " ", m.initProc.s[i] + return true + +proc mergeFiles*(cfilename: string, m: BModule) = + ## merges the C file with the old version on hard disc. + var old: TMergeSections + readMergeSections(cfilename, old) + # do the merge; old section before new section: + for i in low(TCFileSection)..high(TCFileSection): + m.s[i] = old.f[i] & m.s[i] + for i in low(TCProcSection)..high(TCProcSection): + m.initProc.s(i) = old.p[i] & m.initProc.s(i) diff --git a/compiler/ccgmerge_unused.nim b/compiler/ccgmerge_unused.nim deleted file mode 100644 index a1413034f..000000000 --- a/compiler/ccgmerge_unused.nim +++ /dev/null @@ -1,283 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements the merge operation of 2 different C files. This -## is needed for incremental compilation. - -import - ast, ropes, options, strutils, nimlexbase, cgendata, rodutils, - intsets, llstream, tables, modulegraphs, pathutils - -# Careful! Section marks need to contain a tabulator so that they cannot -# be part of C string literals. - -const - CFileSectionNames: array[TCFileSection, string] = [ - cfsHeaders: "NIM_merge_HEADERS", - cfsFrameDefines: "NIM_merge_FRAME_DEFINES", - cfsForwardTypes: "NIM_merge_FORWARD_TYPES", - cfsTypes: "NIM_merge_TYPES", - cfsSeqTypes: "NIM_merge_SEQ_TYPES", - cfsTypeInfo: "NIM_merge_TYPE_INFO", - cfsProcHeaders: "NIM_merge_PROC_HEADERS", - cfsData: "NIM_merge_DATA", - cfsVars: "NIM_merge_VARS", - cfsProcs: "NIM_merge_PROCS", - cfsInitProc: "NIM_merge_INIT_PROC", - cfsDatInitProc: "NIM_merge_DATINIT_PROC", - cfsTypeInit1: "NIM_merge_TYPE_INIT1", - cfsTypeInit3: "NIM_merge_TYPE_INIT3", - cfsDynLibInit: "NIM_merge_DYNLIB_INIT" - ] - CProcSectionNames: array[TCProcSection, string] = [ - cpsLocals: "NIM_merge_PROC_LOCALS", - cpsInit: "NIM_merge_PROC_INIT", - cpsStmts: "NIM_merge_PROC_BODY" - ] - NimMergeEndMark = "/*\tNIM_merge_END:*/" - -proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope = - # useful for debugging and only adds at most a few lines in each file - result.add("\n/* section: ") - result.add(CFileSectionNames[fs]) - result.add(" */\n") - if compilationCachePresent(conf): - result = nil - result.add("\n/*\t") - result.add(CFileSectionNames[fs]) - result.add(":*/\n") - -proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope = - if compilationCachePresent(conf): - result = rope(NimMergeEndMark & "\n") - -proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope = - if compilationCachePresent(conf): - result = rope("") - result.add("\n/*\t") - result.add(CProcSectionNames[ps]) - result.add(":*/\n") - -proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope = - if compilationCachePresent(conf): - result = rope(NimMergeEndMark & "\n") - -proc writeTypeCache(a: TypeCache, s: var string) = - var i = 0 - for id, value in pairs(a): - if i == 10: - i = 0 - s.add('\L') - else: - s.add(' ') - encodeStr($id, s) - s.add(':') - encodeStr($value, s) - inc i - s.add('}') - -proc writeIntSet(a: IntSet, s: var string) = - var i = 0 - for x in items(a): - if i == 10: - i = 0 - s.add('\L') - else: - s.add(' ') - encodeVInt(x, s) - inc i - s.add('}') - -proc genMergeInfo*(m: BModule): Rope = - if not compilationCachePresent(m.config): return nil - var s = "/*\tNIM_merge_INFO:\n" - s.add("typeCache:{") - writeTypeCache(m.typeCache, s) - s.add("declared:{") - writeIntSet(m.declaredThings, s) - when false: - s.add("typeInfo:{") - writeIntSet(m.typeInfoMarker, s) - s.add("labels:") - encodeVInt(m.labels, s) - s.add(" flags:") - encodeVInt(cast[int](m.flags), s) - s.add("\n*/") - result = s.rope - -template `^`(pos: int): untyped = L.buf[pos] - -proc skipWhite(L: var TBaseLexer) = - var pos = L.bufpos - while true: - case ^pos - of CR: pos = nimlexbase.handleCR(L, pos) - of LF: pos = nimlexbase.handleLF(L, pos) - of ' ': inc pos - else: break - L.bufpos = pos - -proc skipUntilCmd(L: var TBaseLexer) = - var pos = L.bufpos - while true: - case ^pos - of CR: pos = nimlexbase.handleCR(L, pos) - of LF: pos = nimlexbase.handleLF(L, pos) - of '\0': break - of '/': - if ^(pos+1) == '*' and ^(pos+2) == '\t': - inc pos, 3 - break - inc pos - else: inc pos - L.bufpos = pos - -proc atEndMark(buf: cstring, pos: int): bool = - var s = 0 - while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s - result = s == NimMergeEndMark.len - -proc readVerbatimSection(L: var TBaseLexer): Rope = - var pos = L.bufpos - var r = newStringOfCap(30_000) - while true: - case L.buf[pos] - of CR: - pos = nimlexbase.handleCR(L, pos) - r.add('\L') - of LF: - pos = nimlexbase.handleLF(L, pos) - r.add('\L') - of '\0': - doAssert(false, "ccgmerge: expected: " & NimMergeEndMark) - break - else: - if atEndMark(L.buf, pos): - inc pos, NimMergeEndMark.len - break - r.add(L.buf[pos]) - inc pos - L.bufpos = pos - result = r.rope - -proc readKey(L: var TBaseLexer, result: var string) = - var pos = L.bufpos - setLen(result, 0) - while L.buf[pos] in IdentChars: - result.add(L.buf[pos]) - inc pos - if L.buf[pos] != ':': doAssert(false, "ccgmerge: ':' expected") - L.bufpos = pos + 1 # skip ':' - -proc readTypeCache(L: var TBaseLexer, result: var TypeCache) = - if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected") - inc L.bufpos - while ^L.bufpos != '}': - skipWhite(L) - var key = decodeStr(L.buf, L.bufpos) - if ^L.bufpos != ':': doAssert(false, "ccgmerge: ':' expected") - inc L.bufpos - discard decodeStr(L.buf, L.bufpos) - inc L.bufpos - -proc readIntSet(L: var TBaseLexer, result: var IntSet) = - if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected") - inc L.bufpos - while ^L.bufpos != '}': - skipWhite(L) - var key = decodeVInt(L.buf, L.bufpos) - result.incl(key) - inc L.bufpos - -proc processMergeInfo(L: var TBaseLexer, m: BModule) = - var k = newStringOfCap("typeCache".len) - while true: - skipWhite(L) - if ^L.bufpos == '*' and ^(L.bufpos+1) == '/': - inc(L.bufpos, 2) - break - readKey(L, k) - case k - of "typeCache": readTypeCache(L, m.typeCache) - of "declared": readIntSet(L, m.declaredThings) - of "typeInfo": - when false: readIntSet(L, m.typeInfoMarker) - of "labels": m.labels = decodeVInt(L.buf, L.bufpos) - of "flags": - m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0) - else: doAssert(false, "ccgmerge: unknown key: " & k) - -template withCFile(cfilename: AbsoluteFile, body: untyped) = - var s = llStreamOpen(cfilename, fmRead) - if s == nil: return - var L {.inject.}: TBaseLexer - openBaseLexer(L, s) - var k {.inject.} = newStringOfCap("NIM_merge_FORWARD_TYPES".len) - while true: - skipUntilCmd(L) - if ^L.bufpos == '\0': break - body - closeBaseLexer(L) - -proc readMergeInfo*(cfilename: AbsoluteFile, m: BModule) = - ## reads the merge meta information into `m`. - withCFile(cfilename): - readKey(L, k) - if k == "NIM_merge_INFO": - processMergeInfo(L, m) - break - -type - TMergeSections = object - f: TCFileSections - p: TCProcSections - -proc readMergeSections(cfilename: AbsoluteFile, m: var TMergeSections) = - ## reads the merge sections into `m`. - withCFile(cfilename): - readKey(L, k) - if k == "NIM_merge_INFO": - discard - elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/': - inc(L.bufpos, 2) - # read back into section - skipWhite(L) - var verbatim = readVerbatimSection(L) - skipWhite(L) - var sectionA = CFileSectionNames.find(k) - if sectionA > 0 and sectionA <= high(TCFileSection).int: - m.f[TCFileSection(sectionA)] = verbatim - else: - var sectionB = CProcSectionNames.find(k) - if sectionB >= 0 and sectionB <= high(TCProcSection).int: - m.p[TCProcSection(sectionB)] = verbatim - else: - doAssert(false, "ccgmerge: unknown section: " & k) - else: - doAssert(false, "ccgmerge: '*/' expected") - -proc mergeRequired*(m: BModule): bool = - for i in cfsHeaders..cfsProcs: - if m.s[i] != nil: - #echo "not empty: ", i, " ", m.s[i] - return true - for i in TCProcSection: - if m.initProc.s(i) != nil: - #echo "not empty: ", i, " ", m.initProc.s[i] - return true - -proc mergeFiles*(cfilename: AbsoluteFile, m: BModule) = - ## merges the C file with the old version on hard disc. - var old: TMergeSections - readMergeSections(cfilename, old) - # do the merge; old section before new section: - for i in TCFileSection: - m.s[i] = old.f[i] & m.s[i] - for i in TCProcSection: - m.initProc.s(i) = old.p[i] & m.initProc.s(i) diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim deleted file mode 100644 index 5e6456704..000000000 --- a/compiler/ccgreset.nim +++ /dev/null @@ -1,107 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2020 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# included from cgen.nim - -## Code specialization instead of the old, incredibly slow 'genericReset' -## implementation. - -proc specializeResetT(p: BProc, accessor: Rope, typ: PType) - -proc specializeResetN(p: BProc, accessor: Rope, n: PNode; - typ: PType) = - if n == nil: return - case n.kind - of nkRecList: - for i in 0.. 2 - # do not close and reopen blocks if this is a 'global' but inside of a block (if/while/block) - forHcr = forHcr and not isGlobalInBlock - - if forHcr: - # check with the boolean if the initializing code for the tuple should be ran - lineCg(p, cpsStmts, "if ($1)$n", [hcrCond]) - startBlock(p) - genLineDir(p, n) - initLocExpr(p, n[^1], tup) + initLocExpr(p, n.sons[L-1], tup) var t = tup.t.skipTypes(abstractInst) - for i in 0.. 0: result.addf("FR_.len+=$1;$n", [b.frameLen.rope]) result.add(b.sections[cpsInit]) @@ -158,7 +116,7 @@ proc blockBody(b: var TBlock; result: var Rope) = proc endBlock(p: BProc, blockEnd: Rope) = let topBlock = p.blocks.len-1 # the block is merged into the parent block - p.blocks[topBlock].blockBody(p.blocks[topBlock-1].sections[cpsStmts]) + add(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody) setLen(p.blocks, topBlock) # this is done after the block is popped so $n is # properly indented when pretty printing is enabled @@ -166,14 +124,13 @@ proc endBlock(p: BProc, blockEnd: Rope) = proc endBlock(p: BProc) = let topBlock = p.blocks.len - 1 + var blockEnd = if p.blocks[topBlock].label != nil: + ropecg(p.module, "} $1: ;$n", p.blocks[topBlock].label) + else: + ~"}$n" let frameLen = p.blocks[topBlock].frameLen - var blockEnd: Rope if frameLen > 0: blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope]) - if p.blocks[topBlock].label.len != 0: - blockEnd.addf("} $1: ;$n", [p.blocks[topBlock].label]) - else: - blockEnd.addf("}$n", []) endBlock(p, blockEnd) proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} = @@ -195,24 +152,23 @@ proc genState(p: BProc, n: PNode) = internalAssert p.config, n.len == 1 let n0 = n[0] if n0.kind == nkIntLit: - let idx = n[0].intVal - linefmt(p, cpsStmts, "STATE$1: ;$n", [idx]) + let idx = n.sons[0].intVal + linefmt(p, cpsStmts, "STATE$1: ;$n", idx.rope) elif n0.kind == nkStrLit: - linefmt(p, cpsStmts, "$1: ;$n", [n0.strVal]) + linefmt(p, cpsStmts, "$1: ;$n", n0.strVal.rope) proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = # Called by return and break stmts. - # Deals with issues faced when jumping out of try/except/finally stmts. + # Deals with issues faced when jumping out of try/except/finally stmts, - var stack = newSeq[tuple[fin: PNode, inExcept: bool, label: Natural]](0) + var stack = newSeq[tuple[n: PNode, inExcept: bool]](0) - inc p.withinBlockLeaveActions - for i in 1..howManyTrys: + for i in countup(1, howManyTrys): let tryStmt = p.nestedTryStmts.pop - if p.config.exc == excSetjmp: + if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions: # Pop safe points generated by try if not tryStmt.inExcept: - linefmt(p, cpsStmts, "#popSafePoint();$n", []) + linefmt(p, cpsStmts, "#popSafePoint();$n") # Pop this try-stmt of the list of nested trys # so we don't infinite recurse on it in the next step. @@ -220,21 +176,19 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = # Find finally-stmt for this try-stmt # and generate a copy of its sons - var finallyStmt = tryStmt.fin - if finallyStmt != nil: - genStmts(p, finallyStmt[0]) - - dec p.withinBlockLeaveActions + var finallyStmt = lastSon(tryStmt.n) + if finallyStmt.kind == nkFinally: + genStmts(p, finallyStmt.sons[0]) # push old elements again: for i in countdown(howManyTrys-1, 0): p.nestedTryStmts.add(stack[i]) - # Pop exceptions that was handled by the - # except-blocks we are in - if noSafePoints notin p.flags: + if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions: + # Pop exceptions that was handled by the + # except-blocks we are in for i in countdown(howManyExcepts-1, 0): - linefmt(p, cpsStmts, "#popCurrentException();$n", []) + linefmt(p, cpsStmts, "#popCurrentException();$n") proc genGotoState(p: BProc, n: PNode) = # we resist the temptation to translate it into duff's device as it later @@ -243,20 +197,20 @@ proc genGotoState(p: BProc, n: PNode) = # case 0: goto STATE0; # ... var a: TLoc - initLocExpr(p, n[0], a) + initLocExpr(p, n.sons[0], a) lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)]) - p.flags.incl beforeRetNeeded + p.beforeRetNeeded = true lineF(p, cpsStmts, "case -1:$n", []) blockLeaveActions(p, howManyTrys = p.nestedTryStmts.len, howManyExcepts = p.inExceptBlockLen) lineF(p, cpsStmts, " goto BeforeRet_;$n", []) - var statesCounter = lastOrd(p.config, n[0].typ) + var statesCounter = lastOrd(p.config, n.sons[0].typ) if n.len >= 2 and n[1].kind == nkIntLit: - statesCounter = getInt(n[1]) + statesCounter = n[1].intVal let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope else: rope"STATE" - for i in 0i64..toInt64(statesCounter): + for i in 0i64 .. statesCounter: lineF(p, cpsStmts, "case $2: goto $1$2;$n", [prefix, rope(i)]) lineF(p, cpsStmts, "}$n", []) @@ -264,11 +218,11 @@ proc genBreakState(p: BProc, n: PNode, d: var TLoc) = var a: TLoc initLoc(d, locExpr, n, OnUnknown) - if n[0].kind == nkClosure: - initLocExpr(p, n[0][1], a) + if n.sons[0].kind == nkClosure: + initLocExpr(p, n.sons[0].sons[1], a) d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)] else: - initLocExpr(p, n[0], a) + initLocExpr(p, n.sons[0], a) # the environment is guaranteed to contain the 'state' field at offset 1: d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)] @@ -278,74 +232,57 @@ proc genGotoVar(p: BProc; value: PNode) = else: lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope]) -proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; result: var Rope) - -proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) = - if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn: - discard "nothing to do" - elif sfGlobal in v.flags and value != nil and isDeepConstExpr(value, p.module.compileToCpp) and - p.withinLoop == 0 and not containsGarbageCollectedRef(v.typ): - #echo "New code produced for ", v.name.s, " ", p.config $ value.info - genBracedInit(p, value, isConst = false, v.typ, result) - -proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = +proc genSingleVar(p: BProc, a: PNode) = + let vn = a.sons[0] + let v = vn.sym + if sfCompileTime in v.flags: return if sfGoto in v.flags: # translate 'var state {.goto.} = X' into 'goto LX': - genGotoVar(p, value) + genGotoVar(p, a.sons[2]) return var targetProc = p - var valueAsRope = "" - potentialValueInit(p, v, value, valueAsRope) if sfGlobal in v.flags: if v.flags * {sfImportc, sfExportc} == {sfImportc} and - value.kind == nkEmpty and + a.sons[2].kind == nkEmpty and v.loc.flags * {lfHeader, lfNoDecl} != {}: return if sfPure in v.flags: # v.owner.kind != skModule: targetProc = p.module.preInitProc - assignGlobalVar(targetProc, vn, valueAsRope) + assignGlobalVar(targetProc, vn) # XXX: be careful here. # Global variables should not be zeromem-ed within loops # (see bug #20). # That's why we are doing the construction inside the preInitProc. # genObjectInit relies on the C runtime's guarantees that # global variables will be initialized to zero. - if valueAsRope.len == 0: - var loc = v.loc - - # When the native TLS is unavailable, a global thread-local variable needs - # one more layer of indirection in order to access the TLS block. - # Only do this for complex types that may need a call to `objectInit` - if sfThread in v.flags and emulatedThreadVars(p.config) and - isComplexValueType(v.typ): - initLocExprSingleUse(p.module.preInitProc, vn, loc) - genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, constructObj) + genObjectInit(p.module.preInitProc, cpsInit, v.typ, v.loc, true) # Alternative construction using default constructor (which may zeromem): # if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc) if sfExportc in v.flags and p.module.g.generatedHeader != nil: genVarPrototype(p.module.g.generatedHeader, vn) - registerTraverseProc(p, v) + registerGcRoot(p, v) else: + let value = a.sons[2] let imm = isAssignedImmediately(p.config, value) if imm and p.module.compileToCpp and p.splitDecls == 0 and not containsHiddenPointer(v.typ): # C++ really doesn't like things like 'Foo f; f = x' as that invokes a # parameterless constructor followed by an assignment operator. So we - # generate better code here: 'Foo f = x;' - genLineDir(p, vn) + # generate better code here: + genLineDir(p, a) let decl = localVarDecl(p, vn) var tmp: TLoc if value.kind in nkCallKinds and value[0].kind == nkSym and sfConstructor in value[0].sym.flags: - var params = newRopeAppender() - var argsCounter = 0 - let typ = skipTypes(value[0].typ, abstractInst) + var params: Rope + let typ = skipTypes(value.sons[0].typ, abstractInst) assert(typ.kind == tyProc) for i in 1.. 3 and v.owner.kind == skModule: - # put it in the locals section - mainly because of loops which - # use the var in a call to resetLoc() in the statements section - lineCg(targetProc, cpsLocals, "hcrRegisterGlobal($3, \"$1\", sizeof($2), $4, (void**)&$1);$n", - [v.loc.r, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc]) - # nothing special left to do later on - let's avoid closing and reopening blocks - forHcr = false - - # we close and reopen the global if (nim_hcr_do_init_) blocks in the main Init function - # for the module so we can have globals and top-level code be interleaved and still - # be able to re-run it but without the top level code - just the init of globals - if forHcr: - lineCg(targetProc, cpsStmts, "if (hcrRegisterGlobal($3, \"$1\", sizeof($2), $4, (void**)&$1))$N", - [v.loc.r, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc]) - startBlock(targetProc) - if value.kind != nkEmpty and valueAsRope.len == 0: - genLineDir(targetProc, vn) - loadInto(targetProc, vn, value, v.loc) - if forHcr: - endBlock(targetProc) - -proc genSingleVar(p: BProc, a: PNode) = - let v = a[0].sym - if sfCompileTime in v.flags: - # fix issue #12640 - # {.global, compileTime.} pragma in proc - if sfGlobal in v.flags and p.prc != nil and p.prc.kind == skProc: - discard - else: - return - genSingleVar(p, v, a[0], a[2]) + if a.sons[2].kind != nkEmpty: + genLineDir(targetProc, a) + loadInto(targetProc, a.sons[0], a.sons[2], v.loc) proc genClosureVar(p: BProc, a: PNode) = - var immediateAsgn = a[2].kind != nkEmpty - var v: TLoc - initLocExpr(p, a[0], v) - genLineDir(p, a) + var immediateAsgn = a.sons[2].kind != nkEmpty if immediateAsgn: - loadInto(p, a[0], a[2], v) - elif sfNoInit notin a[0][1].sym.flags: - constructLoc(p, v) + var v: TLoc + initLocExpr(p, a.sons[0], v) + genLineDir(p, a) + loadInto(p, a.sons[0], a.sons[2], v) proc genVarStmt(p: BProc, n: PNode) = for it in n.sons: if it.kind == nkCommentStmt: continue if it.kind == nkIdentDefs: # can be a lifted var nowadays ... - if it[0].kind == nkSym: + if it.sons[0].kind == nkSym: genSingleVar(p, it) else: genClosureVar(p, it) @@ -438,92 +340,79 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = # bug #4230: avoid false sharing between branches: if d.k == locTemp and isEmptyType(n.typ): d.k = locNone if it.len == 2: - startBlock(p) - initLocExprSingleUse(p, it[0], a) + when newScopeForIf: startBlock(p) + initLocExprSingleUse(p, it.sons[0], a) lelse = getLabel(p) inc(p.labels) lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), lelse]) + when not newScopeForIf: startBlock(p) if p.module.compileToCpp: # avoid "jump to label crosses initialization" error: - p.s(cpsStmts).add "{" - expr(p, it[1], d) - p.s(cpsStmts).add "}" + add(p.s(cpsStmts), "{") + expr(p, it.sons[1], d) + add(p.s(cpsStmts), "}") else: - expr(p, it[1], d) + expr(p, it.sons[1], d) endBlock(p) - if n.len > 1: + if sonsLen(n) > 1: lineF(p, cpsStmts, "goto $1;$n", [lend]) fixLabel(p, lelse) elif it.len == 1: startBlock(p) - expr(p, it[0], d) + expr(p, it.sons[0], d) endBlock(p) else: internalError(p.config, n.info, "genIf()") - if n.len > 1: fixLabel(p, lend) + if sonsLen(n) > 1: fixLabel(p, lend) proc genReturnStmt(p: BProc, t: PNode) = if nfPreventCg in t.flags: return - p.flags.incl beforeRetNeeded + p.beforeRetNeeded = true genLineDir(p, t) - if (t[0].kind != nkEmpty): genStmts(p, t[0]) + if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0]) blockLeaveActions(p, howManyTrys = p.nestedTryStmts.len, howManyExcepts = p.inExceptBlockLen) - if (p.finallySafePoints.len > 0) and noSafePoints notin p.flags: + if (p.finallySafePoints.len > 0): # If we're in a finally block, and we came here by exception # consume it before we return. - var safePoint = p.finallySafePoints[^1] - linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", [safePoint]) + var safePoint = p.finallySafePoints[p.finallySafePoints.len-1] + linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint) lineF(p, cpsStmts, "goto BeforeRet_;$n", []) proc genGotoForCase(p: BProc; caseStmt: PNode) = - for i in 1.. 10_000: localError(p.config, it.info, "case statement has too many cases for computed goto"); return - arraySize = toInt(aSize) - if firstOrd(p.config, it[0].typ) != 0: + arraySize = aSize.int + if firstOrd(p.config, it.sons[0].typ) != 0: localError(p.config, it.info, "case statement has to start at 0 for computed goto"); return if casePos < 0: @@ -533,166 +422,132 @@ proc genComputedGoto(p: BProc; n: PNode) = let tmp = "TMP$1_" % [id.rope] var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope] for i in 1..arraySize-1: - gotoArray.addf("&&TMP$#_, ", [rope(id+i)]) - gotoArray.addf("&&TMP$#_};$n", [rope(id+arraySize)]) + gotoArray.addf("&&TMP$#_, ", [(id+i).rope]) + gotoArray.addf("&&TMP$#_};$n", [(id+arraySize).rope]) line(p, cpsLocals, gotoArray) - for j in 0..= 0 and not p.blocks[idx].isLoop: dec idx if idx < 0 or not p.blocks[idx].isLoop: internalError(p.config, t.info, "no loop to break") - p.blocks[idx].label = "LA" & p.blocks[idx].id.rope + let label = assignLabel(p.blocks[idx]) blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts, p.inExceptBlockLen - p.blocks[idx].nestedExceptStmts) genLineDir(p, t) - lineF(p, cpsStmts, "goto $1;$n", [p.blocks[idx].label]) - -proc raiseExit(p: BProc) = - assert p.config.exc == excGoto - if nimErrorFlagDisabled notin p.flags: - p.flags.incl nimErrorFlagAccessed - if p.nestedTryStmts.len == 0: - p.flags.incl beforeRetNeeded - # easy case, simply goto 'ret': - lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;$n", []) - else: - lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n", - [p.nestedTryStmts[^1].label]) - -proc finallyActions(p: BProc) = - if p.config.exc != excGoto and p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept: - # if the current try stmt have a finally block, - # we must execute it before reraising - let finallyBlock = p.nestedTryStmts[^1].fin - if finallyBlock != nil: - genSimpleBlock(p, finallyBlock[0]) - -proc raiseInstr(p: BProc; result: var Rope) = - if p.config.exc == excGoto: - let L = p.nestedTryStmts.len - if L == 0: - p.flags.incl beforeRetNeeded - # easy case, simply goto 'ret': - result.add ropecg(p.module, "goto BeforeRet_;$n", []) - else: - # raise inside an 'except' must go to the finally block, - # raise outside an 'except' block must go to the 'except' list. - result.add ropecg(p.module, "goto LA$1_;$n", - [p.nestedTryStmts[L-1].label]) - # + ord(p.nestedTryStmts[L-1].inExcept)]) + lineF(p, cpsStmts, "goto $1;$n", [label]) proc genRaiseStmt(p: BProc, t: PNode) = + if p.module.compileToCpp: + discard cgsym(p.module, "popCurrentExceptionEx") + if p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept: + # if the current try stmt have a finally block, + # we must execute it before reraising + var finallyBlock = p.nestedTryStmts[^1].n[^1] + if finallyBlock.kind == nkFinally: + genSimpleBlock(p, finallyBlock[0]) if t[0].kind != nkEmpty: var a: TLoc initLocExprSingleUse(p, t[0], a) - finallyActions(p) var e = rdLoc(a) - discard getTypeDesc(p.module, t[0].typ) var typ = skipTypes(t[0].typ, abstractPtrs) - # XXX For reasons that currently escape me, this is only required by the new - # C++ based exception handling: - if p.config.exc == excCpp: - blockLeaveActions(p, howManyTrys = 0, howManyExcepts = p.inExceptBlockLen) genLineDir(p, t) if isImportedException(typ, p.config): lineF(p, cpsStmts, "throw $1;$n", [e]) else: - lineCg(p, cpsStmts, "#raiseExceptionEx((#Exception*)$1, $2, $3, $4, $5);$n", - [e, makeCString(typ.sym.name.s), - makeCString(if p.prc != nil: p.prc.name.s else: p.module.module.name.s), - quotedFilename(p.config, t.info), toLinenumber(t.info)]) - if optOwnedRefs in p.config.globalOptions: - lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [e]) + lineCg(p, cpsStmts, "#raiseException((#Exception*)$1, $2);$n", + [e, makeCString(typ.sym.name.s)]) else: - finallyActions(p) genLineDir(p, t) # reraise the last exception: - if p.config.exc == excCpp: - line(p, cpsStmts, "throw;\n") + if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions: + line(p, cpsStmts, ~"throw;$n") else: - linefmt(p, cpsStmts, "#reraiseException();$n", []) - raiseInstr(p, p.s(cpsStmts)) + linefmt(p, cpsStmts, "#reraiseException();$n") -template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, +proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, rangeFormat, eqFormat: FormatStr, labl: TLabel) = - var x, y: TLoc - for i in 0.. stringCaseThreshold: var bitMask = math.nextPowerOfTwo(strings) - 1 var branches: seq[Rope] newSeq(branches, bitMask + 1) var a: TLoc - initLocExpr(p, t[0], a) # fist pass: generate ifs+goto: + initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto: var labId = p.labels - for i in 1.. RangeExpandLimit: + if (b.sons[i].kind == nkRange) and + b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit: return true proc ifSwitchSplitPoint(p: BProc, n: PNode): int = - for i in 1.. 0: genIfForCaseUntil(p, n, d, rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n", eqFormat = "if ($1 == $2) goto $3;$n", - splitPoint, a) else: "" + splitPoint, a) else: nil # generate switch part (might be empty): if splitPoint+1 < n.len: lineF(p, cpsStmts, "switch ($1) {$n", [rdCharLoc(a)]) var hasDefault = false - for i in splitPoint+1..= $2 && $1 <= $3) goto $4;$n", "if ($1 == $2) goto $3;$n") else: - if t[0].kind == nkSym and sfGoto in t[0].sym.flags: + if t.sons[0].kind == nkSym and sfGoto in t.sons[0].sym.flags: genGotoForCase(p, t) else: genOrdinalCase(p, t, d) proc genRestoreFrameAfterException(p: BProc) = if optStackTrace in p.module.config.options: - if hasCurFramePointer notin p.flags: - p.flags.incl hasCurFramePointer + if not p.hasCurFramePointer: + p.hasCurFramePointer = true p.procSec(cpsLocals).add(ropecg(p.module, "\tTFrame* _nimCurFrame;$n", [])) p.procSec(cpsInit).add(ropecg(p.module, "\t_nimCurFrame = #getFrame();$n", [])) - linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n", []) + linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n") proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = - #[ code to generate: - - std::exception_ptr error = nullptr; - try { - body; - } catch (Exception e) { - error = std::current_exception(); - if (ofExpr(e, TypeHere)) { - - error = nullptr; // handled - } else if (...) { - - } else { - throw; - } - } catch(...) { - // C++ exception occured, not under Nim's control. - } - { - /* finally: */ - printf('fin!\n'); - if (error) std::rethrow_exception(error); // re-raise the exception - } - ]# - p.module.includeHeader("") - - if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) - genLineDir(p, t) - - inc(p.labels, 2) - let etmp = p.labels - - p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;", [etmp])) - - let fin = if t[^1].kind == nkFinally: t[^1] else: nil - p.nestedTryStmts.add((fin, false, 0.Natural)) - - if t.kind == nkHiddenTryStmt: - lineCg(p, cpsStmts, "try {$n", []) - expr(p, t[0], d) - lineCg(p, cpsStmts, "}$n", []) - else: - startBlock(p, "try {$n") - expr(p, t[0], d) - endBlock(p) - - # First pass: handle Nim based exceptions: - lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1]) - genRestoreFrameAfterException(p) - # an unhandled exception happened! - lineCg(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) - p.nestedTryStmts[^1].inExcept = true - var hasImportedCppExceptions = false - var i = 1 - var hasIf = false - var hasElse = false - while (i < t.len) and (t[i].kind == nkExceptBranch): - # bug #4230: avoid false sharing between branches: - if d.k == locTemp and isEmptyType(t.typ): d.k = locNone - if t[i].len == 1: - hasImportedCppExceptions = true - # general except section: - hasElse = true - if hasIf: lineF(p, cpsStmts, "else ", []) - startBlock(p) - # we handled the error: - linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp]) - expr(p, t[i][0], d) - linefmt(p, cpsStmts, "#popCurrentException();$n", []) - endBlock(p) - else: - var orExpr = newRopeAppender() - var exvar = PNode(nil) - for j in 0..$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(typeNode.typ, p.config)))]) - else: - let checkFor = genTypeInfoV1(p.module, typeNode.typ, typeNode.info) - appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) - - if orExpr.len != 0: - if hasIf: - startBlock(p, "else if ($1) {$n", [orExpr]) - else: - startBlock(p, "if ($1) {$n", [orExpr]) - hasIf = true - if exvar != nil: - fillLocalName(p, exvar.sym) - fillLoc(exvar.sym.loc, locTemp, exvar, OnStack) - linefmt(p, cpsStmts, "$1 $2 = T$3_;$n", [getTypeDesc(p.module, exvar.sym.typ), - rdLoc(exvar.sym.loc), rope(etmp+1)]) - # we handled the error: - linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp]) - expr(p, t[i][^1], d) - linefmt(p, cpsStmts, "#popCurrentException();$n", []) - endBlock(p) - inc(i) - if hasIf and not hasElse: - linefmt(p, cpsStmts, "else throw;$n", [etmp]) - linefmt(p, cpsStmts, "}$n", []) - - # Second pass: handle C++ based exceptions: - template genExceptBranchBody(body: PNode) {.dirty.} = - genRestoreFrameAfterException(p) - #linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) - expr(p, body, d) - - var catchAllPresent = false - incl p.flags, noSafePoints # mark as not needing 'popCurrentException' - if hasImportedCppExceptions: - for i in 1.. 0 and t[^1].kind == nkFinally: - if not catchAllPresent: - startBlock(p, "catch (...) {", []) - genRestoreFrameAfterException(p) - linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) - endBlock(p) - - startBlock(p) - genStmts(p, t[^1][0]) - linefmt(p, cpsStmts, "if (T$1_) std::rethrow_exception(T$1_);$n", [etmp]) - endBlock(p) - -proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = - # There are two versions we generate, depending on whether we - # catch C++ exceptions, imported via .importcpp or not. The - # code can be easier if there are no imported C++ exceptions - # to deal with. - # code to generate: # # try @@ -1189,9 +810,8 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = if not isEmptyType(t.typ) and d.k == locNone: getTemp(p, t.typ, d) genLineDir(p, t) - cgsym(p.module, "popCurrentExceptionEx") - let fin = if t[^1].kind == nkFinally: t[^1] else: nil - p.nestedTryStmts.add((fin, false, 0.Natural)) + discard cgsym(p.module, "popCurrentExceptionEx") + add(p.nestedTryStmts, (t, false)) startBlock(p, "try {$n") expr(p, t[0], d) endBlock(p) @@ -1212,11 +832,10 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = genExceptBranchBody(t[i][0]) endBlock(p) else: - for j in 0.. 1: lineF(p, cpsStmts, "else", []) - startBlock(p) - # we handled the exception, remember this: - linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", []) - expr(p, t[i][0], d) - else: - var orExpr = newRopeAppender() - for j in 0..$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))]) - else: - let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) - appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) - - if i > 1: line(p, cpsStmts, "else ") - startBlock(p, "if ($1) {$n", [orExpr]) - # we handled the exception, remember this: - linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", []) - expr(p, t[i][^1], d) - - linefmt(p, cpsStmts, "#popCurrentException();$n", []) - linefmt(p, cpsStmts, "LA$1_:;$n", [nextExcept]) - endBlock(p) - - inc(i) - discard pop(p.nestedTryStmts) - endBlock(p) - - if i < t.len and t[i].kind == nkFinally: - startBlock(p) - if not bodyCanRaise(p, t[i][0]): - # this is an important optimization; most destroy blocks are detected not to raise an - # exception and so we help the C optimizer by not mutating nimErr_ pointlessly: - genStmts(p, t[i][0]) - else: - # pretend we did handle the error for the safe execution of the 'finally' section: - p.procSec(cpsLocals).add(ropecg(p.module, "NIM_BOOL oldNimErrFin$1_;$n", [lab])) - linefmt(p, cpsStmts, "oldNimErrFin$1_ = *nimErr_; *nimErr_ = NIM_FALSE;$n", [lab]) - genStmts(p, t[i][0]) - # this is correct for all these cases: - # 1. finally is run during ordinary control flow - # 2. finally is run after 'except' block handling: these however set the - # error back to nil. - # 3. finally is run for exception handling code without any 'except' - # handler present or only handlers that did not match. - linefmt(p, cpsStmts, "*nimErr_ = oldNimErrFin$1_;$n", [lab]) - endBlock(p) - raiseExit(p) - if hasExcept: inc p.withinTryWithExcept - -proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = +proc genTry(p: BProc, t: PNode, d: var TLoc) = # code to generate: # # XXX: There should be a standard dispatch algorithm @@ -1372,109 +885,69 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = # if not isEmptyType(t.typ) and d.k == locNone: getTemp(p, t.typ, d) - let quirkyExceptions = p.config.exc == excQuirky or - (t.kind == nkHiddenTryStmt and sfSystemModule in p.module.module.flags) - if not quirkyExceptions: - p.module.includeHeader("") - else: - p.flags.incl noSafePoints + p.module.includeHeader("") genLineDir(p, t) - cgsym(p.module, "Exception") - var safePoint: Rope - if not quirkyExceptions: - safePoint = getTempName(p.module) - linefmt(p, cpsLocals, "#TSafePoint $1;$n", [safePoint]) - linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", [safePoint]) - if isDefined(p.config, "nimStdSetjmp"): - linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) - elif isDefined(p.config, "nimSigSetjmp"): - linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", [safePoint]) - elif isDefined(p.config, "nimBuiltinSetjmp"): - linefmt(p, cpsStmts, "$1.status = __builtin_setjmp($1.context);$n", [safePoint]) - elif isDefined(p.config, "nimRawSetjmp"): - if isDefined(p.config, "mswindows"): - if isDefined(p.config, "vcc") or isDefined(p.config, "clangcl"): - # For the vcc compiler, use `setjmp()` with one argument. - # See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setjmp?view=msvc-170 - linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) - else: - # The Windows `_setjmp()` takes two arguments, with the second being an - # undocumented buffer used by the SEH mechanism for stack unwinding. - # Mingw-w64 has been trying to get it right for years, but it's still - # prone to stack corruption during unwinding, so we disable that by setting - # it to NULL. - # More details: https://github.com/status-im/nimbus-eth2/issues/3121 - linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint]) - else: - linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint]) - else: - linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint]) - lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint]) - let fin = if t[^1].kind == nkFinally: t[^1] else: nil - p.nestedTryStmts.add((fin, quirkyExceptions, 0.Natural)) - expr(p, t[0], d) - if not quirkyExceptions: - linefmt(p, cpsStmts, "#popSafePoint();$n", []) - lineCg(p, cpsStmts, "}$n", []) - startBlock(p, "else {$n") - linefmt(p, cpsStmts, "#popSafePoint();$n", []) - genRestoreFrameAfterException(p) - elif 1 < t.len and t[1].kind == nkExceptBranch: - startBlock(p, "if (#nimBorrowCurrentException()) {$n") + var safePoint = getTempName(p.module) + discard cgsym(p.module, "Exception") + linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint) + linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint) + if isDefined(p.config, "nimStdSetjmp"): + linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) + elif isDefined(p.config, "nimSigSetjmp"): + linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint) + elif isDefined(p.config, "nimRawSetjmp"): + linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint) else: - startBlock(p) + linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) + startBlock(p, "if ($1.status == 0) {$n", [safePoint]) + var length = sonsLen(t) + add(p.nestedTryStmts, (t, false)) + expr(p, t.sons[0], d) + linefmt(p, cpsStmts, "#popSafePoint();$n") + endBlock(p) + startBlock(p, "else {$n") + linefmt(p, cpsStmts, "#popSafePoint();$n") + genRestoreFrameAfterException(p) p.nestedTryStmts[^1].inExcept = true var i = 1 - while (i < t.len) and (t[i].kind == nkExceptBranch): + while (i < length) and (t.sons[i].kind == nkExceptBranch): # bug #4230: avoid false sharing between branches: if d.k == locTemp and isEmptyType(t.typ): d.k = locNone - if t[i].len == 1: + var blen = sonsLen(t.sons[i]) + if blen == 1: # general except section: if i > 1: lineF(p, cpsStmts, "else", []) startBlock(p) - if not quirkyExceptions: - linefmt(p, cpsStmts, "$1.status = 0;$n", [safePoint]) - expr(p, t[i][0], d) - linefmt(p, cpsStmts, "#popCurrentException();$n", []) + linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint) + expr(p, t.sons[i].sons[0], d) + linefmt(p, cpsStmts, "#popCurrentException();$n") endBlock(p) else: - var orExpr = newRopeAppender() - for j in 0..$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))]) - else: - let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) - appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) - + var orExpr: Rope = nil + for j in countup(0, blen - 2): + assert(t.sons[i].sons[j].kind == nkType) + if orExpr != nil: add(orExpr, "||") + let isObjFormat = if not p.module.compileToCpp: + "#isObj(#getCurrentException()->Sup.m_type, $1)" + else: "#isObj(#getCurrentException()->m_type, $1)" + appcg(p.module, orExpr, isObjFormat, + [genTypeInfo(p.module, t[i][j].typ, t[i][j].info)]) if i > 1: line(p, cpsStmts, "else ") startBlock(p, "if ($1) {$n", [orExpr]) - if not quirkyExceptions: - linefmt(p, cpsStmts, "$1.status = 0;$n", [safePoint]) - expr(p, t[i][^1], d) - linefmt(p, cpsStmts, "#popCurrentException();$n", []) + linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint) + expr(p, t.sons[i].sons[blen-1], d) + linefmt(p, cpsStmts, "#popCurrentException();$n") endBlock(p) inc(i) discard pop(p.nestedTryStmts) endBlock(p) # end of else block - if i < t.len and t[i].kind == nkFinally: + if i < length and t.sons[i].kind == nkFinally: p.finallySafePoints.add(safePoint) - startBlock(p) - genStmts(p, t[i][0]) - # pretend we handled the exception in a 'finally' so that we don't - # re-raise the unhandled one but instead keep the old one (it was - # not popped either): - if not quirkyExceptions and getCompilerProc(p.module.g.graph, "nimLeaveFinally") != nil: - linefmt(p, cpsStmts, "if ($1.status != 0) #nimLeaveFinally();$n", [safePoint]) - endBlock(p) + genSimpleBlock(p, t.sons[i].sons[0]) discard pop(p.finallySafePoints) - if not quirkyExceptions: - linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint]) + linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint) -proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = +proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope = var res = "" for it in t.sons: case it.kind @@ -1490,8 +963,13 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = res.add($getTypeDesc(p.module, sym.typ)) else: discard getTypeDesc(p.module, skipTypes(sym.typ, abstractPtrs)) - fillBackendName(p.module, sym) - res.add($sym.loc.r) + var r = sym.loc.r + if r == nil: + # if no name has already been given, + # it doesn't matter much: + r = mangleName(p.module, sym) + sym.loc.r = r # but be consequent! + res.add($r) of nkTypeOfExpr: res.add($getTypeDesc(p.module, it.typ)) else: @@ -1508,135 +986,166 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = if x[j] in {'"', ':'}: # don't modify the line if already in quotes or # some clobber register list: - result.add(x); result.add("\L") + add(result, x); add(result, "\L") else: # ignore empty lines - result.add("\"") - result.add(x.replace("\"", "\\\"")) - result.add("\\n\"\n") + add(result, "\"") + add(result, x) + add(result, "\\n\"\n") else: res.add("\L") - result.add res.rope + result = res.rope proc genAsmStmt(p: BProc, t: PNode) = assert(t.kind == nkAsmStmt) genLineDir(p, t) - var s = newRopeAppender() - genAsmOrEmitStmt(p, t, isAsmStmt=true, s) + var s = genAsmOrEmitStmt(p, t, isAsmStmt=true) # see bug #2362, "top level asm statements" seem to be a mis-feature # but even if we don't do this, the example in #2362 cannot possibly # work: if p.prc == nil: # top level asm statement? - p.module.s[cfsProcHeaders].add runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s]) + addf(p.module.s[cfsProcHeaders], CC[p.config.cCompiler].asmStmtFrmt, [s]) else: - addIndent p, p.s(cpsStmts) - p.s(cpsStmts).add runtimeFormat(CC[p.config.cCompiler].asmStmtFrmt, [s]) + lineF(p, cpsStmts, CC[p.config.cCompiler].asmStmtFrmt, [s]) proc determineSection(n: PNode): TCFileSection = result = cfsProcHeaders - if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}: - let sec = n[0].strVal - if sec.startsWith("/*TYPESECTION*/"): result = cfsForwardTypes # TODO WORKAROUND + if n.len >= 1 and n.sons[0].kind in {nkStrLit..nkTripleStrLit}: + let sec = n.sons[0].strVal + if sec.startsWith("/*TYPESECTION*/"): result = cfsTypes elif sec.startsWith("/*VARSECTION*/"): result = cfsVars elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders proc genEmit(p: BProc, t: PNode) = - var s = newRopeAppender() - genAsmOrEmitStmt(p, t[1], false, s) + var s = genAsmOrEmitStmt(p, t.sons[1]) if p.prc == nil: # top level emit pragma? let section = determineSection(t[1]) genCLineDir(p.module.s[section], t.info, p.config) - p.module.s[section].add(s) + add(p.module.s[section], s) else: genLineDir(p, t) line(p, cpsStmts, s) +proc genBreakPoint(p: BProc, t: PNode) = + var name: string + if optEndb in p.options: + if t.kind == nkExprColonExpr: + assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit}) + name = normalize(t.sons[1].strVal) + else: + inc(p.module.g.breakPointId) + name = "bp" & $p.module.g.breakPointId + genLineDir(p, t) # BUGFIX + appcg(p.module, p.module.g.breakpoints, + "#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [ + rope(toLinenumber(t.info)), makeCString(toFilename(p.config, t.info)), + makeCString(name)]) + +proc genWatchpoint(p: BProc, n: PNode) = + if optEndb notin p.options: return + var a: TLoc + initLocExpr(p, n.sons[1], a) + let typ = skipTypes(n.sons[1].typ, abstractVarRange) + lineCg(p, cpsStmts, "#dbgRegisterWatchpoint($1, (NCSTRING)$2, $3);$n", + [addrLoc(p.config, a), makeCString(renderTree(n.sons[1])), + genTypeInfo(p.module, typ, n.info)]) + proc genPragma(p: BProc, n: PNode) = - for i in 0..$3; $1++) {$n", + [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")]) let oldLen = p.s(cpsStmts).len - genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ[0]) + genTraverseProc(c, "$1->data[$2]" % [accessor, i.r], typ.sons[0]) if p.s(cpsStmts).len == oldLen: # do not emit dummy long loops for faster debug builds: p.s(cpsStmts) = oldCode @@ -140,53 +121,46 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope = var c: TTraversalClosure var p = newProc(nil, m) result = "Marker_" & getTypeName(m, origTyp, sig) - let - hcrOn = m.hcrOn - typ = origTyp.skipTypes(abstractInstOwned) - markerName = if hcrOn: result & "_actual" else: result - header = "static N_NIMCALL(void, $1)(void* p, NI op)" % [markerName] - t = getTypeDesc(m, typ) + var typ = origTyp.skipTypes(abstractInst) + let header = "static N_NIMCALL(void, $1)(void* p, NI op)" % [result] + + let t = getTypeDesc(m, typ) lineF(p, cpsLocals, "$1 a;$n", [t]) lineF(p, cpsInit, "a = ($1)p;$n", [t]) c.p = p - c.visitorFrmt = "op" # "#nimGCvisit((void*)$1, op);$n" + c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n" assert typ.kind != tyTypeDesc if typ.kind == tySequence: genTraverseProcSeq(c, "a".rope, typ) else: - if skipTypes(typ[0], typedescInst+{tyOwned}).kind == tyArray: + if skipTypes(typ.sons[0], typedescInst).kind == tyArray: # C's arrays are broken beyond repair: - genTraverseProc(c, "a".rope, typ[0]) + genTraverseProc(c, "a".rope, typ.sons[0]) else: - genTraverseProc(c, "(*a)".rope, typ[0]) + genTraverseProc(c, "(*a)".rope, typ.sons[0]) - let generatedProc = "$1 {$n$2$3$4}\n" % + let generatedProc = "$1 {$n$2$3$4}$n" % [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)] - m.s[cfsProcHeaders].addf("$1;\n", [header]) + m.s[cfsProcHeaders].addf("$1;$n", [header]) m.s[cfsProcs].add(generatedProc) - if hcrOn: - m.s[cfsProcHeaders].addf("N_NIMCALL_PTR(void, $1)(void*, NI);\n", [result]) - m.s[cfsDynLibInit].addf("\t$1 = (N_NIMCALL_PTR(void, )(void*, NI)) hcrRegisterProc($3, \"$1\", (void*)$2);\n", - [result, markerName, getModuleDllPath(m)]) - proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope = - discard genTypeInfoV1(m, s.loc.t, info) + discard genTypeInfo(m, s.loc.t, info) var c: TTraversalClosure var p = newProc(nil, m) - var sLoc = rdLoc(s.loc) + var sLoc = s.loc.r result = getTempName(m) if sfThread in s.flags and emulatedThreadVars(m.config): accessThreadLocalVar(p, s) sLoc = "NimTV_->" & sLoc - c.visitorFrmt = "0" # "#nimGCvisit((void*)$1, 0);$n" + c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n" c.p = p let header = "static N_NIMCALL(void, $1)(void)" % [result] genTraverseProc(c, sLoc, s.loc.t) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 98c1fc55f..66ad34c32 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -11,8 +11,10 @@ # ------------------------- Name Mangling -------------------------------- -import sighashes, modulegraphs -import std/md5 +import sighashes +from lowerings import createObj + +proc genProcHeader(m: BModule, prc: PSym): Rope proc isKeyword(w: PIdent): bool = # Nim and C++ share some keywords @@ -34,49 +36,44 @@ proc mangleField(m: BModule; name: PIdent): string = if isKeyword(name): result.add "_0" -proc fillBackendName(m: BModule; s: PSym) = - if s.loc.r == "": - var result = s.name.s.mangle.rope - result.add "__" - result.add m.g.graph.ifaces[s.itemId.module].uniqueName - result.add "_" - result.add rope s.itemId.item - if m.hcrOn: - result.add "_" - result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config)) +when false: + proc hashOwner(s: PSym): SigHash = + var m = s + while m.kind != skModule: m = m.owner + let p = m.owner + assert p.kind == skPackage + result = gDebugInfo.register(p.name.s, m.name.s) + +proc mangleName(m: BModule; s: PSym): Rope = + result = s.loc.r + if result == nil: + result = s.name.s.mangle.rope + add(result, idOrSig(s, m.module.name.s, m.sigConflicts)) s.loc.r = result writeMangledName(m.ndi, s, m.config) -proc fillParamName(m: BModule; s: PSym) = - if s.loc.r == "": +proc mangleParamName(m: BModule; s: PSym): Rope = + ## we cannot use 'sigConflicts' here since we have a BModule, not a BProc. + ## Fortunately C's scoping rules are sane enough so that that doesn't + ## cause any trouble. + result = s.loc.r + if result == nil: var res = s.name.s.mangle - res.add idOrSig(s, res, m.sigConflicts, m.config) - # Take into account if HCR is on because of the following scenario: - # if a module gets imported and it has some more importc symbols in it, - # some param names might receive the "_0" suffix to distinguish from what - # is newly available. That might lead to changes in the C code in nimcache - # that contain only a parameter name change, but that is enough to mandate - # recompilation of that source file and thus a new shared object will be - # relinked. That may lead to a module getting reloaded which wasn't intended - # and that may be fatal when parts of the current active callstack when - # performCodeReload() was called are from the module being reloaded - # unintentionally - example (3 modules which import one another): - # main => proxy => reloadable - # we call performCodeReload() in proxy to reload only changes in reloadable - # but there is a new import which introduces an importc symbol `socket` - # and a function called in main or proxy uses `socket` as a parameter name. - # That would lead to either needing to reload `proxy` or to overwrite the - # executable file for the main module, which is running (or both!) -> error. - s.loc.r = res.rope + if isKeyword(s.name) or m.g.config.cppDefines.contains(res): + res.add "_0" + result = res.rope + s.loc.r = result writeMangledName(m.ndi, s, m.config) -proc fillLocalName(p: BProc; s: PSym) = +proc mangleLocalName(p: BProc; s: PSym): Rope = assert s.kind in skLocalVars+{skTemp} #assert sfGlobal notin s.flags - if s.loc.r == "": + result = s.loc.r + if result == nil: var key = s.name.s.mangle + shallow(key) let counter = p.sigConflicts.getOrDefault(key) - var result = key.rope + result = key.rope if s.kind == skTemp: # speed up conflict search for temps (these are quite common): if counter != 0: result.add "_" & rope(counter+1) @@ -92,19 +89,20 @@ proc scopeMangledParam(p: BProc; param: PSym) = ## generate unique identifiers reliably (consider that ``var a = a`` is ## even an idiom in Nim). var key = param.name.s.mangle + shallow(key) p.sigConflicts.inc(key) const irrelevantForBackend = {tyGenericBody, tyGenericInst, tyGenericInvocation, - tyDistinct, tyRange, tyStatic, tyAlias, tySink, - tyInferred, tyOwned} + tyDistinct, tyRange, tyStatic, tyAlias, tySink, tyInferred} -proc typeName(typ: PType; result: var Rope) = +proc typeName(typ: PType): Rope = let typ = typ.skipTypes(irrelevantForBackend) - result.add $typ.kind - if typ.sym != nil and typ.kind in {tyObject, tyEnum}: - result.add "_" - result.add typ.sym.name.s.mangle + result = + if typ.sym != nil and typ.kind in {tyObject, tyEnum}: + rope($typ.kind & '_' & typ.sym.name.s.mangle) + else: + rope($typ.kind) proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope = var t = typ @@ -116,18 +114,15 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope = t = t.lastSon else: break - let typ = if typ.kind in {tyAlias, tySink, tyOwned}: typ.lastSon else: typ - if typ.loc.r == "": - typ.typeName(typ.loc.r) - typ.loc.r.add $sig + let typ = if typ.kind in {tyAlias, tySink}: typ.lastSon else: typ + if typ.loc.r == nil: + typ.loc.r = typ.typeName & $sig else: when defined(debugSigHashes): # check consistency: - var tn = newRopeAppender() - typ.typeName(tn) - assert($typ.loc.r == $(tn & $sig)) + assert($typ.loc.r == $(typ.typeName & $sig)) result = typ.loc.r - if result == "": internalError(m.config, "getTypeName: " & $typ.kind) + if result == nil: internalError(m.config, "getTypeName: " & $typ.kind) proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = case int(getSize(conf, typ)) @@ -137,25 +132,21 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = of 8: result = ctInt64 else: result = ctArray -proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = +proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = ## Maps a Nim type to a C type case typ.kind - of tyNone, tyTyped: result = ctVoid + of tyNone, tyStmt: result = ctVoid of tyBool: result = ctBool of tyChar: result = ctChar - of tyNil: result = ctPtr of tySet: result = mapSetType(conf, typ) - of tyOpenArray, tyVarargs: - if kind == skParam: result = ctArray - else: result = ctStruct - of tyArray, tyUncheckedArray: result = ctArray + of tyOpenArray, tyArray, tyVarargs: result = ctArray of tyObject, tyTuple: result = ctStruct of tyUserTypeClasses: doAssert typ.isResolvedUserTypeClass - return mapType(conf, typ.lastSon, kind) + return mapType(conf, typ.lastSon) of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal, - tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned: - result = mapType(conf, lastSon(typ), kind) + tyTypeDesc, tyAlias, tySink, tyInferred: + result = mapType(conf, lastSon(typ)) of tyEnum: if firstOrd(conf, typ) < 0: result = ctInt32 @@ -166,31 +157,32 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = of 4: result = ctInt32 of 8: result = ctInt64 else: result = ctInt32 - of tyRange: result = mapType(conf, typ[0], kind) - of tyPtr, tyVar, tyLent, tyRef: + of tyRange: result = mapType(conf, typ.sons[0]) + of tyPtr, tyVar, tyLent, tyRef, tyOptAsRef: var base = skipTypes(typ.lastSon, typedescInst) case base.kind - of tyOpenArray, tyArray, tyVarargs, tyUncheckedArray: result = ctPtrToArray - of tySet: - if mapSetType(conf, base) == ctArray: result = ctPtrToArray - else: result = ctPtr + of tyOpenArray, tyArray, tyVarargs: result = ctPtrToArray + #of tySet: + # if mapSetType(base) == ctArray: result = ctPtrToArray + # else: result = ctPtr + # XXX for some reason this breaks the pegs module else: result = ctPtr of tyPointer: result = ctPtr of tySequence: result = ctNimSeq of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct of tyString: result = ctNimStr - of tyCstring: result = ctCString + of tyCString: result = ctCString of tyInt..tyUInt64: result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) of tyStatic: - if typ.n != nil: result = mapType(conf, lastSon typ, kind) - else: doAssert(false, "mapType: " & $typ.kind) - else: doAssert(false, "mapType: " & $typ.kind) + if typ.n != nil: result = mapType(conf, lastSon typ) + else: doAssert(false, "mapType") + else: doAssert(false, "mapType") proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind = #if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr #else: - result = mapType(conf, typ, skResult) + result = mapType(conf, typ) proc isImportedType(t: PType): bool = result = t.sym != nil and sfImportc in t.sym.flags @@ -200,34 +192,29 @@ proc isImportedCppType(t: PType): bool = result = (t.sym != nil and sfInfixCall in t.sym.flags) or (x.sym != nil and sfInfixCall in x.sym.flags) -proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope +proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope +proc needsComplexAssignment(typ: PType): bool = + result = containsGarbageCollectedRef(typ) proc isObjLackingTypeField(typ: PType): bool {.inline.} = result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and - (typ[0] == nil) or isPureObject(typ)) + (typ.sons[0] == nil) or isPureObject(typ)) -proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool = +proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool = # Arrays and sets cannot be returned by a C procedure, because C is # such a poor programming language. # We exclude records with refs too. This enhances efficiency and # is necessary for proper code generation of assignments. - var rettype = typ - var isAllowedCall = true - if isProc: - rettype = rettype[0] - isAllowedCall = typ.callConv in {ccClosure, ccInline, ccNimCall} - if rettype == nil or (isAllowedCall and - getSize(conf, rettype) > conf.target.floatSize*3): - result = true + if rettype == nil: result = true else: - case mapType(conf, rettype, skResult) + case mapType(conf, rettype) of ctArray: result = not (skipTypes(rettype, typedescInst).kind in {tyVar, tyLent, tyRef, tyPtr}) of ctStruct: let t = skipTypes(rettype, typedescInst) if rettype.isImportedCppType or t.isImportedCppType: return false - result = containsGarbageCollectedRef(t) or + result = needsComplexAssignment(t) or (t.kind == tyObject and not isObjLackingTypeField(t)) else: result = false @@ -236,7 +223,7 @@ const "N_STDCALL", "N_CDECL", "N_SAFECALL", "N_SYSCALL", # this is probably not correct for all platforms, # but one can #define it to what one wants - "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_THISCALL", "N_CLOSURE", "N_NOCONV"] + "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"] proc cacheGetType(tab: TypeCache; sig: SigHash): Rope = # returns nil if we need to declare this type @@ -245,26 +232,40 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope = result = tab.getOrDefault(sig) proc addAbiCheck(m: BModule, t: PType, name: Rope) = - if isDefined(m.config, "checkAbi") and (let size = getSize(m.config, t); size != szUnknownSize): - var msg = "backend & Nim disagree on size for: " - msg.addTypeHeader(m.config, t) - var msg2 = "" - msg2.addQuoted msg # not a hostspot so extra allocation doesn't matter - m.s[cfsTypeInfo].addf("NIM_STATIC_ASSERT(sizeof($1) == $2, $3);$n", [name, rope(size), msg2.rope]) - # see `testCodegenABICheck` for example error message it generates + if isDefined(m.config, "checkabi"): + addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(getSize(m.config, t))]) +proc ccgIntroducedPtr(conf: ConfigRef; s: PSym): bool = + var pt = skipTypes(s.typ, typedescInst) + assert skResult != s.kind + if tfByRef in pt.flags: return true + elif tfByCopy in pt.flags: return false + case pt.kind + of tyObject: + if s.typ.sym != nil and sfForward in s.typ.sym.flags: + # forwarded objects are *always* passed by pointers for consistency! + result = true + elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3): + result = true # requested anyway + elif (tfFinal in pt.flags) and (pt.sons[0] == nil): + result = false # no need, because no subtyping possible + else: + result = true # ordinary objects are always passed by reference, + # otherwise casting doesn't work + of tyTuple: + result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options) + else: result = false -proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) = - fillLoc(param.sym.loc, locParam, param, "Result", +proc fillResult(conf: ConfigRef; param: PNode) = + fillLoc(param.sym.loc, locParam, param, ~"Result", OnStack) let t = param.sym.typ - if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, proctype): + if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, t): incl(param.sym.loc.flags, lfIndirect) param.sym.loc.storage = OnUnknown proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope = if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone: - useHeader(m, t.sym) result = t.sym.loc.r else: result = rope(literal) @@ -281,78 +282,67 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = of tyString: case detectStrVersion(m) of 2: - cgsym(m, "NimStrPayload") - cgsym(m, "NimStringV2") + discard cgsym(m, "string") result = typeNameOrLiteral(m, typ, "NimStringV2") else: - cgsym(m, "NimStringDesc") + discard cgsym(m, "NimStringDesc") result = typeNameOrLiteral(m, typ, "NimStringDesc*") - of tyCstring: result = typeNameOrLiteral(m, typ, "NCSTRING") + of tyCString: result = typeNameOrLiteral(m, typ, "NCSTRING") of tyBool: result = typeNameOrLiteral(m, typ, "NIM_BOOL") of tyChar: result = typeNameOrLiteral(m, typ, "NIM_CHAR") - of tyNil: result = typeNameOrLiteral(m, typ, "void*") + of tyNil: result = typeNameOrLiteral(m, typ, "0") of tyInt..tyUInt64: result = typeNameOrLiteral(m, typ, NumericalTypeToStr[typ.kind]) - of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ[0]) + of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0]) of tyStatic: if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ) else: internalError(m.config, "tyStatic for getSimpleTypeDesc") - of tyGenericInst, tyAlias, tySink, tyOwned: + of tyGenericInst, tyAlias, tySink: result = getSimpleTypeDesc(m, lastSon typ) - else: result = "" + else: result = nil - if result != "" and typ.isImportedType(): - let sig = hashType(typ, m.config) - if cacheGetType(m.typeCache, sig) == "": + if result != nil and typ.isImportedType(): + let sig = hashType typ + if cacheGetType(m.typeCache, sig) == nil: m.typeCache[sig] = result + addAbiCheck(m, typ, result) proc pushType(m: BModule, typ: PType) = - for i in 0..high(m.typeStack): - # pointer equality is good enough here: - if m.typeStack[i] == typ: return - m.typeStack.add(typ) + add(m.typeStack, typ) proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope = if typ == nil: result = rope("void") else: result = getSimpleTypeDesc(m, typ) - if result == "": result = cacheGetType(m.typeCache, sig) + if result == nil: result = cacheGetType(m.typeCache, sig) proc structOrUnion(t: PType): Rope = - let cachedUnion = rope("union") - let cachedStruct = rope("struct") let t = t.skipTypes({tyAlias, tySink}) - if tfUnion in t.flags: cachedUnion - else: cachedStruct + (if tfUnion in t.flags: rope("union") else: rope("struct")) -proc addForwardStructFormat(m: BModule, structOrUnion: Rope, typename: Rope) = - if m.compileToCpp: - m.s[cfsForwardTypes].addf "$1 $2;$n", [structOrUnion, typename] - else: - m.s[cfsForwardTypes].addf "typedef $1 $2 $2;$n", [structOrUnion, typename] - -proc seqStar(m: BModule): string = - if optSeqDestructors in m.config.globalOptions: result = "" - else: result = "*" +proc getForwardStructFormat(m: BModule): string = + if m.compileToCpp: result = "$1 $2;$n" + else: result = "typedef $1 $2 $2;$n" proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = result = cacheGetType(m.forwTypeCache, sig) - if result != "": return + if result != nil: return result = getTypePre(m, typ, sig) - if result != "": return - let concrete = typ.skipTypes(abstractInst) + if result != nil: return + let concrete = typ.skipTypes(abstractInst + {tyOpt}) case concrete.kind of tySequence, tyTuple, tyObject: result = getTypeName(m, typ, sig) m.forwTypeCache[sig] = result if not isImportedType(concrete): - addForwardStructFormat(m, structOrUnion(typ), result) + addf(m.s[cfsForwardTypes], getForwardStructFormat(m), + [structOrUnion(typ), result]) else: pushType(m, concrete) doAssert m.forwTypeCache[sig] == result else: internalError(m.config, "getTypeForward(" & $typ.kind & ')') -proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): Rope = +proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = ## like getTypeDescAux but creates only a *weak* dependency. In other words ## we know we only need a pointer to it so we only generate a struct forward ## declaration: @@ -360,57 +350,15 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R case etB.kind of tyObject, tyTuple: if isImportedCppType(etB) and t.kind == tyGenericInst: - result = getTypeDescAux(m, t, check, kind) + result = getTypeDescAux(m, t, check) else: - result = getTypeForward(m, t, hashType(t, m.config)) + result = getTypeForward(m, t, hashType(t)) pushType(m, t) of tySequence: - let sig = hashType(t, m.config) - if optSeqDestructors in m.config.globalOptions: - if skipTypes(etB[0], typedescInst).kind == tyEmpty: - internalError(m.config, "cannot map the empty seq type to a C type") - - result = cacheGetType(m.forwTypeCache, sig) - if result == "": - result = getTypeName(m, t, sig) - if not isImportedType(t): - m.forwTypeCache[sig] = result - addForwardStructFormat(m, rope"struct", result) - let payload = result & "_Content" - addForwardStructFormat(m, rope"struct", payload) - - if cacheGetType(m.typeCache, sig) == "": - m.typeCache[sig] = result - #echo "adding ", sig, " ", typeToString(t), " ", m.module.name.s - appcg(m, m.s[cfsTypes], - "struct $1 {$N" & - " NI len; $1_Content* p;$N" & - "};$N", [result]) - else: - result = getTypeForward(m, t, sig) & seqStar(m) + result = getTypeForward(m, t, hashType(t)) & "*" pushType(m, t) else: - result = getTypeDescAux(m, t, check, kind) - -proc getSeqPayloadType(m: BModule; t: PType): Rope = - var check = initIntSet() - result = getTypeDescWeak(m, t, check, skParam) & "_Content" - #result = getTypeForward(m, t, hashType(t)) & "_Content" - -proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) = - let sig = hashType(t, m.config) - let result = cacheGetType(m.typeCache, sig) - if result == "": - discard getTypeDescAux(m, t, check, skVar) - else: - # little hack for now to prevent multiple definitions of the same - # Seq_Content: - appcg(m, m.s[cfsTypes], """$N -$3ifndef $2_Content_PP -$3define $2_Content_PP -struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE];}; -$3endif$N - """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, skVar), result, rope"#"]) + result = getTypeDescAux(m, t, check) proc paramStorageLoc(param: PSym): TStorageLoc = if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin { @@ -422,143 +370,136 @@ proc paramStorageLoc(param: PSym): TStorageLoc = proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, check: var IntSet, declareEnvironment=true; weakDep=false) = - params = "(" - if t[0] == nil or isInvalidReturnType(m.config, t): - rettype = "void" + params = nil + if t.sons[0] == nil or isInvalidReturnType(m.config, t.sons[0]): + rettype = ~"void" else: - rettype = getTypeDescAux(m, t[0], check, skResult) - for i in 1..