Compare commits

..

14 Commits

Author SHA1 Message Date
ringabout
1204f4a38e more test cases 2023-03-31 16:38:19 +08:00
ringabout
a891b0d948 adds documentation 2023-03-30 23:02:05 +08:00
ringabout
a8c9e9c4e9 deduplicate 2023-03-29 21:12:01 +08:00
ringabout
d997bd4cb5 message 2023-03-26 23:45:37 +08:00
ringabout
e51f27c806 add one more message 2023-03-26 23:44:04 +08:00
ringabout
c1c53bebf1 fixes private fields 2023-03-25 15:47:38 +08:00
ringabout
bde9abb2f7 fixes tests 2023-03-25 09:45:01 +08:00
ringabout
3c36fc17dc Merge remote-tracking branch 'upstream/devel' into pr_object 2023-03-24 23:29:14 +08:00
ringabout
6f8b9b7cc4 better error messages 2023-03-24 23:24:37 +08:00
ringabout
a56697b513 add a filter for unnamed fields 2023-03-24 14:59:44 +08:00
ringabout
24857a0162 fixes a test 2023-03-23 23:06:31 +08:00
ringabout
91dee1bcff typo 2023-03-23 21:49:46 +08:00
ringabout
251fec94ce add some tests 2023-03-23 21:47:17 +08:00
ringabout
0175be50a9 fixes existing tests 2023-03-23 21:08:35 +08:00
934 changed files with 9112 additions and 21401 deletions

View File

@@ -71,6 +71,5 @@ body:
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 (e.g. `choosenim 2.0.0`). The Nim repo also supports online bisecting
via making a comment, which contains a code block starting by `!nim c`, `!nim js` etc. , see [nimrun-action](https://github.com/juancarlospaco/nimrun-action).
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)

69
.github/stale.yml vendored Normal file
View File

@@ -0,0 +1,69 @@
# 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

View File

@@ -1,23 +0,0 @@
# See https://github.com/juancarlospaco/nimrun-action/issues/3#issuecomment-1607344901
name: issue comments bisects
on:
issue_comment:
types: created
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# nimrun-action requires Nim installed.
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: 'devel'
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends -yq valgrind
- uses: juancarlospaco/nimrun-action@nim
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,115 +0,0 @@
name: Benchmarks CI
on:
pull_request:
push:
branches:
- 'devel'
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
cpu: [amd64]
name: '${{ matrix.os }}'
runs-on: ${{ matrix.os }}
timeout-minutes: 60 # refs bug #18178
steps:
- name: 'Checkout'
uses: actions/checkout@v4
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: 'Add build binaries to PATH'
shell: bash
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
- 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: 'Build Nimble'
shell: bash
run: ./koch nimble
- name: 'Action'
shell: bash
run: nim c -r -d:release ci/action.nim
- name: 'Checkout minimize'
uses: actions/checkout@v4
with:
repository: 'nim-lang/ci_bench'
path: minimize
- name: 'Run minimize benchmarks'
shell: bash
run: ./minimize/minimize ci-bench
- name: 'Restore minimize cached database'
uses: actions/cache/restore@v3
with:
path: minimize.csv
key: minimize-db-key
- name: 'Update minimize db'
shell: bash
run: ./minimize/minimize update-db
- name: 'Save minimize cached database'
if: |
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
matrix.target == 'linux'
uses: actions/cache/save@v3
with:
path: minimize.csv
key: minimize-db-key
- name: 'Generate minimize report'
shell: bash
run: ./minimize/minimize generate-report
- name: 'Archive minimize report'
uses: actions/upload-artifact@v3
with:
name: minimize-report
path: |
minimize/minimize.html
minimize/minimize.csv
# Requires additional permissions, see:
# https://github.com/nim-lang/Nim/actions/runs/4778177321/jobs/8494423792?pr=21566
# - name: 'Publish HTML report'
# uses: rossjrw/pr-preview-action@v1
# with:
# source-dir: minimize
# umbrella-dir: minimize
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Extract md summary
run: |
cat minimize/summary.md >> $GITHUB_STEP_SUMMARY

View File

@@ -2,7 +2,8 @@ name: Nim Docs CI
on:
push:
paths:
- 'compiler/**.nim'
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
@@ -17,7 +18,8 @@ on:
pull_request:
# Run only on changes on these files.
paths:
- 'compiler/**.nim'
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
@@ -53,7 +55,7 @@ jobs:
steps:
- name: 'Checkout'
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 2

View File

@@ -28,7 +28,7 @@ jobs:
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
steps:
- name: 'Checkout'
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 2

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: 'Checkout'
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 2

View File

@@ -1,25 +0,0 @@
# https://github.com/actions/stale#usage
name: Stale pull requests
on:
schedule:
- cron: '0 0 * * *' # Midnight.
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
with:
days-before-pr-stale: 365
days-before-pr-close: 30
days-before-issue-stale: -1
days-before-issue-close: -1
exempt-pr-labels: "ARC,bounty,Codegen,Crash,Generics,High Priority,Macros,Next release,Showstopper,Static[T]"
exempt-issue-labels: "Showstopper,Severe,bounty,Compiler Crash,Medium Priority"
stale-pr-message: >
This pull request is stale because it has been open for 1 year with no activity.
Contribute more commits on the pull request and rebase it on the latest devel,
or it will be closed in 30 days. Thank you for your contributions.
close-pr-message: >
This pull request has been marked as stale and closed due to inactivity after 395 days.

2
.gitignore vendored
View File

@@ -110,5 +110,3 @@ htmldocs
nimdoc.out.css
# except here:
!/nimdoc/testproject/expected/*
pkgs/
/compiler/compiler/

62
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,62 @@
# 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

View File

@@ -23,11 +23,11 @@ jobs:
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
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

View File

@@ -10,9 +10,7 @@
[//]: # "Additions:"
- Added `newStringUninit` to system, which creates a new string of length `len` like `newString` but with uninitialized content.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes.
[//]: # "Deprecations:"
@@ -27,7 +25,7 @@
## Compiler changes
## Tool changes
- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package in tow.

View File

@@ -1,330 +1,367 @@
# v2.0.0 - 2023-08-01
# v2.0.0 - yyyy-mm-dd
Version 2.0 is a big milestone with too many changes to list them all here.
For a full list see [details](changelog_2_0_0_details.html).
## 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`.
## New features
- Certain definitions from the default `system` module have been moved to
the following new modules:
### Better tuple unpacking
- `std/syncio`
- `std/assertions`
- `std/formatfloat`
- `std/objectdollar`
- `std/widestrs`
- `std/typedthreads`
- `std/sysatomics`
Tuple unpacking for variables is now treated as syntax sugar that directly
expands into multiple assignments. Along with this, tuple unpacking for
variables can now be nested.
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.
```nim
proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3)
- 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`
# Now nesting is supported!
let (x, (_, y), _, z) = returnsNestedTuple()
- 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.
### Improved type inference
- The `gc:v2` option is removed.
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.
- The `mainmodule` and `m` options are removed.
For example, code like the following now compiles:
- The `threads:on` option is now the default.
```nim
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
```
- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via
`experimental:flexibleOptionalParams`.
### Forbidden Tags
- Automatic dereferencing (experimental feature) is removed.
[Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) now supports the definition
of forbidden tags by the `.forbids` pragma which can be used to disable certain effects in proc types.
- 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.
For example:
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
`sink` for optimization purposes.
```nim
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises.
type IO = object ## input/output effect
proc readLine(): string {.tags: [IO].} = discard
proc echoLine(): void = discard
- 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.
proc no_IO_please() {.forbids: [IO].} =
# this is OK because it didn't define any tag:
echoLine()
# the compiler prevents this:
let y = readLine()
- 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.
### New standard library modules
- Lock levels are deprecated, now a noop.
The famous `os` module got an overhaul. Several of its features are available
under a new interface that introduces a `Path` abstraction. A `Path` is
a `distinct string`, which improves the type safety when dealing with paths, files
and directories.
Use:
- `std/oserrors` for OS error reporting.
- `std/envvars` for environment variables handling.
- `std/paths` for path handling.
- `std/dirs` for directory creation/deletion/traversal.
- `std/files` for file existence checking, file deletions and moves.
- `std/symlinks` for symlink handling.
- `std/appdirs` for accessing configuration/home/temp directories.
- `std/cmdline` for reading command line parameters.
### Consistent underscore handling
The underscore identifier (`_`) is now generally not added to scope when
used as the name of a definition. While this was already the case for
variables, it is now also the case for routine parameters, generic
parameters, routine declarations, type declarations, etc. This means that the following code now does not compile:
```nim
proc foo(_: int): int = _ + 1
echo foo(1)
proc foo[_](t: typedesc[_]): seq[_] = @[default(_)]
echo foo[int]()
proc _() = echo "_"
_()
type _ = int
let x: _ = 3
```
Whereas the following code now compiles:
```nim
proc foo(_, _: int): int = 123
echo foo(1, 2)
proc foo[_, _](): int = 123
echo foo[int, bool]()
proc foo[T, U](_: typedesc[T], _: typedesc[U]): (T, U) = (default(T), default(U))
echo foo(int, bool)
proc _() = echo "one"
proc _() = echo "two"
type _ = int
type _ = float
```
### JavaScript codegen improvement
The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
for 64-bit integer types (`int64` and `uint64`) by default. As this affects
JS code generation, code using these types to interface with the JS backend
may need to be updated. Note that `int` and `uint` are not affected.
For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint)
and in the case of potential bugs with the new implementation, the
old behavior is currently still supported with the command line option
`--jsbigint64:off`.
## Docgen improvements
`Markdown` is now the default markup language of doc comments (instead
of the legacy `RstMarkdown` mode). In this release we begin to separate
RST and Markdown features to better follow specification of each
language, with the focus on Markdown development.
See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html).
* Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to
select the markup language mode in the doc comments of the current `.nim`
file for processing by `nim doc`:
1. `Markdown` (default) is basically CommonMark (standard Markdown) +
some Pandoc Markdown features + some RST features that are missing
in our current implementation of CommonMark and Pandoc Markdown.
2. `RST` closely follows the RST spec with few additional Nim features.
3. `RstMarkdown` is a maximum mix of RST and Markdown features, which
is kept for the sake of compatibility and ease of migration.
* Added separate `md2html` and `rst2html` commands for processing
standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`).
* Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links.
* Docgen now supports concise syntax for referencing Nim symbols:
instead of specifying HTML anchors directly one can use original
Nim symbol declarations (adding the aforementioned link brackets
`[...]` around them).
* To use this feature across modules, a new `importdoc` directive was added.
Using this feature for referencing also helps to ensure that links
(inside one module or the whole project) are not broken.
* Added support for RST & Markdown quote blocks (blocks starting with `>`).
* Added a popular Markdown definition lists extension.
* Added Markdown indented code blocks (blocks indented by >= 4 spaces).
* Added syntax for additional parameters to Markdown code blocks:
```nim test="nim c $1"
...
```
## C++ interop enhancements
Nim 2.0 takes C++ interop to the next level. With the new [virtual](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma and the extended [constructor](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma.
Now one can define constructors and virtual procs that maps to C++ constructors and virtual methods, allowing one to further customize
the interoperability. There is also extended support for the [codeGenDecl](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-codegendecl-pragma) pragma, so that it works on types.
It's a common pattern in C++ to use inheritance to extend a library. Some even use multiple inheritance as a mechanism to make interfaces.
Consider the following example:
```cpp
struct Base {
int someValue;
Base(int inValue) {
someValue = inValue;
};
};
class IPrinter {
public:
virtual void print() = 0;
};
```
```nim
type
Base* {.importcpp, inheritable.} = object
someValue*: int32
IPrinter* {.importcpp.} = object
const objTemplate = """
struct $1 : public $3, public IPrinter {
$2
};
""";
type NimChild {.codegenDecl: objTemplate .} = object of Base
proc makeNimChild(val: int32): NimChild {.constructor: "NimClass('1 #1) : Base(#1)".} =
echo "It calls the base constructor passing " & $this.someValue
this.someValue = val * 2 # Notice how we can access `this` inside the constructor. It's of the type `ptr NimChild`.
proc print*(self: NimChild) {.virtual.} =
echo "Some value is " & $self.someValue
let child = makeNimChild(10)
child.print()
```
It outputs:
```
It calls the base constructor passing 10
Some value is 20
```
## ARC/ORC refinements
With the 2.0 release, the ARC/ORC model got refined once again and is now finally complete:
1. Programmers now have control over the "item was moved from" state as `=wasMoved` is overridable.
2. There is a new `=dup` hook which is more efficient than the old combination of `=wasMoved(tmp); =copy(tmp, x)` operations.
3. Destructors now take a parameter of the attached object type `T` directly and don't have to take a `var T` parameter.
With these important optimizations we improved the runtime of the compiler and important benchmarks by 0%! Wait ... what?
Yes, unfortunately it turns out that for a modern optimizer like in GCC or LLVM there is no difference.
But! This refined model is more efficient once separate compilation enters the picture. In other words, as we think of
providing a stable ABI it is important not to lose any efficiency in the calling conventions.
- 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` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop.
- nimgrep now offers the option `--inContext` (and `--notInContext`), which
allows to filter only matches with the context block containing a given pattern.
- nimgrep: names of options containing "include/exclude" are deprecated,
e.g. instead of `--includeFile` and `--excludeFile` we have
`--filename` and `--notFilename` respectively.
Also, the semantics are now consistent for such positive/negative filters.
- Nim now ships with an alternative package manager called Atlas. More on this in upcoming versions.
## Porting guide
### Block and Break
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. In other words, turn:
```nim
block:
a()
if cond:
break
b()
```
Into:
```nim
block maybePerformB:
a()
if cond:
break maybePerformB
b()
```
### Strict funcs
The definition of `"strictFuncs"` was changed.
The old definition was roughly: "A store to a ref/ptr deref is forbidden unless it's coming from a `var T` parameter".
The new definition is: "A store to a ref/ptr deref is forbidden."
This new definition is much easier to understand, the price is some expressitivity. The following code used to be
accepted:
```nim
{.experimental: "strictFuncs".}
type Node = ref object
s: string
func create(s: string): Node =
result = Node()
result.s = s # store to result[]
```
Now it has to be rewritten to:
```nim
{.experimental: "strictFuncs".}
type Node = ref object
s: string
func create(s: string): Node =
result = Node(s: s)
```
### Standard library
Several standard library modules have been moved to nimble packages, use `nimble` or `atlas` 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`
- `std/md5` => `checksums/md5`
- `std/sha1` => `checksums/sha1`
- `std/sums` => `sums`
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`).

View File

@@ -1,560 +0,0 @@
# v2.0.0 - 2023-08-01
## Changes affecting backward compatibility
- ORC is now the default memory management strategy. Use
`--mm:refc` for a transition period.
- The `threads:on` option is now the default.
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response. It follows Apache's `HttpClient` (Java), `http` (go) and .NET `HttpWebResponse` (C#) behaviors. Previously it raised a `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 an `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, which is replaced by [threading/channels](https://github.com/nim-lang/threading/blob/master/threading/channels.nim). Use the command `nimble install threading` and import `threading/channels`.
- Enabling `-d:nimPreviewCstringConversion` causes `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` to not support conversion to `cstring` anymore.
- Enabling `-d:nimPreviewProcConversion` causes `proc` to not support conversion to
`pointer` anymore. `cast` may be used instead.
- The `gc:v2` option is removed.
- The `mainmodule` and `m` options are removed.
- Optional parameters in combination with `: body` syntax ([RFC #405](https://github.com/nim-lang/RFCs/issues/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`. Instead,
use `type Foo[T] {.final.} = 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.
- `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.
- `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` conversions now trigger 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 have been 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`
- `std/md5` => `checksums/md5`
- `std/sha1` => `checksums/sha1`
- `std/sums` => `std/sums`
- 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.
- When `--warning[BareExcept]:on` is enabled, if an `except` specifies no exception or any exception not inheriting from `Defect` or `CatchableError`, a `warnBareExcept` warning will be triggered. For example, the following code will emit a warning:
```nim
try:
discard
except: # Warning: The bare except clause is deprecated; use `except CatchableError:` instead [BareExcept]
discard
```
- The experimental `strictFuncs` feature now disallows a store to the heap via a `ref` or `ptr` indirection.
- The underscore identifier (`_`) is now generally not added to scope when
used as the name of a definition. While this was already the case for
variables, it is now also the case for routine parameters, generic
parameters, routine declarations, type declarations, etc. This means that the following code now does not compile:
```nim
proc foo(_: int): int = _ + 1
echo foo(1)
proc foo[_](t: typedesc[_]): seq[_] = @[default(_)]
echo foo[int]()
proc _() = echo "_"
_()
type _ = int
let x: _ = 3
```
Whereas the following code now compiles:
```nim
proc foo(_, _: int): int = 123
echo foo(1, 2)
proc foo[_, _](): int = 123
echo foo[int, bool]()
proc foo[T, U](_: typedesc[T], _: typedesc[U]): (T, U) = (default(T), default(U))
echo foo(int, bool)
proc _() = echo "one"
proc _() = echo "two"
type _ = int
type _ = float
```
- Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages.
- The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
for 64-bit integer types (`int64` and `uint64`) by default. As this affects
JS code generation, code using these types to interface with the JS backend
may need to be updated. Note that `int` and `uint` are not affected.
For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint)
and in the case of potential bugs with the new implementation, the
old behavior is currently still supported with the command line option
`--jsbigint64:off`.
- The `proc` and `iterator` type classes now respectively only match
procs and iterators. Previously both type classes matched any of
procs or iterators.
```nim
proc prc(): int =
123
iterator iter(): int =
yield 123
proc takesProc[T: proc](x: T) = discard
proc takesIter[T: iterator](x: T) = discard
# always compiled:
takesProc(prc)
takesIter(iter)
# no longer compiles:
takesProc(iter)
takesIter(prc)
```
- The `proc` and `iterator` type classes now accept a calling convention pragma
(i.e. `proc {.closure.}`) that must be shared by matching proc or iterator
types. Previously, pragmas were parsed but discarded if no parameter list
was given.
This is represented in the AST by an `nnkProcTy`/`nnkIteratorTy` node with
an `nnkEmpty` node in the place of the `nnkFormalParams` node, and the pragma
node in the same place as in a concrete `proc` or `iterator` type node. This
state of the AST may be unexpected to existing code, both due to the
replacement of the `nnkFormalParams` node as well as having child nodes
unlike other type class AST.
- Signed integer literals in `set` literals now default to a range type of
`0..255` instead of `0..65535` (the maximum size of sets).
- `case` statements with `else` branches put before `elif`/`of` branches in macros
are rejected with "invalid order of case branches".
- Destructors now default to `.raises: []` (i.e. destructors must not raise
unlisted exceptions) and explicitly raising destructors are implementation
defined behavior.
- The very old, undocumented `deprecated` pragma statement syntax for
deprecated aliases is now a no-op. The regular deprecated pragma syntax is
generally sufficient instead.
```nim
# now does nothing:
{.deprecated: [OldName: NewName].}
# instead use:
type OldName* {.deprecated: "use NewName instead".} = NewName
const oldName* {.deprecated: "use newName instead".} = newName
```
`defined(nimalias)` can be used to check for versions when this syntax was
available; however since code that used this syntax is usually very old,
these deprecated aliases are likely not used anymore and it may make sense
to simply remove these statements.
- `getProgramResult` and `setProgramResult` in `std/exitprocs` are no longer
declared when they are not available on the backend. Previously it would call
`doAssert false` at runtime despite the condition being checkable at compile-time.
- Custom destructors now supports non-var parameters, e.g. ``proc `=destroy`[T: object](x: T)`` is valid. ``proc `=destroy`[T: object](x: var T)`` is deprecated.
- Relative imports will not resolve to searched paths anymore, e.g. `import ./tables` now reports an error properly.
## 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.
- The `colors` module is 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.
- `strutils.split` and `strutils.rsplit` now return the source string as a single element for an empty separator.
- `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/jsfetch.newFetchOptions` now has default values for all parameters.
- `std/jsformdata` now accepts the `Blob` data type.
- `std/sharedlist` and `std/sharedtables` are now deprecated, see [RFC #433](https://github.com/nim-lang/RFCs/issues/433).
- There is a new compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove the dependency on the 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 the 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 an `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 previously part of `std/os`:
- Added `std/oserrors` for OS error reporting.
- Added `std/envvars` for environment variables handling.
- Added `std/cmdline` for reading command line parameters.
- Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`.
- Added `sep` parameter in `std/uri` to specify the query separator.
- 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 [RFC #460](https://github.com/nim-lang/RFCs/issues/460).
- Added `openArray[char]` overloads for `std/parseutils` and `std/unicode`, allowing for more code reuse.
- Added a `safe` parameter to `base64.encodeMime`.
- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes.
- Added `minmax` to `sequtils`, as a more efficient `(min(_), max(_))` over sequences.
- `std/jscore` for the JavaScript target:
+ 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).
+ Added `toDateString`, `toISOString`, `toJSON`, `toTimeString`, `toUTCString` converters for `DateTime`.
- Added `BackwardsIndex` overload for `CacheSeq`.
- Added support for nested `with` blocks in `std/with`.
- Added `ensureMove` to the system module. It ensures that the passed argument is moved, otherwise an error is given at the compile time.
[//]: # "Deprecations:"
- Deprecated `selfExe` for Nimscript.
- 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 take 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) now 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 backticks 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-nimdefine-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 now be overridden by users.
- There is a new pragma called [quirky](https://nim-lang.github.io/Nim/manual_experimental.html#quirky-routines) that can be used to affect the code
generation of goto based exception handling. It can improve the produced code size but its effects can be subtle so use it with care.
- Tuple unpacking for variables is now treated as syntax sugar that directly
expands into multiple assignments. Along with this, tuple unpacking for
variables can now be nested.
```nim
proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3)
let (x, (_, y), _, z) = returnsNestedTuple()
# roughly becomes
let
tmpTup1 = returnsNestedTuple()
x = tmpTup1[0]
tmpTup2 = tmpTup1[1]
y = tmpTup2[1]
z = tmpTup1[3]
```
As a result `nnkVarTuple` nodes in variable sections will no longer be
reflected in `typed` AST.
- C++ interoperability:
- New [`virtual`](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma added.
- Improvements to [`constructor`](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma.
## 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.
- Removed deprecated `LineTooLong` hint.
- Line numbers and file names of source files work correctly inside templates for JavaScript targets.
- Removed support for LCC (Local C), Pelles C, Digital Mars and Watcom compilers.
## Docgen
- `Markdown` is now the default markup language of doc comments (instead
of the legacy `RstMarkdown` mode). In this release we begin to separate
RST and Markdown features to better follow specification of each
language, with the focus on Markdown development.
See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html).
* Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to
select the markup language mode in the doc comments of the current `.nim`
file for processing by `nim doc`:
1. `Markdown` (default) is basically CommonMark (standard Markdown) +
some Pandoc Markdown features + some RST features that are missing
in our current implementation of CommonMark and Pandoc Markdown.
2. `RST` closely follows the RST spec with few additional Nim features.
3. `RstMarkdown` is a maximum mix of RST and Markdown features, which
is kept for the sake of compatibility and ease of migration.
* Added separate `md2html` and `rst2html` commands for processing
standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`).
- Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links.
- Docgen now supports concise syntax for referencing Nim symbols:
instead of specifying HTML anchors directly one can use original
Nim symbol declarations (adding the aforementioned link brackets
`[...]` around them).
* To use this feature across modules, a new `importdoc` directive was added.
Using this feature for referencing also helps to ensure that links
(inside one module or the whole project) are not broken.
- Added support for RST & Markdown quote blocks (blocks starting with `>`).
- Added a popular Markdown definition lists extension.
- Added Markdown indented code blocks (blocks indented by >= 4 spaces).
- Added syntax for additional parameters to Markdown code blocks:
```nim test="nim c $1"
...
```
## 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` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop.
- nimgrep added the option `--inContext` (and `--notInContext`), which
allows to filter only matches with the context block containing a given pattern.
- nimgrep: names of options containing "include/exclude" are deprecated,
e.g. instead of `--includeFile` and `--excludeFile` we have
`--filename` and `--notFilename` respectively.
Also the semantics are now consistent for such positive/negative filters.
- koch now supports the `--skipIntegrityCheck` option. The command `koch --skipIntegrityCheck boot -d:release` always builds the compiler twice.

View File

@@ -1,12 +0,0 @@
# v2.2.0 - 2023-mm-dd
## Changes affecting backward compatibility
## Standard library additions and changes
## Language changes
## Compiler changes
## Tool changes

View File

@@ -3,7 +3,7 @@ import std/[strutils, os, osproc, parseutils, strformat]
proc main() =
var msg = ""
const cmd = "./koch boot --mm:orc -d:release"
const cmd = "./koch boot --gc:orc -d:release"
let (output, exitCode) = execCmdEx(cmd)

View File

@@ -58,11 +58,7 @@ _nimNumCpu(){
# FreeBSD | macOS: $(sysctl -n hw.ncpu)
# OpenBSD: $(sysctl -n hw.ncpuonline)
# windows: $NUMBER_OF_PROCESSORS ?
if env | grep -q '^NIMCORES='; then
echo $NIMCORES
else
echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1)
fi
echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1)
}
_nimBuildCsourcesIfNeeded(){

View File

@@ -74,7 +74,7 @@ proc aliases*(obj, field: PNode): AliasKind =
# 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 result: seq[PNode]
var n = n
while true:
case n.kind

View File

@@ -114,8 +114,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
# use expensive type check:
if isPartOf(a.sym.typ, b.sym.typ) != arNo:
result = arMaybe
else:
result = arNo
of nkBracketExpr:
result = isPartOf(a[0], b[0])
if a.len >= 2 and b.len >= 2:
@@ -151,7 +149,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
result = isPartOf(a[1], b[1])
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isPartOf(a[0], b[0])
else: result = arNo
else: discard
# Calls return a new location, so a default of ``arNo`` is fine.
else:
# go down recursively; this is quite demanding:
@@ -167,7 +165,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
of DerefKinds:
# a* !<| b[] iff
result = arNo
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a, b[0])
if result == arNo: result = arMaybe
@@ -189,9 +186,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a[0], b)
if result == arNo: result = arMaybe
else:
result = arNo
else: result = arNo
else: discard
of nkObjConstr:
result = arNo
for i in 1..<b.len:
@@ -209,6 +204,4 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
of nkBracket:
if b.len > 0:
result = isPartOf(a, b[0])
else:
result = arNo
else: result = arNo
else: discard

View File

@@ -231,7 +231,7 @@ type
TNodeKinds* = set[TNodeKind]
type
TSymFlag* = enum # 51 flags!
TSymFlag* = enum # 49 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
@@ -283,7 +283,7 @@ type
sfNamedParamCall, # symbol needs named parameter call syntax in target
# language; for interfacing with Objective C
sfDiscardable, # returned value may be discarded implicitly
sfOverridden, # proc is overridden
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
@@ -303,8 +303,6 @@ type
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'
# for templates and macros, means cannot be called
# as a lone symbol (cannot use alias syntax)
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
@@ -312,10 +310,6 @@ type
#
# This is disallowed but can cause the typechecking to go into
# an infinite loop, this flag is used as a sentinel to stop it.
sfVirtual # proc is a C++ virtual function
sfByCopy # param is marked as pass bycopy
sfMember # proc is a C++ member of a type
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
TSymFlags* = set[TSymFlag]
@@ -341,14 +335,13 @@ const
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
sfExperimental* = sfOverridden # module uses the .experimental switch
sfGoto* = sfOverridden # var is used for 'goto' code generation
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
sfCppMember* = { sfVirtual, sfMember, sfConstructor } # proc is a C++ member, meaning it will be attached to the type definition
const
# getting ready for the future expr/stmt merge
@@ -520,7 +513,7 @@ type
nfSkipFieldChecking # node skips field visable checking
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47)
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46)
tfVarargs, # procedure has C styled varargs
# tyArray type represeting a varargs list
tfNoSideEffect, # procedure type does not allow side effects
@@ -590,8 +583,6 @@ type
tfIsConstructor
tfEffectSystemWorkaround
tfIsOutParam
tfSendable
tfImplicitStatic
TTypeFlags* = set[TTypeFlag]
@@ -627,12 +618,13 @@ type
# file (it is loaded on demand, which may
# mean: never)
skPackage, # symbol is a package (used for canonicalization)
skAlias # an alias (needs to be resolved immediately)
TSymKinds* = set[TSymKind]
const
routineKinds* = {skProc, skFunc, skMethod, skIterator,
skConverter, skMacro, skTemplate}
ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub} + routineKinds
ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub, skAlias} + routineKinds
tfUnion* = tfNoSideEffect
tfGcSafe* = tfThread
@@ -693,7 +685,7 @@ type
mIsPartOf, mAstToStr, mParallel,
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
mNewString, mNewStringOfCap, mParseBiggestFloat,
mMove, mEnsureMove, mWasMoved, mDup, mDestroy, mTrace,
mMove, mWasMoved, mDestroy, mTrace,
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
@@ -826,6 +818,9 @@ type
locOther # location is something other
TLocFlag* = enum
lfIndirect, # backend introduced a pointer
lfFullExternalName, # only used when 'conf.cmd == cmdNimfix': Indicates
# that the symbol has been imported via 'importc: "fullname"' and
# no format string.
lfNoDeepCopy, # no need for a deep copy
lfNoDecl, # do not declare it in C
lfDynamicLib, # link symbol to dynamic library
@@ -860,7 +855,7 @@ type
# keep in sync with PackedLib
kind*: TLibKind
generated*: bool # needed for the backends:
isOverridden*: bool
isOverriden*: bool
name*: Rope
path*: PNode # can be a string literal!
@@ -922,9 +917,7 @@ type
# for modules, an unique index corresponding
# to the module's fileIdx
# for variables a slot index for the evaluator
offset*: int32 # offset of record field
disamb*: int32 # disambiguation number; the basic idea is that
# `<procname>__<module>_<disamb>`
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)
@@ -932,11 +925,10 @@ type
cname*: string # resolved C declaration name in importc decl, e.g.:
# proc fun() {.importc: "$1aux".} => cname = funaux
constraint*: PNode # additional constraints like 'lit|result'; also
# misused for the codegenDecl and virtual pragmas in the hope
# misused for the codegenDecl pragma in the hope
# it won't cause problems
# for skModule the string literal to output for
# deprecated modules.
instantiatedFrom*: PSym # for instances, the generic symbol where it came from.
when defined(nimsuggest):
allUsages*: seq[TLineInfo]
@@ -946,7 +938,6 @@ type
attachedWasMoved,
attachedDestructor,
attachedAsgn,
attachedDup,
attachedSink,
attachedTrace,
attachedDeepCopy
@@ -959,7 +950,7 @@ type
kind*: TTypeKind # kind of type
callConv*: TCallingConvention # for procs
flags*: TTypeFlags # flags of the type
sons: TTypeSeq # base types, etc.
sons*: TTypeSeq # base types, etc.
n*: PNode # node for types:
# for range types a nkRange node
# for record types a nkRecord node
@@ -1040,8 +1031,6 @@ 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]
else:
result = ""
proc `comment=`*(n: PNode, a: string) =
let id = n.nodeId
@@ -1132,10 +1121,11 @@ const
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
of nkOpenSymChoice, nkClosedSymChoice: a.sons[0].sym.name
else: nil
const
@@ -1151,17 +1141,13 @@ type
symId*: int32
typeId*: int32
sealed*: bool
disambTable*: CountTable[PIdent]
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, disambTable: initCountTable[PIdent]())
proc idGeneratorForPackage*(nextIdWillBe: int32): IdGenerator =
result = IdGenerator(module: PackageModuleId, symId: nextIdWillBe - 1'i32, typeId: 0, disambTable: initCountTable[PIdent]())
result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0)
proc nextSymId*(x: IdGenerator): ItemId {.inline.} =
assert(not x.sealed)
@@ -1228,7 +1214,6 @@ proc getDeclPragma*(n: PNode): PNode =
case n.kind
of routineDefs:
if n[pragmasPos].kind != nkEmpty: result = n[pragmasPos]
else: result = nil
of nkTypeDef:
#[
type F3*{.deprecated: "x3".} = int
@@ -1248,8 +1233,6 @@ proc getDeclPragma*(n: PNode): PNode =
]#
if n[0].kind == nkPragmaExpr:
result = n[0][1]
else:
result = nil
else:
# support as needed for `nkIdentDefs` etc.
result = nil
@@ -1265,12 +1248,6 @@ proc extractPragma*(s: PSym): PNode =
if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1:
# s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma]
result = s.ast[0][1]
else:
result = nil
else:
result = nil
else:
result = nil
assert result == nil or result.kind == nkPragma
proc skipPragmaExpr*(n: PNode): PNode =
@@ -1362,15 +1339,11 @@ when false:
echo k
echo v
proc newSym*(symKind: TSymKind, name: PIdent, idgen: IdGenerator; owner: PSym,
proc newSym*(symKind: TSymKind, name: PIdent, id: ItemId, owner: PSym,
info: TLineInfo; options: TOptions = {}): PSym =
# generates a symbol and initializes the hash field too
assert not name.isNil
let id = nextSymId idgen
result = PSym(name: name, kind: symKind, flags: {}, info: info, itemId: id,
options: options, owner: owner, offset: defaultOffset,
disamb: getOrDefault(idgen.disambTable, name).int32)
idgen.disambTable.inc name
options: options, owner: owner, offset: defaultOffset)
when false:
if id.module == 48 and id.item == 39:
writeStackTrace()
@@ -1500,7 +1473,7 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
result = newNode(nkIntLit)
of tyStatic: # that's a pre-existing bug, will fix in another PR
result = newNode(nkIntLit)
else: raiseAssert $kind
else: doAssert false, $kind
result.intVal = intVal
result.typ = typ
@@ -1530,7 +1503,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
const
AttachedOpToStr*: array[TTypeAttachedOp, string] = [
"=wasMoved", "=destroy", "=copy", "=dup", "=sink", "=trace", "=deepcopy"]
"=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy"]
proc `$`*(s: PSym): string =
if s != nil:
@@ -1538,31 +1511,15 @@ proc `$`*(s: PSym): string =
else:
result = "<nil>"
iterator items*(t: PType): PType =
for i in 0..<t.sons.len: yield t.sons[i]
iterator pairs*(n: PType): tuple[i: int, n: PType] =
for i in 0..<n.sons.len: yield (i, n.sons[i])
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym, sons: seq[PType] = @[]): PType =
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType =
result = PType(kind: kind, owner: owner, size: defaultSize,
align: defaultAlignment, itemId: id,
uniqueId: id, sons: sons)
uniqueId: id)
when false:
if result.itemId.module == 55 and result.itemId.item == 2:
echo "KNID ", kind
writeStackTrace()
template newType*(kind: TTypeKind, id: ItemId; owner: PSym, parent: PType): PType =
newType(kind, id, owner, parent.sons)
proc newType*(prev: PType, sons: seq[PType]): PType =
result = prev
result.sons = sons
proc addSon*(father, son: PType) =
# todo fixme: in IC, `son` might be nil
father.sons.add(son)
proc mergeLoc(a: var TLoc, b: TLoc) =
if a.k == low(typeof(a.k)): a.k = b.k
@@ -1600,8 +1557,8 @@ proc copyType*(t: PType, id: ItemId, owner: PSym): PType =
proc exactReplica*(t: PType): PType =
result = copyType(t, t.itemId, t.owner)
proc copySym*(s: PSym; idgen: IdGenerator): PSym =
result = newSym(s.kind, s.name, idgen, s.owner, s.info, s.options)
proc copySym*(s: PSym; id: ItemId): PSym =
result = newSym(s.kind, s.name, id, s.owner, s.info, s.options)
#result.ast = nil # BUGFIX; was: s.ast which made problems
result.typ = s.typ
result.flags = s.flags
@@ -1616,9 +1573,9 @@ proc copySym*(s: PSym; idgen: IdGenerator): PSym =
result.bitsize = s.bitsize
result.alignment = s.alignment
proc createModuleAlias*(s: PSym, idgen: IdGenerator, newIdent: PIdent, info: TLineInfo;
proc createModuleAlias*(s: PSym, id: ItemId, newIdent: PIdent, info: TLineInfo;
options: TOptions): PSym =
result = newSym(s.kind, newIdent, idgen, s.owner, info, options)
result = newSym(s.kind, newIdent, id, s.owner, info, options)
# keep ID!
result.ast = s.ast
#result.id = s.id # XXX figure out what to do with the ID.
@@ -1628,13 +1585,19 @@ proc createModuleAlias*(s: PSym, idgen: IdGenerator, newIdent: PIdent, info: TLi
result.loc = s.loc
result.annex = s.annex
proc initStrTable*(): TStrTable =
result = TStrTable(counter: 0)
newSeq(result.data, StartSize)
proc initStrTable*(x: var TStrTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc initIdTable*(): TIdTable =
result = TIdTable(counter: 0)
newSeq(result.data, StartSize)
proc newStrTable*: TStrTable =
initStrTable(result)
proc initIdTable*(x: var TIdTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc newIdTable*: TIdTable =
initIdTable(result)
proc resetIdTable*(x: var TIdTable) =
x.counter = 0
@@ -1642,17 +1605,17 @@ proc resetIdTable*(x: var TIdTable) =
setLen(x.data, 0)
setLen(x.data, StartSize)
proc initObjectSet*(): TObjectSet =
result = TObjectSet(counter: 0)
newSeq(result.data, StartSize)
proc initObjectSet*(x: var TObjectSet) =
x.counter = 0
newSeq(x.data, StartSize)
proc initIdNodeTable*(): TIdNodeTable =
result = TIdNodeTable(counter: 0)
newSeq(result.data, StartSize)
proc initIdNodeTable*(x: var TIdNodeTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc initNodeTable*(): TNodeTable =
result = TNodeTable(counter: 0)
newSeq(result.data, StartSize)
proc initNodeTable*(x: var TNodeTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType =
result = t
@@ -1836,7 +1799,6 @@ proc hasNilSon*(n: PNode): bool =
result = false
proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
result = false
if n == nil: return
case n.kind
of nkEmpty..nkNilLit: result = n.kind in kinds
@@ -1937,7 +1899,7 @@ proc skipGenericOwner*(s: PSym): PSym =
## Generic instantiations are owned by their originating generic
## symbol. This proc skips such owners and goes straight to the owner
## of the generic itself (the module or the enclosing proc).
result = if s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule:
result = if s.kind in skProcKinds and sfFromGeneric in s.flags:
s.owner.owner
else:
s.owner
@@ -1953,6 +1915,20 @@ proc isCompileTimeProc*(s: PSym): bool {.inline.} =
result = s.kind == skMacro or
s.kind in {skProc, skFunc} and sfCompileTime in s.flags
proc isRunnableExamples*(n: PNode): bool =
# Templates and generics don't perform symbol lookups.
result = n.kind == nkSym and n.sym.magic == mRunnableExamples or
n.kind == nkIdent and n.ident.s == "runnableExamples"
proc requiredParams*(s: PSym): int =
# Returns the number of required params (without default values)
# XXX: Perhaps we can store this in the `offset` field of the
# symbol instead?
for i in 1..<s.typ.len:
if s.typ.n[i].sym.ast != nil:
return i - 1
return s.typ.len - 1
proc hasPattern*(s: PSym): bool {.inline.} =
result = isRoutine(s) and s.ast[patternPos].kind != nkEmpty
@@ -2026,7 +2002,7 @@ proc toObjectFromRefPtrGeneric*(typ: PType): PType =
of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0]
# automatic dereferencing is deep, refs #18298.
else: break
# result does not have to be object type
assert result.sym != nil
proc isImportedException*(t: PType; conf: ConfigRef): bool =
assert t != nil
@@ -2038,8 +2014,6 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
if base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}:
result = true
else:
result = false
proc isInfixAs*(n: PNode): bool =
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as"
@@ -2050,12 +2024,10 @@ proc skipColon*(n: PNode): PNode =
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
if n.typ != nil and n.typ.kind == tyTypeDesc:
let t = skipTypes(n.typ, {tyTypeDesc})
if t.kind == tyGenericParam and t.len == 0:
return n
for son in n:
let n = son.findUnresolvedStatic
if n != nil: return n
@@ -2093,12 +2065,6 @@ proc isClosureIterator*(typ: PType): bool {.inline.} =
proc isClosure*(typ: PType): bool {.inline.} =
typ.kind == tyProc and typ.callConv == ccClosure
proc isNimcall*(s: PSym): bool {.inline.} =
s.typ.callConv == ccNimCall
proc isExplicitCallConv*(s: PSym): bool {.inline.} =
tfExplicitCallConv in s.typ.flags
proc isSinkParam*(s: PSym): bool {.inline.} =
s.kind == skParam and (s.typ.kind == tySink or tfHasOwned in s.typ.flags)
@@ -2173,7 +2139,3 @@ const
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
proc isTrue*(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0

View File

@@ -109,7 +109,7 @@ type
data*: TIIPairSeq
proc initIITable*(x: var TIITable)
proc initIiTable*(x: var TIITable)
proc iiTableGet*(t: TIITable, key: int): int
proc iiTablePut*(t: var TIITable, key, val: int)
@@ -197,7 +197,6 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
result = nil
proc sameIgnoreBacktickGensymInfo(a, b: string): bool =
result = false
if a[0] != b[0]: return false
var alen = a.len - 1
while alen > 0 and a[alen] != '`': dec(alen)
@@ -227,11 +226,10 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
## Named parameters are special because a named parameter can be
## gensym'ed and then they have '\`<number>' suffix that we need to
## ignore, see compiler / evaltempl.nim, snippet:
## ```nim
## ```
## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id),
## if c.instLines: actual.info else: templ.info)
## ```
result = nil
for i in 1..<list.len:
let it = list[i].sym
if it.name.id == ident.id or
@@ -329,10 +327,8 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
maxRecDepth: int): Rope =
var sonsRope: Rope
if n == nil:
result = ""
sonsRope = rope("null")
elif containsOrIncl(marker, n.id):
result = ""
sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
strutils.toHex(cast[int](n), sizeof(n) * 2))]
else:
@@ -1067,7 +1063,6 @@ proc isAddrNode*(n: PNode): bool =
else: false
proc listSymbolNames*(symbols: openArray[PSym]): string =
result = ""
for sym in symbols:
if result.len > 0:
result.add ", "

View File

@@ -87,6 +87,5 @@ const populationCount: array[uint8, uint8] = block:
arr
proc bitSetCard*(x: TBitSet): BiggestInt =
result = 0
for it in x:
result.inc int(populationCount[it])

View File

@@ -38,7 +38,6 @@ 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 =
result = default(Val)
var x = b.root
while x.isInternal:
for j in 0..<x.entries:
@@ -69,7 +68,7 @@ proc copyHalf[Key, Val](h, result: Node[Key, Val]) =
result.links[j] = h.links[Mhalf + j]
else:
for j in 0..<Mhalf:
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
when defined(gcArc) or defined(gcOrc):
result.vals[j] = move h.vals[Mhalf + j]
else:
shallowCopy(result.vals[j], h.vals[Mhalf + j])
@@ -92,7 +91,7 @@ proc insert[Key, Val](h: Node[Key, Val], key: Key, val: Val): Node[Key, Val] =
if less(key, h.keys[j]): break
inc j
for i in countdown(h.entries, j+1):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
when defined(gcArc) or defined(gcOrc):
h.vals[i] = move h.vals[i-1]
else:
shallowCopy(h.vals[i], h.vals[i-1])

View File

@@ -24,7 +24,6 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool =
result = false
var n = le
while true:
# do NOT follow nkHiddenDeref here!
@@ -47,7 +46,6 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
# cannot analyse the location; assume the worst
return true
result = false
if le != nil:
for i in 1..<ri.len:
let r = ri[i]
@@ -89,7 +87,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
# 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):
# Great, we can use 'd':
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
@@ -97,7 +95,8 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
pl.add(");\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
pl.add(addrLoc(p.config, tmp))
pl.add(");\n")
line(p, cpsStmts, pl)
@@ -115,24 +114,28 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
excl d.flags, lfSingleUse
else:
if d.k == locNone and p.splitDecls == 0:
d = getTempCpp(p, typ[0], pl)
getTempCpp(p, typ[0], d, pl)
else:
if d.k == locNone: d = getTemp(p, typ[0])
var list = initLoc(locCall, d.lode, OnUnknown)
if d.k == locNone: getTemp(p, typ[0], d)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
elif isHarmlessStore(p, canRaise, d):
if d.k == locNone: d = getTemp(p, typ[0])
if d.k == locNone: getTemp(p, typ[0], d)
assert(d.t != nil) # generate an assignment to d:
var list = initLoc(locCall, d.lode, OnUnknown)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
var list = initLoc(locCall, d.lode, OnUnknown)
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, tmp, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
@@ -154,9 +157,10 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} =
result = true
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
var a = initLocExpr(p, q[1])
var b = initLocExpr(p, q[2])
var c = initLocExpr(p, q[3])
var a, b, c: TLoc
initLocExpr(p, q[1], a)
initLocExpr(p, q[2], b)
initLocExpr(p, q[3], c)
# but first produce the required index checks:
if optBoundsCheck in p.options:
genBoundsCheck(p, a, b, c)
@@ -201,7 +205,6 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, rdLoc(a))],
lengthExpr)
else:
result = ("", "")
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
@@ -221,7 +224,8 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0])
result.add x & ", " & y
else:
var a: TLoc = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
var a: TLoc
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(n):
@@ -265,19 +269,20 @@ 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, gcAtomicArc, gcOrc} and
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcOrc} and
getSize(p.config, a.lode.typ) < 1024:
result = getTemp(p, a.lode.typ, needsInit=false)
getTemp(p, a.lode.typ, result, needsInit=false)
genAssignment(p, result, a, {})
else:
result = a
proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc =
result = getTemp(p, a.lode.typ, needsInit=false)
getTemp(p, a.lode.typ, result, needsInit=false)
genAssignment(p, result, a, {})
proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} =
var a: TLoc = initLocExpr(p, n[0])
var a: TLoc
initLocExpr(p, n[0], a)
appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) =
@@ -287,16 +292,15 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
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]) and
(optByRef notin param.options or not p.module.compileToCpp):
a = initLocExpr(p, n)
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]):
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
n.kind == nkHiddenAddr:
a = initLocExprSingleUse(p, n[0])
initLocExprSingleUse(p, n[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]
@@ -307,7 +311,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
else:
addRdLoc(a, result)
else:
a = initLocExprSingleUse(p, n)
initLocExprSingleUse(p, n, a)
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
#assert result != nil
@@ -316,13 +320,12 @@ proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) =
if n.kind == nkStringToCString:
genArgStringToCString(p, n, result, needsTmp)
else:
a = initLocExprSingleUse(p, n)
initLocExprSingleUse(p, n, a)
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
import aliasanalysis
proc potentialAlias(n: PNode, potentialWrites: seq[PNode]): bool =
result = false
for p in potentialWrites:
if p.aliases(n) != no or n.aliases(p) != no:
return true
@@ -378,13 +381,13 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
# We must generate temporaries in cases like #14396
# to keep the strict Left-To-Right evaluation
var needTmp = newSeq[bool](ri.len - 1)
var potentialWrites: seq[PNode] = @[]
var potentialWrites: seq[PNode]
for i in countdown(ri.len - 1, 1):
if ri[i].skipTrivialIndirections.kind == nkSym:
needTmp[i - 1] = potentialAlias(ri[i], potentialWrites)
else:
#if not ri[i].typ.isCompileTimeOnly:
var potentialReads: seq[PNode] = @[]
var potentialReads: seq[PNode]
getPotentialReads(ri[i], potentialReads)
for n in potentialReads:
if not needTmp[i - 1]:
@@ -416,8 +419,9 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
res = res & "_actual".rope
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc
# this is a hotspot in the compiler
var op: TLoc = initLocExpr(p, ri[0])
initLocExpr(p, ri[0], op)
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
assert(typ.kind == tyProc)
@@ -439,7 +443,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
var op: TLoc = initLocExpr(p, ri[0])
var op: TLoc
initLocExpr(p, ri[0], op)
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
@@ -464,7 +469,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
if d.k == locNone:
d = getTemp(p, typ[0], needsInit=true)
getTemp(p, typ[0], d, needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
@@ -472,15 +477,17 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genCallPattern()
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
pl.add(addrLoc(p.config, tmp))
genCallPattern()
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {}) # no need for deep copying
elif isHarmlessStore(p, canRaise, d):
if d.k == locNone: d = getTemp(p, typ[0])
if d.k == locNone: getTemp(p, typ[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
if tfIterator in typ.flags:
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
else:
@@ -488,9 +495,11 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ[0])
var tmp: TLoc
getTemp(p, typ[0], tmp)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
if tfIterator in typ.flags:
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
else:
@@ -658,7 +667,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
inc j
inc i
of '\'':
var idx, stars: int = 0
var idx, stars: int
if scanCppGenericSlot(pat, i, idx, stars):
var t = resolveStarsInCppType(typ, idx, stars)
if t == nil: result.add("void")
@@ -672,7 +681,8 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
result.add(substr(pat, start, i - 1))
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc = initLocExpr(p, ri[0])
var op: TLoc
initLocExpr(p, ri[0], op)
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
assert(typ.kind == tyProc)
@@ -694,9 +704,10 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
d.r = pl
excl d.flags, lfSingleUse
else:
if d.k == locNone: d = getTemp(p, typ[0])
if d.k == locNone: getTemp(p, typ[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
@@ -716,7 +727,8 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# generates a crappy ObjC call
var op: TLoc = initLocExpr(p, ri[0])
var op: TLoc
initLocExpr(p, ri[0], op)
var pl = "["
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
@@ -758,22 +770,24 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# 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: d = getTemp(p, typ[0], needsInit=true)
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
pl.add("Result: ")
pl.add(addrLoc(p.config, d))
pl.add("];\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
pl.add(addrLoc(p.config, tmp))
pl.add("];\n")
line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
pl.add("]")
if d.k == locNone: d = getTemp(p, typ[0])
if d.k == locNone: getTemp(p, typ[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, ri, OnUnknown)
var list: TLoc
initLoc(list, locCall, ri, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:

File diff suppressed because it is too large Load Diff

View File

@@ -57,7 +57,8 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
specializeResetT(p, accessor, lastSon(typ))
of tyArray:
let arraySize = lengthOrd(p.config, typ[0])
var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt))
var i: TLoc
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i)
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.r, arraySize])
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ[1])
@@ -94,12 +95,12 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
of ctInt8, ctInt16, ctInt32, ctInt64:
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
else:
raiseAssert "unexpected set type kind"
of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
doAssert false, "unexpected set type kind"
of {tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs,
tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable:
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable}:
discard
proc specializeReset(p: BProc, a: TLoc) =

View File

@@ -35,9 +35,7 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
if n.kind == nkEmpty:
result = false
elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc:
if n[0].kind == nkSym and sfConstructor in n[0].sym.flags:
result = true
elif isInvalidReturnType(conf, n[0].typ, true):
if isInvalidReturnType(conf, n[0].typ, true):
# var v = f()
# is transformed into: var v; f(addr v)
# where 'f' **does not** initialize the result!
@@ -50,7 +48,6 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
result = true
proc inExceptBlockLen(p: BProc): int =
result = 0
for x in p.nestedTryStmts:
if x.inExcept: result.inc
@@ -72,6 +69,7 @@ template startBlock(p: BProc, start: FormatStr = "{$n",
proc endBlock(p: BProc)
proc genVarTuple(p: BProc, n: PNode) =
var tup, field: TLoc
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
# if we have a something that's been captured, use the lowering instead:
@@ -83,7 +81,7 @@ proc genVarTuple(p: BProc, n: PNode) =
# check only the first son
var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym)
let hcrCond = if forHcr: getTempName(p.module) else: ""
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] = @[]
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]]
# determine if the tuple is constructed at top-level scope or inside of a block (if/while/block)
let isGlobalInBlock = forHcr and p.blocks.len > 2
# do not close and reopen blocks if this is a 'global' but inside of a block (if/while/block)
@@ -95,7 +93,7 @@ proc genVarTuple(p: BProc, n: PNode) =
startBlock(p)
genLineDir(p, n)
var tup = initLocExpr(p, n[^1])
initLocExpr(p, n[^1], tup)
var t = tup.t.skipTypes(abstractInst)
for i in 0..<n.len-2:
let vn = n[i]
@@ -108,7 +106,7 @@ proc genVarTuple(p: BProc, n: PNode) =
else:
assignLocalVar(p, vn)
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
var field = initLoc(locExpr, vn, tup.storage)
initLoc(field, locExpr, vn, tup.storage)
if t.kind == tyTuple:
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
else:
@@ -169,7 +167,7 @@ proc endBlock(p: BProc, blockEnd: Rope) =
proc endBlock(p: BProc) =
let topBlock = p.blocks.len - 1
let frameLen = p.blocks[topBlock].frameLen
var blockEnd: Rope = ""
var blockEnd: Rope
if frameLen > 0:
blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope])
if p.blocks[topBlock].label.len != 0:
@@ -244,7 +242,8 @@ proc genGotoState(p: BProc, n: PNode) =
# switch (x.state) {
# case 0: goto STATE0;
# ...
var a: TLoc = initLocExpr(p, n[0])
var a: TLoc
initLocExpr(p, n[0], a)
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
p.flags.incl beforeRetNeeded
lineF(p, cpsStmts, "case -1:$n", [])
@@ -263,13 +262,13 @@ proc genGotoState(p: BProc, n: PNode) =
proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
d = initLoc(locExpr, n, OnUnknown)
initLoc(d, locExpr, n, OnUnknown)
if n[0].kind == nkClosure:
a = initLocExpr(p, n[0][1])
initLocExpr(p, n[0][1], a)
d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
else:
a = initLocExpr(p, n[0])
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)]
@@ -289,28 +288,11 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
#echo "New code produced for ", v.name.s, " ", p.config $ value.info
genBracedInit(p, value, isConst = false, v.typ, result)
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) =
var params = newRopeAppender()
var argsCounter = 0
let typ = skipTypes(value[0].typ, abstractInst)
assert(typ.kind == tyProc)
for i in 1..<value.len:
assert(typ.len == typ.n.len)
genOtherArg(p, value, i, typ, params, argsCounter)
if params.len == 0:
decl = runtimeFormat("$#;\n", [decl])
else:
decl = runtimeFormat("$#($#);\n", [decl, params])
proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
if sfGoto in v.flags:
# translate 'var state {.goto.} = X' into 'goto LX':
genGotoVar(p, value)
return
let imm = isAssignedImmediately(p.config, value)
let isCppCtorCall = p.module.compileToCpp and imm and
value.kind in nkCallKinds and value[0].kind == nkSym and
v.typ.kind != tyPtr and sfConstructor in value[0].sym.flags
var targetProc = p
var valueAsRope = ""
potentialValueInit(p, v, value, valueAsRope)
@@ -322,11 +304,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
if sfPure in v.flags:
# v.owner.kind != skModule:
targetProc = p.module.preInitProc
if isCppCtorCall and not containsHiddenPointer(v.typ):
callGlobalVarCppCtor(targetProc, v, vn, value)
else:
assignGlobalVar(targetProc, vn, valueAsRope)
assignGlobalVar(targetProc, vn, valueAsRope)
# XXX: be careful here.
# Global variables should not be zeromem-ed within loops
# (see bug #20).
@@ -335,12 +313,13 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
# 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):
loc = initLocExprSingleUse(p.module.preInitProc, vn)
initLocExprSingleUse(p.module.preInitProc, vn, loc)
genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, constructObj)
# Alternative construction using default constructor (which may zeromem):
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
@@ -348,21 +327,31 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
genVarPrototype(p.module.g.generatedHeader, vn)
registerTraverseProc(p, v)
else:
let imm = isAssignedImmediately(p.config, value)
if imm and p.module.compileToCpp and p.splitDecls == 0 and
not containsHiddenPointer(v.typ) and
nimErrorFlagAccessed notin p.flags:
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)
var decl = localVarDecl(p, vn)
let decl = localVarDecl(p, vn)
var tmp: TLoc
if isCppCtorCall:
genCppVarForCtor(p, v, vn, value, decl)
line(p, cpsStmts, decl)
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)
assert(typ.kind == tyProc)
for i in 1..<value.len:
assert(typ.len == typ.n.len)
genOtherArg(p, value, i, typ, params, argsCounter)
if params.len == 0:
lineF(p, cpsStmts, "$#;$n", [decl])
else:
lineF(p, cpsStmts, "$#($#);$n", [decl, params])
else:
tmp = initLocExprSingleUse(p, value)
lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc])
initLocExprSingleUse(p, value, tmp)
lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc])
return
assignLocalVar(p, vn)
initLocalVar(p, v, imm)
@@ -389,8 +378,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
startBlock(targetProc)
if value.kind != nkEmpty and valueAsRope.len == 0:
genLineDir(targetProc, vn)
if not isCppCtorCall:
loadInto(targetProc, vn, value, v.loc)
loadInto(targetProc, vn, value, v.loc)
if forHcr:
endBlock(targetProc)
@@ -407,7 +395,8 @@ proc genSingleVar(p: BProc, a: PNode) =
proc genClosureVar(p: BProc, a: PNode) =
var immediateAsgn = a[2].kind != nkEmpty
var v: TLoc = initLocExpr(p, a[0])
var v: TLoc
initLocExpr(p, a[0], v)
genLineDir(p, a)
if immediateAsgn:
loadInto(p, a[0], a[2], v)
@@ -442,7 +431,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
a: TLoc
lelse: TLabel
if not isEmptyType(n.typ) and d.k == locNone:
d = getTemp(p, n.typ)
getTemp(p, n.typ, d)
genLineDir(p, n)
let lend = getLabel(p)
for it in n.sons:
@@ -450,7 +439,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
if it.len == 2:
startBlock(p)
a = initLocExprSingleUse(p, it[0])
initLocExprSingleUse(p, it[0], a)
lelse = getLabel(p)
inc(p.labels)
lineF(p, cpsStmts, "if (!$1) goto $2;$n",
@@ -518,7 +507,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
# wrapped inside stmt lists by inject destructors won't be recognised
let n = n.flattenStmts()
var casePos = -1
var arraySize: int = 0
var arraySize: int
for i in 0..<n.len:
let it = n[i]
if it.kind == nkCaseStmt:
@@ -552,7 +541,8 @@ proc genComputedGoto(p: BProc; n: PNode) =
genStmts(p, n[j])
let caseStmt = n[casePos]
var a: TLoc = initLocExpr(p, caseStmt[0])
var a: TLoc
initLocExpr(p, caseStmt[0], a)
# first goto:
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
@@ -590,7 +580,8 @@ proc genComputedGoto(p: BProc; n: PNode) =
else:
genStmts(p, it)
var a: TLoc = initLocExpr(p, caseStmt[0])
var a: TLoc
initLocExpr(p, caseStmt[0], a)
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
endBlock(p)
@@ -618,11 +609,11 @@ proc genWhileStmt(p: BProc, t: PNode) =
else:
p.breakIdx = startBlock(p, "while (1) {$n")
p.blocks[p.breakIdx].isLoop = true
a = initLocExpr(p, t[0])
initLocExpr(p, t[0], a)
if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
lineF(p, cpsStmts, "if (!$1) goto ", [rdLoc(a)])
assignLabel(p.blocks[p.breakIdx], p.s(cpsStmts))
appcg(p, cpsStmts, ";$n", [])
lineF(p, cpsStmts, ";$n", [])
genStmts(p, loopBody)
if optProfiler in p.options:
@@ -637,7 +628,7 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
# bug #4505: allocate the temp in the outer scope
# so that it can escape the generated {}:
if d.k == locNone:
d = getTemp(p, n.typ)
getTemp(p, n.typ, d)
d.flags.incl(lfEnforceDeref)
preserveBreakIdx:
p.breakIdx = startBlock(p)
@@ -657,13 +648,14 @@ proc genParForStmt(p: BProc, t: PNode) =
preserveBreakIdx:
let forLoopVar = t[0].sym
var rangeA, rangeB: TLoc
assignLocalVar(p, t[0])
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t[1]
assert(call.len == 4 or call.len == 5)
var rangeA = initLocExpr(p, call[1])
var rangeB = initLocExpr(p, call[2])
assert(call.len in {4, 5})
initLocExpr(p, call[1], rangeA)
initLocExpr(p, call[2], rangeB)
# $n at the beginning because of #9710
if call.len == 4: # procName(a, b, annotation)
@@ -680,7 +672,8 @@ proc genParForStmt(p: BProc, t: PNode) =
rangeA.rdLoc, rangeB.rdLoc,
call[3].getStr.rope])
else: # `||`(a, b, step, annotation)
var step: TLoc = initLocExpr(p, call[3])
var step: TLoc
initLocExpr(p, call[3], step)
lineF(p, cpsStmts, "$n#pragma omp $5$n" &
"for ($1 = $2; $1 <= $3; $1 += $4)",
[forLoopVar.loc.rdLoc,
@@ -750,7 +743,8 @@ proc raiseInstr(p: BProc; result: var Rope) =
proc genRaiseStmt(p: BProc, t: PNode) =
if t[0].kind != nkEmpty:
var a: TLoc = initLocExprSingleUse(p, t[0])
var a: TLoc
initLocExprSingleUse(p, t[0], a)
finallyActions(p)
var e = rdLoc(a)
discard getTypeDesc(p.module, t[0].typ)
@@ -772,7 +766,11 @@ proc genRaiseStmt(p: BProc, t: PNode) =
else:
finallyActions(p)
genLineDir(p, t)
linefmt(p, cpsStmts, "#reraiseException();$n", [])
# reraise the last exception:
if p.config.exc == excCpp:
line(p, cpsStmts, "throw;\n")
else:
linefmt(p, cpsStmts, "#reraiseException();$n", [])
raiseInstr(p, p.s(cpsStmts))
template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
@@ -780,12 +778,12 @@ template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
var x, y: TLoc
for i in 0..<b.len - 1:
if b[i].kind == nkRange:
x = initLocExpr(p, b[i][0])
y = initLocExpr(p, b[i][1])
initLocExpr(p, b[i][0], x)
initLocExpr(p, b[i][1], y)
lineCg(p, cpsStmts, rangeFormat,
[rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
else:
x = initLocExpr(p, b[i])
initLocExpr(p, b[i], x)
lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
@@ -827,7 +825,8 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: FormatStr) =
var a: TLoc = initLocExpr(p, t[0])
var a: TLoc
initLocExpr(p, t[0], a)
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, t.len-1, a)
fixLabel(p, lend)
@@ -837,8 +836,8 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
var x: TLoc
for i in 0..<b.len - 1:
assert(b[i].kind != nkRange)
x = initLocExpr(p, b[i])
var j: int = 0
initLocExpr(p, b[i], x)
var j: int
case b[i].kind
of nkStrLit..nkTripleStrLit:
j = int(hashString(p.config, b[i].strVal) and high(branches))
@@ -861,7 +860,8 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
var bitMask = math.nextPowerOfTwo(strings) - 1
var branches: seq[Rope]
newSeq(branches, bitMask + 1)
var a: TLoc = initLocExpr(p, t[0]) # first pass: generate ifs+goto:
var a: TLoc
initLocExpr(p, t[0], a) # fist pass: generate ifs+goto:
var labId = p.labels
for i in 1..<t.len:
inc(p.labels)
@@ -897,7 +897,6 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
proc branchHasTooBigRange(b: PNode): bool =
result = false
for it in b:
# last son is block
if (it.kind == nkRange) and
@@ -905,7 +904,6 @@ proc branchHasTooBigRange(b: PNode): bool =
return true
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
result = 0
for i in 1..<n.len:
var branch = n[i]
var stmtBlock = lastSon(branch)
@@ -941,7 +939,8 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
var splitPoint = ifSwitchSplitPoint(p, n)
# generate if part (might be empty):
var a: TLoc = initLocExpr(p, n[0])
var a: TLoc
initLocExpr(p, n[0], a)
var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
eqFormat = "if ($1 == $2) goto $3;$n",
@@ -971,7 +970,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
proc genCase(p: BProc, t: PNode, d: var TLoc) =
genLineDir(p, t)
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
getTemp(p, t.typ, d)
case skipTypes(t[0].typ, abstractVarRange).kind
of tyString:
genStringCase(p, t, tyString, d)
@@ -997,7 +996,7 @@ proc genRestoreFrameAfterException(p: BProc) =
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
#[ code to generate:
std::exception_ptr error;
std::exception_ptr error = nullptr;
try {
body;
} catch (Exception e) {
@@ -1022,13 +1021,13 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
p.module.includeHeader("<exception>")
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
getTemp(p, t.typ, d)
genLineDir(p, t)
inc(p.labels, 2)
let etmp = p.labels
lineCg(p, cpsStmts, "std::exception_ptr T$1_;$n", [etmp])
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))
@@ -1062,6 +1061,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
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)
@@ -1124,7 +1124,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if t[i].len == 1:
# general except section:
startBlock(p, "catch (...) {$n", [])
startBlock(p, "catch (...) {", [])
genExceptBranchBody(t[i][0])
endBlock(p)
catchAllPresent = true
@@ -1150,7 +1150,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
# general finally block:
if t.len > 0 and t[^1].kind == nkFinally:
if not catchAllPresent:
startBlock(p, "catch (...) {$n", [])
startBlock(p, "catch (...) {", [])
genRestoreFrameAfterException(p)
linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp])
endBlock(p)
@@ -1187,7 +1187,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
expr(p, body, d)
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
getTemp(p, t.typ, d)
genLineDir(p, t)
cgsym(p.module, "popCurrentExceptionEx")
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
@@ -1265,7 +1265,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
p.flags.incl nimErrorFlagAccessed
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
getTemp(p, t.typ, d)
expr(p, t[0], d)
@@ -1300,8 +1300,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
if optTinyRtti in p.config.globalOptions:
let checkFor = $getObjDepth(t[i][j].typ)
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$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])
@@ -1372,7 +1371,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
# propagateCurrentException();
#
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
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:
@@ -1381,7 +1380,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
p.flags.incl noSafePoints
genLineDir(p, t)
cgsym(p.module, "Exception")
var safePoint: Rope = ""
var safePoint: Rope
if not quirkyExceptions:
safePoint = getTempName(p.module)
linefmt(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
@@ -1446,8 +1445,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
if optTinyRtti in p.config.globalOptions:
let checkFor = $getObjDepth(t[i][j].typ)
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$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])
@@ -1485,7 +1483,8 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
of nkSym:
var sym = it.sym
if sym.kind in {skProc, skFunc, skIterator, skMethod}:
var a: TLoc = initLocExpr(p, it)
var a: TLoc
initLocExpr(p, it, a)
res.add($rdLoc(a))
elif sym.kind == skType:
res.add($getTypeDesc(p.module, sym.typ))
@@ -1497,7 +1496,8 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
res.add($getTypeDesc(p.module, it.typ))
else:
discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs))
var a: TLoc = initLocExpr(p, it)
var a: TLoc
initLocExpr(p, it, a)
res.add($a.rdLoc)
if isAsmStmt and hasGnuAsm in CC[p.config.cCompiler].props:
@@ -1599,10 +1599,11 @@ when false:
expr(p, call, d)
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
var a, tmp: TLoc
var dotExpr = e[0]
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0]
var a = initLocExpr(p, e[0])
var tmp: TLoc = getTemp(p, a.t)
initLocExpr(p, e[0], a)
getTemp(p, a.t, tmp)
expr(p, e[1], tmp)
if p.inUncheckedAssignSection == 0:
let field = dotExpr[1].sym
@@ -1620,8 +1621,9 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
else:
let le = e[0]
let ri = e[1]
var a: TLoc = initLoc(locNone, le, OnUnknown)
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar)
var a: TLoc
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar)
initLoc(a, locNone, le, OnUnknown)
a.flags.incl(lfEnforceDeref)
a.flags.incl(lfPrepareForMutation)
genLineDir(p, le) # it can be a nkBracketExpr, which may raise
@@ -1633,7 +1635,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
loadInto(p, le, ri, a)
proc genStmts(p: BProc, t: PNode) =
var a: TLoc = default(TLoc)
var a: TLoc
let isPush = p.config.hasHint(hintExtendedContext)
if isPush: pushInfoContext(p.config, t.info)

View File

@@ -21,7 +21,7 @@ const
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType)
proc genCaseRange(p: BProc, branch: PNode)
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
typ: PType) =
@@ -74,7 +74,8 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
genTraverseProc(c, accessor, lastSon(typ))
of tyArray:
let arraySize = lengthOrd(c.p.config, typ[0])
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var i: TLoc
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i)
var oldCode = p.s(cpsStmts)
freeze oldCode
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
@@ -118,10 +119,12 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
var p = c.p
assert typ.kind == tySequence
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
var i: TLoc
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i)
var oldCode = p.s(cpsStmts)
freeze oldCode
var a: TLoc = TLoc(r: accessor)
var a: TLoc
a.r = accessor
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.r, lenExpr(c.p, a)])

File diff suppressed because it is too large Load Diff

View File

@@ -19,16 +19,13 @@ when defined(nimPreviewSlimSystem):
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
case n.kind
of nkStmtList:
result = nil
for i in 0..<n.len:
result = getPragmaStmt(n[i], w)
if result != nil: break
of nkPragma:
result = nil
for i in 0..<n.len:
if whichPragma(n[i]) == w: return n[i]
else:
result = nil
else: discard
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
result = getPragmaStmt(n, w) != nil
@@ -124,11 +121,8 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
var pt = skipTypes(s.typ, typedescInst)
assert skResult != s.kind
#note precedence: params override types
if optByRef in s.options: return true
elif sfByCopy in s.flags: return false
elif tfByRef in pt.flags: return true
if tfByRef in pt.flags: return true
elif tfByCopy in pt.flags: return false
case pt.kind
of tyObject:

View File

@@ -17,8 +17,6 @@ import
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
injectdestructors, astmsgs, modulepaths, backendpragmas
import nir/ast2ir
import pipelineutils
when defined(nimPreviewSlimSystem):
@@ -63,10 +61,12 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
var ms = getModule(s)
result = m.g.modules[ms.position]
proc initLoc(k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}): TLoc =
result = TLoc(k: k, storage: s, lode: lode,
r: "", flags: flags
)
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) =
result.k = k
result.storage = s
result.lode = lode
result.r = ""
result.flags = {}
proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.inline.} =
# fills the loc if it is not already initialized
@@ -216,9 +216,13 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
elif frmt[i] == '#' and frmt[i+1] == '#':
inc(i, 2)
strLit.add("#")
else:
strLit.add(frmt[i])
inc(i)
var start = i
while i < frmt.len:
if frmt[i] != '$' and frmt[i] != '#': inc(i)
else: break
if i - 1 >= start:
strLit.add(substr(frmt, start, i - 1))
flushStrLit()
result.add newCall(ident"rope", resVar)
@@ -269,16 +273,7 @@ proc safeLineNm(info: TLineInfo): int =
proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
assert line >= 0
if optLineDir in conf.options and line > 0:
r.addf("\n#line $2 $1\n",
[rope(makeSingleLineCString(filename)), rope(line)])
proc genCLineDir(r: var Rope, filename: string, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
assert line >= 0
if optLineDir in p.config.options and line > 0:
if lastFileIndex == info.fileIndex:
r.addf("\n#line $1\n", [rope(line)])
else:
r.addf("\n#line $2 $1\n",
r.addf("$N#line $2 $1$N",
[rope(makeSingleLineCString(filename)), rope(line)])
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
@@ -291,33 +286,17 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
p.lastLineInfo.line = info.line
p.lastLineInfo.fileIndex = info.fileIndex
result = true
else:
result = false
proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) =
if optLineDir in conf.options:
let lastFileIndex = p.lastLineInfo.fileIndex
if freshLineInfo(p, info):
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, p, info, lastFileIndex)
proc genLineDir(p: BProc, t: PNode) =
if p == p.module.preInitProc: return
let line = t.info.safeLineNm
if optEmbedOrigSrc in p.config.globalOptions:
p.s(cpsStmts).add("//" & sourceLine(p.config, t.info) & "\L")
let lastFileIndex = p.lastLineInfo.fileIndex
let freshLine = freshLineInfo(p, t.info)
if freshLine:
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p, t.info, lastFileIndex)
genCLineDir(p.s(cpsStmts), t.info, p.config)
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
if freshLine:
if lastFileIndex == t.info.fileIndex:
linefmt(p, cpsStmts, "nimln_($1);",
[line])
else:
linefmt(p, cpsStmts, "nimlf_($1, $2);",
if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
[line, quotedFilename(p.config, t.info)])
proc accessThreadLocalVar(p: BProc, s: PSym)
@@ -377,19 +356,19 @@ template mapTypeChooser(n: PNode): TSymKind =
template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode)
proc addAddrLoc(conf: ConfigRef; a: TLoc; result: var Rope) =
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
result.add "(&" & a.r & ")"
else:
result.add a.r
proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
result = "(&" & a.r & ")"
else:
result = a.r
proc byRefLoc(p: BProc; a: TLoc): Rope =
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a) == skParam) != ctArray and not
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not
p.module.compileToCpp:
result = "(&" & a.r & ")"
else:
@@ -435,13 +414,13 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
of frEmbedded:
if optTinyRtti in p.config.globalOptions:
var tmp: TLoc = default(TLoc)
var tmp: TLoc
if mode == constructRefObj:
let objType = t.skipTypes(abstractInst+{tyRef})
rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp)
linefmt(p, cpsStmts,
"#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n",
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, descKindFromSymKind mapTypeChooser(a))])
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, mapTypeChooser(a))])
else:
rawConstExpr(p, newNodeIT(nkType, a.lode.info, t), tmp)
genAssignment(p, a, tmp, {})
@@ -483,7 +462,8 @@ proc resetLoc(p: BProc, loc: var TLoc) =
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
if containsGcRef:
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.lode, OnStack)
nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc)
else:
@@ -500,40 +480,36 @@ proc resetLoc(p: BProc, loc: var TLoc) =
else:
# array passed as argument decayed into pointer, bug #7332
# so we use getTypeDesc here rather than rdLoc(loc)
let tyDesc = getTypeDesc(p.module, loc.t, descKindFromSymKind mapTypeChooser(loc))
if p.module.compileToCpp and isOrHasImportedCppType(typ):
if lfIndirect in loc.flags:
#C++ cant be just zeroed. We need to call the ctors
var tmp = getTemp(p, loc.t)
linefmt(p, cpsStmts,"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
[addrLoc(p.config, loc), addrLoc(p.config, tmp), tyDesc])
else:
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc), tyDesc])
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc),
getTypeDesc(p.module, loc.t, mapTypeChooser(loc))])
# XXX: We can be extra clever here and call memset only
# on the bytes following the m_type field?
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
proc isOrHasImportedCppType(typ: PType): bool =
searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType)
proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
let typ = loc.t
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
if containsGarbageCollectedRef(loc.t):
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.lode, OnStack)
nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc)
else:
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
getTypeDesc(p.module, typ, descKindFromSymKind mapTypeChooser(loc))])
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
else:
if not isTemp or containsGarbageCollectedRef(loc.t):
# don't use nimZeroMem for temporary values for performance if we can
# avoid it:
if not isOrHasImportedCppType(typ):
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, descKindFromSymKind mapTypeChooser(loc))])
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))])
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
@@ -548,14 +524,17 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
if not immediateAsgn:
constructLoc(p, v.loc)
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels)
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
storage: OnStack, flags: {})
result.r = "T" & rope(p.labels) & "_"
if p.module.compileToCpp and isOrHasImportedCppType(t):
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, dkVar), result.r])
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, skVar), result.r])
else:
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r])
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
result.flags = {}
constructLoc(p, result, not needsInit)
when false:
# XXX Introduce a compiler switch in order to detect these easily.
@@ -566,21 +545,25 @@ proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo
writeStackTrace()
proc getTempCpp(p: BProc, t: PType, value: Rope): TLoc =
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
inc(p.labels)
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
storage: OnStack, flags: {})
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value])
result.r = "T" & rope(p.labels) & "_"
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
result.flags = {}
proc getIntTemp(p: BProc): TLoc =
proc getIntTemp(p: BProc, result: var TLoc) =
inc(p.labels)
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp,
storage: OnStack, lode: lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt),
flags: {})
result.r = "T" & rope(p.labels) & "_"
linefmt(p, cpsLocals, "NI $1;$n", [result.r])
result.k = locTemp
result.storage = OnStack
result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt)
result.flags = {}
proc localVarDecl(p: BProc; n: PNode): Rope =
result = ""
let s = n.sym
if s.loc.k == locNone:
fillLocalName(p, s)
@@ -589,10 +572,10 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
genCLineDir(result, p, n.info, p.config)
genCLineDir(result, n.info, p.config)
result.add getTypeDesc(p.module, s.typ, dkVar)
if sfCodegenDecl notin s.flags:
result.add getTypeDesc(p.module, s.typ, skVar)
if s.constraint.isNil:
if sfRegister in s.flags: result.add(" register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# decl.add(" GC_GUARD")
@@ -607,7 +590,7 @@ proc assignLocalVar(p: BProc, n: PNode) =
#assert(s.loc.k == locNone) # not yet assigned
# this need not be fulfilled for inline procs; they are regenerated
# for each module that uses them!
let nl = if optLineDir in p.config.options: "" else: "\n"
let nl = if optLineDir in p.config.options: "" else: "\L"
let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl
line(p, cpsLocals, decl)
@@ -621,40 +604,6 @@ proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool =
# and s.owner.kind == skModule # owner isn't always a module (global pragma on local var)
# and s.loc.k == locGlobalVar # loc isn't always initialized when this proc is used
proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) =
let s = n.sym
if sfCodegenDecl notin s.flags:
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
if p.hcrOn: decl.add("static ")
elif sfImportc in s.flags: decl.add("extern ")
elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ")
else: decl.add("N_LIB_PRIVATE ")
if s.kind == skLet and value != "": decl.add("NIM_CONST ")
decl.add(td)
if p.hcrOn: decl.add("*")
if sfRegister in s.flags: decl.add(" register")
if sfVolatile in s.flags: decl.add(" volatile")
if sfNoalias in s.flags: decl.add(" NIM_NOALIAS")
else:
if value != "":
decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value])
else:
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope)
proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) =
let s = vn.sym
fillBackendName(p.module, s)
fillLoc(s.loc, locGlobalVar, vn, OnHeap)
var decl: Rope = ""
let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
genGlobalVarDecl(p, vn, td, "", decl)
decl.add " " & $s.loc.r
genCppVarForCtor(p, v, vn, value, decl)
p.module.s[cfsVars].add decl
proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
let s = n.sym
if s.loc.k == locNone:
@@ -680,30 +629,29 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
internalError(p.config, n.info, ".threadvar variables cannot have a value")
else:
var decl: Rope = ""
let td = getTypeDesc(p.module, s.loc.t, dkVar)
genGlobalVarDecl(p, n, td, value, decl)
var td = getTypeDesc(p.module, s.loc.t, skVar)
if s.constraint.isNil:
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
if p.hcrOn: decl.add("static ")
elif sfImportc in s.flags: decl.add("extern ")
elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ")
else: decl.add("N_LIB_PRIVATE ")
if s.kind == skLet and value != "": decl.add("NIM_CONST ")
decl.add(td)
if p.hcrOn: decl.add("*")
if sfRegister in s.flags: decl.add(" register")
if sfVolatile in s.flags: decl.add(" volatile")
if sfNoalias in s.flags: decl.add(" NIM_NOALIAS")
if value != "":
if p.module.compileToCpp and value.startsWith "{{}":
# TODO: taking this branch, re"\{\{\}(,\s\{\})*\}" might be emitted, resulting in
# either warnings (GCC 12.2+) or errors (Clang 15, MSVC 19.3+) of C++11+ compilers **when
# explicit constructors are around** due to overload resolution rules in place [^0][^1][^2]
# *Workaround* here: have C++'s static initialization mechanism do the default init work,
# for us lacking a deeper knowledge of an imported object's constructors' ex-/implicitness
# (so far) *and yet* trying to achieve default initialization.
# Still, generating {}s in genConstObjConstr() just to omit them here is faaaar from ideal;
# need to figure out a better way, possibly by keeping around more data about the
# imported objects' contructors?
#
# [^0]: https://en.cppreference.com/w/cpp/language/aggregate_initialization
# [^1]: https://cplusplus.github.io/CWG/issues/1518.html
# [^2]: https://eel.is/c++draft/over.match.ctor
decl.addf(" $1;$n", [s.loc.r])
else:
decl.addf(" $1 = $2;$n", [s.loc.r, value])
decl.addf(" $1 = $2;$n", [s.loc.r, value])
else:
decl.addf(" $1;$n", [s.loc.r])
else:
if value != "":
decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value])
else:
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
p.module.s[cfsVars].add(decl)
if p.withinLoop > 0 and value == "":
# fixes tests/run/tzeroarray:
@@ -724,7 +672,7 @@ proc getLabel(p: BProc): TLabel =
result = "LA" & rope(p.labels) & "_"
proc fixLabel(p: BProc, labl: TLabel) =
p.s(cpsStmts).add("$1: ;$n" % [labl])
lineF(p, cpsStmts, "$1: ;$n", [labl])
proc genVarPrototype(m: BModule, n: PNode)
proc requestConstImpl(p: BProc, sym: PSym)
@@ -737,12 +685,12 @@ proc genLiteral(p: BProc, n: PNode; result: var Rope)
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
proc raiseExit(p: BProc)
proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
result = initLoc(locNone, e, OnUnknown, flags)
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e, OnUnknown)
expr(p, e, result)
proc initLocExprSingleUse(p: BProc, e: PNode): TLoc =
result = initLoc(locNone, e, OnUnknown)
proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e, OnUnknown)
if e.kind in nkCallKinds and (e[0].kind != nkSym or e[0].sym.magic == mNone):
# We cannot check for tfNoSideEffect here because of mutable parameters.
discard "bug #8202; enforce evaluation order for nested calls for C++ too"
@@ -766,12 +714,8 @@ $1define nimfr_(proc, file) \
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename;NI len;VarSlot s[slots];} FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; #nimFrame((TFrame*)&FR_);
$1define nimln_(n) \
FR_.line = n;
$1define nimlf_(n, file) \
$1define nimln_(n, file) \
FR_.line = n; FR_.filename = file;
"""
if p.module.s[cfsFrameDefines].len == 0:
appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"])
@@ -833,10 +777,11 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
var p = newProc(nil, m)
p.options.excl optStackTrace
p.flags.incl nimErrorFlagDisabled
var dest: TLoc = initLoc(locTemp, lib.path, OnStack)
var dest: TLoc
initLoc(dest, locTemp, lib.path, OnStack)
dest.r = getTempName(m)
appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
[getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)])
[getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)])
expr(p, lib.path, dest)
m.s[cfsVars].add(p.s(cpsLocals))
@@ -868,14 +813,15 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
inc(m.labels, 2)
if isCall:
let n = lib.path
var a: TLoc = initLocExpr(m.initProc, n[0])
var a: TLoc
initLocExpr(m.initProc, n[0], a)
var params = rdLoc(a) & "("
for i in 1..<n.len-1:
a = initLocExpr(m.initProc, n[i])
initLocExpr(m.initProc, n[i], a)
params.add(rdLoc(a))
params.add(", ")
let load = "\t$1 = ($2) ($3$4));$n" %
[tmp, getTypeDesc(m, sym.typ, dkVar), params, makeCString($extname)]
[tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)]
var last = lastSon(n)
if last.kind == nkHiddenStdConv: last = last[1]
internalAssert(m.config, last.kind == nkStrLit)
@@ -889,8 +835,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
else:
appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)])
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)])
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
@@ -902,9 +848,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
inc(m.labels, 2)
appcg(m, m.s[cfsDynLibInit],
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)])
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
m.s[cfsVars].addf("$2* $1;$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)])
[sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.loc.r = mangleDynLibProc(sym)
@@ -935,9 +881,7 @@ proc cgsymValue(m: BModule, name: string): Rope =
result.addActualSuffixForHCR(m.module, sym)
proc generateHeaders(m: BModule) =
var nimbase = m.config.nimbasePattern
if nimbase == "": nimbase = "nimbase.h"
m.s[cfsHeaders].addf("\L#include \"$1\"\L", [nimbase])
m.s[cfsHeaders].add("\L#include \"nimbase.h\"\L")
for it in m.headerFiles:
if it[0] == '#':
@@ -986,19 +930,11 @@ proc closureSetup(p: BProc, prc: PSym) =
linefmt(p, cpsStmts, "$1 = ($2) ClE_0;$n",
[rdLoc(env.loc), getTypeDesc(p.module, env.typ)])
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
nkMacroDef, nkMixinStmt, nkBindStmt, nkFormalParams} +
declarativeDefs
proc containsResult(n: PNode): bool =
result = false
case n.kind
of succ(nkEmpty)..pred(nkSym), succ(nkSym)..nkNilLit, harmless:
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkFormalParams:
discard
of nkReturnStmt:
for i in 0..<n.len:
if containsResult(n[i]): return true
result = n.len > 0 and n[0].kind == nkEmpty
of nkSym:
if n.sym.kind == skResult:
result = true
@@ -1006,8 +942,11 @@ proc containsResult(n: PNode): bool =
for i in 0..<n.len:
if containsResult(n[i]): return true
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
nkMacroDef, nkMixinStmt, nkBindStmt, nkFormalParams} +
declarativeDefs
proc easyResultAsgn(n: PNode): PNode =
result = nil
case n.kind
of nkStmtList, nkStmtListExpr:
var i = 0
@@ -1132,14 +1071,14 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
proc getProcTypeCast(m: BModule, prc: PSym): Rope =
result = getTypeDesc(m, prc.loc.t)
if prc.typ.callConv == ccClosure:
var rettype, params: Rope = ""
var rettype, params: Rope
var check = initIntSet()
genProcParams(m, prc.typ, rettype, params, check)
result = "$1(*)$2" % [rettype, params]
proc genProcBody(p: BProc; procBody: PNode) =
genStmts(p, procBody) # modifies p.locals, p.init, etc.
if {nimErrorFlagAccessed, nimErrorFlagDeclared, nimErrorFlagDisabled} * p.flags == {nimErrorFlagAccessed}:
if {nimErrorFlagAccessed, nimErrorFlagDeclared} * p.flags == {nimErrorFlagAccessed}:
p.flags.incl nimErrorFlagDeclared
p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", []))
p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", []))
@@ -1147,14 +1086,10 @@ proc genProcBody(p: BProc; procBody: PNode) =
proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
sfNoReturn in s.flags and m.config.exc != excGoto
proc genProcAux*(m: BModule, prc: PSym) =
proc genProcAux(m: BModule, prc: PSym) =
var p = newProc(prc, m)
var header = newRopeAppender()
let isCppMember = m.config.backend == backendCpp and sfCppMember * prc.flags != {}
if isCppMember:
genMemberProcHeader(m, prc, header)
else:
genProcHeader(m, prc, header)
genProcHeader(m, prc, header)
var returnStmt: Rope = ""
assert(prc.ast != nil)
@@ -1162,39 +1097,24 @@ proc genProcAux*(m: BModule, prc: PSym) =
if sfInjectDestructors in prc.flags:
procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody)
let tmpInfo = prc.info
discard freshLineInfo(p, prc.info)
if sfPure notin prc.flags and prc.typ[0] != nil:
if resultPos >= prc.ast.len:
internalError(m.config, prc.info, "proc has no result symbol")
let resNode = prc.ast[resultPos]
let res = resNode.sym # get result symbol
if not isInvalidReturnType(m.config, prc.typ) and sfConstructor notin prc.flags:
if not isInvalidReturnType(m.config, prc.typ):
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
var decl = localVarDecl(p, resNode)
var a: TLoc = initLocExprSingleUse(p, val)
var a: TLoc
initLocExprSingleUse(p, val, a)
linefmt(p, cpsStmts, "$1 = $2;$n", [decl, rdLoc(a)])
else:
# declare the result symbol:
assignLocalVar(p, resNode)
assert(res.loc.r != "")
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
allPathsAsgnResult(procBody) == InitSkippable:
# In an ideal world the codegen could rely on injectdestructors doing its job properly
# and then the analysis step would not be required.
discard "result init optimized out"
else:
initLocalVar(p, res, immediateAsgn=false)
initLocalVar(p, res, immediateAsgn=false)
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
elif sfConstructor in prc.flags:
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
let ty = resNode.sym.typ[0] #generate nim's ctor
for i in 1..<resNode.sym.ast.len:
let field = resNode.sym.ast[i]
genFieldObjConstr(p, ty, useTemp = false, isRef = false,
field[0], field[1], check = nil, resNode.sym.loc, "(*this)", tmpInfo)
else:
fillResult(p.config, resNode, prc.typ)
assignParam(p, res, prc.typ[0])
@@ -1219,15 +1139,13 @@ proc genProcAux*(m: BModule, prc: PSym) =
closureSetup(p, prc)
genProcBody(p, procBody)
prc.info = tmpInfo
var generatedProc: Rope = ""
var generatedProc: Rope
generatedProc.genCLineDir prc.info, m.config
if isNoReturn(p.module, prc):
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
header = "__declspec(noreturn) " & header
if sfPure in prc.flags:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
header = "__declspec(naked) " & header
generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N",
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
@@ -1272,7 +1190,7 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
if lfNoDecl in sym.loc.flags or sfCppMember * sym.flags != {}: return
if lfNoDecl in sym.loc.flags: return
if lfDynamicLib in sym.loc.flags:
if sym.itemId.module != m.module.position and
not containsOrIncl(m.declaredThings, sym.id):
@@ -1308,20 +1226,6 @@ proc genProcNoForward(m: BModule, prc: PSym) =
if lfNoDecl in prc.loc.flags:
fillProcLoc(m, prc.ast[namePos])
genProcPrototype(m, prc)
elif lfDynamicLib in prc.loc.flags:
var q = findPendingModule(m, prc)
fillProcLoc(q, prc.ast[namePos])
genProcPrototype(m, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
symInDynamicLib(q, prc)
# register the procedure even though it is in a different dynamic library and will not be
# reloadable (and has no _actual suffix) - other modules will need to be able to get it through
# the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded)
if isReloadable(q, prc):
q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n",
[prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)])
else:
symInDynamicLibPartial(m, prc)
elif prc.typ.callConv == ccInline:
# We add inline procs to the calling module to enable C based inlining.
# This also means that a check with ``q.declaredThings`` is wrong, we need
@@ -1340,6 +1244,20 @@ proc genProcNoForward(m: BModule, prc: PSym) =
# prc.loc.r = mangleName(m, prc)
genProcPrototype(m, prc)
genProcAux(m, prc)
elif lfDynamicLib in prc.loc.flags:
var q = findPendingModule(m, prc)
fillProcLoc(q, prc.ast[namePos])
genProcPrototype(m, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
symInDynamicLib(q, prc)
# register the procedure even though it is in a different dynamic library and will not be
# reloadable (and has no _actual suffix) - other modules will need to be able to get it through
# the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded)
if isReloadable(q, prc):
q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n",
[prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)])
else:
symInDynamicLibPartial(m, prc)
elif sfImportc notin prc.flags:
var q = findPendingModule(m, prc)
fillProcLoc(q, prc.ast[namePos])
@@ -1403,14 +1321,14 @@ proc genVarPrototype(m: BModule, n: PNode) =
if sym.owner.id != m.module.id:
# else we already have the symbol generated!
assert(sym.loc.r != "")
incl(m.declaredThings, sym.id)
if sfThread in sym.flags:
declareThreadVar(m, sym, true)
else:
incl(m.declaredThings, sym.id)
if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0:
m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)]
m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ")
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, dkVar))
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, skVar))
if m.hcrOn: m.s[cfsVars].add("*")
if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*")
if sfRegister in sym.flags: m.s[cfsVars].add(" register")
@@ -1419,7 +1337,7 @@ proc genVarPrototype(m: BModule, n: PNode) =
m.s[cfsVars].addf(" $1;$n", [sym.loc.r])
if m.hcrOn: m.initProc.procSec(cpsLocals).addf(
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(m, sym)])
getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(m, sym)])
proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
result.addf("#define NIM_INTBITS $1\L", [
@@ -1451,21 +1369,17 @@ proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope =
## Returns a mangled module name.
result = ""
result.add mangleModuleName(conf, filename).mangle
proc getSomeNameForModule(m: BModule): Rope =
## Returns a mangled module name.
assert m.module.kind == skModule
assert m.module.owner.kind == skPackage
result = ""
result.add mangleModuleName(m.g.config, m.filename).mangle
proc getSomeInitName(m: BModule, suffix: string): Rope =
if not m.hcrOn:
result = getSomeNameForModule(m)
else:
result = ""
result.add suffix
proc getInitName(m: BModule): Rope =
@@ -1484,10 +1398,10 @@ proc genMainProc(m: BModule) =
## this function is called in cgenWriteModules after all modules are closed,
## it means raising dependency on the symbols is too late as it will not propagate
## into other modules, only simple rope manipulations are allowed
var preMainCode: Rope = ""
var preMainCode: Rope
if m.hcrOn:
proc loadLib(handle: string, name: string): Rope =
result = ""
let prc = magicsys.getCompilerProc(m.g.graph, name)
assert prc != nil
let n = newStrNode(nkStrLit, prc.annex.path.strVal)
@@ -1499,23 +1413,20 @@ proc genMainProc(m: BModule) =
[handle, strLit])
preMainCode.add(loadLib("hcr_handle", "hcrGetProc"))
if m.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
else:
preMainCode.add("\tvoid* rtl_handle;\L")
preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom"))
preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr"))
preMainCode.add("\tinner = $1PreMain;\L" % [rope m.config.nimMainPrefix])
preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L")
preMainCode.add("\t(*inner)();\L")
preMainCode.add("\tvoid* rtl_handle;\L")
preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom"))
preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr"))
preMainCode.add("\tinner = PreMain;\L")
preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L")
preMainCode.add("\t(*inner)();\L")
else:
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
var posixCmdLine: Rope = ""
var posixCmdLine: Rope
if optNoMain notin m.config.globalOptions:
posixCmdLine.add "N_LIB_PRIVATE int cmdCount;\L"
posixCmdLine.add "N_LIB_PRIVATE char** cmdLine;\L"
posixCmdLine.add "N_LIB_PRIVATE char** gEnv;\L"
posixCmdLine.add "\tN_LIB_PRIVATE int cmdCount;\L"
posixCmdLine.add "\tN_LIB_PRIVATE char** cmdLine;\L"
posixCmdLine.add "\tN_LIB_PRIVATE char** gEnv;\L"
const
# The use of a volatile function pointer to call Pre/NimMainInner
@@ -1528,15 +1439,15 @@ proc genMainProc(m: BModule) =
"}$N$N" &
"$4" &
"N_LIB_PRIVATE void $3PreMain(void) {$N" &
"##if $5$N" & # 1 for volatile call, 0 for non-volatile
"\t##if $5$N" & # 1 for volatile call, 0 for non-volatile
"\tvoid (*volatile inner)(void);$N" &
"\tinner = $3PreMainInner;$N" &
"$1" &
"\t(*inner)();$N" &
"##else$N" &
"\t##else$N" &
"$1" &
"\t$3PreMainInner();$N" &
"##endif$N" &
"\t##endif$N" &
"}$N$N"
MainProcs =
@@ -1551,17 +1462,17 @@ proc genMainProc(m: BModule) =
NimMainProc =
"N_CDECL(void, $5NimMain)(void) {$N" &
"##if $6$N" & # 1 for volatile call, 0 for non-volatile
"\t##if $6$N" & # 1 for volatile call, 0 for non-volatile
"\tvoid (*volatile inner)(void);$N" &
"$4" &
"\tinner = $5NimMainInner;$N" &
"$2" &
"\t(*inner)();$N" &
"##else$N" &
"\t##else$N" &
"$4" &
"$2" &
"\t$5NimMainInner();$N" &
"##endif$N" &
"\t##endif$N" &
"}$N$N"
NimMainBody = NimMainInner & NimMainProc
@@ -1592,7 +1503,7 @@ proc genMainProc(m: BModule) =
WinCDllMain =
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
" LPVOID lpvReserved) {$N" &
"\tif (fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "\t}$N" &
"\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
"\treturn 1;$N}$N$N"
PosixNimDllMain = WinNimDllMain
@@ -1626,11 +1537,11 @@ proc genMainProc(m: BModule) =
m.includeHeader("<libc/component.h>")
let initStackBottomCall =
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcAtomicArc, gcOrc}: "".rope
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcOrc}: "".rope
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])
inc(m.labels)
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}: "1" else: "0"
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcOrc}: "1" else: "0"
appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit, m.config.nimMainPrefix, posixCmdLine, isVolatile])
if m.config.target.targetOS == osWindows and
@@ -1770,7 +1681,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
if sfSystemModule in m.module.flags:
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", []))
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
if m.s[cfsInitProc].len > 0:
@@ -1821,10 +1732,10 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
prc.typ.sym = nil
if not containsOrIncl(m.declaredThings, prc.id):
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, dkVar)])
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, skVar)])
result = "\t$1 = ($2) $3($4, $5);$n" %
[tmp, getTypeDesc(m, prc.typ, dkVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
[tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
proc genInitCode(m: BModule) =
## this function is called in cgenWriteModules after all modules are closed,
@@ -1900,13 +1811,13 @@ proc genInitCode(m: BModule) =
if beforeRetNeeded in m.initProc.flags:
prc.add("\tBeforeRet_: ;\n")
if m.config.exc == excGoto:
if sfMainModule in m.module.flags and m.config.exc == excGoto:
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
prc.add(deinitFrame(m.initProc))
elif m.config.exc == excGoto:
elif sfMainModule in m.module.flags and m.config.exc == excGoto:
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
@@ -1963,6 +1874,8 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
openNamespaceNim(m.config.cppCustomNamespace, result)
if m.s[cfsFrameDefines].len > 0:
result.add(m.s[cfsFrameDefines])
else:
result.add("#define nimfr_(x, y)\n#define nimln_(x, y)\n")
for i in cfsForwardTypes..cfsProcs:
if m.s[i].len > 0:
@@ -2006,7 +1919,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
result.preInitProc = newProc(nil, result)
result.preInitProc.flags.incl nimErrorFlagDisabled
result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated
result.dataCache = initNodeTable()
initNodeTable(result.dataCache)
result.typeStack = @[]
result.typeNodesName = getTempName(result)
result.nimTypesName = getTempName(result)
@@ -2111,11 +2024,6 @@ proc genTopLevelStmt*(m: BModule; n: PNode) =
if sfInjectDestructors in m.module.flags:
transformedN = injectDestructorCalls(m.g.graph, m.idgen, m.module, transformedN)
if sfMainModule in m.module.flags:
let moduleCon = initModuleCon(m.g.graph, m.config, m.module)
var procCon = initProcCon(moduleCon, nil)
genCode(procCon, transformedN)
if m.hcrOn:
addHcrInitGuards(m.initProc, transformedN, m.inHcrInitGuard)
else:
@@ -2186,9 +2094,8 @@ proc updateCachedModule(m: BModule) =
cf.flags = {CfileFlag.Cached}
addFileToCompile(m.config, cf)
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
## Also called from IC.
result = nil
if sfMainModule in m.module.flags:
# phase ordering problem here: We need to announce this
# dependency to 'nimTestErrorFlag' before system.c has been written to disk.
@@ -2209,10 +2116,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
if m.hcrOn:
# make sure this is pulled in (meaning hcrGetGlobal() is called for it during init)
let sym = magicsys.getCompilerProc(m.g.graph, "programResult")
# ignore when not available, could be a module imported early in `system`
if sym != nil:
cgsymImpl m, sym
cgsym(m, "programResult")
if m.inHcrInitGuard:
endBlock(m.initProc)
@@ -2229,14 +2133,15 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
cgsym(m, "rawWrite")
# raise dependencies on behalf of genMainProc
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
cgsym(m, "initStackBottomWith")
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
cgsym(m, "initThreadVarsEmulation")
if m.g.forwardedProcs.len == 0:
incl m.flags, objHasKidsValid
result = generateMethodDispatchers(graph, m.idgen)
let disp = generateMethodDispatchers(graph)
for x in disp: genProcAux(m, x.sym)
let mm = m
m.g.modulesClosed.add mm

View File

@@ -193,17 +193,15 @@ proc initBlock*(): TBlock =
result.sections[i] = newRopeAppender()
proc newProc*(prc: PSym, module: BModule): BProc =
result = BProc(
prc: prc,
module: module,
optionsStack: if module.initProc != nil: module.initProc.optionsStack
else: @[],
options: if prc != nil: prc.options
else: module.config.options,
blocks: @[initBlock()],
sigConflicts: initCountTable[string]())
if optQuirky in result.options:
result.flags = {nimErrorFlagDisabled}
new(result)
result.prc = prc
result.module = module
result.options = if prc != nil: prc.options
else: module.config.options
result.blocks = @[initBlock()]
result.nestedTryStmts = @[]
result.finallySafePoints = @[]
result.sigConflicts = initCountTable[string]()
proc newModuleList*(g: ModuleGraph): BModuleList =
BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](),

View File

@@ -44,8 +44,6 @@ proc getDispatcher*(s: PSym): PSym =
if dispatcherPos < s.ast.len:
result = s.ast[dispatcherPos].sym
doAssert sfDispatcher in result.flags
else:
result = nil
proc methodCall*(n: PNode; conf: ConfigRef): PNode =
result = n
@@ -64,7 +62,6 @@ type
MethodResult = enum No, Invalid, Yes
proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
result = No
if a.name.id != b.name.id: return
if a.typ.len != b.typ.len:
return
@@ -116,7 +113,7 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) =
s.ast[dispatcherPos] = dispatcher
proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
var disp = copySym(s, idgen)
var disp = copySym(s, nextSymId(idgen))
incl(disp.flags, sfDispatcher)
excl(disp.flags, sfExported)
let old = disp.typ
@@ -130,7 +127,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
disp.loc.r = ""
if s.typ[0] != nil:
if disp.ast.len > resultPos:
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen)
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextSymId(idgen))
else:
# We've encountered a method prototype without a filled-in
# resultPos slot. We put a placeholder in there that will
@@ -152,7 +149,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
disp.ast[resultPos] = copyTree(meth.ast[resultPos])
proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
var witness: PSym = nil
var witness: PSym
for i in 0..<g.methods.len:
let disp = g.methods[i].dispatcher
case sameMethodBucket(disp, s, multimethods = optMultiMethods in g.config.globalOptions)
@@ -181,7 +178,6 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
proc relevantCol(methods: seq[PSym], col: int): bool =
# returns true iff the position is relevant
result = false
var t = methods[0].typ[col].skipTypes(skipPtrs)
if t.kind == tyObject:
for i in 1..high(methods):
@@ -190,7 +186,6 @@ proc relevantCol(methods: seq[PSym], col: int): bool =
return true
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
result = 0
for col in 1..<a.typ.len:
if contains(relevantCols, col):
var aa = skipTypes(a.typ[col], skipPtrs)
@@ -218,7 +213,7 @@ proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
a[j] = v
if h == 1: break
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PSym =
var base = methods[0].ast[dispatcherPos].sym
result = base
var paramLen = base.typ.len
@@ -277,7 +272,7 @@ proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idg
nilchecks.flags.incl nfTransf # should not be further transformed
result.ast[bodyPos] = nilchecks
proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
proc generateMethodDispatchers*(g: ModuleGraph): PNode =
result = newNode(nkStmtList)
for bucket in 0..<g.methods.len:
var relevantCols = initIntSet()
@@ -287,4 +282,4 @@ proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
# if multi-methods are not enabled, we are interested only in the first field
break
sortBucket(g.methods[bucket].methods, relevantCols)
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols, idgen))
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols))

View File

@@ -183,7 +183,7 @@ proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode =
ctx.newStateAssgn(newIntTypeNode(stateNo, ctx.g.getSysType(TLineInfo(), tyInt)))
proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.idgen, ctx.fn, ctx.fn.info)
result = newSym(skVar, getIdent(ctx.g.cache, name), nextSymId(ctx.idgen), ctx.fn, ctx.fn.info)
result.typ = typ
assert(not typ.isNil)
@@ -258,9 +258,8 @@ proc hasYields(n: PNode): bool =
of nkYieldStmt:
result = true
of nkSkip:
result = false
discard
else:
result = false
for c in n:
if c.hasYields:
result = true
@@ -326,7 +325,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
var ifBranch: PNode
if c.len > 1:
var cond: PNode = nil
var cond: PNode
for i in 0..<c.len - 1:
assert(c[i].kind == nkType)
let nextCond = newTree(nkCall,
@@ -389,22 +388,19 @@ proc getFinallyNode(ctx: var Ctx, n: PNode): PNode =
proc hasYieldsInExpressions(n: PNode): bool =
case n.kind
of nkSkip:
result = false
discard
of nkStmtListExpr:
if isEmptyType(n.typ):
result = false
for c in n:
if c.hasYieldsInExpressions:
return true
else:
result = n.hasYields
of nkCast:
result = false
for i in 1..<n.len:
if n[i].hasYieldsInExpressions:
return true
else:
result = false
for c in n:
if c.hasYieldsInExpressions:
return true
@@ -499,7 +495,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if ns:
needsSplit = true
var tmp: PSym = nil
var tmp: PSym
let isExpr = not isEmptyType(n.typ)
if isExpr:
tmp = ctx.newTempVar(n.typ)
@@ -859,9 +855,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
case n.kind
of nkReturnStmt:
# We're somewhere in try, transform to finally unrolling
if ctx.nearestFinally == 0:
# return is within the finally
return
assert(ctx.nearestFinally != 0)
result = newNodeI(nkStmtList, n.info)
@@ -1354,7 +1348,7 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
let idefs = copyNode(it)
for v in 0..it.len-3:
if it[v].kind == nkSym:
let x = copySym(it[v].sym, c.idgen)
let x = copySym(it[v].sym, nextSymId(c.idgen))
c.tab[it[v].sym.id] = x
idefs.add newSymNode(x)
else:
@@ -1365,7 +1359,6 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
else:
result.add it
of nkRaiseStmt:
result = nil
localError(c.config, c.info, "unsupported control flow: 'finally: ... raise' duplicated because of 'break'")
else:
result = n
@@ -1396,7 +1389,7 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode =
discard c.finallys.pop()
of nkWhileStmt, nkBlockStmt:
if not n.hasYields: return n
if n.hasYields == false: return n
c.blocks.add((n, c.finallys.len))
for i in 0 ..< n.len:
result[i] = preprocess(c, n[i])
@@ -1438,9 +1431,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
# Lambda lifting was not done yet. Use temporary :state sym, which will
# be handled specially by lambda lifting. Local temp vars (if needed)
# should follow the same logic.
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), idgen, fn, fn.info)
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), nextSymId(idgen), fn, fn.info)
ctx.stateVarSym.typ = g.createClosureIterStateType(fn, idgen)
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), idgen, fn, fn.info)
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), nextSymId(idgen), fn, fn.info)
var pc = PreprocessContext(finallys: @[], config: g.config, idgen: idgen)
var n = preprocess(pc, n.toStmtList)
#echo "transformed into ", n
@@ -1473,10 +1466,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
result = ctx.transformStateAssignments(result)
result = ctx.wrapIntoStateLoop(result)
when false:
echo "TRANSFORM TO STATES: "
echo renderTree(result)
# echo "TRANSFORM TO STATES: "
# echo renderTree(result)
echo "exception table:"
for i, e in ctx.exceptionTable:
echo i, " -> ", e
# echo "exception table:"
# for i, e in ctx.exceptionTable:
# echo i, " -> ", e

View File

@@ -7,7 +7,7 @@
# distribution, for details about the copyright.
#
## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest
## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest, nimfix
import
options, idents, nimconf, extccomp, commands, msgs,

View File

@@ -184,7 +184,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo; orig: string; conf: ConfigRef) =
var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off
var i = 0
var notes: set[TMsgKind] = {}
var notes: set[TMsgKind]
var isBracket = false
if i < arg.len and arg[i] == '[':
isBracket = true
@@ -238,9 +238,9 @@ proc processCompile(conf: ConfigRef; filename: string) =
extccomp.addExternalFileToCompile(conf, found)
const
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console', 'lib' or 'staticlib' expected, but '$1' found"
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found"
errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
template warningOptionNoop(switch: string) =
@@ -262,18 +262,13 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
of "go": result = conf.selectedGC == gcGo
of "none": result = conf.selectedGC == gcNone
of "stack", "regions": result = conf.selectedGC == gcRegions
of "atomicarc": result = conf.selectedGC == gcAtomicArc
else:
result = false
localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
of "opt":
case arg.normalize
of "speed": result = contains(conf.options, optOptimizeSpeed)
of "size": result = contains(conf.options, optOptimizeSize)
of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {}
else:
result = false
localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
of "verbosity": result = $conf.verbosity == arg
of "app":
case arg.normalize
@@ -283,9 +278,7 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
not contains(conf.globalOptions, optGenGuiApp)
of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and
not contains(conf.globalOptions, optGenGuiApp)
else:
result = false
localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
of "dynliboverride":
result = isDynlibOverride(conf, arg)
of "exceptions":
@@ -294,12 +287,8 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
of "setjmp": result = conf.exc == excSetjmp
of "quirky": result = conf.exc == excQuirky
of "goto": result = conf.exc == excGoto
else:
result = false
localError(conf, info, errInvalidExceptionSystem % arg)
else:
result = false
invalidCmdLineOption(conf, passCmd1, switch, info)
else: localError(conf, info, errInvalidExceptionSystem % arg)
else: invalidCmdLineOption(conf, passCmd1, switch, info)
proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool =
case switch.normalize
@@ -345,14 +334,9 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros")
result = contains(conf.options, optTrMacros)
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
of "nilseqs", "nilchecks", "taintmode":
warningOptionNoop(switch)
result = false
of "nilseqs", "nilchecks", "taintmode": warningOptionNoop(switch)
of "panics": result = contains(conf.globalOptions, optPanics)
of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64)
else:
result = false
invalidCmdLineOption(conf, passCmd1, switch, info)
else: invalidCmdLineOption(conf, passCmd1, switch, info)
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
notRelativeToProj = false): AbsoluteDir =
@@ -394,8 +378,7 @@ proc makeAbsolute(s: string): AbsoluteFile =
proc setTrackingInfo(conf: ConfigRef; dirty, file, line, column: string,
info: TLineInfo) =
## set tracking info, common code for track, trackDirty, & ideTrack
var ln: int = 0
var col: int = 0
var ln, col: int
if parseUtils.parseInt(line, ln) <= 0:
localError(conf, info, errInvalidNumber % line)
if parseUtils.parseInt(column, col) <= 0:
@@ -532,7 +515,14 @@ proc initOrcDefines*(conf: ConfigRef) =
if conf.exc == excNone and conf.backend != backendCpp:
conf.exc = excGoto
proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef) =
proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef, isOrc: bool) =
if isOrc:
conf.selectedGC = gcOrc
defineSymbol(conf.symbols, "gcorc")
else:
conf.selectedGC = gcArc
defineSymbol(conf.symbols, "gcarc")
defineSymbol(conf.symbols, "gcdestructors")
incl conf.globalOptions, optSeqDestructors
incl conf.globalOptions, optTinyRtti
@@ -542,11 +532,10 @@ proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef) =
if conf.exc == excNone and conf.backend != backendCpp:
conf.exc = excGoto
proc unregisterArcOrc*(conf: ConfigRef) =
proc unregisterArcOrc(conf: ConfigRef) =
undefSymbol(conf.symbols, "gcdestructors")
undefSymbol(conf.symbols, "gcarc")
undefSymbol(conf.symbols, "gcorc")
undefSymbol(conf.symbols, "gcatomicarc")
undefSymbol(conf.symbols, "nimSeqsV2")
undefSymbol(conf.symbols, "nimV2")
excl conf.globalOptions, optSeqDestructors
@@ -572,17 +561,9 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
conf.selectedGC = gcMarkAndSweep
defineSymbol(conf.symbols, "gcmarkandsweep")
of "destructors", "arc":
conf.selectedGC = gcArc
defineSymbol(conf.symbols, "gcarc")
registerArcOrc(pass, conf)
registerArcOrc(pass, conf, false)
of "orc":
conf.selectedGC = gcOrc
defineSymbol(conf.symbols, "gcorc")
registerArcOrc(pass, conf)
of "atomicarc":
conf.selectedGC = gcAtomicArc
defineSymbol(conf.symbols, "gcatomicarc")
registerArcOrc(pass, conf)
registerArcOrc(pass, conf, true)
of "hooks":
conf.selectedGC = gcHooks
defineSymbol(conf.symbols, "gchooks")
@@ -606,8 +587,8 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf: ConfigRef) =
var key = ""
var val = ""
var
key, val: string
case switch.normalize
of "eval":
expectArg(conf, switch, arg, pass, info)
@@ -622,17 +603,17 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
for path in nimbleSubs(conf, arg):
addPath(conf, if pass == passPP: processCfgPath(conf, path, info)
else: processPath(conf, path, info), info)
of "nimblepath":
of "nimblepath", "babelpath":
if switch.normalize == "babelpath": deprecatedAlias(switch, "nimblepath")
if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions:
expectArg(conf, switch, arg, pass, info)
var path = processPath(conf, arg, info, notRelativeToProj=true)
let nimbleDir = AbsoluteDir getEnv("NIMBLE_DIR")
if not nimbleDir.isEmpty and pass == passPP:
path = nimbleDir / RelativeDir"pkgs2"
nimblePath(conf, path, info)
path = nimbleDir / RelativeDir"pkgs"
nimblePath(conf, path, info)
of "nonimblepath":
of "nonimblepath", "nobabelpath":
if switch.normalize == "nobabelpath": deprecatedAlias(switch, "nonimblepath")
expectNoArg(conf, switch, arg, pass, info)
disableNimblePath(conf)
of "clearnimblepath":
@@ -670,9 +651,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
if backend == TBackend.default: localError(conf, info, "invalid backend: '$1'" % arg)
if backend == backendJs: # bug #21209
conf.globalOptions.excl {optThreadAnalysis, optThreads}
if optRun in conf.globalOptions:
# for now, -r uses nodejs, so define nodejs
defineSymbol(conf.symbols, "nodejs")
conf.backend = backend
of "doccmd": conf.docCmd = arg
of "define", "d":
@@ -783,10 +761,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
if conf.backend == backendJs or conf.cmd == cmdNimscript: discard
else: processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
#if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe)
of "tlsemulation":
processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
if optTlsEmulation in conf.globalOptions:
conf.legacyFeatures.incl emitGenerics
of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
of "implicitstatic":
processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info)
of "patterns", "trmacros":
@@ -823,7 +798,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "dll")
of "staticlib":
incl(conf.globalOptions, optGenStaticLib)
incl(conf.globalOptions, optNoMain)
excl(conf.globalOptions, optGenGuiApp)
defineSymbol(conf.symbols, "library")
defineSymbol(conf.symbols, "staticlib")
@@ -847,8 +821,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "header":
if conf != nil: conf.headerFile = arg
incl(conf.globalOptions, optGenIndex)
of "nimbasepattern":
if conf != nil: conf.nimbasePattern = arg
of "index":
case arg.normalize
of "", "on": conf.globalOptions.incl {optGenIndex}
@@ -889,28 +861,21 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
setTarget(conf.target, conf.target.targetOS, cpu)
of "run", "r":
processOnOffSwitchG(conf, {optRun}, arg, pass, info)
if conf.backend == backendJs:
# for now, -r uses nodejs, so define nodejs
defineSymbol(conf.symbols, "nodejs")
of "maxloopiterationsvm":
expectArg(conf, switch, arg, pass, info)
var value: int = 10_000_000
discard parseSaturatedNatural(arg, value)
if not value > 0: localError(conf, info, "maxLoopIterationsVM must be a positive integer greater than zero")
conf.maxLoopIterationsVM = value
conf.maxLoopIterationsVM = parseInt(arg)
of "errormax":
expectArg(conf, switch, arg, pass, info)
# Note: `nim check` (etc) can overwrite this.
# `0` is meaningless, give it a useful meaning as in clang's -ferror-limit
# If user doesn't set this flag and the code doesn't either, it'd
# have the same effect as errorMax = 1
var value: int = 0
discard parseSaturatedNatural(arg, value)
conf.errorMax = if value == 0: high(int) else: value
let ret = parseInt(arg)
conf.errorMax = if ret == 0: high(int) else: ret
of "verbosity":
expectArg(conf, switch, arg, pass, info)
let verbosity = parseInt(arg)
if verbosity notin 0..3:
if verbosity notin {0..3}:
localError(conf, info, "invalid verbosity level: '$1'" % arg)
conf.verbosity = verbosity
var verb = NotesVerbosity[conf.verbosity]
@@ -920,9 +885,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf.mainPackageNotes = conf.notes
of "parallelbuild":
expectArg(conf, switch, arg, pass, info)
var value: int = 0
discard parseSaturatedNatural(arg, value)
conf.numberOfProcessors = value
conf.numberOfProcessors = parseInt(arg)
of "version", "v":
expectNoArg(conf, switch, arg, pass, info)
writeVersionInfo(conf, pass)
@@ -1102,6 +1065,29 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "expandarc":
expectArg(conf, switch, arg, pass, info)
conf.arcToExpand[arg] = "T"
of "useversion":
expectArg(conf, switch, arg, pass, info)
case arg
of "1.0":
defineSymbol(conf.symbols, "NimMajor", "1")
defineSymbol(conf.symbols, "NimMinor", "0")
# old behaviors go here:
defineSymbol(conf.symbols, "nimOldRelativePathBehavior")
undefSymbol(conf.symbols, "nimDoesntTrackDefects")
ast.eqTypeFlags.excl {tfGcSafe, tfNoSideEffect}
conf.globalOptions.incl optNimV1Emulation
of "1.2":
defineSymbol(conf.symbols, "NimMajor", "1")
defineSymbol(conf.symbols, "NimMinor", "2")
conf.globalOptions.incl optNimV12Emulation
of "1.6":
defineSymbol(conf.symbols, "NimMajor", "1")
defineSymbol(conf.symbols, "NimMinor", "6")
conf.globalOptions.incl optNimV16Emulation
else:
localError(conf, info, "unknown Nim version; currently supported values are: `1.0`, `1.2`")
# always be compatible with 1.x.100:
defineSymbol(conf.symbols, "NimPatch", "100")
of "benchmarkvm":
processOnOffSwitchG(conf, {optBenchmarkVM}, arg, pass, info)
of "profilevm":
@@ -1115,8 +1101,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
processOnOffSwitchG(conf, {optPanics}, arg, pass, info)
if optPanics in conf.globalOptions:
defineSymbol(conf.symbols, "nimPanics")
of "jsbigint64":
processOnOffSwitchG(conf, {optJsBigInt64}, arg, pass, info)
of "sourcemap": # xxx document in --fullhelp
conf.globalOptions.incl optSourcemap
conf.options.incl optLineDir
@@ -1131,8 +1115,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
else: invalidCmdLineOption(conf, pass, switch, info)
proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
var cmd = ""
var arg = ""
var cmd, arg: string
splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
processSwitch(cmd, arg, pass, gCmdLineInfo, config)
@@ -1159,10 +1142,7 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
config.projectName = unixToNativePath(p.key)
config.arguments = cmdLineRest(p)
result = true
elif pass != passCmd2:
setCommandEarly(config, p.key)
result = false
else: result = false
elif pass != passCmd2: setCommandEarly(config, p.key)
else:
if pass == passCmd1: config.commandArgs.add p.key
if argsCount == 1:
@@ -1173,6 +1153,4 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
config.projectName = unixToNativePath(p.key)
config.arguments = cmdLineRest(p)
result = true
else:
result = false
inc argsCount

View File

@@ -1,28 +0,0 @@
include "../lib/system/compilation.nim"
version = $NimMajor & "." & $NimMinor & "." & $NimPatch
author = "Andreas Rumpf"
description = "Compiler package providing the compiler sources as a library."
license = "MIT"
skipDirs = @["."]
installDirs = @["compiler"]
import os
var compilerDir = ""
before install:
rmDir("compiler")
let
files = listFiles(".")
dirs = listDirs(".")
mkDir("compiler")
for f in files:
cpFile(f, "compiler" / f)
for d in dirs:
cpDir(d, "compiler" / d)
requires "nim"

View File

@@ -13,6 +13,8 @@
import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types, intsets
from magicsys import addSonSkipIntLit
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -25,12 +27,24 @@ const
proc declareSelf(c: PContext; info: TLineInfo) =
## Adds the magical 'Self' symbols to the current scope.
let ow = getCurrOwner(c)
let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info)
let s = newSym(skType, getIdent(c.cache, "Self"), nextSymId(c.idgen), ow, info)
s.typ = newType(tyTypeDesc, nextTypeId(c.idgen), ow)
s.typ.flags.incl {tfUnresolved, tfPacked}
s.typ.add newType(tyEmpty, nextTypeId(c.idgen), ow)
addDecl(c, s, info)
proc isSelf*(t: PType): bool {.inline.} =
## Is this the magical 'Self' type?
t.kind == tyTypeDesc and tfPacked in t.flags
proc makeTypeDesc*(c: PContext, typ: PType): PType =
if typ.kind == tyTypeDesc and not isSelf(typ):
result = typ
else:
result = newTypeS(tyTypeDesc, c)
incl result.flags, tfCheckedForDestructor
result.addSonSkipIntLit(typ, c.idgen)
proc semConceptDecl(c: PContext; n: PNode): PNode =
## Recursive helper for semantic checking for the concept declaration.
## Currently we only support (possibly empty) lists of statements
@@ -48,7 +62,7 @@ proc semConceptDecl(c: PContext; n: PNode): PNode =
result[i] = n[i]
result[^1] = semConceptDecl(c, n[^1])
of nkCommentStmt:
result = n
discard
else:
localError(c.config, n.info, "unexpected construct in the new-styled concept: " & renderTree(n))
result = n
@@ -107,11 +121,8 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
for i in 0..<a.len:
if not matchType(c, f[i], a[i], m): return false
return true
else:
result = false
of tyGenericInvocation:
result = false
if a.kind == tyGenericInst and a[0].kind == tyGenericBody:
if sameType(f[0], a[0]) and f.len == a.len-1:
for i in 1 ..< f.len:
@@ -145,17 +156,15 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
result = matchType(c, old, ak, m)
if m.magic == mArrPut and ak.kind == tyGenericParam:
result = true
else:
result = false
#echo "B for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
of tyVar, tySink, tyLent, tyOwned:
# modifiers in the concept must be there in the actual implementation
# too but not vice versa.
if a.kind == f.kind:
result = matchType(c, f[0], a[0], m)
result = matchType(c, f.sons[0], a.sons[0], m)
elif m.magic == mArrPut:
result = matchType(c, f[0], a, m)
result = matchType(c, f.sons[0], a, m)
else:
result = false
of tyEnum, tyObject, tyDistinct:
@@ -176,7 +185,6 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
m.inferred.setLen oldLen
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr,
tyGenericInst:
result = false
let ak = a.skipTypes(ignorableForArgType - {f.kind})
if ak.kind == f.kind and f.len == ak.len:
for i in 0..<ak.len:
@@ -201,7 +209,6 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
if not result:
m.inferred.setLen oldLen
else:
result = false
for i in 0..<f.len:
result = matchType(c, f[i], a, m)
if result: break # and remember the binding!
@@ -250,7 +257,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
m.inferred.setLen oldLen
return false
if not matchReturnType(c, n[0].sym.typ[0], candidate.typ[0], m):
if not matchReturnType(c, n[0].sym.typ.sons[0], candidate.typ.sons[0], m):
m.inferred.setLen oldLen
return false
@@ -299,8 +306,6 @@ proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
result = matchSyms(c, n, {skMethod}, m)
of nkIteratorDef:
result = matchSyms(c, n, {skIterator}, m)
of nkCommentStmt:
result = true
else:
# error was reported earlier.
result = false

View File

@@ -45,8 +45,10 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimNewTypedesc") # deadcode
defineSymbol("nimrequiresnimframe") # deadcode
defineSymbol("nimparsebiggestfloatmagic") # deadcode
defineSymbol("nimalias") # deadcode
defineSymbol("nimlocks") # deadcode
defineSymbol("nimnode") # deadcode
defineSymbol("nimnode") # deadcode pending `nimnode` reference in opengl package
# refs https://github.com/nim-lang/opengl/pull/79
defineSymbol("nimvarargstyped") # deadcode
defineSymbol("nimtypedescfixed") # deadcode
defineSymbol("nimKnowsNimvm") # deadcode
@@ -145,19 +147,10 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasCallsitePragma")
defineSymbol("nimHasAmbiguousEnumHint")
defineSymbol("nimHasWarnCastSizes") # deadcode
defineSymbol("nimHasWarnCastSizes")
defineSymbol("nimHasOutParams")
defineSymbol("nimHasSystemRaisesDefect")
defineSymbol("nimHasWarnUnnamedBreak")
defineSymbol("nimHasGenericDefine")
defineSymbol("nimHasDefineAliases")
defineSymbol("nimHasWarnBareExcept")
defineSymbol("nimHasDup")
defineSymbol("nimHasChecksums")
defineSymbol("nimHasSendable")
defineSymbol("nimAllowNonVarDestructor")
defineSymbol("nimHasQuirky")
defineSymbol("nimHasEnsureMove")
defineSymbol("nimUseStrictDefs")
defineSymbol("nimHasNolineTooLong")

View File

@@ -42,7 +42,7 @@ proc toNimblePath(s: string, isStdlib: bool): string =
let sub = "lib/"
var start = s.find(sub)
if start < 0:
raiseAssert "unreachable"
doAssert false
else:
start += sub.len
let base = s[start..^1]
@@ -63,16 +63,12 @@ proc toNimblePath(s: string, isStdlib: bool): string =
sub.add "/pkgs/"
var start = s.find(sub)
if start < 0:
sub[^1] = '2'
sub.add '/'
start = s.find(sub) # /pkgs2
if start < 0:
return s
start += sub.len
start += skipUntil(s, '/', start)
start += 1
result = pkgPrefix & s[start..^1]
result = s
else:
start += sub.len
start += skipUntil(s, '/', start)
start += 1
result = pkgPrefix & s[start..^1]
proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
doAssert n.kind == nkSym, $n.kind
@@ -105,6 +101,11 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
changeFileExt(project, "dot"))
proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
result = PGen(module: module, config: graph.config, graph: graph)
var g: PGen
new(g)
g.module = module
g.config = graph.config
g.graph = graph
if graph.backend == nil:
graph.backend = Backend(dotGraph: "")
result = g

View File

@@ -60,7 +60,6 @@ type
proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string =
# for debugging purposes
# first iteration: compute all necessary labels:
result = ""
var jumpTargets = initIntSet()
let last = if last < 0: c.len-1 else: min(last, c.len-1)
for i in start..last:
@@ -112,7 +111,7 @@ proc patch(c: var Con, p: TPosition) =
proc gen(c: var Con; n: PNode)
proc popBlock(c: var Con; oldLen: int) =
var exits: seq[TPosition] = @[]
var exits: seq[TPosition]
exits.add c.gotoI()
for f in c.blocks[oldLen].breakFixups:
c.patch(f[0])
@@ -129,6 +128,10 @@ template withBlock(labl: PSym; body: untyped) =
body
popBlock(c, oldLen)
proc isTrue(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0
template forkT(body) =
let lab1 = c.forkI()
body
@@ -260,9 +263,8 @@ proc genBreakOrRaiseAux(c: var Con, i: int, n: PNode) =
if c.blocks[i].isTryBlock:
c.blocks[i].raiseFixups.add lab1
else:
var trailingFinales: seq[PNode] = @[]
if c.inTryStmt > 0:
# Ok, we are in a try, lets see which (if any) try's we break out from:
var trailingFinales: seq[PNode]
if c.inTryStmt > 0: #Ok, we are in a try, lets see which (if any) try's we break out from:
for b in countdown(c.blocks.high, i):
if c.blocks[b].isTryBlock:
trailingFinales.add c.blocks[b].finale
@@ -383,8 +385,7 @@ proc genCall(c: var Con; n: PNode) =
# Pass by 'out' is a 'must def'. Good enough for a move optimizer.
genDef(c, n[i])
# every call can potentially raise:
if c.inTryStmt > 0 and canRaiseConservative(n[0]):
inc c.interestingInstructions
if false: # c.inTryStmt > 0 and canRaiseConservative(n[0]):
# we generate the instruction sequence:
# fork lab1
# goto exceptionHandler (except or finally)
@@ -466,7 +467,7 @@ proc gen(c: var Con; n: PNode) =
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, PathKinds1:
gen(c, n[1])
of nkVarSection, nkLetSection: genVarSection(c, n)
of nkDefer: raiseAssert "dfa construction pass requires the elimination of 'defer'"
of nkDefer: doAssert false, "dfa construction pass requires the elimination of 'defer'"
else: discard
when false:
@@ -492,7 +493,7 @@ proc constructCfg*(s: PSym; body: PNode; root: PSym): ControlFlowGraph =
gen(c, body)
if root.kind == skResult:
genImplicitReturn(c)
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
when defined(gcArc) or defined(gcOrc):
result = c.code # will move
else:
shallowCopy(result, c.code)

View File

@@ -112,16 +112,13 @@ type
proc add(dest: var ItemPre, rst: PRstNode) = dest.add ItemFragment(isRst: true, rst: rst)
proc add(dest: var ItemPre, str: string) = dest.add ItemFragment(isRst: false, str: str)
proc addRstFileIndex(d: PDoc, fileIndex: lineinfos.FileIndex): rstast.FileIndex =
let invalid = rstast.FileIndex(-1)
result = d.nimToRstFid.getOrDefault(fileIndex, default = invalid)
if result == invalid:
let fname = toFullPath(d.conf, fileIndex)
result = addFilename(d.sharedState, fname)
d.nimToRstFid[fileIndex] = result
proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.FileIndex =
addRstFileIndex(d, info.fileIndex)
let invalid = rstast.FileIndex(-1)
result = d.nimToRstFid.getOrDefault(info.fileIndex, default = invalid)
if result == invalid:
let fname = toFullPath(d.conf, info)
result = addFilename(d.sharedState, fname)
d.nimToRstFid[info.fileIndex] = result
proc cmpDecimalsIgnoreCase(a, b: string): int =
## For sorting with correct handling of cases like 'uint8' and 'uint16'.
@@ -170,7 +167,6 @@ proc cmpDecimalsIgnoreCase(a, b: string): int =
proc prettyString(a: object): string =
# xxx pending std/prettyprint refs https://github.com/nim-lang/RFCs/issues/203#issuecomment-602534906
result = ""
for k, v in fieldPairs(a):
result.add k & ": " & $v & "\n"
@@ -216,16 +212,12 @@ proc whichType(d: PDoc; n: PNode): PSym =
if n.kind == nkSym:
if d.types.strTableContains(n.sym):
result = n.sym
else:
result = nil
else:
result = nil
for i in 0..<n.safeLen:
let x = whichType(d, n[i])
if x != nil: return x
proc attachToType(d: PDoc; p: PSym): PSym =
result = nil
let params = p.ast[paramsPos]
template check(i) =
result = whichType(d, params[i])
@@ -264,16 +256,7 @@ template declareClosures(currentFilename: AbsoluteFile, destFile: string) =
of mwUnusedImportdoc: k = warnRstUnusedImportdoc
of mwRstStyle: k = warnRstStyle
{.gcsafe.}:
let errorsAsWarnings = (roPreferMarkdown in d.sharedState.options) and
not d.standaloneDoc # not tolerate errors in .rst/.md files
if whichMsgClass(msgKind) == mcError and errorsAsWarnings:
liMessage(conf, newLineInfo(conf, AbsoluteFile filename, line, col),
k, arg, doNothing, instLoc(), ignoreError=true)
# when our Markdown parser fails, we currently can only terminate the
# parsing (and then we will return monospaced text instead of markup):
raiseRecoverableError("")
else:
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
proc docgenFindFile(s: string): string {.gcsafe.} =
result = options.findFile(conf, s).string
@@ -325,9 +308,8 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
standaloneDoc = false, preferMarkdown = true,
hasToc = true): PDoc =
let destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false).string
new(result)
let d = result # pass `d` to `declareClosures`:
declareClosures(currentFilename = filename, destFile = destFile)
new(result)
result.module = module
result.conf = conf
result.cache = cache
@@ -348,7 +330,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
if conf.configVars.hasKey("doc.googleAnalytics") and
conf.configVars.hasKey("doc.plausibleAnalytics"):
raiseAssert "Either use googleAnalytics or plausibleAnalytics"
doAssert false, "Either use googleAnalytics or plausibleAnalytics"
if conf.configVars.hasKey("doc.googleAnalytics"):
result.analytics = """
@@ -373,7 +355,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
result.seenSymbols = newStringTable(modeCaseInsensitive)
result.id = 100
result.jEntriesFinal = newJArray()
result.types = initStrTable()
initStrTable result.types
result.onTestSnippet =
proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) {.gcsafe.} =
if conf.docCmd == docCmdSkip: return
@@ -433,21 +415,16 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
proc genComment(d: PDoc, n: PNode): PRstNode =
if n.comment.len > 0:
d.sharedState.currFileIdx = addRstFileIndex(d, n.info)
try:
result = parseRst(n.comment,
toLinenumber(n.info),
toColumn(n.info) + DocColOffset,
d.conf, d.sharedState)
except ERecoverableError:
result = newRstNode(rnLiteralBlock, @[newRstLeaf(n.comment)])
else:
result = nil
result = parseRst(n.comment,
toLinenumber(n.info),
toColumn(n.info) + DocColOffset,
d.conf, d.sharedState)
proc genRecCommentAux(d: PDoc, n: PNode): PRstNode =
if n == nil: return nil
result = genComment(d, n)
if result == nil:
if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef, nkTypeClassTy,
if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef,
nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkSinkAsgn, nkHiddenStdConv}:
# notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}:
for i in 0..<n.len:
@@ -476,7 +453,6 @@ proc getPlainDocstring(n: PNode): string =
elif startsWith(n.comment, "##"):
result = n.comment
else:
result = ""
for i in 0..<n.safeLen:
result = getPlainDocstring(n[i])
if result.len > 0: return
@@ -492,8 +468,9 @@ proc externalDep(d: PDoc; module: PSym): string =
proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string;
renderFlags: TRenderFlags = {};
procLink: string) =
var r: TSrcGen = initTokRender(n, renderFlags)
var r: TSrcGen
var literal = ""
initTokRender(r, n, renderFlags)
var kind = tkEof
var tokenPos = 0
var procTokenPos = 0
@@ -585,13 +562,10 @@ proc runAllExamples(d: PDoc) =
# most useful semantics is that `docCmd` comes after `rdoccmd`, so that we can (temporarily) override
# via command line
# D20210224T221756:here
var pathArgs = "--path:$path" % [ "path", quoteShell(d.conf.projectPath) ]
for p in d.conf.searchPaths:
pathArgs = "$args --path:$path" % [ "args", pathArgs, "path", quoteShell(p) ]
let cmd = "$nim $backend -r --lib:$libpath --warning:UnusedImport:off $pathArgs --nimcache:$nimcache $rdoccmd $docCmd $file" % [
let cmd = "$nim $backend -r --lib:$libpath --warning:UnusedImport:off --path:$path --nimcache:$nimcache $rdoccmd $docCmd $file" % [
"nim", quoteShell(os.getAppFilename()),
"backend", $d.conf.backend,
"pathArgs", pathArgs,
"path", quoteShell(d.conf.projectPath),
"libpath", quoteShell(d.conf.libpath),
"nimcache", quoteShell(outputDir),
"file", quoteShell(outp),
@@ -607,9 +581,7 @@ proc runAllExamples(d: PDoc) =
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
# removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove
proc quoted(a: string): string =
result = ""
result.addQuoted(a)
proc quoted(a: string): string = result.addQuoted(a)
proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): (string, int, int) =
# xxx expose in compiler/lineinfos.nim
@@ -628,6 +600,7 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
let useRenderModule = false
let loc = d.conf.toFileLineCol(n.info)
let code = extractRunnableExamplesSource(d.conf, n)
let codeIndent = extractRunnableExamplesSource(d.conf, n, indent = 2)
if d.conf.errorCounter > 0:
return (rdoccmd, code)
@@ -643,7 +616,6 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
docComment.comment = comment
var runnableExamples = newTree(nkStmtList,
docComment,
newTree(nkImportStmt, newStrNode(nkStrLit, "std/assertions")),
newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
runnableExamples.info = n.info
for a in n.lastSon: runnableExamples.add a
@@ -657,7 +629,6 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
else:
var code2 = code
if code.len > 0 and "codeReordering" notin code:
let codeIndent = extractRunnableExamplesSource(d.conf, n, indent = 2)
# hacky but simplest solution, until we devise a way to make `{.line.}`
# work without introducing a scope
code2 = """
@@ -668,7 +639,6 @@ $#
#[
$#
]#
import std/assertions
import $#
$#
""" % [comment, d.filename.quoted, code2]
@@ -735,7 +705,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var ItemPre,
let (rdoccmd, code) = prepareExample(d, n, topLevel)
var msg = "Example:"
if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd
var s: string = ""
var s: string
dispA(d.conf, s, "\n<p><strong class=\"examples_text\">$1</strong></p>\n",
"\n\n\\textbf{$1}\n", [msg])
dest.add s
@@ -951,17 +921,14 @@ proc genDeprecationMsg(d: PDoc, n: PNode): string =
if n[1].kind in {nkStrLit..nkTripleStrLit}:
result = getConfigVar(d.conf, "doc.deprecationmsg") % [
"label", "Deprecated:", "message", xmltree.escape(n[1].strVal)]
else:
result = ""
else:
raiseAssert "unreachable"
doAssert false
type DocFlags = enum
kDefault
kForceExport
proc genSeeSrc(d: PDoc, path: string, line: int): string =
result = ""
let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
if docItemSeeSrc.len > 0:
let path = relativeTo(AbsoluteFile path, AbsoluteDir getCurrentDir(), '/')
@@ -1003,7 +970,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
result.symKind = k.toHumanStr
if k in routineKinds:
var
paramTypes: seq[string] = @[]
paramTypes: seq[string]
renderParamTypes(paramTypes, n[paramsPos], toNormalize=true)
let paramNames = renderParamNames(n[paramsPos], toNormalize=true)
# In some rare cases (system.typeof) parameter type is not set for default:
@@ -1028,7 +995,8 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
genNode = n[miscPos][1] # FIXME: what is index 1?
if genNode != nil:
var literal = ""
var r: TSrcGen = initTokRender(genNode, {renderNoBody, renderNoComments,
var r: TSrcGen
initTokRender(r, genNode, {renderNoBody, renderNoComments,
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
var kind = tkEof
while true:
@@ -1049,14 +1017,15 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
var result = ""
var literal, plainName = ""
var kind = tkEof
var comm: ItemPre = default(ItemPre)
var comm: ItemPre
if n.kind in routineDefs:
getAllRunnableExamples(d, n, comm)
else:
comm.add genRecComment(d, n)
var r: TSrcGen
# Obtain the plain rendered string for hyperlink titles.
var r: TSrcGen = initTokRender(n, {renderNoBody, renderNoComments, renderDocComments,
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
while true:
getNextTok(r, kind, literal)
@@ -1091,8 +1060,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
fileIndex: addRstFileIndex(d, nameNode.info))
addAnchorNim(d.sharedState, external = false, refn = symbolOrId,
tooltip = detailedName, langSym = rstLangSymbol,
priority = symbolPriority(k), info = lineinfo,
module = addRstFileIndex(d, FileIndex d.module.position))
priority = symbolPriority(k), info = lineinfo)
let renderFlags =
if nonExports: {renderNoBody, renderNoComments, renderDocComments, renderSyms,
@@ -1155,16 +1123,13 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
if k == skType and nameNode.kind == nkSym:
d.types.strTableAdd nameNode.sym
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): JsonItem =
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonItem =
if not isVisible(d, nameNode): return
var
name = getNameEsc(d, nameNode)
comm = genRecComment(d, n)
r: TSrcGen
renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing}
if nonExports:
renderFlags.incl renderNonExportedFields
r = initTokRender(n, renderFlags)
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing})
result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
"col": %n.info.col}
if comm != nil:
@@ -1196,9 +1161,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false):
result.json["signature"]["genericParams"] = newJArray()
for genericParam in n[genericParamsPos]:
var param = %{"name": %($genericParam)}
if genericParam.sym.typ.len > 0:
if genericParam.sym.typ.sons.len > 0:
param["types"] = newJArray()
for kind in genericParam.sym.typ:
for kind in genericParam.sym.typ.sons:
param["types"].add %($kind)
result.json["signature"]["genericParams"].add param
if optGenIndex in d.conf.globalOptions:
@@ -1293,8 +1258,6 @@ proc documentNewEffect(cache: IdentCache; n: PNode): PNode =
let s = n[namePos].sym
if tfReturnsNew in s.typ.flags:
result = newIdentNode(getIdent(cache, "new"), n.info)
else:
result = nil
proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
let spec = effectSpec(x, effectType)
@@ -1317,8 +1280,6 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, $effectType), n.info), effects)
else:
result = nil
proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode =
let s = n[namePos].sym
@@ -1332,8 +1293,6 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName
if effects.len > 0:
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, pragmaName), n.info), effects)
else:
result = nil
proc documentRaises*(cache: IdentCache; n: PNode) =
if n[namePos].kind != nkSym: return
@@ -1407,7 +1366,7 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0])
of nkCallKinds:
var comm: ItemPre = default(ItemPre)
var comm: ItemPre
getAllRunnableExamples(d, n, comm)
if comm.len != 0: d.modDescPre.add(comm)
else: discard
@@ -1492,8 +1451,7 @@ proc finishGenerateDoc*(d: var PDoc) =
isGroup: true),
priority = symbolPriority(k),
# select index `0` just to have any meaningful warning:
info = overloadChoices[0].info,
module = addRstFileIndex(d, FileIndex d.module.position))
info = overloadChoices[0].info)
if optGenIndexOnly in d.conf.globalOptions:
return
@@ -1516,7 +1474,7 @@ proc finishGenerateDoc*(d: var PDoc) =
overloadChoices.sort(cmp)
var nameContent = ""
for item in overloadChoices:
var itemDesc: string = ""
var itemDesc: string
renderItemPre(d, item.descRst, itemDesc)
nameContent.add(
getConfigVar(d.conf, "doc.item") % (
@@ -1542,7 +1500,7 @@ proc finishGenerateDoc*(d: var PDoc) =
for i, entry in d.jEntriesPre:
if entry.rst != nil:
let resolved = resolveSubs(d.sharedState, entry.rst)
var str: string = ""
var str: string
renderRstToOut(d[], resolved, str)
entry.json[entry.rstField] = %str
d.jEntriesPre[i].rst = nil
@@ -1555,7 +1513,7 @@ proc finishGenerateDoc*(d: var PDoc) =
proc add(d: PDoc; j: JsonItem) =
if j.json != nil or j.rst != nil: d.jEntriesPre.add j
proc generateJson*(d: PDoc, n: PNode, config: ConfigRef, includeComments: bool = true) =
proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) =
case n.kind
of nkPragma:
let doctypeNode = findPragma(n, wDoctype)
@@ -1587,14 +1545,14 @@ proc generateJson*(d: PDoc, n: PNode, config: ConfigRef, includeComments: bool =
if n[i].kind != nkCommentStmt:
# order is always 'type var let const':
d.add genJsonItem(d, n[i], n[i][0],
succ(skType, ord(n.kind)-ord(nkTypeSection)), optShowNonExportedFields in config.globalOptions)
succ(skType, ord(n.kind)-ord(nkTypeSection)))
of nkStmtList:
for i in 0..<n.len:
generateJson(d, n[i], config, includeComments)
generateJson(d, n[i], includeComments)
of nkWhenStmt:
# generate documentation for the first branch only:
if not checkForFalse(n[0][0]):
generateJson(d, lastSon(n[0]), config, includeComments)
generateJson(d, lastSon(n[0]), includeComments)
else: discard
proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string =
@@ -1657,7 +1615,7 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) =
for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase):
var overloadChoices = d.tocTable[kind][plainName]
overloadChoices.sort(cmp)
var content: string = ""
var content: string
for item in overloadChoices:
content.add item.content
d.toc2[kind].add getConfigVar(d.conf, "doc.section.toc2") % [
@@ -1688,7 +1646,7 @@ proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile):
proc genOutFile(d: PDoc, groupedToc = false): string =
var
code, content: string = ""
code, content: string
title = ""
var j = 0
var toc = ""
@@ -1739,7 +1697,7 @@ proc genOutFile(d: PDoc, groupedToc = false): string =
"moduledesc", d.modDescFinal, "date", getDateStr(), "time", getClockStr(),
"content", content, "author", d.meta[metaAuthor],
"version", esc(d.target, d.meta[metaVersion]), "analytics", d.analytics,
"deprecationMsg", d.modDeprecationMsg, "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
"deprecationMsg", d.modDeprecationMsg]
else:
code = content
result = code
@@ -1797,7 +1755,7 @@ proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) =
proc writeOutputJson*(d: PDoc, useWarning = false) =
runAllExamples(d)
var modDesc: string = ""
var modDesc: string
for desc in d.modDescFinal:
modDesc &= desc
let content = %*{"orig": d.filename,
@@ -1809,7 +1767,7 @@ proc writeOutputJson*(d: PDoc, useWarning = false) =
else:
let dir = d.destFile.splitFile.dir
createDir(dir)
var f: File = default(File)
var f: File
if open(f, d.destFile, fmWrite):
write(f, $content)
close(f)
@@ -1843,16 +1801,13 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef;
var filen = addFileExt(filename, "txt")
var d = newDocumentor(filen, cache, conf, outExt, standaloneDoc = true,
preferMarkdown = preferMarkdown, hasToc = false)
try:
let rst = parseRst(readFile(filen.string),
line=LineRstInit, column=ColRstInit,
conf, d.sharedState)
d.modDescPre = @[ItemFragment(isRst: true, rst: rst)]
finishGenerateDoc(d)
writeOutput(d)
generateIndex(d)
except ERecoverableError:
discard "already reported the error"
let rst = parseRst(readFile(filen.string),
line=LineRstInit, column=ColRstInit,
conf, d.sharedState)
d.modDescPre = @[ItemFragment(isRst: true, rst: rst)]
finishGenerateDoc(d)
writeOutput(d)
generateIndex(d)
proc commandRst2Html*(cache: IdentCache, conf: ConfigRef,
preferMarkdown=false) =
@@ -1871,7 +1826,7 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
status: int; content: string) {.gcsafe.} =
localError(conf, newLineInfo(conf, AbsoluteFile d.filename, -1, -1),
warnUser, "the ':test:' attribute is not supported by this backend")
generateJson(d, ast, conf)
generateJson(d, ast)
finishGenerateDoc(d)
let json = d.jEntriesFinal
let content = pretty(json)
@@ -1923,7 +1878,7 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"")
"title", "Index",
"subtitle", "", "tableofcontents", "", "moduledesc", "",
"date", getDateStr(), "time", getClockStr(),
"content", content, "author", "", "version", "", "analytics", "", "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
"content", content, "author", "", "version", "", "analytics", ""]
# no analytics because context is not available
try:

View File

@@ -39,12 +39,10 @@ template closeImpl(body: untyped) {.dirty.} =
discard
proc closeDoc*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
result = nil
closeImpl:
writeOutput(g.doc, useWarning, groupedToc)
proc closeJson*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
result = nil
closeImpl:
writeOutputJson(g.doc, useWarning)
@@ -58,7 +56,7 @@ proc processNodeJson*(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
if shouldProcess(g):
generateJson(g.doc, n, g.config, false)
generateJson(g.doc, n, false)
template myOpenImpl(ext: untyped) {.dirty.} =
var g: PGen

View File

@@ -6,12 +6,12 @@ when defined(nimPreviewSlimSystem):
proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym =
result = newSym(skProc, getIdent(g.cache, "$"), idgen, t.owner, info)
result = newSym(skProc, getIdent(g.cache, "$"), nextSymId idgen, t.owner, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info)
dest.typ = t
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info)
res.typ = getSysType(g, info, tyString)
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
@@ -56,7 +56,6 @@ proc searchObjCaseImpl(obj: PNode; field: PSym): PNode =
if obj.kind == nkRecCase and obj[0].kind == nkSym and obj[0].sym == field:
result = obj
else:
result = nil
for x in obj:
result = searchObjCaseImpl(x, field)
if result != nil: break
@@ -68,12 +67,12 @@ proc searchObjCase(t: PType; field: PSym): PNode =
doAssert result != nil
proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym =
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), idgen, t.owner, info)
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), nextSymId idgen, t.owner, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info)
dest.typ = field.typ
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info)
res.typ = getSysType(g, info, tyUInt8)
result.typ = newType(tyProc, nextTypeId idgen, t.owner)

View File

@@ -11,7 +11,7 @@
import ast, types, options, tables, dynlib, msgs, lineinfos
from os import getAppFilename
import libffi/libffi
import pkg/libffi
when defined(windows):
const libcDll = "msvcrt.dll"
@@ -37,10 +37,9 @@ else:
var gExeHandle = loadLib()
proc getDll(conf: ConfigRef, cache: var TDllCache; dll: string; info: TLineInfo): pointer =
result = nil
if dll in cache:
return cache[dll]
var libs: seq[string] = @[]
var libs: seq[string]
libCandidates(dll, libs)
for c in libs:
result = loadLib(c)
@@ -62,7 +61,7 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode =
let lib = sym.annex
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
globalError(conf, sym.info, "dynlib needs to be a string lit")
var theAddr: pointer = nil
var theAddr: pointer
if (lib.isNil or lib.kind == libHeader) and not gExeHandle.isNil:
libPathMsg = "current exe: " & getAppFilename() & " nor libc: " & libcDll
# first try this exe itself:
@@ -109,7 +108,6 @@ proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI
of ccStdCall: result = when defined(windows) and defined(x86): STDCALL else: DEFAULT_ABI
of ccCDecl: result = DEFAULT_ABI
else:
result = default(TABI)
globalError(conf, info, "cannot map calling convention to FFI")
template rd(typ, p: untyped): untyped = (cast[ptr typ](p))[]
@@ -134,8 +132,6 @@ proc packSize(conf: ConfigRef, v: PNode, typ: PType): int =
result = sizeof(pointer)
elif v.len != 0:
result = v.len * packSize(conf, v[0], typ[1])
else:
result = 0
else:
result = getSize(conf, typ).int
@@ -144,7 +140,6 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer)
proc getField(conf: ConfigRef, n: PNode; position: int): PSym =
case n.kind
of nkRecList:
result = nil
for i in 0..<n.len:
result = getField(conf, n[i], position)
if result != nil: return
@@ -159,8 +154,7 @@ proc getField(conf: ConfigRef, n: PNode; position: int): PSym =
else: internalError(conf, n.info, "getField(record case branch)")
of nkSym:
if n.sym.position == position: result = n.sym
else: result = nil
else: result = nil
else: discard
proc packObject(conf: ConfigRef, x: PNode, typ: PType, res: pointer) =
internalAssert conf, x.kind in {nkObjConstr, nkPar, nkTupleConstr}
@@ -362,7 +356,6 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
of 4: awi(nkIntLit, rd(int32, x).BiggestInt)
of 8: awi(nkIntLit, rd(int64, x).BiggestInt)
else:
result = nil
globalError(conf, n.info, "cannot map value from FFI (tyEnum, tySet)")
of tyFloat: awf(nkFloatLit, rd(float, x))
of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
@@ -388,7 +381,6 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
n[0] = unpack(conf, p, typ.lastSon, n[0])
result = n
else:
result = nil
globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ))
of tyObject, tyTuple:
result = unpackObject(conf, x, typ, n)
@@ -406,7 +398,6 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
result = unpack(conf, x, typ.lastSon, n)
else:
# XXX what to do with 'array' here?
result = nil
globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ))
proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
@@ -433,7 +424,7 @@ proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
internalAssert conf, call[0].kind == nkPtrLit
var cif: TCif
var sig: ParamList = default(ParamList)
var sig: ParamList
# use the arguments' types for varargs support:
for i in 1..<call.len:
sig[i-1] = mapType(conf, call[i].typ)
@@ -445,7 +436,7 @@ proc callForeignFunction*(conf: ConfigRef, call: PNode): PNode =
mapType(conf, typ[0]), sig) != OK:
globalError(conf, call.info, "error in FFI call")
var args: ArgList = default(ArgList)
var args: ArgList
let fn = cast[pointer](call[0].intVal)
for i in 1..<call.len:
var t = call[i].typ
@@ -473,7 +464,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
internalAssert conf, fn.kind == nkPtrLit
var cif: TCif
var sig: ParamList = default(ParamList)
var sig: ParamList
for i in 0..len-1:
var aTyp = args[i+start].typ
if aTyp.isNil:
@@ -487,7 +478,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
mapType(conf, fntyp[0]), sig) != OK:
globalError(conf, info, "error in FFI call")
var cargs: ArgList = default(ArgList)
var cargs: ArgList
let fn = cast[pointer](fn.intVal)
for i in 0..len-1:
let t = args[i+start].typ

View File

@@ -10,7 +10,7 @@
## Template evaluation engine. Now hygienic.
import
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents
type
TemplCtx = object
@@ -49,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
internalAssert c.config, sfGenSym in s.flags or s.kind == skType
var x = PSym(idTableGet(c.mapping, s))
if x == nil:
x = copySym(s, c.idgen)
x = copySym(s, nextSymId(c.idgen))
# sem'check needs to set the owner properly later, see bug #9476
x.owner = nil # c.genSymOwner
#if x.kind == skParam and x.owner.kind == skModule:
@@ -187,7 +187,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
ctx.genSymOwner = genSymOwner
ctx.config = conf
ctx.ic = ic
ctx.mapping = initIdTable()
initIdTable(ctx.mapping)
ctx.instID = instID[]
ctx.idgen = idgen

View File

@@ -14,15 +14,13 @@
import ropes, platform, condsyms, options, msgs, lineinfos, pathutils, modulepaths
import std/[os, osproc, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
import std/[os, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
import std / strutils except addf
when defined(nimPreviewSlimSystem):
import std/syncio
import ../dist/checksums/src/checksums/sha1
type
TInfoCCProp* = enum # properties of the C compiler:
hasSwitchRange, # CC allows ranges in switch statements (GNU C)
@@ -486,10 +484,6 @@ proc vccplatform(conf: ConfigRef): string =
of cpuArm: " --platform:arm"
of cpuAmd64: " --platform:amd64"
else: ""
else:
result = ""
else:
result = ""
proc getLinkOptions(conf: ConfigRef): string =
result = conf.linkOptions & " " & conf.linkOptionsCmd & " "
@@ -538,7 +532,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
# NOTE: should we need the full version, use -dumpfullversion
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except IOError, OSError, ValueError: ("", 1)
if exitCode == 0:
var major: int = 0
var major: int
discard parseInt(s, major)
result = major >= 5
else:
@@ -584,7 +578,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
compilePattern = joinPath(conf.cCompilerPath, exe)
else:
compilePattern = exe
compilePattern = getCompilerExe(conf, c, isCpp)
includeCmd.add(join([CC[c].includeCmd, quoteShell(conf.projectPath.string)]))
@@ -648,7 +642,7 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
let hashFile = toGeneratedFile(conf, conf.mangleModuleName(cfile.cname).AbsoluteFile, "sha1")
let currentHash = footprint(conf, cfile)
var f: File = default(File)
var f: File
if open(f, hashFile.string, fmRead):
let oldHash = parseSecureHash(f.readLine())
close(f)
@@ -783,7 +777,6 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body
raise
proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] =
result = @[]
when defined(macosx):
if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions:
# if needed, add an option to skip or override location
@@ -839,10 +832,7 @@ proc linkViaResponseFile(conf: ConfigRef; cmd: string) =
else:
writeFile(linkerArgs, args)
try:
when defined(macosx):
execLinkCmd(conf, "xargs " & cmd.substr(0, last) & " < " & linkerArgs)
else:
execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
finally:
removeFile(linkerArgs)
@@ -866,7 +856,6 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu
result = conf.getNimcacheDir / RelativeFile(targetName)
proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string =
result = ""
if conf.hasHint(hintCC):
if optListCmd in conf.globalOptions or conf.verbosity > 1:
result = MsgKindToStr[hintCC] % (demangleModuleName(path.splitFile.name) & ": " & compileCmd)
@@ -889,15 +878,15 @@ proc preventLinkCmdMaxCmdLen(conf: ConfigRef, linkCmd: string) =
proc callCCompiler*(conf: ConfigRef) =
var
linkCmd: string = ""
linkCmd: string
extraCmds: seq[string]
if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
return # speed up that call if only compiling and no script shall be
# generated
#var c = cCompiler
var script: Rope = ""
var cmds: TStringSeq = default(TStringSeq)
var prettyCmds: TStringSeq = default(TStringSeq)
var cmds: TStringSeq
var prettyCmds: TStringSeq
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
for idx, it in conf.toCompile:
@@ -1028,9 +1017,8 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)
proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile): bool =
result = false
if not fileExists(jsonFile) or not fileExists(conf.absOutFile): return true
var bcache: BuildCache = default(BuildCache)
var bcache: BuildCache
try: bcache.fromJson(jsonFile.string.parseFile)
except IOError, OSError, ValueError:
stderr.write "Warning: JSON processing failed for: $#\n" % jsonFile.string
@@ -1046,7 +1034,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
if $secureHashFile(file) != hash: return true
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
var bcache: BuildCache = default(BuildCache)
var bcache: BuildCache
try: bcache.fromJson(jsonFile.string.parseFile)
except ValueError, KeyError, JsonKindError:
let e = getCurrentException()
@@ -1059,8 +1047,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
globalError(conf, gCmdLineInfo,
"jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " %
[outputCurrent, output, jsonFile.string])
var cmds: TStringSeq = default(TStringSeq)
var prettyCmds: TStringSeq= default(TStringSeq)
var cmds, prettyCmds: TStringSeq
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
for (name, cmd) in bcache.compile:
cmds.add cmd
@@ -1070,7 +1057,6 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting)
proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope =
result = ""
for it in list:
result.addf("--file:r\"$1\"$N", [rope(it.cname.string)])

View File

@@ -201,15 +201,17 @@ proc parseLine(p: var TTmplParser) =
proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile,
call: PNode): PLLStream =
var p = TTmplParser(config: conf, info: newLineInfo(conf, filename, 0, 0),
outp: llStreamOpen(""), inp: stdin,
subsChar: charArg(conf, call, "subschar", 1, '$'),
nimDirective: charArg(conf, call, "metachar", 2, '#'),
emit: strArg(conf, call, "emit", 3, "result.add"),
conc: strArg(conf, call, "conc", 4, " & "),
toStr: strArg(conf, call, "tostring", 5, "$"),
x: newStringOfCap(120)
)
var p: TTmplParser
p.config = conf
p.info = newLineInfo(conf, filename, 0, 0)
p.outp = llStreamOpen("")
p.inp = stdin
p.subsChar = charArg(conf, call, "subschar", 1, '$')
p.nimDirective = charArg(conf, call, "metachar", 2, '#')
p.emit = strArg(conf, call, "emit", 3, "result.add")
p.conc = strArg(conf, call, "conc", 4, " & ")
p.toStr = strArg(conf, call, "tostring", 5, "$")
p.x = newStringOfCap(120)
# do not process the first line which contains the directive:
if llStreamReadLine(p.inp, p.x):
inc p.info.line

View File

@@ -29,30 +29,23 @@ proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
return n[i]
proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkCharLit: result = chr(int(x.intVal))
else:
result = default(char)
invalidPragma(conf, n)
else: invalidPragma(conf, n)
proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
else:
result = ""
invalidPragma(conf, n)
else: invalidPragma(conf, n)
proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false
else:
result = false
invalidPragma(conf, n)
else: invalidPragma(conf, n)
proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream =
var pattern = strArg(conf, call, "startswith", 1, "")

View File

@@ -9,14 +9,12 @@
## Module that implements ``gorge`` for the compiler.
import msgs, os, osproc, streams, options,
import msgs, std / sha1, os, osproc, streams, options,
lineinfos, pathutils
when defined(nimPreviewSlimSystem):
import std/syncio
import ../dist/checksums/src/checksums/sha1
proc readOutput(p: Process): (string, int) =
result[0] = ""
var output = p.outputStream
@@ -29,11 +27,10 @@ proc readOutput(p: Process): (string, int) =
proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) =
let workingDir = parentDir(toFullPath(conf, info))
result = ("", 0)
if cache.len > 0:
let h = secureHash(cmd & "\t" & input & "\t" & cache)
let filename = toGeneratedFile(conf, AbsoluteFile("gorge_" & $h), "txt").string
var f: File = default(File)
var f: File
if optForceFullMake notin conf.globalOptions and open(f, filename):
result = (f.readAll, 0)
f.close

View File

@@ -51,10 +51,6 @@ proc isLet(n: PNode): bool =
elif n.sym.kind == skParam and skipTypes(n.sym.typ,
abstractInst).kind notin {tyVar}:
result = true
else:
result = false
else:
result = false
proc isVar(n: PNode): bool =
n.kind == nkSym and n.sym.kind in {skResult, skVar} and
@@ -140,8 +136,6 @@ proc neg(n: PNode; o: Operators): PNode =
result = a
elif b != nil:
result = b
else:
result = nil
else:
# leave not (a == 4) as it is
result = newNodeI(nkCall, n.info, 2)
@@ -336,8 +330,6 @@ proc usefulFact(n: PNode; o: Operators): PNode =
result = n
elif n[1].getMagic in someLen or n[2].getMagic in someLen:
result = n
else:
result = nil
of someLe+someLt:
if isLetLocation(n[1], true) or isLetLocation(n[2], true):
# XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
@@ -345,18 +337,12 @@ proc usefulFact(n: PNode; o: Operators): PNode =
elif n[1].getMagic in someLen or n[2].getMagic in someLen:
# XXX Rethink this whole idea of 'usefulFact' for semparallel
result = n
else:
result = nil
of mIsNil:
if isLetLocation(n[1], false) or isVar(n[1]):
result = n
else:
result = nil
of someIn:
if isLetLocation(n[1], true):
result = n
else:
result = nil
of mAnd:
let
a = usefulFact(n[1], o)
@@ -370,14 +356,10 @@ proc usefulFact(n: PNode; o: Operators): PNode =
result = a
elif b != nil:
result = b
else:
result = nil
of mNot:
let a = usefulFact(n[1], o)
if a != nil:
result = a.neg(o)
else:
result = nil
of mOr:
# 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
# with that knowledge...
@@ -394,8 +376,6 @@ proc usefulFact(n: PNode; o: Operators): PNode =
result[1] = a
result[2] = b
result = result.neg(o)
else:
result = nil
elif n.kind == nkSym and n.sym.kind == skLet:
# consider:
# let a = 2 < x
@@ -404,12 +384,8 @@ proc usefulFact(n: PNode; o: Operators): PNode =
# We make can easily replace 'a' by '2 < x' here:
if n.sym.astdef != nil:
result = usefulFact(n.sym.astdef, o)
else:
result = nil
elif n.kind == nkStmtListExpr:
result = usefulFact(n.lastSon, o)
else:
result = nil
type
TModel* = object
@@ -475,9 +451,8 @@ proc hasSubTree(n, x: PNode): bool =
of nkEmpty..nkNilLit:
result = n.sameTree(x)
of nkFormalParams:
result = false
discard
else:
result = false
for i in 0..<n.len:
if hasSubTree(n[i], x): return true
@@ -508,8 +483,6 @@ proc invalidateFacts*(m: var TModel, n: PNode) =
proc valuesUnequal(a, b: PNode): bool =
if a.isValue and b.isValue:
result = not sameValue(a, b)
else:
result = false
proc impliesEq(fact, eq: PNode): TImplication =
let (loc, val) = if isLocation(eq[1]): (1, 2) else: (2, 1)
@@ -520,26 +493,16 @@ proc impliesEq(fact, eq: PNode): TImplication =
# this is not correct; consider: a == b; a == 1 --> unknown!
if sameTree(fact[2], eq[val]): result = impYes
elif valuesUnequal(fact[2], eq[val]): result = impNo
else:
result = impUnknown
elif sameTree(fact[2], eq[loc]):
if sameTree(fact[1], eq[val]): result = impYes
elif valuesUnequal(fact[1], eq[val]): result = impNo
else:
result = impUnknown
else:
result = impUnknown
of mInSet:
# remember: mInSet is 'contains' so the set comes first!
if sameTree(fact[2], eq[loc]) and isValue(eq[val]):
if inSet(fact[1], eq[val]): result = impYes
else: result = impNo
else:
result = impUnknown
of mNot, mOr, mAnd:
result = impUnknown
assert(false, "impliesEq")
else: result = impUnknown
of mNot, mOr, mAnd: assert(false, "impliesEq")
else: discard
proc leImpliesIn(x, c, aSet: PNode): TImplication =
if c.kind in {nkCharLit..nkUInt64Lit}:
@@ -549,19 +512,13 @@ proc leImpliesIn(x, c, aSet: PNode): TImplication =
var value = newIntNode(c.kind, firstOrd(nil, x.typ))
# don't iterate too often:
if c.intVal - value.intVal < 1000:
var i, pos, neg: int = 0
var i, pos, neg: int
while value.intVal <= c.intVal:
if inSet(aSet, value): inc pos
else: inc neg
inc i; inc value.intVal
if pos == i: result = impYes
elif neg == i: result = impNo
else:
result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
proc geImpliesIn(x, c, aSet: PNode): TImplication =
if c.kind in {nkCharLit..nkUInt64Lit}:
@@ -572,23 +529,17 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
let max = lastOrd(nil, x.typ)
# don't iterate too often:
if max - getInt(value) < toInt128(1000):
var i, pos, neg: int = 0
var i, pos, neg: int
while value.intVal <= max:
if inSet(aSet, value): inc pos
else: inc neg
inc i; inc value.intVal
if pos == i: result = impYes
elif neg == i: result = impNo
else: result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
proc compareSets(a, b: PNode): TImplication =
if equalSets(nil, a, b): result = impYes
elif intersectSets(nil, a, b).len == 0: result = impNo
else: result = impUnknown
proc impliesIn(fact, loc, aSet: PNode): TImplication =
case fact[0].sym.magic
@@ -599,32 +550,22 @@ proc impliesIn(fact, loc, aSet: PNode): TImplication =
elif sameTree(fact[2], loc):
if inSet(aSet, fact[1]): result = impYes
else: result = impNo
else:
result = impUnknown
of mInSet:
if sameTree(fact[2], loc):
result = compareSets(fact[1], aSet)
else:
result = impUnknown
of someLe:
if sameTree(fact[1], loc):
result = leImpliesIn(fact[1], fact[2], aSet)
elif sameTree(fact[2], loc):
result = geImpliesIn(fact[2], fact[1], aSet)
else:
result = impUnknown
of someLt:
if sameTree(fact[1], loc):
result = leImpliesIn(fact[1], fact[2].pred, aSet)
elif sameTree(fact[2], loc):
# 4 < x --> 3 <= x
result = geImpliesIn(fact[2], fact[1].pred, aSet)
else:
result = impUnknown
of mNot, mOr, mAnd:
result = impUnknown
assert(false, "impliesIn")
else: result = impUnknown
of mNot, mOr, mAnd: assert(false, "impliesIn")
else: discard
proc valueIsNil(n: PNode): TImplication =
if n.kind == nkNilLit: impYes
@@ -636,19 +577,13 @@ proc impliesIsNil(fact, eq: PNode): TImplication =
of mIsNil:
if sameTree(fact[1], eq[1]):
result = impYes
else:
result = impUnknown
of someEq:
if sameTree(fact[1], eq[1]):
result = valueIsNil(fact[2].skipConv)
elif sameTree(fact[2], eq[1]):
result = valueIsNil(fact[1].skipConv)
else:
result = impUnknown
of mNot, mOr, mAnd:
result = impUnknown
assert(false, "impliesIsNil")
else: result = impUnknown
of mNot, mOr, mAnd: assert(false, "impliesIsNil")
else: discard
proc impliesGe(fact, x, c: PNode): TImplication =
assert isLocation(x)
@@ -659,57 +594,32 @@ proc impliesGe(fact, x, c: PNode): TImplication =
# fact: x = 4; question x >= 56? --> true iff 4 >= 56
if leValue(c, fact[2]): result = impYes
else: result = impNo
else:
result = impUnknown
elif sameTree(fact[2], x):
if isValue(fact[1]) and isValue(c):
if leValue(c, fact[1]): result = impYes
else: result = impNo
else:
result = impUnknown
else:
result = impUnknown
of someLt:
if sameTree(fact[1], x):
if isValue(fact[2]) and isValue(c):
# fact: x < 4; question N <= x? --> false iff N <= 4
if leValue(fact[2], c): result = impNo
else: result = impUnknown
# fact: x < 4; question 2 <= x? --> we don't know
else:
result = impUnknown
elif sameTree(fact[2], x):
# fact: 3 < x; question: N-1 < x ? --> true iff N-1 <= 3
if isValue(fact[1]) and isValue(c):
if leValue(c.pred, fact[1]): result = impYes
else: result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
of someLe:
if sameTree(fact[1], x):
if isValue(fact[2]) and isValue(c):
# fact: x <= 4; question x >= 56? --> false iff 4 <= 56
if leValue(fact[2], c): result = impNo
# fact: x <= 4; question x >= 2? --> we don't know
else:
result = impUnknown
else:
result = impUnknown
elif sameTree(fact[2], x):
# fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3
if isValue(fact[1]) and isValue(c):
if leValue(c, fact[1]): result = impYes
else: result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
of mNot, mOr, mAnd:
result = impUnknown
assert(false, "impliesGe")
else: result = impUnknown
of mNot, mOr, mAnd: assert(false, "impliesGe")
else: discard
proc impliesLe(fact, x, c: PNode): TImplication =
if not isLocation(x):
@@ -724,59 +634,35 @@ proc impliesLe(fact, x, c: PNode): TImplication =
# fact: x = 4; question x <= 56? --> true iff 4 <= 56
if leValue(fact[2], c): result = impYes
else: result = impNo
else:
result = impUnknown
elif sameTree(fact[2], x):
if isValue(fact[1]) and isValue(c):
if leValue(fact[1], c): result = impYes
else: result = impNo
else:
result = impUnknown
else:
result = impUnknown
of someLt:
if sameTree(fact[1], x):
if isValue(fact[2]) and isValue(c):
# fact: x < 4; question x <= N? --> true iff N-1 <= 4
if leValue(fact[2], c.pred): result = impYes
else:
result = impUnknown
# fact: x < 4; question x <= 2? --> we don't know
else:
result = impUnknown
elif sameTree(fact[2], x):
# fact: 3 < x; question: x <= 1 ? --> false iff 1 <= 3
if isValue(fact[1]) and isValue(c):
if leValue(c, fact[1]): result = impNo
else: result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
of someLe:
if sameTree(fact[1], x):
if isValue(fact[2]) and isValue(c):
# fact: x <= 4; question x <= 56? --> true iff 4 <= 56
if leValue(fact[2], c): result = impYes
else: result = impUnknown
# fact: x <= 4; question x <= 2? --> we don't know
else:
result = impUnknown
elif sameTree(fact[2], x):
# fact: 3 <= x; question: x <= 2 ? --> false iff 2 < 3
if isValue(fact[1]) and isValue(c):
if leValue(c, fact[1].pred): result = impNo
else:result = impUnknown
else:
result = impUnknown
else:
result = impUnknown
of mNot, mOr, mAnd:
result = impUnknown
assert(false, "impliesLe")
else: result = impUnknown
of mNot, mOr, mAnd: assert(false, "impliesLe")
else: discard
proc impliesLt(fact, x, c: PNode): TImplication =
# x < 3 same as x <= 2:
@@ -788,8 +674,6 @@ proc impliesLt(fact, x, c: PNode): TImplication =
let q = x.pred
if q != x:
result = impliesLe(fact, q, c)
else:
result = impUnknown
proc `~`(x: TImplication): TImplication =
case x
@@ -841,7 +725,6 @@ proc factImplies(fact, prop: PNode): TImplication =
proc doesImply*(facts: TModel, prop: PNode): TImplication =
assert prop.kind in nkCallKinds
result = impUnknown
for f in facts.s:
# facts can be invalidated, in which case they are 'nil':
if not f.isNil:
@@ -1017,7 +900,6 @@ proc applyReplacements(n: PNode; rep: TReplacements): PNode =
proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
# now check for inferrable facts: a <= b and b <= c implies a <= c
result = impUnknown
for i in 0..m.s.high:
let fact = m.s[i]
if fact != nil and fact.getMagic in someLe:
@@ -1099,7 +981,7 @@ proc addFactLt*(m: var TModel; a, b: PNode) =
proc settype(n: PNode): PType =
result = newType(tySet, ItemId(module: -1, item: -1), n.typ.owner)
var idgen: IdGenerator = nil
var idgen: IdGenerator
addSonSkipIntLit(result, n.typ, idgen)
proc buildOf(it, loc: PNode; o: Operators): PNode =

View File

@@ -10,6 +10,9 @@
# This include implements the high level optimization pass.
# included from sem.nim
when defined(nimPreviewSlimSystem):
import std/assertions
proc hlo(c: PContext, n: PNode): PNode
proc evalPattern(c: PContext, n, orig: PNode): PNode =
@@ -17,11 +20,9 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
# we need to ensure that the resulting AST is semchecked. However, it's
# awful to semcheck before macro invocation, so we don't and treat
# templates and macros as immediate in this context.
var rule: string =
if c.config.hasHint(hintPattern):
renderTree(n, {renderNoComments})
else:
""
var rule: string
if c.config.hasHint(hintPattern):
rule = renderTree(n, {renderNoComments})
let s = n[0].sym
case s.kind
of skMacro:
@@ -72,7 +73,7 @@ proc hlo(c: PContext, n: PNode): PNode =
else:
if n.kind in {nkFastAsgn, nkAsgn, nkSinkAsgn, nkIdentDefs, nkVarTuple} and
n[0].kind == nkSym and
{sfGlobal, sfPure} <= n[0].sym.flags:
{sfGlobal, sfPure} * n[0].sym.flags == {sfGlobal, sfPure}:
# do not optimize 'var g {.global} = re(...)' again!
return n
result = applyPatterns(c, n)

View File

@@ -13,8 +13,6 @@ type
vals: seq[T] # indexed by LitId
keys: seq[LitId] # indexed by hash(val)
proc initBiTable*[T](): BiTable[T] = BiTable[T](vals: @[], keys: @[])
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = (h + 1) and maxHash

View File

@@ -50,10 +50,7 @@ proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var Alive
let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p)
cgen.genTopLevelStmt(bmod, n)
let disps = finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
if disps != nil:
for disp in disps:
genProcAux(bmod, disp.sym)
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =
@@ -101,7 +98,7 @@ proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool
var f2 = rodfiles.open(asymFile.string)
f2.loadHeader()
f2.loadSection aliveSymsSection
var oldData: seq[int32] = @[]
var oldData: seq[int32]
f2.loadSeq(oldData)
f2.close
if f2.err == ok and oldData == s:

View File

@@ -40,14 +40,10 @@ proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): boo
if ({sfExportc, sfCompilerProc} * flags != {}) or
(symPtr.kind == skMethod):
result = true
else:
result = false
# XXX: This used to be a condition to:
# (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
if sfCompilerProc in flags:
c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId)
else:
result = false
template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty

View File

@@ -7,15 +7,13 @@
# distribution, for details about the copyright.
#
import hashes, tables, intsets
import hashes, tables, intsets, std/sha1
import packed_ast, bitabs, rodfiles
import ".." / [ast, idents, lineinfos, msgs, ropes, options,
pathutils, condsyms, packages, modulepaths]
#import ".." / [renderer, astalgo]
from os import removeFile, isAbsolute
import ../../dist/checksums/src/checksums/sha1
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions, formatfloat]
@@ -359,7 +357,7 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
paddingAtEnd: t.paddingAtEnd)
storeNode(p, t, n)
p.typeInst = t.typeInst.storeType(c, m)
for kid in items t:
for kid in items t.sons:
p.types.add kid.storeType(c, m)
c.addMissing t.sym
p.sym = t.sym.safeItemId(c, m)
@@ -374,7 +372,7 @@ proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib
if l.isNil: return
result.kind = l.kind
result.generated = l.generated
result.isOverridden = l.isOverridden
result.isOverriden = l.isOverriden
result.name = toLitId($l.name, m)
storeNode(result, l, path)
@@ -392,7 +390,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
assert sfForward notin s.flags
var p = PackedSym(kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic,
position: s.position, offset: s.offset, disamb: s.disamb, options: s.options,
position: s.position, offset: s.offset, options: s.options,
name: s.name.s.toLitId(m))
storeNode(p, s, ast)
@@ -413,7 +411,6 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
p.annex = toPackedLib(s.annex, c, m)
when hasFFI:
p.cname = toLitId(s.cname, m)
p.instantiatedFrom = s.instantiatedFrom.safeItemId(c, m)
# fill the reserved slot, nothing else:
m.syms[s.itemId.item] = p
@@ -814,7 +811,6 @@ proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule:
proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
tree: PackedTree; n: NodePos): PNode =
result = nil
var i = 0
for n0 in sonsReadonly(tree, n):
if i == bodyPos:
@@ -834,7 +830,6 @@ proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
options: s.options,
position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position,
offset: if s.kind in routineKinds: defaultOffset else: s.offset,
disamb: s.disamb,
name: getIdent(c.cache, g[si].fromDisk.strings[s.name])
)
@@ -852,7 +847,7 @@ proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph;
if l.name.int == 0:
result = nil
else:
result = PLib(generated: l.generated, isOverridden: l.isOverridden,
result = PLib(generated: l.generated, isOverriden: l.isOverriden,
kind: l.kind, name: rope g[si].fromDisk.strings[l.name])
loadAstBody(l, path)
@@ -877,7 +872,6 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
if externalName != "":
result.loc.r = rope externalName
result.loc.flags = s.locFlags
result.instantiatedFrom = loadSym(c, g, si, s.instantiatedFrom)
proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym =
if s == nilItemId:
@@ -919,7 +913,7 @@ proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
result.attachedOps[op] = loadSym(c, g, si, item)
result.typeInst = loadType(c, g, si, t.typeInst)
for son in items t.types:
result.addSon loadType(c, g, si, son)
result.sons.add loadType(c, g, si, son)
loadAstBody(t, n)
when false:
for gen, id in items t.methods:
@@ -1150,8 +1144,6 @@ proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache;
if it.i < it.values.len:
result = loadSym(it.decoder, g, int(module), it.values[it.i])
inc it.i
else:
result = nil
proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym =
@@ -1169,15 +1161,11 @@ proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
if it.i < it.values.len:
result = loadSym(it.decoder, g, int(module), it.values[it.i])
inc it.i
else:
result = nil
proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym =
if it.i < it.values.len:
result = loadSym(it.decoder, g, it.module, it.values[it.i])
inc it.i
else:
result = nil
iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: FileIndex;
@@ -1210,7 +1198,7 @@ proc searchForCompilerproc*(m: LoadedModule; name: string): int32 =
# ------------------------- .rod file viewer ---------------------------------
proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
var m: PackedModule = PackedModule()
var m: PackedModule
let err = loadRodFile(rodfile, m, config, ignoreConfig=true)
if err != ok:
config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err

View File

@@ -34,11 +34,7 @@ proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool =
if current.file == trackPos.file and current.line == trackPos.line:
let col = trackPos.col
if col >= current.col and col < current.col+tokenLen:
result = true
else:
result = false
else:
result = false
return true
proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool =
result = s.name != LitId(0) and

View File

@@ -45,7 +45,7 @@ type
PackedLib* = object
kind*: TLibKind
generated*: bool
isOverridden*: bool
isOverriden*: bool
name*: LitId
path*: NodeId
@@ -63,15 +63,13 @@ type
alignment*: int # for alignment
options*: TOptions
position*: int
offset*: int32
disamb*: int32
offset*: int
externalName*: LitId # instead of TLoc
locFlags*: TLocFlags
annex*: PackedLib
when hasFFI:
cname*: LitId
constraint*: NodeId
instantiatedFrom*: PackedItemId
PackedType* = object
kind*: TTypeKind
@@ -306,7 +304,6 @@ proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) =
result = (NodePos a, NodePos b, NodePos c)
proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos =
result = default(NodePos)
if tree.nodes[n.int].kind > nkNilLit:
var count = 0
for child in sonsReadonly(tree, n):

View File

@@ -215,7 +215,7 @@ proc storeHeader*(f: var RodFile) =
proc loadHeader*(f: var RodFile) =
## Loads the header which is described by `cookie`.
if f.err != ok: return
var thisCookie: array[cookie.len, byte] = default(array[cookie.len, byte])
var thisCookie: array[cookie.len, byte]
if f.f.readBytes(thisCookie, 0, thisCookie.len) != thisCookie.len:
setError f, ioFailure
elif thisCookie != cookie:
@@ -231,14 +231,13 @@ proc storeSection*(f: var RodFile; s: RodSection) =
proc loadSection*(f: var RodFile; expected: RodSection) =
## read the bytes value of s, sets and error if the section is incorrect.
if f.err != ok: return
var s: RodSection = default(RodSection)
var s: RodSection
loadPrim(f, s)
if expected != s and f.err == ok:
setError f, wrongSection
proc create*(filename: string): RodFile =
## create the file and open it for writing
result = default(RodFile)
if not open(result.f, filename, fmWrite):
setError result, cannotOpen
@@ -246,6 +245,5 @@ proc close*(f: var RodFile) = close(f.f)
proc open*(filename: string): RodFile =
## open the file for reading
result = default(RodFile)
if not open(result.f, filename, fmRead):
setError result, cannotOpen

View File

@@ -113,7 +113,6 @@ proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) =
proc splitPragmas(c: PContext, n: PNode): (PNode, seq[TSpecialWord]) =
template bail = globalError(c.config, n.info, "invalid pragma")
result = (nil, @[])
if n.kind == nkPragmaExpr:
if n.len == 2 and n[1].kind == nkPragma:
result[0] = n[0]
@@ -229,15 +228,10 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im
for i in 0..n.safeLen-1:
importForwarded(c, n[i], exceptSet, fromMod, importSet)
proc addUnique[T](x: var seq[T], y: sink T) {.noSideEffect.} =
for i in 0..high(x):
if x[i] == y: return
x.add y
proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym =
result = realModule
template createModuleAliasImpl(ident): untyped =
createModuleAlias(realModule, c.idgen, ident, n.info, c.config.options)
createModuleAlias(realModule, nextSymId c.idgen, ident, n.info, c.config.options)
if n.kind != nkImportAs: discard
elif n.len != 2 or n[1].kind != nkIdent:
localError(c.config, n.info, "module alias must be an identifier")
@@ -251,7 +245,6 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool)
result.options.incl optImportHidden
c.unusedImports.add((result, n.info))
c.importModuleMap[result.id] = realModule.id
c.importModuleLookup.mgetOrPut(result.name.id, @[]).addUnique realModule.id
proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] =
var ret: typeof(result)
@@ -308,8 +301,6 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
suggestSym(c.graph, n.info, result, c.graph.usageSym, false)
importStmtResult.add newSymNode(result, n.info)
#newStrNode(toFullPath(c.config, f), n.info)
else:
result = nil
proc afterImport(c: PContext, m: PSym) =
# fixes bug #17510, for re-exported symbols
@@ -332,24 +323,22 @@ proc evalImport*(c: PContext, n: PNode): PNode =
result = newNodeI(nkImportStmt, n.info)
for i in 0..<n.len:
let it = n[i]
if it.kind in {nkInfix, nkPrefix} and it[^1].kind == nkBracket:
let lastPos = it.len - 1
var imp = copyNode(it)
newSons(imp, it.len)
for i in 0 ..< lastPos: imp[i] = it[i]
imp[lastPos] = imp[0] # dummy entry, replaced in the loop
for x in it[lastPos]:
if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
let sep = it[0]
let dir = it[1]
var imp = newNodeI(nkInfix, it.info)
imp.add sep
imp.add dir
imp.add sep # dummy entry, replaced in the loop
for x in it[2]:
# transform `a/b/[c as d]` to `/a/b/c as d`
if x.kind == nkInfix and x[0].ident.s == "as":
var impAs = copyNode(x)
newSons(impAs, 3)
impAs[0] = x[0]
imp[lastPos] = x[1]
let impAs = copyTree(x)
imp[2] = x[1]
impAs[1] = imp
impAs[2] = x[2]
impMod(c, impAs, result)
impMod(c, imp, result)
else:
imp[lastPos] = x
imp[2] = x
impMod(c, imp, result)
else:
impMod(c, it, result)

View File

@@ -36,7 +36,6 @@ type
body: PNode
otherUsage: TLineInfo
inUncheckedAssignSection: int
inEnsureMove: int
Scope = object # we do scope-based memory management.
# a scope is comparable to an nkStmtListExpr like
@@ -67,11 +66,11 @@ proc hasDestructor(c: Con; t: PType): bool {.inline.} =
result = ast.hasDestructor(t)
when toDebug.len > 0:
# for more effective debugging
if not result and c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
if not result and c.graph.config.selectedGC in {gcArc, gcOrc}:
assert(not containsGarbageCollectedRef(t))
proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.idgen, c.owner, info)
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), nextSymId c.idgen, c.owner, info)
sym.typ = typ
s.vars.add(sym)
result = newSymNode(sym)
@@ -79,11 +78,11 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
proc nestedScope(parent: var Scope; body: PNode): Scope =
Scope(vars: @[], locals: @[], wasMoved: @[], final: @[], body: body, needsTry: false, parent: addr(parent))
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode
type
MoveOrCopyFlag = enum
IsDecl, IsExplicitSink, IsReturn
IsDecl, IsExplicitSink
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; flags: set[MoveOrCopyFlag] = {}): PNode
@@ -185,16 +184,11 @@ proc isCursor(n: PNode): bool =
template isUnpackedTuple(n: PNode): bool =
## we move out all elements of unpacked tuples,
## hence unpacked tuples themselves don't need to be destroyed
## except it's already a cursor
(n.kind == nkSym and n.sym.kind == skTemp and
n.sym.typ.kind == tyTuple and sfCursor notin n.sym.flags)
(n.kind == nkSym and n.sym.kind == skTemp and n.sym.typ.kind == tyTuple)
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFromCopy = false) =
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
if inferredFromCopy:
m.add ", which is inferred from unavailable '=copy'"
if (opname == "=" or opname == "=copy" or opname == "=dup") and ri != nil:
if (opname == "=" or opname == "=copy") and ri != nil:
m.add "; requires a copy because it's not the last read of '"
m.add renderTree(ri)
m.add '\''
@@ -216,12 +210,8 @@ proc makePtrType(c: var Con, baseType: PType): PType =
addSonSkipIntLit(result, baseType, c.idgen)
proc genOp(c: var Con; op: PSym; dest: PNode): PNode =
var addrExp: PNode
if op.typ != nil and op.typ.len > 1 and op.typ[1].kind != tyVar:
addrExp = dest
else:
addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
addrExp.add(dest)
let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
addrExp.add(dest)
result = newTree(nkCall, newSymNode(op), addrExp)
proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
@@ -259,20 +249,10 @@ proc canBeMoved(c: Con; t: PType): bool {.inline.} =
proc isNoInit(dest: PNode): bool {.inline.} =
result = dest.kind == nkSym and sfNoInit in dest.sym.flags
proc deepAliases(dest, ri: PNode): bool =
case ri.kind
of nkCallKinds, nkStmtListExpr, nkBracket, nkTupleConstr, nkObjConstr,
nkCast, nkConv, nkObjUpConv, nkObjDownConv:
for r in ri:
if deepAliases(dest, r): return true
return false
else:
return aliases(dest, ri) != no
proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
proc genSink(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or IsDecl in flags or
(isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)))) or
isNoInit(dest) or IsReturn in flags:
isNoInit(dest):
# optimize sink call into a bitwise memcopy
result = newTree(nkFastAsgn, dest, ri)
else:
@@ -283,14 +263,7 @@ proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFla
else:
# the default is to use combination of `=destroy(dest)` and
# and copyMem(dest, source). This is efficient.
if deepAliases(dest, ri):
# consider: x = x + y, it is wrong to destroy the destination first!
# tmp to support self assignments
let tmp = c.getTemp(s, dest.typ, dest.info)
result = newTree(nkStmtList, newTree(nkFastAsgn, tmp, dest), newTree(nkFastAsgn, dest, ri),
c.genDestroy(tmp))
else:
result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri))
result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri))
proc isCriticalLink(dest: PNode): bool {.inline.} =
#[
@@ -315,13 +288,13 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) =
if c.graph.config.selectedGC == gcOrc:
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(c.graph, t):
if cyclicType(t):
result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest))
proc genMarkCyclic(c: var Con; result, dest: PNode) =
if c.graph.config.selectedGC == gcOrc:
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(c.graph, t):
if cyclicType(t):
if t.kind == tyRef:
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest)
else:
@@ -335,9 +308,6 @@ proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode =
assert ri.typ != nil
proc genCopy(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag]): PNode =
if c.inEnsureMove > 0:
localError(c.graph.config, ri.info, errFailedMove, "cannot move '" & $ri &
"', which introduces an implicit copy")
let t = dest.typ
if tfHasOwned in t.flags and ri.kind != nkNilLit:
# try to improve the error message here:
@@ -366,7 +336,7 @@ proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode =
if hasDestructor(c, objType):
if getAttachedOp(c.graph, objType, attachedDestructor) != nil and
sfOverridden in getAttachedOp(c.graph, objType, attachedDestructor).flags:
sfOverriden in getAttachedOp(c.graph, objType, attachedDestructor).flags:
localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for objects with user defined destructor is not supported, object must have default destructor.
It is best to factor out piece of object that needs custom destructor into separate object or not use discriminator assignment""")
result.add newTree(nkFastAsgn, le, tmp)
@@ -394,7 +364,7 @@ proc genWasMoved(c: var Con, n: PNode): PNode =
result = genOp(c, op, n)
else:
result = newNodeI(nkCall, n.info)
result.add(newSymNode(createMagic(c.graph, c.idgen, "`=wasMoved`", mWasMoved)))
result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved)))
result.add copyTree(n) #mWasMoved does not take the address
#if n.kind != nkSym:
# message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")")
@@ -406,13 +376,13 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
# generate: (let tmp = v; reset(v); tmp)
if (not hasDestructor(c, n.typ)) and c.inEnsureMove == 0:
if not hasDestructor(c, n.typ):
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ)
result = copyTree(n)
else:
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.idgen, c.owner, n.info)
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextSymId c.idgen, c.owner, n.info)
temp.typ = n.typ
var v = newNodeI(nkLetSection, n.info)
let tempAsNode = newSymNode(temp)
@@ -425,8 +395,7 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
result.add v
let nn = skipConv(n)
if hasDestructor(c, n.typ):
c.genMarkCyclic(result, nn)
c.genMarkCyclic(result, nn)
let wasMovedCall = c.genWasMoved(nn)
result.add wasMovedCall
result.add tempAsNode
@@ -434,47 +403,22 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
proc isCapturedVar(n: PNode): bool =
let root = getRoot(n)
if root != nil: result = root.name.s[0] == ':'
else: result = false
proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let tmp = c.getTemp(s, n.typ, n.info)
if hasDestructor(c, n.typ):
let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink})
let op = getAttachedOp(c.graph, typ, attachedDup)
if op != nil and tfHasOwned notin typ.flags:
if sfError in op.flags:
c.checkForErrorPragma(n.typ, n, "=dup")
else:
let copyOp = getAttachedOp(c.graph, typ, attachedAsgn)
if copyOp != nil and sfError in copyOp.flags and
sfOverridden notin op.flags:
c.checkForErrorPragma(n.typ, n, "=dup", inferredFromCopy = true)
let src = p(n, c, s, normal)
var newCall = newTreeIT(nkCall, src.info, src.typ,
newSymNode(op),
src)
c.finishCopy(newCall, n, isFromSink = true)
result.add newTreeI(nkFastAsgn,
src.info, tmp,
newCall
)
else:
result.add c.genWasMoved(tmp)
var m = c.genCopy(tmp, n, {})
m.add p(n, c, s, normal)
c.finishCopy(m, n, isFromSink = true)
result.add m
result.add c.genWasMoved(tmp)
var m = c.genCopy(tmp, n, {})
m.add p(n, c, s, normal)
c.finishCopy(m, n, isFromSink = true)
result.add m
if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
message(c.graph.config, n.info, hintPerformance,
("passing '$1' to a sink parameter introduces an implicit copy; " &
"if possible, rearrange your program's control flow to prevent it") % $n)
if c.inEnsureMove > 0:
localError(c.graph.config, n.info, errFailedMove,
("cannot move '$1', passing '$1' to a sink parameter introduces an implicit copy") % $n)
else:
if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
if c.graph.config.selectedGC in {gcArc, gcOrc}:
assert(not containsManagedMemory(n.typ))
if n.typ.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
localError(c.graph.config, n.info, "cannot create an implicit openArray copy to be passed to a sink parameter")
@@ -510,14 +454,14 @@ proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode =
# This was already done in the sink parameter handling logic.
result = newNodeIT(nkStmtListExpr, arg.info, arg.typ)
let tmp = c.getTemp(s, arg.typ, arg.info)
result.add c.genSink(s, tmp, arg, {IsDecl})
result.add c.genSink(tmp, arg, {IsDecl})
result.add tmp
s.final.add c.genDestroy(tmp)
else:
result = arg
proc cycleCheck(n: PNode; c: var Con) =
if c.graph.config.selectedGC notin {gcArc, gcAtomicArc}: return
if c.graph.config.selectedGC != gcArc: return
var value = n[1]
if value.kind == nkClosure:
value = value[1]
@@ -718,27 +662,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false,
of nkWhen: # This should be a "when nimvm" node.
result = copyTree(n)
result[1][0] = processCall(n[1][0], s)
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
result = shallowCopy(n)
inc c.inUncheckedAssignSection, inUncheckedAssignSection
for i in 0 ..< n.len-1:
result[i] = p(n[i], c, s, normal)
result[^1] = maybeVoid(n[^1], s)
dec c.inUncheckedAssignSection, inUncheckedAssignSection
else:
result = nil
assert(false)
else: assert(false)
proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
@@ -765,9 +689,9 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
result.add copyNode(n[0])
s.needsTry = true
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode =
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode =
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt}:
template process(child, s): untyped = p(child, c, s, mode)
handleNestedTempl(n, process, tmpFlags = tmpFlags)
elif mode == sinkArg:
@@ -778,15 +702,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
result = passCopyToSink(n, c, s)
elif n.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure, nkNilLit} +
nkCallKinds + nkLiterals:
if n.kind in nkCallKinds and n[0].kind == nkSym:
if n[0].sym.magic == mEnsureMove:
inc c.inEnsureMove
result = p(n[1], c, s, sinkArg)
dec c.inEnsureMove
else:
result = p(n, c, s, consumed)
else:
result = p(n, c, s, consumed)
result = p(n, c, s, consumed)
elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and
isLastRead(n, c, s) and not (n.kind == nkSym and isCursor(n)):
# Sinked params can be consumed only once. We need to reset the memory
@@ -858,12 +774,6 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if mode == normal and isRefConstr:
result = ensureDestruction(result, n, c, s)
of nkCallKinds:
if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
inc c.inEnsureMove
result = p(n[1], c, s, sinkArg)
dec c.inEnsureMove
return
let inSpawn = c.inSpawn
if n[0].kind == nkSym and n[0].sym.magic == mSpawn:
c.inSpawn.inc
@@ -894,7 +804,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}:
result[0] = copyTree(n[0])
if c.graph.config.selectedGC in {gcHooks, gcArc, gcAtomicArc, gcOrc}:
if c.graph.config.selectedGC in {gcHooks, gcArc, gcOrc}:
let destroyOld = c.genDestroy(result[1])
result = newTree(nkStmtList, destroyOld, result)
else:
@@ -949,9 +859,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
cycleCheck(n, c)
assert n[1].kind notin {nkAsgn, nkFastAsgn, nkSinkAsgn}
var flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
if inReturn:
flags.incl(IsReturn)
let flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s, flags)
elif isDiscriminantField(n[0]):
result = c.genDiscriminantAsgn(s, n)
@@ -979,6 +887,25 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if mode == normal:
result = ensureDestruction(result, n, c, s)
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
result = shallowCopy(n)
inc c.inUncheckedAssignSection, inUncheckedAssignSection
for i in 0 ..< n.len:
result[i] = p(n[i], c, s, normal)
dec c.inUncheckedAssignSection, inUncheckedAssignSection
if n.typ != nil and hasDestructor(c, n.typ):
if mode == normal:
result = ensureDestruction(result, n, c, s)
of nkHiddenSubConv, nkHiddenStdConv, nkConv:
# we have an "ownership invariance" for all constructors C(x).
# See the comment for nkBracket construction. If the caller wants
@@ -1035,7 +962,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
of nkReturnStmt:
result = shallowCopy(n)
for i in 0..<n.len:
result[i] = p(n[i], c, s, mode, inReturn=true)
result[i] = p(n[i], c, s, mode)
s.needsTry = true
of nkCast:
result = shallowCopy(n)
@@ -1049,12 +976,11 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
of nkGotoState, nkState, nkAsmStmt:
result = n
else:
result = nil
internalError(c.graph.config, n.info, "cannot inject destructors to node kind: " & $n.kind)
proc sameLocation*(a, b: PNode): bool =
proc sameConstant(a, b: PNode): bool =
a.kind in nkLiterals and b.kind in nkLiterals and a.intVal == b.intVal
a.kind in nkLiterals and a.intVal == b.intVal
const nkEndPoint = {nkSym, nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}
if a.kind in nkEndPoint and b.kind in nkEndPoint:
@@ -1078,9 +1004,9 @@ proc sameLocation*(a, b: PNode): bool =
of nkHiddenStdConv, nkHiddenSubConv: sameLocation(a[1], b)
else: false
proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
# with side effects
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), c.idgen, c.owner, ri[1].info)
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), nextSymId c.idgen, c.owner, ri[1].info)
temp.typ = ri[1].typ
var v = newNodeI(nkLetSection, ri[1].info)
let tempAsNode = newSymNode(temp)
@@ -1095,22 +1021,14 @@ proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags:
newAccess.add ri[0]
newAccess.add tempAsNode
var snk = c.genSink(s, dest, newAccess, flags)
var snk = c.genSink(dest, newAccess, flags)
result = newTree(nkStmtList, v, snk, c.genWasMoved(newAccess))
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopyFlag] = {}): PNode =
var ri = ri
var isEnsureMove = 0
if ri.kind in nkCallKinds and ri[0].kind == nkSym and ri[0].sym.magic == mEnsureMove:
ri = ri[1]
isEnsureMove = 1
if sameLocation(dest, ri):
# rule (self-assignment-removal):
result = newNodeI(nkEmpty, dest.info)
elif isCursor(dest) or dest.typ.kind in {tyOpenArray, tyVarargs}:
# hoisted openArray parameters might end up here
# openArray types don't have a lifted assignment operation (it's empty)
# bug #22132
elif isCursor(dest):
case ri.kind:
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags)
@@ -1119,61 +1037,53 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
else:
result = newTree(nkFastAsgn, dest, p(ri, c, s, normal))
else:
let ri2 = if ri.kind == nkWhen: ri[1][0] else: ri
case ri2.kind
case ri.kind
of nkCallKinds:
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
result = c.genSink(dest, p(ri, c, s, consumed), flags)
of nkBracketExpr:
if isUnpackedTuple(ri[0]):
# unpacking of tuple: take over the elements
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
result = c.genSink(dest, p(ri, c, s, consumed), flags)
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s):
if aliases(dest, ri) == no:
# Rule 3: `=sink`(x, z); wasMoved(z)
if isAtom(ri[1]):
var snk = c.genSink(s, dest, ri, flags)
var snk = c.genSink(dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
else:
result = genFieldAccessSideEffects(c, s, dest, ri, flags)
result = genFieldAccessSideEffects(c, dest, ri, flags)
else:
result = c.genSink(s, dest, destructiveMoveVar(ri, c, s), flags)
result = c.genSink(dest, destructiveMoveVar(ri, c, s), flags)
else:
inc c.inEnsureMove, isEnsureMove
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
of nkBracket:
# array constructor
if ri.len > 0 and isDangerousSeq(ri.typ):
inc c.inEnsureMove, isEnsureMove
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
else:
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
result = c.genSink(dest, p(ri, c, s, consumed), flags)
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
result = c.genSink(dest, p(ri, c, s, consumed), flags)
of nkSym:
if isSinkParam(ri.sym) and isLastRead(ri, c, s):
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(s, dest, ri, flags)
let snk = c.genSink(dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri) and
not ({sfGlobal, sfPure} <= ri.sym.flags):
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri):
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(s, dest, ri, flags)
let snk = c.genSink(dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
else:
inc c.inEnsureMove, isEnsureMove
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast:
result = c.genSink(s, dest, p(ri, c, s, sinkArg), flags)
result = c.genSink(dest, p(ri, c, s, sinkArg), flags)
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags)
# We know the result will be a stmt so we use that fact to optimize
@@ -1184,12 +1094,10 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s) and
canBeMoved(c, dest.typ):
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(s, dest, ri, flags)
let snk = c.genSink(dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
else:
inc c.inEnsureMove, isEnsureMove
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)

View File

@@ -78,7 +78,6 @@ Files: "lib"
[Other]
Files: "examples"
Files: "dist/nimble"
Files: "dist/checksums"
Files: "tests"
@@ -92,7 +91,6 @@ Files: "bin/nimgrab.exe"
Files: "bin/nimpretty.exe"
Files: "bin/testament.exe"
Files: "bin/nim-gdb.bat"
Files: "bin/atlas.exe"
Files: "koch.exe"
Files: "finish.exe"

View File

@@ -171,7 +171,6 @@ proc addToHex*(result: var string; arg: Int128) =
i -= 1
proc toHex*(arg: Int128): string =
result = ""
result.addToHex(arg)
proc inc*(a: var Int128, y: uint32 = 1) =
@@ -331,8 +330,8 @@ proc `*`*(a: Int128, b: int32): Int128 =
if b < 0:
result = -result
proc `*=`(a: var Int128, b: int32) =
a = a * b
proc `*=`*(a: var Int128, b: int32): Int128 =
result = result * b
proc makeInt128(high, low: uint64): Int128 =
result.udata[0] = cast[uint32](low)
@@ -361,7 +360,6 @@ proc `*=`*(a: var Int128, b: Int128) =
import bitops
proc fastLog2*(a: Int128): int =
result = 0
if a.udata[3] != 0:
return 96 + fastLog2(a.udata[3])
if a.udata[2] != 0:
@@ -573,4 +571,4 @@ proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} =
of 8:
return maskUInt64(arg)
else:
raiseAssert "masking only implemented for 1, 2, 4 and 8 bytes"
assert(false, "masking only implemented for 1, 2, 4 and 8 bytes")

View File

@@ -21,7 +21,6 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool
proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
case n.kind
of nkRecList:
result = false
for i in 0..<n.len:
result = canAliasN(arg, n[i], marker)
if result: return
@@ -37,7 +36,7 @@ proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
else: discard
of nkSym:
result = canAlias(arg, n.sym.typ, marker)
else: result = false
else: discard
proc canAlias(arg, ret: PType; marker: var IntSet): bool =
if containsOrIncl(marker, ret.id):
@@ -57,7 +56,6 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool =
else:
result = true
of tyTuple:
result = false
for i in 0..<ret.len:
result = canAlias(arg, ret[i], marker)
if result: break
@@ -74,69 +72,6 @@ proc isValueOnlyType(t: PType): bool =
proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr, tyVar, tyLent}
result = not types.searchTypeFor(t, wrap)
type
SearchResult = enum
NotFound, Abort, Found
proc containsDangerousRefAux(t: PType; marker: var IntSet): SearchResult
proc containsDangerousRefAux(n: PNode; marker: var IntSet): SearchResult =
result = NotFound
case n.kind
of nkRecList:
for i in 0..<n.len:
result = containsDangerousRefAux(n[i], marker)
if result == Found: return result
of nkRecCase:
assert(n[0].kind == nkSym)
result = containsDangerousRefAux(n[0], marker)
if result == Found: return result
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
result = containsDangerousRefAux(lastSon(n[i]), marker)
if result == Found: return result
else: discard
of nkSym:
result = containsDangerousRefAux(n.sym.typ, marker)
else: discard
proc containsDangerousRefAux(t: PType; marker: var IntSet): SearchResult =
result = NotFound
if t == nil: return result
if containsOrIncl(marker, t.id): return result
if t.kind == tyRef or (t.kind == tyProc and t.callConv == ccClosure):
result = Found
elif tfSendable in t.flags:
result = Abort
else:
# continue the type traversal:
result = NotFound
if result != NotFound: return result
case t.kind
of tyObject:
if t[0] != nil:
result = containsDangerousRefAux(t[0].skipTypes(skipPtrs), marker)
if result == NotFound: result = containsDangerousRefAux(t.n, marker)
of tyGenericInst, tyDistinct, tyAlias, tySink:
result = containsDangerousRefAux(lastSon(t), marker)
of tyArray, tySet, tyTuple, tySequence:
for i in 0..<t.len:
result = containsDangerousRefAux(t[i], marker)
if result == Found: return result
else:
discard
proc containsDangerousRef(t: PType): bool =
# a `ref` type is "dangerous" if it occurs not within a type that is like `Isolated[T]`.
# For example:
# `ref int` # dangerous
# `Isolated[ref int]` # not dangerous
var marker = initIntSet()
result = containsDangerousRefAux(t, marker) == Found
proc canAlias*(arg, ret: PType): bool =
if isValueOnlyType(arg):
# can alias only with addr(arg.x) and we don't care if it is not safe
@@ -145,15 +80,12 @@ proc canAlias*(arg, ret: PType): bool =
var marker = initIntSet()
result = canAlias(arg, ret, marker)
const
SomeVar = {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
proc containsVariable(n: PNode): bool =
case n.kind
of nodesToIgnoreSet:
result = false
of nkSym:
result = n.sym.kind in SomeVar
result = n.sym.kind in {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
else:
for ch in n:
if containsVariable(ch): return true
@@ -177,7 +109,7 @@ proc checkIsolate*(n: PNode): bool =
discard "fine, it is isolated already"
else:
let argType = n[i].typ
if argType != nil and not isCompileTimeOnly(argType) and containsDangerousRef(argType):
if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType):
if argType.canAlias(n.typ) or containsVariable(n[i]):
# bug #19013: Alias information is not enough, we need to check for potential
# "overlaps". I claim the problem can only happen by reading again from a location
@@ -186,12 +118,10 @@ proc checkIsolate*(n: PNode): bool =
return false
result = true
of nkIfStmt, nkIfExpr:
result = false
for it in n:
result = checkIsolate(it.lastSon)
if not result: break
of nkCaseStmt:
result = false
for i in 1..<n.len:
result = checkIsolate(n[i].lastSon)
if not result: break
@@ -201,7 +131,6 @@ proc checkIsolate*(n: PNode): bool =
result = checkIsolate(n[i].lastSon)
if not result: break
of nkBracket, nkTupleConstr, nkPar:
result = false
for it in n:
result = checkIsolate(it)
if not result: break
@@ -214,12 +143,6 @@ proc checkIsolate*(n: PNode): bool =
result = checkIsolate(n[^1])
else:
result = false
of nkSym:
result = true
if n.sym.kind in SomeVar:
let argType = n.typ
if argType != nil and not isCompileTimeOnly(argType) and containsDangerousRef(argType):
result = false
else:
# unanalysable expression:
result = false

File diff suppressed because it is too large Load Diff

View File

@@ -140,7 +140,7 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator)
rawAddSon(result, intType)
proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym =
result = newSym(skField, getIdent(g.cache, ":state"), idgen, iter, iter.info)
result = newSym(skField, getIdent(g.cache, ":state"), nextSymId(idgen), iter, iter.info)
result.typ = createClosureIterStateType(g, iter, idgen)
proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType =
@@ -154,7 +154,7 @@ proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym
result = iter.ast[resultPos].sym
else:
# XXX a bit hacky:
result = newSym(skResult, getIdent(g.cache, ":result"), idgen, iter, iter.info, {})
result = newSym(skResult, getIdent(g.cache, ":result"), nextSymId(idgen), iter, iter.info, {})
result.typ = iter.typ[0]
incl(result.flags, sfUsed)
iter.ast.add newSymNode(result)
@@ -187,8 +187,6 @@ proc getEnvParam*(routine: PSym): PSym =
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
result = hidden.sym
assert sfFromGeneric in result.flags
else:
result = nil
proc interestingVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and
@@ -201,8 +199,6 @@ proc illegalCapture(s: PSym): bool {.inline.} =
proc isInnerProc(s: PSym): bool =
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone:
result = s.skipGenericOwner.kind in routineKinds
else:
result = false
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
# Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
@@ -271,7 +267,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache, idgen)
env = indirectAccess(newSymNode(it), hp, hp.info)
else:
let e = newSym(skLet, iter.name, idgen, owner, n.info)
let e = newSym(skLet, iter.name, nextSymId(idgen), owner, n.info)
e.typ = hp.typ
e.flags = hp.flags
env = newSymNode(e)
@@ -297,34 +293,33 @@ proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner:
proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
let s = n.sym
let isEnv = s.name.id == getIdent(g.cache, ":env").id
if illegalCapture(s):
localError(g.config, n.info,
("'$1' is of type <$2> which cannot be captured as it would violate memory" &
" safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases." &
" Consider using a <ref $2> which can be captured.") %
[s.name.s, typeToString(s.typ), g.config$s.info])
elif not (owner.typ.isClosure or owner.isNimcall and not owner.isExplicitCallConv or isEnv):
elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags):
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
[s.name.s, owner.name.s, $owner.typ.callConv])
incl(owner.typ.flags, tfCapturesEnv)
if not isEnv:
owner.typ.callConv = ccClosure
owner.typ.callConv = ccClosure
type
DetectionPass = object
processed, capturedVars: IntSet
ownerToType: Table[int, PType]
somethingToDo: bool
inTypeOf: bool
graph: ModuleGraph
idgen: IdGenerator
proc initDetectionPass(g: ModuleGraph; fn: PSym; idgen: IdGenerator): DetectionPass =
result = DetectionPass(processed: toIntSet([fn.id]),
capturedVars: initIntSet(), ownerToType: initTable[int, PType](),
graph: g, idgen: idgen
)
result.processed = initIntSet()
result.capturedVars = initIntSet()
result.ownerToType = initTable[int, PType]()
result.processed.incl(fn.id)
result.graph = g
result.idgen = idgen
discard """
proc outer =
@@ -385,7 +380,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags:
localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor")
else:
let result = newSym(skField, upIdent, c.idgen, obj.owner, obj.owner.info)
let result = newSym(skField, upIdent, nextSymId(c.idgen), obj.owner, obj.owner.info)
result.typ = fieldType
when false:
if c.graph.config.selectedGC == gcDestructors:
@@ -418,15 +413,12 @@ Consider:
"""
proc isTypeOf(n: PNode): bool =
n.kind == nkSym and n.sym.magic in {mTypeOf, mType}
proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
var cp = getEnvParam(fn)
let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner
let t = c.getEnvTypeForOwner(owner, info)
if cp == nil:
cp = newSym(skParam, getIdent(c.graph.cache, paramName), c.idgen, fn, fn.info)
cp = newSym(skParam, getIdent(c.graph.cache, paramName), nextSymId(c.idgen), fn, fn.info)
incl(cp.flags, sfFromGeneric)
cp.typ = t
addHiddenParam(fn, cp)
@@ -452,15 +444,12 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
let body = transformBody(c.graph, c.idgen, s, useCache)
detectCapturedVars(body, s, c)
let ow = s.skipGenericOwner
let innerClosure = innerProc and s.typ.callConv == ccClosure and not s.isIterator
let interested = interestingVar(s)
if ow == owner:
if owner.isIterator:
c.somethingToDo = true
addClosureParam(c, owner, n.info)
if interestingIterVar(s):
if not c.capturedVars.contains(s.id):
if not c.inTypeOf: c.capturedVars.incl(s.id)
if not c.capturedVars.containsOrIncl(s.id):
let obj = getHiddenParam(c.graph, owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
#let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr})
@@ -469,7 +458,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
else:
discard addField(obj, s, c.graph.cache, c.idgen)
# direct or indirect dependency:
elif innerClosure or interested:
elif (innerProc and not s.isIterator and s.typ.callConv == ccClosure) or interestingVar(s):
discard """
proc outer() =
var x: int
@@ -486,12 +475,10 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
addClosureParam(c, owner, n.info)
#echo "capturing ", n.info
# variable 's' is actually captured:
if interestingVar(s):
if not c.capturedVars.contains(s.id):
if not c.inTypeOf: c.capturedVars.incl(s.id)
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr})
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
discard addField(obj, s, c.graph.cache, c.idgen)
if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id):
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr})
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
discard addField(obj, s, c.graph.cache, c.idgen)
# create required upFields:
var w = owner.skipGenericOwner
if isInnerProc(w) or owner.isIterator:
@@ -523,14 +510,9 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
detectCapturedVars(n[namePos], owner, c)
of nkReturnStmt:
detectCapturedVars(n[0], owner, c)
of nkIdentDefs:
detectCapturedVars(n[^1], owner, c)
else:
if n.isCallExpr and n[0].isTypeOf:
c.inTypeOf = true
for i in 0..<n.len:
detectCapturedVars(n[i], owner, c)
c.inTypeOf = false
type
LiftingPass = object
@@ -540,8 +522,9 @@ type
unownedEnvVars: Table[int, PNode] # only required for --newruntime
proc initLiftingPass(fn: PSym): LiftingPass =
result = LiftingPass(processed: toIntSet([fn.id]),
envVars: initTable[int, PNode]())
result.processed = initIntSet()
result.processed.incl(fn.id)
result.envVars = initTable[int, PNode]()
proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let s = n.sym
@@ -562,7 +545,7 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
result = n
proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idgen: IdGenerator): PNode =
var v = newSym(skVar, getIdent(cache, envName), idgen, owner, info)
var v = newSym(skVar, getIdent(cache, envName), nextSymId(idgen), owner, info)
v.flags = {sfShadowed, sfGeneratedOp}
v.typ = typ
result = newSymNode(v)
@@ -586,7 +569,7 @@ proc setupEnvVar(owner: PSym; d: var DetectionPass;
result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info, d.idgen)
c.envVars[owner.id] = result
if optOwnedRefs in d.graph.config.globalOptions:
var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), d.idgen, owner, info)
var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextSymId d.idgen, owner, info)
v.flags = {sfShadowed, sfGeneratedOp}
v.typ = envVarType
c.unownedEnvVars[owner.id] = newSymNode(v)
@@ -670,7 +653,7 @@ proc closureCreationForIter(iter: PNode;
d: var DetectionPass; c: var LiftingPass): PNode =
result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ)
let owner = iter.sym.skipGenericOwner
var v = newSym(skVar, getIdent(d.graph.cache, envName), d.idgen, owner, iter.info)
var v = newSym(skVar, getIdent(d.graph.cache, envName), nextSymId(d.idgen), owner, iter.info)
incl(v.flags, sfShadowed)
v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ)
var vnode: PNode
@@ -728,7 +711,6 @@ proc symToClosure(n: PNode; owner: PSym; d: var DetectionPass;
# direct dependency, so use the outer's env variable:
result = makeClosure(d.graph, d.idgen, s, setupEnvVar(owner, d, c, n.info), n.info)
else:
result = nil
let available = getHiddenParam(d.graph, owner)
let wanted = getHiddenParam(d.graph, s).typ
# ugh: call through some other inner proc;
@@ -810,8 +792,6 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
of nkTypeOfExpr:
result = n
else:
if n.isCallExpr and n[0].isTypeOf:
return
if owner.isIterator:
if nfLL in n.flags:
# special case 'when nimVm' due to bug #3636:
@@ -956,14 +936,14 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
result = newNodeI(nkStmtList, body.info)
# static binding?
var env: PSym = nil
var env: PSym
let op = call[0]
if op.kind == nkSym and op.sym.isIterator:
# createClosure()
let iter = op.sym
let hp = getHiddenParam(g, iter)
env = newSym(skLet, iter.name, idgen, owner, body.info)
env = newSym(skLet, iter.name, nextSymId(idgen), owner, body.info)
env.typ = hp.typ
env.flags = hp.flags

View File

@@ -510,7 +510,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
rememberSplit(splitComma)
wrSpace em
of openPars:
if tsLeading in tok.spacing and not em.endsInWhite and
if tok.strongSpaceA and not em.endsInWhite and
(not em.wasExportMarker or tok.tokType == tkCurlyDotLe):
wrSpace em
wr(em, $tok.tokType, ltSomeParLe)
@@ -528,7 +528,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
wr(em, $tok.tokType, ltOther)
if not em.inquote: wrSpace(em)
of tkOpr, tkDotDot:
if em.inquote or (tok.spacing == {} and
if em.inquote or (((not tok.strongSpaceA) and tok.strongSpaceB == tsNone) and
tok.ident.s notin ["<", ">", "<=", ">=", "==", "!="]):
# bug #9504: remember to not spacify a keyword:
lastTokWasTerse = true
@@ -538,7 +538,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
if not em.endsInWhite: wrSpace(em)
wr(em, tok.ident.s, ltOpr)
template isUnary(tok): bool =
tok.spacing == {tsLeading}
tok.strongSpaceB == tsNone and tok.strongSpaceA
if not isUnary(tok):
rememberSplit(splitBinary)

View File

@@ -23,6 +23,7 @@ when defined(nimPreviewSlimSystem):
import std/[assertions, formatfloat]
const
MaxLineLength* = 80 # lines longer than this lead to a warning
numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'}
SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
@@ -93,18 +94,19 @@ type
base2, base8, base16
TokenSpacing* = enum
tsLeading, tsTrailing, tsEof
tsNone, tsTrailing, tsEof
Token* = object # a Nim token
tokType*: TokType # the type of the token
base*: NumericalBase # the numerical base; only valid for int
# or float literals
spacing*: set[TokenSpacing] # spaces around token
indent*: int # the indentation; != -1 if the token has been
# preceded with indentation
ident*: PIdent # the parsed identifier
iNumber*: BiggestInt # the parsed integer literal
fNumber*: BiggestFloat # the parsed floating point literal
base*: NumericalBase # the numerical base; only valid for int
# or float literals
strongSpaceA*: bool # leading spaces of an operator
strongSpaceB*: TokenSpacing # trailing spaces of an operator
literal*: string # the parsed (string) literal; and
# documentation comments are here too
line*, col*: int
@@ -148,11 +150,9 @@ proc isNimIdentifier*(s: string): bool =
var i = 1
while i < sLen:
if s[i] == '_': inc(i)
if i < sLen and s[i] notin SymChars: return false
if i < sLen and s[i] notin SymChars: return
inc(i)
result = true
else:
result = false
proc `$`*(tok: Token): string =
case tok.tokType
@@ -178,7 +178,7 @@ proc initToken*(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
L.spacing = {}
L.strongSpaceA = false
L.literal = ""
L.fNumber = 0.0
L.base = base10
@@ -191,7 +191,7 @@ proc fillToken(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
L.spacing = {}
L.strongSpaceA = false
setLen(L.literal, 0)
L.fNumber = 0.0
L.base = base10
@@ -539,8 +539,8 @@ proc getNumber(L: var Lexer, result: var Token) =
of floatTypes:
result.fNumber = parseFloat(result.literal)
of tkUInt64Lit, tkUIntLit:
var iNumber: uint64 = uint64(0)
var len: int = 0
var iNumber: uint64
var len: int
try:
len = parseBiggestUInt(result.literal, iNumber)
except ValueError:
@@ -549,8 +549,8 @@ proc getNumber(L: var Lexer, result: var Token) =
raise newException(ValueError, "invalid integer: " & result.literal)
result.iNumber = cast[int64](iNumber)
else:
var iNumber: int64 = int64(0)
var len: int = 0
var iNumber: int64
var len: int
try:
len = parseBiggestInt(result.literal, iNumber)
except ValueError:
@@ -737,6 +737,10 @@ proc handleCRLF(L: var Lexer, pos: int): int =
template registerLine =
let col = L.getColNumber(pos)
when not defined(nimpretty):
if col > MaxLineLength:
lexMessagePos(L, hintLineTooLong, pos)
case L.buf[pos]
of CR:
registerLine()
@@ -956,15 +960,13 @@ proc getOperator(L: var Lexer, tok: var Token) =
tokenEnd(tok, pos-1)
# advance pos but don't store it in L.bufpos so the next token (which might
# be an operator too) gets the preceding spaces:
tok.spacing = tok.spacing - {tsTrailing, tsEof}
var trailing = false
tok.strongSpaceB = tsNone
while L.buf[pos] == ' ':
inc pos
trailing = true
if tok.strongSpaceB != tsTrailing:
tok.strongSpaceB = tsTrailing
if L.buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
tok.spacing.incl(tsEof)
elif trailing:
tok.spacing.incl(tsTrailing)
tok.strongSpaceB = tsEof
proc getPrecedence*(tok: Token): int =
## Calculates the precedence of the given token.
@@ -1009,7 +1011,6 @@ proc getPrecedence*(tok: Token): int =
else: return -10
proc newlineFollows*(L: Lexer): bool =
result = false
var pos = L.bufpos
while true:
case L.buf[pos]
@@ -1076,6 +1077,7 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
when defined(nimpretty): tok.literal.add "\L"
if isDoc:
when not defined(nimpretty): tok.literal.add "\n"
inc tok.iNumber
var c = toStrip
while L.buf[pos] == ' ' and c > 0:
inc pos
@@ -1094,6 +1096,8 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
proc scanComment(L: var Lexer, tok: var Token) =
var pos = L.bufpos
tok.tokType = tkComment
# iNumber contains the number of '\n' in the token
tok.iNumber = 0
assert L.buf[pos+1] == '#'
when defined(nimpretty):
tok.commentOffsetA = L.offsetBase + pos
@@ -1136,6 +1140,7 @@ proc scanComment(L: var Lexer, tok: var Token) =
while L.buf[pos] == ' ' and c > 0:
inc pos
dec c
inc tok.iNumber
else:
if L.buf[pos] > ' ':
L.indentAhead = indent
@@ -1148,7 +1153,7 @@ proc scanComment(L: var Lexer, tok: var Token) =
proc skip(L: var Lexer, tok: var Token) =
var pos = L.bufpos
tokenBegin(tok, pos)
tok.spacing.excl(tsLeading)
tok.strongSpaceA = false
when defined(nimpretty):
var hasComment = false
var commentIndent = L.currLineIndent
@@ -1159,7 +1164,8 @@ proc skip(L: var Lexer, tok: var Token) =
case L.buf[pos]
of ' ':
inc(pos)
tok.spacing.incl(tsLeading)
if not tok.strongSpaceA:
tok.strongSpaceA = true
of '\t':
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead")
inc(pos)
@@ -1181,7 +1187,7 @@ proc skip(L: var Lexer, tok: var Token) =
pos = L.bufpos
else:
break
tok.spacing.excl(tsLeading)
tok.strongSpaceA = false
when defined(nimpretty):
if L.buf[pos] == '#' and tok.line < 0: commentIndent = indent
if L.buf[pos] > ' ' and (L.buf[pos] != '#' or L.buf[pos+1] == '#'):
@@ -1397,9 +1403,8 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef): int =
result = 0
var lex: Lexer = default(Lexer)
var tok: Token = default(Token)
var lex: Lexer
var tok: Token
initToken(tok)
openLexer(lex, fileIdx, inputstream, cache, config)
var prevToken = tkEof

View File

@@ -8,7 +8,7 @@
#
## This module implements lifting for type-bound operations
## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`).
## (``=sink``, ``=copy``, ``=destroy``, ``=deepCopy``).
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils
@@ -34,7 +34,6 @@ type
template destructor*(t: PType): PSym = getAttachedOp(c.g, t, attachedDestructor)
template assignment*(t: PType): PSym = getAttachedOp(c.g, t, attachedAsgn)
template dup*(t: PType): PSym = getAttachedOp(c.g, t, attachedDup)
template asink*(t: PType): PSym = getAttachedOp(c.g, t, attachedSink)
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
@@ -50,9 +49,9 @@ proc at(a, i: PNode, elemType: PType): PNode =
result[1] = i
result.typ = elemType
proc destructorOverridden(g: ModuleGraph; t: PType): bool =
proc destructorOverriden(g: ModuleGraph; t: PType): bool =
let op = getAttachedOp(g, t, attachedDestructor)
op != nil and sfOverridden in op.flags
op != nil and sfOverriden in op.flags
proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
for i in 0..<t.len:
@@ -83,14 +82,14 @@ proc genBuiltin(c: var TLiftCtx; magic: TMagic; name: string; i: PNode): PNode =
result = genBuiltin(c.g, c.idgen, magic, name, i)
proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink, attachedDup}:
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
body.add newAsgnStmt(x, y)
elif c.kind == attachedDestructor and c.addMemReset:
let call = genBuiltin(c, mDefault, "default", x)
call.typ = t
body.add newAsgnStmt(x, call)
elif c.kind == attachedWasMoved:
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc genAddr(c: var TLiftCtx; x: PNode): PNode =
if x.kind == nkHiddenDeref:
@@ -140,14 +139,11 @@ proc genContainerOf(c: var TLiftCtx; objType: PType, field, x: PSym): PNode =
proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
var destroy = newNodeIT(nkCall, x.info, op.typ[0])
destroy.add(newSymNode(op))
if op.typ[1].kind != tyVar:
destroy.add x
else:
destroy.add genAddr(c, x)
destroy.add genAddr(c, x)
if sfNeverRaises notin op.flags:
c.canRaise = true
if c.addMemReset:
result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "`=wasMoved`", x))
result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "wasMoved", x))
else:
result = destroy
@@ -162,7 +158,8 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
if c.filterDiscriminator != nil: return
let f = n.sym
let b = if c.kind == attachedTrace: y else: y.dotField(f)
if (sfCursor in f.flags and c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
c.g.config.selectedGC in {gcArc, gcOrc, gcHooks}) or
enforceDefaultOp:
defaultOp(c, f.typ, body, x.dotField(f), b)
else:
@@ -246,7 +243,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
# for every field (dependent on dest.kind):
# `=` dest.field, src.field
# =destroy(blob)
var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info)
dummy.typ = y.typ
if ccgIntroducedPtr(c.g.config, dummy, y.typ):
# Because of potential aliasing when the src param is passed by ref, we need to check for equality here,
@@ -255,7 +252,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x), newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y))
cond.typ = getSysType(c.g, x.info, tyBool)
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info)
temp.typ = x.typ
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info)
@@ -265,7 +262,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
#body.add newAsgnStmt(blob, x)
var wasMovedCall = newNodeI(nkCall, c.info)
wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "`=wasMoved`", mWasMoved)))
wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "wasMoved", mWasMoved)))
wasMovedCall.add x # mWasMoved does not take the address
body.add wasMovedCall
@@ -286,7 +283,7 @@ proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
result.typ = getSysType(g, info, tyBool)
proc getCycleParam(c: TLiftCtx): PNode =
assert c.kind in {attachedAsgn, attachedDup}
assert c.kind == attachedAsgn
if c.fn.typ.len == 4:
result = c.fn.typ.n.lastSon
assert result.kind == nkSym
@@ -301,7 +298,7 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result.add newSymNode(op)
if sfNeverRaises notin op.flags:
c.canRaise = true
if op.typ[1].kind == tyVar:
if op.typ.sons[1].kind == tyVar:
result.add genAddr(c, x)
else:
result.add x
@@ -325,9 +322,6 @@ proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
proc newDeepCopyCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(c, op, y))
proc newDupCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(c, op, y))
proc usesBuiltinArc(t: PType): bool =
proc wrap(t: PType): bool {.nimcall.} = ast.isGCedMem(t)
result = types.searchTypeFor(t, wrap)
@@ -352,9 +346,9 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
field: var PSym): bool =
if optSeqDestructors in c.g.config.globalOptions:
var op = field
let destructorOverridden = destructorOverridden(c.g, t)
let destructorOverriden = destructorOverriden(c.g, t)
if op != nil and op != c.fn and
(sfOverridden in op.flags or destructorOverridden):
(sfOverriden in op.flags or destructorOverriden):
if sfError in op.flags:
incl c.fn.flags, sfError
#else:
@@ -362,12 +356,10 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
onUse(c.info, op)
body.add newHookCall(c, op, x, y)
result = true
elif op == nil and destructorOverridden:
elif op == nil and destructorOverriden:
op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
body.add newHookCall(c, op, x, y)
result = true
else:
result = false
elif tfHasAsgn in t.flags:
var op: PSym
if sameType(t, c.asgnForType):
@@ -397,14 +389,12 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
assert op.ast[genericParamsPos].kind == nkEmpty
body.add newHookCall(c, op, x, y)
result = true
else:
result = false
proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
let t = orig.skipTypes(abstractInst - {tyDistinct})
var op = t.destructor
if op != nil and sfOverridden in op.flags:
if op != nil and sfOverriden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
op = instantiateGeneric(c, op, t, t.typeInst)
@@ -427,7 +417,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
case c.kind
of attachedDestructor:
var op = t.destructor
if op != nil and sfOverridden in op.flags:
if op != nil and sfOverriden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
@@ -438,12 +428,10 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add destructorCall(c, op, x)
result = true
else:
result = false
#result = addDestructorCall(c, t, body, x)
of attachedAsgn, attachedSink, attachedTrace:
var op = getAttachedOp(c.g, t, c.kind)
if op != nil and sfOverridden in op.flags:
if op != nil and sfOverriden in op.flags:
if op.ast.isGenericRoutine:
# patch generic =trace:
op = instantiateGeneric(c, op, t, t.typeInst)
@@ -460,12 +448,10 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add newDeepCopyCall(c, op, x, y)
result = true
else:
result = false
of attachedWasMoved:
var op = getAttachedOp(c.g, t, attachedWasMoved)
if op != nil and sfOverridden in op.flags:
if op != nil and sfOverriden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
@@ -476,27 +462,9 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add genWasMovedCall(c, op, x)
result = true
else:
result = false
of attachedDup:
var op = getAttachedOp(c.g, t, attachedDup)
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
op = instantiateGeneric(c, op, t, t.typeInst)
setAttachedOp(c.g, c.idgen.module, t, attachedDup, op)
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
body.add newDupCall(c, op, x, y)
result = true
else:
result = false
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info)
temp.typ = getSysType(c.g, body.info, tyInt)
incl(temp.flags, sfFromGeneric)
@@ -506,7 +474,7 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
body.add v
proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info)
temp.typ = value.typ
incl(temp.flags, sfFromGeneric)
@@ -553,28 +521,14 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
else:
body.sons.setLen counterIdx
proc checkSelfAssignment(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var cond = callCodegenProc(c.g, "sameSeqPayload", c.info,
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x),
newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y)
)
cond.typ = getSysType(c.g, c.info, tyBool)
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
of attachedDup:
body.add setLenSeqCall(c, t, x, y)
forallElements(c, t, body, x, y)
of attachedAsgn, attachedDeepCopy:
# we generate:
# if x.p == y.p:
# return
# setLen(dest, y.len)
# var i = 0
# while i < y.len: dest[i] = y[i]; inc(i)
# This is usually more efficient than a destroy/create pair.
checkSelfAssignment(c, t, body, x, y)
body.add setLenSeqCall(c, t, x, y)
forallElements(c, t, body, x, y)
of attachedSink:
@@ -588,17 +542,17 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
forallElements(c, t, body, x, y)
body.add genBuiltin(c, mDestroy, "destroy", x)
of attachedTrace:
if canFormAcycle(c.g, t.elemType):
if canFormAcycle(t.elemType):
# follow all elements:
forallElements(c, t, body, x, y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
createTypeBoundOps(c.g, c.c, t, body.info, c.idgen)
# recursions are tricky, so we might need to forward the generated
# operation here:
var t = t
if t.assignment == nil or t.destructor == nil or t.dup == nil:
if t.assignment == nil or t.destructor == nil:
let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct})
let canon = c.g.canonTypes.getOrDefault(h)
if canon != nil: t = canon
@@ -624,22 +578,16 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
doAssert t.destructor != nil
body.add destructorCall(c, t.destructor, x)
of attachedTrace:
if t.kind != tyString and canFormAcycle(c.g, t.elemType):
if t.kind != tyString and canFormAcycle(t.elemType):
let op = getAttachedOp(c.g, t, c.kind)
if op == nil:
return # protect from recursion
body.add newHookCall(c, op, x, y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
# XXX: replace these with assertions.
let op = getAttachedOp(c.g, t, c.kind)
if op == nil:
return # protect from recursion
body.add newDupCall(c, op, x, y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
of attachedAsgn, attachedDeepCopy, attachedDup:
of attachedAsgn, attachedDeepCopy:
body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y)
of attachedSink:
let moveCall = genBuiltin(c, mMove, "move", x)
@@ -651,11 +599,11 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genBuiltin(c, mDestroy, "destroy", x)
of attachedTrace:
discard "strings are atomic and have no inner elements that are to trace"
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc cyclicType*(g: ModuleGraph, t: PType): bool =
proc cyclicType*(t: PType): bool =
case t.kind
of tyRef: result = types.canFormAcycle(g, t.lastSon)
of tyRef: result = types.canFormAcycle(t.lastSon)
of tyProc: result = t.callConv == ccClosure
else: result = false
@@ -683,7 +631,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let elemType = t.lastSon
createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType)
let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and
(not isPureObject(elemType)) and
@@ -691,7 +639,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# dynamic Acyclic refs need to use dyn decRef
let tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
declareTempOf(c, body, x)
else:
x
@@ -750,16 +698,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# If the ref is polymorphic we have to account for this
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y)
#echo "can follow ", elemType, " static ", isFinal(elemType)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, y, callCodegenProc(c.g,
"nimIncRefCyclic", c.info, y, getCycleParam(c)))
else:
body.add newAsgnStmt(x, y)
body.add genIf(c, y, callCodegenProc(c.g,
"nimIncRef", c.info, y))
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
## Closures are really like refs except they always use a virtual destructor
@@ -769,7 +709,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let isCyclic = c.g.config.selectedGC == gcOrc
let tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
declareTempOf(c, body, xenv)
else:
xenv
@@ -803,21 +743,12 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
of attachedDup:
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
yenv.typ = getSysType(c.g, c.info, tyPointer)
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
else:
body.add newAsgnStmt(x, y)
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv))
of attachedDestructor:
body.add genIf(c, cond, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace:
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
@@ -830,9 +761,6 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
body.add newAsgnStmt(x, y)
of attachedDup:
body.add newAsgnStmt(x, y)
body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
of attachedDestructor:
# it's better to prepend the destruction of weak refs in order to
# prevent wrong "dangling refs exist" problems:
@@ -845,7 +773,7 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.sons.insert(des, 0)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var actions = newNodeI(nkStmtList, c.info)
@@ -867,13 +795,11 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedSink, attachedAsgn:
body.add genIf(c, x, actions)
body.add newAsgnStmt(x, y)
of attachedDup:
body.add newAsgnStmt(x, y)
of attachedDestructor:
body.add genIf(c, x, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if c.kind == attachedDeepCopy:
@@ -885,7 +811,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
call[1] = y
body.add newAsgnStmt(x, call)
elif (optOwnedRefs in c.g.config.globalOptions and
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcOrc}:
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.g, c.info, tyPointer)
case c.kind
@@ -900,11 +826,6 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
body.add newAsgnStmt(x, y)
of attachedDup:
let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
yy.typ = getSysType(c.g, c.info, tyPointer)
body.add newAsgnStmt(x, y)
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
of attachedDestructor:
let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
if body.len == 0:
@@ -913,7 +834,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.sons.insert(des, 0)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
@@ -925,13 +846,11 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedSink, attachedAsgn:
body.add genIf(c, xx, actions)
body.add newAsgnStmt(x, y)
of attachedDup:
body.add newAsgnStmt(x, y)
of attachedDestructor:
body.add genIf(c, xx, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case t.kind
@@ -940,7 +859,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
tyPtr, tyUncheckedArray, tyVar, tyLent:
defaultOp(c, t, body, x, y)
of tyRef:
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
if c.g.config.selectedGC in {gcArc, gcOrc}:
atomicRefOp(c, t, body, x, y)
elif (optOwnedRefs in c.g.config.globalOptions and
optRefCheck in c.g.config.options):
@@ -949,7 +868,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
defaultOp(c, t, body, x, y)
of tyProc:
if t.callConv == ccClosure:
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
if c.g.config.selectedGC in {gcArc, gcOrc}:
atomicClosureOp(c, t, body, x, y)
else:
closureOp(c, t, body, x, y)
@@ -995,25 +914,10 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
defaultOp(c, t, body, x, y)
of tyObject:
if not considerUserDefinedOp(c, t, body, x, y):
if t.sym != nil and sfImportc in t.sym.flags:
case c.kind
of {attachedAsgn, attachedSink, attachedDup}:
body.add newAsgnStmt(x, y)
of attachedWasMoved:
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
else:
fillBodyObjT(c, t, body, x, y)
if c.kind in {attachedAsgn, attachedSink} and t.sym != nil and sfImportc in t.sym.flags:
body.add newAsgnStmt(x, y)
else:
if c.kind == attachedDup:
var op2 = getAttachedOp(c.g, t, attachedAsgn)
if op2 != nil and sfOverridden in op2.flags:
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op2)
body.add newHookCall(c, t.assignment, x, y)
else:
fillBodyObjT(c, t, body, x, y)
else:
fillBodyObjT(c, t, body, x, y)
fillBodyObjT(c, t, body, x, y)
of tyDistinct:
if not considerUserDefinedOp(c, t, body, x, y):
fillBody(c, t[0], body, x, y)
@@ -1034,7 +938,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyAlias, tySink:
fillBody(c, lastSon(t), body, x, y)
of tyConcept, tyIterable: raiseAssert "unreachable"
of tyConcept, tyIterable: doAssert false
proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
kind: TTypeAttachedOp; info: TLineInfo;
@@ -1046,56 +950,15 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
result = getAttachedOp(g, baseType, kind)
setAttachedOp(g, idgen.module, typ, kind, result)
proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym =
let procname = getIdent(g.cache, AttachedOpToStr[kind])
result = newSym(skProc, procname, idgen, owner, info)
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
let src = newSym(skParam, getIdent(g.cache, "src"),
idgen, result, info)
res.typ = typ
src.typ = typ
result.typ = newType(tyProc, nextTypeId idgen, owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
result.typ.n.add newNodeI(nkEffectList, info)
result.typ.addParam src
if g.config.selectedGC == gcOrc and
cyclicType(g, typ.skipTypes(abstractInst)):
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
idgen, result, info)
cycleParam.typ = getSysType(g, info, tyBool)
result.typ.addParam cycleParam
var n = newNodeI(nkProcDef, info, bodyPos+2)
for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
n[namePos] = newSymNode(result)
n[paramsPos] = result.typ.n
n[bodyPos] = newNodeI(nkStmtList, info)
n[resultPos] = newSymNode(res)
result.ast = n
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym =
if kind == attachedDup:
return symDupPrototype(g, typ, owner, kind, info, idgen)
let procname = getIdent(g.cache, AttachedOpToStr[kind])
result = newSym(skProc, procname, idgen, owner, info)
let dest = newSym(skParam, getIdent(g.cache, "dest"), idgen, result, info)
result = newSym(skProc, procname, nextSymId(idgen), owner, info)
let dest = newSym(skParam, getIdent(g.cache, "dest"), nextSymId(idgen), result, info)
let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"),
idgen, result, info)
if kind == attachedDestructor and typ.kind in {tyRef, tyString, tySequence} and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
dest.typ = typ
else:
dest.typ = makeVarType(typ.owner, typ, idgen)
nextSymId(idgen), result, info)
dest.typ = makeVarType(typ.owner, typ, idgen)
if kind == attachedTrace:
src.typ = getSysType(g, info, tyPointer)
else:
@@ -1107,9 +970,9 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
result.typ.addParam src
if kind == attachedAsgn and g.config.selectedGC == gcOrc and
cyclicType(g, typ.skipTypes(abstractInst)):
cyclicType(typ.skipTypes(abstractInst)):
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
idgen, result, info)
nextSymId(idgen), result, info)
cycleParam.typ = getSysType(g, info, tyBool)
result.typ.addParam cycleParam
@@ -1121,9 +984,6 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
result.ast = n
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
if kind == attachedWasMoved:
incl result.flags, sfNoSideEffect
incl result.typ.flags, tfNoSideEffect
proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x)
@@ -1144,25 +1004,22 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType: typ, idgen: idgen,
fn: result)
let dest = if kind == attachedDup: result.ast[resultPos].sym else: result.typ.n[1].sym
let d = if result.typ[1].kind == tyVar: newDeref(newSymNode(dest)) else: newSymNode(dest)
let src = case kind
of {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
of attachedDup: newSymNode(result.typ.n[1].sym)
let dest = result.typ.n[1].sym
let d = newDeref(newSymNode(dest))
let src = if kind in {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
else: newSymNode(result.typ.n[2].sym)
# register this operation already:
setAttachedOpPartial(g, idgen.module, typ, kind, result)
if kind == attachedSink and destructorOverridden(g, typ):
if kind == attachedSink and destructorOverriden(g, typ):
## compiler can use a combination of `=destroy` and memCopy for sink op
dest.flags.incl sfCursor
let op = getAttachedOp(g, typ, attachedDestructor)
result.ast[bodyPos].add newOpCall(a, op, if op.typ[1].kind == tyVar: d[0] else: d)
result.ast[bodyPos].add newOpCall(a, getAttachedOp(g, typ, attachedDestructor), d[0])
result.ast[bodyPos].add newAsgnStmt(d, src)
else:
var tk: TTypeKind
if g.config.selectedGC in {gcArc, gcOrc, gcHooks, gcAtomicArc}:
if g.config.selectedGC in {gcArc, gcOrc, gcHooks}:
tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind
else:
tk = tyNone # no special casing for strings and seqs
@@ -1173,7 +1030,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
fillStrOp(a, typ, result.ast[bodyPos], d, src)
else:
fillBody(a, typ, result.ast[bodyPos], d, src)
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not lacksMTypeField(typ):
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy} and not lacksMTypeField(typ):
# bug #19205: Do not forget to also copy the hidden type field:
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
@@ -1192,7 +1049,7 @@ proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
a.addMemReset = true
let discrimantDest = result.typ.n[1].sym
let dst = newSym(skVar, getIdent(g.cache, "dest"), idgen, result, info)
let dst = newSym(skVar, getIdent(g.cache, "dest"), nextSymId(idgen), result, info)
dst.typ = makePtrType(typ.owner, typ, idgen)
let dstSym = newSymNode(dst)
let d = newDeref(dstSym)
@@ -1218,7 +1075,7 @@ proc patchBody(g: ModuleGraph; c: PContext; n: PNode; info: TLineInfo; idgen: Id
if op != nil:
if op.ast.isGenericRoutine:
internalError(g.config, info, "resolved destructor is generic")
if op.magic == mDestroy and t.kind != tyString:
if op.magic == mDestroy:
internalError(g.config, info, "patching mDestroy with mDestroy?")
n[0] = newSymNode(op)
for x in n: patchBody(g, c, x, info, idgen)
@@ -1271,7 +1128,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
# bug #15122: We need to produce all prototypes before entering the
# mind boggling recursion. Hacks like these imply we should rewrite
# this module.
var generics: array[attachedWasMoved..attachedTrace, bool] = default(array[attachedWasMoved..attachedTrace, bool])
var generics: array[attachedWasMoved..attachedTrace, bool]
for k in attachedWasMoved..lastAttached:
generics[k] = getAttachedOp(g, canon, k) != nil
if not generics[k]:

View File

@@ -49,7 +49,6 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) =
liftLocals(it, i, c)
proc lookupParam(params, dest: PNode): PSym =
result = nil
if dest.kind != nkIdent: return nil
for i in 1..<params.len:
if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:

View File

@@ -7,8 +7,8 @@
# distribution, for details about the copyright.
#
## This module contains the `TMsgKind` enum as well as the
## `TLineInfo` object.
## This module contains the ``TMsgKind`` enum as well as the
## ``TLineInfo`` object.
import ropes, tables, pathutils, hashes
@@ -44,7 +44,6 @@ type
errRstSandboxedDirective,
errProveInit, # deadcode
errGenerated,
errFailedMove,
errUser,
# warnings
warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape",
@@ -84,17 +83,16 @@ type
warnCstringConv = "CStringConv",
warnPtrToCstringConv = "PtrToCstringConv",
warnEffect = "Effect",
warnCastSizes = "CastSizes", # deadcode
warnAboveMaxSizeSet = "AboveMaxSizeSet",
warnCastSizes = "CastSizes"
warnImplicitTemplateRedefinition = "ImplicitTemplateRedefinition",
warnUnnamedBreak = "UnnamedBreak",
warnStmtListLambda = "StmtListLambda",
warnBareExcept = "BareExcept",
warnImplicitDefaultValue = "ImplicitDefaultValue",
warnUser = "User",
# hints
hintSuccess = "Success", hintSuccessX = "SuccessX",
hintCC = "CC",
hintLineTooLong = "LineTooLong",
hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintDuplicateModuleImport = "DuplicateModuleImport",
hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded",
hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX",
@@ -129,7 +127,6 @@ const
errRstSandboxedDirective: "disabled directive: '$1'",
errProveInit: "Cannot prove that '$1' is initialized.", # deadcode
errGenerated: "$1",
errFailedMove: "$1",
errUser: "$1",
warnCannotOpenFile: "cannot open '$1'",
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
@@ -187,18 +184,17 @@ const
warnCstringConv: "$1",
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
warnEffect: "$1",
warnCastSizes: "$1", # deadcode
warnAboveMaxSizeSet: "$1",
warnCastSizes: "$1",
warnImplicitTemplateRedefinition: "template '$1' is implicitly redefined; this is deprecated, add an explicit .redefine pragma",
warnUnnamedBreak: "Using an unnamed break in a block is deprecated; Use a named block with a named break instead",
warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
warnBareExcept: "$1",
warnImplicitDefaultValue: "$1",
warnUser: "$1",
hintSuccess: "operation successful: $#",
# keep in sync with `testament.isSuccess`
hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output",
hintCC: "CC: $1",
hintLineTooLong: "line too long",
hintXDeclaredButNotUsed: "'$1' is declared but not used",
hintDuplicateModuleImport: "$1",
hintXCannotRaiseY: "$1",
@@ -248,8 +244,7 @@ type
TNoteKinds* = set[TNoteKind]
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
result = default(array[0..3, TNoteKinds])
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept}
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv}
result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
result[1] = result[2] - {warnProveField, warnProveIndex,
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
@@ -280,7 +275,7 @@ type
# and parsed; usually "" but is used
# for 'nimsuggest'
hash*: string # the checksum of the file
dirty*: bool # for 'nimpretty' like tooling
dirty*: bool # for 'nimfix' / 'nimpretty' like tooling
when defined(nimpretty):
fullContent*: string
FileIndex* = distinct int32
@@ -311,7 +306,7 @@ proc `==`*(a, b: FileIndex): bool {.borrow.}
proc hash*(i: TLineInfo): Hash =
hash (i.line.int, i.col.int, i.fileIndex.int)
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
proc raiseRecoverableError*(msg: string) {.noinline.} =
raise newException(ERecoverableError, msg)
const
@@ -342,8 +337,9 @@ type
proc initMsgConfig*(): MsgConfig =
result = MsgConfig(msgContext: @[], lastError: unknownLineInfo,
filenameToIndexTbl: initTable[string, FileIndex](),
fileInfos: @[], errorOutputs: {eStdOut, eStdErr}
)
result.msgContext = @[]
result.lastError = unknownLineInfo
result.filenameToIndexTbl = initTable[string, FileIndex]()
result.fileInfos = @[]
result.errorOutputs = {eStdOut, eStdErr}
result.filenameToIndexTbl["???"] = FileIndex(-1)

View File

@@ -19,12 +19,10 @@ const
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
proc identLen*(line: string, start: int): int =
result = 0
while start+result < line.len and line[start+result] in Letters:
inc result
proc `=~`(s: string, a: openArray[string]): bool =
result = false
for x in a:
if s.startsWith(x): return true
@@ -97,7 +95,7 @@ template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind)
if optStyleCheck in ctx.config.options and # ignore if styleChecks are off
{optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # check only if hint/error is enabled
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages
optStyleUsages notin ctx.config.globalOptions and # ignore if requested to only check name usage
sym.kind != skResult and # ignore `result`
sym.kind != skTemp and # ignore temporary variables created by the compiler
@@ -138,7 +136,7 @@ template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) =
## Check symbol uses match their definition's style.
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages
sym.kind != skTemp and # ignore temporary variables created by the compiler
sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols???
sfAnon notin sym.flags: # ignore temporary variables created by the compiler
@@ -149,10 +147,6 @@ proc checkPragmaUseImpl(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragm
if pragmaName != wanted:
lintReport(conf, info, wanted, pragmaName)
template checkPragmaUse*(ctx: PContext; info: TLineInfo; w: TSpecialWord; pragmaName: string, sym: PSym) =
## Check builtin pragma uses match their definition's style.
## Note: This only applies to builtin pragmas, not user pragmas.
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
hintName in ctx.config.notes and # ignore if name checks are not requested
(sym != nil and ctx.config.belongsToProjectPackage(sym)): # ignore foreign packages
checkPragmaUseImpl(ctx.config, info, w, pragmaName)
template checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
checkPragmaUseImpl(conf, info, w, pragmaName)

View File

@@ -40,22 +40,33 @@ type
PLLStream* = ref TLLStream
proc llStreamOpen*(data: sink string): PLLStream =
PLLStream(kind: llsString, s: data)
proc llStreamOpen*(data: string): PLLStream =
new(result)
result.s = data
result.kind = llsString
proc llStreamOpen*(f: File): PLLStream =
PLLStream(kind: llsFile, f: f)
new(result)
result.f = f
result.kind = llsFile
proc llStreamOpen*(filename: AbsoluteFile, mode: FileMode): PLLStream =
result = PLLStream(kind: llsFile)
new(result)
result.kind = llsFile
if not open(result.f, filename.string, mode): result = nil
proc llStreamOpen*(): PLLStream =
PLLStream(kind: llsNone)
new(result)
result.kind = llsNone
proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int
proc llStreamOpenStdIn*(r: TLLRepl = llReadFromStdin, onPrompt: OnPrompt = nil): PLLStream =
PLLStream(kind: llsStdIn, s: "", lineOffset: -1, repl: r, onPrompt: onPrompt)
new(result)
result.kind = llsStdIn
result.s = ""
result.lineOffset = -1
result.repl = r
result.onPrompt = onPrompt
proc llStreamClose*(s: PLLStream) =
case s.kind
@@ -78,8 +89,6 @@ proc endsWith*(x: string, s: set[char]): bool =
while i >= 0 and x[i] == ' ': dec(i)
if i >= 0 and x[i] in s:
result = true
else:
result = false
const
LineContinuationOprs = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^',
@@ -95,7 +104,6 @@ proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs))
proc countTriples(s: string): int =
result = 0
var i = 0
while i+2 < s.len:
if s[i] == '"' and s[i+1] == '"' and s[i+2] == '"':

View File

@@ -8,14 +8,14 @@
#
# This module implements lookup helpers.
import std/[algorithm, strutils, tables]
import std/[algorithm, strutils]
when defined(nimPreviewSlimSystem):
import std/assertions
import
intsets, ast, astalgo, idents, semdata, types, msgs, options,
renderer, lineinfos, modulegraphs, astmsgs, sets, wordrecg
renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs, sets
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
@@ -72,7 +72,7 @@ proc addUniqueSym*(scope: PScope, s: PSym): PSym =
proc openScope*(c: PContext): PScope {.discardable.} =
result = PScope(parent: c.currentScope,
symbols: initStrTable(),
symbols: newStrTable(),
depthLevel: c.scopeDepth + 1)
c.currentScope = result
@@ -94,6 +94,17 @@ iterator localScopesFrom*(c: PContext; scope: PScope): PScope =
if s == c.topLevelScope: break
yield s
proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym =
if s == nil or s.kind != skAlias:
result = s
else:
result = s.owner
if conf.cmd == cmdNimfix:
prettybase.replaceDeprecated(conf, n.info, s, result)
else:
message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " &
s.name.s & " is deprecated")
proc isShadowScope*(s: PScope): bool {.inline.} =
s.parent != nil and s.parent.depthLevel == s.depthLevel
@@ -254,41 +265,6 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
if s.kind in filter:
result.add s
proc isAmbiguous*(c: PContext, s: PIdent, filter: TSymKinds, sym: var PSym): bool =
result = false
block outer:
for scope in allScopes(c.currentScope):
var ti: TIdentIter
var candidate = initIdentIter(ti, scope.symbols, s)
var scopeHasCandidate = false
while candidate != nil:
if candidate.kind in filter:
if scopeHasCandidate:
# 2 candidates in same scope, ambiguous
return true
else:
scopeHasCandidate = true
sym = candidate
candidate = nextIdentIter(ti, scope.symbols)
if scopeHasCandidate:
# scope had a candidate but wasn't ambiguous
return false
var importsHaveCandidate = false
var marked = initIntSet()
for im in c.imports.mitems:
for s in symbols(im, marked, s, c.graph):
if s.kind in filter:
if importsHaveCandidate:
# 2 candidates among imports, ambiguous
return true
else:
importsHaveCandidate = true
sym = s
if importsHaveCandidate:
# imports had a candidate but wasn't ambiguous
return false
proc errorSym*(c: PContext, n: PNode): PSym =
## creates an error symbol to avoid cascading errors (for IDE support)
var m = n
@@ -298,7 +274,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
considerQuotedIdent(c, m)
else:
getIdent(c.cache, "err:" & renderTree(m))
result = newSym(skError, ident, c.idgen, getCurrOwner(c), n.info, {})
result = newSym(skError, ident, nextSymId(c.idgen), getCurrOwner(c), n.info, {})
result.typ = errorType(c)
incl(result.flags, sfDiscardable)
# pretend it's from the top level scope to prevent cascading errors:
@@ -333,7 +309,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
var it: TTabIter
var s = initTabIter(it, scope.symbols)
var missingImpls = 0
var unusedSyms: seq[tuple[sym: PSym, key: string]] = @[]
var unusedSyms: seq[tuple[sym: PSym, key: string]]
while s != nil:
if sfForward in s.flags and s.kind notin {skType, skModule}:
# too many 'implementation of X' errors are annoying
@@ -364,18 +340,17 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string;
# xxx pending bootstrap >= 1.4, replace all those overloads with a single one:
# proc addDecl*(c: PContext, sym: PSym, info = sym.info, scope = c.currentScope) {.inline.} =
proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) =
if sym.name.id == ord(wUnderscore): return
if sym.name.s == "_": return
let conflict = scope.addUniqueSym(sym)
if conflict != nil:
if sym.kind == skModule and conflict.kind == skModule:
if sym.kind == skModule and conflict.kind == skModule and
sym.position == conflict.position:
# e.g.: import foo; import foo
# xxx we could refine this by issuing a different hint for the case
# where a duplicate import happens inside an include.
if c.importModuleMap[sym.id] == c.importModuleMap[conflict.id]:
#only hints if the conflict is the actual module not just a shared name
localError(c.config, info, hintDuplicateModuleImport,
"duplicate import of '$1'; previous import here: $2" %
[sym.name.s, c.config $ conflict.info])
localError(c.config, info, hintDuplicateModuleImport,
"duplicate import of '$1'; previous import here: $2" %
[sym.name.s, c.config $ conflict.info])
else:
wrongRedefinition(c, info, sym.name.s, conflict.info, errGenerated)
@@ -421,12 +396,11 @@ proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) =
if fn.kind notin OverloadableSyms:
internalError(c.config, fn.info, "addOverloadableSymAt")
return
if fn.name.id != ord(wUnderscore):
let check = strTableGet(scope.symbols, fn.name)
if check != nil and check.kind notin OverloadableSyms:
wrongRedefinition(c, fn.info, fn.name.s, check.info)
else:
scope.addSym(fn)
let check = strTableGet(scope.symbols, fn.name)
if check != nil and check.kind notin OverloadableSyms:
wrongRedefinition(c, fn.info, fn.name.s, check.info)
else:
scope.addSym(fn)
proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
## adds an overloadable symbol on the scope and the interface if appropriate
@@ -439,7 +413,7 @@ proc openShadowScope*(c: PContext) =
## opens a shadow scope, just like any other scope except the depth is the
## same as the parent -- see `isShadowScope`.
c.currentScope = PScope(parent: c.currentScope,
symbols: initStrTable(),
symbols: newStrTable(),
depthLevel: c.scopeDepth)
proc closeShadowScope*(c: PContext) =
@@ -463,6 +437,13 @@ proc mergeShadowScope*(c: PContext) =
else:
c.addInterfaceDecl(sym)
when false:
# `nimfix` used to call `altSpelling` and prettybase.replaceDeprecated(n.info, ident, alt)
proc altSpelling(c: PContext, x: PIdent): PIdent =
case x.s[0]
of 'A'..'Z': result = getIdent(c.cache, toLowerAscii(x.s[0]) & x.s.substr(1))
of 'a'..'z': result = getIdent(c.cache, toLowerAscii(x.s[0]) & x.s.substr(1))
else: result = x
import std/editdistance, heapqueue
@@ -493,7 +474,7 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
for (sym, depth, isLocal) in allSyms(c):
let depth = -depth - 1
let dist = editDistance(name0, sym.name.s.nimIdentNormalize)
var msg: string = ""
var msg: string
msg.add "\n ($1, $2): '$3'" % [$dist, $depth, sym.name.s]
list.push SpellCandidate(dist: dist, depth: depth, msg: msg, sym: sym)
@@ -508,9 +489,12 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
let e = list.pop()
if c.config.spellSuggestMax == spellSuggestSecretSauce:
const
minLengthForSuggestion = 4
maxCount = 3 # avoids ton of matches; three counts for equal distances
if e.dist > e0.dist or count >= maxCount or name0.len < minLengthForSuggestion: break
smallThres = 2
maxCountForSmall = 4
# avoids ton of operator matches when mis-matching short symbols such as `i`
# other heuristics could be devised, such as only suggesting operators if `name0`
# is an operator (likewise with non-operators).
if e.dist > e0.dist or (name0.len <= smallThres and count >= maxCountForSmall): break
elif count >= c.config.spellSuggestMax: break
if count == 0:
result.add "\ncandidates (edit distance, scope distance); see '--spellSuggest': "
@@ -523,7 +507,6 @@ proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PS
var err = "ambiguous identifier: '" & s.name.s & "'"
var i = 0
var ignoredModules = 0
result = nil
for candidate in importedItems(c, s.name):
if i == 0: err.add " -- use one of the following:\n"
else: err.add "\n"
@@ -563,16 +546,12 @@ proc errorUseQualifier*(c: PContext; info:TLineInfo; choices: PNode) =
errorUseQualifier(c, info, candidates, prefix)
proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extra = "") =
var err: string
if name == "_":
err = "the special identifier '_' is ignored in declarations and cannot be used"
else:
err = "undeclared identifier: '" & name & "'" & extra
if c.recursiveDep.len > 0:
err.add "\nThis might be caused by a recursive module dependency:\n"
err.add c.recursiveDep
# prevent excessive errors for 'nim check'
c.recursiveDep = ""
var err = "undeclared identifier: '" & name & "'" & extra
if c.recursiveDep.len > 0:
err.add "\nThis might be caused by a recursive module dependency:\n"
err.add c.recursiveDep
# prevent excessive errors for 'nim check'
c.recursiveDep = ""
localError(c.config, info, errGenerated, err)
proc errorUndeclaredIdentifierHint*(c: PContext; n: PNode, ident: PIdent): PSym =
@@ -586,17 +565,17 @@ proc lookUp*(c: PContext, n: PNode): PSym =
var amb = false
case n.kind
of nkIdent:
result = searchInScopes(c, n.ident, amb)
result = searchInScopes(c, n.ident, amb).skipAlias(n, c.config)
if result == nil: result = errorUndeclaredIdentifierHint(c, n, n.ident)
of nkSym:
result = n.sym
of nkAccQuoted:
var ident = considerQuotedIdent(c, n)
result = searchInScopes(c, ident, amb)
result = searchInScopes(c, ident, amb).skipAlias(n, c.config)
if result == nil: result = errorUndeclaredIdentifierHint(c, n, ident)
else:
internalError(c.config, n.info, "lookUp")
return nil
return
if amb:
#contains(c.ambiguousSymbols, result.id):
result = errorUseQualifier(c, n.info, result, amb)
@@ -614,16 +593,14 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
var amb = false
var ident = considerQuotedIdent(c, n)
if checkModule in flags:
result = searchInScopes(c, ident, amb)
result = searchInScopes(c, ident, amb).skipAlias(n, c.config)
else:
let candidates = searchInScopesFilterBy(c, ident, allExceptModule)
let candidates = searchInScopesFilterBy(c, ident, allExceptModule) #.skipAlias(n, c.config)
if candidates.len > 0:
result = candidates[0]
amb = candidates.len > 1
if amb and checkAmbiguity in flags:
errorUseQualifier(c, n.info, candidates)
else:
result = nil
if result == nil:
let candidates = allPureEnumFields(c, ident)
if candidates.len > 0:
@@ -650,20 +627,13 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
ident = considerQuotedIdent(c, n[1])
if ident != nil:
if m == c.module:
result = strTableGet(c.topLevelScope.symbols, ident)
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config)
else:
if c.importModuleLookup.getOrDefault(m.name.id).len > 1:
var amb: bool
result = errorUseQualifier(c, n.info, m, amb)
else:
result = someSym(c.graph, m, ident)
result = someSym(c.graph, m, ident).skipAlias(n, c.config)
if result == nil and checkUndeclared in flags:
result = errorUndeclaredIdentifierHint(c, n[1], ident)
elif n[1].kind == nkSym:
result = n[1].sym
if result.owner != nil and result.owner != m and checkUndeclared in flags:
# dotExpr in templates can end up here
result = errorUndeclaredIdentifierHint(c, n[1], considerQuotedIdent(c, n[1]))
elif checkUndeclared in flags and
n[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
localError(c.config, n[1].info, "identifier expected, but got: " &
@@ -679,12 +649,11 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.marked = initIntSet()
case n.kind
of nkIdent, nkAccQuoted:
result = nil
var ident = considerQuotedIdent(c, n)
var scope = c.currentScope
o.mode = oimNoQualifier
while true:
result = initIdentIter(o.it, scope.symbols, ident)
result = initIdentIter(o.it, scope.symbols, ident).skipAlias(n, c.config)
if result != nil:
o.currentScope = scope
break
@@ -692,7 +661,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
scope = scope.parent
if scope == nil:
for i in 0..c.imports.high:
result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph)
result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph).skipAlias(n, c.config)
if result != nil:
o.currentScope = nil
o.importIdx = i
@@ -703,7 +672,6 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = n.sym
o.mode = oimDone
of nkDotExpr:
result = nil
o.mode = oimOtherModule
o.m = qualifiedLookUp(c, n[0], {checkUndeclared, checkModule})
if o.m != nil and o.m.kind == skModule:
@@ -716,10 +684,10 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if o.m == c.module:
# a module may access its private members:
result = initIdentIter(o.it, c.topLevelScope.symbols,
ident)
ident).skipAlias(n, c.config)
o.mode = oimSelfModule
else:
result = initModuleIter(o.mit, c.graph, o.m, ident)
result = initModuleIter(o.mit, c.graph, o.m, ident).skipAlias(n, c.config)
else:
noidentError(c.config, n[1], n)
result = errorSym(c, n[1])
@@ -733,7 +701,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.symChoiceIndex = 1
o.marked = initIntSet()
incl(o.marked, result.id)
else: result = nil
else: discard
when false:
if result != nil and result.kind == skStub: loadStub(result)
@@ -748,12 +716,11 @@ proc lastOverloadScope*(o: TOverloadIter): int =
else: result = -1
proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = nil
assert o.currentScope == nil
var idx = o.importIdx+1
o.importIdx = c.imports.len # assume the other imported modules lack this symbol too
while idx < c.imports.len:
result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph)
result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph).skipAlias(n, c.config)
if result != nil:
# oh, we were wrong, some other module had the symbol, so remember that:
o.importIdx = idx
@@ -761,10 +728,9 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym
inc idx
proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym =
result = nil
assert o.currentScope == nil
while o.importIdx < c.imports.len:
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config)
#while result != nil and result.id in o.marked:
# result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx])
if result != nil:
@@ -779,29 +745,29 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
of oimNoQualifier:
if o.currentScope != nil:
assert o.importIdx < 0
result = nextIdentIter(o.it, o.currentScope.symbols)
result = nextIdentIter(o.it, o.currentScope.symbols).skipAlias(n, c.config)
while result == nil:
o.currentScope = o.currentScope.parent
if o.currentScope != nil:
result = initIdentIter(o.it, o.currentScope.symbols, o.it.name)
result = initIdentIter(o.it, o.currentScope.symbols, o.it.name).skipAlias(n, c.config)
# BUGFIX: o.it.name <-> n.ident
else:
o.importIdx = 0
if c.imports.len > 0:
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config)
if result == nil:
result = nextOverloadIterImports(o, c, n)
break
elif o.importIdx < c.imports.len:
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph)
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config)
if result == nil:
result = nextOverloadIterImports(o, c, n)
else:
result = nil
of oimSelfModule:
result = nextIdentIter(o.it, c.topLevelScope.symbols)
result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n, c.config)
of oimOtherModule:
result = nextModuleIter(o.mit, c.graph)
result = nextModuleIter(o.mit, c.graph).skipAlias(n, c.config)
of oimSymChoice:
if o.symChoiceIndex < n.len:
result = n[o.symChoiceIndex].sym
@@ -812,28 +778,26 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.mode = oimSymChoiceLocalLookup
o.currentScope = c.currentScope
result = firstIdentExcluding(o.it, o.currentScope.symbols,
n[0].sym.name, o.marked)
n[0].sym.name, o.marked).skipAlias(n, c.config)
while result == nil:
o.currentScope = o.currentScope.parent
if o.currentScope != nil:
result = firstIdentExcluding(o.it, o.currentScope.symbols,
n[0].sym.name, o.marked)
n[0].sym.name, o.marked).skipAlias(n, c.config)
else:
o.importIdx = 0
result = symChoiceExtension(o, c, n)
break
if result != nil:
incl o.marked, result.id
else:
result = nil
of oimSymChoiceLocalLookup:
if o.currentScope != nil:
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked)
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked).skipAlias(n, c.config)
while result == nil:
o.currentScope = o.currentScope.parent
if o.currentScope != nil:
result = firstIdentExcluding(o.it, o.currentScope.symbols,
n[0].sym.name, o.marked)
n[0].sym.name, o.marked).skipAlias(n, c.config)
else:
o.importIdx = 0
result = symChoiceExtension(o, c, n)
@@ -842,23 +806,20 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
incl o.marked, result.id
elif o.importIdx < c.imports.len:
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph)
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config)
#assert result.id notin o.marked
#while result != nil and result.id in o.marked:
# result = nextIdentIter(o.it, c.imports[o.importIdx])
# result = nextIdentIter(o.it, c.imports[o.importIdx]).skipAlias(n, c.config)
if result == nil:
inc o.importIdx
result = symChoiceExtension(o, c, n)
else:
result = nil
when false:
if result != nil and result.kind == skStub: loadStub(result)
proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind];
flags: TSymFlags = {}): PSym =
result = nil
var o: TOverloadIter = default(TOverloadIter)
var o: TOverloadIter
var a = initOverloadIter(o, c, n)
while a != nil:
if a.kind in kinds and flags <= a.flags:

View File

@@ -79,7 +79,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: P
if avoidTemp:
tempAsNode = value
else:
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
owner, value.info, g.config.options)
temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flags, sfFromGeneric)
@@ -100,7 +100,7 @@ proc evalOnce*(g: ModuleGraph; value: PNode; idgen: IdGenerator; owner: PSym): P
## freely, multiple times. This is frequently required and such a builtin would also be
## handy to have in macros.nim. The value that can be reused is 'result.lastSon'!
result = newNodeIT(nkStmtListExpr, value.info, value.typ)
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
owner, value.info, g.config.options)
temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flags, sfFromGeneric)
@@ -122,10 +122,29 @@ proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
proc newTryFinally*(body, final: PNode): PNode =
result = newTree(nkHiddenTryStmt, body, newTree(nkFinally, final))
proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
let value = n.lastSon
result = newNodeI(nkStmtList, n.info)
var temp = newSym(skTemp, getIdent(g.cache, "_"), nextSymId(idgen), owner, value.info, owner.options)
var v = newNodeI(nkLetSection, value.info)
let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
vpart[0] = tempAsNode
vpart[1] = newNodeI(nkEmpty, value.info)
vpart[2] = value
v.add vpart
result.add(v)
let lhs = n[0]
for i in 0..<lhs.len:
result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempAsNode, i))
proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
result = newNodeI(nkStmtList, n.info)
# note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
var temp = newSym(skVar, getIdent(g.cache, genPrefix), idgen, owner, n.info, owner.options)
var temp = newSym(skVar, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, n.info, owner.options)
temp.typ = n[1].typ
incl(temp.flags, sfFromGeneric)
incl(temp.flags, sfGenSym)
@@ -152,7 +171,8 @@ proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo
rawAddSon(result, getCompilerProc(g, "RootObj").typ)
result.n = newNodeI(nkRecList, info)
let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s),
idgen, owner, info, owner.options)
nextSymId(idgen),
owner, info, owner.options)
incl s.flags, sfAnon
s.typ = result
result.sym = s
@@ -214,13 +234,10 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
# because of 'gensym' support, we have to mangle the name with its ID.
# This is hacky but the clean solution is much more complex than it looks.
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len),
idgen, s.owner, s.info, s.options)
nextSymId(idgen), s.owner, s.info, s.options)
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
let t = skipIntLit(s.typ, idgen)
field.typ = t
if s.kind in {skLet, skVar, skField, skForVar}:
#field.bitsize = s.bitsize
field.alignment = s.alignment
assert t.kind != tyTyped
propagateToOwner(obj, t)
field.position = obj.n.len
@@ -233,7 +250,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym {.discardable.} =
result = lookupInRecord(obj.n, s.itemId)
if result == nil:
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), idgen,
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), nextSymId(idgen),
s.owner, s.info, s.options)
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
let t = skipIntLit(s.typ, idgen)
@@ -330,8 +347,7 @@ proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
proc callCodegenProc*(g: ModuleGraph; name: string;
info: TLineInfo = unknownLineInfo;
arg1: PNode = nil, arg2: PNode = nil,
arg3: PNode = nil, optionalArgs: PNode = nil): PNode =
arg1, arg2, arg3, optionalArgs: PNode = nil): PNode =
result = newNodeI(nkCall, info)
let sym = magicsys.getCompilerProc(g, name)
if sym == nil:

View File

@@ -26,11 +26,11 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
result = systemModuleSym(g, getIdent(g.cache, name))
if result == nil:
localError(g.config, info, "system module needs: " & name)
result = newSym(skError, getIdent(g.cache, name), g.idgen, g.systemModule, g.systemModule.info, {})
result = newSym(skError, getIdent(g.cache, name), nextSymId(g.idgen), g.systemModule, g.systemModule.info, {})
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
if result.kind == skAlias: result = result.owner
proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
result = nil
let id = getIdent(g.cache, name)
for r in systemModuleSyms(g, id):
if r.magic == m:
@@ -39,7 +39,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy
result = r
if result != nil: return result
localError(g.config, info, "system module needs: " & name)
result = newSym(skError, id, g.idgen, g.systemModule, g.systemModule.info, {})
result = newSym(skError, id, nextSymId(g.idgen), g.systemModule, g.systemModule.info, {})
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
@@ -81,8 +81,8 @@ proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType =
proc resetSysTypes*(g: ModuleGraph) =
g.systemModule = nil
g.compilerprocs = initStrTable()
g.exposed = initStrTable()
initStrTable(g.compilerprocs)
initStrTable(g.exposed)
for i in low(g.sysTypes)..high(g.sysTypes):
g.sysTypes[i] = nil
@@ -100,7 +100,7 @@ proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} =
proc addSonSkipIntLit*(father, son: PType; id: IdGenerator) =
let s = son.skipIntLit(id)
father.add(s)
father.sons.add(s)
propagateToOwner(father, s)
proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
@@ -124,7 +124,7 @@ proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
strTableGet(g.exposed, getIdent(g.cache, name))
proc resetNimScriptSymbols*(g: ModuleGraph) = g.exposed = initStrTable()
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)
proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
case t.kind
@@ -146,7 +146,6 @@ proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
of tyProc:
result = getSysMagic(g, info, "==", mEqProc)
else:
result = nil
globalError(g.config, info,
"can't find magic equals operator for type kind " & $t.kind)

View File

@@ -13,7 +13,7 @@ when not defined(nimcore):
{.error: "nimcore MUST be defined for Nim's core tooling".}
import
std/[strutils, os, times, tables, with, json],
std/[strutils, os, times, tables, sha1, with, json],
llstream, ast, lexer, syntaxes, options, msgs,
condsyms,
idents, extccomp,
@@ -22,8 +22,6 @@ import
modules,
modulegraphs, lineinfos, pathutils, vmprofiler
# ensure NIR compiles:
import nir / nir
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
@@ -31,8 +29,6 @@ when defined(nimPreviewSlimSystem):
import ic / [cbackend, integrity, navigator]
from ic / ic import rodViewer
import ../dist/checksums/src/checksums/sha1
import pipelines
when not defined(leanCompiler):
@@ -58,7 +54,7 @@ proc writeCMakeDepsFile(conf: ConfigRef) =
for it in conf.toCompile: cfiles.add(it.cname.string)
let fileset = cfiles.toCountTable()
# read old cfiles list
var fl: File = default(File)
var fl: File
var prevset = initCountTable[string]()
if open(fl, fname.string, fmRead):
for line in fl.lines: prevset.inc(line)
@@ -117,7 +113,7 @@ when not defined(leanCompiler):
setPipeLinePass(graph, Docgen2JsonPass)
of HtmlExt:
setPipeLinePass(graph, Docgen2Pass)
else: raiseAssert $ext
else: doAssert false, $ext
compilePipelineProject(graph)
proc commandCompileToC(graph: ModuleGraph) =
@@ -198,7 +194,7 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
if stream != nil:
var
L: Lexer
tok: Token = default(Token)
tok: Token
initToken(tok)
openLexer(L, f, stream, cache, config)
while true:
@@ -269,7 +265,7 @@ proc mainCommand*(graph: ModuleGraph) =
# and it has added this define implictly, so we must undo that here.
# A better solution might be to fix system.nim
undefSymbol(conf.symbols, "useNimRtl")
of backendInvalid: raiseAssert "unreachable"
of backendInvalid: doAssert false
proc compileToBackend() =
customizeForBackend(conf.backend)
@@ -279,7 +275,7 @@ proc mainCommand*(graph: ModuleGraph) =
of backendCpp: commandCompileToC(graph)
of backendObjc: commandCompileToC(graph)
of backendJs: commandCompileToJS(graph)
of backendInvalid: raiseAssert "unreachable"
of backendInvalid: doAssert false
template docLikeCmd(body) =
when defined(leanCompiler):
@@ -419,7 +415,7 @@ proc mainCommand*(graph: ModuleGraph) =
of cmdJsonscript:
setOutFile(graph.config)
commandJsonScript(graph)
of cmdUnknown, cmdNone, cmdIdeTools:
of cmdUnknown, cmdNone, cmdIdeTools, cmdNimfix:
rawMessage(conf, errGenerated, "invalid command: " & conf.command)
if conf.errorCounter == 0 and conf.cmd notin {cmdTcc, cmdDump, cmdNop}:

View File

@@ -11,8 +11,7 @@
## represents a complete Nim project. Single modules can either be kept in RAM
## or stored in a rod-file.
import intsets, tables, hashes
import ../dist/checksums/src/checksums/md5
import intsets, tables, hashes, md5
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
import ic / [packed_ast, ic]
@@ -79,7 +78,6 @@ type
procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId.
attachedOps*: array[TTypeAttachedOp, Table[ItemId, LazySym]] # Type ID, destructors, etc.
methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual and ctor so far)
enumToStringProcs*: Table[ItemId, LazySym]
emittedTypeInfo*: Table[string, FileIndex]
@@ -142,7 +140,7 @@ type
isFrontend: bool]
proc resetForBackend*(g: ModuleGraph) =
g.compilerprocs = initStrTable()
initStrTable(g.compilerprocs)
g.typeInstCache.clear()
g.procInstCache.clear()
for a in mitems(g.attachedOps):
@@ -196,8 +194,8 @@ template semtabAll*(g: ModuleGraph, m: PSym): TStrTable =
g.ifaces[m.position].interfHidden
proc initStrTables*(g: ModuleGraph, m: PSym) =
semtab(g, m) = initStrTable()
semtabAll(g, m) = initStrTable()
initStrTable(semtab(g, m))
initStrTable(semtabAll(g, m))
proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
strTableAdd(semtab(g, m), s)
@@ -368,7 +366,6 @@ proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
setAttachedOp(g, module, dest, k, op)
proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
result = nil
if g.config.symbolFiles == disabledSf: return nil
# slow, linear search, but the results are cached:
@@ -414,7 +411,7 @@ proc stopCompile*(g: ModuleGraph): bool {.inline.} =
result = g.doStopCompile != nil and g.doStopCompile()
proc createMagic*(g: ModuleGraph; idgen: IdGenerator; name: string, m: TMagic): PSym =
result = newSym(skProc, getIdent(g.cache, name), idgen, nil, unknownLineInfo, {})
result = newSym(skProc, getIdent(g.cache, name), nextSymId(idgen), nil, unknownLineInfo, {})
result.magic = m
result.flags = {sfNeverRaises}
@@ -459,7 +456,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
# A module ID of -1 means that the symbol is not attached to a module at all,
# but to the module graph:
result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32)
result.packageSyms = initStrTable()
initStrTable(result.packageSyms)
result.deps = initIntSet()
result.importDeps = initTable[FileIndex, seq[FileIndex]]()
result.ifaces = @[]
@@ -469,9 +466,9 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.suggestSymbols = initTable[FileIndex, seq[SymInfoPair]]()
result.suggestErrors = initTable[FileIndex, seq[Suggest]]()
result.methods = @[]
result.compilerprocs = initStrTable()
result.exposed = initStrTable()
result.packageTypes = initStrTable()
initStrTable(result.compilerprocs)
initStrTable(result.exposed)
initStrTable(result.packageTypes)
result.emptyNode = newNode(nkEmpty)
result.cacheSeqs = initTable[string, PNode]()
result.cacheCounters = initTable[string, BiggestInt]()
@@ -488,7 +485,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
initModuleGraphFields(result)
proc resetAllModules*(g: ModuleGraph) =
g.packageSyms = initStrTable()
initStrTable(g.packageSyms)
g.deps = initIntSet()
g.ifaces = @[]
g.importStack = @[]
@@ -496,12 +493,11 @@ proc resetAllModules*(g: ModuleGraph) =
g.usageSym = nil
g.owners = @[]
g.methods = @[]
g.compilerprocs = initStrTable()
g.exposed = initStrTable()
initStrTable(g.compilerprocs)
initStrTable(g.exposed)
initModuleGraphFields(g)
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
result = nil
if fileIdx.int32 >= 0:
if isCachedModule(g, fileIdx.int32):
result = g.packed[fileIdx.int32].module
@@ -607,7 +603,6 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
proc needsCompilation*(g: ModuleGraph): bool =
# every module that *depends* on this file is also dirty:
result = false
for i in 0i32..<g.ifaces.len.int32:
let m = g.ifaces[i].module
if m != nil:
@@ -615,7 +610,6 @@ proc needsCompilation*(g: ModuleGraph): bool =
return true
proc needsCompilation*(g: ModuleGraph, fileIdx: FileIndex): bool =
result = false
let module = g.getModule(fileIdx)
if module != nil and g.isDirty(module):
return true
@@ -637,8 +631,6 @@ proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
## Returns 'nil' if the module needs to be recompiled.
if g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
result = moduleFromRodFile(g.packed, g.config, g.cache, fileIdx, cachedModules)
else:
result = nil
proc configComplete*(g: ModuleGraph) =
rememberStartupConfig(g.startupPackedConfig, g.config)

View File

@@ -226,7 +226,7 @@ proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: AbsoluteFile)
proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
assert fileIdx.int32 >= 0
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
when defined(gcArc) or defined(gcOrc):
conf.m.fileInfos[fileIdx.int32].hash = hash
else:
shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash)
@@ -234,7 +234,7 @@ proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string =
assert fileIdx.int32 >= 0
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
when defined(gcArc) or defined(gcOrc):
result = conf.m.fileInfos[fileIdx.int32].hash
else:
shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash)
@@ -294,11 +294,9 @@ proc toColumn*(info: TLineInfo): int {.inline.} =
result = info.col
proc toFileLineCol(info: InstantiationInfo): string {.inline.} =
result = ""
result.toLocation(info.filename, info.line, info.column + ColOffset)
proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
result = ""
result.toLocation(toMsgFilename(conf, info), info.line.int, info.col.int + ColOffset)
proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info)
@@ -410,7 +408,7 @@ proc getMessageStr(msg: TMsgKind, arg: string): string = msgKindToString(msg) %
type TErrorHandling* = enum doNothing, doAbort, doRaise
proc log*(s: string) =
var f: File = default(File)
var f: File
if open(f, getHomeDir() / "nimsuggest.log", fmAppend):
f.writeLine(s)
close(f)
@@ -504,8 +502,6 @@ proc getSurroundingSrc(conf: ConfigRef; info: TLineInfo): string =
result = "\n" & indent & $sourceLine(conf, info)
if info.col >= 0:
result.add "\n" & indent & spaces(info.col) & '^'
else:
result = ""
proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string =
let title = case msg
@@ -515,8 +511,7 @@ proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): s
conf.toFileLineCol(info) & " " & title & getMessageStr(msg, arg)
proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling, info2: InstantiationInfo, isRaw = false,
ignoreError = false) {.gcsafe, noinline.} =
eh: TErrorHandling, info2: InstantiationInfo, isRaw = false) {.gcsafe, noinline.} =
var
title: string
color: ForegroundColor
@@ -581,8 +576,7 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
" compiler msg initiated here", KindColor,
KindFormat % $hintMsgOrigin,
resetStyle, conf.unitSep)
if not ignoreError:
handleError(conf, msg, eh, s, ignoreMsg)
handleError(conf, msg, eh, s, ignoreMsg)
if msg in fatalMsgs:
# most likely would have died here but just in case, we restore state
conf.m.errorOutputs = errorOutputsOld

View File

@@ -309,7 +309,6 @@ proc symbol(n: PNode): Symbol =
# echo "symbol ", n, " ", n.kind, " ", result.int
func `$`(map: NilMap): string =
result = ""
var now = map
var stack: seq[NilMap] = @[]
while not now.isNil:
@@ -417,7 +416,7 @@ proc moveOut(ctx: NilCheckerContext, map: NilMap, target: PNode) =
if targetSetIndex != noSetIndex:
var targetSet = map.sets[targetSetIndex]
if targetSet.len > 1:
var other: ExprIndex = default(ExprIndex)
var other: ExprIndex
for element in targetSet:
if element.ExprIndex != targetIndex:
@@ -562,7 +561,7 @@ proc derefWarning(n, ctx, map; kind: Nilability) =
if n.info in ctx.warningLocations:
return
ctx.warningLocations.incl(n.info)
var a: seq[History] = @[]
var a: seq[History]
if n.kind == nkSym:
a = history(map, ctx.index(n))
var res = ""
@@ -766,7 +765,7 @@ proc checkIf(n, ctx, map): Check =
# the state of the conditions: negating conditions before the current one
var layerHistory = newNilMap(mapIf)
# the state after branch effects
var afterLayer: NilMap = nil
var afterLayer: NilMap
# the result nilability for expressions
var nilability = Safe
@@ -863,10 +862,9 @@ proc checkInfix(n, ctx, map): Check =
## a or b : map is an union of a and b's
## a == b : use checkCondition
## else: no change, just check args
result = default(Check)
if n[0].kind == nkSym:
var mapL: NilMap = nil
var mapR: NilMap = nil
var mapL: NilMap
var mapR: NilMap
if n[0].sym.magic notin {mAnd, mEqRef}:
mapL = checkCondition(n[1], ctx, map, false, false)
mapR = checkCondition(n[2], ctx, map, false, false)
@@ -911,7 +909,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
else: ""
var cache = newIdentCache()
var op = newSym(skVar, cache.getIdent(name), ctx.idgen, nil, r.info)
var op = newSym(skVar, cache.getIdent(name), nextSymId ctx.idgen, nil, r.info)
op.magic = magic
result = nkInfix.newTree(
@@ -922,7 +920,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
var cache = newIdentCache()
var op = newSym(skVar, cache.getIdent("not"), ctx.idgen, nil, node.info)
var op = newSym(skVar, cache.getIdent("not"), nextSymId ctx.idgen, nil, node.info)
op.magic = mNot
result = nkPrefix.newTree(
@@ -949,7 +947,7 @@ proc checkCase(n, ctx, map): Check =
let base = n[0]
result.map = map.copyMap()
result.nilability = Safe
var a: PNode = nil
var a: PNode
for child in n:
case child.kind:
of nkOfBranch:
@@ -1224,7 +1222,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check =
# TODO deeper nested elements?
# A(field: B()) #
# field: Safe ->
var elements: seq[(PNode, Nilability)] = @[]
var elements: seq[(PNode, Nilability)]
for i, child in n:
result = check(child, ctx, result.map)
if i > 0:
@@ -1335,7 +1333,7 @@ proc preVisit(ctx: NilCheckerContext, s: PSym, body: PNode, conf: ConfigRef) =
ctx.symbolIndices = {resultId: resultExprIndex}.toTable()
var cache = newIdentCache()
ctx.expressions = SeqOfDistinct[ExprIndex, PNode](@[newIdentNode(cache.getIdent("result"), s.ast.info)])
var emptySet: IntSet = initIntSet() # set[ExprIndex]
var emptySet: IntSet # set[ExprIndex]
ctx.dependants = SeqOfDistinct[ExprIndex, IntSet](@[emptySet])
for i, arg in s.typ.n.sons:
if i > 0:

View File

@@ -7,7 +7,6 @@ define:nimcore
define:nimPreviewFloatRoundtrip
define:nimPreviewSlimSystem
define:nimPreviewCstringConversion
define:nimPreviewProcConversion
define:nimPreviewRangeDefault
threads:off
@@ -15,6 +14,7 @@ threads:off
@if windows:
cincludes: "$lib/wrappers/libffi/common"
tlsEmulation:off
@end
define:useStdoutAsStdmsg
@@ -31,6 +31,9 @@ define:useStdoutAsStdmsg
warning[ObservableStores]:off
@end
@if nimHasWarnCastSizes:
warning[CastSizes]:on
@end
@if nimHasWarningAsError:
warningAsError[GcUnsafe2]:on
@@ -43,11 +46,3 @@ define:useStdoutAsStdmsg
@if nimHasWarnBareExcept:
warningAserror[BareExcept]:on
@end
@if nimUseStrictDefs:
experimental:strictDefs
warningAsError[Uninit]:on
warningAsError[ProveInit]:on
@end

View File

@@ -12,7 +12,10 @@ import std/[os, strutils, parseopt]
when defined(nimPreviewSlimSystem):
import std/assertions
when defined(windows):
when defined(windows) and not defined(nimKochBootstrap):
# remove workaround pending bootstrap >= 1.5.1
# refs https://github.com/nim-lang/Nim/issues/18334#issuecomment-867114536
# alternative would be to prepend `currentSourcePath.parentDir.quoteShell`
when defined(gcc):
when defined(x86):
{.link: "../icons/nim.res".}
@@ -91,9 +94,6 @@ proc getNimRunExe(conf: ConfigRef): string =
if conf.isDefined("mingw"):
if conf.isDefined("i386"): result = "wine"
elif conf.isDefined("amd64"): result = "wine64"
else: result = ""
else:
result = ""
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
let self = NimProg(
@@ -140,7 +140,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
# tasyncjs_fail` would fail, refs https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode
if cmdPrefix.len == 0: cmdPrefix = findNodeJs().quoteShell
cmdPrefix.add " --unhandled-rejections=strict"
else: raiseAssert $conf.backend
else: doAssert false, $conf.backend
if cmdPrefix.len > 0: cmdPrefix.add " "
# without the `cmdPrefix.len > 0` check, on windows you'd get a cryptic:
# `The parameter is incorrect`

View File

@@ -10,13 +10,11 @@
## Implements some helper procs for Nimble (Nim's package manager) support.
import parseutils, strutils, os, options, msgs, sequtils, lineinfos, pathutils,
tables
std/sha1, tables
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import ../dist/checksums/src/checksums/sha1
proc addPath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) =
if not conf.searchPaths.contains(path):
conf.searchPaths.insert(path, 0)
@@ -37,16 +35,11 @@ proc isSpecial(ver: Version): bool =
proc isValidVersion(v: string): bool =
if v.len > 0:
if v[0] in {'#'} + Digits:
result = true
else:
result = false
else:
result = false
if v[0] in {'#'} + Digits: return true
proc `<`*(ver: Version, ver2: Version): bool =
## This is synced from Nimble's version module.
result = false
# Handling for special versions such as "#head" or "#branch".
if ver.isSpecial or ver2.isSpecial:
if ver2.isSpecial and ($ver2).normalize == "#head":
@@ -150,7 +143,7 @@ proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) =
conf.lazyPaths.insert(AbsoluteDir path, 0)
proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) =
var packages: PackageInfo = initTable[string, tuple[version, checksum: string]]()
var packages: PackageInfo
var pos = dir.len-1
if dir[pos] in {DirSep, AltSep}: inc(pos)
for k,p in os.walkDir(dir):

View File

@@ -214,7 +214,7 @@ proc parseAssignment(L: var Lexer, tok: var Token;
proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
config: ConfigRef): bool =
var
L: Lexer = default(Lexer)
L: Lexer
tok: Token
stream: PLLStream
stream = llStreamOpen(filename, fmRead)
@@ -228,8 +228,6 @@ proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
if condStack.len > 0: lexMessage(L, errGenerated, "expected @end")
closeLexer(L)
return true
else:
result = false
proc getUserConfigPath*(filename: RelativeFile): AbsoluteFile =
result = getConfigDir().AbsoluteDir / RelativeDir"nim" / filename
@@ -252,7 +250,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen:
template runNimScriptIfExists(path: AbsoluteFile, isMain = false) =
let p = path # eval once
var s: PLLStream = nil
var s: PLLStream
if isMain and optWasNimscript in conf.globalOptions:
if conf.projectIsStdin: s = stdin.llStreamOpen
elif conf.projectIsCmd: s = llStreamOpen(conf.cmdInput)

View File

@@ -12,7 +12,7 @@ import
ast, modules, condsyms,
options, llstream, lineinfos, vm,
vmdef, modulegraphs, idents, os, pathutils,
scriptconfig, std/[compilesettings, tables]
scriptconfig, std/compilesettings
import pipelines
@@ -78,9 +78,6 @@ proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) =
assert i != nil
assert i.mainModule != nil, "no main module selected"
initStrTables(i.graph, i.mainModule)
i.graph.cacheSeqs.clear()
i.graph.cacheCounters.clear()
i.graph.cacheTables.clear()
i.mainModule.ast = nil
let s = if scriptStream != nil: scriptStream

111
compiler/nimfix/nimfix.nim Normal file
View File

@@ -0,0 +1,111 @@
#
#
# The Nim Compiler
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code.
import strutils, os, parseopt
import compiler/[options, commands, modules, sem,
passes, passaux, linter,
msgs, nimconf,
extccomp, condsyms,
modulegraphs, idents]
const Usage = """
Nimfix - Tool to patch Nim code
Usage:
nimfix [options] projectfile.nim
Options:
--overwriteFiles:on|off overwrite the original nim files.
DEFAULT is ON!
--wholeProject overwrite every processed file.
--checkExtern:on|off style check also extern names
--styleCheck:on|off|auto performs style checking for identifiers
and suggests an alternative spelling;
'auto' corrects the spelling.
--bestEffort try to fix the code even when there
are errors.
In addition, all command line options of Nim are supported.
"""
proc mainCommand =
registerPass verbosePass
registerPass semPass
conf.setCmd cmdNimfix
searchPaths.add options.libpath
if gProjectFull.len != 0:
# current path is always looked first for modules
searchPaths.insert(gProjectPath, 0)
compileProject(newModuleGraph(), newIdentCache())
pretty.overwriteFiles()
proc processCmdLine*(pass: TCmdLinePass, cmd: string, config: ConfigRef) =
var p = parseopt.initOptParser(cmd)
var argsCount = 0
gOnlyMainfile = true
while true:
parseopt.next(p)
case p.kind
of cmdEnd: break
of cmdLongoption, cmdShortOption:
case p.key.normalize
of "overwritefiles":
case p.val.normalize
of "on": gOverWrite = true
of "off": gOverWrite = false
else: localError(gCmdLineInfo, errOnOrOffExpected)
of "checkextern":
case p.val.normalize
of "on": gCheckExtern = true
of "off": gCheckExtern = false
else: localError(gCmdLineInfo, errOnOrOffExpected)
of "stylecheck":
case p.val.normalize
of "off": gStyleCheck = StyleCheck.None
of "on": gStyleCheck = StyleCheck.Warn
of "auto": gStyleCheck = StyleCheck.Auto
else: localError(gCmdLineInfo, errOnOrOffExpected)
of "wholeproject": gOnlyMainfile = false
of "besteffort": msgs.gErrorMax = high(int) # don't stop after first error
else:
processSwitch(pass, p, config)
of cmdArgument:
options.gProjectName = unixToNativePath(p.key)
# if processArgument(pass, p, argsCount): break
proc handleCmdLine(config: ConfigRef) =
if paramCount() == 0:
stdout.writeLine(Usage)
else:
processCmdLine(passCmd1, "", config)
if gProjectName != "":
try:
gProjectFull = canonicalizePath(gProjectName)
except OSError:
gProjectFull = gProjectName
var p = splitFile(gProjectFull)
gProjectPath = p.dir
gProjectName = p.name
else:
gProjectPath = getCurrentDir()
loadConfigs(DefaultConfig, config) # load all config files
# now process command line arguments again, because some options in the
# command line can overwrite the config file's settings
extccomp.initVars()
processCmdLine(passCmd2, "", config)
mainCommand()
when compileOption("gc", "refc"):
GC_disableMarkAndSweep()
condsyms.initDefines()
defineSymbol "nimfix"
handleCmdline newConfigRef()

View File

@@ -0,0 +1,17 @@
# Special configuration file for the Nim project
# gc:markAndSweep
hint[XDeclaredButNotUsed]:off
path:"$projectPath/.."
path:"$lib/packages/docutils"
path:"$nim"
define:useStdoutAsStdmsg
symbol:nimfix
define:nimfix
cs:partial
#define:useNodeIds
define:booting
define:noDocgen

View File

@@ -0,0 +1,45 @@
#
#
# The Nim Compiler
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import strutils except Letters
import ".." / [ast, msgs, lineinfos, idents, options, linter]
proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PIdent) =
let line = sourceLine(conf, info)
var first = min(info.col.int, line.len)
if first < 0: return
#inc first, skipIgnoreCase(line, "proc ", first)
while first > 0 and line[first-1] in Letters: dec first
if first < 0: return
if line[first] == '`': inc first
let last = first+identLen(line, first)-1
if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
when defined(gcArc) or defined(gcOrc):
conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x
else:
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
conf.m.fileInfos[info.fileIndex.int32].dirty = true
#if newSym.s == "File": writeStackTrace()
proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PSym) =
replaceDeprecated(conf, info, oldSym.name, newSym.name)
proc replaceComment*(conf: ConfigRef; info: TLineInfo) =
let line = sourceLine(conf, info)
var first = info.col.int
if line[first] != '#': inc first
var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
when defined(gcArc) or defined(gcOrc):
conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x
else:
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
conf.m.fileInfos[info.fileIndex.int32].dirty = true

View File

@@ -62,9 +62,7 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
result = false
proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet =
result = @[]
var first: Int128 = Zero
var j: Int128 = Zero
var first, j: Int128
first = firstOrd(conf, s.typ[0])
bitSetInit(result, int(getSize(conf, s.typ)))
for i in 0..<s.len:

File diff suppressed because it is too large Load Diff

View File

@@ -1,78 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# We produce C code as a list of tokens.
import std / assertions
import .. / ic / bitabs
type
Token = LitId # indexing into the tokens BiTable[string]
PredefinedToken = enum
IgnoreMe = "<unused>"
EmptyToken = ""
DeclPrefix = "" # the next token is the name of a definition
CurlyLe = "{"
CurlyRi = "}"
ParLe = "("
ParRi = ")"
BracketLe = "["
BracketRi = "]"
NewLine = "\n"
Semicolon = ";"
Comma = ", "
Space = " "
Colon = ":"
Dot = "."
Arrow = "->"
Star = "*"
Amp = "&"
AsgnOpr = " = "
ScopeOpr = "::"
ConstKeyword = "const "
StaticKeyword = "static "
NimString = "NimString"
StrLitPrefix = "(NimChar*)"
StrLitNamePrefix = "Qstr"
LoopKeyword = "while (true) "
WhileKeyword = "while ("
IfKeyword = "if ("
ElseKeyword = "else "
SwitchKeyword = "switch ("
CaseKeyword = "case "
DefaultKeyword = "default:"
BreakKeyword = "break"
NullPtr = "nullptr"
IfNot = "if (!("
ReturnKeyword = "return "
const
ModulePrefix = Token(int(ReturnKeyword)+1)
proc fillTokenTable(tab: var BiTable[string]) =
for e in EmptyToken..high(PredefinedToken):
let id = tab.getOrIncl $e
assert id == LitId(e)
type
GeneratedCode* = object
code: seq[LitId]
tokens: BiTable[string]
proc initGeneratedCode*(): GeneratedCode =
result = GeneratedCode(code: @[], tokens: initBiTable[string]())
fillTokenTable(result.tokens)
proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} =
g.code.add Token(t)
proc add*(g: var GeneratedCode; s: string) {.inline.} =
g.code.add g.tokens.getOrIncl(s)

View File

@@ -1,22 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nim Intermediate Representation, designed to capture all of Nim's semantics without losing too much
## precious information. Can easily be translated into C. And to JavaScript, hopefully.
import nirtypes, nirinsts, ast2ir
when false:
type
Module* = object
types: TypeGraph
data: seq[Tree]
init: seq[Tree]
procs: seq[Tree]

View File

@@ -1,314 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## NIR instructions. Somewhat inspired by LLVM's instructions.
import std / [assertions, hashes, strformat]
import .. / ic / bitabs
import nirlineinfos, nirtypes
type
SymId* = distinct int
proc `$`*(s: SymId): string {.borrow.}
proc hash*(s: SymId): Hash {.borrow.}
proc `==`*(a, b: SymId): bool {.borrow.}
type
Opcode* = enum
Nop,
ImmediateVal,
IntVal,
StrVal,
SymDef,
SymUse,
ModuleId,
Typed, # with type ID
NilVal,
Label,
Goto,
CheckedGoto,
LoopLabel,
GotoLoop, # last atom
ModuleSymUse, # `module.x`
ArrayConstr,
ObjConstr,
Ret,
Yld,
Select,
SelectPair, # ((values...), Label)
SelectList, # (values...)
SelectValue, # (value)
SelectRange, # (valueA..valueB)
SummonGlobal,
SummonThreadLocal,
Summon, # x = Summon Typed <Type ID>; x begins to live
Kill, # `Kill x`: scope end for `x`
AddrOf,
ArrayAt, # addr(a[i])
FieldAt, # addr(obj.field)
Load, # a[]
Store, # a[] = b
Asgn, # a = b
SetExc,
TestExc,
Call,
IndirectCall,
CheckedCall, # call that can raise
CheckedIndirectCall, # call that can raise
CheckedAdd, # with overflow checking etc.
CheckedSub,
CheckedMul,
CheckedDiv,
CheckedMod,
Add,
Sub,
Mul,
Div,
Mod,
BitShl,
BitShr,
BitAnd,
BitOr,
BitXor,
BitNot,
Eq,
Le,
Lt,
Cast,
NumberConv,
CheckedObjConv,
ObjConv,
TestOf,
Emit,
ProcDecl
const
LastAtomicValue = GotoLoop
OpcodeBits = 8'u32
OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32
ValueProducingAtoms = {ImmediateVal, IntVal, StrVal, SymUse, NilVal}
ValueProducing* = {
ImmediateVal,
IntVal,
StrVal,
SymUse,
NilVal,
ModuleSymUse,
ArrayConstr,
ObjConstr,
CheckedAdd,
CheckedSub,
CheckedMul,
CheckedDiv,
CheckedMod,
Add,
Sub,
Mul,
Div,
Mod,
BitShl,
BitShr,
BitAnd,
BitOr,
BitXor,
BitNot,
Eq,
Le,
Lt,
Cast,
NumberConv,
CheckedObjConv,
ObjConv,
AddrOf,
Load,
ArrayAt,
FieldAt,
TestOf
}
type
Instr* = object # 8 bytes
x: uint32
info: PackedLineInfo
template kind*(n: Instr): Opcode = Opcode(n.x and OpcodeMask)
template operand(n: Instr): uint32 = (n.x shr OpcodeBits)
template toX(k: Opcode; operand: uint32): uint32 =
uint32(k) or (operand shl OpcodeBits)
template toX(k: Opcode; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl OpcodeBits)
proc `$`*(n: Instr): string =
result = fmt"{n.kind}: {n.operand}"
type
Tree* = object
nodes: seq[Instr]
Values* = object
numbers: BiTable[int64]
strings: BiTable[string]
type
PatchPos* = distinct int
NodePos* = distinct int
const
InvalidPatchPos* = PatchPos(-1)
proc debug*(t: Tree) {.deprecated.} =
for i in t.nodes:
echo i
proc isValid(p: PatchPos): bool {.inline.} = p.int != -1
proc prepare*(tree: var Tree; info: PackedLineInfo; kind: Opcode): PatchPos =
result = PatchPos tree.nodes.len
tree.nodes.add Instr(x: toX(kind, 1'u32), info: info)
proc isAtom(tree: Tree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
proc isAtom(tree: Tree; pos: NodePos): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
proc patch*(tree: var Tree; pos: PatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > LastAtomicValue
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
template build*(tree: var Tree; info: PackedLineInfo; kind: Opcode; body: untyped) =
let pos = prepare(tree, info, kind)
body
patch(tree, pos)
proc len*(tree: Tree): int {.inline.} = tree.nodes.len
template rawSpan(n: Instr): int = int(operand(n))
proc nextChild(tree: Tree; pos: var int) {.inline.} =
if tree.nodes[pos].kind > LastAtomicValue:
assert tree.nodes[pos].operand > 0'u32
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
iterator sons*(tree: Tree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield NodePos pos
nextChild tree, pos
template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int]
proc span(tree: Tree; pos: int): int {.inline.} =
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
proc copyTree*(dest: var Tree; src: Tree) =
let pos = 0
let L = span(src, pos)
let d = dest.nodes.len
dest.nodes.setLen(d + L)
assert L > 0
for i in 0..<L:
dest.nodes[d+i] = src.nodes[pos+i]
type
LabelId* = distinct int
proc newLabel*(labelGen: var int): LabelId {.inline.} =
result = LabelId labelGen
inc labelGen
proc addNewLabel*(t: var Tree; labelGen: var int; info: PackedLineInfo; k: Opcode): LabelId =
assert k in {Label, LoopLabel}
result = LabelId labelGen
t.nodes.add Instr(x: toX(k, uint32(result)), info: info)
inc labelGen
proc boolVal*(t: var Tree; info: PackedLineInfo; b: bool) =
t.nodes.add Instr(x: toX(ImmediateVal, uint32(b)), info: info)
proc gotoLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) =
assert k in {Goto, GotoLoop, CheckedGoto}
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
proc addLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) {.inline.} =
assert k in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
proc addSymUse*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
t.nodes.add Instr(x: toX(SymUse, uint32(s)), info: info)
proc addTyped*(t: var Tree; info: PackedLineInfo; typ: TypeId) {.inline.} =
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
proc addSummon*(t: var Tree; info: PackedLineInfo; s: SymId; typ: TypeId) {.inline.} =
let x = prepare(t, info, Summon)
t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
patch t, x
proc addImmediateVal*(t: var Tree; info: PackedLineInfo; x: int) =
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
t.nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
type
Value* = distinct Tree
proc prepare*(dest: var Value; info: PackedLineInfo; k: Opcode): PatchPos {.inline.} =
assert k in ValueProducing - ValueProducingAtoms
result = prepare(Tree(dest), info, k)
proc patch*(dest: var Value; pos: PatchPos) {.inline.} =
patch(Tree(dest), pos)
proc localToValue*(info: PackedLineInfo; s: SymId): Value =
result = Value(Tree())
Tree(result).addSymUse info, s
proc hasValue*(v: Value): bool {.inline.} = Tree(v).len > 0
proc isEmpty*(v: Value): bool {.inline.} = Tree(v).len == 0
proc extractTemp*(v: Value): SymId =
if hasValue(v) and Tree(v)[NodePos 0].kind == SymUse:
result = SymId(Tree(v)[NodePos 0].operand)
else:
result = SymId(-1)
proc copyTree*(dest: var Tree; src: Value) = copyTree dest, Tree(src)
proc addImmediateVal*(t: var Value; info: PackedLineInfo; x: int) =
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
Tree(t).nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
template build*(tree: var Value; info: PackedLineInfo; kind: Opcode; body: untyped) =
let pos = prepare(Tree(tree), info, kind)
body
patch(tree, pos)
proc addTyped*(t: var Value; info: PackedLineInfo; typ: TypeId) {.inline.} =
addTyped(Tree(t), info, typ)

View File

@@ -1,78 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# For the line information we use 32 bits. They are used as follows:
# Bit 0 (AsideBit): If we have inline line information or not. If not, the
# remaining 31 bits are used as an index into a seq[(LitId, int, int)].
#
# We use 10 bits for the "file ID", this means a program can consist of as much
# as 1024 different files. (If it uses more files than that, the overflow bit
# would be set.)
# This means we have 21 bits left to encode the (line, col) pair. We use 7 bits for the column
# so 128 is the limit and 14 bits for the line number.
# The packed representation supports files with up to 16384 lines.
# Keep in mind that whenever any limit is reached the AsideBit is set and the real line
# information is kept in a side channel.
import std / assertions
const
AsideBit = 1
FileBits = 10
LineBits = 14
ColBits = 7
FileMax = (1 shl FileBits) - 1
LineMax = (1 shl LineBits) - 1
ColMax = (1 shl ColBits) - 1
static:
assert AsideBit + FileBits + LineBits + ColBits == 32
import .. / ic / bitabs # for LitId
type
PackedLineInfo* = distinct uint32
LineInfoManager* = object
aside*: seq[(LitId, int32, int32)]
proc pack*(m: var LineInfoManager; file: LitId; line, col: int32): PackedLineInfo =
if file.uint32 <= FileMax.uint32 and line <= LineMax and col <= ColMax:
let col = if col < 0'i32: 0'u32 else: col.uint32
let line = if line < 0'i32: 0'u32 else: line.uint32
# use inline representation:
result = PackedLineInfo((file.uint32 shl 1'u32) or (line shl uint32(AsideBit + FileBits)) or
(col shl uint32(AsideBit + FileBits + LineBits)))
else:
result = PackedLineInfo((m.aside.len shl 1) or AsideBit)
m.aside.add (file, line, col)
proc unpack*(m: LineInfoManager; i: PackedLineInfo): (LitId, int32, int32) =
let i = i.uint32
if (i and 1'u32) == 0'u32:
# inline representation:
result = (LitId((i shr 1'u32) and FileMax.uint32),
int32((i shr uint32(AsideBit + FileBits)) and LineMax.uint32),
int32((i shr uint32(AsideBit + FileBits + LineBits)) and ColMax.uint32))
else:
result = m.aside[int(i shr 1'u32)]
proc getFileId*(m: LineInfoManager; i: PackedLineInfo): LitId =
result = unpack(m, i)[0]
when isMainModule:
var m = LineInfoManager(aside: @[])
for i in 0'i32..<16388'i32:
for col in 0'i32..<100'i32:
let packed = pack(m, LitId(1023), i, col)
let u = unpack(m, packed)
assert u[0] == LitId(1023)
assert u[1] == i
assert u[2] == col
echo m.aside.len

View File

@@ -1,97 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Management of slots. Similar to "register allocation"
## in lower level languages.
import std / [assertions, tables]
import nirtypes, nirinsts
type
SlotManagerFlag* = enum
ReuseTemps,
ReuseVars
SlotManager* = object # "register allocator"
live: Table[SymId, TypeId]
dead: Table[TypeId, seq[SymId]]
flags: set[SlotManagerFlag]
inScope: seq[SymId]
locGen: ref int
proc initSlotManager*(flags: set[SlotManagerFlag]; generator: ref int): SlotManager {.inline.} =
SlotManager(flags: flags, locGen: generator)
proc allocRaw(m: var SlotManager; t: TypeId; f: SlotManagerFlag): SymId {.inline.} =
if f in m.flags and m.dead.hasKey(t) and m.dead[t].len > 0:
result = m.dead[t].pop()
else:
result = SymId(m.locGen[])
inc m.locGen[]
m.inScope.add result
m.live[result] = t
proc allocTemp*(m: var SlotManager; t: TypeId): SymId {.inline.} =
result = allocRaw(m, t, ReuseTemps)
proc allocVar*(m: var SlotManager; t: TypeId): SymId {.inline.} =
result = allocRaw(m, t, ReuseVars)
proc freeLoc*(m: var SlotManager; s: SymId) =
let t = m.live.getOrDefault(s)
assert t.int != 0
m.live.del s
m.dead.mgetOrPut(t, @[]).add s
iterator stillAlive*(m: SlotManager): (SymId, TypeId) =
for k, v in pairs(m.live):
yield (k, v)
proc getType*(m: SlotManager; s: SymId): TypeId {.inline.} = m.live[s]
proc openScope*(m: var SlotManager) =
m.inScope.add SymId(-1) # add marker
proc closeScope*(m: var SlotManager) =
var i = m.inScope.len - 1
while i >= 0:
if m.inScope[i] == SymId(-1):
m.inScope.setLen i-1
break
dec i
when isMainModule:
var m = initSlotManager({ReuseTemps}, new(int))
var g = initTypeGraph()
let a = g.openType ArrayTy
g.addBuiltinType Int8Id
g.addArrayLen 5'u64
let finalArrayType = sealType(g, a)
let obj = g.openType ObjectDecl
g.addName "MyType"
g.addField "p", finalArrayType
let objB = sealType(g, obj)
let x = m.allocTemp(objB)
assert x.int == 0
let y = m.allocTemp(objB)
assert y.int == 1
let z = m.allocTemp(Int8Id)
assert z.int == 2
m.freeLoc y
let y2 = m.allocTemp(objB)
assert y2.int == 1

View File

@@ -1,339 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Type system for NIR. Close to C's type system but without its quirks.
import std / [assertions, hashes]
import .. / ic / bitabs
type
NirTypeKind* = enum
VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal, IntVal,
AnnotationVal,
VarargsTy, # the `...` in a C prototype; also the last "atom"
APtrTy, # pointer to aliasable memory
UPtrTy, # pointer to unique/unaliasable memory
AArrayPtrTy, # pointer to array of aliasable memory
UArrayPtrTy, # pointer to array of unique/unaliasable memory
ArrayTy,
LastArrayTy, # array of unspecified size as a last field inside an object
ObjectTy,
UnionTy,
ProcTy,
ObjectDecl,
UnionDecl,
FieldDecl
const
TypeKindBits = 8'u32
TypeKindMask = (1'u32 shl TypeKindBits) - 1'u32
type
TypeNode* = object # 4 bytes
x: uint32
template kind*(n: TypeNode): NirTypeKind = NirTypeKind(n.x and TypeKindMask)
template operand(n: TypeNode): uint32 = (n.x shr TypeKindBits)
template toX(k: NirTypeKind; operand: uint32): uint32 =
uint32(k) or (operand shl TypeKindBits)
template toX(k: NirTypeKind; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl TypeKindBits)
type
TypeId* = distinct int
proc `==`*(a, b: TypeId): bool {.borrow.}
proc hash*(a: TypeId): Hash {.borrow.}
type
TypeGraph* = object
nodes: seq[TypeNode]
names: BiTable[string]
numbers: BiTable[uint64]
const
VoidId* = TypeId 0
Bool8Id* = TypeId 1
Char8Id* = TypeId 2
Int8Id* = TypeId 3
Int16Id* = TypeId 4
Int32Id* = TypeId 5
Int64Id* = TypeId 6
UInt8Id* = TypeId 7
UInt16Id* = TypeId 8
UInt32Id* = TypeId 9
UInt64Id* = TypeId 10
Float32Id* = TypeId 11
Float64Id* = TypeId 12
LastBuiltinId* = 12
proc initTypeGraph*(): TypeGraph =
result = TypeGraph(nodes: @[
TypeNode(x: toX(VoidTy, 0'u32)),
TypeNode(x: toX(BoolTy, 8'u32)),
TypeNode(x: toX(CharTy, 8'u32)),
TypeNode(x: toX(IntTy, 8'u32)),
TypeNode(x: toX(IntTy, 16'u32)),
TypeNode(x: toX(IntTy, 32'u32)),
TypeNode(x: toX(IntTy, 64'u32)),
TypeNode(x: toX(UIntTy, 8'u32)),
TypeNode(x: toX(UIntTy, 16'u32)),
TypeNode(x: toX(UIntTy, 32'u32)),
TypeNode(x: toX(UIntTy, 64'u32)),
TypeNode(x: toX(FloatTy, 32'u32)),
TypeNode(x: toX(FloatTy, 64'u32))
])
assert result.nodes.len == LastBuiltinId+1
type
TypePatchPos* = distinct int
const
InvalidTypePatchPos* = TypePatchPos(-1)
LastAtomicValue = VarargsTy
proc isValid(p: TypePatchPos): bool {.inline.} = p.int != -1
proc prepare(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
result = TypePatchPos tree.nodes.len
tree.nodes.add TypeNode(x: toX(kind, 1'u32))
proc isAtom(tree: TypeGraph; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
proc isAtom(tree: TypeGraph; pos: TypeId): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
proc patch(tree: var TypeGraph; pos: TypePatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > LastAtomicValue
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
proc len*(tree: TypeGraph): int {.inline.} = tree.nodes.len
template rawSpan(n: TypeNode): int = int(operand(n))
proc nextChild(tree: TypeGraph; pos: var int) {.inline.} =
if tree.nodes[pos].kind > LastAtomicValue:
assert tree.nodes[pos].operand > 0'u32
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
iterator sons*(tree: TypeGraph; n: TypeId): TypeId =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield TypeId pos
nextChild tree, pos
template `[]`*(t: TypeGraph; n: TypeId): TypeNode = t.nodes[n.int]
proc elementType*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
assert tree[n].kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ArrayTy, LastArrayTy}
result = TypeId(n.int+1)
proc kind*(tree: TypeGraph; n: TypeId): NirTypeKind {.inline.} = tree[n].kind
proc span(tree: TypeGraph; pos: int): int {.inline.} =
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
proc sons2(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
result = (TypeId a, TypeId b)
proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
result = (TypeId a, TypeId b, TypeId c)
proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestUInt =
assert tree[n].kind == ArrayTy
result = tree.numbers[LitId tree[n].operand]
proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy,
ArrayTy, LastArrayTy, ProcTy, ObjectDecl, UnionDecl,
FieldDecl}
result = prepare(tree, kind)
proc sealType*(tree: var TypeGraph; p: TypePatchPos): TypeId =
# TODO: Search for an existing instance of this type in
# order to reduce memory consumption.
result = TypeId(p)
patch tree, p
proc nominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string): TypeId =
assert kind in {ObjectTy, UnionTy}
result = TypeId tree.nodes.len
tree.nodes.add TypeNode(x: toX(kind, tree.names.getOrIncl(name)))
proc addNominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string) =
assert kind in {ObjectTy, UnionTy}
tree.nodes.add TypeNode(x: toX(kind, tree.names.getOrIncl(name)))
proc addVarargs*(tree: var TypeGraph) =
tree.nodes.add TypeNode(x: toX(VarargsTy, 0'u32))
proc getFloat128Type*(tree: var TypeGraph): TypeId =
result = TypeId tree.nodes.len
tree.nodes.add TypeNode(x: toX(FloatTy, 128'u32))
proc addBuiltinType*(g: var TypeGraph; id: TypeId) =
g.nodes.add g[id]
template firstSon(n: TypeId): TypeId = TypeId(n.int+1)
proc addType*(g: var TypeGraph; t: TypeId) =
# We cannot simply copy `*Decl` nodes. We have to introduce `*Ty` nodes instead:
if g[t].kind in {ObjectDecl, UnionDecl}:
assert g[t.firstSon].kind == NameVal
let name = LitId g[t.firstSon].operand
if g[t].kind == ObjectDecl:
g.nodes.add TypeNode(x: toX(ObjectTy, name))
else:
g.nodes.add TypeNode(x: toX(UnionTy, name))
else:
let pos = t.int
let L = span(g, pos)
let d = g.nodes.len
g.nodes.setLen(d + L)
assert L > 0
for i in 0..<L:
g.nodes[d+i] = g.nodes[pos+i]
proc addArrayLen*(g: var TypeGraph; len: uint64) =
g.nodes.add TypeNode(x: toX(IntVal, g.numbers.getOrIncl(len)))
proc addName*(g: var TypeGraph; name: string) =
g.nodes.add TypeNode(x: toX(NameVal, g.names.getOrIncl(name)))
proc addAnnotation*(g: var TypeGraph; name: string) =
g.nodes.add TypeNode(x: toX(NameVal, g.names.getOrIncl(name)))
proc addField*(g: var TypeGraph; name: string; typ: TypeId) =
let f = g.openType FieldDecl
g.addType typ
g.addName name
discard sealType(g, f)
proc toString*(dest: var string; g: TypeGraph; i: TypeId) =
case g[i].kind
of VoidTy: dest.add "void"
of IntTy:
dest.add "i"
dest.addInt g[i].operand
of UIntTy:
dest.add "u"
dest.addInt g[i].operand
of FloatTy:
dest.add "f"
dest.addInt g[i].operand
of BoolTy:
dest.add "b"
dest.addInt g[i].operand
of CharTy:
dest.add "c"
dest.addInt g[i].operand
of NameVal, AnnotationVal:
dest.add g.names[LitId g[i].operand]
of IntVal:
dest.add $g.numbers[LitId g[i].operand]
of VarargsTy:
dest.add "..."
of APtrTy:
dest.add "aptr["
toString(dest, g, g.elementType(i))
dest.add "]"
of UPtrTy:
dest.add "uptr["
toString(dest, g, g.elementType(i))
dest.add "]"
of AArrayPtrTy:
dest.add "aArrayPtr["
toString(dest, g, g.elementType(i))
dest.add "]"
of UArrayPtrTy:
dest.add "uArrayPtr["
toString(dest, g, g.elementType(i))
dest.add "]"
of ArrayTy:
dest.add "Array["
let (elems, len) = g.sons2(i)
toString(dest, g, elems)
dest.add ", "
toString(dest, g, len)
dest.add "]"
of LastArrayTy:
# array of unspecified size as a last field inside an object
dest.add "LastArrayTy["
toString(dest, g, g.elementType(i))
dest.add "]"
of ObjectTy:
dest.add "object "
dest.add g.names[LitId g[i].operand]
of UnionTy:
dest.add "union "
dest.add g.names[LitId g[i].operand]
of ProcTy:
dest.add "proc["
for t in sons(g, i): toString(dest, g, t)
dest.add "]"
of ObjectDecl:
dest.add "object["
for t in sons(g, i):
toString(dest, g, t)
dest.add '\n'
dest.add "]"
of UnionDecl:
dest.add "union["
for t in sons(g, i):
toString(dest, g, t)
dest.add '\n'
dest.add "]"
of FieldDecl:
let (typ, name) = g.sons2(i)
toString(dest, g, typ)
dest.add ' '
toString(dest, g, name)
proc toString*(dest: var string; g: TypeGraph) =
var i = 0
while i < g.len:
toString(dest, g, TypeId i)
dest.add '\n'
nextChild g, i
proc `$`(g: TypeGraph): string =
result = ""
toString(result, g)
when isMainModule:
var g = initTypeGraph()
let a = g.openType ArrayTy
g.addBuiltinType Int8Id
g.addArrayLen 5'u64
let finalArrayType = sealType(g, a)
let obj = g.openType ObjectDecl
g.nodes.add TypeNode(x: toX(NameVal, g.names.getOrIncl("MyType")))
g.addField "p", finalArrayType
discard sealType(g, obj)
echo g

View File

@@ -1,426 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import std / [assertions, tables, sets]
import ".." / [ast, types, options, sighashes, modulegraphs]
import nirtypes
type
TypesCon* = object
processed: Table[ItemId, TypeId]
recursionCheck: HashSet[ItemId]
g: TypeGraph
conf: ConfigRef
proc initTypesCon*(conf: ConfigRef): TypesCon =
TypesCon(g: initTypeGraph(), conf: conf)
proc mangle(c: var TypesCon; t: PType): string =
result = $sighashes.hashType(t, c.conf)
template cached(c: var TypesCon; t: PType; body: untyped) =
result = c.processed.getOrDefault(t.itemId)
if result.int == 0:
body
c.processed[t.itemId] = result
proc typeToIr*(c: var TypesCon; t: PType): TypeId
proc collectFieldTypes(c: var TypesCon; n: PNode; dest: var Table[ItemId, TypeId]) =
case n.kind
of nkRecList:
for i in 0..<n.len:
collectFieldTypes(c, n[i], dest)
of nkRecCase:
assert(n[0].kind == nkSym)
collectFieldTypes(c, n[0], dest)
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
collectFieldTypes c, lastSon(n[i]), dest
else: discard
of nkSym:
dest[n.sym.itemId] = typeToIr(c, n.sym.typ)
else:
assert false, "unknown node kind: " & $n.kind
proc objectToIr(c: var TypesCon; n: PNode; fieldTypes: Table[ItemId, TypeId]; unionId: var int) =
case n.kind
of nkRecList:
for i in 0..<n.len:
objectToIr(c, n[i], fieldTypes, unionId)
of nkRecCase:
assert(n[0].kind == nkSym)
objectToIr(c, n[0], fieldTypes, unionId)
let u = openType(c.g, UnionDecl)
c.g.addName "u_" & $unionId
inc unionId
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
let subObj = openType(c.g, ObjectDecl)
c.g.addName "uo_" & $unionId & "_" & $i
objectToIr c, lastSon(n[i]), fieldTypes, unionId
discard sealType(c.g, subObj)
else: discard
discard sealType(c.g, u)
of nkSym:
c.g.addField n.sym.name.s & "_" & $n.sym.position, fieldTypes[n.sym.itemId]
else:
assert false, "unknown node kind: " & $n.kind
proc objectToIr(c: var TypesCon; t: PType): TypeId =
if t[0] != nil:
# ensure we emitted the base type:
discard typeToIr(c, t[0])
var unionId = 0
var fieldTypes = initTable[ItemId, TypeId]()
collectFieldTypes c, t.n, fieldTypes
let obj = openType(c.g, ObjectDecl)
c.g.addName mangle(c, t)
if t[0] != nil:
c.g.addNominalType(ObjectTy, mangle(c, t[0]))
else:
c.g.addBuiltinType VoidId # object does not inherit
if not lacksMTypeField(t):
let f2 = c.g.openType FieldDecl
let voidPtr = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
discard sealType(c.g, voidPtr)
c.g.addName "m_type"
discard sealType(c.g, f2) # FieldDecl
objectToIr c, t.n, fieldTypes, unionId
result = sealType(c.g, obj)
proc objectHeaderToIr(c: var TypesCon; t: PType): TypeId =
result = c.g.nominalType(ObjectTy, mangle(c, t))
proc tupleToIr(c: var TypesCon; t: PType): TypeId =
var fieldTypes = newSeq[TypeId](t.len)
for i in 0..<t.len:
fieldTypes[i] = typeToIr(c, t[i])
let obj = openType(c.g, ObjectDecl)
c.g.addName mangle(c, t)
for i in 0..<t.len:
c.g.addField "f_" & $i, fieldTypes[i]
result = sealType(c.g, obj)
proc procToIr(c: var TypesCon; t: PType; addEnv = false): TypeId =
var fieldTypes = newSeq[TypeId](0)
for i in 0..<t.len:
if not isCompileTimeOnly(t[i]):
fieldTypes.add typeToIr(c, t[i])
let obj = openType(c.g, ProcTy)
case t.callConv
of ccNimCall, ccFastCall, ccClosure: c.g.addAnnotation "__fastcall"
of ccStdCall: c.g.addAnnotation "__stdcall"
of ccCDecl: c.g.addAnnotation "__cdecl"
of ccSafeCall: c.g.addAnnotation "__safecall"
of ccSysCall: c.g.addAnnotation "__syscall"
of ccInline: c.g.addAnnotation "__inline"
of ccNoInline: c.g.addAnnotation "__noinline"
of ccThisCall: c.g.addAnnotation "__thiscall"
of ccNoConvention: c.g.addAnnotation ""
for i in 0..<fieldTypes.len:
c.g.addType fieldTypes[i]
if addEnv:
let a = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
discard sealType(c.g, a)
if tfVarargs in t.flags:
c.g.addVarargs()
result = sealType(c.g, obj)
proc nativeInt(c: TypesCon): TypeId =
case c.conf.target.intSize
of 2: result = Int16Id
of 4: result = Int32Id
else: result = Int64Id
proc openArrayToIr(c: var TypesCon; t: PType): TypeId =
# object (a: ArrayPtr[T], len: int)
let e = lastSon(t)
let mangledBase = mangle(c, e)
let typeName = "NimOpenArray" & mangledBase
let elementType = typeToIr(c, e)
let p = openType(c.g, ObjectDecl)
c.g.addName typeName
let f = c.g.openType FieldDecl
let arr = c.g.openType AArrayPtrTy
c.g.addType elementType
discard sealType(c.g, arr) # LastArrayTy
c.g.addName "data"
discard sealType(c.g, f) # FieldDecl
c.g.addField "len", c.nativeInt
result = sealType(c.g, p) # ObjectDecl
proc stringToIr(c: var TypesCon; t: PType): TypeId =
#[
NimStrPayload = object
cap: int
data: UncheckedArray[char]
NimStringV2 = object
len: int
p: ptr NimStrPayload
]#
let p = openType(c.g, ObjectDecl)
c.g.addName "NimStrPayload"
c.g.addField "cap", c.nativeInt
let f = c.g.openType FieldDecl
let arr = c.g.openType LastArrayTy
c.g.addBuiltinType Char8Id
discard sealType(c.g, arr) # LastArrayTy
c.g.addName "data"
discard sealType(c.g, f) # FieldDecl
let payload = sealType(c.g, p)
let str = openType(c.g, ObjectDecl)
c.g.addName "NimStringV2"
c.g.addField "len", c.nativeInt
let fp = c.g.openType FieldDecl
let ffp = c.g.openType APtrTy
c.g.addNominalType ObjectTy, "NimStrPayload"
discard sealType(c.g, ffp) # APtrTy
c.g.addName "p"
discard sealType(c.g, fp) # FieldDecl
result = sealType(c.g, str) # ObjectDecl
proc seqToIr(c: var TypesCon; t: PType): TypeId =
#[
NimSeqPayload[T] = object
cap: int
data: UncheckedArray[T]
NimSeqV2*[T] = object
len: int
p: ptr NimSeqPayload[T]
]#
let e = lastSon(t)
let mangledBase = mangle(c, e)
let payloadName = "NimSeqPayload" & mangledBase
let elementType = typeToIr(c, e)
let p = openType(c.g, ObjectDecl)
c.g.addName payloadName
c.g.addField "cap", c.nativeInt
let f = c.g.openType FieldDecl
let arr = c.g.openType LastArrayTy
c.g.addType elementType
discard sealType(c.g, arr) # LastArrayTy
c.g.addName "data"
discard sealType(c.g, f) # FieldDecl
let payload = sealType(c.g, p)
let sq = openType(c.g, ObjectDecl)
c.g.addName "NimSeqV2" & mangledBase
c.g.addField "len", c.nativeInt
let fp = c.g.openType FieldDecl
let ffp = c.g.openType APtrTy
c.g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
discard sealType(c.g, ffp) # APtrTy
c.g.addName "p"
discard sealType(c.g, fp) # FieldDecl
result = sealType(c.g, sq) # ObjectDecl
proc closureToIr(c: var TypesCon; t: PType): TypeId =
# struct {fn(args, void* env), env}
# typedef struct {$n" &
# "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
# "void* ClE_0;$n} $1;$n"
let mangledBase = mangle(c, t)
let typeName = "NimClosure" & mangledBase
let procType = procToIr(c, t, addEnv=true)
let p = openType(c.g, ObjectDecl)
c.g.addName typeName
let f = c.g.openType FieldDecl
c.g.addType procType
c.g.addName "ClP_0"
discard sealType(c.g, f) # FieldDecl
let f2 = c.g.openType FieldDecl
let voidPtr = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
discard sealType(c.g, voidPtr)
c.g.addName "ClE_0"
discard sealType(c.g, f2) # FieldDecl
result = sealType(c.g, p) # ObjectDecl
proc typeToIr*(c: var TypesCon; t: PType): TypeId =
case t.kind
of tyInt:
case int(getSize(c.conf, t))
of 2: result = Int16Id
of 4: result = Int32Id
else: result = Int64Id
of tyInt8: result = Int8Id
of tyInt16: result = Int16Id
of tyInt32: result = Int32Id
of tyInt64: result = Int64Id
of tyFloat:
case int(getSize(c.conf, t))
of 4: result = Float32Id
else: result = Float64Id
of tyFloat32: result = Float32Id
of tyFloat64: result = Float64Id
of tyFloat128: result = getFloat128Type(c.g)
of tyUInt:
case int(getSize(c.conf, t))
of 2: result = UInt16Id
of 4: result = UInt32Id
else: result = UInt64Id
of tyUInt8: result = UInt8Id
of tyUInt16: result = UInt16Id
of tyUInt32: result = UInt32Id
of tyUInt64: result = UInt64Id
of tyBool: result = Bool8Id
of tyChar: result = Char8Id
of tyVoid: result = VoidId
of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange:
result = typeToIr(c, t.lastSon)
of tyEnum:
if firstOrd(c.conf, t) < 0:
result = Int32Id
else:
case int(getSize(c.conf, t))
of 1: result = UInt8Id
of 2: result = UInt16Id
of 4: result = Int32Id
of 8: result = Int64Id
else: result = Int32Id
of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
if t.len > 0:
result = typeToIr(c, t.lastSon)
else:
result = TypeId(-1)
of tyFromExpr:
if t.n != nil and t.n.typ != nil:
result = typeToIr(c, t.n.typ)
else:
result = TypeId(-1)
of tyArray:
cached(c, t):
var n = toInt64(lengthOrd(c.conf, t))
if n <= 0: n = 1 # make an array of at least one element
let elemType = typeToIr(c, t[1])
let a = openType(c.g, ArrayTy)
c.g.addType(elemType)
c.g.addArrayLen uint64(n)
result = sealType(c.g, a)
of tyPtr, tyRef:
cached(c, t):
let e = t.lastSon
if e.kind == tyUncheckedArray:
let elemType = typeToIr(c, e.lastSon)
let a = openType(c.g, AArrayPtrTy)
c.g.addType(elemType)
result = sealType(c.g, a)
else:
let elemType = typeToIr(c, t.lastSon)
let a = openType(c.g, APtrTy)
c.g.addType(elemType)
result = sealType(c.g, a)
of tyVar, tyLent:
cached(c, t):
let elemType = typeToIr(c, t.lastSon)
let a = openType(c.g, APtrTy)
c.g.addType(elemType)
result = sealType(c.g, a)
of tySet:
let s = int(getSize(c.conf, t))
case s
of 1: result = UInt8Id
of 2: result = UInt16Id
of 4: result = UInt32Id
of 8: result = UInt64Id
else:
# array[U8, s]
cached(c, t):
let a = openType(c.g, ArrayTy)
c.g.addType(UInt8Id)
c.g.addArrayLen uint64(s)
result = sealType(c.g, a)
of tyPointer:
let a = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
result = sealType(c.g, a)
of tyObject:
# Objects are special as they can be recursive in Nim. This is easily solvable.
# We check if we are already "processing" t. If so, we produce `ObjectTy`
# instead of `ObjectDecl`.
cached(c, t):
if not c.recursionCheck.containsOrIncl(t.itemId):
result = objectToIr(c, t)
else:
result = objectHeaderToIr(c, t)
of tyTuple:
cached(c, t):
result = tupleToIr(c, t)
of tyProc:
cached(c, t):
if t.callConv == ccClosure:
result = closureToIr(c, t)
else:
result = procToIr(c, t)
of tyVarargs, tyOpenArray:
cached(c, t):
result = openArrayToIr(c, t)
of tyString:
cached(c, t):
result = stringToIr(c, t)
of tySequence:
cached(c, t):
result = seqToIr(c, t)
of tyCstring:
cached(c, t):
let a = openType(c.g, AArrayPtrTy)
c.g.addBuiltinType Char8Id
result = sealType(c.g, a)
of tyUncheckedArray:
# We already handled the `ptr UncheckedArray` in a special way.
cached(c, t):
let elemType = typeToIr(c, t.lastSon)
let a = openType(c.g, LastArrayTy)
c.g.addType(elemType)
result = sealType(c.g, a)
of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc,
tyNil, tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
result = TypeId(-1)

View File

@@ -1,2 +0,0 @@
template unreachable*(s = "unreachable") = raiseAssert s
template todo*(s = "todo") = raiseAssert s

View File

@@ -12,8 +12,6 @@
const
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
DefaultSetElements* = 1 shl 8
## assumed set element count when using int literals
VersionAsString* = system.NimVersion
RodFileVersion* = "1223" # modify this if the rod-format changes!

View File

@@ -113,7 +113,7 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) =
if n[0].kind == nkSym:
let s = n[0].sym
let name = s.name.s.normalize
if name == "=wasmoved":
if s.magic == mWasMoved or name == "=wasmoved":
b.wasMovedLocs.add n
special = true
elif name == "=destroy":
@@ -279,7 +279,7 @@ proc optimize*(n: PNode): PNode =
Now assume 'use' raises, then we shouldn't do the 'wasMoved(s)'
]#
var c: Con = Con()
var c: Con
var b: BasicBlock
analyse(c, b, n)
if c.somethingTodo:

Some files were not shown because too many files have changed in this diff Show More