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..d804fb8f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,39 +1,26 @@ * !**/ !*.* - -# Cache -nimcache*/ -rnimcache*/ -dnimcache*/ +nimcache/ *.o !/icons/*.o -*.obj -*.ilk -*.exp -*.pdb -*.lib -*.dll *.exe *.so *.dylib *.zip *.iss -*.log -*.pdb mapping.txt tags install.sh deinstall.sh -doc/html/ doc/*.html -doc/pdf +doc/*.pdf doc/*.idx /web/upload -/build/* +build/* bin/* # iOS specific wildcards. @@ -43,70 +30,15 @@ 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 - -# Private directories and files (IDEs) -.*/ -~* - -# testament cruft; TODO: generate these in a gitignore'd dir (./build) in the first place. -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/* +/csources/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 31908d223..000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,62 +0,0 @@ -# xxx unused, out of date - -image: ubuntu:18.04 - -stages: - - pre-build - - build - - deploy - - test - -.linux_set_path: &linux_set_path_def - before_script: - - export PATH=$(pwd)/bin${PATH:+:$PATH} - tags: - - linux - -.windows_set_path: &win_set_path_def - before_script: - - set PATH=%CD%\bin;%PATH% - tags: - - windows - - -build-windows: - stage: build - script: - - ci\build.bat - artifacts: - paths: - - bin\nim.exe - - bin\nimd.exe - - compiler\nim.exe - - koch.exe - expire_in: 1 week - tags: - - windows - -deploy-windows: - stage: deploy - script: - - koch.exe winrelease - artifacts: - paths: - - build/*.exe - - build/*.zip - expire_in: 1 week - tags: - - windows - - fast - - - -test-windows: - stage: test - <<: *win_set_path_def - script: - - call ci\deps.bat - - nim c testament\tester - - testament\tester.exe all - tags: - - windows - - fast 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/empty.txt b/bin/empty.txt index 666142073..20f9a91e3 100644 --- a/bin/empty.txt +++ b/bin/empty.txt @@ -1 +1 @@ -This file keeps several tools from deleting this subdirectory. +This file keeps several tools from deleting this subdirectory. 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.sh b/build.sh new file mode 100644 index 000000000..139c28359 --- /dev/null +++ b/build.sh @@ -0,0 +1,19 @@ +#!/bin/sh +set -e +set -x + +if [ ! -d "csources" ]; then + git clone --depth 1 https://github.com/nim-lang/csources.git +fi + +cd "csources" +sh build.sh +cd ".." + +./bin/nim c koch +./koch boot -d:release + +cp -f install.sh.template install.sh +chmod +x install.sh + +exit 0 diff --git a/build/empty.txt b/build/empty.txt index 666142073..20f9a91e3 100644 --- a/build/empty.txt +++ b/build/empty.txt @@ -1 +1 @@ -This file keeps several tools from deleting this subdirectory. +This file keeps several tools from deleting this subdirectory. 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 deleted file mode 100644 index 2db577d0b..000000000 --- a/changelog.md +++ /dev/null @@ -1,31 +0,0 @@ -# v2.2.0 - yyyy-mm-dd - - -## Changes affecting backward compatibility - - -## Standard library additions and changes - -[//]: # "Changes:" - - -[//]: # "Additions:" -- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes. - -[//]: # "Deprecations:" - - -[//]: # "Removals:" - - -## Language changes - - - -## Compiler changes - - - - -## Tool changes - 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_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/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/compiler.nimble b/compiler.nimble new file mode 100644 index 000000000..52eb4083b --- /dev/null +++ b/compiler.nimble @@ -0,0 +1,11 @@ +[Package] +name = "compiler" +version = "0.10.3" +author = "Andreas Rumpf" +description = "Compiler package providing the compiler sources as a library." +license = "MIT" + +InstallDirs = "doc, compiler" + +[Deps] +Requires: "nim >= 0.10.3" 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..3f3d45ff7 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -10,11 +10,8 @@ ## 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 arNo, arMaybe, arYes @@ -24,43 +21,42 @@ proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult 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; - # if they are + # we know it's the same array and we have 2 constant indexes; + # if they are var x = if a[1].kind == nkHiddenStdConv: a[1][1] else: a[1] var y = if b[1].kind == nkHiddenStdConv: b[1][1] else: b[1] - + if sameValue(x, y): result = arYes else: result = arNo # else: maybe and no are accurate @@ -131,7 +122,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult = # pointer derefs: if result != arYes: if isPartOf(a.typ, b.typ) != arNo: result = arMaybe - + of nkDotExpr: result = isPartOf(a[0], b[0]) if result != arNo: @@ -144,7 +135,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult = # weaken because of indirection: if result != arYes: if isPartOf(a.typ, b.typ) != arNo: result = arMaybe - + of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = isPartOf(a[1], b[1]) of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: @@ -153,26 +144,26 @@ proc isPartOf*(a, b: PNode): TAnalysisResult = # Calls return a new location, so a default of ``arNo`` is fine. else: # go down recursively; this is quite demanding: - const + const Ix0Kinds = {nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv, - nkCheckedFieldExpr, nkHiddenAddr} + nkCheckedFieldExpr} Ix1Kinds = {nkHiddenStdConv, nkHiddenSubConv, nkConv} DerefKinds = {nkHiddenDeref, nkDerefExpr} case b.kind of Ix0Kinds: # a* !<| b.f iff a* !<| b result = isPartOf(a, b[0]) - + of DerefKinds: - # a* !<| b[] iff + # a* !<| b[] iff if isPartOf(a.typ, b.typ) != arNo: result = isPartOf(a, b[0]) if result == arNo: result = arMaybe - + of Ix1Kinds: # a* !<| T(b) iff a* !<| b result = isPartOf(a, b[1]) - + of nkSym: # b is an atom, so we have to check a: case a.kind @@ -181,27 +172,11 @@ proc isPartOf*(a, b: PNode): TAnalysisResult = result = isPartOf(a[0], b) of Ix1Kinds: result = isPartOf(a[1], b) - + of DerefKinds: if isPartOf(a.typ, b.typ) != arNo: result = isPartOf(a[0], b) if result == arNo: result = arMaybe else: discard - of nkObjConstr: - 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..3798410e8 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 + msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists, + 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 @@ -63,8 +62,8 @@ type nkTripleStrLit, # a triple string literal """ nkNilLit, # the nil literal # end of atoms - nkComesFrom, # "comes from" template/macro information for - # better stack trace generation + nkMetaNode_Obsolete, # difficult to explain; represents itself + # (used for macros) nkDotCall, # used to temporarily flag a nkCall node; # this is used # for transforming ``s.len`` to ``len(s)`` @@ -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,25 @@ 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 32 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 +233,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,65 +249,35 @@ 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 - # deprecated and unused, except for the con + sfDeadCodeElim, # dead code elimination for the module is turned on sfBorrow, # proc is borrowed sfInfixCall, # symbol needs infix call syntax in target language; # for interfacing with C++, JS 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 + sfFakeConst* = sfDeadCodeElim # const cannot be put into a data section + sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher sfNoInit* = sfMainModule # don't generate code to init the variable - sfAllUntyped* = sfVolatile # macro or template is immediately expanded \ - # in a generic context + sfImmediate* = sfDeadCodeElim + # macro or template is immediately expanded + # without considering any possible overloads sfDirty* = sfPure # template is not hygienic (old styled template) @@ -330,18 +290,13 @@ const sfNoForward* = sfRegister # forward declarations are not required (per module) - sfReorder* = sfForward - # reordering pass is enabled + sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't + # require RC ops sfCompileToCpp* = sfInfixCall # compile the module as C++ code sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code sfExperimental* = sfOverriden # module uses the .experimental switch sfGoto* = sfOverriden # var is used for 'goto' code generation - sfWrittenTo* = sfBorrow # param is assigned to - # currently unimplemented - sfBase* = sfDiscriminant - 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,25 +305,17 @@ 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! # Don't forget to change hti.nim if you make a change here # XXX put this into an include file to avoid this issue! - # several types are no longer used (guess which), but a - # spot in the sequence is kept for backwards compatibility - # (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, tyArrayConstr, 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,73 +338,64 @@ 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, - tyVarargs, - tyUncheckedArray - # An array with boundaries [0,+∞] - + tyBigNum, + tyConst, tyMutable, tyVarargs, + tyIter, # unused tyProxy # used as errornous type (for idetools) - tyBuiltInTypeClass + tyBuiltInTypeClass #\ # Type such as the catch-all object, tuple, seq, etc - tyUserTypeClass + tyUserTypeClass #\ # the body of a user-defined type class - tyUserTypeClassInst + tyUserTypeClassInst #\ # Instance of a parametric user-defined type class. # Structured similarly to tyGenericInst. # tyGenericInst represents concrete types, while # this is still a "generic param" that will bind types # and resolves them during sigmatch and instantiation. - tyCompositeTypeClass + tyCompositeTypeClass #\ # Type such as seq[Number] # The notes for tyUserTypeClassInst apply here as well # sons[0]: the original expression used by the user. # sons[1]: fully expanded and instantiated meta type # (potentially following aliases) - tyInferred - # In the initial state `base` stores a type class constraining - # the types that can be inferred. After a candidate type is - # selected, it's stored in `lastSon`. Between `base` and `lastSon` - # there may be 0, 2 or more types that were also considered as - # possible candidates in the inference process (i.e. lastSon will - # be updated to store a type best conforming to all candidates) - - tyAnd, tyOr, tyNot + tyAnd, tyOr, tyNot #\ # boolean type classes such as `string|int`,`not seq`, # `Sortable and Enumable`, etc - tyAnything + tyAnything #\ # a type class matching any type - tyStatic + tyStatic #\ # a value known at compile type (the underlying type is .base) - tyFromExpr + tyFromExpr #\ # This is a type representing an expression that depends # on generic parameters (the expression is stored in t.n) # It will be converted to a real type only during generic # instantiation and prior to this it has the potential to # be any type. - tyConcept - # new style concept. - - tyVoid - # now different from tyEmpty, hurray! - tyIterable + tyFieldAccessor #\ + # Expressions such as Type.field (valid in contexts such + # as the `is` operator and magics like `high` and `low`). + # Could be lifted to a single argument proc returning the + # field value. + # sons[0]: type of containing object or tuple + # sons[1]: field type + # .n: nkDotExpr storing the field name 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 +409,7 @@ const tyUserTypeClass, tyUserTypeClassInst, tyAnd, tyOr, tyNot, tyAnything} - tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyUntyped} + 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? + tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses type TTypeKinds* = set[TTypeKind] @@ -491,7 +423,6 @@ type # but unfortunately it has measurable impact for compilation # efficiency nfTransf, # node has been transformed - nfNoRewrite # node should not be transformed anymore nfSem # node has been checked for semantics nfLL # node has gone through lambda lifting nfDotField # the call can use a dot operator @@ -499,27 +430,15 @@ 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) + nfIsCursor # this node is attached a cursor; used for idetools TNodeFlags* = set[TNodeFlag] - TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46) + TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 28) 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`` @@ -530,24 +449,18 @@ type # proc foo(T: typedesc, list: seq[T]): var T # proc foo(L: static[int]): array[L, int] # can be attached to ranges to indicate that the range - # can be attached to generic procs with free standing - # type parameters: e.g. proc foo[T]() # depends on unresolved static params. - tfResolved # marks a user type class, after it has been bound to a - # concrete type (lastSon becomes the concrete type) tfRetType, # marks return types in proc (used to detect type classes # used as return types for return type inference) tfCapturesEnv, # whether proc really captures some environment tfByCopy, # pass object/tuple by copy (C backend) tfByRef, # pass object/tuple by reference (C backend) tfIterator, # type is really an iterator, not a tyProc - tfPartial, # type is declared as 'partial' + tfShared, # type is 'shared' 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 initalization 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 @@ -556,33 +469,12 @@ type tfHasStatic 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]) # T and I here can bind to both typedesc and static types # before this is determined, we'll consider them to be a # wildcard type. tfHasAsgn # type has overloaded assignment operator tfBorrowDot # distinct type borrows '.' - 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 - 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] @@ -603,9 +495,9 @@ type skConst, # a constant skResult, # special 'result' variable skProc, # a proc - skFunc, # a func skMethod, # a method - skIterator, # an iterator + skIterator, # an inline iterator + skClosureIterator, # a resumable closure iterator skConverter, # a type converter skMacro, # a macro skTemplate, # a template; currently also misused for user-defined @@ -622,157 +514,114 @@ type TSymKinds* = set[TSymKind] const - routineKinds* = {skProc, skFunc, skMethod, skIterator, + routineKinds* = {skProc, skMethod, skIterator, skClosureIterator, skConverter, skMacro, skTemplate} - ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub, skAlias} + routineKinds - + tfIncompleteStruct* = tfVarargs + tfUncheckedArray* = tfVarargs tfUnion* = tfNoSideEffect tfGcSafe* = tfThread tfObjHasKids* = tfEnumHasHoles - 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, tfShared, 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, + mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin, + mEcho, mShallowCopy, mSlurp, mStaticExec, mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst, - mInc, mDec, mOrd, - mNew, mNewFinalize, mNewSeq, mNewSeqOfCap, - mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq, + mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, + mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq, mIncl, mExcl, mCard, mChr, mGCref, mGCunref, - mAddI, mSubI, mMulI, mDivI, mModI, - mSucc, mPred, + + mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64, + mDivI64, mModI64, mSucc, mPred, mAddF64, mSubF64, mMulF64, mDivF64, - mShrI, mShlI, mAshrI, mBitandI, mBitorI, mBitxorI, - mMinI, mMaxI, - mAddU, mSubU, mMulU, mDivU, mModU, - mEqI, mLeI, mLtI, - mEqF64, mLeF64, mLtF64, - mLeU, mLtU, - mEqEnum, mLeEnum, mLtEnum, - mEqCh, mLeCh, mLtCh, - mEqB, mLeB, mLtB, - mEqRef, mLePtr, mLtPtr, - mXor, mEqCString, mEqProc, - mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, + + mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, + mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, + mMinF64, mMaxF64, mAddU, mSubU, mMulU, + mDivU, mModU, mEqI, mLeI, + mLtI, + mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64, + mLeU, mLtU, mLeU64, mLtU64, + mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef, + mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI, + mUnaryMinusI64, mAbsI, mAbsI64, mNot, mUnaryPlusI, mBitnotI, - mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, - mIntToStr, mInt64ToStr, mFloatToStr, # for compiling nimStdlibVersion < 1.5.1 (not bootstrapping) - mCStrToStr, - mStrToStr, mEnumToStr, - mAnd, mOr, - mImplies, mIff, mExists, mForall, mOld, - mEqStr, mLeStr, mLtStr, - mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, - mConStrStr, mSlice, + mBitnotI64, 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, mSymDiffSet, mConStrStr, mSlice, mDotDot, # this one is only necessary to give nice compile time warnings mFields, mFieldPairs, mOmpParFor, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mInSet, mRepr, mExit, - mSetLengthStr, mSetLengthSeq, + 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, + mReset, mArray, mOpenArray, mRange, mSet, mSeq, 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, + mCpuEndian, mHostOS, mHostCPU, mAppType, + mNaN, mInf, mNegInf, mCompileOption, mCompileOptionArg, - mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, - mNKind, mNSymKind, - - mNccValue, mNccInc, mNcsAdd, mNcsIncl, mNcsLen, mNcsAt, - mNctPut, mNctLen, mNctGet, mNctHasNext, mNctNext, - + mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, - mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetStrVal, mNLineInfo, - mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mNSigHash, mNSizeOf, - mNBindSym, 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 - + mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo, + mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, + mNBindSym, mLocals, mNCallSite, + mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError, + mInstantiationInfo, mGetTypeInfo, mNGenSym +# 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, mIncl, mExcl, mCard, mChr, - mAddI, mSubI, mMulI, mDivI, mModI, - mAddF64, mSubF64, mMulF64, mDivF64, - mShrI, mShlI, mBitandI, mBitorI, mBitxorI, - mMinI, mMaxI, - mAddU, mSubU, mMulU, mDivU, mModU, - mEqI, mLeI, mLtI, - mEqF64, mLeF64, mLtF64, - mLeU, mLtU, - mEqEnum, mLeEnum, mLtEnum, - mEqCh, mLeCh, mLtCh, - mEqB, mLeB, mLtB, - mEqRef, mEqProc, mLePtr, mLtPtr, mEqCString, mXor, - mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI, - mUnaryPlusF64, mUnaryMinusF64, - mCharToStr, mBoolToStr, - mIntToStr, mInt64ToStr, mFloatToStr, - mCStrToStr, - mStrToStr, mEnumToStr, - mAnd, mOr, - mEqStr, mLeStr, mLtStr, - mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, - mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem, - mInSet, mRepr, mOpenArrayToSeq} - - generatedMagics* = {mNone, mIsolate, mFinished, mOpenArrayToSeq} - ## magics that are generated as normal procs in the backend + mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64, + mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64, + mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, + mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, + mMinF64, mMaxF64, mAddU, mSubU, mMulU, + mDivU, mModU, mEqI, mLeI, + mLtI, + mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64, + mLeU, mLtU, mLeU64, mLtU64, + mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef, + mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, + mUnaryMinusI64, mAbsI, mAbsI64, mNot, + mUnaryPlusI, mBitnotI, + mBitnotI64, 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, mSymDiffSet, mConStrStr, + mAppendStrCh, mAppendStrStr, mAppendSeqElem, + 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, + mEcho, 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 +645,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 +667,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 'gCmd == cmdPretty': Indicates # that the symbol has been imported via 'importc: "fullname"' and # no format string. lfNoDeepCopy, # no need for a deep copy @@ -828,74 +677,81 @@ 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 OnHeap # location is on heap or global # (reference counting needed) TLocFlags* = set[TLocFlag] TLoc* = object k*: TLocKind # kind of location - storage*: TStorageLoc + s*: TStorageLoc flags*: TLocFlags # location's flags - lode*: PNode # Node where the location came from; can be faked - r*: Rope # rope value of location (code generators) + t*: PType # type of location + r*: Rope # rope value of location (code generators) + heapRoot*: Rope # keeps track of the enclosing heap object that + # owns this location (required by GC algorithms + # employing heap snapshots or sliding views) # ---------------- end of backend information ------------------------------ TLibKind* = enum libHeader, libDynamic - - TLib* = object # also misused for headers! - # keep in sync with PackedLib + TLib* = object of lists.TListEntry # also misused for headers! kind*: TLibKind generated*: bool # needed for the backends: isOverriden*: bool name*: Rope path*: PNode # can be a string literal! - - CompilesId* = int ## id that is used for the caching logic within - ## ``system.compiles``. See the seminst module. TInstantiation* = object sym*: PSym concreteTypes*: seq[PType] - compilesId*: CompilesId + usedBy*: seq[int32] # list of modules using the generic + # needed in caas mode for purging the cache + # XXX: it's possible to switch to a + # simple ref count here PInstantiation* = ref TInstantiation - TScope* {.acyclic.} = object + TScope* = object depthLevel*: int symbols*: TStrTable + usingSyms*: seq[PNode] 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] + typScope*: PScope 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: + # 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,43 +766,28 @@ 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 - # for skModule the string literal to output for - # deprecated modules. - when defined(nimsuggest): - 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 +796,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,20 +804,24 @@ 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 '=' operator 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 TPairSeq* = seq[TPair] + TTable* = object # the same as table[PObject] of PObject + counter*: int + data*: TPairSeq TIdPair* = object key*: PIdObj @@ -997,7 +842,7 @@ type data*: TIdNodePairSeq TNodePair* = object - h*: Hash # because it is expensive to compute! + h*: THash # because it is expensive to compute! key*: PNode val*: int @@ -1015,162 +860,68 @@ 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} + OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator, + skConverter, skModule, skTemplate, skMacro} GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody, tyGenericParam} - StructuralEquivTypes*: TTypeKinds = {tyNil, tyTuple, tyArray, - tySet, tyRange, tyPtr, tyRef, tyVar, tyLent, tySequence, tyProc, tyOpenArray, + StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray, + tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray, tyVarargs} ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in:: # var x = expr tyBool, tyChar, tyEnum, tyArray, tyObject, - tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tyLent, tySequence, tyProc, + tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, 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 - ConstantDataTypes*: TTypeKinds = {tyArray, tySet, + tyFloat..tyFloat128, tyUInt..tyUInt64} + ConstantDataTypes*: TTypeKinds = {tyArrayConstr, 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, skMethod, skType, + skIterator, skClosureIterator, + 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, nfIsCursor} namePos* = 0 patternPos* = 1 # empty except for term rewriting macros genericParamsPos* = 2 paramsPos* = 3 pragmasPos* = 4 - miscPos* = 5 # used for undocumented and hacky stuff + optimizedCodePos* = 5 # will be used for exception tracking 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} nkIdentKinds* = {nkIdent, nkSym, nkAccQuoted, nkOpenSymChoice, nkClosedSymChoice} - nkPragmaCallKinds* = {nkExprColonExpr, nkCall, nkCallStrLit} nkLiterals* = {nkCharLit..nkTripleStrLit} - nkFloatLiterals* = {nkFloatLit..nkFloat128Lit} nkLambdaKinds* = {nkLambda, nkDo} - declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef} - routineDefs* = declarativeDefs + {nkMacroDef, nkTemplateDef} + declarativeDefs* = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef} procDefs* = nkLambdaKinds + declarativeDefs - callableDefs* = nkLambdaKinds + routineDefs nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice} nkStrKinds* = {nkStrLit..nkTripleStrLit} skLocalVars* = {skVar, skLet, skForVar, skParam, skResult} - skProcKinds* = {skProc, skFunc, skTemplate, skMacro, skIterator, + skProcKinds* = {skProc, skTemplate, skMacro, skIterator, skClosureIterator, 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 + skIterators* = {skIterator, skClosureIterator} var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things @@ -1179,106 +930,39 @@ proc isCallExpr*(n: PNode): bool = 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 - elif n.kind in {nkNone..nkFloat128Lit}: result = 0 - else: result = n.len - -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) +proc `[]`*(n: PNode, i: int): PNode {.inline.} = + result = n.sons[i] -template `[]`*(n: Indexable, i: int): Indexable = n.sons[i] -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 +proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode = result = newNode(kind) - result.info = info + result.intVal = intVal + +proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode = + result = newIntNode(kind, intVal) result.typ = typ -proc newTree*(kind: TNodeKind; children: varargs[PNode]): PNode = +proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode = result = newNode(kind) - if children.len > 0: - result.info = children[0].info - result.sons = @children + result.floatVal = floatVal -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 newStrNode*(kind: TNodeKind, strVal: string): PNode = + result = newNode(kind) + result.strVal = strVal -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, - info: TLineInfo; options: TOptions = {}): PSym = +proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym, + info: TLineInfo): 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 + new(result) + result.name = name + result.kind = symKind + result.flags = {} + result.info = info + result.options = gOptions + result.owner = owner + result.offset = - 1 + result.id = getID() + when debugIds: + registerId(result) + #if result.id < 2000: + # MessageOut(name.s & " has id: " & toString(result.id)) -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 +var emptyNode* = newNode(nkEmpty) +# There is a single empty node that is shared! Do not overwrite it! + +var anyGlobal* = newSym(skVar, getIdent("*"), nil, unknownLineInfo()) proc isMetaType*(t: PType): bool = return t.kind in tyMetaTypes or (t.kind == tyStatic and t.n == nil) or tfHasMeta in t.flags -proc isUnresolvedStatic*(t: PType): bool = - return t.kind == tyStatic and t.n == nil - proc linkTo*(t: PType, s: PSym): PType {.discardable.} = t.sym = s s.typ = t @@ -1375,13 +1023,13 @@ proc linkTo*(s: PSym, t: PType): PSym {.discardable.} = s.typ = t result = s -template fileIdx*(c: PSym): FileIndex = +template fileIdx*(c: PSym): int32 = # XXX: this should be used only on module symbols - c.position.FileIndex + c.position.int32 template filename*(c: PSym): string = # XXX: this should be used only on module symbols - c.position.FileIndex.toFilename + c.position.int32.toFilename proc appendToModule*(m: PSym, n: PNode) = ## The compiler will use this internally to add nodes that will be @@ -1399,21 +1047,30 @@ 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 copyTable*(dest: var TTable, src: TTable) = + dest.counter = src.counter + 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 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,100 +1093,128 @@ proc newSymNode*(sym: PSym, info: TLineInfo): PNode = result.typ = sym.typ result.info = info -proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode = +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.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 + result.info = info result.typ = typ -proc newIntTypeNode*(intVal: Int128, typ: PType): PNode = - # XXX: introduce range check - newIntTypeNode(castToInt64(intVal), typ) +proc addSon*(father, son: PNode) = + assert son != nil + if isNil(father.sons): father.sons = @[] + add(father.sons, son) -proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode = - result = newNode(kind) - result.floatVal = floatVal - -proc newStrNode*(kind: TNodeKind, strVal: string): PNode = - result = newNode(kind) - result.strVal = strVal - -proc newStrNode*(strVal: string; info: TLineInfo): PNode = - result = newNodeI(nkStrLit, info) - result.strVal = strVal +var emptyParams = newNode(nkFormalParams) +emptyParams.addSon(emptyNode) proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode, - params, + params = emptyParams, name, pattern, genericParams, - pragmas, exceptions: PNode): PNode = + pragmas, exceptions = ast.emptyNode): PNode = result = newNodeI(kind, info) result.sons = @[name, pattern, genericParams, params, 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 newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType = - result = PType(kind: kind, owner: owner, size: defaultSize, - align: defaultAlignment, itemId: id, - uniqueId: id) - when false: - if result.itemId.module == 55 and result.itemId.item == 2: - echo "KNID ", kind - writeStackTrace() +proc `$`*(x: TLockLevel): string = + if x.ord == UnspecifiedLockLevel.ord: result = "" + elif x.ord == UnknownLockLevel.ord: result = "" + else: result = $int16(x) +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) + #if result.id == 92231: + # echo "KNID ", kind + # writeStackTrace() + # messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id)) 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.lode == nil: a.lode = b.lode - if a.r == "": a.r = b.r + if a.k == low(a.k): a.k = b.k + if a.s == low(a.s): a.s = b.s + a.flags = a.flags + b.flags + if a.t == nil: a.t = b.t + if a.r == nil: a.r = b.r + #if a.a == 0: a.a = b.a -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 = + if isNil(n.sons): result = 0 + else: result = len(n.sons) + +proc len*(n: PType): int = + if isNil(n.sons): result = 0 + else: result = len(n.sons) + +proc sonsLen*(n: PNode): int = + if isNil(n.sons): result = 0 + else: result = len(n.sons) + +proc lastSon*(n: PNode): PNode = + result = n.sons[sonsLen(n) - 1] + +proc lastSon*(n: PType): PType = + result = n.sons[sonsLen(n) - 1] proc assignType*(dest, src: PType) = dest.kind = src.kind @@ -1538,52 +1223,63 @@ 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.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 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 {tyEmpty, tyStmt} proc makeStmtList*(n: PNode): PNode = if n.kind == nkStmtList: @@ -1952,190 +1553,10 @@ proc makeStmtList*(n: PNode): PNode = result = newNodeI(nkStmtList, n.info) result.add n -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 = - ## 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) - 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 - -proc isImportedException*(t: PType; conf: ConfigRef): bool = - assert t != nil - - if conf.exc != excCpp: - return false - - let base = t.skipTypes({tyAlias, tyPtr, tyDistinct, tyGenericInst}) - - if base.sym != nil and {sfCompileToCpp, sfImportc} * 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: - return n - - for son in n: - let n = son.findUnresolvedStatic - if n != nil: return n - - return nil - -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} +let + opNot* = createMagic("not", mNot) + opContains* = createMagic("contains", mInSet) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 4e09fab02..1707718d7 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -12,72 +12,71 @@ # the data structures here are used in various places of the compiler. import - ast, hashes, intsets, options, lineinfos, ropes, idents, rodutils, - msgs + ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils -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 +proc hashNode*(p: RootRef): THash +proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope # Convert a tree into its YAML representation; this is used by the # YAML code generator and it is invaluable for debugging purposes. # If maxRecDepht <> -1 then it won't print the whole graph. -proc typeToYaml*(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope -proc symToYaml*(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope -proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): Rope +proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope +proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope +proc lineInfoToStr*(info: TLineInfo): Rope +# ----------------------- node sets: --------------------------------------- +proc objectSetContains*(t: TObjectSet, obj: RootRef): bool + # returns true whether n is in t +proc objectSetIncl*(t: var TObjectSet, obj: RootRef) + # include an element n in the table t +proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool + # more are not needed ... + +# ----------------------- (key, val)-Hashtables ---------------------------- +proc tablePut*(t: var TTable, key, val: RootRef) +proc tableGet*(t: TTable, key: RootRef): RootRef +type + TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found + +proc tableSearch*(t: TTable, key, closure: RootRef, + comparator: TCmpProc): RootRef + # return val as soon as comparator returns true; if this never happens, + # nil is returned + +# ----------------------- str table ----------------------------------------- +proc strTableContains*(t: TStrTable, n: PSym): bool +proc strTableAdd*(t: var TStrTable, n: PSym) +proc strTableGet*(t: TStrTable, name: PIdent): PSym + +type + TTabIter*{.final.} = object # consider all fields here private + h*: THash # current hash + +proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym +proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym + # usage: + # var + # i: TTabIter + # s: PSym + # s = InitTabIter(i, table) + # while s != nil: + # ... + # s = NextIter(i, table) + # + +type + TIdentIter*{.final.} = object # iterator over all syms with same identifier + h*: THash # current hash + name*: PIdent + + +proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym +proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym # 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 - 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() +proc debug*(n: PSym) {.deprecated.} +proc debug*(n: PType) {.deprecated.} +proc debug*(n: PNode) {.deprecated.} # --------------------------- ident tables ---------------------------------- proc idTableGet*(t: TIdTable, key: PIdObj): RootRef @@ -91,9 +90,11 @@ 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 getModule*(s: PSym): PSym proc mustRehash*(length, counter: int): bool -proc nextTry*(h, maxHash: Hash): Hash {.inline.} +proc nextTry*(h, maxHash: THash): THash {.inline.} # ------------- table[int, int] --------------------------------------------- const @@ -115,28 +116,28 @@ 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: if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal else: - # don't raise an internal error for 'nim check': + # don't raise an internal error for 'nimrod check': #InternalError(a.info, "SameValue") discard @@ -144,14 +145,14 @@ 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: if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal else: - # don't raise an internal error for 'nim check': + # don't raise an internal error for 'nimrod check': #InternalError(a.info, "leValue") discard @@ -165,77 +166,37 @@ 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", + [istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)]) + inc(mycount) + if mycount > 0: addf(result, "$N$1", [rspaces(indent)]) + add(result, "]") + assert(mycount == n.counter) -proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet, indent: int, +proc ropeConstr(indent: int, c: openArray[Rope]): Rope = + # array of (name, value) pairs + var istr = rspaces(indent + 2) + result = rope("{") + var i = 0 + while i <= high(c): + if i > 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(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)]) + var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1) + result = ropeConstr(indent, [rope("kind"), + makeYamlString($n.kind), + rope("name"), makeYamlString(n.name.s), + rope("typ"), typeToYamlAux(n.typ, marker, + indent + 2, maxRecDepth - 1), + rope("info"), lineInfoToStr(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, +proc typeToYamlAux(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(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") + result = rope("null") + result = ropeConstr(indent, [rope("kind"), + makeYamlString($n.kind), + rope("sym"), symToYamlAux(n.sym, marker, + indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(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]) - 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]) - -proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int, +proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int, maxRecDepth: int): Rope = if n == nil: result = rope("null") @@ -362,320 +334,147 @@ 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(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", - [istr, symToYamlAux(conf, n.sym, marker, indent + 2, maxRecDepth)]) + addf(result, ",$N$1\"sym\": $2", + [istr, symToYamlAux(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(n.sons[i], marker, indent + 4, maxRecDepth - 1)]) - result.addf("$N$1]", [istr]) - result.addf(",$N$1\"typ\": $2", - [istr, typeToYamlAux(conf, n.typ, marker, indent + 2, maxRecDepth)]) - result.addf("$N$1}", [rspaces(indent)]) + addf(result, "$N$1]", [istr]) + addf(result, ",$N$1\"typ\": $2", + [istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)]) + addf(result, "$N$1}", [rspaces(indent)]) -proc treeToYaml(conf: ConfigRef; n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope = +proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope = var marker = initIntSet() - result = treeToYamlAux(conf, n, marker, indent, maxRecDepth) + result = treeToYamlAux(n, marker, indent, maxRecDepth) -proc typeToYaml(conf: ConfigRef; n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope = +proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope = var marker = initIntSet() - result = typeToYamlAux(conf, n, marker, indent, maxRecDepth) + result = typeToYamlAux(n, marker, indent, maxRecDepth) -proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope = +proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope = var marker = initIntSet() - result = symToYamlAux(conf, n, marker, indent, maxRecDepth) + result = symToYamlAux(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(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(n.sons[i], maxRecDepth-1)) + if n.kind == tyObject and n.n != nil: + add(result, ", node: ") + add(result, debugTree(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(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)] + if maxRecDepth != 0: + 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(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(n.sons[i], + indent + 4, maxRecDepth - 1, renderType)]) + addf(result, "$N$1]", [istr]) + addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) + 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 +proc debug(n: PSym) = + if n == nil: + msgWriteln("null") + elif n.kind == skUnknown: + msgWriteln("skUnknown") 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: result = t.data[index].val + else: result = nil + +proc tableRawInsert(data: var TPairSeq, key, val: RootRef) = + var h: THash = hashNode(key) and high(data) + while data[h].key != nil: + assert(data[h].key != key) + h = nextTry(h, high(data)) + assert(data[h].key == nil) + data[h].key = key + data[h].val = val + +proc tableEnlarge(t: var TTable) = + var n: TPairSeq + newSeq(n, len(t.data) * GrowthFactor) + for i in countup(0, high(t.data)): + if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val) + swap(t.data, n) + +proc tablePut(t: var TTable, key, val: RootRef) = + var index = tableRawGet(t, key) + if index >= 0: + t.data[index].val = val + else: + if mustRehash(len(t.data), t.counter): tableEnlarge(t) + tableRawInsert(t.data, key, val) + inc(t.counter) + +proc strTableContains(t: TStrTable, n: PSym): bool = + var h: THash = n.name.h and high(t.data) # start with real hash value while t.data[h] != nil: if (t.data[h] == n): return true h = nextTry(h, high(t.data)) result = false -proc strTableRawInsert(data: var seq[PSym], n: PSym) = - var h: Hash = n.name.h and high(data) - while data[h] != nil: - if data[h] == n: - # allowed for 'export' feature: - #InternalError(n.info, "StrTableRawInsert: " & n.name.s) - return - h = nextTry(h, high(data)) - assert(data[h] == nil) - data[h] = n +proc strTableRawInsert(data: var TSymSeq, n: PSym) = + var h: THash = n.name.h and high(data) + if sfImmediate notin n.flags: + # fast path: + while data[h] != nil: + if data[h] == n: + # allowed for 'export' feature: + #InternalError(n.info, "StrTableRawInsert: " & n.name.s) + return + h = nextTry(h, high(data)) + assert(data[h] == nil) + data[h] = n + else: + # slow path; we have to ensure immediate symbols are preferred for + # symbol lookups. + # consider the chain: foo (immediate), foo, bar, bar (immediate) + # then bar (immediate) gets replaced with foo (immediate) and the non + # immediate foo is picked! Thus we need to replace it with the first + # slot that has in fact the same identifier stored in it! + var favPos = -1 + while data[h] != nil: + if data[h] == n: return + if favPos < 0 and data[h].name.id == n.name.id: favPos = h + h = nextTry(h, high(data)) + assert(data[h] == nil) + data[h] = n + if favPos >= 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) + var h: THash = prevSym.name.h and high(data) while data[h] != nil: if data[h] == prevSym: data[h] = newSym @@ -753,24 +618,29 @@ 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) +proc strTableAdd(t: var TStrTable, n: PSym) = + 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 reallySameIdent(a, b: string): bool {.inline.} = + when defined(nimfix): + result = a[0] == b[0] + else: + result = true + +proc strTableIncl*(t: var TStrTable, n: PSym): 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 h: THash = n.name.h and high(t.data) var replaceSlot = -1 while true: var it = t.data[h] @@ -779,69 +649,52 @@ proc strTableInclReportConflict*(t: var TStrTable, n: PSym; # and overloading: (var x=@[]; x).mapIt(it). # 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.name.id == n.name.id and reallySameIdent(it.name.s, n.name.s): + 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): + t.data[replaceSlot] = n # overwrite it with newer definition! + 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 + result = false -proc strTableIncl*(t: var TStrTable, n: PSym; - onConflictKeepOld = false): bool {.discardable.} = - result = strTableInclReportConflict(t, n, onConflictKeepOld) != nil - -proc strTableGet*(t: TStrTable, name: PIdent): PSym = - var h: Hash = name.h and high(t.data) +proc strTableGet(t: TStrTable, name: PIdent): PSym = + var h: THash = name.h and high(t.data) while true: result = t.data[h] if result == nil: break if result.name.id == name.id: break h = nextTry(h, high(t.data)) - -type - TIdentIter* = object # iterator over all syms with same identifier - h*: Hash # current hash - 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 - h = nextTry(h, high(tab.data)) - if h == start: - p = nil - break - p = tab.data[h] - if p != nil: - result = p # increase the count - else: - result = nil - ti.h = nextTry(h, high(tab.data)) - -proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym = +proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym = ti.h = s.h ti.name = s if tab.counter == 0: result = nil else: result = nextIdentIter(ti, tab) +proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym = + var h = ti.h and high(tab.data) + var start = h + result = tab.data[h] + while result != nil: + if result.name.id == ti.name.id: break + h = nextTry(h, high(tab.data)) + if h == start: + result = nil + break + result = tab.data[h] + ti.h = nextTry(h, high(tab.data)) + proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, excluding: IntSet): PSym = - var h: Hash = ti.h and high(tab.data) + var h: THash = ti.h and high(tab.data) var start = h result = tab.data[h] while result != nil: @@ -862,33 +715,20 @@ proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent, if tab.counter == 0: result = nil else: result = nextIdentExcluding(ti, tab, excluding) -type - TTabIter* = object - h: Hash +proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym = + ti.h = 0 # we start by zero ... + if tab.counter == 0: + result = nil # FIX 1: removed endless loop + else: + result = nextIter(ti, tab) -proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym = - # usage: - # var - # i: TTabIter - # s: PSym - # s = InitTabIter(i, table) - # while s != nil: - # ... - # s = NextIter(i, table) - # +proc nextIter(ti: var TTabIter, tab: TStrTable): PSym = result = nil while (ti.h <= high(tab.data)): result = tab.data[ti.h] inc(ti.h) # ... and increment by one always if result != nil: break -proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym = - ti.h = 0 - if tab.counter == 0: - result = nil - else: - result = nextIter(ti, tab) - iterator items*(tab: TStrTable): PSym = var it: TTabIter var s = initTabIter(it, tab) @@ -897,13 +737,13 @@ 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 proc idTableRawGet(t: TIdTable, key: int): int = - var h: Hash + var h: THash h = key and high(t.data) # start with real hash value while t.data[h].key != nil: if t.data[h].key.id == key: @@ -932,7 +772,7 @@ iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] = yield (t.data[i].key.id, t.data[i].val) proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) = - var h: Hash + var h: THash h = key.id and high(data) while data[h].key != nil: assert(data[h].key.id != key.id) @@ -950,9 +790,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,11 +801,11 @@ 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 = - var h: Hash + var h: THash h = key.id and high(t.data) # start with real hash value while t.data[h].key != nil: if t.data[h].key.id == key.id: @@ -979,8 +819,12 @@ 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 + var h: THash h = key.id and high(data) while data[h].key != nil: assert(data[h].key.id != key.id) @@ -995,27 +839,31 @@ 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 bitSetDiff*(x: var TBitSet, y: TBitSet) = - for i in 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 bitSetIntersect*(x: var TBitSet, y: TBitSet) = - for i in 0..high(x): x[i] = x[i] and y[i] - -proc bitSetEquals*(x, y: TBitSet): bool = - for i in 0..high(x): - if x[i] != 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 countup(0, high(x)): x[i] = x[i] and not 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 countup(0, high(x)): x[i] = x[i] and y[i] + +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] - - proc countSetBits(x: uint8): uint8 = - 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) - - - for it in low(uint8)..high(uint8): - arr[it] = countSetBits(cast[uint8](it)) - - arr - -proc bitSetCard*(x: TBitSet): BiggestInt = - for it in x: - result.inc int(populationCount[it]) diff --git a/compiler/btrees.nim b/compiler/btrees.nim deleted file mode 100644 index c79442249..000000000 --- a/compiler/btrees.nim +++ /dev/null @@ -1,179 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2018 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## 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 - entries: int - keys: array[M, Key] - case isInternal: bool - of false: - vals: array[M, Val] - of true: - links: array[M, Node[Key, Val]] - BTree*[Key, Val] = object - root: Node[Key, Val] - entries: int ## number of key-value pairs - -proc initBTree*[Key, Val](): BTree[Key, Val] = - BTree[Key, Val](root: Node[Key, Val](entries: 0, isInternal: false)) - -template less(a, b): bool = cmp(a, b) < 0 -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.. 0: result.add(indent & "(" & $h.keys[j] & ")\n") - toString(h.links[j], indent & " ", result) - -proc `$`[Key, Val](b: BTree[Key, Val]): string = - result = "" - toString(b.root, "", result) - -proc hasNext*[Key, Val](b: BTree[Key, Val]; index: int): bool = index < b.entries - -proc countSubTree[Key, Val](it: Node[Key, Val]): int = - if it.isInternal: - result = 0 - for k in 0.. i: - it = it.links[k] - dec i, (sum - c) - break - result = (it.keys[i], it.vals[i], index+1) - -iterator pairs*[Key, Val](b: BTree[Key, Val]): (Key, Val) = - var i = 0 - while hasNext(b, i): - let (k, v, i2) = next(b, i) - i = i2 - yield (k, v) - -proc len*[Key, Val](b: BTree[Key, Val]): int {.inline.} = b.entries diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim new file mode 100644 index 000000000..6fcc57a91 --- /dev/null +++ b/compiler/canonicalizer.nim @@ -0,0 +1,416 @@ +# +# +# The Nim Compiler +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements the canonalization for the various caching mechanisms. + +import strutils, db_sqlite, md5 + +var db: TDbConn + +# We *hash* the relevant information into 128 bit hashes. This should be good +# enough to prevent any collisions. + +type + TUid = distinct MD5Digest + +# For name mangling we encode these hashes via a variant of base64 (called +# 'base64a') and prepend the *primary* identifier to ease the debugging pain. +# So a signature like: +# +# proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) +# +# is mangled into: +# gABI_MTdmOWY5MTQ1MDcyNGQ3ZA +# +# This is a good compromise between correctness and brevity. ;-) + +const + cb64 = [ + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", + "O", "P", "Q", "R", "S", "T" "U", "V", "W", "X", "Y", "Z", + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", + "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "_A", "_B"] + +proc toBase64a(s: cstring, len: int): string = + ## encodes `s` into base64 representation. After `lineLen` characters, a + ## `newline` is added. + result = newStringOfCap(((len + 2) div 3) * 4) + var i = 0 + while i < s.len - 2: + let a = ord(s[i]) + let b = ord(s[i+1]) + let c = ord(s[i+2]) + result.add cb64[a shr 2] + result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] + result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)] + result.add cb64[c and 0x3F] + inc(i, 3) + if i < s.len-1: + let a = ord(s[i]) + let b = ord(s[i+1]) + result.add cb64[a shr 2] + result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] + result.add cb64[((b and 0x0F) shl 2)] + elif i < s.len: + let a = ord(s[i]) + result.add cb64[a shr 2] + result.add cb64[(a and 3) shl 4] + +proc toBase64a(u: TUid): string = toBase64a(cast[cstring](u), sizeof(u)) + +proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len) + +proc hashSym(c: var MD5Context, s: PSym) = + if sfAnon in s.flags or s.kind == skGenericParam: + c &= ":anon" + else: + var it = s.owner + while it != nil: + hashSym(c, it) + c &= "." + it = s.owner + c &= s.name.s + +proc hashTree(c: var MD5Context, n: PNode) = + if n == nil: + c &= "\255" + return + var k = n.kind + md5Update(c, cast[cstring](addr(k)), 1) + # we really must not hash line information. 'n.typ' is debatable but + # shouldn't be necessary for now and avoids potential infinite recursions. + case n.kind + of nkEmpty, nkNilLit, nkType: discard + of nkIdent: + c &= n.ident.s + of nkSym: + hashSym(c, n.sym) + of nkCharLit..nkUInt64Lit: + var v = n.intVal + md5Update(c, cast[cstring](addr(v)), sizeof(v)) + of nkFloatLit..nkFloat64Lit: + var v = n.floatVal + md5Update(c, cast[cstring](addr(v)), sizeof(v)) + of nkStrLit..nkTripleStrLit: + c &= n.strVal + else: + for i 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 preceeding [ 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 Symbol( + 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) + );""") + + 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) + );""") + + + #db.exec(sql""" + # --create unique index if not exists TsstNameIx on TestResult(name); + # """, []) + diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 48e7fd290..2dacc25e9 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -9,531 +9,250 @@ # # 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)] - of tyArray: - result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))] - of tyPtr, tyRef: - case lastSon(a.t).kind + var b, c: TLoc + initLocExpr(p, q[1], a) + initLocExpr(p, q[2], b) + initLocExpr(p, q[3], c) + let fmt = + case skipTypes(a.t, abstractVar+{tyPtr}).kind + of tyOpenArray, tyVarargs, tyArray, tyArrayConstr: + "($1)+($2), ($3)-($2)+1" 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)] - of tyArray: - result.add "$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, {}) + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): + "(*$1)->data+($2), ($3)-($2)+1" + else: + "$1->data+($2), ($3)-($2)+1" + else: (internalError("openArrayLoc: " & typeToString(a.t)); "") + result = fmt % [rdLoc(a), rdLoc(b), rdLoc(c)] else: - result = a + initLocExpr(p, n, a) + case skipTypes(a.t, abstractVar).kind + of tyOpenArray, tyVarargs: + result = "$1, $1Len0" % [rdLoc(a)] + of tyString, tySequence: + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): + result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)] + else: + result = "$1->data, $1->$2" % [a.rdLoc, lenField(p)] + of tyArray, tyArrayConstr: + result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))] + else: internalError("openArrayLoc: " & typeToString(a.t)) -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->data" % [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(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(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(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) - -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(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) - elif d.k notin {locTemp} and not hasNoInit(ri): + getTemp(p, typ.sons[0], d, needsInit=true) + elif d.k notin {locExpr, locTemp} and not hasNoInit(ri): # reset before pass as 'result' var: - discard "resetLoc(p, d)" - pl.add(addrLoc(p.config, d)) + resetLoc(p, d) + add(pl, addrLoc(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(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, {}) + initLoc(list, locCall, d.t, OnUnknown) + 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 ri.sons[i].typ.isCompileTimeOnly: + result = nil + elif 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] - 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 + assert(typ.n.sons[i].kind == nkSym) + if 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") - 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 +296,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 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}) + 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) + var op, a: TLoc + 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 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 +422,121 @@ 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) + initLoc(list, locCall, d.t, 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 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: - 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(" ") + 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(ri.info, "varargs for objective C method?") + 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(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(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(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) + initLoc(list, locCall, nil, 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.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) + when false: + if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d) 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.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) + postStmtActions(p) + when false: + if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d) -proc genCall(p: BProc, e: PNode, d: var TLoc) = genAsgnCall(p, nil, e, d) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a64a42219..93a9dd65d 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -9,153 +9,142 @@ # 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 = rfmt(nil, "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 = rfmt(nil, "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 int32Literal(i: int): Rope = + if i == int(low(int32)): + result = ~"(-2147483647 -1)" + else: + result = rope(i) -proc genLiteral(p: BProc, n: PNode, ty: PType; result: var Rope) = +proc genHexLiteral(v: PNode): Rope = + # hex literals are unsigned in C + # so we don't generate hex literals any longer. + if v.kind notin {nkIntLit..nkUInt64Lit}: + internalError(v.info, "genHexLiteral") + result = intLiteral(v.intVal) + +proc getStrLit(m: BModule, s: string): Rope = + discard cgsym(m, "TGenericSeq") + result = "TMP" & rope(backendId()) + addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n", + [result, makeCString(s), rope(len(s))]) + +proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = + if ty == nil: internalError(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, + skipTypes(ty, abstractVarRange)), 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 id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) - let tmpName = p.module.tmpBase & rope(id) - if id == p.module.labels: + let t = skipTypes(ty, abstractVarRange) + if t.kind == tyProc and t.callConv == ccClosure: + var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) + result = "TMP" & rope(id) + if id == gBackendId: # not found in cache: - inc(p.module.labels) - p.module.s[cfsStrData].addf( + inc(gBackendId) + 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, t), 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 - of tyNil: - genNilStringLiteral(p.module, n.info, result) - of tyString: - # with the new semantics for not '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) + if n.strVal.isNil: + result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", []) + elif skipTypes(ty, abstractVarRange).kind == tyString: + var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) + if id == gBackendId: + # string literal not found in the cache: + result = ropecg(p.module, "((#NimStringDesc*) &$1)", + [getStrLit(p.module, n.strVal)]) else: - genStringLiteral(p.module, n, result) + result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [rope(id)]) else: - result.add makeCString(n.strVal) - of nkFloatLit, nkFloat64Lit: - if ty.kind == tyFloat32: - result.add rope(n.floatVal.float32.toStrMaxPrecision) - else: - result.add rope(n.floatVal.toStrMaxPrecision) - of nkFloat32Lit: - result.add rope(n.floatVal.float32.toStrMaxPrecision) + result = makeCString(n.strVal) + of nkFloatLit..nkFloat64Lit: + result = rope(n.floatVal.toStrMaxPrecision) else: - internalError(p.config, n.info, "genLiteral(" & $n.kind & ')') + internalError(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: - let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) - let tmpName = p.module.tmpBase & rope(id) - if id == p.module.labels: + var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) + result = "TMP" & rope(id) + if id == gBackendId: # 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 + inc(gBackendId) + 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,43 +158,46 @@ proc getStorageLoc(n: PNode): TStorageLoc = else: result = OnUnknown else: result = OnUnknown of nkDerefExpr, nkHiddenDeref: - case n[0].typ.kind - of tyVar, tyLent: result = OnUnknown + case n.sons[0].typ.kind + of tyVar: result = OnUnknown of tyPtr: result = OnStack of tyRef: result = OnHeap - else: doAssert(false, "getStorageLoc") + else: internalError(n.info, "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 = - # for now we're conservative here: - if n.kind == nkBracket: - # This needs to be kept consistent with 'const' seq code - # generation! - 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)]) - elif dest.storage == OnHeap: - linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n", - [addrLoc(p.config, dest), rdLoc(src)]) +proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = + if dest.s == OnStack or not usesNativeGC(): + linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) + if needToKeepAlive in flags: keepAlive(p, dest) + elif dest.s == OnHeap: + # 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(dest), rdLoc(src)) + else: + linefmt(p, cpsStmts, "#asgnRefNoCycle((void**) $1, $2);$n", + addrLoc(dest), rdLoc(src)) else: linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", - [addrLoc(p.config, dest), rdLoc(src)]) + addrLoc(dest), rdLoc(src)) + if needToKeepAlive in flags: keepAlive(p, dest) proc asgnComplexity(n: PNode): int = if n != nil: @@ -220,32 +212,33 @@ 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 + result.s = a.s + result.t = t result.r = rdLoc(a) & "." & field + result.heapRoot = a.heapRoot proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = let newflags = - if src.storage == OnStatic: + if src.k == locData: flags + {needToCopy} elif tfShallow in dest.t.flags: flags - {needToCopy} 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 + result = getTempName() + linefmt(p, cpsLocals, "$1 $2;$n", storage, result) + lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b)) + if size < platform.intSize or t.kind in {tyRange, tyEnum}: + linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n", + result, intLiteral(firstOrd(t)), intLiteral(lastOrd(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" - ] - prc64: array[mAddI..mPred, string] = [ - "nimAddInt64", "nimSubInt64", - "nimMulInt64", "nimDivInt64", "nimModInt64", - "nimAddInt64", "nimSubInt64" - ] - opr: array[mAddI..mPred, string] = ["+", "-", "*", "/", "%", "+", "-"] + "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n", + "$# = #mulInt($#, $#);$n", "$# = #divInt($#, $#);$n", + "$# = #modInt($#, $#);$n", + "$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n", + "$# = #mulInt64($#, $#);$n", "$# = #divInt64($#, $#);$n", + "$# = #modInt64($#, $#);$n", + "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$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)] - putIntoDest(p, d, e, res) + let res = opr[m] % [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)] + putIntoDest(p, d, e.typ, 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, prc[m]) + putIntoDest(p, d, e.typ, "($#)($#)" % [getTypeDesc(p.module, t), res]) proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = + const + opr: array[mUnaryMinusI..mAbsI64, string] = [ + mUnaryMinusI: "((NI$2)-($1))", + mUnaryMinusI64: "-($1)", + mAbsI: "($1 > 0? ($1) : -($1))", + mAbsI64: "($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(t))) + putIntoDest(p, d, e.typ, opr[m] % [rdLoc(a), rope(getSize(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$3)($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 + "($4)((NU64)($1) >> (NU64)($2))", # ShrI64 + "($4)((NU64)($1) << (NU64)($2))", # ShlI64 + "($4)($1 & $2)", # BitandI64 + "($4)($1 | $2)", # BitorI64 + "($4)($1 ^ $2)", # BitxorI64 + "(($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)", # EqI64 + "($1 <= $2)", # LeI64 + "($1 < $2)", # LtI64 + "($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)", # EqCString + "($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) + s: BiggestInt + 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) + s = max(getSize(a.t), getSize(b.t)) * 8 + putIntoDest(p, d, e.typ, + binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s), + getSimpleTypeDesc(p.module, e.typ)]) 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: - putIntoDest(p, d, e, - "($1.ClP_0 == $2.ClP_0 && $1.ClE_0 == $2.ClE_0)" % [rdLoc(a), rdLoc(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) + if a.t.callConv == ccClosure: + putIntoDest(p, d, e.typ, + "($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)" % [rdLoc(a), rdLoc(b)]) else: - putIntoDest(p, d, e, "($1 == $2)" % [rdLoc(a), rdLoc(b)]) + putIntoDest(p, d, e.typ, "($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)") + unaryExpr(p, e, d, "$1.ClPrc == 0") else: - unaryExpr(p, e, d, "($1 == 0)") + 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 + "($3)((NU$2) ~($1))", # BitnotI64 + "$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.typ, + unArithTab[op] % [rdLoc(a), rope(getSize(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(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: - d.storage = OnHeap + #if e[0].kind != nkBracketExpr: + # message(e.info, warnUser, "CAME HERE " & renderTree(e)) + expr(p, e.sons[0], d) else: var a: TLoc - var typ = e[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: - initLocExprSingleUse(p, e[0][0], d) - return - else: - initLocExprSingleUse(p, e[0], a) + initLocExprSingleUse(p, e.sons[0], a) if d.k == locNone: + let typ = skipTypes(a.t, abstractInst) # 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 + # It is completely wrong to set 'd.s' here, unless it's not yet # been assigned to. case typ.kind of tyRef: - d.storage = OnHeap - of tyVar, tyLent: - d.storage = OnUnknown + d.s = OnHeap + of tyVar: + d.s = OnUnknown if tfVarIsPtr notin typ.flags and p.module.compileToCpp and e.kind == nkHiddenDeref: - putIntoDest(p, d, e, rdLoc(a), a.storage) + putIntoDest(p, d, e.typ, rdLoc(a)) return of tyPtr: - d.storage = OnUnknown # BUGFIX! - else: - internalError(p.config, e.info, "genDeref " & $typ.kind) + d.s = OnUnknown # BUGFIX! + else: internalError(e.info, "genDeref " & $a.t.kind) elif p.module.compileToCpp: - if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and + let typ = skipTypes(a.t, abstractInst) + if typ.kind == tyVar and tfVarIsPtr notin typ.flags and e.kind == nkHiddenDeref: - putIntoDest(p, d, e, rdLoc(a), a.storage) + putIntoDest(p, d, e.typ, rdLoc(a)) 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, a.t.sons[0], rdLoc(a)) 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]) + putIntoDest(p, d, e.typ, "(*$1)" % [rdLoc(a)]) 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) - putIntoDest(p, d, e, "&" & a.r, a.storage) + initLocExpr(p, e.sons[0], a) + putIntoDest(p, d, e.typ, "&" & a.r) #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(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) - putIntoDest(p, d, e, addrLoc(p.config, a), a.storage) + initLocExpr(p, e.sons[0], a) + putIntoDest(p, d, e.typ, addrLoc(a)) template inheritLocation(d: var TLoc, a: TLoc) = - if d.k == locNone: d.storage = a.storage + if d.k == locNone: d.s = a.s + if d.heapRoot == nil: + d.heapRoot = if a.heapRoot != nil: a.heapRoot else: a.r -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") +proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType = + initLocExpr(p, e.sons[0], a) + if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux") d.inheritLocation(a) discard getTypeDesc(p.module, a.t) # fill the record's fields.loc + result = a.t.getUniqueType 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}) - assert tupType.kind == tyTuple + initLocExpr(p, e.sons[0], a) d.inheritLocation(a) discard getTypeDesc(p.module, a.t) # fill the record's fields.loc + var ty = a.t.getUniqueType var r = rdLoc(a) - case e[1].kind - of nkIntLit..nkUInt64Lit: i = int(e[1].intVal) - else: internalError(p.config, e.info, "genTupleElem") - r.addf(".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 != "" - while ty != nil: - ty = ty.skipTypes(skipPtrs) - assert(ty.kind in {tyTuple, tyObject}) - result = lookupInRecord(ty.n, field.name) - if result != nil: - if resTyp != nil: resTyp[] = ty - break - if not p.module.compileToCpp: r.add(".Sup") - ty = ty[0] - if result == nil: internalError(p.config, field.info, "genCheckedRecordField") + case e.sons[1].kind + of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal) + else: internalError(e.info, "genTupleElem") + addf(r, ".Field$1", [rope(i)]) + putIntoDest(p, d, ty.sons[i], r) proc genRecordField(p: BProc, e: PNode, d: var TLoc) = var a: TLoc - genRecordFieldAux(p, e, d, a) + var ty = 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 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) - putIntoDest(p, d, e, r, a.storage) + addf(r, ".Field$1", [rope(f.position)]) + putIntoDest(p, d, f.typ, r) 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 - putIntoDest(p, d, e, r, a.storage) - r.freeze + var field: PSym = nil + while ty != nil: + if ty.kind notin {tyTuple, tyObject}: + internalError(e.info, "genRecordField") + field = lookupInRecord(ty.n, f.name) + if field != nil: break + if not p.module.compileToCpp: add(r, ".Sup") + ty = getUniqueType(ty.sons[0]) + if field == nil: internalError(e.info, "genRecordField 2 ") + if field.loc.r == nil: internalError(e.info, "genRecordField 3") + addf(r, ".$1", [field.loc.r]) + putIntoDest(p, d, field.typ, r) + #d.s = a.s 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, 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", [] + if firstOrd(ty) == 0: + if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)): + linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError();$n", + rdCharLoc(b), intLiteral(lastOrd(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(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))) + if idx < firstOrd(ty) or idx > lastOrd(ty): + localError(x.info, errIndexOutOfBounds) d.inheritLocation(a) - putIntoDest(p, d, n, - ropecg(p.module, "$1[($2)- $3]", [rdLoc(a), rdCharLoc(b), first]), a.storage) + putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), + rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first)) -proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) = +proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) = var a, b: TLoc initLocExpr(p, x, a) initLocExpr(p, y, b) - inheritLocation(d, a) - putIntoDest(p, d, n, - ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) + var ty = skipTypes(a.t, abstractVarRange) + if d.k == locNone: d.s = a.s + putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), + rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b))) -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", [] - - 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", [] - - else: discard - -proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = +proc genOpenArrayElem(p: BProc, 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", [] + initLocExpr(p, y, b) # emit range check: + if optBoundsCheck in p.options: + linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n", + rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``! + if d.k == locNone: d.s = a.s + putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)), + rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b))) - 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) - -proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = +proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) = var a, b: TLoc initLocExpr(p, x, a) initLocExpr(p, y, b) @@ -1114,51 +890,31 @@ 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 d.k == locNone: d.storage = OnHeap + if ty.kind == tyString: + linefmt(p, cpsStmts, + "if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", + rdLoc(b), rdLoc(a), lenField(p)) + else: + linefmt(p, cpsStmts, + "if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", + rdLoc(b), rdLoc(a), lenField(p)) + if d.k == locNone: d.s = OnHeap + d.heapRoot = a.r 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)]) - putIntoDest(p, d, n, - ropecg(p.module, "$1$3[$2]", [rdLoc(a), rdCharLoc(b), dataField(p)]), a.storage) + a.r = rfmt(nil, "(*$1)", a.r) + putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)), + rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b))) 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) 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, tyArrayConstr: genArrayElem(p, n.sons[0], n.sons[1], d) + of tyOpenArray, tyVarargs: genOpenArrayElem(p, n.sons[0], n.sons[1], d) + of tySequence, tyString: genSeqElem(p, n.sons[0], n.sons[1], d) + of tyCString: genCStringElem(p, 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])) - p.module.includeHeader("") - p.module.includeHeader("") - linefmt(p, cpsStmts, """Genode::log($1);$n""", [args]) - else: - if n.len == 0: - linefmt(p, cpsStmts, "#echoBinSafe(NIM_NIL, $1);$n", [n.len]) - else: - var a: TLoc - initLocExpr(p, n, a) - linefmt(p, cpsStmts, "#echoBinSafe($1, $2);$n", [a.rdLoc, n.len]) - 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", []) + internalAssert n.kind == nkBracket + discard lists.includeStr(p.module.headerFiles, "") + var args: Rope = nil + var a: TLoc + for i in countup(0, n.len-1): + initLocExpr(p, n.sons[i], a) + addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)]) + linefmt(p, cpsStmts, "printf($1$2);$n", + makeCString(repeat("%s", n.len) & tnl), args) -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 gcUsage(n: PNode) = + if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree) 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,32 +992,32 @@ 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 + ", [rdLoc(a), lenField(p)]) + add(appends, rfmt(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 + keepAlive(p, tmp) else: - genAssignment(p, d, tmp, {}) # no need for deep copying - gcUsage(p.config, e) + genAssignment(p, d, tmp, {needToKeepAlive}) # no need for deep copying + gcUsage(e) 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,991 +1028,610 @@ 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 + ", [rdLoc(a), lenField(p)]) + add(appends, rfmt(p.module, "#appendString($1, $2);$n", + rdLoc(dest), rdLoc(a))) + linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", + rdLoc(dest), lens, rope(L)) + keepAlive(p, dest) + add(p.s(cpsStmts), appends) + gcUsage(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) - #if bt != b.t: - # echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t) - initLoc(dest, locExpr, e[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}) - gcUsage(p.config, e) + let seqAppendPattern = if not p.module.compileToCpp: + "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n" + else: + "$1 = ($2) #incrSeq($1, sizeof($3));$n" + var a, b, dest: TLoc + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + lineCg(p, cpsStmts, seqAppendPattern, [ + rdLoc(a), + getTypeDesc(p.module, skipTypes(e.sons[1].typ, abstractVar)), + getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))]) + keepAlive(p, a) + initLoc(dest, locExpr, b.t, OnHeap) + dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField(p)) + genAssignment(p, dest, b, {needToCopy, afDestIsNil}) + gcUsage(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(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange))) -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 + let refType = skipTypes(a.t, abstractVarRange) var b: TLoc - initLoc(b, locExpr, a.lode, OnHeap) - let refType = typ.skipTypes(abstractInstOwned) - 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)]) + initLoc(b, locExpr, a.t, OnHeap) + if sizeExpr.isNil: + sizeExpr = "sizeof($1)" % + [getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange))] + let args = [getTypeDesc(p.module, refType), + genTypeInfo(p.module, refType), + sizeExpr] + if a.s == OnHeap and usesNativeGC(): + # use newObjRC1 as an optimization; and we don't need 'keepAlive' either + if canFormAcycle(a.t): + linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$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);$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, {needToKeepAlive}) # set the object type: + let bt = skipTypes(refType.sons[0], abstractRange) + 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) - gcUsage(p.config, e) + rawGenNew(p, a, nil) + gcUsage(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), length] var call: TLoc - initLoc(call, locExpr, dest.lode, OnHeap) - if dest.storage == OnHeap and usesWriteBarrier(p.config): + initLoc(call, locExpr, dest.t, OnHeap) + if dest.s == OnHeap and usesNativeGC(): if canFormAcycle(dest.t): - linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [dest.rdLoc]) + linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$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);$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]) - genAssignment(p, dest, call, {}) + call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args) + genAssignment(p, dest, call, {needToKeepAlive}) 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) - -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", []) - -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) - result = true - else: - result = false + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + genNewSeqAux(p, a, b.rdLoc) + gcUsage(e) proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = - #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 handleConstExpr(p, e, d): return - var t = e.typ.skipTypes(abstractInstOwned) - let isRef = t.kind == tyRef - - # check if we need to construct the object in a temporary - var useTemp = - isRef or - (d.k notin {locTemp,locLocalVar,locGlobalVar,locParam,locField}) or - (isPartOf(d.lode, e) != arNo) - var tmp: TLoc - var r: Rope - if useTemp: - getTemp(p, t, tmp) - r = rdLoc(tmp) - if isRef: - rawGenNew(p, tmp, "", needsInit = nfAllFieldsSet notin e.flags) - t = t.lastSon.skipTypes(abstractInstOwned) - r = "(*$1)" % [r] - gcUsage(p.config, e) - else: - constructLoc(p, tmp) + var t = e.typ.skipTypes(abstractInst) + getTemp(p, t, tmp) + let isRef = t.kind == tyRef + var r = rdLoc(tmp) + if isRef: + rawGenNew(p, tmp, nil) + t = t.lastSon.skipTypes(abstractInst) + r = "(*$1)" % [r] + gcUsage(e) else: - resetLoc(p, d) - r = rdLoc(d) + constructLoc(p, tmp) discard getTypeDesc(p.module, t) - let ty = getUniqueType(t) - for i in 1..data[$2]", rdLoc(d), intLiteral(i)) + arr.s = OnHeap # we know that sequences are on the heap + expr(p, t.sons[i], arr) + gcUsage(t) + +proc genArrToSeq(p: BProc, t: 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 t.kind == nkBracket: + t.sons[1].typ = t.typ + genSeqConstr(p, t.sons[1], d) return if d.k == locNone: - getTemp(p, n.typ, d) - initLocExpr(p, n[1], a) + getTemp(p, t.typ, d) # 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) - # bug #5007; do not produce excessive C source code: - if L < 10: - for i in 0..data[$2]", rdLoc(d), intLiteral(i)) + elem.s = OnHeap # we know that sequences are on the heap + initLoc(arr, locExpr, elemType(skipTypes(t.sons[1].typ, abstractInst)), a.s) + arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i)) + genAssignment(p, elem, arr, {afDestIsNil, needToCopy}) proc genNewFinalize(p: BProc, e: PNode) = var 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) - 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)]) + oldModule: BModule + refType = skipTypes(e.sons[1].typ, abstractVarRange) + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], f) + initLoc(b, locExpr, a.t, OnHeap) + ti = genTypeInfo(p.module, refType) + 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: + genAssignment(p, a, b, {needToKeepAlive}) # set the object type: bt = skipTypes(refType.lastSon, abstractRange) - genObjectInit(p, cpsStmts, bt, a, constructRefObj) - gcUsage(p.config, e) + genObjectInit(p, cpsStmts, bt, a, false) + gcUsage(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): Rope = + # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we + # have to call it here first: + let ti = genTypeInfo(p.module, dest) + if tfFinal in dest.flags or (p.module.objHasKidsValid 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 = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache) + when false: + # former version: + result = rfmt(p.module, "#isObj($1.m_type, $2)", + a, genTypeInfo(p.module, dest)) 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) - 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}) - discard getTypeDesc(p.module, t) + var nilCheck: Rope = nil + var t = skipTypes(a.t, abstractInst) + while t.kind in {tyVar, tyPtr, tyRef}: + if t.kind != tyVar: nilCheck = r + if t.kind != tyVar or not p.module.compileToCpp: + r = rfmt(nil, "(*$1)", r) + t = skipTypes(t.lastSon, typedescInst) 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], typedescInst) if isObjLackingTypeField(t): - globalError(p.config, x.info, + globalError(x.info, errGenerated, "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 = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r)) else: - ofExpr.add ro - ofExpr.add ")" - - putIntoDest(p, d, x, ofExpr, a.storage) + r = rfmt(p.module, "($1)", genOfHelper(p, dest, r)) + putIntoDest(p, d, getSysType(tyBool), r) 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, - ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]), a.storage) + putIntoDest(p, d, e.typ, + ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)])) of tyFloat..tyFloat128: - putIntoDest(p, d, e, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]), a.storage) + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)])) of tyBool: - putIntoDest(p, d, e, ropecg(p.module, "#reprBool($1)", [rdLoc(a)]), a.storage) + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprBool($1)", [rdLoc(a)])) of tyChar: - putIntoDest(p, d, e, ropecg(p.module, "#reprChar($1)", [rdLoc(a)]), a.storage) + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprChar($1)", [rdLoc(a)])) of tyEnum, tyOrdinal: - putIntoDest(p, d, e, - ropecg(p.module, "#reprEnum((NI)$1, $2)", [ - rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage) + putIntoDest(p, d, e.typ, + ropecg(p.module, "#reprEnum($1, $2)", [ + rdLoc(a), genTypeInfo(p.module, t)])) of tyString: - putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage) + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprStr($1)", [rdLoc(a)])) of tySet: - putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [ - addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), a.storage) + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprSet($1, $2)", [ + addrLoc(a), genTypeInfo(p.module, t)])) 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) + putIntoDest(p, b, e.typ, "$1, $1Len0" % [rdLoc(a)]) 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) - 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()") - putIntoDest(p, d, e, + putIntoDest(p, b, e.typ, + "$1->data, $1->$2" % [rdLoc(a), lenField(p)]) + of tyArray, tyArrayConstr: + putIntoDest(p, b, e.typ, + "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))]) + else: internalError(e.sons[0].info, "genRepr()") + putIntoDest(p, d, e.typ, 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: - putIntoDest(p, d, e, + genTypeInfo(p.module, elemType(t))])) + of tyCString, tyArray, tyArrayConstr, tyRef, tyPtr, tyPointer, tyNil, + tySequence: + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)", [ - rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage) - of tyEmpty, tyVoid: - localError(p.config, e.info, "'repr' doesn't support 'void' type") + rdLoc(a), genTypeInfo(p.module, t)])) else: - putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)", - [addrLoc(p.config, a), genTypeInfoV1(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" + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)", + [addrLoc(a), genTypeInfo(p.module, t)])) + gcUsage(e) 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)) + var t = skipTypes(e.sons[1].typ, abstractVarRange) + putIntoDest(p, d, e.typ, genTypeInfo(p.module, t)) -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) + genAssignment(p, d, a, {needToKeepAlive}) + gcUsage(n) proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = - var a = e[1] - if a.kind == nkHiddenAddr: a = a[0] - var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses) + var a = e.sons[1] + if a.kind == nkHiddenAddr: a = a.sons[0] + var typ = skipTypes(a.typ, abstractVar) 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)])) + if op == mHigh: unaryExpr(p, e, d, "($1Len0-1)") + else: unaryExpr(p, e, d, "$1Len0") + 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, tySequence: + 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 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)") - 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) - 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]) - putIntoDest(p, d, e, tmp.r) - of tyArray: + if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)") + else: unaryExpr(p, e, d, "($1 ? $1->len : 0)") + of tyArray, tyArrayConstr: # YYY: length(sideeffect) is optimized away incorrectly? - if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(p.config, typ))) - 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) + if op == mHigh: putIntoDest(p, d, e.typ, rope(lastOrd(typ))) + else: putIntoDest(p, d, e.typ, rope(lengthOrd(typ))) + else: internalError(e.info, "genArrayLen()") 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] - 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[1], a) + initLocExpr(p, e.sons[2], b) + var t = skipTypes(e.sons[1].typ, abstractVar) + let setLenPattern = if not p.module.compileToCpp: + "$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n" + else: + "$1 = ($3) #setLengthSeq($1, sizeof($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, {}) - gcUsage(p.config, e) + getTypeDesc(p.module, t.sons[0])]) + keepAlive(p, a) + gcUsage(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") + keepAlive(p, d) + gcUsage(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(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 ")" + if firstOrd(setType) != 0: + result = "($1- $2)" % [result, rope(firstOrd(setType))] -proc fewCmps(conf: ConfigRef; s: PNode): bool = +proc fewCmps(s: PNode): bool = # this function estimates whether it is better to emit code # for constructing the set or generating a bunch of comparisons directly - if s.kind != nkCurly: return false - if (getSize(conf, s.typ) <= conf.target.intSize) and (nfAllConst in s.flags): + if s.kind != nkCurly: internalError(s.info, "fewCmps") + if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags): result = false # it is better to emit the set generation code 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.typ, frmt % [rdLoc(a), rdSetElemLoc(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)") - 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)") + case int(getSize(skipTypes(e.sons[1].typ, abstractVar))) + of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1<<(($2)&7)))!=0)") + of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1<<(($2)&15)))!=0)") + of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1<<(($2)&31)))!=0)") + of 8: binaryExprIn(p, e, a, b, d, "(($1 &(IL64(1)<<(($2)&IL64(63))))!=0)") + else: binaryExprIn(p, e, a, b, d, "(($1[$2/8] &(1<<($2%8)))!=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(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(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: - b.r = rope("(") - for i in 0..= $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(")") - else: - # handle the case of an empty set - b.r = rope("0") - putIntoDest(p, d, e, b.r) + initLoc(b, locExpr, e.typ, OnUnknown) + b.r = rope("(") + var length = sonsLen(e.sons[1]) + for i in countup(0, length - 1): + if e.sons[1].sons[i].kind == nkRange: + initLocExpr(p, e.sons[1].sons[i].sons[0], x) + initLocExpr(p, e.sons[1].sons[i].sons[1], y) + addf(b.r, "$1 >= $2 && $1 <= $3", + [rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)]) + else: + initLocExpr(p, e.sons[1].sons[i], x) + addf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)]) + if i < length - 1: add(b.r, " || ") + add(b.r, ")") + putIntoDest(p, d, e.typ, 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 size = int(getSize(p.config, setType)) + var setType = skipTypes(e.sons[1].typ, abstractVar) + var size = int(getSize(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 = "NI" & $(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 = "NI" & $(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()") + else: internalError(e.info, "genSetOp()") else: 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 mIncl: binaryStmtInExcl(p, e, d, "$1[$2/8] |=(1<<($2%8));$n") + of mExcl: binaryStmtInExcl(p, e, d, "$1[$2/8] &= ~(1<<($2%8));$n") + 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(tyInt), i) # our counter + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + if d.k == locNone: getTemp(p, getSysType(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(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", [ rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b), rope(lookupOpr[op])]) of mInSet: genInOp(p, e, d) - else: internalError(p.config, e.info, "genSetOp") + else: internalError(e.info, "genSetOp") proc genOrd(p: BProc, e: PNode, d: var TLoc) = unaryExprChar(p, e, d, "$1") proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = const - ValueTypes = {tyTuple, tyObject, tyArray, tyOpenArray, tyVarargs, tyUncheckedArray} + ValueTypes = {tyTuple, tyObject, tyArray, tyOpenArray, tyVarargs, + tyArrayConstr} # 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: - putIntoDest(p, d, e, "(($1) ($2))" % - [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)], a.storage) + putIntoDest(p, d, e.typ, "(*($1*) ($2))" % + [getTypeDesc(p.module, e.typ), addrLoc(a)]) + elif etyp.kind == tyProc and etyp.callConv == ccClosure: + putIntoDest(p, d, e.typ, "(($1) ($2))" % + [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)]) else: - # 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) + putIntoDest(p, d, e.typ, "(($1) ($2))" % + [getTypeDesc(p.module, e.typ), rdCharLoc(a)]) proc genCast(p: BProc, e: PNode, d: var TLoc) = - const ValueTypes = {tyFloat..tyFloat128, tyTuple, tyObject, tyArray} + const floatTypes = {tyFloat..tyFloat128} let destt = skipTypes(e.typ, abstractRange) - srct = skipTypes(e[1].typ, abstractRange) - if destt.kind in ValueTypes or srct.kind in ValueTypes: + srct = skipTypes(e.sons[1].typ, abstractRange) + if destt.kind in floatTypes or srct.kind in floatTypes: # 'cast' and some float type involved? --> use a union. inc(p.labels) var lbl = p.labels.rope 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, srct), getTypeDesc(p.module, destt), lbl) tmp.k = locExpr - tmp.lode = lodeTyp srct - tmp.storage = OnStack + tmp.t = srct + tmp.s = OnStack tmp.flags = {} - expr(p, e[1], tmp) - putIntoDest(p, d, e, "LOC$#.dest" % [lbl], tmp.storage) + expr(p, e.sons[1], tmp) + putIntoDest(p, d, e.typ, "LOC$#.dest" % [lbl]) 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.kind in {tyUInt..tyUInt64}: + initLocExpr(p, n.sons[0], a) + putIntoDest(p, d, n.typ, "(($1) ($2))" % + [getTypeDesc(p.module, dest), rdCharLoc(a)]) 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, 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)])) 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) + let destType = e.typ.skipTypes({tyVar, tyGenericInst}) + if compareTypes(destType, e.sons[1].typ, dcEqIgnoreDistinct): + 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], - a.storage) + initLocExpr(p, n.sons[0], a) + putIntoDest(p, d, skipTypes(n.typ, abstractVar), "$1->data" % [rdLoc(a)]) proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = var a: TLoc - initLocExpr(p, n[0], a) - putIntoDest(p, d, n, - ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]), - a.storage) - gcUsage(p.config, n) + initLocExpr(p, n.sons[0], a) + putIntoDest(p, d, skipTypes(n.typ, abstractVar), + ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)])) + gcUsage(n) proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = var x: TLoc - var a = e[1] - var b = e[2] - if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "": - initLocExpr(p, e[2], x) - putIntoDest(p, d, e, - ropecg(p.module, "($1 == 0)", [lenExpr(p, x)])) - elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "": - initLocExpr(p, e[1], x) - putIntoDest(p, d, e, - ropecg(p.module, "($1 == 0)", [lenExpr(p, x)])) + var a = e.sons[1] + var b = e.sons[2] + if (a.kind == nkNilLit) or (b.kind == nkNilLit): + binaryExpr(p, e, d, "($1 == $2)") + elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""): + initLocExpr(p, e.sons[2], x) + putIntoDest(p, d, e.typ, + rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p))) + elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""): + initLocExpr(p, e.sons[1], x) + putIntoDest(p, d, e.typ, + rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p))) else: binaryExpr(p, e, d, "#eqStrings($1, $2)") @@ -2310,174 +1639,65 @@ 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) - putIntoDest(p, d, e, ropecg(p.module, "(($4)($2) $1 ($4)($3))", - [opr[m], rdLoc(a), rdLoc(b), - getSimpleTypeDesc(p.module, e[1].typ)])) + 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.typ, rfmt(nil, "(($4)($2) $1 ($4)($3))", + 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) = + var line, filen: Rope case op of mOr, mAnd: genAndOr(p, e, d, op) - of mNot..mUnaryMinusF64: unaryArith(p, e, d, op) - of mUnaryMinusI..mAbsI: unaryArithOverflow(p, e, d, op) + of mNot..mToBiggestInt: unaryArith(p, e, d, op) + of mUnaryMinusI..mAbsI64: unaryArithOverflow(p, e, d, op) of mAddF64..mDivF64: binaryFloatArith(p, e, d, op) of mShrI..mXor: binaryArith(p, e, d, op) of mEqProc: genEqProc(p, e, d) 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, tyVar, 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, tyVar}) let res = binaryArithOverflowRaw(p, ranged, a, b, if underlying.kind == tyInt64: fun64[op] else: fun[op]) - - putIntoDest(p, a, e[1], "($#)($#)" % [ + putIntoDest(p, a, ranged, "($#)($#)" % [ 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, {}) + binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n") + # strictly speaking we need to generate "keepAlive" here too, but this + # very likely not needed and would slow down the code too much I fear 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,538 +1706,328 @@ 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 mNewSeqOfCap: genNewSeqOfCap(p, e, d) + of mNewFinalize: genNewFinalize(p, e) + of mNewSeq: genNewSeq(p, e) 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.typ, "((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, mXLenSeq: + if not p.module.compileToCpp: + unaryExpr(p, e, d, "($1->Sup.len-1)") + else: + unaryExpr(p, e, d, "$1->len") + 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(e.info, 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.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.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" + of mDotDot: genCall(p, e, d) + else: internalError(e.info, "genMagicExpr: " & $op) + +proc genConstExpr(p: BProc, n: PNode): Rope +proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = + if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr: + var t = getUniqueType(n.typ) + discard getTypeDesc(p.module, t) # so that any fields are initialized + var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) + fillLoc(d, locData, t, "TMP" & rope(id), OnHeap) + if id == gBackendId: + # expression not found in the cache: + inc(gBackendId) + addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", + [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)]) + result = true else: - when defined(debugMagics): - echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind - internalError(p.config, e.info, "genMagicExpr: " & $op) + result = false 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.typ, genSetNode(p, e)) else: if d.k == locNone: getTemp(p, e.typ, d) - if getSize(p.config, e.typ) > 8: + if getSize(e.typ) > 8: # big set: - linefmt(p, cpsStmts, "#nimZeroMem($1, 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) + useStringh(p.module) + lineF(p, cpsStmts, "memset($1, 0, sizeof($1));$n", [rdLoc(d)]) + for i in countup(0, sonsLen(e) - 1): + if e.sons[i].kind == nkRange: + getTemp(p, getSysType(tyInt), idx) # our counter + initLocExpr(p, e.sons[i].sons[0], a) + initLocExpr(p, e.sons[i].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]) + "$2[$1/8] |=(1<<($1%8));$n", [rdLoc(idx), rdLoc(d), + rdSetElemLoc(a, e.typ), rdSetElemLoc(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]) + initLocExpr(p, e.sons[i], a) + lineF(p, cpsStmts, "$1[$2/8] |=(1<<($2%8));$n", + [rdLoc(d), rdSetElemLoc(a, e.typ)]) else: # small set - var ts = "NU" & $(getSize(p.config, e.typ) * 8) + var ts = "NI" & $(getSize(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) - + for i in countup(0, sonsLen(e) - 1): + if e.sons[i].kind == nkRange: + getTemp(p, getSysType(tyInt), idx) # our counter + initLocExpr(p, e.sons[i].sons[0], a) + initLocExpr(p, e.sons[i].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 |=(1<<((" & ts & ")($1)%(sizeof(" & ts & ")*8)));$n", [ + rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ), + rdSetElemLoc(b, e.typ)]) else: - initLocExpr(p, it, a) - var aa = newRopeAppender() - rdSetElemLoc(p.config, a, e.typ, aa) + initLocExpr(p, e.sons[i], a) lineF(p, cpsStmts, - "$1 |=(($3)(1)<<(($2)%(sizeof($3)*8)));$n", - [rdLoc(d), aa, rope(ts)]) + "$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n", + [rdLoc(d), rdSetElemLoc(a, e.typ)]) proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = var rec: TLoc if not handleConstExpr(p, n, d): - let t = n.typ + var t = getUniqueType(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) - proc genStmtListExpr(p: BProc, n: PNode, d: var TLoc) = - genStmtListExprImpl: - expr(p, n[^1], d) - -proc genStmtList(p: BProc, n: PNode) = - genStmtListExprImpl: - genStmts(p, n[^1]) - -from parampatterns import isLValue + var length = sonsLen(n) + for i in countup(0, length - 2): genStmts(p, n.sons[i]) + if length > 0: expr(p, n.sons[length - 1], d) proc upConv(p: BProc, n: PNode, d: var TLoc) = var a: TLoc - initLocExpr(p, n[0], a) - let dest = skipTypes(n.typ, abstractPtrs) + initLocExpr(p, n.sons[0], a) + var 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, tyPtr, tyRef}: + if t.kind != tyVar: nilCheck = r + if t.kind != tyVar or not p.module.compileToCpp: + r = "(*$1)" % [r] + t = skipTypes(t.lastSon, abstractInst) + if not p.module.compileToCpp: + while t.kind == tyObject and t.sons[0] != nil: + add(r, ".Sup") + t = skipTypes(t.sons[0], abstractInst) + if nilCheck != nil: + linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n", + nilCheck, r, genTypeInfo(p.module, dest)) 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, - "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage) + linefmt(p, cpsStmts, "#chckObj($1.m_type, $2);$n", + r, genTypeInfo(p.module, dest)) + if n.sons[0].typ.kind != tyObject: + putIntoDest(p, d, n.typ, + "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)]) else: - putIntoDest(p, d, n, "(*($1*) ($2))" % - [getTypeDesc(p.module, dest), addrLoc(p.config, a)], a.storage) + putIntoDest(p, d, n.typ, "(*($1*) ($2))" % + [getTypeDesc(p.module, dest), addrLoc(a)]) 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: + 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) 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} + 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}: + getTemp(p, n.typ, d) + linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r) + else: + r = "&" & r + putIntoDest(p, d, n.typ, r) + else: + putIntoDest(p, d, n.typ, r) proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = - let t = n.typ + var t = getUniqueType(n.typ) discard getTypeDesc(p.module, t) # so that any fields are initialized - let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) - let tmp = p.module.tmpBase & rope(id) + var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) + var tmp = "TMP" & rope(id) - if id == p.module.labels: + if id == gBackendId: # 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", []) + inc(gBackendId) + 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) + fillLoc(d, locData, t, tmp, OnHeap) else: - putDataIntoDest(p, d, n, tmp) - # This fixes bug #4551, but we really need better dataflow - # analysis to make this 100% safe. - 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) + putDataIntoDest(p, d, t, tmp) 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) + fillProcLoc(sym) genProcPrototype(p.module, sym) else: genProc(p.module, sym) putLocIntoDest(p, d, sym.loc) - of skProc, skConverter, skIterator, skFunc: - #if sym.kind == skIterator: - # echo renderTree(sym.getBody, {renderIds}) - 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: - internalError(p.config, n.info, "expr: proc not init " & sym.name.s) + of skProc, skConverter, skIterators: + genProc(p.module, sym) + if sym.loc.r == nil or sym.loc.t == nil: + internalError(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)) + if sfFakeConst in sym.flags: + if sfGlobal in sym.flags: genVarPrototype(p.module, sym) putLocIntoDest(p, d, sym.loc) + elif isSimpleConst(sym.typ): + putIntoDest(p, d, n.typ, genLiteral(p, sym.ast, sym.typ)) else: genComplexConst(p, sym, d) of skEnumField: - # we never reach this case - as of the time of this comment, - # skEnumField is folded to an int in semfold.nim, but this code - # remains for robustness - putIntoDest(p, d, n, rope(sym.position)) + putIntoDest(p, d, n.typ, rope(sym.position)) 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 sfGlobal in sym.flags: genVarPrototype(p.module, sym) + 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 + internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id if sfThread in sym.flags: accessThreadLocalVar(p, sym) - if emulatedThreadVars(p.config): - putIntoDest(p, d, sym.loc.lode, "NimTV_->" & sym.loc.r) + if emulatedThreadVars(): + putIntoDest(p, d, sym.loc.t, "NimTV->" & sym.loc.r) else: putLocIntoDest(p, d, sym.loc) 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) + internalError(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: - # echo "FAILED FOR PRCO ", p.prc.name.s - # debug p.prc.typ.n - # echo renderTree(p.prc.ast, {renderIds}) - internalError(p.config, n.info, "expr: param not init " & sym.name.s & "_" & $sym.id) + 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}) + internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id) putLocIntoDest(p, d, sym.loc) - else: internalError(p.config, n.info, "expr(" & $sym.kind & "); unknown symbol") + else: internalError(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.typ, 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.typ, genLiteral(p, n)) + of nkIntLit..nkUInt64Lit, + nkFloatLit..nkFloat128Lit, nkCharLit: + putIntoDest(p, d, n.typ, 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 +2043,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.typ, genSetNode(p, n)) else: genSetConstr(p, n, d) of nkBracket: @@ -3045,87 +2053,61 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = genSeqConstr(p, n, d) 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: + of nkPar: + 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) of nkCheckedFieldExpr: genCheckedRecordField(p, n, d) of nkBlockExpr, nkBlockStmt: genBlock(p, n, d) of nkStmtListExpr: genStmtListExpr(p, n, d) - of nkStmtList: genStmtList(p, n) + of nkStmtList: + for i in countup(0, sonsLen(n) - 1): genStmts(p, n.sons[i]) of nkIfExpr, nkIfStmt: genIf(p, n, d) - of nkWhen: - # This should be a "when nimvm" node. - expr(p, n[1][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: - internalError(p.config, n.info, "expr: proc not init " & sym.name.s) + if sym.loc.r == nil or sym.loc.t == nil: + internalError(n.info, "expr: proc not init " & sym.name.s) putLocIntoDest(p, d, sym.loc) of nkClosure: genClosure(p, n, d) 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 nkForStmt: internalError(p.config, n.info, "for statement not eliminated") + of nkConstSection: genConstStmt(p, n) + of nkForStmt: internalError(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]) - 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. - genAsgn(p, n, fastAsgn=p.prc != nil) + of nkAsgn: genAsgn(p, n, fastAsgn=false) + of nkFastAsgn: + # transf is overly aggressive with 'nkFastAsgn', so we work around here. + # See tests/run/tcnstseq3 for an example that would fail otherwise. + genAsgn(p, n, fastAsgn=p.prc != nil) of nkDiscardStmt: - let ex = n[0] - if ex.kind != nkEmpty: + if n.sons[0].kind != nkEmpty: genLineDir(p, n) var a: TLoc - initLocExprSingleUse(p, ex, a) - line(p, cpsStmts, "(void)(" & a.r & ");\L") + initLocExpr(p, n.sons[0], a) of nkAsmStmt: genAsmStmt(p, n) - of nkTryStmt, nkHiddenTryStmt: - case p.config.exc - of excGoto: - genTryGoto(p, n, d) - of excCpp: - genTryCpp(p, n, d) - else: - genTrySetjmp(p, n, d) + of nkTryStmt: + if p.module.compileToCpp: genTryCpp(p, n, d) + else: genTry(p, n, d) of nkRaiseStmt: genRaiseStmt(p, n) of nkTypeSection: # we have to emit the type information for object types here to support @@ -3133,344 +2115,81 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = genTypeSection(p.module, n) of nkCommentStmt, nkIteratorDef, nkIncludeStmt, nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, - nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: + nkFromStmt, nkTemplateDef, nkMacroDef: 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 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 ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or + of nkPragmaBlock: expr(p, n.lastSon, d) + of nkProcDef, nkMethodDef, nkConverterDef: + 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: + if (optDeadCodeElim notin gGlobalOptions and + sfDeadCodeElim notin getModule(prc).flags) or + ({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 nkBreakState: genBreakState(p, n, d) - of nkMixinStmt, nkBindStmt: discard - else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind") + of nkGotoState: genGotoState(p, n) + of nkBreakState: genBreakState(p, n) + else: internalError(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}) - 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 tyProc: - if t.callConv != ccClosure: - result.add "NIM_NIL" - else: - result.add "{NIM_NIL, NIM_NIL}" - of tyObject: - var count = 0 - result.add "{" - getNullValueAuxT(p, t, t, t.n, nil, result, count, true, info) - result.add "}" - 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 "}" - 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 tySet: - if mapSetType(p.config, t) == ctArray: result.add "{}" - else: result.add "0" - else: - globalError(p.config, info, "cannot create null element for: " & $t.kind) +proc genNamedConstExpr(p: BProc, n: PNode): Rope = + if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1]) + else: result = genConstExpr(p, n) -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 genConstSimpleList(p: BProc, n: PNode): Rope = + var length = sonsLen(n) + result = rope("{") + 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 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) = - case obj.kind - of nkRecList: - for it in obj.sons: - getNullValueAux(p, t, it, constOrNil, result, count, isConst, info) - 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 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) = - var data = "{{$1, $1 | NIM_STRLIT_FLAG}" % [n.len.rope] - let base = t.skipTypes(abstractInst)[0] +proc genConstSeq(p: BProc, n: PNode, t: PType): Rope = + var data = "{{$1, $1}" % [n.len.rope] 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) + inc(gBackendId) + result = "CNSTSEQ" & gBackendId.rope - 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, t.sons[0]), 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(n, cs) + result = genRawSetData(cs, int(getSize(n.typ))) + of nkBracket, nkPar, nkClosure, nkObjConstr: + var t = skipTypes(n.typ, abstractInst) + if t.kind == tySequence: + result = genConstSeq(p, n, t) + else: + result = genConstSimpleList(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 deleted file mode 100644 index cbef6771f..000000000 --- a/compiler/ccgliterals.nim +++ /dev/null @@ -1,118 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2018 Andreas Rumpf -# -# See the file "copying.txt", included in this -# 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. -## The price is that seqs and strings are not purely a library -## implementation. - -template detectVersion(field, corename) = - if m.g.field == 0: - let core = getCompilerProc(m.g.graph, corename) - if core == nil or core.kind != skConst: - m.g.field = 1 - else: - m.g.field = toInt(ast.getInt(core.astdef)) - result = m.g.field - -proc detectStrVersion(m: BModule): int = - detectVersion(strVersion, "nimStrVersion") - -proc detectSeqVersion(m: BModule): int = - detectVersion(seqVersion, "nimSeqVersion") - -# ----- 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 genStringLiteralV1(m: BModule; n: PNode; result: var Rope) = - if s.isNil: - appcg(m, result, "((#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 ")" - else: - appcg(m, result, "((#NimStringDesc*) &$1$2)", - [m.tmpBase, 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 genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var 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: "")]) - 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] - -# ------ Version selector --------------------------------------------------- - -proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo; - isConst: bool; result: var 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 - 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 genStringLiteral(m: BModule; n: PNode; result: var Rope) = - case detectStrVersion(m) - of 0, 1: genStringLiteralV1(m, n, result) - of 2: genStringLiteralV2(m, n, isConst = true, result) - 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..2a37257b6 --- /dev/null +++ b/compiler/ccgmerge.nim @@ -0,0 +1,298 @@ +# +# +# 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 + +# 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", + cfsData: "NIM_merge_DATA", + cfsVars: "NIM_merge_VARS", + 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): Rope = + if compilationCachePresent: + result = rope(tnl) + add(result, "/*\t") + add(result, CFileSectionNames[fs]) + add(result, ":*/") + add(result, tnl) + +proc genSectionEnd*(fs: TCFileSection): Rope = + if compilationCachePresent: + result = rope(NimMergeEndMark & tnl) + +proc genSectionStart*(ps: TCProcSection): Rope = + if compilationCachePresent: + result = rope(tnl) + add(result, "/*\t") + add(result, CProcSectionNames[ps]) + add(result, ":*/") + add(result, tnl) + +proc genSectionEnd*(ps: TCProcSection): Rope = + if compilationCachePresent: + result = rope(NimMergeEndMark & tnl) + +proc writeTypeCache(a: TIdTable, s: var string) = + var i = 0 + for id, value in pairs(a): + if i == 10: + i = 0 + s.add(tnl) + else: + s.add(' ') + encodeVInt(id, s) + s.add(':') + encodeStr($Rope(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(tnl) + else: + s.add(' ') + encodeVInt(x, s) + inc i + s.add('}') + +proc genMergeInfo*(m: BModule): Rope = + if optSymbolFiles notin gGlobalOptions: return nil + var s = "/*\tNIM_merge_INFO:" + s.add(tnl) + s.add("typeCache:{") + writeTypeCache(m.typeCache, s) + s.add("declared:{") + writeIntSet(m.declaredThings, s) + s.add("typeInfo:{") + writeIntSet(m.typeInfoMarker, s) + s.add("labels:") + encodeVInt(m.labels, s) + s.add(" hasframe:") + encodeVInt(ord(m.frameDeclared), s) + s.add(tnl) + s.add("*/") + result = s.rope + +template `^`(pos: int): expr = 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(tnl) + of LF: + pos = nimlexbase.handleLF(L, pos) + buf = L.buf + r.add(tnl) + of '\0': + internalError("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] != ':': internalError("ccgmerge: ':' expected") + L.bufpos = pos + 1 # skip ':' + +proc newFakeType(id: int): PType = + new(result) + result.id = id + +proc readTypeCache(L: var TBaseLexer, result: var TIdTable) = + if ^L.bufpos != '{': internalError("ccgmerge: '{' expected") + inc L.bufpos + while ^L.bufpos != '}': + skipWhite(L) + var key = decodeVInt(L.buf, L.bufpos) + if ^L.bufpos != ':': internalError("ccgmerge: ':' expected") + inc L.bufpos + var value = decodeStr(L.buf, L.bufpos) + # XXX little hack: we create a "fake" type object with the correct Id + # better would be to adapt the data structure to not even store the + # object as key, but only the Id + idTablePut(result, newFakeType(key), value.rope) + inc L.bufpos + +proc readIntSet(L: var TBaseLexer, result: var IntSet) = + if ^L.bufpos != '{': internalError("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": readIntSet(L, m.typeInfoMarker) + of "labels": m.labels = decodeVInt(L.buf, L.bufpos) + of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0 + else: internalError("ccgmerge: unknown key: " & k) + +when not defined(nimhygiene): + {.pragma: inject.} + +template withCFile(cfilename: string, body: stmt) {.immediate.} = + 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: + internalError("ccgmerge: unknown section: " & k) + else: + internalError("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) - + useLowering = true; break + if useLowering: + genStmts(p, lowerTupleUnpacking(n, p.prc)) + return genLineDir(p, n) - initLocExpr(p, n[^1], tup) - var t = tup.t.skipTypes(abstractInst) - for i in 0.. 0: - result.addf("FR_.len+=$1;$n", [b.frameLen.rope]) + result.addf("F.len+=$1;$n", [b.frameLen.rope]) result.add(b.sections[cpsInit]) result.add(b.sections[cpsStmts]) 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 +117,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: + rfmt(nil, "} $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", []) + blockEnd.addf("F.len-=$1;$n", [frameLen.rope]) endBlock(p, blockEnd) proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} = @@ -186,55 +136,15 @@ proc exprBlock(p: BProc, n: PNode, d: var TLoc) = expr(p, n, d) endBlock(p) -template preserveBreakIdx(body: untyped): untyped = +template preserveBreakIdx(body: stmt): stmt {.immediate.} = var oldBreakIdx = p.breakIdx body p.breakIdx = oldBreakIdx 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]) - elif n0.kind == nkStrLit: - linefmt(p, cpsStmts, "$1: ;$n", [n0.strVal]) - -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. - - var stack = newSeq[tuple[fin: PNode, inExcept: bool, label: Natural]](0) - - inc p.withinBlockLeaveActions - for i in 1..howManyTrys: - let tryStmt = p.nestedTryStmts.pop - if p.config.exc == excSetjmp: - # Pop safe points generated by try - if not tryStmt.inExcept: - 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. - stack.add(tryStmt) - - # 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 - - # 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: - for i in countdown(howManyExcepts-1, 0): - linefmt(p, cpsStmts, "#popCurrentException();$n", []) + internalAssert n.len == 1 and n.sons[0].kind == nkIntLit + let idx = n.sons[0].intVal + linefmt(p, cpsStmts, "STATE$1: ;$n", idx.rope) proc genGotoState(p: BProc, n: PNode) = # we resist the temptation to translate it into duff's device as it later @@ -243,177 +153,127 @@ 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 - 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) - if n.len >= 2 and n[1].kind == nkIntLit: - statesCounter = getInt(n[1]) - let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope - else: rope"STATE" - for i in 0i64..toInt64(statesCounter): - lineF(p, cpsStmts, "case $2: goto $1$2;$n", [prefix, rope(i)]) + p.beforeRetNeeded = true + lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", []) + for i in 0 .. lastOrd(n.sons[0].typ): + lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [rope(i)]) lineF(p, cpsStmts, "}$n", []) -proc genBreakState(p: BProc, n: PNode, d: var TLoc) = +proc genBreakState(p: BProc, n: PNode) = var a: TLoc - initLoc(d, locExpr, n, OnUnknown) - - if n[0].kind == nkClosure: - initLocExpr(p, n[0][1], a) - d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)] + if n.sons[0].kind == nkClosure: + # XXX this produces quite inefficient code! + initLocExpr(p, n.sons[0].sons[1], a) + lineF(p, cpsStmts, "if (((NI*) $1)[0] < 0) break;$n", [rdLoc(a)]) else: - initLocExpr(p, n[0], a) - # the environment is guaranteed to contain the 'state' field at offset 1: - d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)] + initLocExpr(p, n.sons[0], a) + # the environment is guaranteed to contain the 'state' field at offset 0: + lineF(p, cpsStmts, "if ((((NI*) $1.ClEnv)[0]) < 0) break;$n", [rdLoc(a)]) + # lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)]) + +proc genVarPrototypeAux(m: BModule, sym: PSym) proc genGotoVar(p: BProc; value: PNode) = if value.kind notin {nkCharLit..nkUInt64Lit}: - localError(p.config, value.info, "'goto' target must be a literal value") + localError(value.info, "'goto' target must be a literal value") 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) = - if sfGoto in v.flags: +proc genSingleVar(p: BProc, a: PNode) = + var v = a.sons[0].sym + if {sfCompileTime, sfGoto} * v.flags != {}: # translate 'var state {.goto.} = X' into 'goto LX': - genGotoVar(p, value) + if sfGoto in v.flags: 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, v) # 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) + if sfExportc in v.flags and generatedHeader != nil: + genVarPrototypeAux(generatedHeader, v) + registerGcRoot(p, v) else: - let imm = isAssignedImmediately(p.config, value) + let value = a.sons[2] + let imm = isAssignedImmediately(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) - let decl = localVarDecl(p, vn) + # generate better code here: + genLineDir(p, a) + let decl = localVarDecl(p, v) 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: + for i in countup(0, sonsLen(n) - 1): + var a = n.sons[i] + if a.kind == nkCommentStmt: continue + if a.kind == nkIdentDefs: # can be a lifted var nowadays ... - if it[0].kind == nkSym: - genSingleVar(p, it) + if a.sons[0].kind == nkSym: + genSingleVar(p, a) else: - genClosureVar(p, it) + genClosureVar(p, a) else: - genVarTuple(p, it) + genVarTuple(p, a) + +proc genConstStmt(p: BProc, t: PNode) = + for i in countup(0, sonsLen(t) - 1): + var it = t.sons[i] + if it.kind == nkCommentStmt: continue + if it.kind != nkConstDef: internalError(t.info, "genConstStmt") + var c = it.sons[0].sym + if c.typ.containsCompileTimeOnly: continue + if sfFakeConst in c.flags: + genSingleVar(p, it) + elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and + c.ast.len != 0: + if not emitLazily(c): requestConstImpl(p, c) proc genIf(p: BProc, n: PNode, d: var TLoc) = # @@ -434,505 +294,428 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = getTemp(p, n.typ, d) genLineDir(p, n) let lend = getLabel(p) - for it in n.sons: - # bug #4230: avoid false sharing between branches: - if d.k == locTemp and isEmptyType(n.typ): d.k = locNone + for i in countup(0, sonsLen(n) - 1): + let it = n.sons[i] 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) + else: internalError(n.info, "genIf()") + if sonsLen(n) > 1: fixLabel(p, lend) + + +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, + + var stack: seq[PNode] + newSeq(stack, 0) + + var alreadyPoppedCnt = p.inExceptBlock + for i in countup(1, howManyTrys): + if not p.module.compileToCpp: + # Pop safe points generated by try + if alreadyPoppedCnt > 0: + dec alreadyPoppedCnt + else: + 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. + var tryStmt = p.nestedTryStmts.pop + stack.add(tryStmt) + + # Find finally-stmt for this try-stmt + # and generate a copy of its sons + var finallyStmt = lastSon(tryStmt) + 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]) + + if not p.module.compileToCpp: + # Pop exceptions that was handled by the + # except-blocks we are in + for i in countdown(howManyExcepts-1, 0): + linefmt(p, cpsStmts, "#popCurrentException();$n") 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: + howManyExcepts = p.inExceptBlock) + 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]) - lineF(p, cpsStmts, "goto BeforeRet_;$n", []) + 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, + localError(it.info, "case statement has too many cases for computed goto"); return - arraySize = toInt(aSize) - if firstOrd(p.config, it[0].typ) != 0: - localError(p.config, it.info, + arraySize = aSize.int + if firstOrd(it.sons[0].typ) != 0: + localError(it.info, "case statement has to start at 0 for computed goto"); return if casePos < 0: - localError(p.config, n.info, "no case statement found for computed goto"); return + localError(n.info, "no case statement found for computed goto"); return var id = p.labels+1 inc p.labels, arraySize+1 - let tmp = "TMP$1_" % [id.rope] + 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 + internalError(t.info, "no loop to break") + let label = assignLabel(p.blocks[idx]) blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts, - p.inExceptBlockLen - p.blocks[idx].nestedExceptStmts) + p.inExceptBlock - p.blocks[idx].nestedExceptStmts) genLineDir(p, t) - lineF(p, cpsStmts, "goto $1;$n", [p.blocks[idx].label]) + lineF(p, cpsStmts, "goto $1;$n", [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)]) +proc getRaiseFrmt(p: BProc): string = + if p.module.compileToCpp: + result = "throw NimException($1, $2);$n" + elif getCompilerProc("Exception") != nil: + result = "#raiseException((#Exception*)$1, $2);$n" + else: + result = "#raiseException((#E_Base*)$1, $2);$n" proc genRaiseStmt(p: BProc, t: PNode) = - if t[0].kind != nkEmpty: + if p.inExceptBlock > 0: + # if the current try stmt have a finally block, + # we must execute it before reraising + var finallyBlock = p.nestedTryStmts[p.nestedTryStmts.len - 1].lastSon + if finallyBlock.kind == nkFinally: + genSimpleBlock(p, finallyBlock.sons[0]) + if t.sons[0].kind != nkEmpty: var a: TLoc - initLocExprSingleUse(p, t[0], a) - finallyActions(p) + initLocExpr(p, t.sons[0], a) 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) + var typ = skipTypes(t.sons[0].typ, abstractPtrs) 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, getRaiseFrmt(p), [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: + 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 - p.procSec(cpsLocals).add(ropecg(p.module, "\tTFrame* _nimCurFrame;$n", [])) - p.procSec(cpsInit).add(ropecg(p.module, "\t_nimCurFrame = #getFrame();$n", [])) - linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n", []) +proc hasGeneralExceptSection(t: PNode): bool = + var length = sonsLen(t) + var i = 1 + while (i < length) and (t.sons[i].kind == nkExceptBranch): + var blen = sonsLen(t.sons[i]) + if blen == 1: + return true + inc(i) + result = false 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: # + # XXX: There should be a standard dispatch algorithm + # that's used both here and with multi-methods + # # try # { # myDiv(4, 9); - # } catch (NimExceptionType1&) { - # body - # } catch (NimExceptionType2&) { - # finallyPart() - # raise; - # } - # catch(...) { - # general_handler_body - # } - # finallyPart(); - - template genExceptBranchBody(body: PNode) {.dirty.} = - genRestoreFrameAfterException(p) - expr(p, body, d) - + # } catch (NimException& exp) { + # if (isObj(exp, EIO) { + # ... + # } else if (isObj(exp, ESystem) { + # ... + # finallyPart() + # raise; + # } else { + # // general handler + # } + # } + # finallyPart(); if not isEmptyType(t.typ) and d.k == locNone: getTemp(p, t.typ, d) + var + exc: Rope + i, length, blen: int 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)) + exc = getTempName() + if getCompilerProc("Exception") != nil: + discard cgsym(p.module, "Exception") + else: + discard cgsym(p.module, "E_Base") + add(p.nestedTryStmts, t) startBlock(p, "try {$n") - expr(p, t[0], d) - endBlock(p) - + expr(p, t.sons[0], d) + length = sonsLen(t) + endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc])) + if optStackTrace in p.options: + linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n") + inc p.inExceptBlock + i = 1 var catchAllPresent = false - - p.nestedTryStmts[^1].inExcept = true - for i in 1.. 1: addf(p.s(cpsStmts), "else ", []) + if blen == 1: # general except section: catchAllPresent = true - startBlock(p, "catch (...) {$n") - genExceptBranchBody(t[i][0]) - endBlock(p) + exprBlock(p, t.sons[i].sons[0], d) 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) - + var orExpr: Rope = nil + for j in countup(0, blen - 2): + assert(t.sons[i].sons[j].kind == nkType) + if orExpr != nil: add(orExpr, "||") + appcg(p.module, orExpr, + "#isObj($1.exp->m_type, $2)", + [exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)]) + lineF(p, cpsStmts, "if ($1) ", [orExpr]) + exprBlock(p, t.sons[i].sons[blen-1], d) inc(i) - discard pop(p.nestedTryStmts) - endBlock(p) - if i < t.len and t[i].kind == nkFinally: + # reraise the exception if there was no catch all + # and none of the handlers matched + if not catchAllPresent: + if i > 1: lineF(p, cpsStmts, "else ", []) 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 + var finallyBlock = t.lastSon + if finallyBlock.kind == nkFinally: + #expr(p, finallyBlock.sons[0], d) + genStmts(p, finallyBlock.sons[0]) -proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = + line(p, cpsStmts, ~"throw;$n") + endBlock(p) + + lineF(p, cpsStmts, "}$n", []) # end of catch block + dec p.inExceptBlock + + discard pop(p.nestedTryStmts) + if (i < length) and (t.sons[i].kind == nkFinally): + genSimpleBlock(p, t.sons[i].sons[0]) + +proc genTry(p: BProc, t: PNode, d: var TLoc) = # code to generate: # # XXX: There should be a standard dispatch algorithm @@ -1372,271 +886,222 @@ 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 + discard lists.includeStr(p.module.headerFiles, "") 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() + if getCompilerProc("Exception") != nil: + discard cgsym(p.module, "Exception") else: - startBlock(p) - p.nestedTryStmts[^1].inExcept = true + discard cgsym(p.module, "E_Base") + linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint) + linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint) + if isDefined("nimStdSetjmp"): + linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) + elif isDefined("nimSigSetjmp"): + linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint) + elif isDefined("nimRawSetjmp"): + linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint) + else: + 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) + expr(p, t.sons[0], d) + linefmt(p, cpsStmts, "#popSafePoint();$n") + endBlock(p) + startBlock(p, "else {$n") + linefmt(p, cpsStmts, "#popSafePoint();$n") + if optStackTrace in p.options: + linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n") + inc p.inExceptBlock var i = 1 - 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: + while (i < length) and (t.sons[i].kind == nkExceptBranch): + 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, "||") + appcg(p.module, orExpr, + "#isObj(#getCurrentException()->Sup.m_type, $1)", + [genTypeInfo(p.module, t.sons[i].sons[j].typ)]) 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) + dec p.inExceptBlock 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 + for i in countup(0, sonsLen(t) - 1): + case t.sons[i].kind of nkStrLit..nkTripleStrLit: - res.add(it.strVal) + res.add(t.sons[i].strVal) of nkSym: - var sym = it.sym - if sym.kind in {skProc, skFunc, skIterator, skMethod}: + var sym = t.sons[i].sym + if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}: var a: TLoc - initLocExpr(p, it, a) + initLocExpr(p, t.sons[i], a) res.add($rdLoc(a)) - elif sym.kind == skType: - 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) - of nkTypeOfExpr: - res.add($getTypeDesc(p.module, it.typ)) - else: - discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs)) - var a: TLoc - initLocExpr(p, it, a) - res.add($a.rdLoc) + var r = sym.loc.r + if r == nil: + # if no name has already been given, + # it doesn't matter much: + r = mangleName(sym) + sym.loc.r = r # but be consequent! + res.add($r) + else: internalError(t.sons[i].info, "genAsmOrEmitStmt()") - if isAsmStmt and hasGnuAsm in CC[p.config.cCompiler].props: + if isAsmStmt and hasGnuAsm in CC[cCompiler].props: for x in splitLines(res): var j = 0 - while j < x.len and x[j] in {' ', '\t'}: inc(j) - if j < x.len: - if x[j] in {'"', ':'}: - # don't modify the line if already in quotes or - # some clobber register list: - result.add(x); result.add("\L") - else: - # ignore empty lines - result.add("\"") - result.add(x.replace("\"", "\\\"")) - result.add("\\n\"\n") + while x[j] in {' ', '\t'}: inc(j) + if x[j] in {'"', ':'}: + # don't modify the line if already in quotes or + # some clobber register list: + add(result, x); add(result, tnl) + elif x[j] != '\0': + # ignore empty lines + add(result, "\"") + add(result, x) + add(result, "\\n\"\n") else: - res.add("\L") - result.add res.rope + res.add(tnl) + 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[cCompiler].asmStmtFrmt, [s]) else: - addIndent p, p.s(cpsStmts) - p.s(cpsStmts).add runtimeFormat(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 - elif sec.startsWith("/*VARSECTION*/"): result = cfsVars - elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders + lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s]) 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) + genCLineDir(p.module.s[cfsProcHeaders], t.info) + add(p.module.s[cfsProcHeaders], s) else: genLineDir(p, t) line(p, cpsStmts, s) +var + breakPointId: int = 0 + gBreakpoints: Rope # later the breakpoints are inserted into the main proc + +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(breakPointId) + name = "bp" & $breakPointId + genLineDir(p, t) # BUGFIX + appcg(p.module, gBreakpoints, + "#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [ + rope(toLinenumber(t.info)), makeCString(toFilename(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", + [a.addrLoc, makeCString(renderTree(n.sons[1])), + genTypeInfo(p.module, typ)]) + 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")]) + genTraverseProc(c, "$1->data[$2]" % [accessor, i.r], typ.sons[0]) + lineF(p, cpsStmts, "}$n", []) - lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", - [i.r, lenExpr(c.p, a)]) - let oldLen = p.s(cpsStmts).len - genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ[0]) - if p.s(cpsStmts).len == oldLen: - # do not emit dummy long loops for faster debug builds: - p.s(cpsStmts) = oldCode - else: - lineF(p, cpsStmts, "}$n", []) - -proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope = +proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): 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) + result = getGlobalTempName() + case reason + of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n" + else: assert false + + let header = "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" - 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 in {tyArrayConstr, 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) +proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope = + discard genTypeInfo(m, s.loc.t) var c: TTraversalClosure var p = newProc(nil, m) - var sLoc = rdLoc(s.loc) - result = getTempName(m) + var sLoc = s.loc.r + result = getGlobalTempName() - if sfThread in s.flags and emulatedThreadVars(m.config): + if sfThread in s.flags and emulatedThreadVars(): accessThreadLocalVar(p, s) - sLoc = "NimTV_->" & sLoc + 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] + let header = "N_NIMCALL(void, $1)()" % [result] genTraverseProc(c, sLoc, s.loc.t) let generatedProc = "$1 {$n$2$3$4}$n" % diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 98c1fc55f..60ebf591b 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1,7 +1,7 @@ # # # The Nim Compiler -# (c) Copyright 2017 Andreas Rumpf +# (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -11,223 +11,174 @@ # ------------------------- Name Mangling -------------------------------- -import sighashes, modulegraphs -import std/md5 +proc mangleField(name: string): string = + result = mangle(name) + result[0] = result[0].toUpper # Mangling makes everything lowercase, + # but some identifiers are C keywords proc isKeyword(w: PIdent): bool = - # Nim and C++ share some keywords - # it's more efficient to test the whole Nim keywords range + # nimrod and C++ share some keywords + # it's more efficient to test the whole nimrod keywords range case w.id of ccgKeywordsLow..ccgKeywordsHigh, nimKeywordsLow..nimKeywordsHigh, ord(wInline): return true else: return false -proc mangleField(m: BModule; name: PIdent): string = - result = mangle(name.s) - # fields are tricky to get right and thanks to generic types producing - # duplicates we can end up mangling the same field multiple times. However - # if we do so, the 'cppDefines' table might be modified in the meantime - # meaning we produce inconsistent field names (see bug #5404). - # Hence we do not check for ``m.g.config.cppDefines.contains(result)`` here - # anymore: - if isKeyword(name): - result.add "_0" - -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)) - s.loc.r = result - writeMangledName(m.ndi, s, m.config) - -proc fillParamName(m: BModule; s: PSym) = - if s.loc.r == "": - 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 - writeMangledName(m.ndi, s, m.config) - -proc fillLocalName(p: BProc; s: PSym) = - assert s.kind in skLocalVars+{skTemp} - #assert sfGlobal notin s.flags - if s.loc.r == "": - var key = s.name.s.mangle - let counter = p.sigConflicts.getOrDefault(key) - var 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) - elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key): - result.add "_" & rope(counter+1) - p.sigConflicts.inc(key) - s.loc.r = result - if s.kind != skTemp: writeMangledName(p.module.ndi, s, p.config) - -proc scopeMangledParam(p: BProc; param: PSym) = - ## parameter generation only takes BModule, not a BProc, so we have to - ## remember these parameter names are already in scope to be able to - ## generate unique identifiers reliably (consider that ``var a = a`` is - ## even an idiom in Nim). - var key = param.name.s.mangle - p.sigConflicts.inc(key) - -const - irrelevantForBackend = {tyGenericBody, tyGenericInst, tyGenericInvocation, - tyDistinct, tyRange, tyStatic, tyAlias, tySink, - tyInferred, tyOwned} - -proc typeName(typ: PType; result: var 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 - -proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope = - var t = typ - while true: - if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}: - return t.sym.loc.r - - if t.kind in irrelevantForBackend: - t = t.lastSon +proc mangleName(s: PSym): Rope = + result = s.loc.r + if result == nil: + when oKeepVariableNames: + let keepOrigName = s.kind in skLocalVars - {skForVar} and + {sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and + not isKeyword(s.name) + # XXX: This is still very experimental + # + # Even with all these inefficient checks, the bootstrap + # time is actually improved. This is probably because so many + # rope concatenations are now eliminated. + # + # Future notes: + # sfFromGeneric seems to be needed in order to avoid multiple + # definitions of certain variables generated in transf with + # names such as: + # `r`, `res` + # I need to study where these come from. + # + # about sfShadowed: + # consider the following nimrod code: + # var x = 10 + # block: + # var x = something(x) + # The generated C code will be: + # NI x; + # x = 10; + # { + # NI x; + # x = something(x); // Oops, x is already shadowed here + # } + # Right now, we work-around by not keeping the original name + # of the shadowed variable, but we can do better - we can + # create an alternative reference to it in the outer scope and + # use that in the inner scope. + # + # about isCKeyword: + # nimrod variable names can be C keywords. + # We need to avoid such names in the generated code. + # XXX: Study whether mangleName is called just once per variable. + # Otherwise, there might be better place to do this. + # + # about sfGlobal: + # This seems to be harder - a top level extern variable from + # another modules can have the same name as a local one. + # Maybe we should just implement sfShadowed for them too. + # + # about skForVar: + # These are not properly scoped now - we need to add blocks + # around for loops in transf + if keepOrigName: + result = s.name.s.mangle.rope + else: + add(result, rope(mangle(s.name.s))) + add(result, ~"_") + add(result, rope(s.id)) 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 - else: - when defined(debugSigHashes): - # check consistency: - var tn = newRopeAppender() - typ.typeName(tn) - assert($typ.loc.r == $(tn & $sig)) - result = typ.loc.r - if result == "": internalError(m.config, "getTypeName: " & $typ.kind) + add(result, rope(mangle(s.name.s))) + add(result, ~"_") + add(result, rope(s.id)) + s.loc.r = result -proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = - case int(getSize(conf, typ)) +proc typeName(typ: PType): Rope = + result = if typ.sym != nil: typ.sym.name.s.mangle.rope + else: ~"TY" + +proc getTypeName(typ: PType): Rope = + if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}: + result = typ.sym.loc.r + else: + if typ.loc.r == nil: + typ.loc.r = typ.typeName & typ.id.rope + result = typ.loc.r + if result == nil: internalError("getTypeName: " & $typ.kind) + +proc mapSetType(typ: PType): TCTypeKind = + case int(getSize(typ)) of 1: result = ctInt8 of 2: result = ctInt16 of 4: result = ctInt32 of 8: result = ctInt64 else: result = ctArray -proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = - ## Maps a Nim type to a C type +proc mapType(typ: PType): TCTypeKind = + ## Maps a nimrod 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 tySet: result = mapSetType(typ) + of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctArray of tyObject, tyTuple: result = ctStruct - of tyUserTypeClasses: - doAssert typ.isResolvedUserTypeClass - return mapType(conf, typ.lastSon, kind) of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal, - tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned: - result = mapType(conf, lastSon(typ), kind) + tyConst, tyMutable, tyIter, tyTypeDesc: + result = mapType(lastSon(typ)) of tyEnum: - if firstOrd(conf, typ) < 0: + if firstOrd(typ) < 0: result = ctInt32 else: - case int(getSize(conf, typ)) + case int(getSize(typ)) of 1: result = ctUInt8 of 2: result = ctUInt16 of 4: result = ctInt32 of 8: result = ctInt64 - else: result = ctInt32 - of tyRange: result = mapType(conf, typ[0], kind) - of tyPtr, tyVar, tyLent, tyRef: + else: internalError("mapType") + of tyRange: result = mapType(typ.sons[0]) + of tyPtr, tyVar, tyRef: 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, tyArrayConstr, tyArray, tyVarargs: result = ctPtrToArray 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) + else: internalError("mapType") -proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind = - #if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr - #else: - result = mapType(conf, typ, skResult) +proc mapReturnType(typ: PType): TCTypeKind = + if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr + else: result = mapType(typ) proc isImportedType(t: PType): bool = result = t.sym != nil and sfImportc in t.sym.flags proc isImportedCppType(t: PType): bool = - let x = t.skipTypes(irrelevantForBackend) - result = (t.sym != nil and sfInfixCall in t.sym.flags) or - (x.sym != nil and sfInfixCall in x.sym.flags) + result = t.sym != nil and sfInfixCall in t.sym.flags -proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope +proc getTypeDescAux(m: BModule, typ: 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(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(rettype) of ctArray: result = not (skipTypes(rettype, typedescInst).kind in - {tyVar, tyLent, tyRef, tyPtr}) + {tyVar, 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,36 +187,48 @@ 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 = +proc cacheGetType(tab: TIdTable, key: PType): Rope = # returns nil if we need to declare this type # since types are now unique via the ``getUniqueType`` mechanism, this slow # linear search is not necessary anymore: - result = tab.getOrDefault(sig) + result = Rope(idTableGet(tab, key)) -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 +proc getTempName(): Rope = + result = rfmt(nil, "TMP$1", rope(backendId())) +proc getGlobalTempName(): Rope = + result = rfmt(nil, "TMP$1", rope(backendId())) -proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) = - fillLoc(param.sym.loc, locParam, param, "Result", +proc ccgIntroducedPtr(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 (optByRef in s.options) or (getSize(pt) > platform.floatSize * 2): + 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(pt) > platform.floatSize*2) or (optByRef in s.options) + else: result = false + +proc fillResult(param: PSym) = + fillLoc(param.loc, locParam, param.typ, ~"Result", OnStack) - let t = param.sym.typ - if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, proctype): - incl(param.sym.loc.flags, lfIndirect) - param.sym.loc.storage = OnUnknown + if (mapReturnType(param.typ) != ctArray) and isInvalidReturnType(param.typ): + incl(param.loc.flags, lfIndirect) + param.loc.s = OnUnknown -proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope = +proc typeNameOrLiteral(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 + result = getTypeName(t) else: result = rope(literal) @@ -274,365 +237,263 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = NumericalTypeToStr: array[tyInt..tyUInt64, string] = [ "NI", "NI8", "NI16", "NI32", "NI64", "NF", "NF32", "NF64", "NF128", - "NU", "NU8", "NU16", "NU32", "NU64"] + "NU", "NU8", "NU16", "NU32", "NU64",] case typ.kind of tyPointer: - result = typeNameOrLiteral(m, typ, "void*") - of tyString: - case detectStrVersion(m) - of 2: - cgsym(m, "NimStrPayload") - cgsym(m, "NimStringV2") - result = typeNameOrLiteral(m, typ, "NimStringV2") + result = typeNameOrLiteral(typ, "void*") + of tyEnum: + if firstOrd(typ) < 0: + result = typeNameOrLiteral(typ, "NI32") else: - cgsym(m, "NimStringDesc") - result = typeNameOrLiteral(m, typ, "NimStringDesc*") - 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*") + case int(getSize(typ)) + of 1: result = typeNameOrLiteral(typ, "NU8") + of 2: result = typeNameOrLiteral(typ, "NU16") + of 4: result = typeNameOrLiteral(typ, "NI32") + of 8: result = typeNameOrLiteral(typ, "NI64") + else: + internalError(typ.sym.info, "getSimpleTypeDesc: " & $(getSize(typ))) + result = nil + of tyString: + discard cgsym(m, "NimStringDesc") + result = typeNameOrLiteral(typ, "NimStringDesc*") + of tyCString: result = typeNameOrLiteral(typ, "NCSTRING") + of tyBool: result = typeNameOrLiteral(typ, "NIM_BOOL") + of tyChar: result = typeNameOrLiteral(typ, "NIM_CHAR") + of tyNil: result = typeNameOrLiteral(typ, "0") of tyInt..tyUInt64: - result = typeNameOrLiteral(m, typ, NumericalTypeToStr[typ.kind]) - of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ[0]) - of tyStatic: - if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ) - else: internalError(m.config, "tyStatic for getSimpleTypeDesc") - of tyGenericInst, tyAlias, tySink, tyOwned: - result = getSimpleTypeDesc(m, lastSon typ) - else: result = "" - - if result != "" and typ.isImportedType(): - let sig = hashType(typ, m.config) - if cacheGetType(m.typeCache, sig) == "": - m.typeCache[sig] = result + result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind]) + of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0]) + else: result = nil 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 = +proc getTypePre(m: BModule, typ: PType): 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, typ) 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 getForwardStructFormat(m: BModule): string = + if m.compileToCpp: result = "$1 $2;$n" + else: result = "typedef $1 $2 $2;$n" -proc seqStar(m: BModule): string = - if optSeqDestructors in m.config.globalOptions: result = "" - else: result = "*" - -proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = - result = cacheGetType(m.forwTypeCache, sig) - if result != "": return - result = getTypePre(m, typ, sig) - if result != "": return - let concrete = typ.skipTypes(abstractInst) - case concrete.kind +proc getTypeForward(m: BModule, typ: PType): Rope = + result = cacheGetType(m.forwTypeCache, typ) + if result != nil: return + result = getTypePre(m, typ) + if result != nil: return + case typ.kind of tySequence, tyTuple, tyObject: - result = getTypeName(m, typ, sig) - m.forwTypeCache[sig] = result - if not isImportedType(concrete): - addForwardStructFormat(m, structOrUnion(typ), result) - else: - pushType(m, concrete) - doAssert m.forwTypeCache[sig] == result - else: internalError(m.config, "getTypeForward(" & $typ.kind & ')') + result = getTypeName(typ) + if not isImportedType(typ): + addf(m.s[cfsForwardTypes], getForwardStructFormat(m), + [structOrUnion(typ), result]) + idTablePut(m.forwTypeCache, typ, result) + else: internalError("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: - let etB = t.skipTypes(abstractInst) + var etB = t.skipTypes(abstractInst) 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)) - pushType(m, t) + let x = getUniqueType(etB) + result = getTypeForward(m, x) + pushType(m, x) 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) - pushType(m, t) + let x = getUniqueType(etB) + result = getTypeForward(m, x) & "*" + pushType(m, x) 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 { - tyArray, tyOpenArray, tyVarargs}: + if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}: result = OnStack else: result = OnUnknown 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" + check: var IntSet, declareEnvironment=true) = + params = nil + if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]): + rettype = ~"void" else: - rettype = getTypeDescAux(m, t[0], check, skResult) - for i in 1..