Compare commits

...

705 Commits

Author SHA1 Message Date
narimiran
c00e8e71e0 bump NimVersion to 2.0.6 2024-06-16 19:01:20 +02:00
narimiran
a073e225c8 Revert "fixes #22510 (#23100)"
This reverts commit d6bc8699b9.
2024-06-16 19:01:01 +02:00
Andreas Rumpf
140d641443 fixes #22927; no test case extractable [backport] (#23707)
(cherry picked from commit 3770236bee)
2024-06-13 11:08:08 +02:00
ringabout
cc779a42ce remove pkg "pylib" (#23691)
https://github.com/Yardanico/nimpylib is 404 now
(cherry picked from commit 09b5ed251e)
2024-06-11 14:07:27 +02:00
ringabout
26a4b137c6 [backport] fixes #23690; SIGSEGV with object variants and RTTI (#23703)
fixes #23690

```nim
dest.`:state` = src.`:state`
var :tmp_553651276 = dest.e1.a
`=wasMoved`(dest.e1.a)
dest.e1.a.kind = src.e1.a.kind
case dest.e1.a.kind
of 0:
  dest.e1.a.a = src.e1.a.a
of 1:
  `=copy`(dest.e1.a.c, src.e1.a.c)
case :tmp_553651276.kind
of 0:
of 1:
  `=destroy`(:tmp_553651276.c)
```
`dest.e1.a.kind = src.e1.a.kind` changes the discrimant but it fails to
clear the memory of `dest.e1.a`. Before using hooks for copying, we need
to clear the dest, e.g. `=wasMoved(dest.e1.a.c)`.

```nim
dest.`:state` = src.`:state`
var :tmp_553651276 = dest.e1.a
`=wasMoved`(dest.e1.a)
dest.e1.a.kind = src.e1.a.kind
case dest.e1.a.kind
of 0:
  `=wasMoved`(dest.e1.a.a)
  dest.e1.a.a = src.e1.a.a
  `=wasMoved`(dest.e1.a.b)
of 1:
  `=wasMoved`(dest.e1.a.c)
  `=copy`(dest.e1.a.c, src.e1.a.c)
case :tmp_553651276.kind
of 0:
of 1:
  `=destroy`(:tmp_553651276.c)
```

(cherry picked from commit 262ff648aa)
2024-06-11 14:04:29 +02:00
Juan M Gómez
d7544ec3db [Backport 2.0] Nimsuggest handle unknown file (#23701) 2024-06-10 17:14:16 +02:00
narimiran
767a901267 Revert "Fix #22826: Don't skip generic instances in type comparison (#22828)"
This reverts commit 5e20e935dd.
2024-06-07 16:30:32 +02:00
Andreas Rumpf
36f8cccda4 fixes #23354; [backport] (#23685)
(cherry picked from commit 7039b8b5bc)
2024-06-07 15:34:34 +02:00
Andreas Rumpf
d6bc8699b9 fixes #22510 (#23100)
(cherry picked from commit 69d0b73d66)
2024-06-06 16:14:57 +02:00
ringabout
7db4376cda fixes openarray hoist with gcc 14 (#23647)
blocks https://github.com/nim-lang/Nim/pull/23673

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 17475fc5d3)
2024-06-04 10:13:14 +02:00
ringabout
a85c635da8 fixes#23665; rework spawn with gcc 14 and fixes other tests (#23660)
fixes #23665

(cherry picked from commit 08f1eac8ac)
2024-06-04 07:38:38 +02:00
Miran
3e18c48cda [backport] test more packages (#23671)
These packages are some of the dependencies of Nimbus with shorter
testing times.

(cherry picked from commit d22e8f7f82)
2024-06-03 15:06:37 +02:00
ringabout
3455623500 rework ctypes with gcc 14 (#23636)
(cherry picked from commit 4bd1cf2376)
2024-06-03 08:25:55 +02:00
Juan M Gómez
8daac1b061 [Backport 2.0] Updates nimble (#23643) 2024-06-02 15:16:04 +02:00
ringabout
7071e3a080 closes #15778; adds a test case (#23613)
closes #15778

(cherry picked from commit c08356865d)
2024-05-24 15:57:30 +02:00
ringabout
98075688f3 fixes openarray views default values in JS (#23607)
(cherry picked from commit 0fcd838fd9)
2024-05-24 15:57:15 +02:00
ringabout
5abf9a1d77 fixes #23440; fixes destruction for temporary object subclass (#23452)
fixes #23440

(cherry picked from commit f175c81079)
2024-05-24 11:18:18 +02:00
metagn
ab053fd56a remove HEAD arraymancer dependency requirement in package CI (#23509)
Was introduced to handle a break in #23392, according to
https://github.com/nim-lang/Nim/pull/23503#issuecomment-2057266475
should not be needed anymore

(cherry picked from commit 49e1ca0b3e)
2024-05-24 08:28:08 +02:00
lit
598de35d45 doc(format): ospaths2,strutils: followup #23560 (#23629)
followup #23560

(cherry picked from commit b838d3ece1)
2024-05-23 13:55:24 +02:00
lit
a88b275bc3 doc(format): system.nim: doc of hostCPU for loongarch64 (#23621)
In doc, `loongarch64` used to be written as `'"loongarch64"'`

since it's [supported](https://github.com/nim-lang/Nim/pull/19223)

(cherry picked from commit b3b26b2e56)
2024-05-23 13:55:24 +02:00
PHO
e57b207ff8 Support NetBSD/aarch64 (#23616)
I could trivially port Nim to NetBSD/aarch64 because it already
supported NetBSD and aarch64. I only needed to generate `c_code` for
this combination.

(cherry picked from commit 0ba932132e)
2024-05-23 13:55:23 +02:00
ringabout
b9951e8c87 fixes lifting subtype calling parent's hooks (#23612)
ref https://forum.nim-lang.org/t/11587

Tested with `gcc version 14.0.1 20240412` locally

(cherry picked from commit 2c8551556e)
2024-05-23 13:55:23 +02:00
ringabout
9ad0ada8e4 adds Nim-related mimetypes back (#23589)
ref https://github.com/nim-lang/Nim/pull/23226

(cherry picked from commit 1eb9aac2f7)
2024-05-23 09:02:25 +02:00
lit
30eb2b394e Improve strutils.rsplit doc, proc and iterator have oppose result order. (#23570)
[`rsplit
iterator`](https://nim-lang.org/docs/strutils.html#rsplit.i,string,char,int)
yields substring in reversed order,

while [`proc
rsplit`](https://nim-lang.org/docs/strutils.html#rsplit%2Cstring%2Cchar%2Cint)'s
order is not reversed, but its doc only declare ```
The same as the rsplit iterator, but is a func that returns a sequence
of substrings.
```

(cherry picked from commit 2e3777d6f3)
2024-05-23 09:02:19 +02:00
ringabout
6a1694b28b fixes #23552; Invalid codegen when trying to mannualy delete distinct seq (#23558)
fixes #23552

(cherry picked from commit 2995a0318b)
2024-05-23 09:01:58 +02:00
Antonis Geralis
8f5451832e Add a note about the sideeffect pragma (#23543)
(cherry picked from commit 63398b11f5)
2024-05-23 08:59:31 +02:00
Angel Ezquerra
cd65b5e5f8 Add Complex version of almostEqual function (#23549)
This adds a version of `almostEqual` (which was already available for
floats) thata works with `Complex[SomeFloat]`.

Proof that this is needed is that the first thing that the complex.nim
runnable examples block did before this commit was define (an
incomplete) `almostEqual` function that worked with complex values.

(cherry picked from commit d8e1504ed1)
2024-05-23 08:59:23 +02:00
ringabout
80a6005f55 fixes #22409; don't check style for enumFieldSymChoice in the function (#23580)
fixes #22409

(cherry picked from commit 1ad4e80060)
2024-05-23 08:59:09 +02:00
lit
cd72be29c6 fixes #23442, fix for FileId under Windows (#23444)
See according issue:

Details:
<https://github.com/nim-lang/Nim/issues/23442#issuecomment-2021763669>

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 6cc783f7f3)
2024-05-23 08:57:35 +02:00
ringabout
1425654e9d fixes #23556; typeinfo.extendSeq generates random values in ORC (#23557)
fixes #23556

It should somehow handle default fields in the future

(cherry picked from commit 36bf3fa47b)
2024-05-23 08:57:27 +02:00
lit
1463d811fb Update unicode.nim: cmpRunesIgnoreCase: fix doc format (#23560)
Its doc used to render wrongly where `>` is considered as quote block:

![image](https://github.com/nim-lang/Nim/assets/97860435/4aeda257-3231-42a5-9dd9-0052950a160e)

(cherry picked from commit d772186b2d)
2024-05-23 08:57:19 +02:00
ringabout
d372a0030d fixes #23419; internal error with void in generic array instantiation (#23550)
fixes #23419

`void` is only supported as fields of objects/tuples. It shouldn't allow
void in the array.

I didn't merge it with taField because that flag is also used for
tyLent, which is allowed in the fields of other types.

(cherry picked from commit 185e06c923)
2024-05-23 08:56:53 +02:00
ringabout
a6e729ed5d fixes #23321; Error: internal error: openArrayLoc: ref array[0..0, int] (#23548)
fixes #23321

In the function `mapType`, ptrs (tyPtr, tyVar, tyLent, tyRef)
are mapped into ctPtrToArray, the dereference of which is skipped
in the `genref`. We need to skip these ptrs in the function
`genOpenArraySlice`.

(cherry picked from commit d09c3c0f58)
2024-05-22 09:39:02 +02:00
yojiyama7
c5f2d84ac7 fix typo: "As can been seen" to "As can be seen" (#23544)
(cherry picked from commit 47594eb909)
2024-05-22 09:38:57 +02:00
ringabout
24e5e9875c fixes #23531; fixes invalid meta type accepted in the object fields (#23532)
fixes #23531
fixes #19546
fixes #6982

(cherry picked from commit f682dabf71)
2024-05-22 09:38:27 +02:00
ringabout
4e977767a7 fixes #23536; Stack trace with wrong line number when the proc called inside for loop (#23540)
fixes #23536

(cherry picked from commit 0b0f185bd1)
2024-05-22 09:28:43 +02:00
ringabout
df589bcce1 fixes #23522; fixes pre-existing wrong type for iter in liftIterSym (#23538)
fixes #23522

(cherry picked from commit 407c0cb64a)
2024-05-22 09:28:21 +02:00
ringabout
e690ff35a2 fixes #23525; an 'emit' pragma cannot be pushed (#23537)
fixes #23525

(cherry picked from commit 4601bb0255)
2024-05-22 09:24:12 +02:00
ringabout
e3f4c3d417 fixes #23524; global variables cannot be analysed when injecting move (#23529)
fixes #23524

```nim
proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool =
  ...
  result = n.kind == nkSym and n.sym.owner == owner and
    {sfGlobal, sfThread, sfCursor} * n.sym.flags == {} and
    (n.sym.kind != skParam or isSinkParam(n.sym))
```
In `isAnalysableFieldAccess`, globals, cursors are already rejected

(cherry picked from commit cd3cf3a20e)
2024-05-22 09:23:43 +02:00
Nikolay Nikolov
efcb6b4b11 * fix for the debug line info code generation (#23488)
Previously, in certain cases, the compiler would generate debug info for
the correct line number, but for the wrong .nim source file.

(cherry picked from commit 7e3bac9235)
2024-05-21 18:51:04 +02:00
José Paulo
5eee3e06fc fix #23518 - <expr> is crashes nimsuggest (#23523)
This solution should resolve the nimsuggest crash issue. However,
perhaps the problem is in the parser?

fix #23518

(cherry picked from commit 60af04635f)
2024-05-21 18:51:04 +02:00
ringabout
dbbd2c8002 fixes #23505; fixes injectdestructors errors on transformed addr (deref) refs (#23507)
fixes #23505

(cherry picked from commit acd4c8a353)
2024-05-21 18:51:04 +02:00
ringabout
59e49ded2d fixes #23494; Wrong type in object construction error message (#23504)
fixes #23494

(cherry picked from commit 20698b8057)
2024-05-21 18:51:03 +02:00
Pouriya Jamshidi
4bf12a086d fix JSON deep copy description (#23495)
Hi,

This is a tiny change, fixing the error in the documentation of JSON's
deep copy proc.

(cherry picked from commit 1bd0955218)
2024-05-21 18:51:03 +02:00
metagn
b1bfba9a31 stop gensym identifiers hijacking routine decl names in templates (#23392)
fixes #23326

In a routine declaration node in a template, if the routine is marked as
`gensym`, the compiler adds it as a new symbol to a preliminary scope of
the template. If it's not marked as gensym, then it searches the
preliminary scope of the template for the name of the routine, then when
it matches a template parameter or a gensym identifier, the compiler
replaces the name node with a symbol node of the found symbol.

This makes sense for the template parameter since it has to be replaced
later, but not really for the gensym identifier, as it doesn't allow us
to inject a routine with the same name as an identifier previously
declared as gensym (the problem in #23326 is when this is in another
`when` branch).

However this is the only channel to reuse a gensym symbol in a
declaration, so maybe removing it has side effects. For example if we
have:

```nim
proc foo(x: int) {.gensym.} = discard
proc foo(x: float) {.gensym.} = discard
```

it will not behave the same as

```nim
proc foo(x: int) {.gensym.} = discard
proc foo(x: float) = discard
```

behaved previously, which maybe allowed overloading over the gensym'd
symbols.

A note to the "undeclared identifier" error message has also been added
for a potential error code that implicitly depended on the old behavior
might give, namely ``undeclared identifier: 'abc`gensym123'``, which
happens when in a template an identifier is first declared gensym in
code that doesn't compile, then as a routine which injects by default,
then the identifier is used.

(cherry picked from commit 73b0b0d31c)
2024-05-21 18:51:03 +02:00
lit
a798356838 Update encodings.nim, fix open with bad arg raising no EncodingError (#23481)
On POSIX, `std/encodings` uses iconv, and `iconv_open` returns
`(iconv_t) -1` on failure, not `NULL`

(cherry picked from commit c23d6a3cb9)
2024-05-21 18:51:02 +02:00
lit
1d7170f0ed Update syncio.nim, fixes "open by FileHandle" doesn't work on Windows (#23456)
## Reprodution
if on Windows:
```Nim
when defined(windows):
  var file: File
  let succ = file.open(<aFileHandle>)
```
then `succ` will be false.

If tested, it can be found to fail with errno `22` and message: `Invalid
argument`

## Problem
After some investigations and tests,
I found it's due to the `mode` argument for `fdopen`.

Currently `NoInheritFlag`(`'N'` in Windows) is added to `mode` arg
passed to `_fdopen`, but if referring to
[Windows `_fdopen`
doc](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fdopen-wfdopen?view=msvc-170),
you'll find there is no `'N'` describled. That's `'N'` is not accepted
by `_fdopen`.

Therefore, the demo above will fail.

## In Addition
To begin with, technologically speaking, when opening with a
`fileHandle`(or called `fd`), there is no concept of fd-inheritable as
`fd` is opened already.

In POSIX, `NoInheritFlag` is defined as `e`.

It's pointed out in [POSIX `open`
man-doc](https://www.man7.org/linux/man-pages/man3/fopen.3.html) that
`e` in mode is ignored for fdopen(),

which means `e` for `fdopen()` is not wanted, just allowed.

Therefore, better to also not pass `e` to `fdopen`

---

In all, that's this PR.

(cherry picked from commit dee55f587f)
2024-05-21 18:35:22 +02:00
ringabout
eaa8c7ca7a fixes #23422; card regression (#23437)
fixes #23422

ref https://github.com/nim-lang/Nim/issues/20997
https://github.com/nim-lang/Nim/pull/21165

The function `cardSet` is used for large sets that are stored in the
form of arrays. It shouldn't be passed as a pointer

(cherry picked from commit 4b6a9e4add)
2024-05-21 18:35:04 +02:00
ringabout
5f8e08031d fixes #23429; rework --verbosity with warnings/hints (#23441)
fixes #23429

(cherry picked from commit a24990bd8c)
2024-05-21 14:52:30 +02:00
Gianmarco
c2a14cb3fc Fix compile time errors when using tables on 8/16-bits systems. (#23450)
Refer to the discussion in #23439.

(cherry picked from commit afc30a3b93)
2024-05-21 14:52:30 +02:00
arkanoid87
b3a62931cd Update manual.md (#23393)
adding link to generic == for tuples in Open and Closed symbols example

(cherry picked from commit cbf48a253f)
2024-05-21 14:52:29 +02:00
soonsouth
b213da9937 chore: fix some typos (#23412)
Signed-off-by: soonsouth <cuibuwei@163.com>
(cherry picked from commit b387bc49b5)
2024-05-21 14:52:29 +02:00
ringabout
6eb3e3134e closes #22846; adds a test case (#23374)
closes #22846

(cherry picked from commit 6ebad30e7a)
2024-05-21 14:19:42 +02:00
ringabout
1e2d98a3e0 closes #15751; adds a test case (#23372)
closes #15751

(cherry picked from commit a2584c779b)
2024-05-21 14:19:35 +02:00
ringabout
55b5068d20 closes #10219; adds a test case (#23370)
closes #10219

(cherry picked from commit d373d304ff)
2024-05-21 14:19:25 +02:00
Juan M Gómez
c17e48c9c5 makes nimsuggest listen on localhost by default (#23351)
(cherry picked from commit 2081da3207)
2024-05-21 14:19:19 +02:00
ringabout
11713ef018 remove obselete doc with nimrtl (#23358)
since nimrtl.dll is created with `--threads:on`

(cherry picked from commit a619434904)
2024-05-21 14:19:04 +02:00
Juan M Gómez
b522d1fe24 Dont mangle when targeting cpp (#23335)
Unfortunately we cant trick the debugger when targeting C++ so this one
also needs to wait for our own debugger adapter.

(cherry picked from commit 90fe1b340f)
2024-05-21 14:18:54 +02:00
autumngray
dd94d98110 Fix nimsuggest highlight for import statements (#23263)
Currently, I don't have syntax highlighting (+ no/wrong
jump-to-definition) for some import statement forms, namely:

- `import module/name/with/(slashes)`
- `import (mod) as alias`
- `import basemod/[ (sub1), (sub2) ]`

With this patch, highlight/def will work for the regions indicated by
parentheses.

(cherry picked from commit 15577043e8)
2024-05-21 14:17:58 +02:00
Juan M Gómez
2f399807cb [Backport 2.0 ] Skips generic owner when mangling instances (#23600) 2024-05-14 15:03:26 +02:00
metagn
5cecd81a05 fix semFinishOperands for bracket expressions [backport:2.0] (#23571)
fixes #23568, fixes #23310

In #23091 `semFinishOperands` was changed to not be called for `mArrGet`
and `mArrPut`, presumably in preparation for #23188 (not sure why it was
needed in #23091, maybe they got mixed together), since the compiler
handles these later and needs the first argument to not be completely
"typed" since brackets can serve as explicit generic instantiations in
which case the first argument would have to be an unresolved generic
proc (not accepted by `finishOperand`).

In this PR we just make it so `mArrGet` and `mArrPut` specifically skip
calling `finishOperand` on the first argument. This way the generic
arguments in the explicit instantiation get typed, but not the
unresolved generic proc.

(cherry picked from commit 09bd9d0b19)
2024-05-08 18:41:43 +02:00
narimiran
526e48b2ed handle the weirdness of the type of the type keyword 2024-05-03 07:35:06 +02:00
metagn
a16f126614 add switch, warning, and bind support for new generic injection behavior (#23102)
refs #23091, especially post merge comments

Unsure if `experimental` and `bind` are the perfect constructs to use
but they seem to get the job done here. Symbol nodes do not get marked
`nfOpenSym` if the `bind` statement is used for their symbol, and
`nfOpenSym` nodes do not get replaced by new local symbols if the
experimental switch is not enabled in the local context (meaning it also
works with `push experimental`). However this incurs a warning as the
fact that the node is marked `nfOpenSym` means we did not `bind` it, so
we might want to do that or turn on the experimental switch if we didn't
intend to bind it.

The experimental switch name is arbitrary and could be changed.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 4b1a841707)
2024-05-03 07:32:19 +02:00
metagn
8b815cc857 delay resolved procvar check for proc params + acknowledge unresolved statics (#23188)
fixes #23186

As explained in #23186, generics can transform `genericProc[int]` into a
call `` `[]`(genericProc, int) `` which causes a problem when
`genericProc` is resemmed, since it is not a resolved generic proc. `[]`
needs unresolved generic procs since `mArrGet` also handles explicit
generic instantiations, so delay the resolved generic proc check to
`semFinishOperands` which is intentionally not called for `mArrGet`.

The root issue for
[t6137](https://github.com/nim-lang/Nim/blob/devel/tests/generics/t6137.nim)
is also fixed (because this change breaks it otherwise), the compiler
doesn't consider the possibility that an assigned generic param can be
an unresolved static value (note the line `if t.kind == tyStatic: s.ast
= t.n` below the change in sigmatch), now it properly errors that it
couldn't instantiate it as it would for a type param. ~~The change in
semtypinst is just for symmetry with the code above it which also gives
a `cannot instantiate` error, it may or may not be necessary/correct.~~
Now removed, I don't think it was correct.

Still possible that this has unintended consequences.

(cherry picked from commit e8092a5470)
2024-05-02 12:17:23 +02:00
metagn
d43672833a allow replacing captured syms in macro calls in generics (#23091)
fixes #22605, separated from #22744

This marks symbol captures in macro calls in generic contexts as
`nfOpenSym`, which means if there is a new symbol in the local
instantiatied body during instantiation time, this symbol replaces the
captured symbol. We have to be careful not to consider symbols outside
of the instantiation body during instantiation, because this will leak
symbols from the instantiation context scope rather than the original
declaration scope. This is done by checking if the local context owner
(maybe should be the symbol of the proc currently getting instantiated
instead? not sure how to get this) is the same as or a parent owner of
the owner of the replacement candidate symbol.

This solution is distinct from the symchoice mechanisms which we
originally assumed had to be related, if this assumption was wrong it
would explain why this solution took so long to arrive at.

(cherry picked from commit 941659581a)
2024-05-02 10:02:06 +02:00
Juan M Gómez
fcb8461efa Fixes an issue where exported types werent being cgen with the exportc pragma (#23369)
(cherry picked from commit 78c834dd76)
2024-04-28 06:57:55 +02:00
ringabout
871cd4b9db fixes refc with non-var destructor; cancel warnings (#23156)
fixes https://forum.nim-lang.org/t/10807

(cherry picked from commit 35ec9c31bd)
2024-04-27 20:00:30 +02:00
ringabout
fa78d937dc fixes #22597; avoid side effects for call returning openArray types (#23257)
fixes #22597

```nim
proc autoToOpenArray*[T](s: Slice[T]): openArray[T] =
  echo "here twice"
  result = toOpenArray(s.p, s.first, s.last)
```
For functions returning openarray types, `fixupCall` creates a temporary
variable to store the return value: `let tmp = autoToOpenArray()`. But
`genOpenArrayConv` cannot handle openarray assignements with side
effects. It should have stored the right part of the assignment first
instead of calling the right part twice.

(cherry picked from commit d44b0b1869)
2024-04-27 20:00:30 +02:00
metagn
b302b3102e don't use previous bindings of auto for routine return types (#23207)
fixes #23200, fixes #18866

not turned to `tyUntyped`. This had the side effect that anything
previously bound to `tyAnything` in the proc type match was then bound
to the proc return type, which is wrong since we don't know the proc
return type even if we know the expected parameter types (`tyUntyped`
also [does not care about its previous bindings in
`typeRel`](ab4278d217/compiler/sigmatch.nim (L1059-L1061))
maybe for this reason).

Now we mark `tyAnything` return types for routines as `tfRetType` [as
done for other meta return
types](18b5fb256d/compiler/semtypes.nim (L1451)),
and ignore bindings to `tyAnything` + `tfRetType` types in `semtypinst`.
On top of this, we reset the type relation in `paramTypesMatch` only
after creating the instantiation (instead of trusting
`isInferred`/`isInferredConvertible` before creating the instantiation),
using the same mechanism that `isBothMetaConvertible` uses.

This fixes the issues as well as making the disabled t15386_2 test
introduced in #21065 work. As seen in the changes for the other tests,
the error messages give an obscure `proc (a: GenericParam): auto` now,
but it does give the correct error that the overload doesn't match
instead of matching the overload pre-emptively and expecting a specific
return type.

tsugar had to be changed due to #16906, which is the problem where
`void` is not inferred in the case where `result` was never touched.

(cherry picked from commit f46f26e79a)
2024-04-27 20:00:30 +02:00
ringabout
eb3aa70ffa fixes #22939; fixes #16890; push should but doesn't apply to importc … (#22944)
…var/let symbols

fixes #22939
fixes #16890

Besides, it was applied to let/const/var with pragmas, now it is
universally applied.

```nim
{.push exportc.}
proc foo =
  let bar = 12
  echo bar
{.pop.}
```

For example, the `bar` variable will be affected by `exportc`.

(cherry picked from commit cecaf9c56b)
2024-04-26 14:27:17 +02:00
ringabout
72a2fe5125 fixes broken nightlies; follow up #22544 (#22585)
ref https://github.com/nim-lang/nightlies/actions/runs/5970369118/job/16197865657

> /home/runner/work/nightlies/nightlies/nim/lib/pure/os.nim(678, 30) Error: getApplOpenBsd() can raise an unlisted exception: ref OSError

(cherry picked from commit 1fcb53cded)
2024-04-24 06:48:51 +02:00
narimiran
e582f1ccb3 Revert "Look up generic parameters when found inside semOverloadedCall, fixin… (#23054)"
This reverts commit 54bd380011.
2024-04-23 18:01:24 +02:00
narimiran
0e1a699937 Revert "Overloads passed to static proc parameters now convert to the desired… (#23063)"
This reverts commit 82e77a13f3.
2024-04-23 18:01:12 +02:00
bptato
494b5486ba Fix std/base64.decode out of bounds read (#23526)
inputLen may end up as 0 in the loop if the input string only includes
trailing characters. e.g. without the patch, decode(" ") would panic.

(cherry picked from commit 30cf570af9)
2024-04-23 06:57:55 +02:00
narimiran
33817f2c30 Revert "fixes #22923; fixes =dup issues (#23182)"
This reverts commit fbb9ce4d5c.
2024-04-23 06:57:09 +02:00
Gianmarco
f44c49c5bd Change unicode lookup tables to have int32 elements to support platforms where sizeof(int) < 4 (#23433)
Fixes an issue that comes up when using strutils.`%` or any other
strutils/strformat feature that uses the unicode lookup tables behind
the scenes, on systems where ints are than 32-bit wide.

Tested with:

```bash
./koch test cat lib
```

Refer to the discussion in #23125.

(cherry picked from commit 4c38569229)
2024-04-22 16:18:24 +02:00
Igor Sirotin
3dd5e11480 fix: use ErrorColor for hints marked as errors (#23430)
# Description

When using `--hintAsError`, we want some red color to appear in the
logs.
Same is already done for `warningAsError`.

# Cherry-picking to Nim 1.6

Would be nice to cherry-pick this and the `warningAsError` log highlight
to 1.6 branch, as it's used in status-desktop.

(cherry picked from commit 50c1e93a74)
2024-04-22 16:18:16 +02:00
ringabout
716ff93161 fixes #23401; prevents nrvo for cdecl procs (#23409)
fixes #23401

(cherry picked from commit f639cf063f)
2024-04-22 16:18:08 +02:00
metagn
1ac5aa951d propagate efWantStmt in semWhen (#23400)
fixes #23399

The new case introduced in #21657 is triggered by `efWantStmt` but the
`when` statement doesn't normally propagate this flag, so propagate it
when the `semCheck` param in `semWhen` is true which happens when the
`when` statement is `efWhenStmt` anyway.

(cherry picked from commit fb6c805568)
2024-04-22 16:17:56 +02:00
ringabout
d112874078 fixes #22166; adds sideeffects for close and setFilePos (#23380)
fixes #22166

(cherry picked from commit 1e20165a15)
2024-04-22 16:17:09 +02:00
ringabout
61da33f31b fixes #22284; fixes #22282; don't override original parameters of inferred lambdas (#23368)
fixes #22284
fixes #22282

```
Error: j(uRef, proc (config: F; sources: auto) {.raises: [].} = discard ) can raise an unlisted exception: Exception
```

The problem is that `n.typ.n` contains the effectList which shouldn't
appear in the parameter of a function defintion. We could not simply use
`n.typ.n` as `n[paramsPos]`. The effect lists should be stripped away
anyway.

(cherry picked from commit 320311182c)
2024-04-22 16:16:57 +02:00
ringabout
e15aa20059 fixes sink regression for ORC; ref #23354 (#23359)
ref #23354

The new move analyzer requires types that have the tfAsgn flag
(otherwise `lastRead` will return true); tfAsgn is included when the
destructor is not trival. But it should consider the assignement for
objects in this case because objects might have a trival destructors but
it's the assignement that matters when it is passed to sink parameters.

(cherry picked from commit 572b0b67ff)
2024-04-22 10:22:28 +02:00
ringabout
8d7b7ff861 fixes #13481; fixes #22708; disable using union objects in VM (#23362)
fixes #13481;
fixes #22708

Otherwise it gives implicit results or bad codegen

(cherry picked from commit 31d7554524)
2024-04-22 10:22:28 +02:00
Jacek Sieka
d389310bb9 strformat: detect format string errors at compile-time (#23356)
This also prevents unwanted `raises: [ValueError]` effects from bubbling
up from correct format strings which makes `fmt` broadly unusable with
`raises`.

The old runtime-based `formatValue` overloads are kept for
backwards-compatibility, should anyone be using runtime format strings.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit a1e41930f8)
2024-04-22 10:22:28 +02:00
ringabout
1ae6deda61 fixes #22723; skips tyUserTypeClasses in injectdestructors (#23341)
fixes #22723

(cherry picked from commit 6ce6cd4bb8)
2024-04-22 10:22:28 +02:00
ringabout
6d38eafda1 fixes #23304; uses snprintf instead of sprintf (#23322)
fixes #23304

(cherry picked from commit dfd778d056)
2024-04-22 10:22:28 +02:00
heterodoxic
845be91df5 assume a module's usage if it contains a passC/passL/compile pragma w… (#23323)
…hich conveys effects beyond its module scope for C/C++
codegen(suppresses current UnusedImport warning)

Just a minor inconvenience working in the area of C/C++ integration I
guess, but here we go:

I noticed receiving ```UnusedImport``` warnings for modules having only
```passC```/```passL```/```compile``` pragmas around. I gather the
compiler cannot actually infer those modules being unused as they *may*
have consequences for the whole build process (as they did in my simple
case).

Thus, I hereby suggest adding the `sfUsed` flag to the respective module
in order to suppress the compiler's warning.

I reckon other pragmas should be put into consideration as well: I will
keep up the investigation with PR followups.

(cherry picked from commit 9a46230335)
2024-04-22 10:22:27 +02:00
ringabout
fa003a00ee fixes regression #22909; don't optimize result init if statements can raise which corrupts the compiler (#23271)
fixes #22909
required by https://github.com/nim-lang/Nim/pull/23267

```nim
proc foo: string =
  assert false
  result = ""
```

In the function `foo`, `assert false` raises an exception, which can
cause `result` to be uninitialized if the default result initialization
is optimized out

(cherry picked from commit 7d9721007c)
2024-04-22 08:53:16 +02:00
ringabout
45f1b19942 clean up goto exceptions; remove the setjmp.h dep (#23259)
(cherry picked from commit e3350cbe6f)
2024-04-22 08:53:03 +02:00
ringabout
96917755cd fixes #23247; don't destroy openarray since it doesn't own the data (#23254)
fixes #23247
closes #23251 (which accounts for why the openarray type is lifted
because ops are lifted for openarray conversions)

related: https://github.com/nim-lang/Nim/pull/18713

It seems to me that openarray doesn't own the data, so it cannot destroy
itself. The same case should be applied to
https://github.com/nim-lang/Nim/issues/19435. It shouldn't be destroyed
even openarray can have a destructor. A cleanup will be followed for
https://github.com/nim-lang/Nim/pull/19723 if it makes sense.

According to https://github.com/nim-lang/Nim/pull/12073, it lifts
destructor for openarray when openarray is sunk into the function, when
means `sink openarray` owns the data and needs to destroy it. In other
cases, destructor shouldn't be lifted for `openarray` in the first place
and it shouldn't destroy the data if it doesn't own it.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 24a606902a)
2024-04-22 08:52:55 +02:00
Bung
8a7a776034 fix mime types data (#23226)
generated via https://github.com/bung87/mimetypes_gen

source data:
http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/conf/mime.types?view=co

(cherry picked from commit 01097fc1fc)
2024-04-20 09:44:31 +02:00
Angel Ezquerra
e33d96ad4e Make std/math classify work without --passc:-fast-math. (#23211)
By using the existing isNaN function we can make std/math's classify
function work even if `--passc:-fast-math` is used.

(cherry picked from commit 38f9ee0e58)
2024-04-20 09:44:31 +02:00
ringabout
5a2cd98867 fixes #22218; avoids cursor when copy is disabled (#23209)
fixes #22218

(cherry picked from commit b2f79df81c)
2024-04-20 09:44:31 +02:00
ringabout
a1b310d186 fixes #12334; keeps nkHiddenStdConv for cstring conversions (#23216)
fixes #12334

`nkHiddenStdConv` shouldn't be removed if the sources aren't literals,
viz. constant symbols.

(cherry picked from commit 3fb46fac32)
2024-04-20 09:44:31 +02:00
metagn
f97c0cced0 error on large integer types as array index range (#23229)
fixes #17163, refs #23204

Types that aren't `tyRange` and are bigger than 16 bits, so `int32`,
`uint64`, `int` etc, are disallowed as array index range types.
`tyRange` is excluded because the max array size is backend independent
(except for the specific size of `high(uint64)` which crashes the
compiler) and so there should still be an escape hatch for people who
want bigger arrays.

(cherry picked from commit 3ab8b6b2cf)
2024-04-20 09:44:31 +02:00
ringabout
2c964268f8 fixes #23223; prevents insert self-assignment (#23225)
fixes #23223

(cherry picked from commit 3379d26629)
2024-04-20 09:44:30 +02:00
ringabout
a715aeb716 fixes #23180; fixes #19805; prohibits invalid tuple unpacking code in for loop (#23185)
fixes #23180
fixes #19805

(cherry picked from commit ab4278d217)
2024-04-20 09:44:30 +02:00
ringabout
d57200bc6f fixes #15924; Tuple destructuring is broken with closure iterators (#23205)
fixes #15924

(cherry picked from commit 8484abc2e4)
2024-04-20 09:44:30 +02:00
ringabout
fbb9ce4d5c fixes #22923; fixes =dup issues (#23182)
fixes #22923

(cherry picked from commit 29ac3c9986)
2024-04-20 09:44:29 +02:00
metagn
76735147b3 trigger range check with new type inference on nkIntLit [backport:1.6] (#23179)
fixes #23177

`changeType` doesn't perform range checks to see if the expression fits
the new type [if the old type is the same as the new
type](62d8ca4306/compiler/semexprs.nim (L633)).
For `nkIntLit`, we previously set the type to the concrete base of the
expected type first, then call `changeType`, which works for things like
range types but not bare types of smaller bit size like `int8`. Now we
don't set the type (so the type is nil), and `changeType` performs the
range check when the type is unset (nil).

(cherry picked from commit 00be8f287a)
2024-04-19 18:31:38 +02:00
metagn
c2d297cc3c don't transform typed bracket exprs to [] calls in templates (#23175)
fixes #22775

It's pre-existing that [`prepareOperand` doesn't typecheck expressions
which have
types](a4f3bf3742/compiler/sigmatch.nim (L2444)).
Templates can take typed subscript expressions, transform them into
calls to `[]`, and then have this `[]` not be resolved later if the
expression is nested inside of a call argument, which leaks an untyped
expression past semantic analysis. To prevent this, don't transform any
typed subscript expressions into calls to `[]` in templates. Ditto for
curly subscripts (with `{}`) and assignments to subscripts and curly
subscripts (with `[]=` and `{}=`).

(cherry picked from commit 62d8ca4306)
2024-04-19 16:42:44 +02:00
Ryan McConnell
4886534ed3 Fixes #23172 (#23173)
#23172

(cherry picked from commit a4f3bf3742)
2024-04-19 16:42:34 +02:00
ringabout
2ed16bf2d4 fixes #23139; Cannot get repr of range type of enum (#23164)
fixes #23139

(cherry picked from commit 3dee1a3e4c)
2024-04-19 16:42:27 +02:00
ringabout
c3d043e980 fixes #23167; take nkOpenSymChoice into consideration caused by templates [backport] (#23168)
fixes #23167

(cherry picked from commit 4eaa3b028c)
2024-04-19 16:39:22 +02:00
Jacek Sieka
0cdca3a0cd Recommend hanging indent in NEP1 (#23105)
This PR modernises the NEP1 style guide to prefer hanging indent over
vertial alignment for long code statements while still allowing
alignment in legacy code.

The change is based on research and study of existing style guides for
both braced and indented languages that have seen wide adoption as well
as working with a large Nim codebase with several teams touching the
same code regularly.

The research was done as part of due diligence leading up to
[nph](https://github.com/arnetheduck/nph) which uses this style
throughout.

There are several reasons why hanging indent works well for
collaboration, good code practices and modern Nim features:

* as NEP1 itself points out, alignment causes unnecessary friction when
refactoring, adding/removing items to lists and otherwise improving code
style or due to the need for realignment - the new recommendation aligns
NEP1 with itself
* When collaborating, alignment leads to unnecessary git conflicts and
blame changes - with hanging indent, such conflicts are minimised.
* Vertical alignment pushes much of the code to the right where often
there is little space - when using modern features such as generics
where types may be composed of several (descriptively named) components,
there is simply no more room for parameters or comments
* The space to the left of the alignemnt cannot productively be used for
anything (unlike on the right, where comments may be placed)
* Double hanging indent maintaines visual separation between parameters
/ condition and the body that follows.

This may seem like a drastic change, but in reality, it is not:

* the most popular editor for Nim (vscode) already promotes this style
by default (if you press enter after `(`, it will jump to an indent on
the next line)
* although orthogonal to these changes, tools such as `nph` can be used
to reformat existing code should this be desired - when done in a single
commit, `git blame` is not lost and neither are exsting PRs (they can
simply be reformatted deterministically) - `nph` is also integrated with
vscode.
* It only affects long lines - ie most code remains unchanged

Examples of vertical alignment in the wild, for wildly successful
languages and formatters:

* [PEP-8](https://peps.python.org/pep-0008/#indentation)
*
[black](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#how-black-wraps-lines)
* [prettier](https://prettier.io/docs/en/)

The above examples are useful mainly to show that hanging-indent
_generally_ is no impediment to efficient code reading and on the whole
is an uncontroversial choice as befits the standard library.

(cherry picked from commit c4f98b7696)
2024-04-19 16:39:13 +02:00
Gianmarco
5e22f6ca58 Fix cmpRunesIgnoreCase on system where sizeof(int) < 4. Fixes #23125. (#23138)
Fixes an issue where importing the `strutils` module, or any other
importing the `strutils` module, ends up with a compile time error on
platforms where ints are less then 32-bit wide.

The fix follows the suggestions made in #23125.

(cherry picked from commit 15c7b76c66)
2024-04-19 16:37:28 +02:00
metagn
f8d538f4ad fix spurious indent and newlines in rendering of nkRecList (#23121)
Rendering of `nkRecList` produces an indent and adds a new line at the
end. However for things like case object `of`/`else` branches or `when`
branches this is already done, so this produces 2 indents and an extra
new line. Instead, just add an indent in the place where the indent that
`nkRecList` produces is needed, for the rendering of the final node of
`nkObjectTy`. There doesn't seem to be a need to add the newline.

Before:

```nim
case x*: bool
of true:
    y*: int

of false:
  nil
```

After:

```nim
case x*: bool
of true:
  y*: int
of false:
  nil
```

(cherry picked from commit fc49c6e3ba)
2024-04-19 16:37:23 +02:00
Jake Leahy
8efdc313a3 Don't crash for invalid toplevel parseStmt/Expr calls (#23089)
This code will crash `check`/`nimsuggest` since the `ra` register is
uninitialised

```nim
import macros

static:
  discard parseExpr("'")
```
Now it assigns an empty node so that it has something

Testament changes were so I could properly write a test. It would pass
even with a segfault since it could find the error

(cherry picked from commit db9d8003b0)
2024-04-19 16:37:16 +02:00
Jake Leahy
49cc3c5746 Mark macros.error as .noreturn. (#23081)
Closes #14329

Marks `macros.error` as `.noreturn` so that it can be used in
expressions. This also fixes the issue that occurred in #19659 where a
stmt that could be an expression (Due to having `discardable` procs at
the end of other branches) would believe a `noreturn` proc is returning
the same type e.g.
```nim
 proc bar(): int {.discardable.} = discard

if true: bar()
else: quit(0) # Says that quit is of type `int` and needs to be used/discarded except it actually has no return type
```

(cherry picked from commit b3b87f0f8a)
2024-04-19 16:35:26 +02:00
Jake Leahy
865a2f895e Allow parseAll to parse statements separated by semicolons (#23088)
Fixes the second issue listed in #9918.

Fixed by replacing the logic used in `parseAll` with just a continious
loop to `complexOrSimpleStmt` like what the [normal parser
does](https://github.com/nim-lang/Nim/blob/devel/compiler/passes.nim#L143-L146).
`complexOrSimpleStmt` [guarantees
progress](https://github.com/nim-lang/Nim/blob/devel/compiler/parser.nim#L2541)
so we don't need to check progress ourselves.

Also allows `nimpretty` to parse more valid Nim code such as
```nim
proc foo(); # Would complain about indention here
proc foo() =
  # ...
```

(cherry picked from commit 0bd4d80238)
2024-04-19 16:35:07 +02:00
Jason Beetham
82e77a13f3 Overloads passed to static proc parameters now convert to the desired… (#23063)
… type mirroring proc params

(cherry picked from commit 91efa49550)
2024-04-19 14:01:22 +02:00
Pylgos
fca71c4bb4 fixes #9381; Fix double evaluation of types in generic objects (#23072)
fixes https://github.com/nim-lang/Nim/issues/9381

(cherry picked from commit 1b7b0d69db)
2024-04-19 14:01:07 +02:00
ringabout
3d4ec68e54 fixes #23060; editDistance wrongly compare the length of rune strings (#23062)
fixes #23060

(cherry picked from commit 7e1ea50bc3)
2024-04-19 14:00:01 +02:00
Jason Beetham
54bd380011 Look up generic parameters when found inside semOverloadedCall, fixin… (#23054)
…g static procs

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 8cc3c774c8)
2024-04-19 13:59:54 +02:00
narimiran
55905604da Revert "fixes #22913; fixes #12985 differently push-ing pragma exportc genera… (#22941)"
This reverts commit d566d21730.
2024-04-19 08:12:35 +02:00
Jakub
fd64402e47 allow Nix builds by not calling git in isGitRepo for Nimble (#23515)
Because `isGitRepo()` call requires `/bin/sh` it will always fail when
building Nim in a Nix build sandbox, and the check doesn't even make
sense if Nix already provides Nimble source code.

Since for Nimble `allowBundled` is set to `true` this effectlvely does
not change behavior for normal builds, but does avoid ugly hacks when
building in Nix which lacks `/bin/sh` and fails to call `git`.

Reference:
*
https://github.com/status-im/nimbus-eth2/pull/6180#discussion_r1570237858

Signed-off-by: Jakub Sokołowski <jakub@status.im>
(cherry picked from commit d6823f4776)
2024-04-18 12:28:06 +02:00
ringabout
c696ec92db fixes #23001; give a better warning for PtrToCstringConv (#23005)
fixes #23001

(cherry picked from commit 7ea5aaaebb)
2024-04-18 10:34:01 +02:00
SirOlaf
4bc45bb6bc Fix endsInNoReturn for case statements (#23009)
While looking at the CI I noticed that there's a couple false positives
for `case` statements that cannot be checked for exhaustiveness since my
changes, this should resolve them.

---------

Co-authored-by: SirOlaf <>
(cherry picked from commit 9140f8e221)
2024-04-18 10:33:54 +02:00
ringabout
9f35ede1a8 fixes #22926; Different type inferred when setting a default value for an array field (#22999)
fixes #22926

(cherry picked from commit 96513b2506)
2024-04-18 10:33:47 +02:00
ringabout
51fa2fada1 fixes #22996; typeAllowedCheck for default fields (#22998)
fixes #22996

(cherry picked from commit 795aad4f2a)
2024-04-18 10:33:25 +02:00
John Viega
aed04c6405 fix: std/marshal unmarshaling of ref objects (#22983)
Fixes #16496

![Marshal doesn't properly unmarshal *most* ref objects; the exceptions
being nil
ones](https://github-production-user-asset-6210df.s3.amazonaws.com/4764481/285471431-a39ee2c5-5670-4b12-aa10-7a10ba6b5b96.gif)
Test case added.

Note that this test (t9754) does pass locally, but there are tons of
failures by default on OS X arm64, mostly around the bohem GC, so it's
pretty spammy, and could easily have missed something. If there are
better instructions please do let me know.

---------

Co-authored-by: John Viega <viega@Johns-MacBook-Pro.local>
Co-authored-by: John Viega <viega@Johns-MBP.localdomain>
Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
(cherry picked from commit 5b2fcabff5)
2024-04-18 10:33:14 +02:00
ringabout
d566d21730 fixes #22913; fixes #12985 differently push-ing pragma exportc genera… (#22941)
…tes invalid C identifiers

fixes #22913
fixes #12985 differently

`{.push.} now does not apply to generic instantiations`

(cherry picked from commit 5dafcf4957)
2024-04-18 10:30:56 +02:00
Derek
5c4c8c44dc let InotifyEvent type sizeof-able (#22958)
Since the `InotifyEvent`s are receive through `read()`, user need the
size of the type.

(cherry picked from commit 0f7488e20f)
2024-04-18 10:30:51 +02:00
握猫猫
47f1ab7b97 Fix OSError errorCode field is not assigned a value (#22954)
In this PR, the following changes were made:
1. Replaced `raise newException(OSError, osErrorMsg(errno))` in batches
with `raiseOSError(errcode)`.
2. Replaced `newException(OSError, osErrorMsg(errno))` in batches with
`newOSError(errcode)`.

There are still some places that have not been replaced. After checking,
they are not system errors in the traditional sense.

```nim
proc dlclose(lib: LibHandle) =
  raise newException(OSError, "dlclose not implemented on Nintendo Switch!")
```

```nim
if not fileExists(result) and not dirExists(result):
  # consider using: `raiseOSError(osLastError(), result)`
  raise newException(OSError, "file '" & result & "' does not exist")
```

```nim
proc paramStr*(i: int): string =
  raise newException(OSError, "paramStr is not implemented on Genode")
```

(cherry picked from commit 39fbd30513)
2024-04-18 10:30:46 +02:00
ringabout
710801d880 fixes #22932; treats closure iterators as pointers (#22934)
fixes #22932
follow up https://github.com/nim-lang/Nim/pull/21629

---------

Co-authored-by: Nickolay Bukreyev <SirNickolas@users.noreply.github.com>
(cherry picked from commit 0dc3513613)
2024-04-18 10:30:40 +02:00
ringabout
39d0eb3a58 fixes #22673; Cannot prove that result is initialized for a placehold… (#22915)
…er base method returning a lent

fixes #22673

(cherry picked from commit 2e070dfc76)
2024-04-18 10:30:34 +02:00
Jacek Sieka
71dde8f7cf reserve sysFatal for Defect (#22158)
Per manual, `panics:on` affects _only_ `Defect`:s - thus `sysFatal`
should not redirect any other exceptions.

Also, when `sysFatal` is used in `nimPanics` mode, it should use regular
exception handling pipeline to ensure exception hooks are called
consistently for all raised defects.

(cherry picked from commit 58c44312af)
2024-04-18 10:30:26 +02:00
ringabout
683a1213db fixes #22860; suppress AnyEnumConv warning when iterating over set (#22904)
fixes #22860

(cherry picked from commit af556841ac)
2024-04-18 10:30:16 +02:00
ringabout
3ae3050b80 fixes #22902; borrow from proc return type mismatch (#22908)
fixes #22902

(cherry picked from commit 95e5ad6927)
2024-04-18 10:30:09 +02:00
ringabout
bd829c093d fixes #22883; replace default(typeof( with reset; suppress `Unsaf… (#22895)
fixes #22883

…eDefault` warnings

avoid issues mentioned by https://forum.nim-lang.org namely, it
allocated unnecessary stack objects in the loop

```c
while (1)
{
tyObject_N__8DSNqSGSHBKOhI8CqSgAow T5_;
nimZeroMem((void *)(&T5_), sizeof(tyObject_N__8DSNqSGSHBKOhI8CqSgAow));
eqsink___test4954_u450((&(*t_p0).data.p->data[i].Field1), T5_);
}
```

It might be more efficient in some cases

follow up https://github.com/nim-lang/Nim/pull/21821

(cherry picked from commit 92141e82ed)
2024-04-18 10:29:59 +02:00
SirOlaf
5e20e935dd Fix #22826: Don't skip generic instances in type comparison (#22828)
Close #22826

I am not sure why this code skips generic insts, so letting CI tell me.
Update: It has told me nothing. Maybe someone knows during review.

Issue itself seems to be that the generic instance is skipped thus it
ends up being just `float` which makes it use the wrong generic instance
of the proc because it matches the one in cache

---------

Co-authored-by: SirOlaf <>
(cherry picked from commit c13c48500b)
2024-04-18 10:29:53 +02:00
ringabout
106c7d2afb fixes #22844; uses arrays to store holeyenums for iterations; much more efficient than sets and reasonable for holeyenums (#22845)
fixes #22844

(cherry picked from commit e10878085e)
2024-04-18 10:29:47 +02:00
ringabout
755a15d8d4 fixes #19250; fixes #22259; ORC AssertionDefect not containsManagedMemory(n.typ) (#22823)
fixes #19250
fixes #22259

The strings, seqs, refs types all have this flag, why should closures be
treated differently?

follow up https://github.com/nim-lang/Nim/pull/14336

(cherry picked from commit f5d70e7fa7)
2024-04-18 10:29:33 +02:00
ringabout
a5a6a4d39e fixes #22790; use cast suppress AnyEnumConv warnings for enums withou… (#22813)
…t holes

fixes #22790

(cherry picked from commit ecaccafa6c)
2024-04-18 09:04:17 +02:00
ringabout
3120c6e839 use lent for the return value of index accesses of tables (#22812)
ref https://forum.nim-lang.org/t/10525

(cherry picked from commit 9d7acd001f)
2024-04-18 09:03:06 +02:00
ringabout
0d255b4ea1 suppress incorrect var T destructor warnings for newFinalizer in stdlib (#22810)
in `std/nre`
```nim
proc initRegex(pattern: string, flags: int, study = true): Regex =
  new(result, destroyRegex)
```
gives incorrect warnings like

```
C:\Users\blue\Documents\Nim\lib\impure\nre.nim(252, 6) Error: A custom '=destroy' hook which takes a 'var T' parameter is deprecated; it should take a 'T' parameter [Deprecated
```

(cherry picked from commit 14d25eedfd)
2024-04-18 09:02:55 +02:00
ringabout
e9067c03c6 allows cast int to bool/enum in VM (#22809)
Since they are integer types, by mean of allowing cast integer to enums
in VM, we can suppress some enum warnings in the stdlib in the unified
form, namely using a cast expression.

(cherry picked from commit 2cf214d6d4)
2024-04-18 09:02:44 +02:00
ringabout
999d29d2a0 fixes #8893; guard against array access in renderer (#22807)
fixes #8893

(cherry picked from commit 81b2ae747e)
2024-04-18 09:02:38 +02:00
ringabout
08d37c2d7e fixes #22787; marks var section in the loop as reassign preventing cursor (#22800)
fixes #22787

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit efa64aa49b)
2024-04-18 09:02:29 +02:00
Ryan McConnell
4f78a4dd3e Make typeRel behave to spec (#22261)
The goal of this PR is to make `typeRel` accurate to it's definition for
generics:
```
# 3) When used with two type classes, it will check whether the types
# matching the first type class (aOrig) are a strict subset of the types matching
# the other (f). This allows us to compare the signatures of generic procs in
# order to give preferrence to the most specific one:
```

I don't want this PR to break any code, and I want to preserve all of
Nims current behaviors. I think that making this more accurate will help
serve as ground work for the future. It may not be possible to not break
anything but this is my attempt.

So that it is understood, this code was part of another PR (#22143) but
that problem statement only needed this change by extension. It's more
organized to split two problems into two PRs and this issue, being
non-breaking, should be a more immediate improvement.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit b2ca6bedae)
2024-04-18 09:01:14 +02:00
ringabout
bb82d46ef1 fixes #22696; func strutils.join for non-strings uses proc $ which can have side effects (#22770)
fixes #22696
partially revert https://github.com/nim-lang/Nim/pull/16281

`join` calls `$` interally, which might introduce a sideeffect call.

(cherry picked from commit 5eeafbf550)
2024-04-18 09:01:09 +02:00
Juan M Gómez
567900be76 case macro now can be used inside generic. Fixes #20435 (#22752)
fixes #20435

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
Co-authored-by: Jake Leahy <jake@leahy.dev>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 0c179db657)
2024-04-18 09:01:03 +02:00
ringabout
cb899ccf25 ref #19727; implement setLenUninit for seqsv2 (#22767)
ref #19727

(cherry picked from commit 285cbcb6aa)
2024-04-18 09:00:58 +02:00
ringabout
710fd14393 fixes #10542; suppresses varargs conversion warnings (#22757)
fixes #10542
revives and close #20169

(cherry picked from commit a7a0cfe8eb)
2024-04-18 09:00:51 +02:00
ringabout
499ad5b63c fixes #22706; turn "unknown hint" into a hint (#22755)
fixes #22706

(cherry picked from commit 3979e83fcb)
2024-04-18 09:00:46 +02:00
ringabout
8ab6cf1ca8 fixes #22246; generate __builtin_unreachable hints for case defaults (#22737)
fixes #22246
resurrects #22350

(cherry picked from commit a1b6fa9420)
2024-04-18 09:00:35 +02:00
ringabout
577ffbc57c items, pairs and friends now use unCheckedInc (#22729)
`{.push overflowChecks: off.}` works in backends. Though it could be
implemented as a magic function.

By inspecting the generated C code, the overflow check is eliminated in
the debug or release mode.

![image](https://github.com/nim-lang/Nim/assets/43030857/49c3dbf4-675e-414a-b972-b91cf218c9f8)

Likewise, the index checking is probably not needed.

(cherry picked from commit d82bc0a29f)
2024-04-18 09:00:28 +02:00
Juan M Gómez
e918a762f7 fixes compiler crash by preventing exportc on generics (#22731)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit fefde3a735)
2024-04-18 09:00:05 +02:00
metagn
d56000eaff make parseEnum skip type aliases for enum type sym (#22727)
fixes #22726

(cherry picked from commit 51cb493b22)
2024-04-18 08:59:51 +02:00
litlighilit
cc7f76a247 Update osfiles.nim, make moveFile consider permission on *nix (#22719)
see https://github.com/nim-lang/Nim/issues/22674

(cherry picked from commit 741285b335)
2024-04-18 08:59:35 +02:00
ringabout
adf3e3ceb5 fixes incorrect cint overflow in system (#22718)
fixes #22700

(cherry picked from commit 63c2ea5566)
2024-04-18 08:59:28 +02:00
SirOlaf
344feb0dd1 Fix #22713: Make size unknown for tyForward (#22714)
Close #22713

---------

Co-authored-by: SirOlaf <>
(cherry picked from commit fcf4c1ae17)
2024-04-17 16:02:18 +02:00
metagn
dc6058fb9b implement semgnrc for tuple and object type nodes (#22709)
fixes #22699

(cherry picked from commit 8836207a4e)
2024-04-17 16:01:48 +02:00
Amjad Ben Hedhili
bbf32118a2 followup of #22568 (#22690)
(cherry picked from commit 38b58239e8)
2024-04-17 16:01:36 +02:00
metagn
b2cb5f55ac refactor semtempl ident declarations, some special word use (#22693)
`semtempl` is refactored to combine the uses of `getIdentNode`,
`onlyReplaceParams`, `isTemplParam` and most of `replaceIdentBySym` into
a single `getIdentReplaceParams` proc. This might fix possible problems
with injections of `nkAccQuoted`.

Some special word comparison in `ast` and `semtempl` are also made more
efficient.

(cherry picked from commit ac1804aba6)
2024-04-17 16:01:29 +02:00
ringabout
7083d397f3 fixes the discVal register is used after free in vmgen (#22688)
follow up https://github.com/nim-lang/Nim/pull/11955

(cherry picked from commit b1a8d6976f)
2024-04-17 16:01:23 +02:00
Amjad Ben Hedhili
3ddacd90d1 Remove some unnecessary initialization in seq operations (#22677)
* `PrepareSeqAdd`
* `add`
* `setLen`
* `grow`

Merge after #21842.

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
(cherry picked from commit fbb5ac512c)
2024-04-17 16:01:17 +02:00
ringabout
cb3e5d3f28 [minor] merge similar branches in vmgen (#22683)
(cherry picked from commit 2ce9197d3a)
2024-04-17 16:01:11 +02:00
Amjad Ben Hedhili
12f2c36aca Make newSeqOfCap not initialize memory. (#21842)
It's used in `newSeqUninitialized`.

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
(cherry picked from commit 8853fb0775)
2024-04-17 15:53:16 +02:00
ringabout
a12cb273b3 fixes #22664; guard against potential seqs self assignments (#22671)
fixes #22664

(cherry picked from commit 5f13e15e0a)
2024-04-17 15:51:26 +02:00
Juan M Gómez
1bbbb2f46b fixes #22662 Procs with constructor pragma doesn't initialize object's fields (#22665)
fixes #22662 Procs with constructor pragma doesn't initialize object's
fields

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit d45270bdf7)
2024-04-17 15:51:15 +02:00
SirOlaf
28cef86a09 Fix #21742: Check generic alias depth before skip (#22443)
Close #21742

Checking if there's any side-effects and if just changing typeRel is
adequate for this issue before trying to look into related ones.

`skipBoth` is also not that great, it can lead to code that works
sometimes but fails when the proc is instantiated with branching
aliases. This is mostly an issue with error clarity though.

---------

Co-authored-by: SirOlaf <unknown>
Co-authored-by: SirOlaf <>
(cherry picked from commit 2a8c759df0)
2024-04-17 14:07:06 +02:00
metagn
9ac5666271 make getType nodes of generic insts have full inst type (#22655)
fixes #22639 for the third time

Nodes generated by `getType` for `tyGenericInst` types, instead of
having the original `tyGenericInst` type, will have the type of the last
child (due to the `mapTypeToAst` calls which set the type to the given
argument). This will cause subsequent `getType` calls to lose
information and think it's OK to use the sym of the instantiated type
rather than fully expand the generic instantiation.

To prevent this, update the type of the node from the `mapTypeToAst`
calls to the full generic instantiation type.

(cherry picked from commit ed9e3cba07)
2024-04-17 14:06:46 +02:00
metagn
70ab7a53f3 resolve unambiguous enum symchoices from local scope, error on rest (#22606)
fixes #22598, properly fixes #21887 and fixes test case issue number

When an enum field sym choice has to choose a type, check if its name is
ambiguous in the local scope, then check if the first symbol found in
the local scope is the first symbol in the sym choice. If so, choose
that symbol. Otherwise, give an ambiguous identifier error.

The dependence on the local scope implies this will always give
ambiguity errors for unpicked enum symchoices from generics and
templates and macros from other scopes. We can change `not
isAmbiguous(...) and foundSym == first` to `not (isAmbiguous(...) and
foundSym == first)` to make it so they never give ambiguity errors, and
always pick the first symbol in the symchoice. I can do this if this is
preferred, but no code from CI seems affected.

(cherry picked from commit 480e98c479)
2024-04-17 14:06:38 +02:00
metagn
70d771d1a9 fix isNil folding for compile time closures (#22574)
fixes #20543

(cherry picked from commit bd6adbcc9d)
2024-04-17 14:06:21 +02:00
Pylgos
45aa0a4725 Fix the problem where instances of generic objects with sendable pragmas are not being cached (#22622)
remove `tfSendable` from `eqTypeFlags`

(cherry picked from commit 9f1fe8a2da)
2024-04-17 14:06:09 +02:00
Juan M Gómez
d4c1cc7a34 fixes internal error: no generic body fixes #1500 (#22580)
* fixes internal error: no generic body fixes #1500

* adds guard

* adds guard

* removes unnecessary test

* refactor: extracts containsGenericInvocationWithForward

(cherry picked from commit 0c6e13806d)
2024-04-17 14:06:00 +02:00
metagn
131a0328b5 resolve local symbols in generic type call RHS (#22610)
resolve local symbols in generic type call

fixes #14509

(cherry picked from commit f1789cc465)
2024-04-17 14:05:52 +02:00
metagn
7335495db7 don't update const symbol on const section re-sems (#22609)
fixes #19849

(cherry picked from commit 53d9fb259f)
2024-04-17 14:05:42 +02:00
ringabout
24f3272db3 fixes #22613; Default value does not work with object's discriminator (#22614)
* fixes #22613; Default value does not work with object's discriminator

fixes #22613

* merge branches

* add a test case

* fixes status

* remove outdated comments

* move collectBranchFields into the global scope

(cherry picked from commit affd3f7858)
2024-04-17 14:04:48 +02:00
metagn
3911c90d7b type annotations for variable tuple unpacking, better error messages (#22611)
* type annotations for variable tuple unpacking, better error messages

closes #17989, closes https://github.com/nim-lang/RFCs/issues/339

* update grammar

* fix test

(cherry picked from commit ba158d73dc)
2024-04-17 14:04:43 +02:00
metagn
7c44af4e22 properly fold constants for dynlib pragma (#22575)
fixes #12929

(cherry picked from commit 6b955ac4af)
2024-04-17 14:04:29 +02:00
Bung
d49d7ba90c fix #22548;environment misses for type reference in iterator access n… (#22559)
* fix #22548;environment misses for type reference in iterator access nested in closure

* fix #21737

* Update lambdalifting.nim

* remove containsCallKinds

* simplify

(cherry picked from commit 0b78b7f595)
2024-04-17 14:04:19 +02:00
ringabout
26f3dfff75 fixes a strictdef ten years long vintage bug, which counts the same thing twice (#22549)
fixes a strictdef ten years long vintage bug

(cherry picked from commit 1013378854)
2024-04-17 14:03:45 +02:00
Jacek Sieka
271632a72d Fix getAppFilename exception handling (#22544)
* Fix `getAppFilename` exception handling

avoid platform-dependendent error handling strategies

* more fixes

* space

(cherry picked from commit bc9785c08d)
2024-04-17 14:01:27 +02:00
metagn
0d02bee23f round out tuple unpacking assignment, support underscores (#22537)
* round out tuple unpacking assignment, support underscores

fixes #18710

* fix test messages

* use discard instead of continue

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 53d43e9671)
2024-04-17 14:00:45 +02:00
metagn
c39a0139fc allow non-pragma special words as user pragmas (#22526)
allow non-pragma special words as macro pragmas

fixes #22525

(cherry picked from commit 602f537eb2)
2024-04-17 12:40:00 +02:00
SirOlaf
06464fe2ff Fix #21722 (#22512)
* Keep return in mind for sink
* Keep track of return using bool instead of mode
* Update compiler/injectdestructors.nim
* Add back IsReturn

---------

Co-authored-by: SirOlaf <>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit c0ecdb01a9)
2024-04-17 12:40:00 +02:00
metagn
8eaf98d64f cascade tyFromExpr in type conversions in generic bodies (#22499)
fixes #22490, fixes #22491, adapts #22029 to type conversions

(cherry picked from commit 98c39e8e57)
2024-04-17 12:40:00 +02:00
ringabout
2a4755ddf2 fixes #22469; generates nimTestErrorFlag for top level statements (#22472)
fixes #22469; generates `nimTestErrorFlag` for top level statements

(cherry picked from commit 09d0fda7fd)
2024-04-17 12:39:59 +02:00
Pylgos
814e929eeb fix #22448 Remove structuredErrorHook temporary in tryConstExpr (#22450)
* fix #22448

* add test

(cherry picked from commit 48da472dd2)
2024-04-17 12:39:59 +02:00
ringabout
6f00b46c4b fixes move sideeffects issues [backport] (#22439)
* fixes move sideeffects issues [backport]

* fix openarray

* fixes openarray

(cherry picked from commit faf1c91e6a)
2024-04-17 12:39:44 +02:00
Bung
665480372e fix #19304 Borrowing std/times.format causes Error: illformed AST (#20659)
* fix #19304 Borrowing std/times.format causes Error: illformed AST

* follow suggestions

* mitigate for #4121

* improve error message

(cherry picked from commit 2aab03bdfb)
2024-04-17 10:57:32 +02:00
SirOlaf
2fa314a89d Fix #21760 (#22422)
* Remove call-specific replaceTypeVarsN

* Run for all call kinds and ignore typedesc

* Testcase

---------

Co-authored-by: SirOlaf <>
(cherry picked from commit baf350493b)
2024-04-17 10:55:19 +02:00
Bung
bd63124a00 fix #12938 index type of array in type section without static (#20529)
* fix #12938 nim compiler assertion fail when literal integer is passed as template argument for array size

* use new flag tfImplicitStatic

* fix

* fix #14193

* correct tfUnresolved add condition

* clean test

(cherry picked from commit d53a89e453)
2024-04-17 10:55:14 +02:00
Bung
b67d0a64b4 fix #20891 Illegal capture error of env its self (#22414)
* fix #20891 Illegal capture error of env its self

* fix innerClosure too earlier, make condition shorter

(cherry picked from commit 989da75b84)
2024-04-17 10:55:05 +02:00
ringabout
09109c55c9 clean up gc:arc or gc:orc in docs and in error messages (#22408)
* clean up gc:arc/orc in docs

* in error messages

(cherry picked from commit 10a6e4c236)
2024-04-17 10:54:56 +02:00
Bung
c1745b5924 fix #18823 Passing Natural to bitops.BitsRange[T] parameter in generi… (#20683)
* fix #18823 Passing Natural to bitops.BitsRange[T] parameter in generic proc is compile error

(cherry picked from commit 37d8f32ae9)
2024-04-17 09:37:18 +02:00
ringabout
a7394440b9 Delete parse directory, which was pushed wrongly before [backport] (#22401)
Delete parse directory

(cherry picked from commit 614a18cd05)
2024-04-17 09:37:02 +02:00
Bung
42e4190e1a add test for #3907 (#21069)
* add test for #3907

(cherry picked from commit 137d608d7d)
2024-04-17 09:36:48 +02:00
norrath-hero-cn
36b339bbcf Prevent early destruction of gFuns, fixes AddressSanitizer: heap-use-after-free (#22386)
Prevent destruction of gFuns before callClosures

(cherry picked from commit e0396900ed)
2024-04-17 09:36:41 +02:00
Andreas Rumpf
fb2cc06557 destructors: better docs [backport:2.0] (#22391)
(cherry picked from commit 9872453365)
2024-04-17 09:36:34 +02:00
Tomohiro
ac66f6ce7a Fix searchExtPos so that it returns -1 when the path is not a file ext (#22245)
* Fix searchExtPos so that it returns -1 when the path is not a file ext

* fix comparision expression

* Remove splitDrive from searchExtPos

(cherry picked from commit db435a4a79)
2024-04-17 09:36:23 +02:00
Bung
f4d99c8d56 fix #20883 Unspecified generic on default value segfaults the compiler (#21172)
* fix #20883 Unspecified generic on default value segfaults the compiler

* fallback to isGeneric

* change to closer error

* Update t20883.nim

(cherry picked from commit 26f183043f)
2024-04-17 09:36:10 +02:00
ringabout
d097028307 fixes a typo in the manual (#22383)
ref 0d3bde95f5 (commitcomment-122093273)

(cherry picked from commit 7c2a2c8dc8)
2024-04-17 09:35:58 +02:00
ringabout
7fbf42960b follow up #22322; fixes changelog (#22381)
(cherry picked from commit fb7acd6600)
2024-04-17 09:35:13 +02:00
konsumlamm
526dbf0cf2 Make repr(HSlice) always available (#22332)
Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
(cherry picked from commit d37b620757)
2024-04-17 09:34:31 +02:00
ringabout
1c19d5c72e fixes #22362; Compiler crashes with staticBoundsCheck on (#22363)
(cherry picked from commit 825a0e7df4)
2024-04-17 09:34:23 +02:00
ringabout
413395866f fixes #22360; compare with the half of randMax (#22361)
* fixes #22360; compare with the half of randMax

* add a test

(cherry picked from commit f3a7622514)
2024-04-17 09:34:15 +02:00
narimiran
3ad16028aa bump NimVersion to 2.0.5 2024-04-16 15:49:33 +02:00
Nikolay Nikolov
b47747d318 [backport v2.0] Converted the 'invalid kind for firstOrd/lastOrd(XXX)' messages from internal errors to fatal errors. (#23443) (#23446)
This fixes a nimsuggest crash when opening:
    beacon_chain/consensus_object_pools/blockchain_dag.nim
from the nimbus-eth2 project and many other .nim files (44 files, to be
precise) in the same project.

Replaces: https://github.com/nim-lang/Nim/pull/23402 (cherry picked from
commit c934d5986d)
2024-03-27 15:58:56 +01:00
Александр Старочкин
5667fbfbf3 fix position for "imported but not used" warning for modules inside brackets (#23424) 2024-03-21 08:03:31 +01:00
narimiran
d4b58b0b06 bump NimVersion to 2.0.4 2024-03-19 16:39:02 +01:00
Nikolay Nikolov
ef356cfd4b * [backport] fixed nimsuggest crash with 'Something = concept' put (erroneously) outside of a 'type' block (#23331) (#23346)
(cherry picked from commit 37ed8c8480)
2024-03-19 05:46:52 +01:00
Juan M Gómez
e374759f29 [Backport 2.0] When NimScript errors prevents NimSuggest from Init (#23349) 2024-03-09 11:42:34 +01:00
Juan M Gómez
0de70dc7f3 [backport 2.0] nimsuggest fix (#23336) 2024-03-04 09:58:54 +01:00
Andreas Rumpf
2f15b67fd9 fixes an issue with string to 'var openArray' at compile-time; [backport] (#23363)
(cherry picked from commit 24fbacc63f)
2024-03-03 15:42:20 +01:00
ringabout
e03667e920 improve error messages [backport] (#23345)
ref https://forum.nim-lang.org/t/11052

![image](https://github.com/nim-lang/Nim/assets/43030857/1df87691-32d9-46b5-b61b-6b9f7cc94862)

(cherry picked from commit 1e7ca2dc78)
2024-02-27 08:17:37 +01:00
Nikolay Nikolov
11c048b06f fixes #22753; Nimsuggest segfault with invalid assignment to table (#22781) (#23313)
fixes #22753

## Future work
We should turn all the error nodes into nodes of a nkError kind, which
could be a industrious task. But perhaps we can add a special treatment
for error nodes to make the transition smooth.

(cherry picked from commit 642ac0c1c3)

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2024-02-24 07:54:42 +01:00
Nikolay Nikolov
22de3ae53e * fixed nimsuggest crash when opening a .nim file, that contain a {.fatal: "msg".} pragma. (#23325) (#23328)
(cherry picked from commit 773c066634)
2024-02-24 07:40:18 +01:00
Juan M Gómez
3be2514683 [Backport 2.0] Itanium mangling scheme (#23301) 2024-02-13 08:09:23 +01:00
ringabout
57658b685c fixes regression #23280; Operations on inline toOpenArray len return a wrong result (#23285)
fixes #23280

(cherry picked from commit 4b67cccf50)
2024-02-07 20:25:45 +01:00
ringabout
5f6ff1f051 compute checksum of nim files early in the pipelines (#23268)
related https://github.com/nim-lang/Nim/issues/21717 configs will be
resolved later

(cherry picked from commit 519d976f62)
2024-02-01 12:30:21 +01:00
rockcavera
7e6f4723c3 Fix system.currentSourcePath() documentation [backport 2.0] (#23243)
The documentation links for `parentDir()` and `getCurrentDir()` are
broken as they are no longer part of `std/os`. Link changed to
`std/private/ospaths2`.

(cherry picked from commit 9c155eaccc)
2024-01-30 08:11:10 +01:00
metagn
4a1151d6b4 give typedesc param nodes type T not typedesc[T] [backport:2.0] (#23115)
fixes https://github.com/nim-lang/Nim/issues/23112, fixes a mistake in
https://github.com/nim-lang/Nim/pull/22581

This makes `getType(t)` where `t` is a typedesc param with value `T`
equal to `getType(T)`.

(cherry picked from commit 3224337550)
2024-01-19 09:19:18 +01:00
Giuliano Mega
9994b019c5 Fix reset code gen for range types (#22462, #23214) (#23215)
This PR modifies `specializeResetT` so that it generates the proper
reset code for range types. I've tested it in the examples for issues
issues I had been experiencing.

(cherry picked from commit 473f259268)
2024-01-19 09:18:23 +01:00
metagn
bb930aef2d don't render underscore identifiers with id (#22538)
(cherry picked from commit 4f891aa50c)
2024-01-16 08:43:09 +01:00
Nikolay Nikolov
be66aedb9e + show the inferred exception list (as part of the type) for functions that don't have an explicit .raises pragma (#23193) (#23210)
(cherry picked from commit 18b5fb256d)
2024-01-16 15:36:03 +08:00
Juan M Gómez
4bc305db1e backport nimsuggest capabilities to 2.0 (#23191) 2024-01-09 22:48:18 +08:00
Juan M Gómez
fdb1f4451d makes nimsuggest con work under v3 [backport 2.0.2] (#23159)
Co-authored-by: Jake Leahy <jake@leahy.dev>
2024-01-08 20:30:59 +01:00
metagn
02497c9533 2.0 branch fixes: no LineTooLong, update macos CI (#23184)
Adapts #23108 to the version-2-0 branch and makes the 2.0 compiler
define `nimHasNoLineTooLong` as the devel compiler depends on it to not
turn off `hint[LineTooLong]`, which means the 2.0 compiler errors on the
devel compiler config (as mentioned in
https://github.com/nim-lang/Nim/issues/23178#issuecomment-1880511322).

Would have these as separate PRs but the macos CI PR would have to be
merged first, then the second PR would have to be rebased.
2024-01-08 13:49:20 +01:00
ringabout
0acdce502c fixes #23148; restricts infix path concatenation to what starts with / (#23150)
fixes #23148

(cherry picked from commit c7d742e484)
2024-01-03 10:57:42 +01:00
narimiran
fe1d4a6232 bump NimVersion to 2.0.3 2024-01-03 10:57:30 +01:00
narimiran
c4c44d10df bump NimVersion to 2.0.2 2023-12-14 17:51:05 +01:00
ringabout
55bb60a56b fixes #22947; static integers in quote do [backport] (#22948)
fixes #22947

(cherry picked from commit 09ea1b168f)
2023-12-14 17:48:55 +01:00
Amjad Ben Hedhili
ef8b8317ff Fix capacity for const and shallow [backport] (#22705)
(cherry picked from commit b542be1e7d)
2023-12-14 17:47:00 +01:00
Nikolay Nikolov
fff127bec7 Skip trailing asterisk when placing inlay type hints. Fixes #23067 (backport of #23068) (#23070)
(cherry picked from commit a3739751a8)
2023-12-14 09:26:01 +08:00
Kernel-Zhang
7b5289a1a4 Correction of “Tnfds” type error (#23045)
The types in Nim don't match the actual types in the header files, this
can lead to bugs in some cases.
2023-12-08 11:09:49 +01:00
Nikolay Nikolov
3a0d09c1c5 backport to version 2.0: display raises pragma in proc types (#23026) (#23028)
This affects also nimsuggest hints (e.g. on mouse hover), as well as
compiler messages.

(cherry picked from commit 618ccb6b6a)
2023-12-04 09:46:57 +01:00
metagn
3ab6012c81 fix generic param substitution in templates (#22535)
* fix generic param substitution in templates

fixes #13527, fixes #17240, fixes #6340, fixes #20033, fixes #19576, fixes #19076

* fix bare except in test, test updated packages in CI

(cherry picked from commit 1cc4d3f622)
2023-12-01 08:27:06 +01:00
Jake Leahy
add124e07a Register declaration of enum field has a use (#22990)
Currently when using `use` with nimsuggest on an enum field, it doesn't
return the definition of the field.

Breaks renaming in IDEs since it will replace all the usages, but not
the declaration

(cherry picked from commit c31bbb07fb)
2023-11-28 08:25:56 +01:00
tersec
8834f3e74d remove unnecessary side-effects from base64.encode(mime) (#22986)
Fixes https://github.com/nim-lang/Nim/issues/22985

(cherry picked from commit 26f2ea149c)
2023-11-26 07:15:40 +01:00
Nikolay Nikolov
489dd89a45 backport to v 2.0: nimsuggest: Added optional command line option '--clientProcessId:XXX' (#22969) (#22981)
When it is specified, the nimsuggest instance monitors whether this
process is still alive. In case it's found to be dead, nimsuggest shuts
itself down. Currently only implemented on POSIX and Windows platforms.
The switch is silently ignored on other platforms. Note that the Nim
language server should still try to shut down its child nimsuggest
processes. This switch just adds extra protection against crashing Nim
language server and gets rid of the remaining nimsuggest processes,
which consume memory and system resources.

(cherry picked from commit 502a4486ae)
2023-11-25 11:50:27 +01:00
Nikolay Nikolov
ba9effc8a1 Backport to 2.0: Introduced version 4 of the NimSuggest protocol. The InlayHints feature made V4 or later only. (#22953) (#22963)
Since nimsuggest now has a protocol version support detection via
`--info:protocolVer`, the InlayHints feature can be moved to protocol
V4. This way, the Nim language server can detect the nimsuggest version
and avoid sending unsupported `InlayHints` commands to older nimsuggest
versions. Related nim language server PR:
https://github.com/nim-lang/langserver/pull/60

(cherry picked from commit 4fc0027b57)
2023-11-20 09:13:33 +08:00
Nikolay Nikolov
0d93fdf607 backport to version 2.0: nimsuggest: Instead of checking for protocol version 3 exactly, check for version 3 or later. (#22945) (#22957)
Refactored the way nimsuggest checks for protocol version 3. Instead of
checking for version 3 exactly, it now checks for version 3 or later.
This way, once a version 4 is introduced, it will use version 3 as a
base line, and then extra changes to the protocol can be added on top.
No functional changes are introduced in this commit.

(cherry picked from commit 3680200df4)
2023-11-18 09:52:06 +08:00
Nikolay Nikolov
b8cec0c714 Added new command line option --info:X to nimsuggest for obtaining … (#22943)
…information. (#22940)

`--info:protocolVer` returns the highest nimsuggest protocol version
that is supported (currently, it's version 3).
`--info:nimVer` returns the Nim compiler version that nimsuggest uses
internally.

Note that you can obtain the Nim compiler version via `nimsuggest -v`,
but that requires parsing the output, which looks like this:

```
Nim Compiler Version 2.1.1 [Linux: amd64]
Compiled at 2023-11-14
Copyright (c) 2006-2023 by Andreas Rumpf

git hash: 47ddfeca5247dce992becd734d1ae44e621207b8
active boot switches: -d:release -d:danger --gc:markAndSweep
```

`--info:nimVer` will return just:

```
2.1.1
```

(cherry picked from commit d0cc02dfc4)
2023-11-16 20:30:22 +08:00
Nikolay Nikolov
4793fc0fc1 Inlay hints backport to Nim v2.0.x (#22919)
Backport of the nimsuggest inlay hints to the Nim v2.0.x series.
2023-11-09 07:33:20 +01:00
ringabout
e1b44666b0 iNim switch to the official URL (#22762)
ref https://github.com/inim-repl/INim/pull/139

(cherry picked from commit 02ba28eda5)
2023-11-08 13:55:49 +01:00
ringabout
194d21a6e4 fixes stint CI (#22756)
(cherry picked from commit 46544f234d)
2023-11-08 13:55:41 +01:00
metagn
1b80f7126a switch back to main neo in CI (#22660)
refs https://github.com/andreaferretti/neo/pull/53

(cherry picked from commit b9f039e0c3)
2023-11-08 13:55:31 +01:00
ringabout
1dc85802e2 add union to packages (#22658)
(cherry picked from commit 009ce1e17e)
2023-11-08 13:55:23 +01:00
ringabout
9e081579bb fixes yaml tests (#22595)
(cherry picked from commit dfb3a88cc3)
2023-11-08 13:55:15 +01:00
ringabout
30dad5dfa1 deprecate std/threadpool; use malebolgia, weave, nim-taskpool instead (#22576)
* deprecate `std/threadpool`; use `malebolgia` instead

* Apply suggestions from code review

* Apply suggestions from code review

* change the URL of inim

(cherry picked from commit a7a0105d8c)
2023-11-08 13:55:01 +01:00
ringabout
6d32066055 update test command of important packages (#22485)
(cherry picked from commit 9296b45de4)
2023-11-08 13:54:54 +01:00
ringabout
86e5545c25 fixes #22866; fixes #19998; ensure destruction for Object construction with custom destructors (#22901)
fixes #22866;
fixes #19998

(cherry picked from commit b68e0aab4c)
2023-11-02 14:40:40 +01:00
ringabout
f4e80d51ff bump node to 20.x; since 16.x is End-of-Life (#22892)
(cherry picked from commit f61311f7a0)
2023-10-31 07:08:42 +01:00
ringabout
1db305af1c fixes #22868; fixes std/nre leaks under ARC/ORC (#22872)
fixes #22868

(cherry picked from commit d66f3febd1)
2023-10-29 18:14:45 +01:00
握猫猫
805b4e2dc2 fix use after free (#22854)
1. `freeAddrInfo` is called prematurely, the variable `myAddr` is still
in use
2. Use defer syntax to ensure that `freeAddrInfo` is also called on
exceptions

(cherry picked from commit 562a5fb8f9)
2023-10-24 08:57:38 +02:00
rockcavera
e8e9948223 fix #22834 (#22843)
fix #22834

Edit: also fixes `result.addrList` when IPv6, which previously only
performed a `result.addrList = cstringArrayToSeq(s.h_addr_list)` which
does not provide the textual representation of an IPv6

(cherry picked from commit 27deacecaa)
2023-10-24 08:57:25 +02:00
Amjad Ben Hedhili
75441dcdc3 Initialize newString in js [backport:1.6] (#22745)
```nim
echo newString(8)
```

results in:
```
D:\User\test.js:25
                  var code_33556944 = c_33556931.toString(16);
                                                 ^

TypeError: Cannot read properties of undefined (reading 'toString')
    at toJSStr (D:\User\test.js:25:50)
    at rawEcho (D:\User\test.js:70:16)
    at Object.<anonymous> (D:\User\test.js:101:1)
    at Module._compile (node:internal/modules/cjs/loader:1095:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1147:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:17:47

Node.js v17.0.1
Error: execution of an external program failed: '"C:\Program Files\nodejs\node.exe" --unhandled-rejections=strict D:\User\test.js'
```

(cherry picked from commit eadd0d72cf)
2023-10-24 08:49:16 +02:00
SirOlaf
d30565f810 Fix #17509: Continue instead of return with unfinished generics (#22563)
Close #17509

Current knowledge:
- delaying cache fixes the issue
- changing return of `if inst.len < key.len:` in `searchInstTypes` to
`continue` fixes the issue. With return the broken types are also cached
over and over

Related issues are completely unaffected as of now, so there must be
something deeper.

I am also still trying to find the true cause, so feel free to ignore
for now

---------

Co-authored-by: SirOlaf <>
(cherry picked from commit ee4a219012)
2023-09-18 12:13:00 +02:00
Amjad Ben Hedhili
5c916b645b Remove some unnecessary initialization in string operations (#22579)
* `prepareAdd`
* `toNimStr`
* `setLengthStrV2`
* `NimAsgnStrV2`
* `prepareMutation`
* Some cleanups

(cherry picked from commit a4df44d9fb)
2023-09-18 12:13:00 +02:00
SirOlaf
9ad184841e Exclude block from endsInNoReturn, fix regression (#22632)
Co-authored-by: SirOlaf <>
(cherry picked from commit d2f36c071b)
2023-09-18 12:13:00 +02:00
metagn
7536d7f94a use dummy dest for void branches to fix noreturn in VM (#22617)
fixes #22216

(cherry picked from commit 2542dc09c8)
2023-09-18 12:13:00 +02:00
metagn
ee0d3f9b34 unify explicit generic param semchecking in calls (#22618)
fixes #9040

(cherry picked from commit 6738f44af3)
2023-09-18 12:13:00 +02:00
SirOlaf
d3cf815dbe Fix #22604: Make endsInNoReturn traverse the tree (#22612)
* Rewrite endsInNoReturn

* Handle `try` stmt again and add tests

* Fix unreachable code warning

* Remove unreachable code in semexprs again

* Check `it.len` before skip

* Move import of assertions

---------

Co-authored-by: SirOlaf <>
(cherry picked from commit 3b206ed988)
2023-09-18 12:12:59 +02:00
ringabout
b477c2adcc fixes #17197; fixes #22560; fixes the dest of newSeqOfCap in refc (#22594)
(cherry picked from commit 5bd1afc3f9)
2023-09-18 12:12:59 +02:00
metagn
78d4aa3d01 handle typedesc params in VM (#22581)
* handle typedesc params in VM

fixes #15760

* add test

* fix getType(typedesc) test

(cherry picked from commit 2e4e2f8f50)
2023-09-18 12:12:59 +02:00
metagn
855f5c8b81 clearer error for different size int/float cast in VM (#22582)
refs #16547

(cherry picked from commit b6cea7b599)
2023-09-18 12:12:59 +02:00
metagn
7ab0f3beec correct logic for qualified symbol in templates (#22577)
* correct logic for qualified symbol in templates

fixes #19865

* add test

(cherry picked from commit 3de8d75513)
2023-09-18 12:12:59 +02:00
ringabout
ba8c9a9d1e newStringOfCap now won't initialize all elements anymore (#22568)
newStringOfCap nows won't initialize all elements anymore

(cherry picked from commit 2e7c8a339f)
2023-09-18 12:12:59 +02:00
metagn
87c1200c93 test case haul for old generic/template/macro issues (#22564)
* test case haul for old generic/template/macro issues

closes #12582, closes #19552, closes #2465, closes #4596, closes #15246,
closes #12683, closes #7889, closes #4547, closes #12415, closes #2002,
closes #1771, closes #5121

The test for #5648 is also moved into its own test
from `types/tissues_types` due to not being joinable.

* fix template gensym test

(cherry picked from commit c19fd69b69)
2023-09-18 12:12:58 +02:00
ringabout
d46e71bea3 fixes #22541; peg matchLen can raise an unlisted exception: Exception (#22545)
The `mopProc` is a recursive function.

(cherry picked from commit c56a712e7d)
2023-09-18 12:12:58 +02:00
SirOlaf
4cf2658235 Fix #21532: Check if template return is untyped (#22517)
* Don't ignore return in semTemplateDef

* Add test

---------

Co-authored-by: SirOlaf <>
(cherry picked from commit 3de75ffc02)
2023-09-18 12:12:58 +02:00
metagn
5fa48e97b6 fix getNullValue for cstring in VM, make other VM code aware of nil cstring (#22527)
* fix getNullValue for cstring in VM

fixes #22524

* very ugly fixes, but fix #15730

* nil cstring len works, more test lines

* fix high

(cherry picked from commit 942f846f04)
2023-09-18 12:12:58 +02:00
ringabout
562fb0d14b fixes #22481; fixes card undefined misalignment behavior (#22484)
* fixes `card` undefined misalignment behavior

* Update lib/system/sets.nim

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit ade75a1483)
2023-09-18 12:12:58 +02:00
Emery Hemingway
320ecc69a0 Add Linux constant SO_BINDTODEVICE (#22468)
(cherry picked from commit 1927ae72d0)
2023-09-18 12:12:58 +02:00
Bung
106cf7a9f7 Fix #5780 (#22428)
* fix #5780

(cherry picked from commit 46e94c83d4)
2023-09-18 10:13:38 +02:00
Jake Leahy
7221c6f156 Fix crash when using uninstantiated generic (#22379)
* Add test case

* Add in a bounds check when accessing generic types

Removes idnex out of bounds exception when comparing a generic that isn't fully instantiated

(cherry picked from commit 3efabd3ec6)
2023-09-18 10:13:27 +02:00
ringabout
4a7cdaecb4 fixes #22262; fixes -d:useMalloc broken with --mm:none and --threads on (#22355)
* fixes #22262; -d:useMalloc broken with --mm:none and threads on

* fixes

(cherry picked from commit a23e53b490)
2023-09-18 10:13:09 +02:00
Amjad Ben Hedhili
81d58d2cc8 Make capacity work with refc [backport] (#22697)
followup of #19771.

(cherry picked from commit 325341866f)
2023-09-14 06:02:46 +02:00
Andreas Rumpf
1080f5eba2 produce better code for object constructions and 'result' [backport] (#22668)
(cherry picked from commit 8f5b90f886)
2023-09-14 06:02:30 +02:00
ringabout
18e62ad136 fixes #22619; don't lift cursor fields in the hook calls (#22638)
fixes https://github.com/nim-lang/Nim/issues/22619

It causes double free for closure iterators because cursor fields are
destroyed in the lifted destructors of `Env`.

Besides, according to the Nim manual

> In fact, cursor more generally prevents object
construction/destruction pairs and so can also be useful in other
contexts.

At least, destruction of cursor fields might cause troubles.

todo
- [x] tests
- [x] revert a certain old PR

---------

Co-authored-by: zerbina <100542850+zerbina@users.noreply.github.com>
(cherry picked from commit eb91cf991a)
2023-09-05 11:50:59 +02:00
metagn
f03aa1d0b5 define toList procs after add for lists [backport] (#22573)
fixes #22543

(cherry picked from commit 94454addb2)
2023-09-05 11:50:41 +02:00
Daniel Belmes
ef63d47ecd fix server caching issue causing Theme failures (#22378)
* fix server caching issue causing Theme failures

* Fix tester to ignore version cache param

* fix case of people using -d:nimTestsNimdocFixup

* rsttester needed the same fix

(cherry picked from commit 7bf7496557)
2023-08-22 08:28:30 +02:00
ringabout
0a58af8cbf fixes #22357; don't sink elements of var tuple cursors (#22486)
(cherry picked from commit 940b1607b8)
2023-08-22 08:23:56 +02:00
Jason Beetham
8359f9683a When in object handles procedure call again, fixes #22474 (#22480)
Ping @narimiran please backport to the 2.0 line.

(cherry picked from commit 6c4e7835bf)
2023-08-22 08:23:32 +02:00
ringabout
c3425c05e9 relax the parameter of ensureMove; allow let statements (#22466)
* relax the parameter of `ensureMove`; allow let statements

* fixes the test

(cherry picked from commit 4c89223171)
2023-08-22 08:23:06 +02:00
Alberto Torres
3fa378533a Fix #22366 by making nimlf_/nimln_ part of the same line (backport) (#22508) 2023-08-22 08:22:58 +02:00
Amjad Ben Hedhili
4850bb5a59 fix seq.capacity [backport] (#22505) 2023-08-22 08:22:42 +02:00
ringabout
037f536e7e fixes #22419; async/closure environment does not align local variables (#22425)
* fixes #22419; async/closure environment does not align local variables

* Apply suggestions from code review

* Update tests/align/talign.nim

Co-authored-by: Jacek Sieka <arnetheduck@gmail.com>

* apply code review

* update tests

---------

Co-authored-by: Jacek Sieka <arnetheduck@gmail.com>
(cherry picked from commit 5334dc921f)
2023-08-11 10:49:49 +02:00
ringabout
287fbc5fb5 fixes #22387; Undefined behavior when with hash(...) (#22404)
* fixes #22387; Undefined behavior when with hash(...)

* fixes vm

* fixes nimscript

(cherry picked from commit 47d06d3d4c)
2023-08-11 10:49:30 +02:00
metagn
f553288db3 block ambiguous type conversion dotcalls in generics (#22375)
fixes #22373

(cherry picked from commit 3aaef9e4cf)
2023-08-11 10:49:11 +02:00
norrath-hero-cn
e0e386314f fixes AddressSanitizer: global-buffer-overflow in getAppFilename on windows 10 (#22380)
fixes AddressSanitizer: global-buffer-overflow

(cherry picked from commit 73a29d72e3)
2023-08-11 10:48:21 +02:00
Michal Maršálek
1de6a7a023 Fix the position of "Grey" in colors.nim (#22358)
Update the position of "Grey"

(cherry picked from commit da368885da)
2023-08-11 10:47:54 +02:00
narimiran
d1db4c29fa bump NimVersion to 2.0.1 2023-08-11 10:47:05 +02:00
narimiran
a488067a41 bump NimVersion to 2.0.0 2023-07-31 21:22:28 +02:00
Andreas Rumpf
35ff70f36c Tomorrow is the release. I hope. (#22353) 2023-07-31 20:19:18 +02:00
ringabout
0b3ddd4e47 Revert "fixes #22246; generate __builtin_unreachable hints for case defaults" (#22351)
Revert "fixes #22246; generate `__builtin_unreachable` hints for case defaults (#22350)"

This reverts commit b56df5c07f.
2023-07-31 22:14:15 +08:00
ringabout
b56df5c07f fixes #22246; generate __builtin_unreachable hints for case defaults (#22350)
* fixes #22246; generate `__builtin_unreachable` hints

* use elif

* indentation

* fixes holy enums in sim
2023-07-31 16:02:52 +02:00
ringabout
569ccc50ff fixes #22174; fixes destructor examples (#22349)
* fixes #22174; fixes destructor examples

* Update doc/destructors.md

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-07-31 15:37:24 +02:00
Bung
d51bc084fd remove thread duplicated code (#22348) 2023-07-31 10:58:59 +02:00
ringabout
281016a802 add a changelog for ensureMove (#22347)
* add a changelog for `ensureMove`

* Update changelogs/changelog_2_0_0_details.md

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-07-30 20:43:52 +02:00
Juan Carlos
19d1fe7af3 Add Valgrind (#22346)
* .

* Add Valgrind for Bisect bot in GitHub Actions
2023-07-30 13:21:22 +08:00
Juan M Gómez
e70992d291 fixes an issue where byref wasnt properly handled when using it in a generic param (#22337)
* fixes an issue where byref wasnt properly handled when using it in a generic param

* removes unreachable check
2023-07-29 18:05:31 +02:00
ringabout
f0f3904ff0 implement ensureMove (#22339)
* implement `ensureMove`

* use an additional flag

* improve some logics

* progress: fixes discard ensureMove

* forbids nested expressions

* improve error messages

* checkpoint

* fixes cursor

* ADD MORE TESTS

* fixes cursorinference again

* tiny cleanup

* improve error messages

* fixes docs

* implement comments add more tests

* fixes js
2023-07-29 10:57:03 +02:00
Eric N. Vander Weele
f1ac979184 Remove declared and not used variable in packedsets.bitincl (#22334)
When compiling code that uses PackedSet with warnings enabled, `var ret`
in `bitincl` emits a "XDeclaredButNotUsed" warning.
2023-07-27 23:07:03 +02:00
konsumlamm
db77c98471 [JS] Fix bitwise ops & shifts (#22340)
* [JS] Fix bitwise ops & shifts

* Test `int64` & `uint64` only with `jsbigint64`
2023-07-27 23:06:30 +02:00
ringabout
11c8dfc9b3 fixes docs (#22331) 2023-07-26 10:04:34 +08:00
konsumlamm
c0994c2dbd [JS] Fix casting to ints (#22327)
* [JS] Fix casting to ints

* Simplify `genCast` by using `asUintN`/`asIntN`
2023-07-25 17:56:14 +02:00
ringabout
1c2ccfad08 fixes #22301; fixes #22324; rejects branch initialization with a runtime discriminator with defaults (#22303)
* fixes #22301; rejects branch initialization with a runtime discriminator with defaults

* undefault nimPreviewRangeDefault

* fixes tests

* use oldCheckDefault
2023-07-25 12:08:32 +02:00
Khaled Hammouda
dce714b259 Fix grammar top rule (#22325)
change stmt to complexOrSimpleStmt in the top grammar rule
2023-07-24 19:48:41 +02:00
ringabout
8216d7dd46 fixes #22321; fixes building DLL with --noMain still produces a DllMain (#22323)
* fixes #22321; Building DLL with --noMain produces an unexpected DllMain on devel branch

* remove implicit nomain
2023-07-24 17:22:50 +02:00
Juan M Gómez
49a108b302 Expands codegenDecl to work in function params. fixes #22306 (#22307)
* Expands codegenDecl to work in function params. fixes #22306

* makes the test more concrete so T{lit} params dont match

* adds sfCodegenDecl
2023-07-23 16:42:20 +02:00
SirOlaf
808c9c6c2a Testcase for #22008 (#22320)
Testcase

Co-authored-by: SirOlaf <>
2023-07-23 21:35:30 +08:00
Andreas Rumpf
be1844541c implemented 'push quirky' switch for fine grained control over the ex… (#22318)
* implemented 'push quirky' switch for fine grained control over the exception handling overhead

* documentation
2023-07-23 13:39:58 +02:00
SirOlaf
62869a5c68 Check try block for endsInNoReturn (#22314)
Co-authored-by: SirOlaf <>
2023-07-22 21:13:55 +02:00
konsumlamm
b10d3cd98d Update 2.0 changelog (#22311) 2023-07-22 21:13:23 +02:00
konsumlamm
e2ea9140ac Document cast zeroing memory (#22313) 2023-07-22 21:11:49 +02:00
konsumlamm
0e555ade31 Add test for #22309 (#22316) 2023-07-22 21:11:08 +02:00
konsumlamm
576f4a7348 Fix doc comment rendering for concepts (#22312) 2023-07-22 19:10:12 +02:00
SirOlaf
3ebe24977c Open scope for defer (#22315)
Co-authored-by: SirOlaf <>
2023-07-22 19:09:39 +02:00
ringabout
b02c1dd6ca fixes #22297; return in the finally in the closure iterators (#22300)
ref #22297; return in the finally in the closure iterators
2023-07-22 06:37:27 +02:00
ringabout
993fcf5bda fixes CI; disable SSL tests on osx for now (#22304)
* test CI

* disable osx
2023-07-22 11:31:01 +08:00
ringabout
91987f8eb5 fixes #22210; transform return future in try/finally properly (#22249)
* wip; fixes #22210; transform return future in try/finally properly

* add a test case for #22210

* minor

* inserts a needsCompletion flag

* uses copyNimNode
2023-07-21 05:40:11 +02:00
Ryan McConnell
2f817ee5b4 infixArgument fail in renderer.nim sometimes (#22264)
* fixing minor typo

* Adding err msg
2023-07-20 19:56:54 +02:00
Jake Leahy
3f9e16594f fix jsondoc not getting showNonExports flag (#22267)
Pass the config down so we can check if the `--showNonExports` flag is used
2023-07-20 19:56:04 +02:00
Andreas Rumpf
c1a82aa5c5 minor code improvement (#22293) 2023-07-19 16:03:26 +02:00
ringabout
5ed44e1ec4 fixes #22254; fixes #22253; stricteffects bugs on recursive calls (#22294) 2023-07-19 15:20:41 +02:00
Ryan McConnell
0d3bde95f5 Adding info to manual (#22252)
* Adjustments

* Moving example

* typo

* adding code example back and fix terms

* Condensing
2023-07-19 15:04:14 +02:00
ringabout
7d9fe106ec fixes #22268; fixes move codegen (#22288) 2023-07-19 12:57:58 +02:00
ringabout
1aff402998 fixes #6499; disallow built-in procs used as procvars (#22291) 2023-07-19 09:45:28 +02:00
Anna
14a9929464 Fix #22281 (#22289)
Respect `--gcc.exe` and similar options when `--genScript:on` is used.
2023-07-18 16:06:21 +02:00
ringabout
f16b94a9d7 extend the skipAddr for potential types for destructors (#22265)
extend the skipAddr for potential types
2023-07-18 16:05:05 +02:00
Jake Leahy
17915d93bf Fix non-toplevel fields in objects not getting rendered (#22266)
* Add example object into testproject

The proc is there to check the case of an identDef being inside an identDef (We do want to render those even if they are not exported)

* Add `inside` set to `TSrcGen` which allows us to see what context we are in

This is done instead of adding another inXyz bool parameter

We then use this to know if we are inside an object when rendering an nkIdentDefs (To know if we need to skip rendering it)

* Update test files
2023-07-16 19:46:18 +02:00
Juan M Gómez
50d435cd39 Fixes Naive virtual crash the compiler fixes #22269 (#22271)
* Fixes Naive virtual crash the compiler fixes #22269

* adds type specific test
2023-07-16 17:01:34 +02:00
ringabout
f9280090f6 fixes idx properly (#22280) 2023-07-14 14:44:02 +02:00
Juan Carlos
db1ce4ff12 Fix #22273 (#22275)
* Fix #22273
2023-07-14 12:40:57 +02:00
ringabout
3b377937de gendepends now supports pkgs2 (#22277) 2023-07-14 12:40:24 +02:00
ringabout
9471b5f964 fixes #22256; fixes GC_disableOrc overflow (#22257) 2023-07-11 19:01:18 +02:00
Solitude
9ddd768cce Rename seq.add parameter to be consistent with refc (#22244) 2023-07-10 14:27:28 +02:00
ringabout
ecc6ab7ee0 fixes #22237; fixes #21160; wrong cursor on unowned parameters in the for loop in ORC (#22240)
fixes #22237; fixes #21160; wrong cursor on unowned parameters
2023-07-10 10:31:13 +02:00
Jake Leahy
1b132ddaa2 Fix nimsuggest not showing suggestions for imported tuples (#22241)
* Add tests

Also test if exported all tuple fields works. This seems like a hacky solution so will try and dive further to find a better solution

* Always suggest tuple fields if it passes the filter

If the tuple we are accessing is in scope then all the fields will also be in scope

* Update tests so line numbers are correct
2023-07-10 08:34:10 +02:00
ringabout
6ec10a4c91 fixes #21730; adds pkgs2 as well when nimbleDir is set (#22234) 2023-07-07 12:40:29 +02:00
Juan Carlos
54d7c9fdf8 Fix #21595 (#22233)
* .

* Fix #21595
2023-07-07 12:39:59 +02:00
Andrey Makarov
2e987cb75a Tolerate markup errors for doc comments (#19607) (#22235)
Follow-up to #21576 (for solving #19607).

1) errors in Markdown mode for `.nim` doc comments are reported with
   red color but allow to generate `.html` with the comment represented by
   literate block (monospaced text). We suppose that it's what people want
   for (supposedly) small doc comments. And this behavior is also a bit
   more Markdown-ish in the sense that Markdown generally does not have
   the concept of parsing error.
   - However, for standalone `.md` it's **not** applied because for large
     files the consequences are way bigger.

(In {.doctype: rst.} mode the behavior is the same as before -- report
the error and stop.)
In future, when our parser can handle Markdown without errors according to
the spec, this code will most probably be not needed.
2023-07-07 12:38:37 +02:00
Juan Carlos
148ff74c93 Fix #21401 (#22232) 2023-07-07 09:18:40 +02:00
Andreas Rumpf
a15db5d60b fixes #22175 (#22229) 2023-07-06 15:15:50 +02:00
ringabout
dfa0d2569e alternative to #22219; adds a pointer wrapper for T destructor (#22225)
* alternative to #22219; adds a pointer wrapper for T destructor

* clean up and add comments

* Update compiler/ccgtypes.nim

* tidy up

* fixes comments

* fixes cpp

* fixes cpp
2023-07-06 11:14:42 +02:00
Jake Leahy
7616e6ee2b Fix concepts with doc comments (#22228)
* Add testcase

This tries to use a concept with a doc comment which currently leads to a segfault

* Ignore nil nodes which happen when there are doc comments in new style concept

This was done instead of semming the comments since `semConceptDecl` says it only supports lists of actual statements

* Go with alternative fix: Sem comments but ignore them

Since `nil` could mean anything it is best to not silently ignore it (In case another nil problem happens in future

Also fix test case so it isn't an infinite loop
2023-07-06 08:18:47 +02:00
ringabout
145e002c74 fixes #22132; hoisted openArray params result in erroneous code (#22224) 2023-07-05 11:21:57 +02:00
Andreas Rumpf
86ff37fab8 fixes #22138 (#22221) 2023-07-04 23:35:25 +02:00
ringabout
31ba1046fc add a test case for #22190 in case of regression (#22217) 2023-07-04 10:58:14 +08:00
ringabout
c513e37a70 fixes #22212; Compile error when running a Nimscript that compares se… (#22213)
fixes #22212; Compile error when running a Nimscript that compares seq with switch("mm", "arc")
2023-07-03 14:15:44 +02:00
ringabout
d9a24b9b81 fixes #22208; Ambiguous error when import modules with same names but… (#22211)
fixes #22208; Ambiguous error when import modules with same names but different aliases
2023-07-03 14:08:40 +02:00
ringabout
1ad618d96c clean up the documentation (#22196) 2023-07-02 22:36:05 +02:00
ringabout
57296a5139 fixes #22197; Distinct ref objects + destructor cause C++ codegen error (#22207) 2023-07-02 21:04:48 +02:00
Andreas Rumpf
83a5865024 fixes #22200 (#22206)
* fixes #22200

* typo
2023-07-02 20:57:10 +02:00
Juan Carlos
aedb4c26de Bisect Bugs (#22157)
* Add Git bisect like for bug repro code on issue comments against Nim versions >1.0
* Add Git bisect like for bug repro code on issue comments against Nim versions >1.0
* Add Git bisect like for bug repro code on issue comments against Nim versions >1.0
2023-07-01 18:18:21 +02:00
心夏❤v
7cb59efd4b Tidy contributing.md: format cmd (#22204) 2023-07-01 16:16:59 +08:00
Juan M Gómez
2f109595e9 reset macrocache after each script evaluation (#22195) 2023-06-30 23:03:25 +02:00
Jacek Sieka
4d2ebbb877 fix controlflow test (#22194)
the function actually returns
2023-06-30 14:54:46 +02:00
Andreas Rumpf
3a1adf7d66 v2.0: changelog improvements (#22192)
* changelog improvements

* changelog that people want to actually read

* improvements
2023-06-30 14:54:29 +02:00
metagn
210b10dd0d fix nested call regression in generic bodies (#22189)
fixes #22187
2023-06-29 22:05:18 +02:00
ringabout
41ec894cb0 alternative to #22183; nimscript shares the same compileTime sym with VM (#22184) 2023-06-29 11:21:22 +02:00
ringabout
d139d99946 fixes #19101; zero initialization union casts (#22185)
* zero initialization union casts

* cleans up and adds a test case for #19101

* uses nimZeroMem
2023-06-29 10:51:18 +02:00
Andrey Makarov
57de460437 Don't throw errors on RST tables in Markdown and RstMarkdown modes (#22165)
* Don't throw errors on RST tables in Markdown and RstMarkdown modes

Additions to RST simple tables (#19859) made their parsing more
restrictive, which can introduce problems with of some old
nimforum posts, which have tables with sloppily aligned columns
(like this one:
https://github.com/nim-lang/nimforum/issues/330#issuecomment-1376039966).
Also this strictness contradicts to Markdown style of not getting
in the way (ignoring errors).

So this PR proposes a new strategy of dealing with errors:
* In Markdown and legacy (old default) RstMarkdown we try to
  continue parsing, emitting only warnings
* And only in pure RST mode we throw a error

I expect that this strategy will be applied to more parts of markup code
in the future.

* Don't return anything in `checkColumns`
2023-06-28 22:38:54 +02:00
metagn
b35942ef83 fix new type inference for noreturn [backport] (#22182)
fixes #22180

Backported since apparently the new type inference was backported
2023-06-28 22:38:08 +02:00
Juan M Gómez
d195877615 docs nimBasePattern (#22179) 2023-06-28 17:49:35 +02:00
Andreas Rumpf
427ad17161 fixes #22001 (#22177)
* fixes #22001

* added test case
2023-06-27 22:42:48 +02:00
Andreas Rumpf
9616762cfe Revert "fix struct stat" (#22171)
Revert "fix struct stat (#22161)"

This reverts commit 4b761295e7.
2023-06-27 16:46:41 +02:00
Andreas Rumpf
ce0909f047 fixes #22137 (#22170) 2023-06-27 14:58:02 +02:00
Andreas Rumpf
faa59b1e1f Use pinned Atlas commit (#22169) 2023-06-27 14:12:21 +02:00
ringabout
e422b3c860 adds =destroy T support for strings and seqs (#22167)
* adds =destroy T support for strings and seqs

* fixes system

* fixes tests
2023-06-27 13:07:29 +02:00
Andreas Rumpf
d52b1d848e destructors: update, =destroy does not require a 'var T' (#22168) 2023-06-27 12:55:47 +02:00
Jacek Sieka
47635d3031 fix Sigaction struct definition (#22160)
SigInfo is still wrong (most of its fields are in a union)
2023-06-27 10:09:04 +02:00
Jacek Sieka
cb40f11e6c uint arithmetic for pointers (#22159)
pointers are not signed and arithmetic may correctly cross int.max
threshold

this PR only fixes 2 occurances - there are plenty however in the std
lib
2023-06-27 08:20:02 +02:00
Jacek Sieka
4b761295e7 fix struct stat (#22161)
Undo damage of https://github.com/nim-lang/Nim/pull/14170
2023-06-27 08:19:17 +02:00
ringabout
4ce3a68e79 fixes #22163; use {.push warning[BareExcept]:off.} to override settings temporarily (#21390)
* use `{.push warning[BareExcept]:off.}` to override settings temporarily

* likewise, suppress expect
2023-06-27 08:03:52 +08:00
ringabout
4546f5dfe5 adds T destructor for refs (#22147)
* adds T destructor for refs

* add `newRefdestructor`

* adds ref overload for destructors

* fixes config
2023-06-26 15:10:06 +02:00
Jake Leahy
43a3de9077 Fix regression in std/times (#22155)
* Add simple test case

Just so the regression doesn't happen again

* Specify initDateTime is gcsafe in the forward declarations
2023-06-26 15:07:42 +02:00
tersec
3e44d5742f rm zero-extension and uint conversions deprecated since 0.19.9 (#22151) 2023-06-25 20:37:21 +02:00
ringabout
942c378659 fixes #22148; std/memfiles.memSlices nesting now fails with memory sa… (#22154)
* fixes #22148; std/memfiles.memSlices nesting now fails with memory safety capture violation

* adds a test case
2023-06-25 17:15:47 +02:00
metagn
20037a4749 make var object match better than object (#22152)
* fix `var object` not matching better than `object`

fixes #13302

* remove comment for brevity

* try note

* try minimize breaks
2023-06-25 16:52:16 +02:00
metagn
f718f295df fix VM uint conversion size bug, stricter int gen on JS (#22150)
* fix VM uint conversion bug, stricter int gen on JS

fixes #19929

* fix float -> uint64 conversion too

* no need to mask to source type

* simpler diff with explanation, add test for described issue
2023-06-25 00:01:08 +02:00
Etan Kissling
c6c85f84db macOS ar doesn't support @ syntax (#22146)
When the linker command line is long, Nim compiler generates a file for
passing the linker arguments. On `macOS`, that mechanism fails as the
`@` syntax is not supported by `ar`. Use `xargs` instead to pass the
linker arguments file.
2023-06-24 08:13:43 +02:00
Juan M Gómez
beaac609ab adds nimbasePattern compiler option (#22144)
adds optonal --nimbasepattern
2023-06-24 08:13:15 +02:00
ringabout
88114948c4 fixes #21110; duplicate proc definitions for inline iters (#21136)
fixes #21110; duplicate proc definitions for iters
2023-06-22 22:17:23 +02:00
ringabout
d137a3b52a fixes :idx: index in in modules (2.0 regression) and in markdown files (persistent issues since 0.20.2) (#22141)
fixes :idx: index
2023-06-22 15:58:10 +02:00
ringabout
ac7b8b678c fixes #21231; template with module as parameter elides usage/checking of module name specifier (#22109)
* fixes #21231; template with module as parameter elides usage/checking of module name specifier

* add a test case
2023-06-21 16:30:55 +02:00
ringabout
eb2f0353bc adds missing staticlib hints (#22140) 2023-06-21 16:30:23 +02:00
Bung
3ad2e7df1c fix #20023 hash for generic tables (#20346)
* fix #20023 hash for generic tables

* use default computation

* Update lib/pure/collections/tables.nim

Co-authored-by: Dan Rose <dan@digilabs.io>

* Update lib/pure/collections/tables.nim

Co-authored-by: Dan Rose <dan@digilabs.io>

* Update lib/pure/collections/tables.nim

* Update lib/pure/collections/tables.nim

* Update t20023.nim

---------

Co-authored-by: Dan Rose <dan@digilabs.io>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-06-21 12:19:40 +02:00
Juan M Gómez
ede03782a3 Update changelog_2_0_0.md (#22135) 2023-06-21 11:41:40 +02:00
Zoom
5e529b3bfa strutils.split/rsplit now return src on an empty sep (#22136)
This is a rebase of an earlier rejected PR. Following the discussion
around it, this commit provides a valid output for and edge case
of an empty separator for `split` and `rsplit` routines. The empty
separator is interpreted as "split by no separators" and the initial
string is returned. This is consistent with the behaviour of the
`set[char]` version of `split`/`rsplit` routines and unifies them all.

Compared to a commit merged earlier, this one has a benefit of
not using assertions that will be removed in release builds
and thus still not preventing possible infinite loops (which was the
earlier behaviour for this edge case for separator of type `string`).

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-06-21 08:52:33 +02:00
ringabout
a345cde26e allow destructors to accept non var parameters; deprecate proc =destroy(x: var T) (#22130)
* make destructors accept non var parameters
* define nimAllowNonVarDestructor
* add a test case and a changelog
* update documentation and error messages
* deprecate destructors taking 'var T'
2023-06-21 08:51:03 +02:00
Ryan McConnell
db41f04ab0 Amend divmod (#22131)
* Add Overflow checks & test adjust

* Avoiding nimvm differences in tests

* distinguish DivByZeroDefect
2023-06-20 13:04:34 +02:00
ringabout
f524d60fa1 fixes #22123; Compiler bug with default initializer values and arrays (#22128) 2023-06-20 08:02:06 +02:00
ringabout
29a43124cf overhaul the error messages of =dup (#22129) 2023-06-20 07:08:39 +02:00
ringabout
2054f1c3a9 fixes #22117; View types lifetime tracking does not work with defer (#22121) 2023-06-19 15:23:51 +02:00
Ivan Yonchovski
2bb7277a61 Create compiler and nimsuggest packages (#22118)
I have tested it locally with the following in my local packages_official.json

```
  {
    "name": "compiler",
    "url": "https://github.com/yyoncho/Nim.git/?subdir=compiler",
    "method": "git",
    "tags": [
      "library",
      "compiler"
    ],
    "description": "Package providing the Nim compiler binaries plus all its source files that can be used as a library",
    "license": "MIT",
    "web": "https://github.com/nim-lang/Nim"
  },
  {
    "name": "nimsuggest",
    "url": "https://github.com/yyoncho/Nim.git/?nimsuggest=compiler",
    "method": "git",
    "tags": [
      "library",
      "compiler"
    ],
    "description": "Package providing the Nim compiler binaries plus all its source files that can be used as a library",
    "license": "MIT",
    "web": "https://github.com/nim-lang/Nim"
  },
```

Then `nimble install compiler`, `nimble install nimsuggest` work as expected.
2023-06-18 16:06:14 +02:00
metagn
6d21637245 fix scoping regression with calls in generic bodies (#22115)
refs #22029, refs https://github.com/status-im/nim-libp2p/actions/runs/5263850340/jobs/9514434659
2023-06-17 15:24:32 +08:00
Ryan McConnell
647d9611ae Add divmod (#22102)
* Adding divmod

* Adding support to VM

* Wrapped C structs and funcs

* Fix javascript impl

* Fixing struct compat

* Segregate tests, better compiletime defs

* Using `inline` and switch back to `func`

* Apply suggestions from code review

* Explicit structures

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-06-17 05:42:05 +02:00
Andreas Rumpf
e8d0f1c3ae fixes #16331; aliasing of tuple construction within a single assignme… (#22113)
* fixes #16331; aliasing of tuple construction within a single assignment, great coding style

* added test case
2023-06-16 20:59:59 +02:00
metagn
0de9e6bbf3 add test to close #7209 (#22110)
* add test to close #7209

was fixed by #22029

* fix echo => doAssert
2023-06-16 20:20:06 +02:00
Andreas Rumpf
8c3b0e9b48 added new experimental API isUniqueRef (#21812)
* added new experimental API isUniqueRef

* typo
2023-06-16 19:35:16 +02:00
Miran
7ea8f1d5dd bump NimVersion to 1.9.5 (#22112) 2023-06-16 17:20:28 +02:00
metagn
88388040db add tests to close #7223, close #11733 (#22111)
add test to close #7223, close #11733

closes #7223, closes #11733, were fixed by #22076
2023-06-16 17:14:47 +02:00
ringabout
77beb15214 fixes #22049; fixes #22054; implicit conversion keeps varness (#22097)
* fixes #22054; codegen for var tuples conv

* rethink fixes

* add test cases

* templates only

* fixes var tuples

* keep varness no matter what

* fixes typ.isNil

* make it work for generics

* restore isSubrange

* add a test case as requested
2023-06-16 12:06:50 +02:00
Andreas Rumpf
0750210a50 fixes #19607 (#21576) 2023-06-16 12:06:18 +02:00
metagn
3ac2d81601 consider object types as declarative in templates (#22106)
* consider object types as declarative in templates

fixes #16005

* correct logic for nkRecList children, inject fields

* don't actually inject fields
2023-06-16 08:38:48 +02:00
Juan M Gómez
b4d9be0f8a fixes ilegal recursion (#22105) 2023-06-16 08:23:25 +02:00
Juan Carlos
0a19d78b22 Revert the .inline semantics change (#22104) 2023-06-15 21:09:33 +02:00
Juan M Gómez
4937aa952b adds another pass for sets fixes #6259 (#22099)
* adds another pass for sets fixes #6259

* Update tsets.nim

removes extra `#`
2023-06-15 18:50:00 +02:00
ringabout
edb64bcff4 fixes explicit deref block (#22093)
fixes explicit deref
2023-06-15 09:56:58 +02:00
Juan M Gómez
d90581c677 Allows for arbitrary ordering of inheritance in type section #6259 (#22070)
* Allows for arbitrary ordering of inheritance in type section #6259

* prevents ilegal recursion

* fixes ilegal recursion. Test passes with a better message

* Apply suggestions from code review

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-06-15 09:56:08 +02:00
metagn
13b7e4e0e5 use TimeInterval instead of Duration for calculating ISO week date (#22091)
* use TimeInterval instead of Duration for calculating ISO week date

hopefully actually fixes (space) #22059

* forward declare

* explicit effects
2023-06-14 20:43:46 +02:00
ringabout
44f377edaf imrpove changelog (#22096)
Update changelog_2_0_0.md
2023-06-14 13:10:24 +02:00
metagn
20dfdba2df fix timezone in initDateTime for ISO week date (#22090)
fixes #22059
2023-06-13 20:09:28 +02:00
metagn
894a19c6ed fix calls in generic bodies, delay typecheck when no overloads match (#22029)
* sacrifice "tgenericshardcases" for working statics

* legacy switch for CI, maybe experimental later

* convert to experimental

* apparently untyped needs the experimental switch

* try special case call semcheck

* try fix

* fix compilation

* final cleanup, not experimental, make `when` work

* remove last needed use of untyped

* fix unused warning in test

* remove untyped feature
2023-06-13 20:05:44 +02:00
Andreas Rumpf
606e9941d0 better docs; undocument sinkInference as it doesn't work (#22089) 2023-06-13 13:44:41 +02:00
ringabout
cca5e5ffb9 fixes #22065; do not search path for relative imports (#22073)
* fixes #22065; do not search path for "./"

* simplify

* fixes

* fixes

* allow ".."

* cleanup

* add a test case

* slightly modify the import

* adds a changelog
2023-06-13 13:23:11 +02:00
metagn
fda8b6f193 strictly typecheck expressions in bracketed emit (#22074)
* strictly typecheck expressions in bracketed `emit`

* use nim check in test
2023-06-13 12:04:24 +02:00
ringabout
2e12d3e26b fixes #22058; invalid free with {.noSideEffect.} in template (#22088) 2023-06-13 12:03:20 +02:00
ringabout
5679f2b84c clean up nimfix leftover (#22087) 2023-06-13 16:34:16 +08:00
ringabout
db8f6f4e38 change it to the latest branch instead of head (#22086)
Who knows what's wrong with git
2023-06-13 09:51:43 +02:00
ringabout
93cace160e fix atlas nightlies regresion; fixes the hash value (#22080) 2023-06-12 17:25:30 +02:00
metagn
71801c2b8f fix dot calls with resolved symbols in templates (#22076)
* fix dot calls with resolved symbols in templates

* make old code work

* fix custom number literals test

* remove leftover debug marker

* enable "bug 9" test too

* fix renderer, add test for #7085
2023-06-12 06:34:34 +02:00
metagn
e0ad71a912 make binary not not parse complex expressions on right side (#22078)
* binary `not` only parses simple expressions

fixes #16324

* switch to primary
2023-06-12 06:22:50 +02:00
metagn
7b1c448744 more test cases for generic object impl AST (#22077)
closes #9899, closes #14708, refs #21017
2023-06-11 19:20:17 +02:00
metagn
5139a2ec37 make borrow . work with aliases if not overriden (#22072) 2023-06-11 19:19:48 +02:00
ringabout
9b5f310b9e build atlas documentation (#22071) 2023-06-11 19:18:32 +02:00
Andreas Rumpf
21d941c16a Atlas: now in its own repository (#22066)
* Atlas: now in its own repository

* progress
2023-06-10 17:32:11 +02:00
Etan Kissling
8bba04078c avoid AnyEnumConv warning in genEnumCaseStmt (#22061)
When parsing enums from strings using `genEnumCaseStmt`, `AnyEnumConv`
warnings are generated due to conversion from integer value. It seems
possible meanwhile to refer to the actual `enum` value by symbol instead
of being required to do the conversion from `ord`, even when the `enum`
is defined in a `block`.
2023-06-10 14:45:00 +02:00
Jake Leahy
d3af0882cf BackwardsIndex overload for CacheSeq.[] (#22043)
* Add `BackwardsIndex` support for `CacheSeq`

* Add changelog entry

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-06-10 14:43:32 +02:00
Juan Carlos
b2d7761975 Remove Deprecated Nimfix (#22062)
* Remove Deprecated Nimfix
* Trailing whitespace cleanups
2023-06-10 07:09:03 +02:00
Andreas Rumpf
65c412e3f0 atlas: SAT based package solver, WIP (#22027)
* atlas: SAT based package solver, WIP

* progress

* make tests green

* progress

* SAT: now works; enabled unit tests in versions.nim

* Atlas: SAT: completed
2023-06-09 16:15:43 +02:00
Qinsi (James) ZHU
744a99d75c add const RLIMIT_STACK (#21772)
* add const RLIMIT_STACK

* generate by detect.nim

* add generated const for linux-amd64
2023-06-09 16:03:28 +02:00
litlighilit
1d6fd30afb Update browsers.nim, fix openDefaultBrowser()'s bug (#22052)
modified to fix blank page fault. see openDefaultBrowser()

The previous implement use "http:about:blank" which will be processed by "prepare" and be considered as a file path, turning to "file://...", which is no doubt beyond expectation.
To fix it,firstly the "about:blank" is used instead. Next, a new "openDefaultBrowserImplPrep" proc is added, take place of the previous version of "openDefaultBrowserImpl"
2023-06-09 15:54:33 +02:00
ringabout
64b27edd3a make move use =wasMoved internally (#22032)
* make `move` use `=wasMoved` internally

* fixes tests

* fixes spawn finally

* fixes views

* rename to internalMove

* add a test case
2023-06-09 15:53:12 +02:00
ringabout
49e11d9dcc clean up isNilConversion for seqs, strings (#22057) 2023-06-09 14:47:52 +02:00
awr1
18462b1026 Add nested with to changelog (#22053)
Add nested with to changelog
2023-06-09 14:40:17 +02:00
ringabout
f09101416f fixes stale bot (#22056) 2023-06-09 17:16:13 +08:00
Juan M Gómez
a7682325a2 fixes typos in the constructor docs (#22035)
* fixes typos in the constructor docs

* updates constructor docs

* Update doc/manual_experimental.md

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-06-09 09:55:24 +02:00
Antonis Geralis
a3bbb71240 Remove debug echo from with (#22047) 2023-06-08 22:52:24 +08:00
Tanguy
a4f9413a65 Fix: don't track Defect in proc effect compatibility (#22037) 2023-06-08 14:09:06 +02:00
ringabout
a8d0dda833 allow addressing elements of openArray[char] in VM (#22045)
allow addressing elements of openArray[char]
2023-06-08 14:08:49 +02:00
Antonis Geralis
750a33cbf1 Fix indentation in destructors.md (#22048) 2023-06-08 14:07:40 +02:00
ringabout
64accd1c57 fixes {.global.} ref typedesc regressions (#22046) 2023-06-08 13:06:47 +02:00
awr1
6514eaa8e0 Nested with blocks (#22042)
* Implemented with-nesting in underscoredCalls()

* Add tests for nested with
2023-06-08 08:02:57 +02:00
ringabout
7ee00d86b1 fixes overriden typo (#22044) 2023-06-08 08:02:11 +02:00
Raynei
ba4fb21032 fixes #19086: Document exception and defect hierarchy (#22030)
* Documented exception and defect hierarchy (#19086)

* Fixed style
2023-06-08 06:55:17 +02:00
Juan Carlos
ea91cfb305 Improve compiler messages (#22040)
* Improve compiler messages
2023-06-08 00:09:09 +02:00
Juan M Gómez
d29237b3c7 adds rkInt to the opcCastPtrToInt op (#22039)
adds rkInt to the opcCastPtrToInt op
2023-06-08 00:08:36 +02:00
heterodoxic
7fad6e5c70 fixes #21995: align C++ with C backend behavior for empty raise state… (#21998)
* fixes #21995: align C with C++ backend behavior for empty raise statements

* make runtime behavior match across both C and C++ backend and all exception modes
2023-06-07 15:15:08 +02:00
ringabout
47fa7506ab fixes #21989; lift =dup from a custom =copy for objects to keep backward compatibilities (#22009)
* fixes #21989; optimize `=dup` iff it is overridden

* remove owned

* fixes refs

* lift destructors

* lift dup
2023-06-07 15:13:34 +02:00
ringabout
ebecfbc7a5 switch to the official chronicles URL (#22033) 2023-06-07 17:58:24 +08:00
metagn
ce72b564bc retain forced open undeclared ident information (#22019) 2023-06-07 11:36:51 +02:00
ringabout
fcc383d899 fixes stale workflows; stale issues defaults to -1 instead of 7 days (#22031)
* fixes workflows; stale issues defaults to 100 years instead of 7 days

* Update .github/workflows/stale.yml

* Update .github/workflows/stale.yml
2023-06-07 10:02:19 +08:00
Juan Carlos
9f3d1b1290 Improve compiler messages (#22028)
* Improve compiler messages with simpler code
2023-06-07 02:02:14 +02:00
metagn
ccc706ff12 add test case to close #7974 (#22023)
close #7974 by adding test case
2023-06-06 23:32:15 +02:00
metagn
1dedad5620 make runnableExamples a special word (#22024)
* make runnableExamples a special word

* fix imports
2023-06-06 23:31:55 +02:00
Juan M Gómez
80fc749835 fixes #22025 vcc fails with The filename or extension is too long. when linking (#22026)
[vcc]makes paths relative when possible fixes #22025
2023-06-06 21:32:16 +02:00
Juan M Gómez
134b1890d5 documents constructor (#22013)
* documents constructor

* Apply suggestions from code review

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-06-06 21:22:32 +02:00
ringabout
0f3d6b5a52 small fixes for atomicArc (#22017)
* small fixes for atomicArc

* Update lib/system/arc.nim
2023-06-06 21:22:07 +02:00
ringabout
7ca55f7de6 close #12852; add a test case (#22016) 2023-06-06 20:40:17 +08:00
metagn
b97d603cd0 some test cleanups & category reorganization (#22010)
* clean up some test categories

* mention exact slice issue

* magics into system

* move trangechecks into overflow

* move tmemory to system

* try fix CI

* try fix CI

* final CI fix
2023-06-06 06:54:07 +02:00
metagn
2ab948ce53 post expr blocks colon fix + correct grammar (#21983)
* post expr blocks colon fix + correct grammar

fixes #21982

* fix dochelpers

* this is remarkably common

* use head for unchained

* fix atlas

* final grammar fix
2023-06-06 06:53:21 +02:00
metagn
0a212f97a5 properly disallow unresolved generic proc values (#22005)
* properly disallow unresolved generic proc values

* mirrors semoperand

* shallow efTypeAllowed, add back special case
2023-06-05 10:53:40 +02:00
Bung
c7c3362cc8 add test case for #7839 (#22006) 2023-06-05 16:30:08 +08:00
ringabout
1edae67efd infer error for =dup if there is a custom =copy error hook (#22004) 2023-06-05 08:06:14 +02:00
Miguel Madrid-Mencía
211ef26f29 Remove unused astago import warning from vm.nim (#22003) 2023-06-04 22:56:14 +08:00
Miguel Madrid-Mencía
85d8ee2cee Fix typo in installer.ini (#22002) 2023-06-04 16:07:29 +02:00
ringabout
767fec1640 fixes nightlies regression caused by atlas moving out of the tools dir (#21999)
fixes nightlies caused by atlas moving out of the tools dir
2023-06-04 13:51:03 +02:00
Andreas Rumpf
a1b7d2278a Atlas: refactoring and --autoenv feature (#21993) 2023-06-04 11:32:37 +02:00
heterodoxic
0d4d70f15c shallow fix for #21972, #18552 by moving std::exception_ptr to the parent sco… (#21988)
shallow fix for #21972 by moving std::exception_ptr to the parent scope, minor cleanup
2023-06-04 08:56:11 +02:00
ringabout
929cb4d601 fixes #21987; don't create type bound ops for anything in a function with a nodestroy pragma (#21992)
* fixes #21987; don't create type bound ops for anything in a function with a `nodestroy` pragma

* add a comment
2023-06-04 08:37:58 +02:00
Andreas Rumpf
25fe4124e6 Atlas: 'list outdated packages' feature (#21991) 2023-06-04 05:02:29 +02:00
Andreas Rumpf
f552618d6b atlas: tests graph generation (#21990)
* atlas: tests graph generation

* silly typo

* make tests green; lockfile implementation begins to make sense

* make tests green on Windows
2023-06-03 20:07:48 +02:00
Antonis Geralis
3d18b204dd Add drchaos, ssostrings, cowstrings to important packages (#21824)
* Add drchaos, ssostrings, cowstrings to important packages

* Update important_packages.nim

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-06-03 12:36:57 +02:00
Andreas Rumpf
b86060b2ba Atlas: --project switch and better graph representation (#21971) 2023-06-03 12:34:58 +02:00
ringabout
8cc49f221e update the documentation of the dup hook (#21984)
* update the documentation of the dup hook

* document `=dup`

* typo

* minor improvement

* typo

* Update doc/destructors.md

* Update doc/destructors.md

* Update doc/destructors.md

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-06-03 07:09:05 +02:00
ringabout
6dd30a6d86 switch to official manu URL (#21986) 2023-06-03 12:15:08 +08:00
ringabout
1133f20fe2 lift the =dup hook (#21903)
* fixes tests again
* remove helper functions
* fixes closures, owned refs
* final cleanup
2023-06-02 16:03:32 +02:00
Gruruya
ead7e20926 Atlas: avoid segfault on failed Github search (#21980)
* Atlas: avoid segfault on failed Github search

* Return empty array on failed search instead of nil
2023-06-02 05:02:40 +02:00
heterodoxic
c507ced51e partially fixes #20787 by having a char dummy member prepended to objs only containing an UncheckedArray (i.e. C FAM) (#21979)
partial fix for #20787
2023-06-01 19:37:01 +02:00
ringabout
8e35b3d577 fixes #21974; fixes sameConstant fieldDefect (#21981)
* fixes #21974; fixes sameConstant fieldDefect

* add a test case
2023-06-01 19:02:56 +02:00
ringabout
b3e1892eb7 fixes #21977; add sideEffects to dirExists, fileExists and symlinkExists (#21978) 2023-06-01 08:03:17 +02:00
metagn
8f760080c5 privateAccess ignores non-objects (#21973)
closes #21969
2023-06-01 05:20:08 +02:00
Etan Kissling
b880cdff49 handle out of range value for COLUMNS / LINES (#21968)
* handle out of range value for `COLUMNS` / `LINES`

Querying terminal size may fail with a `ValueError` if size is too big.
Return highest possible value instead. Note that `ValueError` is also
reported on underflow (negative size) but that is out of POSIX specs.

* `parseSaturatedNatural`
2023-05-31 19:10:58 +02:00
heterodoxic
0e5c18a73a removal of seq spam in generated C/C++ code and Module.typeStack cleanup (#21964)
* WIP: removal of seq spam in generated C/C++ output and Module.typeStack cleanup

* removal of seq spam in generated C/C++ output and Module.typeStack cleanup
2023-05-31 16:24:45 +02:00
Juan Carlos
086a3e42eb Add GitHub Action Stale, remove Deprecated Probot Stale (#21943)
* .

* Add github action stale,remove deprecated stalebot

* Add github action stale,remove deprecated stalebot

* Update .github/workflows/stale.yml

* Update .github/workflows/stale.yml

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-05-31 22:00:35 +08:00
SirOlaf
bf9ee00998 Atlas: Use copyFileWithPermissions to copy nim executable (#21967)
Use copyFileWithPermissions to copy nim executable

Co-authored-by: SirOlaf <>
2023-05-31 06:26:51 +02:00
Juan M Gómez
e43a51fcf3 Implements: [C++] constructor pragma improvement (fix #21921) (#21916)
* implements: [C++] constructor pragma improvement (fix #21921)

t

* fix test so it doesnt use echo in globals

* Update compiler/ccgtypes.nim

* Update lib/std/private/dragonbox.nim

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-05-30 21:47:26 +02:00
metagn
20446b437b make proc not implicitly convert to pointer with a preview define (#21953)
* test `proc` not converting to `pointer`

* ignore define for now to test

* remove cstring

* fixes, changelog
2023-05-30 21:29:38 +02:00
Andreas Rumpf
a9385a6b4a Atlas: virtual environments (#21965)
* Atlas: virtual environments

* fixes
2023-05-30 18:02:55 +02:00
Andreas Rumpf
4d20227438 Atlas: URL rewrite rules; --autoinit flag (#21963) 2023-05-30 14:00:09 +02:00
heterodoxic
546af8c571 simple micro-optimizations of ropes' runtime-formatting (#21962) 2023-05-30 13:41:56 +02:00
ringabout
40f88da90b alternative to #21914; split, rsplit now forbid an empty separator (#21961) 2023-05-30 13:40:09 +02:00
metagn
7e055413f9 hot code reloading: fix regression? and PreMain with arc/orc (#21940)
* fix PreMain for hot code reloading with arc/orc

* fix regression? actually test nimhcr_basic
2023-05-30 07:35:29 +02:00
Mamy Ratsimbazafy
171b916613 Add anti-regression for #21958 (#21960)
Add anti-regression test to close #21958
2023-05-30 10:46:24 +08:00
Andreas Rumpf
244565397d fixes #21734; backport (#21957) 2023-05-29 21:31:53 +02:00
Federico Ceratto
ef060e8184 Suggest files and paths modules (#21950) 2023-05-29 17:51:31 +02:00
ringabout
108410ac34 fixes fieldDefect loses enum type info in ORC; consistent with VM and refc (#21954)
fixes fieldDefect loses enum type info in ORC
2023-05-29 14:59:59 +02:00
heterodoxic
f47b27d532 prevent spamming of thread local forward declarations in C/C++ output (#21955) 2023-05-29 14:55:04 +02:00
Simon Krauter
8c55e2999b Fix documentation typo in endians.nim (#21949) 2023-05-28 19:40:37 +02:00
Andreas Rumpf
7ebb042f79 Atlas: some final cleanups (#21947) 2023-05-28 18:18:30 +02:00
ringabout
5997324709 fixes atlas logging colors on windows (#21946)
fixes atlas logging colors
2023-05-28 08:58:23 +02:00
Gruruya
9cb0fcf319 Atlas: checkout latest tagged commit with atlas use (#21944)
Now any deps with unspecified version reqs will checkout the last
tagged commit instead of the first commit.
2023-05-28 08:57:29 +02:00
ringabout
c2abcb06cc ship atlas and build documentation (#21945)
* ship atlas and build documentation

* move atlas.md and link it in tools' index
2023-05-28 08:28:49 +02:00
Andreas Rumpf
2900987c2f Atlas: use colored output (#21939)
* Atlas: use colored output

* fixes merge conflict

* another tiny improvement
2023-05-28 05:54:32 +02:00
Juan Carlos
b96c501836 Refactor pragma inline (#21930)
* Add __force_inline support
2023-05-27 20:52:08 +02:00
Gruruya
d5ba14db61 Atlas: add atlas tag command (#21936)
* Initial structure, `GitTags` → `GitRefsTags`

* Determine if we should use v prefix

* get tag from latest tag, patch nimble file

* Just do tags for now

* atlas tag now tags and pushes

* Improve UX of `atlas tag`

* better description for `tag`

* Small fixup

* Consistent naming

* strip after checking status

* Take major/minor/patch as arg for `atlas tag`

* undo testing comment

* Fix for `v` prefixed versions

* Avoid useless assignment

* Remove uselss enum assignment

* Consistent parameter seperation

* Add error handling for non-semver tags

* Use `assert` to quit on error

* Update tools/atlas/atlas.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>

* Don't push tags if errors occurred

* Allow `atlas tag [tag]` again

* Add atlas tag `a..z` for fields > 3

* Document the three input options

* Take up less lines in help

* Less or in help

* One last doc pass

* Check args length

* clarify last tag

* consistency/order

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-05-27 20:49:19 +02:00
metagn
2dcc7195da support generic void return type for templates (#21934)
fixes #21920
2023-05-27 20:09:34 +02:00
Andreas Rumpf
ef3c0bec1c Atlas: explicit graph representation (#21937) 2023-05-27 16:48:10 +02:00
heterodoxic
af3fd5a010 fixes #15428 by updating deep open array copy codegen (#21935)
* fix #15428

* add test
2023-05-27 15:27:42 +02:00
Andreas Rumpf
73095e2abb Atlas: fixes 'use' command (#21932)
* Atlas: fixes 'use' command

* Atlas: refactoring + make tests green again
2023-05-27 13:53:07 +02:00
Gruruya
6048367a9f Atlas: clone with --recursive (#21933) 2023-05-27 10:55:31 +02:00
Juan Carlos
b0e1bc02c6 Remove unused dead code (#21931)
* .

* Remove dead code
2023-05-27 10:24:32 +02:00
Juan Carlos
38fdf13982 Clean nimbase (#21927)
* .

* Clean out nimbase.h

* Clean out nimbase.h
2023-05-27 07:44:15 +02:00
heterodoxic
6128ef53c5 fix #10964 by honoring pointer deref syntax if a reified openarray is used to get an array's length (#21925)
* fix #10964

* add test
2023-05-27 06:54:41 +02:00
Gruruya
09f36f5198 atlas: search improvements (#21929)
* Get description and license from github json response

* Allow running `atlas search` outside of a workspace

* Check `len` instead of `dirExists`

* make `list` identical to `search`
2023-05-27 06:54:21 +02:00
Andreas Rumpf
2beea72810 atlas: better code (#21926) 2023-05-26 21:24:29 +02:00
metagn
1aaff9dc48 fix & add test for basic hot code reloading case (#21915)
fixes #21885
2023-05-26 17:07:37 +02:00
Zoom
656706026b JS: Add some to-cstring converters for DateTime (#21912)
Add some to-cstring converters for DateTime

Changelog update
2023-05-26 16:40:53 +02:00
Juan Carlos
f2d26f2973 Fix Nimgrab (#21918)
* .

* Fix nimgrab client not closing

* Fix nimgrab client not closing

* Fix nimgrab client not closing
2023-05-26 14:37:59 +02:00
SirOlaf
b50babd0ae Atlas: Actually use deps for use command (#21922)
Co-authored-by: SirOlaf <>
2023-05-26 14:36:20 +02:00
ringabout
ab4d044a81 fixes #21887; Type conversion on overloaded enum field does not always call (#21908)
* fixes #21887; Type conversion on overloaded enum field does not always call

* remove comments

* add a test case

* restrict it to enums
2023-05-26 09:24:43 +02:00
Andreas Rumpf
908e971732 Atlas: misc (#21919)
* Atlas: misc

* Atlas: use the lockfile if one exists
2023-05-26 09:24:01 +02:00
heterodoxic
609bf3d7c8 fix #21501 by making --app:lib and --app:staticLib imply --noMain (#21910) 2023-05-26 03:20:56 +02:00
Andreas Rumpf
0eb508e434 atlas: better docs (#21911)
* atlas: better docs

* better workspace/project handling

* make tests green again

* bugfix
2023-05-25 22:23:07 +02:00
Jake Leahy
a8718d8a9e Fix const in async regression (#21898)
* Add test case for a const being used inside an async proc

* Use `typeof` to get the type of the block instead of overloaded templates

This removes the problem with the symbol having different types

I am unsure why I didn't use this in the first place. IIRC I had problems with `typeof` when I first tried to use it in the original implementation
2023-05-25 07:08:36 +02:00
Juan Carlos
b7925bf5c9 Remove GC (#21904)
* .

* Remove GC v2
2023-05-25 07:06:31 +02:00
metagn
446e5fbbb3 when T is both a type symbol and a routine symbol in scope of a generic proc do not account for the type symbol when doing a.T() (#21899)
fix #21883
2023-05-24 20:39:40 +02:00
Juan Carlos
cb3f6fdc66 Improve times (#21901)
* .

* Improve times
2023-05-24 17:55:48 +02:00
metagn
4d6be458a0 js -r defines nodejs & program result undeclared if unavailable (#21849)
* js -r defines nodejs & program result undefined if unavailable

fixes #16985, fixes #16074

* fix

* add changelog too

* minor word change
2023-05-24 17:55:09 +02:00
Juan M Gómez
c7f2541914 actually fixes #21889 "constructor pragma doing nothing in globals" (#21897)
actually fixes #21889
2023-05-24 16:42:53 +02:00
Andreas Rumpf
b63b5c930e Atlas: added 'use' command (#21902)
* Atlas: added 'use' command

* typo
2023-05-24 16:39:58 +02:00
Bung
266cc69f19 fix #21896 asign parameter to global variable generates invalid code (#21900) 2023-05-24 15:30:14 +02:00
ringabout
761b927e47 fixes #21863; Incorrect enum field access can cause internal error (#21886)
fixes 21863; Incorrect enum field access can cause internal error
2023-05-24 07:43:30 +02:00
Andreas Rumpf
9493e67291 Atlas: first lockfiles implementation; cleared up upated vs updateWor… (#21895)
Atlas: first lockfiles implementation; cleared up upated vs updateWorkspace commands
2023-05-23 23:48:00 +02:00
Juan M Gómez
bdccc9fef9 small refactor in preparation to fix #21889 (#21892) 2023-05-23 20:10:24 +02:00
Andreas Rumpf
1252070193 minor atlas improvements (#21888)
* minor atlas improvements

* atlas: support a _deps workspace subdirectory
2023-05-23 13:47:51 +02:00
Juan Carlos
d372ad3ee6 Fix jsgen (#21880)
* .

* Fix jsgen FrameInfo

* Fix jsgen FrameInfo

* .

* Move to PProc
2023-05-23 09:59:21 +02:00
Bung
76a98fee65 fix #21251 Compiler SIGSEGV when using SharedTable (#21876)
fix #21251
2023-05-23 09:39:44 +02:00
Andreas Rumpf
d696ef5ad7 Atlas tool: search github too, no need to register your project at pa… (#21884)
* Atlas tool: search github too, no need to register your project at packages.json

* added missing file
2023-05-22 20:35:27 +02:00
Juan M Gómez
ee3650b29e documents changes on byref and bycopy (#21882) 2023-05-22 17:39:54 +02:00
ringabout
b14043c39e revert #21808 (#21881) 2023-05-22 12:53:50 +08:00
Carlo Capocasa
9c2d2773ec Weekday parse/format (replacement) (#21857)
* parsing capability for iso week year

* remove outdated test
2023-05-21 20:12:05 +02:00
Jason Beetham
28a116a477 Fixed generic parameters failing to be used in inheritance (#21866) 2023-05-21 20:10:32 +02:00
Juan M Gómez
5606702e6d implements: "Allow bycopy to work in params #21874" (#21877)
* implements: "Allow bycopy to work in params #21874"

* Update compiler/pragmas.nim

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-05-21 04:44:43 +02:00
Juan M Gómez
44f059c75e implements allow byref to work in params #21873 (#21875) 2023-05-21 00:19:09 +02:00
metagn
016aa1d98c remove legacy define for zero_functional tests (#21871)
test remove legacy define for zero_functional tests
2023-05-21 00:13:30 +02:00
Juan M Gómez
fcf2dcf099 Moves virtual under its own section manual_experimental.md (#21870) 2023-05-20 23:52:21 +02:00
metagn
641e34bcb2 fix #14254 (#21837)
* fix #14254

* use temporary PR branch for neo

* fix url
2023-05-20 21:09:16 +02:00
Juan M Gómez
a852b2e9cf refactor gettypedesc so it accepts its own kind instead of symkind (#21867) 2023-05-19 21:31:57 +02:00
heterodoxic
476e032004 potential fix for C++ codegen with ARC/ORC and goto exceptions fixes #21579, fixes #21862 (#21868)
potential fix for C++ codegen with ARC/ORC and goto exceptions
2023-05-19 21:24:37 +02:00
noah edward hall
4186529ff7 Update threadpool.nim with correct link to typedthreads module (#21865) 2023-05-19 21:23:44 +02:00
Juan M Gómez
21ff10b882 documents virtual (#21860)
* documents virtual

* Apply suggestions from code review

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-05-19 21:23:29 +02:00
Juan M Gómez
02a10ec379 Cpp Vfunctions draft (#21790)
* introduces virtual pragma, modifies proc def, prevents proc decl

* marks virtual procs as infix

* forward declare vfuncs inside the typedef

* adds naked callConv to virtual

* virtual proc error if not defined in the same top level scope as the type

* first param is now this. extracts genvirtualheaderproc

* WIP syntax

* supports obj. Removes the need for the prefix

* parameter count starts as this. Cleanup

* clean up

* sem tests

* adds integration tests

* uses constraint to store the virtual content

* introduces genVirtualProcParams

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-05-17 11:44:42 +02:00
Andreas Rumpf
1314ea7516 tasks that support return values (#21859)
tasks.nim: Code cleanups and support expressions that produce a value
2023-05-17 06:02:11 +02:00
ringabout
f22e5067c5 fixes #21847; let parseFloat behave like strtod (#21854) 2023-05-17 00:21:34 +02:00
ringabout
eecf12c4b5 fixes #21708; skip colons for tuples in VM (#21850)
* fixes #21708; skip colon for tuples in VM

* skip nimnodes

* fixes types
2023-05-17 00:20:40 +02:00
ringabout
ce1ba91573 close #19990; adds a test case (#21853) 2023-05-15 21:17:06 +02:00
heterodoxic
cf1ab2a30b fix #21848 (#21852) 2023-05-15 21:16:49 +02:00
Andreas Rumpf
f4a9b258c3 isolation spec update; WIP (#21843)
* isolation spec update; WIP

* wip

* docs update, WIP

* progress

* Update doc/manual.md
2023-05-14 16:58:28 +02:00
ringabout
0ece98620f closes #7590; add a test case (#21846) 2023-05-14 13:59:41 +08:00
ringabout
ddce555998 improve wasMoved hooks; allow reset to use the overridden wasMoved hook (#21831)
* improve `wasMoved` hooks

* Because `wasMoved` is lifted
2023-05-12 15:24:14 +02:00
Ecorous
871e4af6ef add getDataDir to std/appdirs.nim (#21754)
* add getDataDir to std/appdirs.nim

* reuse `osappdirs.getDataDir`

* Update lib/std/appdirs.nim

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-05-12 20:44:29 +08:00
ringabout
9c40dd2406 fixes #21840; nested local template lookup regression (#21841)
* fixes #21840; nested local template lookup regression

* use original types

* fixes js vm tests
2023-05-12 19:38:10 +08:00
metagn
161f50643a make deprecated statement a no-op (#21836) 2023-05-12 10:05:38 +02:00
ringabout
c6e2dc1919 fixes nightlies regressions; disable build-id=none on macos (#21839)
* fixes nightlies regressions; disable `build-id=none` on macos

* fixes typos
2023-05-12 10:03:41 +02:00
Matt Wilson
ea39c600ab Add minmax to comparisons (#21820)
* Add `minmax` to sequtils

This adds a `minmax` proc to complement `min` and `max`; it computes
both results in a single pass for efficiency.

* Update lib/pure/collections/sequtils.nim

* Add minmax note to changelog.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-05-12 14:02:09 +08:00
metagn
9810b8cf7f just set CallNodes = nnkCallKinds, follows up #21829 (#21833)
These sets are now equal
2023-05-11 20:50:01 +02:00
ringabout
ebbad9e960 cursor fields cannot form reference cycles (#21832)
* cursor fields cannot form a reference cycle

* fixes typo

* fixes position
2023-05-11 20:49:47 +02:00
Tanguy
c004483581 Bootstrap: Allow to override number of CPUs (#21823)
* Allow to override number of cpu

* NCPU -> NIMCORES
2023-05-11 16:50:18 +02:00
ringabout
f7ed293fbd switch to the official URL of loop-fusion in the impoerant packages (#21830)
ref https://github.com/mratsim/loop-fusion/pull/9
2023-05-11 22:04:25 +08:00
Matt Wilson
802d57c237 Add nnkHiddenCallConv to nnkCallKinds (#21781) (#21829) 2023-05-11 20:14:44 +08:00
ringabout
3b9999b93c adds documentation for =wasMoved and =dup hooks and small fixes (#21827)
* adds documentation for `=wasMoved` and `=dup` hooks and small fixes

* Update doc/destructors.md

* Update doc/destructors.md

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-05-11 19:38:27 +08:00
Juan Carlos
fa5e7dc44a Improve nimsuggest (#21825)
Small improvement for nimsuggest
2023-05-11 10:49:19 +02:00
ringabout
71dc929ad7 bring #21802 back; fixes #21753 [backport] (#21815)
* bring #21802 back; fixes #21753 [backport]

* adds tests and multiple fixes

* add test cases

* refactor and remove startId

* fixes custom hooks and adds tests

* handle tyUncheckedArray better
2023-05-11 10:29:11 +02:00
metagn
02be212dae clean up SOME pending/xxx/issue link comments (#21826)
* clean up SOME pending/xxx/issue link comments

* great
2023-05-11 10:23:52 +02:00
Juan Carlos
3a08e2e6ac Remove LineTooLong (#21819)
* LineTooLong refactor to make it actually useful
* Improve error message
* changelog wording
* Fix typo
2023-05-11 10:10:51 +02:00
ringabout
055a00a6ef make reset use the =destroy and wasMoved pair (#21821)
* make reset use the `=destroy` and `waMoved` pair

* fixes a space

* fixes `shrink` instead

* tiny fix

* fixes vm

* suppress the annotations since it breaks some important packages
2023-05-11 09:02:29 +02:00
ringabout
71439c2891 fixes links of generic define pragma (#21828) 2023-05-11 15:00:30 +08:00
Andreas Rumpf
f3a4cc584e make ORC threadlocal, take two (#21818)
* ORC: make rootsThreshold thread local [backport]

* fixes the regression
2023-05-10 12:54:43 +02:00
ringabout
deaf684375 fix #9423 followup #17594: distinct generics now work in VM (#21816)
* fix #9423 distinct generics now work in vm

* fixes cpp tests

---------

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>
2023-05-10 11:06:14 +02:00
metagn
4b76037e5f ignore inline hint for dynlib procs in codegen [backport] (#21817) 2023-05-09 21:44:47 +02:00
metagn
5592d1ef2c fix nimrtl and nimhcr on arc/orc (#21814)
* fix/workaround for nimrtl and nimhcr on arc/orc

fixes #21803

* try fix clang, debug linux failure

* just make duplicated procs not rtl

* actual fix for duplicated procs
2023-05-09 20:34:39 +02:00
Jordan Gillard
b169dad1e5 Improve and refactor cellseqs_v2 in Nim standard library (#21796)
* Refactor and optimize cellseqs_v2 in Nim standard library

* Extract resizing logic into a separate 'resize' procedure for better readability and separation of concerns
* Implement realloc for non-threaded cases to improve memory operations efficiency
* Use ',' instead of ';' between parameters in 'add' procedure for consistency with other Nim code

* Respond to Araq's feedback: Refactor resize function to use reallocShared

This commit replaces the usage of allocShared and deallocShared with reallocShared to optimize memory allocation and deallocation while resizing the CellSeq.
2023-05-09 20:33:35 +02:00
metagn
5491e0c274 re-enable badssl test (#21775)
test reenable badssl
2023-05-09 21:37:32 +08:00
Juan Carlos
4ee70165f1 Add build-id=none for GCC when build for Release (#21808)
* Add build-id=none to GCC/Clang, unneeded metadata in binaries

* Add build-id=none to GCC/Clang, unneeded metadata in binaries

* Add build-id=none to Clang

* Fix

* Fix

* Add build-id=none to GCC
2023-05-08 18:53:32 +02:00
Andreas Rumpf
ec3bca8fab Windows: use __declspec(thread) TLS implementation, it is MUCH faster… (#21810)
* Windows: use __declspec(thread) TLS implementation, it is MUCH faster than _Thread_local [backport]

* Update lib/nimbase.h

* better fix
2023-05-08 18:52:47 +02:00
Juan M Gómez
e45eb39ef7 documents codegendecl for object types (#21811) 2023-05-08 17:04:27 +02:00
ringabout
4533e894ad adds an experimental mm:atomicArc switch (#21798) 2023-05-08 16:25:47 +02:00
ringabout
ebdff1c7d3 fixes #21801; object field initialization with overloaded functions (#21805)
* fixes #21801; object field initialization with overloaded functions

* use the correct type
2023-05-08 13:52:28 +02:00
Jordan Gillard
71f2e1a502 🚀 Enhancing CellSeq for Better Readability and Maintainability (#21797)
Refactor and improve readability of CellSeq in system directory

* Use half-open range in the contains procedure for better readability and to avoid potential off-by-one errors
* Extract resizing logic from add procedure into a separate resize procedure for better code readability and separation of concerns
2023-05-07 09:25:25 +02:00
ringabout
4a94f3606e revert #21799 and #21802 which don't pass the tests (#21804)
* Revert "ORC: make rootsThreshold thread local [backport] (#21799)"

This reverts commit b74d49c037.

* Revert "fixes #21752 [backport] (#21802)"

This reverts commit d0c62fa169.
2023-05-07 09:22:42 +02:00
ringabout
8cf5643621 fixes #21280; Enum with int64.high() value crashes compiler (#21285)
* fixes #21280; Enum with int64.high() value crashes compiler

* Update tests/enum/tenum.nim

* Update tests/enum/tenum.nim

* fixes tests

* Update tests/enum/tenum.nim

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-05-06 21:38:17 +02:00
ringabout
b562e1e6d8 implement =dup hook eliminating wasMoved and =copy pairs (#21586)
* import `=dup` hook eliminating `wasMoved` and `=copy` pairs

* add dup

* add a test for dup

* fixes documentation

* fixes signature

* resolve comments

* fixes tests

* fixes tests

* clean up
2023-05-06 21:36:57 +02:00
metagn
ba698d37c3 some Token refactors (#21762)
* test some Token refactors

* fix CI

* showcase for more reductions, will revert

* Revert "showcase for more reductions, will revert"

This reverts commit 5ba48591f4.

* make line and column int32

* remove int32 change
2023-05-06 21:27:28 +02:00
Andreas Rumpf
d0c62fa169 fixes #21753 [backport] (#21802) 2023-05-06 21:25:45 +02:00
quantimnot
365a753eed Fix some styleCheck bugs (#20095)
refs #19822

Fixes these bugs:

* Style check violations in generics defined in foreign packages are raised.
* Builtin pragma usage style check violations in foreign packages are raised.
* User pragma definition style check violations are not raised.

Co-authored-by: quantimnot <quantimnot@users.noreply.github.com>
2023-05-06 19:10:13 +02:00
ringabout
53c15f24e9 fixes #21704; remove nfIsRef for genLit in VM (#21765)
* fixes #21704; remove `nfIsRef` for genLit

* remove nfIsRef from the output of macros

* make the logic better

* try again

* act together

* excl nfIsRef
2023-05-06 18:04:08 +02:00
Andreas Rumpf
b74d49c037 ORC: make rootsThreshold thread local [backport] (#21799) 2023-05-06 17:58:00 +02:00
Tomohiro
10328e50a5 Document about size pragma (#21794)
* Document about size pragma

* Fix typos

* Fix manual.md

* Update doc/manual.md

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-05-06 12:03:45 +02:00
Daniel Belmes
85dbfc68b5 Update the Nim Manual compile pragma with the second tuple form (#21773)
* Update the nim manual compile pragma with the second tuple form of

* Incorrectly put 'two' forms
2023-05-05 14:27:33 +02:00
ringabout
07233ceca0 fixes #21792; enable checks for sum, prod, cumsummed and cumsum (#21793)
* enable checks for sum, prod, cumsummed  and cumsum

* fixes #21792

* add test cases
2023-05-05 14:23:38 +02:00
ringabout
724866b14f adds koch --skipIntegrityCheck boot support (#21795)
add `koch --skipIntegrityCheck boot` support
2023-05-05 13:58:29 +02:00
metagn
e92d7681bb consistent use of scForceOpen for generic dot field symbols (#21738)
* always force open generic dot field symbols?

fixes #21724 but might break code

* alternative, should fix CI

* other alternative, add test for previous CI failure

* not needed

* make sure call doesn't compile too

* ok actual second test

* ok final actual correct test

* apply performance idea

* don't make fromDotExpr static
2023-05-05 07:28:06 +02:00
ringabout
62f1ad54ae build documentation for checksums/md5 and checksums/sha1 (#21791)
* build documentation for md5 and sha1

* fixes documentation reference
2023-05-04 17:40:37 +02:00
Andreas Rumpf
79ac242c72 fixes #21780 [backport:1.6] (#21785)
* fixes #21780 [backport:1.6]

* complete patch
2023-05-04 16:42:04 +02:00
Federico Ceratto
acfa7849d3 Benchmark CI: drop id (#21787) 2023-05-04 20:30:58 +08:00
heterodoxic
a929e513fa amends #21690 to fix broken Nim to C++ source line mappings (#21784)
resync fork
2023-05-04 20:09:53 +08:00
ringabout
c34950f8f5 minor cleanup vmprofiler (#21783) 2023-05-04 15:44:46 +08:00
ringabout
34b78be396 adds checksums to important packages (#21782) 2023-05-04 15:10:49 +08:00
metagn
44736d26cd error on user pragma args (#21776)
closes #20978
2023-05-03 14:18:55 +02:00
ringabout
f37ecbb994 closes #21778; document threading/channels (#21779) 2023-05-03 19:25:07 +08:00
ringabout
1d80dc7df6 closes #21771; fixes the link (#21777)
closes #21771
2023-05-03 18:54:40 +08:00
ringabout
a154950570 closes #10108; add a test case (#21770) 2023-05-03 06:42:32 +02:00
metagn
e5d0907a42 line info for strformat + fix issue with typed templates (#21761)
* line info in strformat

* also fix #20381
2023-05-02 11:28:52 +02:00
metagn
ca82b4ea16 underscore as special word (#21766)
* underscore as special word

* fix really hard to notice error
2023-05-02 11:15:06 +02:00
metagn
c2bcfd8cd9 cheap fix for #10853 + better tuple subscript error message (#21767)
* cheap fix for #10853

* also better tuple subscript error message

* weird
2023-05-02 11:13:38 +02:00
ringabout
afc30ca879 fixes #19863; move sha1, md5 to nimble packages for 2.0 (#21702)
* move sha1, md5 to nimble packages

* boot the compiler

* fixes tests

* build the documentation

* fixes docs

* lol, I forgot koch.nim

* add `nimHasChecksums` define

* clone checksums but maybe copying is better

* bump nimble hash

* use ChecksumsStableCommit

* fixes tests

* deprecate them

* fixes paths

* fixes koch
2023-05-02 10:49:17 +02:00
Amjad Ben Hedhili
2844ac8b5e Ignore pkgs folder (#21755) 2023-05-02 10:41:59 +02:00
Juan M Gómez
3e82a315fc implements #21747 (#21748) 2023-05-02 10:10:51 +02:00
ringabout
aec5a4c474 fixes #20144; fixes asyncnet ssl on bsds (#21763)
fixes asyncnet on bsds
2023-05-01 15:42:53 +02:00
ringabout
8e0f336f6d fixes #21483; fixes nim doc skips documentation of annotated elements of objects (#21743)
* fixes #21483; skipPragmaExpr

* add a test case for #21483

* fixes HTML
2023-04-29 15:30:44 +02:00
Al Hoang
a593e40ad6 fix build on haiku (#21752)
* missing maxDescriptors
2023-04-29 09:50:46 +02:00
Federico Ceratto
77093bf7b9 Save and restore ci_bench cache (#21750) 2023-04-29 15:01:23 +08:00
ringabout
43f29842fc closes #21745 (#21746) 2023-04-28 20:26:21 +08:00
heterodoxic
91abf35442 improve C/C++ debug output readability (1/N) (#21690)
* hacky attempt to reconcile default explicit constructors with enforcement of brace initialization, instead of memsetting imported objects to 0

* improve C/C++ debug output readability (1/N)
2023-04-28 10:30:16 +02:00
ringabout
560fa9a1fe handle quoted routine symbols and non symbols expressions as before (#21740) 2023-04-28 10:25:31 +02:00
Andreas Rumpf
220b450489 fixes #21245; warn about destructors that can raise (#21726)
* fixes #21245; warn about destructors that can raise

* doc update

* progress

* typo
2023-04-26 22:32:10 +02:00
ringabout
8f79a124c9 fixes broken CI (#21732)
* fixes broken CI

* Update testament/important_packages.nim
2023-04-26 16:00:43 +08:00
ringabout
69c193e5e2 fixes #21731; fixes #21537; disable warnBareExcept by default [backport] (#21728)
* disable warnBareExcept for default

* fixes a typo
2023-04-26 08:04:13 +02:00
metagn
0032322ea8 fix #21727 (#21729) 2023-04-26 08:02:44 +02:00
Federico Ceratto
f0ae1ed544 Add benchmarking based on Minimize (#21566)
* Add benchmarking based on Minimize

* Update .github/workflows/ci_bench.yml

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-04-25 19:29:17 +08:00
Juan M Gómez
897dff69dd documents #21628 (#21723)
* documents #21628

* Update doc/manual.md

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-04-24 18:09:07 +02:00
Juan M Gómez
4754c51f1b Pragma to force the exportc of a type. #21645 (#21648)
exportc export all types not just those used by exported proc/globals

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-04-24 17:44:29 +02:00
ringabout
0f226c0e48 fixes #21703; moveOrCopy should consider when vm (#21721) 2023-04-24 14:57:48 +02:00
Andreas Rumpf
20b011de19 refactoring in preparation for better, simpler name mangling that wor… (#21667)
* refactoring in preparation for better, simpler name mangling that works with IC flawlessly

* use new disamb field

* see if this makes tests green

* make tests green again
2023-04-24 06:52:37 +02:00
metagn
380dafcc32 fix iterator equality + add test for proc equality + fix sameType (#21707)
* fix iterator equality + add test also for procs

fixes #21706

* all targets

* and isNil and repr

* separate overloads, fix sameType

* more restricted sameType?

* merge overloads again??

* remove sametype change for now

* fix sameType anyway (CI failure was not related)

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-04-23 17:43:59 +08:00
ringabout
265a340e80 fixes booting warnings (#21711)
follow up https://github.com/nim-lang/Nim/pull/21604
2023-04-23 15:34:46 +08:00
metagn
6ad246b215 temporarily disable badssl tests (#21710)
* temporarily disable badssl tests

refs #21709

* fix
2023-04-23 07:09:25 +02:00
metagn
63d29ddd69 alias syntax fixes, improvements and tests (#21671)
* alias syntax fixes, improvements and tests

* even better, cannot use alias syntax with generics

* more type tests, improve comment

* fix again

* consistent error message + make t5167_5 work

* more comments, remove {.noalias.}
2023-04-22 09:11:56 +02:00
Juan M Gómez
c136ebf1ed implements #21620: allowing to import multiple modules with shared names (#21628) 2023-04-21 15:40:13 +02:00
ringabout
4fa86422c0 stdlib tests now check refc too (#21664)
* stdlib tests now check refc too

* typo

* fixes line numbers

* disable cpp

* do not touch
2023-04-21 15:37:58 +02:00
Raynei
48de0d0cf4 Documented path substitution by compiler (#21662)
Document compiler path substitution (nim-lang#19928)
2023-04-21 15:37:21 +02:00
ringabout
b54b03d04f tweak spellsuggest; three counts for equal distances candidates by default (#21700)
* tweak spellsuggest; three counts for equal distances candidates

* only suggest typos when length > 3
2023-04-21 15:36:18 +02:00
quantimnot
175a83c2de refact: Remove assertion effect hiding workaround (#21472)
refact: Remove asseertion effect hiding workaround

There was a code comment to remove after bootstrapping with `nim >= 1.4.0`.

Co-authored-by: quantimnot <quantimnot@users.noreply.github.com>
Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-04-21 18:06:20 +08:00
Bung
d76458a6cd add test for #13764 (#21699) 2023-04-21 18:05:50 +08:00
Yardanico
418e54452b Fix json.to for float fields that are not present (#21695) 2023-04-21 06:11:30 +02:00
ringabout
f9477396a6 static link pthread correctly (#21693) 2023-04-20 17:35:15 +02:00
Thiago
ed7c6cdc98 Fixed window.find return (#21621)
https://developer.mozilla.org/en-US/docs/Web/API/Window/find
2023-04-19 21:51:23 +02:00
ringabout
135b677704 fixes nightlies regression (#21689)
* fixes nightlies regression

ref https://github.com/nim-lang/Nim/pull/21659
ref https://github.com/nim-lang/nightlies/actions/runs/4727252660/jobs/8387899690

> /home/runner/work/nightlies/nightlies/nim-1.9.3/lib/std/sysrand.nim(198, 12) Error: cannot evaluate at compile time: EINTR

Because EINTR is not a const on i386

* Update lib/std/sysrand.nim
2023-04-19 11:56:12 +02:00
ringabout
9cb06d357e fixes #21540; deref block at transf phase to make injectdestructors function properly (#21688)
* fixes #21540; deref block at transf phase to make injectdestructors function properly

* add a test case

* add one more test

* fixes the type of block

* transform block
2023-04-19 11:55:54 +02:00
Bung
0d6b994bee fix #20997 (#21165)
* fix #20997

* use ptr UncheckedArray[uint8] instead
2023-04-19 09:50:49 +02:00
ringabout
d2d849db8e docuement case statement breaking changes in the changelog (#21686)
Reported on Discord 
follow up https://github.com/nim-lang/Nim/pull/20862
2023-04-19 14:19:30 +08:00
Andrey Makarov
24b6378382 Fix RST/Markdown false heading detection (#21685) 2023-04-18 10:37:47 +02:00
metagn
2f547afb0f import brackets support as and prefixes [backport] (#21636)
* import brackets support `as` and prefixes

fixes #21635

* copyTree -> copyNode
2023-04-18 10:35:35 +02:00
metagn
9dc1f2dd0f actually fix #19015 (#21680)
* actually fix #19015

* more tests

* round out
2023-04-17 20:56:52 +02:00
metagn
202b190473 revert #21227 (#21681)
* revert #21227 but keep test

* add test for #21677

* don't export

* delete test
2023-04-17 20:56:11 +02:00
metagn
b0a98cc01e warn on set types bigger than max size, default to 0..255 for int literals (#21659)
* test implicitly huge set types

refs https://github.com/nim-lang/RFCs/issues/298

* oh my god

* boot at least

* don't error, fix remaining issues, no 2 len arrays

* fix runnable example

* test assuming 0..255 for int literal

* test refactor, add changelog, test
2023-04-17 20:55:22 +02:00
Emery Hemingway
2621f78b68 compiler/docgen: pass --path:… to runnableExamples (#21669) 2023-04-17 20:53:42 +02:00
ringabout
65223e6f59 fixes #21674; lent can be used in the fields or the cast type as a parameter (#21684)
* fixes #21674; `lent` can be used in the fields or the cast type as a parameter

* add a test case

* fix the test
2023-04-18 00:31:47 +08:00
ringabout
91e4381a20 fixes #20155; repr range with distinct types is broken in ORC (#21682)
fixes #20155; repr range with distinct types is broken with ORC
2023-04-17 17:08:53 +02:00
metagn
8c4b7129b5 fix small mistake from #21629 (#21672) 2023-04-17 17:07:09 +02:00
Jaremy Creechley
1af21c2668 change compile pragma to use mangled compile objects (#21678)
change compile pragma to use mangle
2023-04-17 14:17:02 +02:00
Mamy Ratsimbazafy
938f5c5e99 LTO improvements - fix #15578 (#21679) 2023-04-17 13:02:34 +02:00
Andrey Makarov
a0da74ed4c Update nim 2.0 documentation for docgen & nimgrep (#21665)
* Update nim 2.0 documentation for docgen & nimgrep

* [skip ci] Update changelogs/changelog_2_0_0.md

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>

* [skip ci] expand section on Markdown migration and `doctype`

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-04-17 10:57:51 +02:00
Andreas Rumpf
ea8aafa7c9 minor codegen bugfix (#21670) 2023-04-15 01:17:17 +02:00
ringabout
512517c223 fixes #18146; fixes #19372; disable tlsEmulation on windows; static link pthreads with mingw (#21668)
* fixes #18146; disable tlsEmulation on windows; static link libwinthreads DLL

* whatever
2023-04-14 22:52:35 +02:00
metagn
1a99bcd6ab runnableExamples imports std/assertions by default (#21658)
closes https://github.com/nim-lang/RFCs/issues/499
2023-04-14 12:39:23 +02:00
metagn
2a0d8a9a06 make grammar a bit more honest (#21655)
* test if expr parsing expr

refs #19802

* in any case

* just be honest

* fix symbol/keyword issue too
2023-04-14 12:34:49 +02:00
metagn
c694d8e4fd custom pragmas: correct error condition, remove outdated symkind whitelist (#21653)
* test not restricting custom pragma applied symbols

fixes #21652

* fix other test

* different patch

* fix tests

* actually test #18212 and other routines
2023-04-13 12:50:43 +02:00
ringabout
16f42084d3 fixes #20900; Calling template through from generic function across module fails to build (#21649)
* fixes #20900; Calling template through from generic function across module fails to build

* sanother way
2023-04-13 12:11:06 +02:00
metagn
3f51b6f73d set module symbol type to None instead of nil for discard check (#21657)
* set module symbol type to None instead of nil

fixes #19225

* alright
2023-04-13 11:56:16 +02:00
ringabout
c33ab0ba38 stops building nimsuggest twice and nim_dbg in tests; saves 3 * 5 minutes CI time (#21654)
stop building nimsuggest twice and nim_dbg in tests; saving 3 * 5 minutes CI time
2023-04-13 11:52:24 +02:00
ringabout
1ed54b7718 fixes #21632; enforce deref for wasMoved in ORC (#21647)
fixes #21632; enforce deref for `wasMoved`
2023-04-12 10:45:45 +02:00
metagn
f05387045d int64/uint64 as bigint in JS (#21613)
* int64/uint64 as bigint in JS

* fix CI

* convert to compile option

* fix lie

* smaller diff, changelog entry
2023-04-11 21:20:20 +02:00
metagn
be06446ffe fix #15691 (#21623)
`semProcAux` has a check for `checkMinSonsLen(n, bodyPos + 1)`
2023-04-11 09:37:53 +02:00
metagn
1bb117cd7a proc typeclass accounts for iterator, call conventions + nil fix + document typeclass AST (#21629)
* test fix #16546 #16548 + another issue

* please don't tell me other packages do this

* fix CI + test typeclass callconv pragma

* better logic in parser

* docs and changelog
2023-04-11 09:23:41 +02:00
Andrey Makarov
420b0c14eb Fix option lists with additional indentation in Markdown (#21633)
This is more Markdown-ish way to fix issue #21055, then PR #21625.
It does not enable RST definition lists, instead it makes
adding additional indentation (less than 4) right after a paragraph
be ignored, as it's done for all block elements in Markdown.
(In this case this tenet is applied to option lists that are not
part of CommonMark spec by themselves).
2023-04-11 06:40:20 +02:00
ringabout
4c073cffbe disable i386 tests for now; help wanted (#21642)
I have done some investigations but still cannot figure it out in https://github.com/nim-lang/Nim/pull/21637, https://github.com/nim-lang/Nim/pull/21612 and https://forum.nim-lang.org/t/10069. If someone has a clue, please enlighten me.
2023-04-11 06:39:31 +02:00
ringabout
5e016e4466 fixes #21638; fromJson should support empty objects (#21641)
* fixes #21638; `fromJson` should supports empty objects

* complete the logic
2023-04-11 06:38:30 +02:00
Etan Kissling
75205fee93 terminal size env-vars have precendence in POSIX (#21643)
In POSIX Base Definitions Section 8.1 Environment Variable Definition,
it is explained that the `COLUMNS` and `LINES` environment variables,
if present, take precedence over any other implementation-defined method
to determine the terminal size. This is useful, for example, to capture
output programmatically in simulations for various terminal sizes.
2023-04-11 11:43:21 +08:00
ringabout
4d683fc689 fixes booting warnings (#21583) 2023-04-10 09:43:12 +02:00
metagn
16bc546aea remove useVersion (#21626)
test removing useVersion
2023-04-08 11:42:17 +02:00
Jason Beetham
686c75cef0 for loop expression can now have generated iterator's called (#21627)
A for expression now can have a generated iterator, allowing for more composable iterables
2023-04-08 11:40:43 +02:00
ringabout
a37a83cbff fixes #21617; createTypeBoundOps with PContext in order to instantiate generics (#21619)
* fixes #21617; createTypeBoundOps with PContext in order to instantiate generics

* keep idgen
2023-04-07 22:18:09 +02:00
metagn
814d3e6818 fix #19430 (#21603) 2023-04-06 13:36:21 +02:00
metagn
4898b054ce warn against a, b = val in routine arguments (#21604)
closes https://github.com/nim-lang/RFCs/issues/480
2023-04-06 13:21:48 +02:00
ringabout
baa577e9e8 switch to the official regex URL (#21616)
ref https://github.com/nitely/nim-regex/pull/119
2023-04-06 15:06:06 +08:00
ringabout
c71192043b fixes #21392; document nimble develop breaking changes (#21614) 2023-04-04 20:37:01 +02:00
ringabout
3575f2bf9c fix #20972 fixes invalid and UB codegen case object transitions for both refc and ORC [backport] (#21611)
fix #20972 fixes invalid and UB codegen case object transitions for refc and ORC
2023-04-04 12:18:43 +02:00
chmod222
31d3606fe8 fixes #21564; std/bitops: Add explicit type masking for the JS target (#21598)
* std/bitops: Add explicit type masking for the JS target

Typecasts on the JavaScript backend do not function the same way as they
do on C and C++ backends, so for bitwise operations we may need to mask them
back down into their allowed range when they get shifted outside it.

Since they do work as expected on the other backends, a default bitmask
of all 1's is casted down into the target type as an easily optimizable
"& 0xFF" operation for these backends.

* Fixup: this should still be a func

* Run test case on js target

* Adapt testcase to contributor guide and best practices

* Simplify constrain logic and turn into actual no-op for the C side
2023-04-03 05:22:31 +02:00
Tomohiro
6ec9c7f683 Fix example code of proc add*[T](x: var seq[T], y: sink openArray[T]) (#21607)
* Fix example code in system.nim

* Add example code to lib/system.nim

* Fix compile error

* Fix example code that can be unsafe
2023-04-03 05:15:14 +02:00
Andrey Makarov
63b4b3c5b8 Fix nim doc crash with group referencing & include (#21600)
This fixes a regression introduced in #20990 . When a group referencing
is used and one of the overloaded symbols is in `include`d file, then
`nim doc` crashes. The fix is in distinguishing (the index of) module
and file where the symbol is defined, and using only module as the
key in hash table for group referencing.
2023-04-02 10:32:36 +02:00
chmod222
0c6f14af04 macros: Extend treeTraverse intVal range to nnkUInt64Lit (#21597)
* Extend intVal range to nnkUInt64Lit

Fixes #21593

* Properly cast intVal as unsigned

* Add testcase for #21593
2023-04-01 20:29:28 +02:00
ringabout
a80f1a324f fixes #21592; create type bound operations for calls in the method dispatcher for ORC (#21594)
* fixes #21592; create type operations for the method dispatcher

* add a test case
2023-04-01 17:08:45 +02:00
ringabout
1c7fd71720 fixes changelog (#21590) 2023-03-31 15:51:37 +08:00
Andreas Rumpf
d5719c47dc make --exceptions:quirky work with C++ (#21581)
* make --exceptions:quirky work with C++

* make tests green again
2023-03-31 04:16:09 +02:00
Miran
2e4ba4ad93 bump NimVersion to 1.9.3 (#21587) 2023-03-30 20:25:14 +02:00
Yardanico
b865f6a5f0 Remove the "This module" suffix and reword some entries from the stdlib overview (#21580)
Remove a lot of "This module x" and reword some entries
2023-03-30 15:35:17 +02:00
Andreas Rumpf
72ca444122 hopefully easier to understand error message (#21585) 2023-03-30 15:35:00 +02:00
metagn
ecf9efa397 document general use of _, error message, fixes (#21584)
* document general use of `_`, error message, fixes

fixes #20687, fixes #21435

Documentation and changelog updated to clarify new universal behavior
of `_`. Also new error message for attempting to use `_`, new tests,
and fixes with overloadable symbols and
implicit generics.

* add test for #21435
2023-03-30 15:34:42 +02:00
tersec
51ced0d684 remove seq[T] setLen undefined behavior (#21582)
remove seq[T] setLen UB
2023-03-29 12:00:00 +02:00
Jason Beetham
c06623bf8c Fix segfault caused by ensuring valueless statics are not evaluated (#21577) 2023-03-29 04:50:56 +02:00
metagn
2315b01ae6 tuple unpacking for vars as just sugar, allowing nesting (#21563)
* tuple unpacking for vars as just sugar, allowing nesting

* set temp symbol AST

* hopeful fix some issues, add test for #19364

* always use temp for consts

* document, fix small issue

* fix manual indentation

* actually fix manual

* use helper proc

* don't resem temp tuple assignment
2023-03-28 17:52:23 +02:00
Zoom
4fc9f0c3a3 Docs: Mention Source Code Filters in lib/String handling (#21570)
Mention Source Code Filters in `String handling`

...as a viable solution for templating
2023-03-28 13:37:49 +02:00
Andreas Rumpf
115cec1745 fixes #20993 [backport:1.6] (#21574)
* fixes #20993 [backport:1.6]

* proper line endings for the test file
2023-03-28 13:27:17 +02:00
metagn
0630c649c6 disable google request in thttpclient (#21572)
was breaking macos CI
2023-03-28 16:34:30 +08:00
ringabout
ff5ed1dbb1 Revert "Add cursor to lists iterator variables" (#21571)
Revert "Add `cursor` to lists iterator variables (#21527)"

This reverts commit 3936071772.
2023-03-28 14:29:12 +08:00
heterodoxic
7d83dfd0d1 fixes #21505 (overload resolution of explicit constructors for imported C++ types) (#21511)
hacky attempt to reconcile default explicit constructors with enforcement of brace initialization, instead of memsetting imported objects to 0
2023-03-27 17:20:20 +02:00
Amjad Ben Hedhili
3936071772 Add cursor to lists iterator variables (#21527)
* followup #21507
2023-03-27 17:10:51 +02:00
943 changed files with 18519 additions and 9324 deletions

69
.github/stale.yml vendored
View File

@@ -1,69 +0,0 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 365
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 30
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- ARC
- bounty
- Codegen
- Crash
- Generics
- High Priority
- Macros
- Next release
- Showstopper
- Static[T]
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This pull request has been automatically marked as stale because it has not had
recent activity.
If you think it is still a valid PR, please rebase it on the latest devel;
otherwise it will be closed. Thank you for your contributions.
# Comment to post when removing the stale label.
# unmarkComment: >
# Your comment here.
# Comment to post when closing a stale Issue or Pull Request.
# closeComment: >
# Your comment here.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 20
# Limit to only `issues` or `pulls`
only: pulls
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:
# daysUntilStale: 30
# markComment: >
# This pull request has been automatically marked as stale because it has not had
# recent activity. It will be closed if no further activity occurs. Thank you
# for your contributions.
# issues:
# exemptLabels:
# - confirmed

23
.github/workflows/bisects.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
# 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@v3
# 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 }}

115
.github/workflows/ci_bench.yml vendored Normal file
View File

@@ -0,0 +1,115 @@
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@v3
with:
fetch-depth: 2
- name: 'Install node.js 20.x'
uses: actions/setup-node@v4
with:
node-version: '20.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@v3
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

@@ -47,7 +47,7 @@ jobs:
- target: windows
os: windows-2019
- target: osx
os: macos-11
os: macos-12
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}

View File

@@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-11]
os: [ubuntu-20.04, macos-12]
cpu: [amd64]
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'
@@ -32,10 +32,10 @@ jobs:
with:
fetch-depth: 2
- name: 'Install node.js 16.x'
uses: actions/setup-node@v3
- name: 'Install node.js 20.x'
uses: actions/setup-node@v4
with:
node-version: '16.x'
node-version: '20.x'
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'

View File

@@ -21,10 +21,10 @@ jobs:
with:
fetch-depth: 2
- name: 'Install node.js 16.x'
uses: actions/setup-node@v3
- name: 'Install node.js 20.x'
uses: actions/setup-node@v4
with:
node-version: '16.x'
node-version: '20.x'
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'

25
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
# 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,3 +110,5 @@ htmldocs
nimdoc.out.css
# except here:
!/nimdoc/testproject/expected/*
pkgs/
/compiler/compiler/

View File

@@ -1,62 +0,0 @@
# xxx unused, out of date
image: ubuntu:18.04
stages:
- pre-build
- build
- deploy
- test
.linux_set_path: &linux_set_path_def
before_script:
- export PATH=$(pwd)/bin${PATH:+:$PATH}
tags:
- linux
.windows_set_path: &win_set_path_def
before_script:
- set PATH=%CD%\bin;%PATH%
tags:
- windows
build-windows:
stage: build
script:
- ci\build.bat
artifacts:
paths:
- bin\nim.exe
- bin\nimd.exe
- compiler\nim.exe
- koch.exe
expire_in: 1 week
tags:
- windows
deploy-windows:
stage: deploy
script:
- koch.exe winrelease
artifacts:
paths:
- build/*.exe
- build/*.zip
expire_in: 1 week
tags:
- windows
- fast
test-windows:
stage: test
<<: *win_set_path_def
script:
- call ci\deps.bat
- nim c testament\tester
- testament\tester.exe all
tags:
- windows
- fast

View File

@@ -23,16 +23,16 @@ 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'
vmImage: 'macOS-12'
CPU: amd64
OSX_amd64_cpp:
vmImage: 'macOS-11'
vmImage: 'macOS-12'
CPU: amd64
NIM_COMPILE_TO_CPP: true
Windows_amd64_batch0_3:

View File

@@ -10,7 +10,12 @@
[//]: # "Additions:"
- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes.
- Added `newStringUninit` to system, which creates a new string of length `len` like `newString` but with uninitialized content.
- Added `setLenUninit` to system, which doesn't initalize
slots when enlarging a sequence.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
- Added Viewport API for the JavaScript targets in the `dom` module.
[//]: # "Deprecations:"
@@ -22,10 +27,45 @@
- An experimental option `genericsOpenSym` has been added to allow captured
symbols in generic routine bodies to be replaced by symbols injected locally
by templates/macros at instantiation time. `bind` may be used to keep the
captured symbols over the injected ones regardless of enabling the option.
Since this change may affect runtime behavior, the experimental switch
`genericsOpenSym` needs to be enabled, and a warning is given in the case
where an injected symbol would replace a captured symbol not bound by `bind`
and the experimental switch isn't enabled.
```nim
const value = "captured"
template foo(x: int, body: untyped) =
let value {.inject.} = "injected"
body
proc old[T](): string =
foo(123):
return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:genericsOpenSym`
echo old[int]() # "captured"
{.experimental: "genericsOpenSym".}
proc bar[T](): string =
foo(123):
return value
assert bar[int]() == "injected" # previously it would be "captured"
proc baz[T](): string =
bind value
foo(123):
return value
assert baz[int]() == "captured"
```
## 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,367 +1,330 @@
# v2.0.0 - yyyy-mm-dd
# v2.0.0 - 2023-08-01
Version 2.0 is a big milestone with too many changes to list them all here.
## 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`.
For a full list see [details](changelog_2_0_0_details.html).
- `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:
## New features
- `std/syncio`
- `std/assertions`
- `std/formatfloat`
- `std/objectdollar`
- `std/widestrs`
- `std/typedthreads`
- `std/sysatomics`
### Better tuple unpacking
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.
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.
- 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`
```nim
proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3)
- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in
in the `system` module.
# Now nesting is supported!
let (x, (_, y), _, z) = returnsNestedTuple()
- Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore.
```
- The `gc:v2` option is removed.
### Improved type inference
- The `mainmodule` and `m` options are 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 `threads:on` option is now the default.
For example, code like the following now compiles:
- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via
`experimental:flexibleOptionalParams`.
```nim
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
```
- Automatic dereferencing (experimental feature) is removed.
### Forbidden Tags
- 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.
[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.
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
`sink` for optimization purposes.
For example:
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises.
```nim
- 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.
type IO = object ## input/output effect
proc readLine(): string {.tags: [IO].} = discard
proc echoLine(): void = discard
- Removed the `nimIncrSeqV3` define.
proc no_IO_please() {.forbids: [IO].} =
# this is OK because it didn't define any tag:
echoLine()
# the compiler prevents this:
let y = readLine()
- `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.
### New standard library modules
- 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.
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.
## 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`).
- 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`

View File

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

@@ -58,7 +58,11 @@ _nimNumCpu(){
# FreeBSD | macOS: $(sysctl -n hw.ncpu)
# OpenBSD: $(sysctl -n hw.ncpuonline)
# windows: $NUMBER_OF_PROCESSORS ?
echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1)
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
}
_nimBuildCsourcesIfNeeded(){

View File

@@ -10,7 +10,7 @@
# abstract syntax tree + symbol table
import
lineinfos, hashes, options, ropes, idents, int128, tables
lineinfos, hashes, options, ropes, idents, int128, tables, wordrecg
from strutils import toLowerAscii
when defined(nimPreviewSlimSystem):
@@ -231,7 +231,7 @@ type
TNodeKinds* = set[TNodeKind]
type
TSymFlag* = enum # 49 flags!
TSymFlag* = enum # 51 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
sfOverriden, # proc is overridden
sfOverridden, # 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,6 +303,8 @@ 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
@@ -310,6 +312,9 @@ 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
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
TSymFlags* = set[TSymFlag]
@@ -335,8 +340,8 @@ const
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
sfExperimental* = sfOverriden # module uses the .experimental switch
sfGoto* = sfOverriden # var is used for 'goto' code generation
sfExperimental* = sfOverridden # module uses the .experimental switch
sfGoto* = sfOverridden # var is used for 'goto' code generation
sfWrittenTo* = sfBorrow # param is assigned to
# currently unimplemented
sfBase* = sfDiscriminant
@@ -511,9 +516,10 @@ type
nfFirstWrite # this node is a first write
nfHasComment # node has a comment
nfSkipFieldChecking # node skips field visable checking
nfOpenSym # node is a captured sym but can be overriden by local symbols
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46)
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47)
tfVarargs, # procedure has C styled varargs
# tyArray type represeting a varargs list
tfNoSideEffect, # procedure type does not allow side effects
@@ -583,6 +589,8 @@ type
tfIsConstructor
tfEffectSystemWorkaround
tfIsOutParam
tfSendable
tfImplicitStatic
TTypeFlags* = set[TTypeFlag]
@@ -618,13 +626,12 @@ 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, skAlias} + routineKinds
ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub} + routineKinds
tfUnion* = tfNoSideEffect
tfGcSafe* = tfThread
@@ -685,7 +692,7 @@ type
mIsPartOf, mAstToStr, mParallel,
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
mNewString, mNewStringOfCap, mParseBiggestFloat,
mMove, mWasMoved, mDestroy, mTrace,
mMove, mEnsureMove, mWasMoved, mDup, mDestroy, mTrace,
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
@@ -818,9 +825,6 @@ 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
@@ -855,7 +859,7 @@ type
# keep in sync with PackedLib
kind*: TLibKind
generated*: bool # needed for the backends:
isOverriden*: bool
isOverridden*: bool
name*: Rope
path*: PNode # can be a string literal!
@@ -896,6 +900,7 @@ type
info*: TLineInfo
when defined(nimsuggest):
endInfo*: TLineInfo
hasUserSpecifiedType*: bool # used for determining whether to display inlay type hints
owner*: PSym
flags*: TSymFlags
ast*: PNode # syntax tree of proc, iterator, etc.:
@@ -917,7 +922,9 @@ type
# for modules, an unique index corresponding
# to the module's fileIdx
# for variables a slot index for the evaluator
offset*: int # offset of record field
offset*: int32 # offset of record field
disamb*: int32 # disambiguation number; the basic idea is that
# `<procname>__<module>_<disamb>`
loc*: TLoc
annex*: PLib # additional fields (seldom used, so we use a
# reference to another object to save space)
@@ -925,7 +932,7 @@ 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 pragma in the hope
# misused for the codegenDecl and virtual pragmas in the hope
# it won't cause problems
# for skModule the string literal to output for
# deprecated modules.
@@ -938,6 +945,7 @@ type
attachedWasMoved,
attachedDestructor,
attachedAsgn,
attachedDup,
attachedSink,
attachedTrace,
attachedDeepCopy
@@ -1081,7 +1089,8 @@ const
nfIsRef, nfIsPtr, nfPreventCg, nfLL,
nfFromTemplate, nfDefaultRefsParam,
nfExecuteOnReload, nfLastRead,
nfFirstWrite, nfSkipFieldChecking}
nfFirstWrite, nfSkipFieldChecking,
nfOpenSym}
namePos* = 0
patternPos* = 1 # empty except for term rewriting macros
genericParamsPos* = 2
@@ -1121,11 +1130,10 @@ 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
@@ -1141,13 +1149,17 @@ 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)
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]())
proc nextSymId*(x: IdGenerator): ItemId {.inline.} =
assert(not x.sealed)
@@ -1339,11 +1351,15 @@ when false:
echo k
echo v
proc newSym*(symKind: TSymKind, name: PIdent, id: ItemId, owner: PSym,
proc newSym*(symKind: TSymKind, name: PIdent, idgen: IdGenerator; 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)
options: options, owner: owner, offset: defaultOffset,
disamb: getOrDefault(idgen.disambTable, name).int32)
idgen.disambTable.inc name
when false:
if id.module == 48 and id.item == 39:
writeStackTrace()
@@ -1503,7 +1519,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
const
AttachedOpToStr*: array[TTypeAttachedOp, string] = [
"=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy"]
"=wasMoved", "=destroy", "=copy", "=dup", "=sink", "=trace", "=deepcopy"]
proc `$`*(s: PSym): string =
if s != nil:
@@ -1557,8 +1573,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; id: ItemId): PSym =
result = newSym(s.kind, s.name, id, s.owner, s.info, s.options)
proc copySym*(s: PSym; idgen: IdGenerator): PSym =
result = newSym(s.kind, s.name, idgen, s.owner, s.info, s.options)
#result.ast = nil # BUGFIX; was: s.ast which made problems
result.typ = s.typ
result.flags = s.flags
@@ -1573,9 +1589,9 @@ proc copySym*(s: PSym; id: ItemId): PSym =
result.bitsize = s.bitsize
result.alignment = s.alignment
proc createModuleAlias*(s: PSym, id: ItemId, newIdent: PIdent, info: TLineInfo;
proc createModuleAlias*(s: PSym, idgen: IdGenerator, newIdent: PIdent, info: TLineInfo;
options: TOptions): PSym =
result = newSym(s.kind, newIdent, id, s.owner, info, options)
result = newSym(s.kind, newIdent, idgen, s.owner, info, options)
# keep ID!
result.ast = s.ast
#result.id = s.id # XXX figure out what to do with the ID.
@@ -1915,20 +1931,6 @@ 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
@@ -2002,7 +2004,7 @@ proc toObjectFromRefPtrGeneric*(typ: PType): PType =
of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0]
# automatic dereferencing is deep, refs #18298.
else: break
assert result.sym != nil
# result does not have to be object type
proc isImportedException*(t: PType; conf: ConfigRef): bool =
assert t != nil
@@ -2016,7 +2018,7 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
result = true
proc isInfixAs*(n: PNode): bool =
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as"
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.id == ord(wAs)
proc skipColon*(n: PNode): PNode =
result = n
@@ -2024,10 +2026,12 @@ 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
@@ -2065,6 +2069,12 @@ 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)

View File

@@ -24,6 +24,12 @@ proc addDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) =
result.add " declared in " & toFileLineCol(conf, typ.sym.info)
result.add "]"
proc addTypeNodeDeclaredLoc*(result: var string, conf: ConfigRef; typ: PType) =
result.add " [$1" % typ.kind.toHumanStr
if typ.sym != nil:
result.add " declared in " & toFileLineCol(conf, typ.sym.info)
result.add "]"
proc addDeclaredLocMaybe*(result: var string, conf: ConfigRef; typ: PType) =
if optDeclaredLocs in conf.globalOptions: addDeclaredLoc(result, conf, typ)

View File

@@ -68,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):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result.vals[j] = move h.vals[Mhalf + j]
else:
shallowCopy(result.vals[j], h.vals[Mhalf + j])
@@ -91,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):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
h.vals[i] = move h.vals[i-1]
else:
shallowCopy(h.vals[i], h.vals[i-1])

View File

@@ -24,6 +24,7 @@ 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!
@@ -82,6 +83,10 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
if typ[0] != nil:
var flags: TAssignmentFlags = {}
if typ[0].kind in {tyOpenArray, tyVarargs}:
# perhaps generate no temp if the call doesn't have side effects
flags.incl needTempForOpenArray
if isInvalidReturnType(p.config, typ):
if params.len != 0: pl.add(", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
@@ -129,7 +134,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
genAssignment(p, d, list, flags) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc
@@ -137,7 +142,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, tmp, list, {}) # no need for deep copying
genAssignment(p, tmp, list, flags) # no need for deep copying
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {})
else:
@@ -166,7 +171,10 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
genBoundsCheck(p, a, b, c)
if prepareForMutation:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
let ty = skipTypes(a.t, abstractVar+{tyPtr})
# bug #23321: In the function mapType, ptrs (tyPtr, tyVar, tyLent, tyRef)
# are mapped into ctPtrToArray, the dereference of which is skipped
# in the `genref`. We need to skip these ptrs here
let ty = skipTypes(a.t, abstractVar+{tyPtr, tyRef})
let dest = getTypeDesc(p.module, destType)
let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)]
case ty.kind
@@ -269,7 +277,7 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
# Bug https://github.com/status-im/nimbus-eth2/issues/1549
# Aliasing is preferred over stack overflows.
# Also don't regress for non ARC-builds, too risky.
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcOrc} and
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
getSize(p.config, a.lode.typ) < 1024:
getTemp(p, a.lode.typ, result, needsInit=false)
genAssignment(p, result, a, {})
@@ -292,7 +300,8 @@ 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]):
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and
(optByRef notin param.options or not p.module.compileToCpp):
initLocExpr(p, n, a)
if n.kind in {nkCharLit..nkNilLit}:
addAddrLoc(p.config, literalsNeedsTmp(p, a), result)
@@ -312,6 +321,11 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
addRdLoc(a, result)
else:
initLocExprSingleUse(p, n, a)
if param.typ.kind in abstractPtrs:
let typ = skipTypes(param.typ, abstractPtrs)
if typ.sym != nil and sfImportc in typ.sym.flags:
a.r = "(($1) ($2))" %
[getTypeDesc(p.module, param.typ), rdCharLoc(a)]
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
#assert result != nil

View File

@@ -285,15 +285,23 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)])
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc; flags: TAssignmentFlags) =
assert d.k != locNone
# getTemp(p, d.t, d)
case a.t.skipTypes(abstractVar).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(a.lode):
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), a.rdLoc])
if needTempForOpenArray in flags:
var tmp: TLoc
getTemp(p, a.t, tmp)
linefmt(p, cpsStmts, "$2 = $1; $n",
[a.rdLoc, tmp.rdLoc])
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), tmp.rdLoc])
else:
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), a.rdLoc])
else:
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $2Len_0;$n",
[rdLoc(d), a.rdLoc])
@@ -382,7 +390,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
else:
linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyArray:
if containsGarbageCollectedRef(dest.t) and p.config.selectedGC notin {gcArc, gcOrc, gcHooks}:
if containsGarbageCollectedRef(dest.t) and p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
genGenericAsgn(p, dest, src, flags)
else:
linefmt(p, cpsStmts,
@@ -392,7 +400,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# open arrays are always on the stack - really? What if a sequence is
# passed to an open array?
if reifiedOpenArray(dest.lode):
genOpenArrayConv(p, dest, src)
genOpenArrayConv(p, dest, src, flags)
elif containsGarbageCollectedRef(dest.t):
linefmt(p, cpsStmts, # XXX: is this correct for arrays?
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
@@ -401,7 +409,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
else:
linefmt(p, cpsStmts,
# bug #4799, keep the nimCopyMem for a while
#"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);$n",
#"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);\n",
"$1 = $2;$n",
[rdLoc(dest), rdLoc(src)])
of tySet:
@@ -450,9 +458,10 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
[addrLoc(p.config, dest), rdLoc(src),
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
of tyOpenArray, tyVarargs:
let source = addrLocOrTemp(src)
linefmt(p, cpsStmts,
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
[addrLoc(p.config, dest), addrLocOrTemp(src),
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $2->Field1, $3);$n",
[addrLoc(p.config, dest), source,
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
of tySet:
if mapSetType(p.config, ty) == ctArray:
@@ -615,7 +624,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
if t.kind == tyInt64: prc64[m] else: prc[m])
putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res])
else:
let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
let res = "($1)(($2) $3 ($4))" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
putIntoDest(p, d, e, res)
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
@@ -752,23 +761,8 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
skipTypes(typ, abstractInstOwned).kind in {tyVar} and
tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags
proc derefBlock(p: BProc, e: PNode, d: var TLoc) =
# We transform (block: x)[] to (block: x[])
let e0 = e[0]
var n = shallowCopy(e0)
n.typ = e.typ
for i in 0 ..< e0.len - 1:
n[i] = e0[i]
n[e0.len-1] = newTreeIT(nkHiddenDeref, e.info, e.typ, e0[e0.len-1])
expr p, n, d
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
if e.kind == nkHiddenDeref and e[0].kind in {nkBlockExpr, nkBlockStmt}:
# bug #20107. Watch out to not deref the pointer too late.
derefBlock(p, e, d)
return
let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0]))
let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0]) == skParam)
if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags:
# XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then?
@@ -836,7 +830,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e[0], a)
putIntoDest(p, d, e, "&" & a.r, a.storage)
#Message(e.info, warnUser, "HERE NEW &")
elif mapType(p.config, e[0].typ, mapTypeChooser(e[0])) == ctArray or isCppRef(p, e.typ):
elif mapType(p.config, e[0].typ, mapTypeChooser(e[0]) == skParam) == ctArray or isCppRef(p, e.typ):
expr(p, e[0], d)
else:
var a: TLoc
@@ -945,10 +939,17 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
var discIndex = newRopeAppender()
rdSetElemLoc(p.config, v, u.t, discIndex)
if optTinyRtti in p.config.globalOptions:
# not sure how to use `genEnumToStr` here
if p.config.getStdlibVersion < (1, 5, 1):
const code = "{ #raiseFieldError($1); "
linefmt(p, cpsStmts, code, [strLit])
let base = disc.typ.skipTypes(abstractInst+{tyRange})
case base.kind
of tyEnum:
const code = "{ #raiseFieldErrorStr($1, $2); "
let toStrProc = getToStringProc(p.module.g.graph, base)
# XXX need to modify this logic for IC.
# need to analyze nkFieldCheckedExpr and marks procs "used" like range checks in dce
var toStr: TLoc
expr(p, newSymNode(toStrProc), toStr)
let enumStr = "$1($2)" % [rdLoc(toStr), rdLoc(v)]
linefmt(p, cpsStmts, code, [strLit, enumStr])
else:
const code = "{ #raiseFieldError2($1, (NI)$2); "
linefmt(p, cpsStmts, code, [strLit, discIndex])
@@ -959,12 +960,8 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
var firstLit = newRopeAppender()
int64Literal(cast[int](first), firstLit)
let discName = genTypeInfo(p.config, p.module, disc.sym.typ, e.info)
if p.config.getStdlibVersion < (1,5,1):
const code = "{ #raiseFieldError($1); "
linefmt(p, cpsStmts, code, [strLit])
else:
const code = "{ #raiseFieldError2($1, #reprDiscriminant(((NI)$2) + (NI)$3, $4)); "
linefmt(p, cpsStmts, code, [strLit, discIndex, firstLit, discName])
const code = "{ #raiseFieldError2($1, #reprDiscriminant(((NI)$2) + (NI)$3, $4)); "
linefmt(p, cpsStmts, code, [strLit, discIndex, firstLit, discName])
raiseInstr(p, p.s(cpsStmts))
linefmt p, cpsStmts, "}$n", []
@@ -1427,7 +1424,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
if a.storage == OnHeap and usesWriteBarrier(p.config):
if canFormAcycle(a.t):
if canFormAcycle(p.module.g.graph, a.t):
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [a.rdLoc])
else:
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", [a.rdLoc])
@@ -1464,7 +1461,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
var call: TLoc
initLoc(call, locExpr, dest.lode, OnHeap)
if dest.storage == OnHeap and usesWriteBarrier(p.config):
if canFormAcycle(dest.t):
if canFormAcycle(p.module.g.graph, dest.t):
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [dest.rdLoc])
else:
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", [dest.rdLoc])
@@ -1507,11 +1504,12 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
initLocExpr(p, e[1], a)
if optSeqDestructors in p.config.globalOptions:
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false)
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3));$n",
[d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype),
])
else:
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false) # bug #22560
putIntoDest(p, d, e, ropecg(p.module,
"($1)#nimNewSeqOfCap($2, $3)", [
getTypeDesc(p.module, seqtype),
@@ -1561,6 +1559,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
var tmp: TLoc
var r: Rope
let needsZeroMem = p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc} or nfAllFieldsSet notin e.flags
if useTemp:
getTemp(p, t, tmp)
r = rdLoc(tmp)
@@ -1569,10 +1568,13 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
t = t.lastSon.skipTypes(abstractInstOwned)
r = "(*$1)" % [r]
gcUsage(p.config, e)
else:
elif needsZeroMem:
constructLoc(p, tmp)
else:
genObjectInit(p, cpsStmts, t, tmp, constructObj)
else:
resetLoc(p, d)
if needsZeroMem: resetLoc(p, d)
else: genObjectInit(p, cpsStmts, d.t, d, if isRef: constructRefObj else: constructObj)
r = rdLoc(d)
discard getTypeDesc(p.module, t)
let ty = getUniqueType(t)
@@ -1887,16 +1889,25 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
if optBoundsCheck in p.options:
genBoundsCheck(p, m, b, c)
if op == mHigh:
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)", [rdLoc(b), rdLoc(c)]))
putIntoDest(p, d, e, ropecg(p.module, "(($2)-($1))", [rdLoc(b), rdLoc(c)]))
else:
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)]))
putIntoDest(p, d, e, ropecg(p.module, "(($2)-($1)+1)", [rdLoc(b), rdLoc(c)]))
else:
if not reifiedOpenArray(a):
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
else: unaryExpr(p, e, d, "$1Len_0")
else:
if op == mHigh: unaryExpr(p, e, d, "($1.Field1-1)")
else: unaryExpr(p, e, d, "$1.Field1")
let isDeref = a.kind in {nkHiddenDeref, nkDerefExpr}
if op == mHigh:
if isDeref:
unaryExpr(p, e, d, "($1->Field1-1)")
else:
unaryExpr(p, e, d, "($1.Field1-1)")
else:
if isDeref:
unaryExpr(p, e, d, "$1->Field1")
else:
unaryExpr(p, e, d, "$1.Field1")
of tyCstring:
if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)")
else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
@@ -1921,10 +1932,6 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ)))
else: internalError(p.config, e.info, "genArrayLen()")
proc makePtrType(baseType: PType; idgen: IdGenerator): PType =
result = newType(tyPtr, nextTypeId idgen, baseType.owner)
addSonSkipIntLit(result, baseType, idgen)
proc makeAddr(n: PNode; idgen: IdGenerator): PNode =
if n.kind == nkHiddenAddr:
result = n
@@ -1947,7 +1954,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
initLoc(call, locCall, e, OnHeap)
if not p.module.compileToCpp:
const setLenPattern = "($3) #setLengthSeqV2(&($1)->Sup, $4, $2)"
const setLenPattern = "($3) #setLengthSeqV2(($1)?&($1)->Sup:NIM_NIL, $4, $2)"
call.r = ropecg(p.module, setLenPattern, [
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
@@ -2126,7 +2133,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mCard:
var a: TLoc
initLocExpr(p, e[1], a)
putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [addrLoc(p.config, a), size]))
putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [rdCharLoc(a), size]))
of mLtSet, mLeSet:
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter
initLocExpr(p, e[1], a)
@@ -2207,8 +2214,15 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
var lbl = p.labels.rope
var tmp: TLoc
tmp.r = "LOC$1.source" % [lbl]
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
[getTypeDesc(p.module, e[1].typ), getTypeDesc(p.module, e.typ), lbl])
let destsize = getSize(p.config, destt)
let srcsize = getSize(p.config, srct)
if destsize > srcsize:
linefmt(p, cpsLocals, "union { $1 dest; $2 source; } LOC$3;$n #nimZeroMem(&LOC$3, sizeof(LOC$3));$n",
[getTypeDesc(p.module, e.typ), getTypeDesc(p.module, e[1].typ), lbl])
else:
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
[getTypeDesc(p.module, e[1].typ), getTypeDesc(p.module, e.typ), lbl])
tmp.k = locExpr
tmp.lode = lodeTyp srct
tmp.storage = OnStack
@@ -2339,7 +2353,7 @@ proc genWasMoved(p: BProc; n: PNode) =
if p.withinBlockLeaveActions > 0 and notYetAlive(n1):
discard
else:
initLocExpr(p, n1, a)
initLocExpr(p, n1, a, {lfEnforceDeref})
resetLoc(p, a)
#linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
# [addrLoc(p.config, a), getTypeDesc(p.module, a.t)])
@@ -2356,8 +2370,32 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
linefmt(p, cpsStmts, "}$n$1.len = $2.len; $1.p = $2.p;$n", [rdLoc(a), rdLoc(src)])
else:
if d.k == locNone: getTemp(p, n.typ, d)
genAssignment(p, d, a, {})
resetLoc(p, a)
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
genAssignment(p, d, a, {})
var op = getAttachedOp(p.module.g.graph, n.typ, attachedWasMoved)
if op == nil:
resetLoc(p, a)
else:
var b: TLoc
initLocExpr(p, newSymNode(op), b)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
of tyOpenArray, tyVarargs: # todo fixme generated `wasMoved` hooks for
# openarrays, but it probably shouldn't?
var s: string
if reifiedOpenArray(a.lode):
if a.t.kind in {tyVar, tyLent}:
s = "$1->Field0, $1->Field1" % [rdLoc(a)]
else:
s = "$1.Field0, $1.Field1" % [rdLoc(a)]
else:
s = "$1, $1Len_0" % [rdLoc(a)]
linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), s])
else:
linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), byRefLoc(p, a)])
else:
let flags = if not canMove(p, n[1], d): {needToCopy} else: {}
genAssignment(p, d, a, flags)
resetLoc(p, a)
proc genDestroy(p: BProc; n: PNode) =
if optSeqDestructors in p.config.globalOptions:
@@ -2411,7 +2449,7 @@ proc genSlice(p: BProc; e: PNode; d: var TLoc) =
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon,
prepareForMutation = e[1].kind == nkHiddenDeref and
e[1].typ.skipTypes(abstractInst).kind == tyString and
p.config.selectedGC in {gcArc, gcOrc})
p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc})
if d.k == locNone: getTemp(p, e.typ, d)
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y])
when false:
@@ -2518,10 +2556,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
of mSizeOf:
let t = e[1].typ.skipTypes({tyTypeDesc})
putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, skVar)])
putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, dkVar)])
of mAlignOf:
let t = e[1].typ.skipTypes({tyTypeDesc})
putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, skVar)])
putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, dkVar)])
of mOffsetOf:
var dotExpr: PNode
if e[1].kind == nkDotExpr:
@@ -2531,7 +2569,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else:
internalError(p.config, e.info, "unknown ast")
let t = dotExpr[0].typ.skipTypes({tyTypeDesc})
let tname = getTypeDesc(p.module, t, skVar)
let tname = getTypeDesc(p.module, t, dkVar)
let member =
if t.kind == tyTuple:
"Field" & rope(dotExpr[1].sym.position)
@@ -2593,9 +2631,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
let n = semparallel.liftParallel(p.module.g.graph, p.module.idgen, p.module.module, e)
expr(p, n, d)
of mDeepCopy:
if p.config.selectedGC in {gcArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions:
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions:
localError(p.config, e.info,
"for --gc:arc|orc 'deepcopy' support has to be enabled with --deepcopy:on")
"for --mm:arc|atomicArc|orc 'deepcopy' support has to be enabled with --deepcopy:on")
var a, b: TLoc
let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
@@ -2610,6 +2648,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mAccessTypeField: genAccessTypeField(p, e, d)
of mSlice: genSlice(p, e, d)
of mTrace: discard "no code to generate"
of mEnsureMove:
expr(p, e[1], d)
else:
when defined(debugMagics):
echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
@@ -2680,15 +2720,30 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
if not handleConstExpr(p, n, d):
let t = n.typ
discard getTypeDesc(p.module, t) # so that any fields are initialized
if d.k == locNone: getTemp(p, t, d)
var tmp: TLoc
# bug #16331
let doesAlias = lhsDoesAlias(d.lode, n)
let dest = if doesAlias: addr(tmp) else: addr(d)
if doesAlias:
getTemp(p, n.typ, tmp)
elif d.k == locNone:
getTemp(p, n.typ, d)
for i in 0..<n.len:
var it = n[i]
if it.kind == nkExprColonExpr: it = it[1]
initLoc(rec, locExpr, it, d.storage)
rec.r = "$1.Field$2" % [rdLoc(d), rope(i)]
initLoc(rec, locExpr, it, dest[].storage)
rec.r = "$1.Field$2" % [rdLoc(dest[]), rope(i)]
rec.flags.incl(lfEnforceDeref)
expr(p, it, rec)
if doesAlias:
if d.k == locNone:
d = tmp
else:
genAssignment(p, d, tmp, {})
proc isConstClosure(n: PNode): bool {.inline.} =
result = n[0].kind == nkSym and isRoutine(n[0].sym) and
n[1].kind == nkNilLit
@@ -2846,7 +2901,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
# expression not found in the cache:
inc(p.module.labels)
p.module.s[cfsData].addf("static NIM_CONST $1 $2 = ",
[getTypeDesc(p.module, t, skConst), tmp])
[getTypeDesc(p.module, t, dkConst), tmp])
genBracedInit(p, n, isConst = true, t, p.module.s[cfsData])
p.module.s[cfsData].addf(";$n", [])
@@ -2873,13 +2928,13 @@ proc genConstHeader(m, q: BModule; p: BProc, sym: PSym) =
if not genConstSetup(p, sym): return
assert(sym.loc.r != "", $sym.name.s & $sym.itemId)
if m.hcrOn:
m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]);
m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, dkVar), sym.loc.r]);
m.initProc.procSec(cpsLocals).addf(
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(q, sym)])
getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(q, sym)])
else:
let headerDecl = "extern NIM_CONST $1 $2;$n" %
[getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]
[getTypeDesc(m, sym.loc.t, dkVar), sym.loc.r]
m.s[cfsData].add(headerDecl)
if sfExportc in sym.flags and p.module.g.generatedHeader != nil:
p.module.g.generatedHeader.s[cfsData].add(headerDecl)
@@ -2895,7 +2950,7 @@ proc genConstDefinition(q: BModule; p: BProc; sym: PSym) =
q.s[cfsData].add data
if q.hcrOn:
# generate the global pointer with the real name
q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(q, sym.loc.t, skVar), sym.loc.r])
q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(q, sym.loc.t, dkVar), sym.loc.r])
# register it (but ignore the boolean result of hcrRegisterGlobal)
q.initProc.procSec(cpsLocals).addf(
"\thcrRegisterGlobal($1, \"$2\", sizeof($3), NULL, (void**)&$2);$n",
@@ -3380,18 +3435,19 @@ proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool; result: var Rope)
proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool; result: var Rope) =
let base = t.skipTypes(abstractInst)[0]
var data = rope"{"
for i in 0..<n.len:
if i > 0: data.addf(",$n", [])
genBracedInit(p, n[i], isConst, base, data)
data.add("}")
var data = rope""
if n.len > 0:
data.add(", {")
for i in 0..<n.len:
if i > 0: data.addf(",$n", [])
genBracedInit(p, n[i], isConst, base, data)
data.add("}")
let payload = getTempName(p.module)
appcg(p.module, cfsStrData,
"static $5 struct {$n" &
" NI cap; $1 data[$2];$n" &
"} $3 = {$2 | NIM_STRLIT_FLAG, $4};$n", [
"} $3 = {$2 | NIM_STRLIT_FLAG$4};$n", [
getTypeDesc(p.module, base), n.len, payload, data,
if isConst: "const" else: ""])
result.add "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload]

View File

@@ -83,7 +83,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor])
else:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
of tyChar, tyBool, tyEnum, tyInt..tyUInt64:
of tyChar, tyBool, tyEnum, tyRange, tyInt..tyUInt64:
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
of tyCstring, tyPointer, tyPtr, tyVar, tyLent:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
@@ -97,7 +97,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
else:
doAssert false, "unexpected set type kind"
of {tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs,
tyGenericParam, tyOrdinal, tyOpenArray, tyForward, tyVarargs,
tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable}:

View File

@@ -35,7 +35,9 @@ 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 isInvalidReturnType(conf, n[0].typ, true):
if n[0].kind == nkSym and sfConstructor in n[0].sym.flags:
result = true
elif isInvalidReturnType(conf, n[0].typ, true):
# var v = f()
# is transformed into: var v; f(addr v)
# where 'f' **does not** initialize the result!
@@ -288,11 +290,28 @@ 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)
@@ -304,7 +323,11 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
if sfPure in v.flags:
# v.owner.kind != skModule:
targetProc = p.module.preInitProc
assignGlobalVar(targetProc, vn, valueAsRope)
if isCppCtorCall and not containsHiddenPointer(v.typ):
callGlobalVarCppCtor(targetProc, v, vn, value)
else:
assignGlobalVar(targetProc, vn, valueAsRope)
# XXX: be careful here.
# Global variables should not be zeromem-ed within loops
# (see bug #20).
@@ -313,7 +336,6 @@ 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`
@@ -327,31 +349,21 @@ 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):
not containsHiddenPointer(v.typ) and
nimErrorFlagAccessed notin p.flags:
# C++ really doesn't like things like 'Foo f; f = x' as that invokes a
# parameterless constructor followed by an assignment operator. So we
# generate better code here: 'Foo f = x;'
genLineDir(p, vn)
let decl = localVarDecl(p, vn)
var decl = localVarDecl(p, vn)
var tmp: TLoc
if value.kind in nkCallKinds and value[0].kind == nkSym and
sfConstructor in value[0].sym.flags:
var params = newRopeAppender()
var argsCounter = 0
let typ = skipTypes(value[0].typ, abstractInst)
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])
if isCppCtorCall:
genCppVarForCtor(p, v, vn, value, decl)
line(p, cpsStmts, decl)
else:
initLocExprSingleUse(p, value, tmp)
lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc])
lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc])
return
assignLocalVar(p, vn)
initLocalVar(p, v, imm)
@@ -378,7 +390,8 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
startBlock(targetProc)
if value.kind != nkEmpty and valueAsRope.len == 0:
genLineDir(targetProc, vn)
loadInto(targetProc, vn, value, v.loc)
if not isCppCtorCall:
loadInto(targetProc, vn, value, v.loc)
if forHcr:
endBlock(targetProc)
@@ -613,7 +626,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
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))
lineF(p, cpsStmts, ";$n", [])
appcg(p, cpsStmts, ";$n", [])
genStmts(p, loopBody)
if optProfiler in p.options:
@@ -653,7 +666,7 @@ proc genParForStmt(p: BProc, t: PNode) =
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t[1]
assert(call.len in {4, 5})
assert(call.len == 4 or call.len == 5)
initLocExpr(p, call[1], rangeA)
initLocExpr(p, call[2], rangeB)
@@ -766,11 +779,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
else:
finallyActions(p)
genLineDir(p, t)
# reraise the last exception:
if p.config.exc == excCpp:
line(p, cpsStmts, "throw;\n")
else:
linefmt(p, cpsStmts, "#reraiseException();$n", [])
linefmt(p, cpsStmts, "#reraiseException();$n", [])
raiseInstr(p, p.s(cpsStmts))
template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
@@ -962,8 +971,11 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
hasDefault = true
exprBlock(p, branch.lastSon, d)
lineF(p, cpsStmts, "break;$n", [])
if (hasAssume in CC[p.config.cCompiler].props) and not hasDefault:
lineF(p, cpsStmts, "default: __assume(0);$n", [])
if not hasDefault:
if hasBuiltinUnreachable in CC[p.config.cCompiler].props:
lineF(p, cpsStmts, "default: __builtin_unreachable();$n", [])
elif hasAssume in CC[p.config.cCompiler].props:
lineF(p, cpsStmts, "default: __assume(0);$n", [])
lineF(p, cpsStmts, "}$n", [])
if lend != "": fixLabel(p, lend)
@@ -996,7 +1008,7 @@ proc genRestoreFrameAfterException(p: BProc) =
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
#[ code to generate:
std::exception_ptr error = nullptr;
std::exception_ptr error;
try {
body;
} catch (Exception e) {
@@ -1027,7 +1039,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
inc(p.labels, 2)
let etmp = p.labels
p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;", [etmp]))
lineCg(p, cpsStmts, "std::exception_ptr T$1_;$n", [etmp])
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
p.nestedTryStmts.add((fin, false, 0.Natural))
@@ -1061,7 +1073,6 @@ 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 +1135,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if t[i].len == 1:
# general except section:
startBlock(p, "catch (...) {", [])
startBlock(p, "catch (...) {$n", [])
genExceptBranchBody(t[i][0])
endBlock(p)
catchAllPresent = true
@@ -1150,7 +1161,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 (...) {", [])
startBlock(p, "catch (...) {$n", [])
genRestoreFrameAfterException(p)
linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp])
endBlock(p)
@@ -1300,7 +1311,8 @@ 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])
@@ -1622,7 +1634,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
let le = e[0]
let ri = e[1]
var a: TLoc
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar)
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar)
initLoc(a, locNone, le, OnUnknown)
a.flags.incl(lfEnforceDeref)
a.flags.incl(lfPrepareForMutation)

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,8 @@ import
ast, types, hashes, strutils, msgs, wordrecg,
platform, trees, options, cgendata
import std/[hashes, strutils, formatfloat]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -122,13 +124,19 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
var pt = skipTypes(s.typ, typedescInst)
assert skResult != s.kind
if tfByRef in pt.flags: return true
#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
elif tfByCopy in pt.flags: return false
case pt.kind
of tyObject:
if s.typ.sym != nil and sfForward in s.typ.sym.flags:
# forwarded objects are *always* passed by pointers for consistency!
result = true
elif s.typ.kind == tySink and conf.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
# bug #23354:
result = false
elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3):
result = true # requested anyway
elif (tfFinal in pt.flags) and (pt[0] == nil):
@@ -145,3 +153,64 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or
pt.kind == tySet and mapSetType(conf, pt) == ctArray)
proc encodeName*(name: string): string =
result = mangle(name)
result = $result.len & result
proc makeUnique(m: BModule; s: PSym, name: string = ""): string =
result = if name == "": s.name.s else: name
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.add $s.itemId.item
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
#Module::Type
var name = s.name.s
if makeUnique:
name = makeUnique(m, s, name)
"N" & encodeName(s.skipGenericOwner.name.s) & encodeName(name) & "E"
proc elementType*(n: PType): PType {.inline.} = n.sons[^1]
proc encodeType*(m: BModule; t: PType): string =
result = ""
var kindName = ($t.kind)[2..^1]
kindName[0] = toLower($kindName[0])[0]
case t.kind
of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam:
result = encodeSym(m, t.sym)
of tyGenericInst, tyUserTypeClassInst, tyGenericBody:
result = encodeName(t[0].sym.name.s)
result.add "I"
for i in 1..<t.len - 1:
result.add encodeType(m, t[i])
result.add "E"
of tySequence, tyOpenArray, tyArray, tyVarargs, tyTuple, tyProc, tySet, tyTypeDesc,
tyPtr, tyRef, tyVar, tyLent, tySink, tyStatic, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
result =
case t.kind:
of tySequence: encodeName("seq")
else: encodeName(kindName)
result.add "I"
for i in 0..<t.len:
let s = t[i]
if s.isNil: continue
result.add encodeType(m, s)
result.add "E"
of tyRange:
var val = "range_"
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
val.addFloat t.n[0].floatVal
val.add "_"
val.addFloat t.n[1].floatVal
else:
val.add $t.n[0].intVal & "_" & $t.n[1].intVal
result = encodeName(val)
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
result = encodeName(kindName)
of tyAlias, tyInferred, tyOwned:
result = encodeType(m, t.elementType)
else:
assert false, "encodeType " & $t.kind

View File

@@ -30,6 +30,12 @@ import strutils except `%`, addf # collides with ropes.`%`
from ic / ic import ModuleBackendFlag
import dynlib
const
# we use some ASCII control characters to insert directives that will be converted to real code in a postprocessing pass
postprocessDirStart = '\1'
postprocessDirSep = '\31'
postprocessDirEnd = '\23'
when not declared(dynlib.libCandidates):
proc libCandidates(s: string, dest: var seq[string]) =
## given a library name pattern `s` write possible library names to `dest`.
@@ -61,12 +67,12 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
var ms = getModule(s)
result = m.g.modules[ms.position]
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) =
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}) =
result.k = k
result.storage = s
result.lode = lode
result.r = ""
result.flags = {}
result.flags = 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,13 +222,9 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
elif frmt[i] == '#' and frmt[i+1] == '#':
inc(i, 2)
strLit.add("#")
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))
else:
strLit.add(frmt[i])
inc(i)
flushStrLit()
result.add newCall(ident"rope", resVar)
@@ -270,15 +272,28 @@ proc safeLineNm(info: TLineInfo): int =
result = toLinenumber(info)
if result < 0: result = 0 # negative numbers are not allowed in #line
proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
proc genPostprocessDir(field1, field2, field3: string): string =
result = postprocessDirStart & field1 & postprocessDirSep & field2 & postprocessDirSep & field3 & postprocessDirEnd
proc genCLineDir(r: var Rope, fileIdx: FileIndex, 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)])
if fileIdx == InvalidFileIdx:
r.add(rope("\n#line " & $line & " \"generated_not_to_break_here\"\n"))
else:
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
assert line >= 0
if optLineDir in p.config.options and line > 0:
if fileIdx == InvalidFileIdx:
r.add(rope("\n#line " & $line & " \"generated_not_to_break_here\"\n"))
else:
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
if optLineDir in conf.options:
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
genCLineDir(r, info.fileIndex, info.safeLineNm, conf)
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
if p.lastLineInfo.line != info.line or
@@ -287,17 +302,25 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
p.lastLineInfo.fileIndex = info.fileIndex
result = true
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, info.fileIndex, info.safeLineNm, p, info, lastFileIndex)
proc genLineDir(p: BProc, t: PNode) =
let line = t.info.safeLineNm
if optEmbedOrigSrc in p.config.globalOptions:
p.s(cpsStmts).add("//" & sourceLine(p.config, t.info) & "\L")
genCLineDir(p.s(cpsStmts), t.info, p.config)
let lastFileIndex = p.lastLineInfo.fileIndex
let freshLine = freshLineInfo(p, t.info)
if freshLine:
genCLineDir(p.s(cpsStmts), t.info.fileIndex, line, p, t.info, lastFileIndex)
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
[line, quotedFilename(p.config, t.info)])
if freshLine:
line(p, cpsStmts, genPostprocessDir("nimln", $line, $t.info.fileIndex.int32))
proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
@@ -356,19 +379,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)) != ctArray:
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != 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)) != ctArray:
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != 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)) != ctArray and not
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a) == skParam) != ctArray and not
p.module.compileToCpp:
result = "(&" & a.r & ")"
else:
@@ -383,6 +406,7 @@ proc rdCharLoc(a: TLoc): Rope =
type
TAssignmentFlag = enum
needToCopy
needTempForOpenArray
TAssignmentFlags = set[TAssignmentFlag]
proc genObjConstr(p: BProc, e: PNode, d: var TLoc)
@@ -420,7 +444,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
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, mapTypeChooser(a))])
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, descKindFromSymKind mapTypeChooser(a))])
else:
rawConstExpr(p, newNodeIT(nkType, a.lode.info, t), tmp)
genAssignment(p, a, tmp, {})
@@ -482,14 +506,11 @@ proc resetLoc(p: BProc, loc: var TLoc) =
# so we use getTypeDesc here rather than rdLoc(loc)
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc),
getTypeDesc(p.module, loc.t, mapTypeChooser(loc))])
getTypeDesc(p.module, loc.t, descKindFromSymKind 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}:
@@ -502,14 +523,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
genRefAssign(p, loc, nilLoc)
else:
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
getTypeDesc(p.module, typ, descKindFromSymKind 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, mapTypeChooser(loc))])
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, descKindFromSymKind mapTypeChooser(loc))])
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
@@ -528,9 +549,9 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels)
result.r = "T" & rope(p.labels) & "_"
if p.module.compileToCpp and isOrHasImportedCppType(t):
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, skVar), result.r])
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, dkVar), result.r])
else:
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r])
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
@@ -548,7 +569,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
inc(p.labels)
result.r = "T" & rope(p.labels) & "_"
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value])
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
@@ -572,10 +593,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, n.info, p.config)
genCLineDir(result, p, n.info, p.config)
result.add getTypeDesc(p.module, s.typ, skVar)
if s.constraint.isNil:
result.add getTypeDesc(p.module, s.typ, dkVar)
if sfCodegenDecl notin s.flags:
if sfRegister in s.flags: result.add(" register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# decl.add(" GC_GUARD")
@@ -590,7 +611,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: "\L"
let nl = if optLineDir in p.config.options: "" else: "\n"
let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl
line(p, cpsLocals, decl)
@@ -604,6 +625,40 @@ 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:
@@ -629,29 +684,30 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
internalError(p.config, n.info, ".threadvar variables cannot have a value")
else:
var decl: Rope = ""
var td = getTypeDesc(p.module, s.loc.t, skVar)
let td = getTypeDesc(p.module, s.loc.t, dkVar)
genGlobalVarDecl(p, n, td, value, decl)
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 != "":
decl.addf(" $1 = $2;$n", [s.loc.r, 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])
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:
@@ -672,7 +728,7 @@ proc getLabel(p: BProc): TLabel =
result = "LA" & rope(p.labels) & "_"
proc fixLabel(p: BProc, labl: TLabel) =
lineF(p, cpsStmts, "$1: ;$n", [labl])
p.s(cpsStmts).add("$1: ;$n" % [labl])
proc genVarPrototype(m: BModule, n: PNode)
proc requestConstImpl(p: BProc, sym: PSym)
@@ -685,8 +741,8 @@ 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, result: var TLoc) =
initLoc(result, locNone, e, OnUnknown)
proc initLocExpr(p: BProc, e: PNode, result: var TLoc, flags: TLocFlags = {}) =
initLoc(result, locNone, e, OnUnknown, flags)
expr(p, e, result)
proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
@@ -714,8 +770,12 @@ $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, file) \
$1define nimln_(n) \
FR_.line = n;
$1define nimlf_(n, file) \
FR_.line = n; FR_.filename = file;
"""
if p.module.s[cfsFrameDefines].len == 0:
appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"])
@@ -781,7 +841,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
initLoc(dest, locTemp, lib.path, OnStack)
dest.r = getTempName(m)
appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
[getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)])
[getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)])
expr(p, lib.path, dest)
m.s[cfsVars].add(p.s(cpsLocals))
@@ -821,7 +881,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
params.add(rdLoc(a))
params.add(", ")
let load = "\t$1 = ($2) ($3$4));$n" %
[tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)]
[tmp, getTypeDesc(m, sym.typ, dkVar), params, makeCString($extname)]
var last = lastSon(n)
if last.kind == nkHiddenStdConv: last = last[1]
internalAssert(m.config, last.kind == nkStrLit)
@@ -835,8 +895,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, skVar), lib.name, makeCString($extname)])
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
[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)])
proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
@@ -848,9 +908,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, skVar), lib.name, makeCString($extname)])
[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, skVar)])
[sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)])
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.loc.r = mangleDynLibProc(sym)
@@ -881,7 +941,9 @@ proc cgsymValue(m: BModule, name: string): Rope =
result.addActualSuffixForHCR(m.module, sym)
proc generateHeaders(m: BModule) =
m.s[cfsHeaders].add("\L#include \"nimbase.h\"\L")
var nimbase = m.config.nimbasePattern
if nimbase == "": nimbase = "nimbase.h"
m.s[cfsHeaders].addf("\L#include \"$1\"\L", [nimbase])
for it in m.headerFiles:
if it[0] == '#':
@@ -930,11 +992,19 @@ 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 nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkFormalParams:
of succ(nkEmpty)..pred(nkSym), succ(nkSym)..nkNilLit, harmless:
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
@@ -942,10 +1012,6 @@ 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 =
case n.kind
of nkStmtList, nkStmtListExpr:
@@ -965,7 +1031,7 @@ proc easyResultAsgn(n: PNode): PNode =
type
InitResultEnum = enum Unknown, InitSkippable, InitRequired
proc allPathsAsgnResult(n: PNode): InitResultEnum =
proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
# Exceptions coming from calls don't have not be considered here:
#
# proc bar(): string = raise newException(...)
@@ -980,7 +1046,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
# echo "a was not written to"
#
template allPathsInBranch(it) =
let a = allPathsAsgnResult(it)
let a = allPathsAsgnResult(p, it)
case a
of InitRequired: return InitRequired
of InitSkippable: discard
@@ -992,7 +1058,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
case n.kind
of nkStmtList, nkStmtListExpr:
for it in n:
result = allPathsAsgnResult(it)
result = allPathsAsgnResult(p, it)
if result != Unknown: return result
of nkAsgn, nkFastAsgn, nkSinkAsgn:
if n[0].kind == nkSym and n[0].sym.kind == skResult:
@@ -1000,6 +1066,8 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
else: result = InitRequired
elif containsResult(n):
result = InitRequired
else:
result = allPathsAsgnResult(p, n[1])
of nkReturnStmt:
if n.len > 0:
if n[0].kind == nkEmpty and result != InitSkippable:
@@ -1008,7 +1076,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
# initialized. This avoids cases like #9286 where this heuristic lead to
# wrong code being generated.
result = InitRequired
else: result = allPathsAsgnResult(n[0])
else: result = allPathsAsgnResult(p, n[0])
of nkIfStmt, nkIfExpr:
var exhaustive = false
result = InitSkippable
@@ -1034,9 +1102,9 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
of nkWhileStmt:
# some dubious code can assign the result in the 'while'
# condition and that would be fine. Everything else isn't:
result = allPathsAsgnResult(n[0])
result = allPathsAsgnResult(p, n[0])
if result == Unknown:
result = allPathsAsgnResult(n[1])
result = allPathsAsgnResult(p, n[1])
# we cannot assume that the 'while' loop is really executed at least once:
if result == InitSkippable: result = Unknown
of harmless:
@@ -1061,9 +1129,17 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
allPathsInBranch(n[0])
for i in 1..<n.len:
if n[i].kind == nkFinally:
result = allPathsAsgnResult(n[i].lastSon)
result = allPathsAsgnResult(p, n[i].lastSon)
else:
allPathsInBranch(n[i].lastSon)
of nkCallKinds:
if canRaiseDisp(p, n[0]):
result = InitRequired
else:
for i in 0..<n.safeLen:
allPathsInBranch(n[i])
of nkRaiseStmt:
result = InitRequired
else:
for i in 0..<n.safeLen:
allPathsInBranch(n[i])
@@ -1078,7 +1154,7 @@ proc getProcTypeCast(m: BModule, prc: PSym): Rope =
proc genProcBody(p: BProc; procBody: PNode) =
genStmts(p, procBody) # modifies p.locals, p.init, etc.
if {nimErrorFlagAccessed, nimErrorFlagDeclared} * p.flags == {nimErrorFlagAccessed}:
if {nimErrorFlagAccessed, nimErrorFlagDeclared, nimErrorFlagDisabled} * 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", []))
@@ -1086,10 +1162,13 @@ 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()
genProcHeader(m, prc, header)
if m.config.backend == backendCpp and {sfVirtual, sfConstructor} * prc.flags != {}:
genMemberProcHeader(m, prc, header)
else:
genProcHeader(m, prc, header)
var returnStmt: Rope = ""
assert(prc.ast != nil)
@@ -1097,12 +1176,15 @@ 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):
if not isInvalidReturnType(m.config, prc.typ) and sfConstructor notin prc.flags:
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)
@@ -1113,8 +1195,16 @@ proc genProcAux(m: BModule, prc: PSym) =
# declare the result symbol:
assignLocalVar(p, resNode)
assert(res.loc.r != "")
initLocalVar(p, res, immediateAsgn=false)
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
allPathsAsgnResult(p, 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)
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
elif sfConstructor in prc.flags:
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
else:
fillResult(p.config, resNode, prc.typ)
assignParam(p, res, prc.typ[0])
@@ -1125,7 +1215,7 @@ proc genProcAux(m: BModule, prc: PSym) =
# global is either 'nil' or points to valid memory and so the RC operation
# succeeds without touching not-initialized memory.
if sfNoInit in prc.flags: discard
elif allPathsAsgnResult(procBody) == InitSkippable: discard
elif allPathsAsgnResult(p, procBody) == InitSkippable: discard
else:
resetLoc(p, res.loc)
if skipTypes(res.typ, abstractInst).kind == tyArray:
@@ -1139,6 +1229,8 @@ proc genProcAux(m: BModule, prc: PSym) =
closureSetup(p, prc)
genProcBody(p, procBody)
prc.info = tmpInfo
var generatedProc: Rope
generatedProc.genCLineDir prc.info, m.config
if isNoReturn(p.module, prc):
@@ -1190,7 +1282,7 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
if lfNoDecl in sym.loc.flags: return
if lfNoDecl in sym.loc.flags or {sfVirtual, sfConstructor} * sym.flags != {}: return
if lfDynamicLib in sym.loc.flags:
if sym.itemId.module != m.module.position and
not containsOrIncl(m.declaredThings, sym.id):
@@ -1226,6 +1318,20 @@ 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
@@ -1244,20 +1350,6 @@ 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])
@@ -1321,14 +1413,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, skVar))
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, dkVar))
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")
@@ -1337,7 +1429,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, skVar), getModuleDllPath(m, sym)])
getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(m, sym)])
proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
result.addf("#define NIM_INTBITS $1\L", [
@@ -1413,20 +1505,23 @@ proc genMainProc(m: BModule) =
[handle, strLit])
preMainCode.add(loadLib("hcr_handle", "hcrGetProc"))
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")
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")
else:
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
var posixCmdLine: Rope
if optNoMain notin m.config.globalOptions:
posixCmdLine.add "\tN_LIB_PRIVATE int cmdCount;\L"
posixCmdLine.add "\tN_LIB_PRIVATE char** cmdLine;\L"
posixCmdLine.add "\tN_LIB_PRIVATE char** gEnv;\L"
posixCmdLine.add "N_LIB_PRIVATE int cmdCount;\L"
posixCmdLine.add "N_LIB_PRIVATE char** cmdLine;\L"
posixCmdLine.add "N_LIB_PRIVATE char** gEnv;\L"
const
# The use of a volatile function pointer to call Pre/NimMainInner
@@ -1439,15 +1534,15 @@ proc genMainProc(m: BModule) =
"}$N$N" &
"$4" &
"N_LIB_PRIVATE void $3PreMain(void) {$N" &
"\t##if $5$N" & # 1 for volatile call, 0 for non-volatile
"##if $5$N" & # 1 for volatile call, 0 for non-volatile
"\tvoid (*volatile inner)(void);$N" &
"\tinner = $3PreMainInner;$N" &
"$1" &
"\t(*inner)();$N" &
"\t##else$N" &
"##else$N" &
"$1" &
"\t$3PreMainInner();$N" &
"\t##endif$N" &
"##endif$N" &
"}$N$N"
MainProcs =
@@ -1462,17 +1557,17 @@ proc genMainProc(m: BModule) =
NimMainProc =
"N_CDECL(void, $5NimMain)(void) {$N" &
"\t##if $6$N" & # 1 for volatile call, 0 for non-volatile
"##if $6$N" & # 1 for volatile call, 0 for non-volatile
"\tvoid (*volatile inner)(void);$N" &
"$4" &
"\tinner = $5NimMainInner;$N" &
"$2" &
"\t(*inner)();$N" &
"\t##else$N" &
"##else$N" &
"$4" &
"$2" &
"\t$5NimMainInner();$N" &
"\t##endif$N" &
"##endif$N" &
"}$N$N"
NimMainBody = NimMainInner & NimMainProc
@@ -1503,7 +1598,7 @@ proc genMainProc(m: BModule) =
WinCDllMain =
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
" LPVOID lpvReserved) {$N" &
"\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
"\tif (fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "\t}$N" &
"\treturn 1;$N}$N$N"
PosixNimDllMain = WinNimDllMain
@@ -1537,11 +1632,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, gcOrc}: "".rope
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcAtomicArc, gcOrc}: "".rope
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])
inc(m.labels)
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcOrc}: "1" else: "0"
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, 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
@@ -1681,7 +1776,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, gcOrc}:
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
if m.s[cfsInitProc].len > 0:
@@ -1706,7 +1801,7 @@ proc genDatInitCode(m: BModule) =
# we don't want to break into such init code - could happen if a line
# directive from a function written by the user spills after itself
genCLineDir(prc, "generated_not_to_break_here", 999999, m.config)
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
for i in cfsTypeInit1..cfsDynLibInit:
if m.s[i].len != 0:
@@ -1732,10 +1827,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, skVar)])
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, dkVar)])
result = "\t$1 = ($2) $3($4, $5);$n" %
[tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
[tmp, getTypeDesc(m, prc.typ, dkVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
proc genInitCode(m: BModule) =
## this function is called in cgenWriteModules after all modules are closed,
@@ -1747,7 +1842,7 @@ proc genInitCode(m: BModule) =
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), initname]
# we don't want to break into such init code - could happen if a line
# directive from a function written by the user spills after itself
genCLineDir(prc, "generated_not_to_break_here", 999999, m.config)
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
if m.typeNodes > 0:
if m.hcrOn:
appcg(m, m.s[cfsTypeInit1], "\t#TNimNode* $1;$N", [m.typeNodesName])
@@ -1811,13 +1906,13 @@ proc genInitCode(m: BModule) =
if beforeRetNeeded in m.initProc.flags:
prc.add("\tBeforeRet_: ;\n")
if sfMainModule in m.module.flags and m.config.exc == excGoto:
if 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 sfMainModule in m.module.flags and m.config.exc == excGoto:
elif m.config.exc == excGoto:
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
@@ -1862,6 +1957,40 @@ proc genInitCode(m: BModule) =
registerModuleToMain(m.g, m)
proc postprocessCode(conf: ConfigRef, r: var Rope) =
# find the first directive
var f = r.find(postprocessDirStart)
if f == -1:
return
var
nimlnDirLastF = ""
var res: Rope = r.substr(0, f - 1)
while f != -1:
var
e = r.find(postprocessDirEnd, f + 1)
dir = r.substr(f + 1, e - 1).split(postprocessDirSep)
case dir[0]
of "nimln":
if dir[2] == nimlnDirLastF:
res.add("nimln_(" & dir[1] & ");")
else:
res.add("nimlf_(" & dir[1] & ", " & quotedFilename(conf, dir[2].parseInt.FileIndex) & ");")
nimlnDirLastF = dir[2]
else:
raiseAssert "unexpected postprocess directive"
# find the next directive
f = r.find(postprocessDirStart, e + 1)
# copy the code until the next directive
if f != -1:
res.add(r.substr(e + 1, f - 1))
else:
res.add(r.substr(e + 1))
r = res
proc genModule(m: BModule, cfile: Cfile): Rope =
var moduleIsEmpty = true
@@ -1874,8 +2003,6 @@ 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:
@@ -1892,9 +2019,17 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
if m.config.cppCustomNamespace.len > 0:
closeNamespaceNim(result)
if optLineDir in m.config.options:
var srcFileDefs = ""
for fi in 0..m.config.m.fileInfos.high:
srcFileDefs.add("#define FX_" & $fi & " " & makeSingleLineCString(toFullPath(m.config, fi.FileIndex)) & "\n")
result = srcFileDefs & result
if moduleIsEmpty:
result = ""
postprocessCode(m.config, result)
proc initProcOptions(m: BModule): TOptions =
let opts = m.config.options
if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
@@ -2094,7 +2229,7 @@ proc updateCachedModule(m: BModule) =
cf.flags = {CfileFlag.Cached}
addFileToCompile(m.config, cf)
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
## Also called from IC.
if sfMainModule in m.module.flags:
# phase ordering problem here: We need to announce this
@@ -2116,7 +2251,10 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
if m.hcrOn:
# make sure this is pulled in (meaning hcrGetGlobal() is called for it during init)
cgsym(m, "programResult")
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
if m.inHcrInitGuard:
endBlock(m.initProc)
@@ -2133,15 +2271,14 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
cgsym(m, "rawWrite")
# raise dependencies on behalf of genMainProc
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, 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
let disp = generateMethodDispatchers(graph)
for x in disp: genProcAux(m, x.sym)
result = generateMethodDispatchers(graph, m.idgen)
let mm = m
m.g.modulesClosed.add mm

View File

@@ -135,6 +135,7 @@ type
# unconditionally...
# nimtvDeps is VERY hard to cache because it's
# not a list of IDs nor can it be made to be one.
mangledPrcs*: HashSet[string]
TCGen = object of PPassContext # represents a C source file
s*: TCFileSections # sections of the C file
@@ -148,7 +149,7 @@ type
typeABICache*: HashSet[SigHash] # cache for ABI checks; reusing typeCache
# would be ideal but for some reason enums
# don't seem to get cached so it'd generate
# 1 ABI check per occurence in code
# 1 ABI check per occurrence in code
forwTypeCache*: TypeCache # cache for forward declarations of types
declaredThings*: IntSet # things we have declared in this .c file
declaredProtos*: IntSet # prototypes we have declared in this .c file
@@ -193,15 +194,17 @@ proc initBlock*(): TBlock =
result.sections[i] = newRopeAppender()
proc newProc*(prc: PSym, module: BModule): BProc =
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]()
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}
proc newModuleList*(g: ModuleGraph): BModuleList =
BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](),

View File

@@ -95,7 +95,8 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
return No
if result == Yes:
# check for return type:
if not sameTypeOrNil(a.typ[0], b.typ[0]):
# ignore flags of return types; # bug #22673
if not sameTypeOrNil(a.typ[0], b.typ[0], {IgnoreFlags}):
if b.typ[0] != nil and b.typ[0].kind == tyUntyped:
# infer 'auto' from the base to make it consistent:
b.typ[0] = a.typ[0]
@@ -113,7 +114,7 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) =
s.ast[dispatcherPos] = dispatcher
proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
var disp = copySym(s, nextSymId(idgen))
var disp = copySym(s, idgen)
incl(disp.flags, sfDispatcher)
excl(disp.flags, sfExported)
let old = disp.typ
@@ -127,7 +128,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, nextSymId(idgen))
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen)
else:
# We've encountered a method prototype without a filled-in
# resultPos slot. We put a placeholder in there that will
@@ -213,7 +214,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): PSym =
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
var base = methods[0].ast[dispatcherPos].sym
result = base
var paramLen = base.typ.len
@@ -272,7 +273,7 @@ proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PS
nilchecks.flags.incl nfTransf # should not be further transformed
result.ast[bodyPos] = nilchecks
proc generateMethodDispatchers*(g: ModuleGraph): PNode =
proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
result = newNode(nkStmtList)
for bucket in 0..<g.methods.len:
var relevantCols = initIntSet()
@@ -282,4 +283,4 @@ proc generateMethodDispatchers*(g: ModuleGraph): 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))
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols, idgen))

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), nextSymId(ctx.idgen), ctx.fn, ctx.fn.info)
result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.idgen, ctx.fn, ctx.fn.info)
result.typ = typ
assert(not typ.isNil)
@@ -855,7 +855,9 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
case n.kind
of nkReturnStmt:
# We're somewhere in try, transform to finally unrolling
assert(ctx.nearestFinally != 0)
if ctx.nearestFinally == 0:
# return is within the finally
return
result = newNodeI(nkStmtList, n.info)
@@ -1348,7 +1350,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, nextSymId(c.idgen))
let x = copySym(it[v].sym, c.idgen)
c.tab[it[v].sym.id] = x
idefs.add newSymNode(x)
else:
@@ -1389,7 +1391,7 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode =
discard c.finallys.pop()
of nkWhileStmt, nkBlockStmt:
if n.hasYields == false: return n
if not n.hasYields: return n
c.blocks.add((n, c.finallys.len))
for i in 0 ..< n.len:
result[i] = preprocess(c, n[i])
@@ -1431,9 +1433,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"), nextSymId(idgen), fn, fn.info)
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), idgen, fn, fn.info)
ctx.stateVarSym.typ = g.createClosureIterStateType(fn, idgen)
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), nextSymId(idgen), fn, fn.info)
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), idgen, fn, fn.info)
var pc = PreprocessContext(finallys: @[], config: g.config, idgen: idgen)
var n = preprocess(pc, n.toStmtList)
#echo "transformed into ", n
@@ -1466,9 +1468,10 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
result = ctx.transformStateAssignments(result)
result = ctx.wrapIntoStateLoop(result)
# echo "TRANSFORM TO STATES: "
# echo renderTree(result)
when false:
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, nimfix
## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest
import
options, idents, nimconf, extccomp, commands, msgs,
@@ -55,6 +55,11 @@ proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: Confi
if conf.cmd == cmdNimscript:
incl(conf.globalOptions, optWasNimscript)
loadConfigs(DefaultConfig, cache, conf, graph.idgen) # load all config files
# restores `conf.notes` after loading config files
# because it has overwrites the notes when compiling the system module which
# is a foreign module compared to the project
if conf.cmd in cmdBackends:
conf.notes = conf.mainPackageNotes
if not self.suggestMode:
let scriptFile = conf.projectFull.changeFileExt("nims")

View File

@@ -205,7 +205,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
# unfortunately, hintUser and warningUser clash, otherwise implementation would simplify a bit
let x = findStr(noteMin, noteMax, id, errUnknown)
if x != errUnknown: notes = {TNoteKind(x)}
else: localError(conf, info, "unknown $#: $#" % [name, id])
else:
if isSomeHint:
message(conf, info, hintUnknownHint, id)
else:
localError(conf, info, "unknown $#: $#" % [name, id])
case id.normalize
of "all": # other note groups would be easy to support via additional cases
notes = if isSomeHint: {hintMin..hintMax} else: {warnMin..warnMax}
@@ -238,9 +242,9 @@ proc processCompile(conf: ConfigRef; filename: string) =
extccomp.addExternalFileToCompile(conf, found)
const
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found"
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console', 'lib' or 'staticlib' expected, but '$1' found"
errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
template warningOptionNoop(switch: string) =
@@ -262,6 +266,7 @@ 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: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
of "opt":
case arg.normalize
@@ -336,6 +341,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
of "nilseqs", "nilchecks", "taintmode": warningOptionNoop(switch)
of "panics": result = contains(conf.globalOptions, optPanics)
of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64)
else: invalidCmdLineOption(conf, passCmd1, switch, info)
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
@@ -515,14 +521,7 @@ proc initOrcDefines*(conf: ConfigRef) =
if conf.exc == excNone and conf.backend != backendCpp:
conf.exc = excGoto
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")
proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef) =
defineSymbol(conf.symbols, "gcdestructors")
incl conf.globalOptions, optSeqDestructors
incl conf.globalOptions, optTinyRtti
@@ -532,10 +531,11 @@ proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef, isOrc: bool) =
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
@@ -561,9 +561,17 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
conf.selectedGC = gcMarkAndSweep
defineSymbol(conf.symbols, "gcmarkandsweep")
of "destructors", "arc":
registerArcOrc(pass, conf, false)
conf.selectedGC = gcArc
defineSymbol(conf.symbols, "gcarc")
registerArcOrc(pass, conf)
of "orc":
registerArcOrc(pass, conf, true)
conf.selectedGC = gcOrc
defineSymbol(conf.symbols, "gcorc")
registerArcOrc(pass, conf)
of "atomicarc":
conf.selectedGC = gcAtomicArc
defineSymbol(conf.symbols, "gcatomicarc")
registerArcOrc(pass, conf)
of "hooks":
conf.selectedGC = gcHooks
defineSymbol(conf.symbols, "gchooks")
@@ -610,6 +618,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
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", "nobabelpath":
@@ -651,6 +661,9 @@ 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":
@@ -798,6 +811,7 @@ 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")
@@ -821,6 +835,8 @@ 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}
@@ -861,6 +877,9 @@ 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)
conf.maxLoopIterationsVM = parseInt(arg)
@@ -875,7 +894,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
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]
@@ -1065,29 +1084,6 @@ 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":
@@ -1101,6 +1097,8 @@ 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

28
compiler/compiler.nimble Normal file
View File

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

@@ -27,7 +27,7 @@ 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"), nextSymId(c.idgen), ow, info)
let s = newSym(skType, getIdent(c.cache, "Self"), 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)
@@ -62,7 +62,7 @@ proc semConceptDecl(c: PContext; n: PNode): PNode =
result[i] = n[i]
result[^1] = semConceptDecl(c, n[^1])
of nkCommentStmt:
discard
result = n
else:
localError(c.config, n.info, "unexpected construct in the new-styled concept: " & renderTree(n))
result = n
@@ -306,13 +306,15 @@ 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
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var TIdTable; invocation: PType): bool =
## Entry point from sigmatch. 'concpt' is the concept we try to match (here still a PType but
## we extract its AST via 'concpt.n.lastSon'). 'arg' is the type that might fullfill the
## we extract its AST via 'concpt.n.lastSon'). 'arg' is the type that might fulfill the
## concept's requirements. If so, we return true and fill the 'bindings' with pairs of
## (typeVar, instance) pairs. ('typeVar' is usually simply written as a generic 'T'.)
## 'invocation' can be nil for atomic concepts. For non-atomic concepts, it contains the

View File

@@ -45,10 +45,8 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimNewTypedesc") # deadcode
defineSymbol("nimrequiresnimframe") # deadcode
defineSymbol("nimparsebiggestfloatmagic") # deadcode
defineSymbol("nimalias") # deadcode
defineSymbol("nimlocks") # deadcode
defineSymbol("nimnode") # deadcode pending `nimnode` reference in opengl package
# refs https://github.com/nim-lang/opengl/pull/79
defineSymbol("nimnode") # deadcode
defineSymbol("nimvarargstyped") # deadcode
defineSymbol("nimtypedescfixed") # deadcode
defineSymbol("nimKnowsNimvm") # deadcode
@@ -147,10 +145,19 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasCallsitePragma")
defineSymbol("nimHasAmbiguousEnumHint")
defineSymbol("nimHasWarnCastSizes")
defineSymbol("nimHasWarnCastSizes") # deadcode
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("nimHasNoReturnError")
defineSymbol("nimHasCastExtendedVm")

View File

@@ -63,12 +63,16 @@ proc toNimblePath(s: string, isStdlib: bool): string =
sub.add "/pkgs/"
var start = s.find(sub)
if start < 0:
result = s
else:
start += sub.len
start += skipUntil(s, '/', start)
start += 1
result = pkgPrefix & s[start..^1]
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]
proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
doAssert n.kind == nkSym, $n.kind

View File

@@ -264,7 +264,8 @@ proc genBreakOrRaiseAux(c: var Con, i: int, n: PNode) =
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:
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
@@ -385,7 +386,8 @@ 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 false: # c.inTryStmt > 0 and canRaiseConservative(n[0]):
if c.inTryStmt > 0 and canRaiseConservative(n[0]):
inc c.interestingInstructions
# we generate the instruction sequence:
# fork lab1
# goto exceptionHandler (except or finally)
@@ -493,7 +495,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):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result = c.code # will move
else:
shallowCopy(result, c.code)

View File

@@ -112,13 +112,16 @@ 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, info: lineinfos.TLineInfo): rstast.FileIndex =
proc addRstFileIndex(d: PDoc, fileIndex: lineinfos.FileIndex): rstast.FileIndex =
let invalid = rstast.FileIndex(-1)
result = d.nimToRstFid.getOrDefault(info.fileIndex, default = invalid)
result = d.nimToRstFid.getOrDefault(fileIndex, default = invalid)
if result == invalid:
let fname = toFullPath(d.conf, info)
let fname = toFullPath(d.conf, fileIndex)
result = addFilename(d.sharedState, fname)
d.nimToRstFid[info.fileIndex] = result
d.nimToRstFid[fileIndex] = result
proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.FileIndex =
addRstFileIndex(d, info.fileIndex)
proc cmpDecimalsIgnoreCase(a, b: string): int =
## For sorting with correct handling of cases like 'uint8' and 'uint16'.
@@ -256,7 +259,16 @@ template declareClosures(currentFilename: AbsoluteFile, destFile: string) =
of mwUnusedImportdoc: k = warnRstUnusedImportdoc
of mwRstStyle: k = warnRstStyle
{.gcsafe.}:
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
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)
proc docgenFindFile(s: string): string {.gcsafe.} =
result = options.findFile(conf, s).string
@@ -308,8 +320,9 @@ 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
declareClosures(currentFilename = filename, destFile = destFile)
new(result)
let d = result # pass `d` to `declareClosures`:
declareClosures(currentFilename = filename, destFile = destFile)
result.module = module
result.conf = conf
result.cache = cache
@@ -415,16 +428,19 @@ 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)
result = parseRst(n.comment,
toLinenumber(n.info),
toColumn(n.info) + DocColOffset,
d.conf, d.sharedState)
try:
result = parseRst(n.comment,
toLinenumber(n.info),
toColumn(n.info) + DocColOffset,
d.conf, d.sharedState)
except ERecoverableError:
result = newRstNode(rnLiteralBlock, @[newRstLeaf(n.comment)])
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,
if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef, nkTypeClassTy,
nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkSinkAsgn, nkHiddenStdConv}:
# notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}:
for i in 0..<n.len:
@@ -562,10 +578,13 @@ proc runAllExamples(d: PDoc) =
# most useful semantics is that `docCmd` comes after `rdoccmd`, so that we can (temporarily) override
# via command line
# D20210224T221756:here
let cmd = "$nim $backend -r --lib:$libpath --warning:UnusedImport:off --path:$path --nimcache:$nimcache $rdoccmd $docCmd $file" % [
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" % [
"nim", quoteShell(os.getAppFilename()),
"backend", $d.conf.backend,
"path", quoteShell(d.conf.projectPath),
"pathArgs", pathArgs,
"libpath", quoteShell(d.conf.libpath),
"nimcache", quoteShell(outputDir),
"file", quoteShell(outp),
@@ -600,7 +619,6 @@ 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)
@@ -616,6 +634,7 @@ 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
@@ -629,6 +648,7 @@ 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 = """
@@ -639,6 +659,7 @@ $#
#[
$#
]#
import std/assertions
import $#
$#
""" % [comment, d.filename.quoted, code2]
@@ -1060,7 +1081,8 @@ 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)
priority = symbolPriority(k), info = lineinfo,
module = addRstFileIndex(d, FileIndex d.module.position))
let renderFlags =
if nonExports: {renderNoBody, renderNoComments, renderDocComments, renderSyms,
@@ -1123,13 +1145,16 @@ 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): JsonItem =
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): JsonItem =
if not isVisible(d, nameNode): return
var
name = getNameEsc(d, nameNode)
comm = genRecComment(d, n)
r: TSrcGen
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing})
renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing}
if nonExports:
renderFlags.incl renderNonExportedFields
initTokRender(r, n, renderFlags)
result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
"col": %n.info.col}
if comm != nil:
@@ -1451,7 +1476,8 @@ proc finishGenerateDoc*(d: var PDoc) =
isGroup: true),
priority = symbolPriority(k),
# select index `0` just to have any meaningful warning:
info = overloadChoices[0].info)
info = overloadChoices[0].info,
module = addRstFileIndex(d, FileIndex d.module.position))
if optGenIndexOnly in d.conf.globalOptions:
return
@@ -1513,7 +1539,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, includeComments: bool = true) =
proc generateJson*(d: PDoc, n: PNode, config: ConfigRef, includeComments: bool = true) =
case n.kind
of nkPragma:
let doctypeNode = findPragma(n, wDoctype)
@@ -1545,14 +1571,14 @@ proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) =
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)))
succ(skType, ord(n.kind)-ord(nkTypeSection)), optShowNonExportedFields in config.globalOptions)
of nkStmtList:
for i in 0..<n.len:
generateJson(d, n[i], includeComments)
generateJson(d, n[i], config, includeComments)
of nkWhenStmt:
# generate documentation for the first branch only:
if not checkForFalse(n[0][0]):
generateJson(d, lastSon(n[0]), includeComments)
generateJson(d, lastSon(n[0]), config, includeComments)
else: discard
proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string =
@@ -1697,7 +1723,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]
"deprecationMsg", d.modDeprecationMsg, "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
else:
code = content
result = code
@@ -1801,13 +1827,16 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef;
var filen = addFileExt(filename, "txt")
var d = newDocumentor(filen, cache, conf, outExt, standaloneDoc = true,
preferMarkdown = preferMarkdown, hasToc = false)
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)
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"
proc commandRst2Html*(cache: IdentCache, conf: ConfigRef,
preferMarkdown=false) =
@@ -1826,7 +1855,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)
generateJson(d, ast, conf)
finishGenerateDoc(d)
let json = d.jEntriesFinal
let content = pretty(json)
@@ -1878,7 +1907,7 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"")
"title", "Index",
"subtitle", "", "tableofcontents", "", "moduledesc", "",
"date", getDateStr(), "time", getClockStr(),
"content", content, "author", "", "version", "", "analytics", ""]
"content", content, "author", "", "version", "", "analytics", "", "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
# no analytics because context is not available
try:

View File

@@ -56,7 +56,7 @@ proc processNodeJson*(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
if shouldProcess(g):
generateJson(g.doc, n, false)
generateJson(g.doc, n, g.config, 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, "$"), nextSymId idgen, t.owner, info)
result = newSym(skProc, getIdent(g.cache, "$"), idgen, t.owner, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
dest.typ = t
let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info)
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
res.typ = getSysType(g, info, tyString)
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
@@ -67,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"), nextSymId idgen, t.owner, info)
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), idgen, t.owner, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
dest.typ = field.typ
let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info)
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
res.typ = getSysType(g, info, tyUInt8)
result.typ = newType(tyProc, nextTypeId idgen, t.owner)

View File

@@ -10,7 +10,7 @@
## Template evaluation engine. Now hygienic.
import
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
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, nextSymId(c.idgen))
x = copySym(s, 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:

View File

@@ -14,12 +14,14 @@
import ropes, platform, condsyms, options, msgs, lineinfos, pathutils, modulepaths
import std/[os, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
import std/[os, osproc, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
import std / strutils except addf
when defined(nimPreviewSlimSystem):
import std/syncio
import std/[syncio, assertions]
import ../dist/checksums/src/checksums/sha1
type
TInfoCCProp* = enum # properties of the C compiler:
@@ -31,6 +33,7 @@ type
hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax
hasDeclspec, # CC has __declspec(X)
hasAttribute, # CC has __attribute__((X))
hasBuiltinUnreachable # CC has __builtin_unreachable
TInfoCCProps* = set[TInfoCCProp]
TInfoCC* = tuple[
name: string, # the short name of the compiler
@@ -93,7 +96,7 @@ compiler gcc:
produceAsm: gnuAsmListing,
cppXsupport: "-std=gnu++17 -funsigned-char",
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
hasAttribute})
hasAttribute, hasBuiltinUnreachable})
# GNU C and C++ Compiler
compiler nintendoSwitchGCC:
@@ -120,7 +123,7 @@ compiler nintendoSwitchGCC:
produceAsm: gnuAsmListing,
cppXsupport: "-std=gnu++17 -funsigned-char",
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
hasAttribute})
hasAttribute, hasBuiltinUnreachable})
# LLVM Frontend for GCC/G++
compiler llvmGcc:
@@ -578,7 +581,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
compilePattern = joinPath(conf.cCompilerPath, exe)
else:
compilePattern = getCompilerExe(conf, c, isCpp)
compilePattern = exe
includeCmd.add(join([CC[c].includeCmd, quoteShell(conf.projectPath.string)]))
@@ -832,7 +835,10 @@ proc linkViaResponseFile(conf: ConfigRef; cmd: string) =
else:
writeFile(linkerArgs, args)
try:
execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
when defined(macosx):
execLinkCmd(conf, "xargs " & cmd.substr(0, last) & " < " & linkerArgs)
else:
execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
finally:
removeFile(linkerArgs)
@@ -987,7 +993,7 @@ type BuildCache = object
depfiles: seq[(string, string)]
nimexe: string
proc writeJsonBuildInstructions*(conf: ConfigRef) =
proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
var linkFiles = collect(for it in conf.externalToLink:
var it = it
if conf.noAbsolutePaths: it = it.extractFilename
@@ -1008,10 +1014,14 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
currentDir: getCurrentDir())
if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"):
bcache.cmdline = conf.commandLine
bcache.depfiles = collect(for it in conf.m.fileInfos:
for it in conf.m.fileInfos:
let path = it.fullPath.string
if isAbsolute(path): # TODO: else?
(path, $secureHashFile(path)))
if path in deps:
bcache.depfiles.add (path, deps[path])
else: # backup for configs etc.
bcache.depfiles.add (path, $secureHashFile(path))
bcache.nimexe = hashNimExe()
conf.jsonBuildFile = conf.jsonBuildInstructionsFile
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)

View File

@@ -9,12 +9,14 @@
## Module that implements ``gorge`` for the compiler.
import msgs, std / sha1, os, osproc, streams, options,
import msgs, 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

View File

@@ -10,9 +10,6 @@
# 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 =

View File

@@ -50,7 +50,10 @@ 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)
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
let disps = finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
if disps != nil:
for disp in disps:
genProcAux(bmod, disp.sym)
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =

View File

@@ -7,13 +7,15 @@
# distribution, for details about the copyright.
#
import hashes, tables, intsets, std/sha1
import hashes, tables, intsets
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]
@@ -372,7 +374,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.isOverriden = l.isOverriden
result.isOverridden = l.isOverridden
result.name = toLitId($l.name, m)
storeNode(result, l, path)
@@ -390,7 +392,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, options: s.options,
position: s.position, offset: s.offset, disamb: s.disamb, options: s.options,
name: s.name.s.toLitId(m))
storeNode(p, s, ast)
@@ -419,7 +421,7 @@ proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pac
## add a remote symbol reference to the tree
let info = n.info.toPackedInfo(c, m)
ir.nodes.add PackedNode(kind: nkModuleRef, operand: 3.int32, # spans 3 nodes in total
typeId: storeTypeLater(n.typ, c, m), info: info)
typeId: storeTypeLater(n.typ, c, m), info: info, flags: n.flags)
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
operand: toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
@@ -830,6 +832,7 @@ 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])
)
@@ -847,7 +850,7 @@ proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph;
if l.name.int == 0:
result = nil
else:
result = PLib(generated: l.generated, isOverriden: l.isOverriden,
result = PLib(generated: l.generated, isOverridden: l.isOverridden,
kind: l.kind, name: rope g[si].fromDisk.strings[l.name])
loadAstBody(l, path)

View File

@@ -45,7 +45,7 @@ type
PackedLib* = object
kind*: TLibKind
generated*: bool
isOverriden*: bool
isOverridden*: bool
name*: LitId
path*: NodeId
@@ -63,7 +63,8 @@ type
alignment*: int # for alignment
options*: TOptions
position*: int
offset*: int
offset*: int32
disamb*: int32
externalName*: LitId # instead of TLoc
locFlags*: TLocFlags
annex*: PackedLib

View File

@@ -228,10 +228,15 @@ 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, nextSymId c.idgen, ident, n.info, c.config.options)
createModuleAlias(realModule, 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")
@@ -245,6 +250,7 @@ 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)
@@ -298,7 +304,15 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
var prefix = ""
if realModule.constraint != nil: prefix = realModule.constraint.strVal & "; "
message(c.config, n.info, warnDeprecated, prefix & realModule.name.s & " is deprecated")
suggestSym(c.graph, n.info, result, c.graph.usageSym, false)
proc suggestMod(n: PNode; s: PSym) =
if n.kind == nkImportAs:
suggestMod(n[0], realModule)
elif n.kind == nkInfix:
suggestMod(n[2], s)
else:
suggestSym(c.graph, n.info, s, c.graph.usageSym, false)
suggestMod(n, result)
importStmtResult.add newSymNode(result, n.info)
#newStrNode(toFullPath(c.config, f), n.info)
@@ -323,22 +337,26 @@ 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 == 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]:
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]:
# transform `a/b/[c as d]` to `/a/b/c as d`
if x.kind == nkInfix and x[0].ident.s == "as":
let impAs = copyTree(x)
imp[2] = x[1]
var impAs = copyNode(x)
newSons(impAs, 3)
impAs[0] = x[0]
imp[lastPos] = x[1]
impAs[1] = imp
impMod(c, imp, result)
impAs[2] = x[2]
impAs.info = x[2].info
impMod(c, impAs, result)
else:
imp[2] = x
imp[lastPos] = x
imp.info = x.info
impMod(c, imp, result)
else:
impMod(c, it, result)

View File

@@ -36,6 +36,7 @@ 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
@@ -66,11 +67,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}:
if not result and c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
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"), nextSymId c.idgen, c.owner, info)
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.idgen, c.owner, info)
sym.typ = typ
s.vars.add(sym)
result = newSymNode(sym)
@@ -78,11 +79,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}): PNode
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode
type
MoveOrCopyFlag = enum
IsDecl, IsExplicitSink
IsDecl, IsExplicitSink, IsReturn
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; flags: set[MoveOrCopyFlag] = {}): PNode
@@ -160,7 +161,8 @@ proc isLastReadImpl(n: PNode; c: var Con; scope: var Scope): bool =
result = false
proc isLastRead(n: PNode; c: var Con; s: var Scope): bool =
if not hasDestructor(c, n.typ): return true
# bug #23354; an object type could have a non-trival assignements when it is passed to a sink parameter
if not hasDestructor(c, n.typ) and (n.typ.kind != tyObject or isTrival(getAttachedOp(c.graph, n.typ, attachedAsgn))): return true
let m = skipConvDfa(n)
result = (m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or
@@ -184,11 +186,16 @@ 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
(n.kind == nkSym and n.sym.kind == skTemp and n.sym.typ.kind == tyTuple)
## 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)
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFromCopy = false) =
var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
if (opname == "=" or opname == "=copy") and ri != nil:
if inferredFromCopy:
m.add ", which is inferred from unavailable '=copy'"
if (opname == "=" or opname == "=copy" or opname == "=dup") and ri != nil:
m.add "; requires a copy because it's not the last read of '"
m.add renderTree(ri)
m.add '\''
@@ -210,8 +217,12 @@ proc makePtrType(c: var Con, baseType: PType): PType =
addSonSkipIntLit(result, baseType, c.idgen)
proc genOp(c: var Con; op: PSym; dest: PNode): PNode =
let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
addrExp.add(dest)
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)
result = newTree(nkCall, newSymNode(op), addrExp)
proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
@@ -249,10 +260,20 @@ 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 genSink(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
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 =
if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or IsDecl in flags or
(isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)))) or
isNoInit(dest):
isNoInit(dest) or IsReturn in flags:
# optimize sink call into a bitwise memcopy
result = newTree(nkFastAsgn, dest, ri)
else:
@@ -263,12 +284,19 @@ proc genSink(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNod
else:
# the default is to use combination of `=destroy(dest)` and
# and copyMem(dest, source). This is efficient.
result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri))
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))
proc isCriticalLink(dest: PNode): bool {.inline.} =
#[
Lins's idea that only "critical" links can introduce a cycle. This is
critical for the performance gurantees that we strive for: If you
critical for the performance guarantees that we strive for: If you
traverse a data structure, no tracing will be performed at all.
ORC is about this promise: The GC only touches the memory that the
mutator touches too.
@@ -287,14 +315,14 @@ 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(t):
let t = dest.typ.skipTypes(tyUserTypeClasses + {tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(c.graph, 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(t):
if cyclicType(c.graph, t):
if t.kind == tyRef:
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest)
else:
@@ -308,6 +336,9 @@ 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:
@@ -336,7 +367,7 @@ proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode =
if hasDestructor(c, objType):
if getAttachedOp(c.graph, objType, attachedDestructor) != nil and
sfOverriden in getAttachedOp(c.graph, objType, attachedDestructor).flags:
sfOverridden 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)
@@ -364,7 +395,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 & ")")
@@ -376,13 +407,16 @@ 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):
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ)
if (not hasDestructor(c, n.typ)) and c.inEnsureMove == 0:
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ) or
(n.typ.kind == tyPtr and n.sym.typ.kind == tyRef)
# bug #23505; transformed by `transf`: addr (deref ref) -> ptr
# we know it's really a pointer; so here we assign it directly
result = copyTree(n)
else:
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextSymId c.idgen, c.owner, n.info)
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.idgen, c.owner, n.info)
temp.typ = n.typ
var v = newNodeI(nkLetSection, n.info)
let tempAsNode = newSymNode(temp)
@@ -395,7 +429,8 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
result.add v
let nn = skipConv(n)
c.genMarkCyclic(result, nn)
if hasDestructor(c, n.typ):
c.genMarkCyclic(result, nn)
let wasMovedCall = c.genWasMoved(nn)
result.add wasMovedCall
result.add tempAsNode
@@ -406,21 +441,46 @@ proc isCapturedVar(n: PNode): bool =
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):
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:
let nTyp = n.typ.skipTypes(tyUserTypeClasses)
let tmp = c.getTemp(s, nTyp, n.info)
if hasDestructor(c, nTyp):
let typ = nTyp.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(nTyp, 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(nTyp, 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
if isLValue(n) and not isCapturedVar(n) and nTyp.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}:
assert(not containsManagedMemory(n.typ))
if n.typ.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
assert(not containsManagedMemory(nTyp))
if nTyp.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")
result.add newTree(nkAsgn, tmp, p(n, c, s, normal))
# Since we know somebody will take over the produced copy, there is
@@ -454,14 +514,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(tmp, arg, {IsDecl})
result.add c.genSink(s, 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 != gcArc: return
if c.graph.config.selectedGC notin {gcArc, gcAtomicArc}: return
var value = n[1]
if value.kind == nkClosure:
value = value[1]
@@ -534,7 +594,9 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt
# tricky because you would have to intercept moveOrCopy at a certain point
let tmp = c.getTemp(s.parent[], ret.typ, ret.info)
tmp.sym.flags = tmpFlags
let cpy = if hasDestructor(c, ret.typ):
let cpy = if hasDestructor(c, ret.typ) and
ret.typ.kind notin {tyOpenArray, tyVarargs}:
# bug #23247 we don't own the data, so it's harmful to destroy it
s.parent[].final.add c.genDestroy(tmp)
moveOrCopy(tmp, ret, c, s, {IsDecl})
else:
@@ -662,6 +724,24 @@ 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: assert(false)
proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
@@ -689,9 +769,21 @@ 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}): PNode =
template isCustomDestructor(c: Con, t: PType): bool =
hasDestructor(c, t) and
getAttachedOp(c.graph, t, attachedDestructor) != nil and
sfOverridden in getAttachedOp(c.graph, t, attachedDestructor).flags
proc hasCustomDestructor(c: Con, t: PType): bool =
result = isCustomDestructor(c, t)
var obj = t
while obj.len > 0 and obj[0] != nil:
obj = skipTypes(obj[0], abstractPtrs)
result = result or isCustomDestructor(c, obj)
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode =
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt}:
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
template process(child, s): untyped = p(child, c, s, mode)
handleNestedTempl(n, process, tmpFlags = tmpFlags)
elif mode == sinkArg:
@@ -702,7 +794,15 @@ 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:
result = p(n, c, s, consumed)
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)
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
@@ -771,9 +871,15 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
result[i][1] = p(n[i][1], c, s, m)
else:
result[i] = p(n[i], c, s, m)
if mode == normal and isRefConstr:
if mode == normal and (isRefConstr or hasCustomDestructor(c, t)):
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
@@ -804,14 +910,17 @@ 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, gcOrc}:
if c.graph.config.selectedGC in {gcHooks, gcArc, gcAtomicArc, gcOrc}:
let destroyOld = c.genDestroy(result[1])
result = newTree(nkStmtList, destroyOld, result)
else:
result[0] = p(n[0], c, s, normal)
if canRaise(n[0]): s.needsTry = true
if mode == normal:
result = ensureDestruction(result, n, c, s)
if result.typ != nil and result.typ.kind notin {tyOpenArray, tyVarargs}:
# Returns of openarray types shouldn't be destroyed
# bug #19435; # bug #23247
result = ensureDestruction(result, n, c, s)
of nkDiscardStmt: # Small optimization
result = shallowCopy(n)
if n[0].kind != nkEmpty:
@@ -859,7 +968,9 @@ 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}
let flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
var flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
if inReturn:
flags.incl(IsReturn)
result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s, flags)
elif isDiscriminantField(n[0]):
result = c.genDiscriminantAsgn(s, n)
@@ -887,25 +998,6 @@ 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
@@ -962,7 +1054,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)
result[i] = p(n[i], c, s, mode, inReturn=true)
s.needsTry = true
of nkCast:
result = shallowCopy(n)
@@ -980,7 +1072,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
proc sameLocation*(a, b: PNode): bool =
proc sameConstant(a, b: PNode): bool =
a.kind in nkLiterals and a.intVal == b.intVal
a.kind in nkLiterals and b.kind in nkLiterals and a.intVal == b.intVal
const nkEndPoint = {nkSym, nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}
if a.kind in nkEndPoint and b.kind in nkEndPoint:
@@ -1004,9 +1096,9 @@ proc sameLocation*(a, b: PNode): bool =
of nkHiddenStdConv, nkHiddenSubConv: sameLocation(a[1], b)
else: false
proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
# with side effects
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), nextSymId c.idgen, c.owner, ri[1].info)
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), c.idgen, c.owner, ri[1].info)
temp.typ = ri[1].typ
var v = newNodeI(nkLetSection, ri[1].info)
let tempAsNode = newSymNode(temp)
@@ -1021,14 +1113,22 @@ proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode; flags: set[MoveOrCop
newAccess.add ri[0]
newAccess.add tempAsNode
var snk = c.genSink(dest, newAccess, flags)
var snk = c.genSink(s, 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):
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
case ri.kind:
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags)
@@ -1037,53 +1137,60 @@ 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:
case ri.kind
let ri2 = if ri.kind == nkWhen: ri[1][0] else: ri
case ri2.kind
of nkCallKinds:
result = c.genSink(dest, p(ri, c, s, consumed), flags)
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
of nkBracketExpr:
if isUnpackedTuple(ri[0]):
# unpacking of tuple: take over the elements
result = c.genSink(dest, p(ri, c, s, consumed), flags)
result = c.genSink(s, 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(dest, ri, flags)
var snk = c.genSink(s, dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
else:
result = genFieldAccessSideEffects(c, dest, ri, flags)
result = genFieldAccessSideEffects(c, s, dest, ri, flags)
else:
result = c.genSink(dest, destructiveMoveVar(ri, c, s), flags)
result = c.genSink(s, 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(dest, p(ri, c, s, consumed), flags)
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
result = c.genSink(dest, p(ri, c, s, consumed), flags)
result = c.genSink(s, 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(dest, ri, flags)
let snk = c.genSink(s, 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):
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(dest, ri, flags)
let snk = c.genSink(s, 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(dest, p(ri, c, s, sinkArg), flags)
result = c.genSink(s, 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
@@ -1094,10 +1201,12 @@ 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(dest, ri, flags)
let snk = c.genSink(s, 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

@@ -10,7 +10,7 @@ Platforms: """
macosx: i386;amd64;powerpc64;arm64
solaris: i386;amd64;sparc;sparc64
freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el
netbsd: i386;amd64
netbsd: i386;amd64;arm64
openbsd: i386;amd64;arm;arm64
dragonfly: i386;amd64
crossos: amd64
@@ -78,6 +78,7 @@ Files: "lib"
[Other]
Files: "examples"
Files: "dist/nimble"
Files: "dist/checksums"
Files: "tests"
@@ -91,6 +92,7 @@ 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

@@ -72,6 +72,69 @@ 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
@@ -80,12 +143,15 @@ 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 {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
result = n.sym.kind in SomeVar
else:
for ch in n:
if containsVariable(ch): return true
@@ -109,7 +175,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 containsTyRef(argType):
if argType != nil and not isCompileTimeOnly(argType) and containsDangerousRef(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
@@ -143,6 +209,12 @@ 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

View File

@@ -50,6 +50,7 @@ type
graph: ModuleGraph
config: ConfigRef
sigConflicts: CountTable[SigHash]
initProc: PProc
BModule = ref TJSGen
TJSTypeKind = enum # necessary JS "types"
@@ -110,6 +111,7 @@ type
extraIndent: int
up: PProc # up the call chain; required for closure support
declaredGlobals: IntSet
previousFileName: string # For frameInfo inside templates.
template config*(p: PProc): ConfigRef = p.module.config
@@ -157,6 +159,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
options: TOptions): PProc =
result = PProc(
blocks: @[],
optionsStack: if module.initProc != nil: module.initProc.optionsStack
else: @[],
options: options,
module: module,
procDef: procDef,
@@ -555,28 +559,36 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string,
r.res = frmt % [a, b, tmp, tmp2]
r.kind = resExpr
proc unsignedTrimmerJS(size: BiggestInt): Rope =
proc unsignedTrimmer(size: BiggestInt): string =
case size
of 1: rope"& 0xff"
of 2: rope"& 0xffff"
of 4: rope">>> 0"
else: rope""
of 1: "& 0xff"
of 2: "& 0xffff"
of 4: ">>> 0"
else: ""
template unsignedTrimmer(size: BiggestInt): Rope =
size.unsignedTrimmerJS
proc signedTrimmer(size: BiggestInt): string =
# sign extension is done by shifting to the left and then back to the right
"<< $1 >> $1" % [$(32 - size * 8)]
proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
reassign: static[bool] = false) =
var x, y: TCompRes
gen(p, n[1], x)
gen(p, n[2], y)
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
let size = n[1].typ.skipTypes(abstractRange).size
when reassign:
let (a, tmp) = maybeMakeTempAssignable(p, n[1], x)
r.res = "$1 = (($5 $2 $3) $4)" % [a, rope op, y.rdLoc, trimmer, tmp]
if size == 8 and optJsBigInt64 in p.config.globalOptions:
r.res = "$1 = BigInt.asUintN(64, ($4 $2 $3))" % [a, rope op, y.rdLoc, tmp]
else:
let trimmer = unsignedTrimmer(size)
r.res = "$1 = (($5 $2 $3) $4)" % [a, rope op, y.rdLoc, trimmer, tmp]
else:
r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
if size == 8 and optJsBigInt64 in p.config.globalOptions:
r.res = "BigInt.asUintN(64, ($1 $2 $3))" % [x.rdLoc, rope op, y.rdLoc]
else:
let trimmer = unsignedTrimmer(size)
r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
r.kind = resExpr
template ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
@@ -617,32 +629,103 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
template applyFormat(frmtA, frmtB) =
if i == 0: applyFormat(frmtA) else: applyFormat(frmtB)
template bitwiseExpr(op: string) =
let typ = n[1].typ.skipTypes(abstractVarRange)
if typ.kind in {tyUInt, tyUInt32}:
r.res = "(($1 $2 $3) >>> 0)" % [xLoc, op, yLoc]
else:
r.res = "($1 $2 $3)" % [xLoc, op, yLoc]
case op
of mAddI: applyFormat("addInt($1, $2)", "($1 + $2)")
of mSubI: applyFormat("subInt($1, $2)", "($1 - $2)")
of mMulI: applyFormat("mulInt($1, $2)", "($1 * $2)")
of mDivI: applyFormat("divInt($1, $2)", "Math.trunc($1 / $2)")
of mModI: applyFormat("modInt($1, $2)", "Math.trunc($1 % $2)")
of mAddI:
if i == 0:
if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
useMagic(p, "addInt64")
applyFormat("addInt64($1, $2)")
else:
applyFormat("addInt($1, $2)")
else:
applyFormat("($1 + $2)")
of mSubI:
if i == 0:
if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
useMagic(p, "subInt64")
applyFormat("subInt64($1, $2)")
else:
applyFormat("subInt($1, $2)")
else:
applyFormat("($1 - $2)")
of mMulI:
if i == 0:
if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
useMagic(p, "mulInt64")
applyFormat("mulInt64($1, $2)")
else:
applyFormat("mulInt($1, $2)")
else:
applyFormat("($1 * $2)")
of mDivI:
if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
useMagic(p, "divInt64")
applyFormat("divInt64($1, $2)", "$1 / $2")
else:
applyFormat("divInt($1, $2)", "Math.trunc($1 / $2)")
of mModI:
if n[1].typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
useMagic(p, "modInt64")
applyFormat("modInt64($1, $2)", "$1 % $2")
else:
applyFormat("modInt($1, $2)", "Math.trunc($1 % $2)")
of mSucc: applyFormat("addInt($1, $2)", "($1 + $2)")
of mPred: applyFormat("subInt($1, $2)", "($1 - $2)")
of mAddF64: applyFormat("($1 + $2)", "($1 + $2)")
of mSubF64: applyFormat("($1 - $2)", "($1 - $2)")
of mMulF64: applyFormat("($1 * $2)", "($1 * $2)")
of mDivF64: applyFormat("($1 / $2)", "($1 / $2)")
of mShrI: applyFormat("", "")
of mShrI:
let typ = n[1].typ.skipTypes(abstractVarRange)
if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
applyFormat("BigInt.asIntN(64, BigInt.asUintN(64, $1) >> BigInt($2))")
elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
applyFormat("($1 >> BigInt($2))")
else:
if typ.kind in {tyInt..tyInt32}:
let trimmerU = unsignedTrimmer(typ.size)
let trimmerS = signedTrimmer(typ.size)
r.res = "((($1 $2) >>> $3) $4)" % [xLoc, trimmerU, yLoc, trimmerS]
else:
applyFormat("($1 >>> $2)")
of mShlI:
if n[1].typ.size <= 4:
applyFormat("($1 << $2)", "($1 << $2)")
let typ = n[1].typ.skipTypes(abstractVarRange)
if typ.size == 8:
if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
applyFormat("BigInt.asIntN(64, $1 << BigInt($2))")
elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
applyFormat("BigInt.asUintN(64, $1 << BigInt($2))")
else:
applyFormat("($1 * Math.pow(2, $2))")
else:
applyFormat("($1 * Math.pow(2, $2))", "($1 * Math.pow(2, $2))")
if typ.kind in {tyUInt..tyUInt32}:
let trimmer = unsignedTrimmer(typ.size)
r.res = "(($1 << $2) $3)" % [xLoc, yLoc, trimmer]
else:
let trimmer = signedTrimmer(typ.size)
r.res = "(($1 << $2) $3)" % [xLoc, yLoc, trimmer]
of mAshrI:
if n[1].typ.size <= 4:
applyFormat("($1 >> $2)", "($1 >> $2)")
let typ = n[1].typ.skipTypes(abstractVarRange)
if typ.size == 8:
if optJsBigInt64 in p.config.globalOptions:
applyFormat("($1 >> BigInt($2))")
else:
applyFormat("Math.floor($1 / Math.pow(2, $2))")
else:
applyFormat("Math.floor($1 / Math.pow(2, $2))", "Math.floor($1 / Math.pow(2, $2))")
of mBitandI: applyFormat("($1 & $2)", "($1 & $2)")
of mBitorI: applyFormat("($1 | $2)", "($1 | $2)")
of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)")
if typ.kind in {tyUInt..tyUInt32}:
applyFormat("($1 >>> $2)")
else:
applyFormat("($1 >> $2)")
of mBitandI: bitwiseExpr("&")
of mBitorI: bitwiseExpr("|")
of mBitxorI: bitwiseExpr("^")
of mMinI: applyFormat("nimMin($1, $2)", "nimMin($1, $2)")
of mMaxI: applyFormat("nimMax($1, $2)", "nimMax($1, $2)")
of mAddU: applyFormat("", "")
@@ -678,7 +761,16 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mAbsI: applyFormat("absInt($1)", "Math.abs($1)")
of mNot: applyFormat("!($1)", "!($1)")
of mUnaryPlusI: applyFormat("+($1)", "+($1)")
of mBitnotI: applyFormat("~($1)", "~($1)")
of mBitnotI:
let typ = n[1].typ.skipTypes(abstractVarRange)
if typ.kind in {tyUInt..tyUInt64}:
if typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
applyFormat("BigInt.asUintN(64, ~($1))")
else:
let trimmer = unsignedTrimmer(typ.size)
r.res = "(~($1) $2)" % [xLoc, trimmer]
else:
applyFormat("~($1)")
of mUnaryPlusF64: applyFormat("+($1)", "+($1)")
of mUnaryMinusF64: applyFormat("-($1)", "-($1)")
of mCharToStr: applyFormat("nimCharToStr($1)", "nimCharToStr($1)")
@@ -697,17 +789,14 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mMulU: binaryUintExpr(p, n, r, "*")
of mDivU:
binaryUintExpr(p, n, r, "/")
if n[1].typ.skipTypes(abstractRange).size == 8:
if optJsBigInt64 notin p.config.globalOptions and
n[1].typ.skipTypes(abstractRange).size == 8:
# bigint / already truncates
r.res = "Math.trunc($1)" % [r.res]
of mDivI:
arithAux(p, n, r, op)
of mModI:
arithAux(p, n, r, op)
of mShrI:
var x, y: TCompRes
gen(p, n[1], x)
gen(p, n[2], y)
r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc]
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr:
arithAux(p, n, r, op)
of mEqRef:
@@ -741,6 +830,10 @@ proc genLineDir(p: PProc, n: PNode) =
lineF(p, "$1", [lineDir(p.config, n.info, line)])
if hasFrameInfo(p):
lineF(p, "F.line = $1;$n", [rope(line)])
let currentFileName = toFilename(p.config, n.info)
if p.previousFileName != currentFileName:
lineF(p, "F.filename = $1;$n", [makeJSString(currentFileName)])
p.previousFileName = currentFileName
proc genWhileStmt(p: PProc, n: PNode) =
var cond: TCompRes
@@ -1105,7 +1198,7 @@ proc needsNoCopy(p: PProc; y: PNode): bool =
return y.kind in nodeKindsNeedNoCopy or
((mapType(y.typ) != etyBaseIndex or (y.kind == nkSym and y.sym.kind == skParam)) and
(skipTypes(y.typ, abstractInst).kind in
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned} + IntegralTypes))
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned, tyOpenArray} + IntegralTypes))
proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
var a, b: TCompRes
@@ -1764,15 +1857,25 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v
createRecordVarAux(p, t.n, excludedFieldIDs, output)
t = t[0]
proc arrayTypeForElemType(typ: PType): string =
proc arrayTypeForElemType(conf: ConfigRef; typ: PType): string =
let typ = typ.skipTypes(abstractRange)
case typ.kind
of tyInt, tyInt32: "Int32Array"
of tyInt16: "Int16Array"
of tyInt8: "Int8Array"
of tyInt64:
if optJsBigInt64 in conf.globalOptions:
"BigInt64Array"
else:
""
of tyUInt, tyUInt32: "Uint32Array"
of tyUInt16: "Uint16Array"
of tyUInt8, tyChar, tyBool: "Uint8Array"
of tyUInt64:
if optJsBigInt64 in conf.globalOptions:
"BigUint64Array"
else:
""
of tyFloat32: "Float32Array"
of tyFloat64, tyFloat: "Float64Array"
of tyEnum:
@@ -1786,11 +1889,18 @@ proc arrayTypeForElemType(typ: PType): string =
proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
var t = skipTypes(typ, abstractInst)
case t.kind
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar:
of tyInt8..tyInt32, tyUInt8..tyUInt32, tyEnum, tyChar:
result = putToSeq("0", indirect)
of tyInt, tyUInt:
if $t.sym.loc.r == "bigint":
result = putToSeq("0n", indirect)
else:
result = putToSeq("0", indirect)
of tyInt64, tyUInt64:
if optJsBigInt64 in p.config.globalOptions:
result = putToSeq("0n", indirect)
else:
result = putToSeq("0", indirect)
of tyFloat..tyFloat128:
result = putToSeq("0.0", indirect)
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent:
@@ -1804,7 +1914,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
of tyArray:
let length = toInt(lengthOrd(p.config, t))
let e = elemType(t)
let jsTyp = arrayTypeForElemType(e)
let jsTyp = arrayTypeForElemType(p.config, e)
if jsTyp.len > 0:
result = "new $1($2)" % [rope(jsTyp), rope(length)]
elif length > 32:
@@ -1842,7 +1952,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result = putToSeq("null", indirect)
of tySequence, tyString:
result = putToSeq("[]", indirect)
of tyCstring, tyProc:
of tyCstring, tyProc, tyOpenArray:
result = putToSeq("null", indirect)
of tyStatic:
if t.n != nil:
@@ -1979,7 +2089,11 @@ proc genNewSeq(p: PProc, n: PNode) =
proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
case skipTypes(n[1].typ, abstractVar + abstractRange).kind
of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n[1], r)
of tyEnum, tyInt..tyInt32, tyUInt..tyUInt32, tyChar: gen(p, n[1], r)
of tyInt64, tyUInt64:
if optJsBigInt64 in p.config.globalOptions:
unaryExpr(p, n, r, "", "Number($1)")
else: gen(p, n[1], r)
of tyBool: unaryExpr(p, n, r, "", "($1 ? 1 : 0)")
else: internalError(p.config, n.info, "genOrd")
@@ -2091,6 +2205,13 @@ proc genMove(p: PProc; n: PNode; r: var TCompRes) =
genReset(p, n)
#lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
proc genDup(p: PProc; n: PNode; r: var TCompRes) =
var a: TCompRes
r.kind = resVal
r.res = p.getTemp()
gen(p, n[1], a)
lineF(p, "$1 = $2;$n", [r.rdLoc, a.rdLoc])
proc genJSArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
r.res = rope("[")
@@ -2202,14 +2323,34 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
r.res = "($1).length - 1" % [x.rdLoc]
r.kind = resExpr
of mInc:
if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}:
let typ = n[1].typ.skipTypes(abstractVarRange)
case typ.kind
of tyUInt..tyUInt32:
binaryUintExpr(p, n, r, "+", true)
of tyUInt64:
if optJsBigInt64 in p.config.globalOptions:
binaryExpr(p, n, r, "", "$1 = BigInt.asUintN(64, $3 + BigInt($2))", true)
else: binaryUintExpr(p, n, r, "+", true)
elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
if optOverflowCheck notin p.options:
binaryExpr(p, n, r, "", "$1 = BigInt.asIntN(64, $3 + BigInt($2))", true)
else: binaryExpr(p, n, r, "addInt64", "$1 = addInt64($3, BigInt($2))", true)
else:
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2")
else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)", true)
of ast.mDec:
if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}:
let typ = n[1].typ.skipTypes(abstractVarRange)
case typ.kind
of tyUInt..tyUInt32:
binaryUintExpr(p, n, r, "-", true)
of tyUInt64:
if optJsBigInt64 in p.config.globalOptions:
binaryExpr(p, n, r, "", "$1 = BigInt.asUintN(64, $3 - BigInt($2))", true)
else: binaryUintExpr(p, n, r, "+", true)
elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
if optOverflowCheck notin p.options:
binaryExpr(p, n, r, "", "$1 = BigInt.asIntN(64, $3 - BigInt($2))", true)
else: binaryExpr(p, n, r, "subInt64", "$1 = subInt64($3, BigInt($2))", true)
else:
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)", true)
@@ -2265,6 +2406,10 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
r.kind = resExpr
of mMove:
genMove(p, n, r)
of mDup:
genDup(p, n, r)
of mEnsureMove:
gen(p, n[1], r)
else:
genCall(p, n, r)
#else internalError(p.config, e.info, 'genMagic: ' + magicToStr[op]);
@@ -2303,7 +2448,7 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
## Nim sequence maps to JS array.
var t = skipTypes(n.typ, abstractInst)
let e = elemType(t)
let jsTyp = arrayTypeForElemType(e)
let jsTyp = arrayTypeForElemType(p.config, e)
if skipTypes(n.typ, abstractVarRange).kind != tySequence and jsTyp.len > 0:
# generate typed array
# for example Nim generates `new Uint8Array([1, 2, 3])` for `[byte(1), 2, 3]`
@@ -2384,7 +2529,29 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) =
r.res = "(!!($1))" % [r.res]
r.kind = resExpr
elif toInt:
r.res = "(($1) | 0)" % [r.res]
if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
r.res = "Number($1)" % [r.res]
else:
r.res = "(($1) | 0)" % [r.res]
elif dest.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
if fromInt or fromUint or src.kind in {tyBool, tyChar, tyEnum}:
r.res = "BigInt($1)" % [r.res]
elif src.kind in {tyFloat..tyFloat64}:
r.res = "BigInt(Math.trunc($1))" % [r.res]
elif src.kind == tyUInt64:
r.res = "BigInt.asIntN(64, $1)" % [r.res]
elif dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
if fromUint or src.kind in {tyBool, tyChar, tyEnum}:
r.res = "BigInt($1)" % [r.res]
elif fromInt: # could be negative
r.res = "BigInt.asUintN(64, BigInt($1))" % [r.res]
elif src.kind in {tyFloat..tyFloat64}:
r.res = "BigInt.asUintN(64, BigInt(Math.trunc($1)))" % [r.res]
elif src.kind == tyInt64:
r.res = "BigInt.asUintN(64, $1)" % [r.res]
elif toUint or dest.kind in tyFloat..tyFloat64:
if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
r.res = "Number($1)" % [r.res]
else:
# TODO: What types must we handle here?
discard
@@ -2395,7 +2562,11 @@ proc upConv(p: PProc, n: PNode, r: var TCompRes) =
proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
var a, b: TCompRes
gen(p, n[0], r)
if optRangeCheck notin p.options or (skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64} and
let src = skipTypes(n[0].typ, abstractVarRange)
let dest = skipTypes(n.typ, abstractVarRange)
if src.kind in {tyInt64, tyUInt64} and dest.kind notin {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
r.res = "Number($1)" % [r.res]
if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and
checkUnsignedConversions notin p.config.legacyFeatures):
discard "XXX maybe emit masking instructions here"
else:
@@ -2584,24 +2755,35 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) =
let fromInt = (src.kind in tyInt..tyInt32)
let fromUint = (src.kind in tyUInt..tyUInt32)
if toUint and (fromInt or fromUint):
let trimmer = unsignedTrimmer(dest.size)
r.res = "($1 $2)" % [r.res, trimmer]
if toUint:
if fromInt or fromUint:
r.res = "Number(BigInt.asUintN($1, BigInt($2)))" % [$(dest.size * 8), r.res]
elif src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
r.res = "Number(BigInt.asUintN($1, $2))" % [$(dest.size * 8), r.res]
elif toInt:
if fromInt:
return
elif fromUint:
if src.size == 4 and dest.size == 4:
# XXX prevent multi evaluations
r.res = "($1 | 0)" % [r.res]
else:
let trimmer = unsignedTrimmer(dest.size)
let minuend = case dest.size
of 1: "0xfe"
of 2: "0xfffe"
of 4: "0xfffffffe"
else: ""
r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer]
if fromInt or fromUint:
r.res = "Number(BigInt.asIntN($1, BigInt($2)))" % [$(dest.size * 8), r.res]
elif src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
r.res = "Number(BigInt.asIntN($1, $2))" % [$(dest.size * 8), r.res]
elif dest.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
if fromInt or fromUint or src.kind in {tyBool, tyChar, tyEnum}:
r.res = "BigInt($1)" % [r.res]
elif src.kind in {tyFloat..tyFloat64}:
r.res = "BigInt(Math.trunc($1))" % [r.res]
elif src.kind == tyUInt64:
r.res = "BigInt.asIntN(64, $1)" % [r.res]
elif dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
if fromUint or src.kind in {tyBool, tyChar, tyEnum}:
r.res = "BigInt($1)" % [r.res]
elif fromInt: # could be negative
r.res = "BigInt.asUintN(64, BigInt($1))" % [r.res]
elif src.kind in {tyFloat..tyFloat64}:
r.res = "BigInt.asUintN(64, BigInt(Math.trunc($1)))" % [r.res]
elif src.kind == tyInt64:
r.res = "BigInt.asUintN(64, $1)" % [r.res]
elif dest.kind in tyFloat..tyFloat64:
if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
r.res = "Number($1)" % [r.res]
elif (src.kind == tyPtr and mapType(p, src) == etyObject) and dest.kind == tyPointer:
r.address = r.res
r.res = "null"
@@ -2620,10 +2802,25 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkSym:
genSym(p, n, r)
of nkCharLit..nkUInt64Lit:
if n.typ.kind == tyBool:
case n.typ.skipTypes(abstractVarRange).kind
of tyBool:
r.res = if n.intVal == 0: rope"false" else: rope"true"
of tyUInt64:
r.res = rope($cast[BiggestUInt](n.intVal))
if optJsBigInt64 in p.config.globalOptions:
r.res.add('n')
of tyInt64:
let wrap = n.intVal < 0 # wrap negative integers with parens
if wrap: r.res.add '('
r.res.addInt n.intVal
if optJsBigInt64 in p.config.globalOptions:
r.res.add('n')
if wrap: r.res.add ')'
else:
r.res = rope(n.intVal)
let wrap = n.intVal < 0 # wrap negative integers with parens
if wrap: r.res.add '('
r.res.addInt n.intVal
if wrap: r.res.add ')'
r.kind = resExpr
of nkNilLit:
if isEmptyType(n.typ):
@@ -2842,6 +3039,7 @@ proc processJSCodeGen*(b: PPassContext, n: PNode): PNode =
if m.module == nil: internalError(m.config, n.info, "myProcess")
let globals = PGlobals(m.graph.backend)
var p = newInitProc(globals, m)
m.initProc = p
p.unique = globals.unique
genModule(p, n)
p.g.code.add(p.locals)
@@ -2855,7 +3053,7 @@ proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
var p = newInitProc(globals, m)
attachProc(p, prc)
var disp = generateMethodDispatchers(graph)
var disp = generateMethodDispatchers(graph, m.idgen)
for i in 0..<disp.len:
let prc = disp[i].sym
if not globals.generatedSyms.containsOrIncl(prc.id):

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"), nextSymId(idgen), iter, iter.info)
result = newSym(skField, getIdent(g.cache, ":state"), 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"), nextSymId(idgen), iter, iter.info, {})
result = newSym(skResult, getIdent(g.cache, ":result"), idgen, iter, iter.info, {})
result.typ = iter.typ[0]
incl(result.flags, sfUsed)
iter.ast.add newSymNode(result)
@@ -258,8 +258,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
let iter = n.sym
assert iter.isIterator
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
result = newNodeIT(nkStmtListExpr, n.info, iter.typ)
let hp = getHiddenParam(g, iter)
var env: PNode
if owner.isIterator:
@@ -267,7 +266,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, nextSymId(idgen), owner, n.info)
let e = newSym(skLet, iter.name, idgen, owner, n.info)
e.typ = hp.typ
e.flags = hp.flags
env = newSymNode(e)
@@ -293,23 +292,26 @@ 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.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags):
elif not (owner.typ.isClosure or owner.isNimcall and not owner.isExplicitCallConv or isEnv):
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)
owner.typ.callConv = ccClosure
if not isEnv:
owner.typ.callConv = ccClosure
type
DetectionPass = object
processed, capturedVars: IntSet
ownerToType: Table[int, PType]
somethingToDo: bool
inTypeOf: bool
graph: ModuleGraph
idgen: IdGenerator
@@ -380,7 +382,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, nextSymId(c.idgen), obj.owner, obj.owner.info)
let result = newSym(skField, upIdent, c.idgen, obj.owner, obj.owner.info)
result.typ = fieldType
when false:
if c.graph.config.selectedGC == gcDestructors:
@@ -413,12 +415,15 @@ 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), nextSymId(c.idgen), fn, fn.info)
cp = newSym(skParam, getIdent(c.graph.cache, paramName), c.idgen, fn, fn.info)
incl(cp.flags, sfFromGeneric)
cp.typ = t
addHiddenParam(fn, cp)
@@ -444,12 +449,15 @@ 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.containsOrIncl(s.id):
if not c.capturedVars.contains(s.id):
if not c.inTypeOf: c.capturedVars.incl(s.id)
let obj = getHiddenParam(c.graph, owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
#let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr})
@@ -458,7 +466,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 (innerProc and not s.isIterator and s.typ.callConv == ccClosure) or interestingVar(s):
elif innerClosure or interested:
discard """
proc outer() =
var x: int
@@ -475,10 +483,12 @@ 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) 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)
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)
# create required upFields:
var w = owner.skipGenericOwner
if isInnerProc(w) or owner.isIterator:
@@ -510,9 +520,14 @@ 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
@@ -545,7 +560,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), nextSymId(idgen), owner, info)
var v = newSym(skVar, getIdent(cache, envName), idgen, owner, info)
v.flags = {sfShadowed, sfGeneratedOp}
v.typ = typ
result = newSymNode(v)
@@ -569,7 +584,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"), nextSymId d.idgen, owner, info)
var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), d.idgen, owner, info)
v.flags = {sfShadowed, sfGeneratedOp}
v.typ = envVarType
c.unownedEnvVars[owner.id] = newSymNode(v)
@@ -653,7 +668,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), nextSymId(d.idgen), owner, iter.info)
var v = newSym(skVar, getIdent(d.graph.cache, envName), d.idgen, owner, iter.info)
incl(v.flags, sfShadowed)
v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ)
var vnode: PNode
@@ -792,6 +807,8 @@ 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:
@@ -943,7 +960,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
let iter = op.sym
let hp = getHiddenParam(g, iter)
env = newSym(skLet, iter.name, nextSymId(idgen), owner, body.info)
env = newSym(skLet, iter.name, idgen, owner, body.info)
env.typ = hp.typ
env.flags = hp.flags
@@ -971,12 +988,15 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
# gather vars in a tuple:
var v2 = newNodeI(nkLetSection, body.info)
var vpart = newNodeI(if body.len == 3: nkIdentDefs else: nkVarTuple, body.info)
for i in 0..<body.len-2:
if body[i].kind == nkSym:
body[i].sym.transitionToLet()
vpart.add body[i]
if body.len == 3 and body[0].kind == nkVarTuple:
vpart = body[0] # fixes for (i,j) in walk() # bug #15924
else:
for i in 0..<body.len-2:
if body[i].kind == nkSym:
body[i].sym.transitionToLet()
vpart.add body[i]
vpart.add newNodeI(nkEmpty, body.info) # no explicit type
vpart.add newNodeI(nkEmpty, body.info) # no explicit type
if not env.isNil:
call[0] = makeClosure(g, idgen, call[0].sym, env.newSymNode, body.info)
vpart.add call

View File

@@ -510,7 +510,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
rememberSplit(splitComma)
wrSpace em
of openPars:
if tok.strongSpaceA and not em.endsInWhite and
if tsLeading in tok.spacing 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 (((not tok.strongSpaceA) and tok.strongSpaceB == tsNone) and
if em.inquote or (tok.spacing == {} 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.strongSpaceB == tsNone and tok.strongSpaceA
tok.spacing == {tsLeading}
if not isUnary(tok):
rememberSplit(splitBinary)

View File

@@ -23,7 +23,6 @@ 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'}
@@ -94,19 +93,18 @@ type
base2, base8, base16
TokenSpacing* = enum
tsNone, tsTrailing, tsEof
tsLeading, 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
@@ -178,7 +176,7 @@ proc initToken*(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
L.strongSpaceA = false
L.spacing = {}
L.literal = ""
L.fNumber = 0.0
L.base = base10
@@ -191,7 +189,7 @@ proc fillToken(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
L.strongSpaceA = false
L.spacing = {}
setLen(L.literal, 0)
L.fNumber = 0.0
L.base = base10
@@ -737,10 +735,6 @@ 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()
@@ -960,13 +954,15 @@ 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.strongSpaceB = tsNone
tok.spacing = tok.spacing - {tsTrailing, tsEof}
var trailing = false
while L.buf[pos] == ' ':
inc pos
if tok.strongSpaceB != tsTrailing:
tok.strongSpaceB = tsTrailing
trailing = true
if L.buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
tok.strongSpaceB = tsEof
tok.spacing.incl(tsEof)
elif trailing:
tok.spacing.incl(tsTrailing)
proc getPrecedence*(tok: Token): int =
## Calculates the precedence of the given token.
@@ -1077,7 +1073,6 @@ 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
@@ -1096,8 +1091,6 @@ 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
@@ -1140,7 +1133,6 @@ 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
@@ -1153,7 +1145,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.strongSpaceA = false
tok.spacing.excl(tsLeading)
when defined(nimpretty):
var hasComment = false
var commentIndent = L.currLineIndent
@@ -1164,8 +1156,7 @@ proc skip(L: var Lexer, tok: var Token) =
case L.buf[pos]
of ' ':
inc(pos)
if not tok.strongSpaceA:
tok.strongSpaceA = true
tok.spacing.incl(tsLeading)
of '\t':
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead")
inc(pos)
@@ -1187,7 +1178,7 @@ proc skip(L: var Lexer, tok: var Token) =
pos = L.bufpos
else:
break
tok.strongSpaceA = false
tok.spacing.excl(tsLeading)
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] == '#'):

View File

@@ -8,7 +8,7 @@
#
## This module implements lifting for type-bound operations
## (``=sink``, ``=copy``, ``=destroy``, ``=deepCopy``).
## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`).
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils
@@ -34,11 +34,12 @@ 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)
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym
info: TLineInfo; idgen: IdGenerator; isDistinct = false): PSym
proc createTypeBoundOps*(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo;
idgen: IdGenerator)
@@ -49,9 +50,9 @@ proc at(a, i: PNode, elemType: PType): PNode =
result[1] = i
result.typ = elemType
proc destructorOverriden(g: ModuleGraph; t: PType): bool =
proc destructorOverridden(g: ModuleGraph; t: PType): bool =
let op = getAttachedOp(g, t, attachedDestructor)
op != nil and sfOverriden in op.flags
op != nil and sfOverridden in op.flags
proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
for i in 0..<t.len:
@@ -82,14 +83,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}:
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink, attachedDup}:
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:
@@ -139,11 +140,14 @@ 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))
destroy.add genAddr(c, x)
if op.typ[1].kind != tyVar:
destroy.add x
else:
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
@@ -152,17 +156,18 @@ proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
result.add(newSymNode(op))
result.add genAddr(c, x)
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) =
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool, enforceWasMoved = false) =
case n.kind
of nkSym:
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 f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
c.g.config.selectedGC in {gcArc, gcOrc, gcHooks}) or
if (sfCursor in f.flags and c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
enforceDefaultOp:
defaultOp(c, f.typ, body, x.dotField(f), b)
else:
if enforceWasMoved:
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x.dotField(f))
fillBody(c, f.typ, body, x.dotField(f), b)
of nkNilLit: discard
of nkRecCase:
@@ -201,7 +206,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
branch[^1] = newNodeI(nkStmtList, c.info)
fillBodyObj(c, n[i].lastSon, branch[^1], x, y,
enforceDefaultOp = localEnforceDefaultOp)
enforceDefaultOp = localEnforceDefaultOp, enforceWasMoved = c.kind == attachedAsgn)
if branch[^1].len == 0: inc emptyBranches
caseStmt.add(branch)
if emptyBranches != n.len-1:
@@ -212,13 +217,16 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
c.filterDiscriminator = oldfilterDiscriminator
of nkRecList:
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp)
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp, enforceWasMoved)
else:
illFormedAstLocal(n, c.g.config)
proc fillBodyObjTImpl(c: var TLiftCtx; t: PType, body, x, y: PNode) =
if t.len > 0 and t[0] != nil:
fillBody(c, skipTypes(t[0], abstractPtrs), body, x, y)
let obj = newNodeIT(nkHiddenSubConv, c.info, t[0])
obj.add newNodeI(nkEmpty, c.info)
obj.add x
fillBody(c, skipTypes(t[0], abstractPtrs), body, obj, y)
fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false)
proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
@@ -243,7 +251,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), nextSymId c.idgen, c.fn, c.info)
var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), 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,
@@ -252,7 +260,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), nextSymId c.idgen, c.fn, c.info)
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
temp.typ = x.typ
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info)
@@ -262,7 +270,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
@@ -275,6 +283,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
c.kind = attachedDestructor
fillBodyObjTImpl(c, t, body, blob, y)
c.kind = prevKind
else:
fillBodyObjTImpl(c, t, body, x, y)
@@ -283,7 +292,7 @@ proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
result.typ = getSysType(g, info, tyBool)
proc getCycleParam(c: TLiftCtx): PNode =
assert c.kind == attachedAsgn
assert c.kind in {attachedAsgn, attachedDup}
if c.fn.typ.len == 4:
result = c.fn.typ.n.lastSon
assert result.kind == nkSym
@@ -322,6 +331,9 @@ 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)
@@ -346,9 +358,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 destructorOverriden = destructorOverriden(c.g, t)
let destructorOverridden = destructorOverridden(c.g, t)
if op != nil and op != c.fn and
(sfOverriden in op.flags or destructorOverriden):
(sfOverridden in op.flags or destructorOverridden):
if sfError in op.flags:
incl c.fn.flags, sfError
#else:
@@ -356,7 +368,7 @@ 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 destructorOverriden:
elif op == nil and destructorOverridden:
op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
body.add newHookCall(c, op, x, y)
result = true
@@ -394,7 +406,7 @@ proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
let t = orig.skipTypes(abstractInst - {tyDistinct})
var op = t.destructor
if op != nil and sfOverriden in op.flags:
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
op = instantiateGeneric(c, op, t, t.typeInst)
@@ -417,7 +429,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 sfOverriden in op.flags:
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
@@ -431,7 +443,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
#result = addDestructorCall(c, t, body, x)
of attachedAsgn, attachedSink, attachedTrace:
var op = getAttachedOp(c.g, t, c.kind)
if op != nil and sfOverriden in op.flags:
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic =trace:
op = instantiateGeneric(c, op, t, t.typeInst)
@@ -451,7 +463,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
of attachedWasMoved:
var op = getAttachedOp(c.g, t, attachedWasMoved)
if op != nil and sfOverriden in op.flags:
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
@@ -463,8 +475,22 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
body.add genWasMovedCall(c, op, x)
result = true
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
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info)
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
temp.typ = getSysType(c.g, body.info, tyInt)
incl(temp.flags, sfFromGeneric)
@@ -474,7 +500,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), nextSymId(c.idgen), c.fn, c.info)
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
temp.typ = value.typ
incl(temp.flags, sfFromGeneric)
@@ -521,14 +547,28 @@ 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:
@@ -542,17 +582,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(t.elemType):
if canFormAcycle(c.g, 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:
if t.assignment == nil or t.destructor == nil or t.dup == nil:
let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct})
let canon = c.g.canonTypes.getOrDefault(h)
if canon != nil: t = canon
@@ -578,16 +618,22 @@ 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(t.elemType):
if t.kind != tyString and canFormAcycle(c.g, 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 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)
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
of attachedAsgn, attachedDeepCopy:
of attachedAsgn, attachedDeepCopy, attachedDup:
body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y)
of attachedSink:
let moveCall = genBuiltin(c, mMove, "move", x)
@@ -599,11 +645,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*(t: PType): bool =
proc cyclicType*(g: ModuleGraph, t: PType): bool =
case t.kind
of tyRef: result = types.canFormAcycle(t.lastSon)
of tyRef: result = types.canFormAcycle(g, t.lastSon)
of tyProc: result = t.callConv == ccClosure
else: result = false
@@ -631,7 +677,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(elemType)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType)
let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and
(not isPureObject(elemType)) and
@@ -639,7 +685,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}:
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
declareTempOf(c, body, x)
else:
x
@@ -698,8 +744,16 @@ 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 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))
proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
## Closures are really like refs except they always use a virtual destructor
@@ -709,7 +763,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}:
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
declareTempOf(c, body, xenv)
else:
xenv
@@ -743,12 +797,21 @@ 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
@@ -761,6 +824,9 @@ 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:
@@ -773,7 +839,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)
@@ -795,11 +861,13 @@ 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:
@@ -811,7 +879,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, gcOrc}:
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.g, c.info, tyPointer)
case c.kind
@@ -826,6 +894,11 @@ 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:
@@ -834,7 +907,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)
@@ -846,11 +919,13 @@ 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
@@ -859,7 +934,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}:
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
atomicRefOp(c, t, body, x, y)
elif (optOwnedRefs in c.g.config.globalOptions and
optRefCheck in c.g.config.options):
@@ -868,7 +943,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}:
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
atomicClosureOp(c, t, body, x, y)
else:
closureOp(c, t, body, x, y)
@@ -914,10 +989,25 @@ 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 c.kind in {attachedAsgn, attachedSink} and t.sym != nil and sfImportc in t.sym.flags:
body.add newAsgnStmt(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)
else:
fillBodyObjT(c, t, body, x, y)
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)
of tyDistinct:
if not considerUserDefinedOp(c, t, body, x, y):
fillBody(c, t[0], body, x, y)
@@ -946,19 +1036,62 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
assert typ.kind == tyDistinct
let baseType = typ[0]
if getAttachedOp(g, baseType, kind) == nil:
discard produceSym(g, c, baseType, kind, info, idgen)
# TODO: fixme `isDistinct` is a fix for #23552; remove it after
# `-d:nimPreviewNonVarDestructor` becomes the default
discard produceSym(g, c, baseType, kind, info, idgen, isDistinct = true)
result = getAttachedOp(g, baseType, kind)
setAttachedOp(g, idgen.module, typ, kind, result)
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
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; isDistinct = false): PSym =
if kind == attachedDup:
return symDupPrototype(g, typ, owner, kind, info, idgen)
let procname = getIdent(g.cache, AttachedOpToStr[kind])
result = newSym(skProc, procname, nextSymId(idgen), owner, info)
let dest = newSym(skParam, getIdent(g.cache, "dest"), nextSymId(idgen), result, info)
result = newSym(skProc, procname, idgen, owner, info)
let dest = newSym(skParam, getIdent(g.cache, "dest"), idgen, result, info)
let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"),
nextSymId(idgen), result, info)
dest.typ = makeVarType(typ.owner, typ, idgen)
idgen, result, info)
if kind == attachedDestructor and typ.kind in {tyRef, tyString, tySequence} and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and not isDistinct:
dest.typ = typ
else:
dest.typ = makeVarType(typ.owner, typ, idgen)
if kind == attachedTrace:
src.typ = getSysType(g, info, tyPointer)
else:
@@ -970,9 +1103,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(typ.skipTypes(abstractInst)):
cyclicType(g, typ.skipTypes(abstractInst)):
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
nextSymId(idgen), result, info)
idgen, result, info)
cycleParam.typ = getSysType(g, info, tyBool)
result.typ.addParam cycleParam
@@ -984,6 +1117,9 @@ 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)
@@ -993,33 +1129,36 @@ proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newAsgnStmt(xx, yy)
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym =
info: TLineInfo; idgen: IdGenerator; isDistinct = false): PSym =
if typ.kind == tyDistinct:
return produceSymDistinctType(g, c, typ, kind, info, idgen)
result = getAttachedOp(g, typ, kind)
if result == nil:
result = symPrototype(g, typ, typ.owner, kind, info, idgen)
result = symPrototype(g, typ, typ.owner, kind, info, idgen, isDistinct = isDistinct)
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType: typ, idgen: idgen,
fn: result)
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))
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)
else: newSymNode(result.typ.n[2].sym)
# register this operation already:
setAttachedOpPartial(g, idgen.module, typ, kind, result)
if kind == attachedSink and destructorOverriden(g, typ):
if kind == attachedSink and destructorOverridden(g, typ):
## compiler can use a combination of `=destroy` and memCopy for sink op
dest.flags.incl sfCursor
result.ast[bodyPos].add newOpCall(a, getAttachedOp(g, typ, attachedDestructor), d[0])
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 newAsgnStmt(d, src)
else:
var tk: TTypeKind
if g.config.selectedGC in {gcArc, gcOrc, gcHooks}:
if g.config.selectedGC in {gcArc, gcOrc, gcHooks, gcAtomicArc}:
tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind
else:
tk = tyNone # no special casing for strings and seqs
@@ -1030,7 +1169,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} and not lacksMTypeField(typ):
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not lacksMTypeField(typ):
# bug #19205: Do not forget to also copy the hidden type field:
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
@@ -1049,7 +1188,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"), nextSymId(idgen), result, info)
let dst = newSym(skVar, getIdent(g.cache, "dest"), idgen, result, info)
dst.typ = makePtrType(typ.owner, typ, idgen)
let dstSym = newSymNode(dst)
let d = newDeref(dstSym)
@@ -1075,7 +1214,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:
if op.magic == mDestroy and t.kind != tyString:
internalError(g.config, info, "patching mDestroy with mDestroy?")
n[0] = newSymNode(op)
for x in n: patchBody(g, c, x, info, idgen)
@@ -1093,7 +1232,7 @@ proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: I
else:
localError(g.config, info, "unresolved generic parameter")
proc isTrival(s: PSym): bool {.inline.} =
proc isTrival*(s: PSym): bool {.inline.} =
s == nil or (s.ast != nil and s.ast[bodyPos].len == 0)
proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo;

View File

@@ -44,6 +44,7 @@ type
errRstSandboxedDirective,
errProveInit, # deadcode
errGenerated,
errFailedMove,
errUser,
# warnings
warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape",
@@ -83,16 +84,18 @@ type
warnCstringConv = "CStringConv",
warnPtrToCstringConv = "PtrToCstringConv",
warnEffect = "Effect",
warnCastSizes = "CastSizes"
warnCastSizes = "CastSizes", # deadcode
warnAboveMaxSizeSet = "AboveMaxSizeSet",
warnImplicitTemplateRedefinition = "ImplicitTemplateRedefinition",
warnUnnamedBreak = "UnnamedBreak",
warnStmtListLambda = "StmtListLambda",
warnBareExcept = "BareExcept",
warnImplicitDefaultValue = "ImplicitDefaultValue",
warnGenericsIgnoredInjection = "GenericsIgnoredInjection",
warnUser = "User",
# hints
hintSuccess = "Success", hintSuccessX = "SuccessX",
hintCC = "CC",
hintLineTooLong = "LineTooLong",
hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintDuplicateModuleImport = "DuplicateModuleImport",
hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded",
hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX",
@@ -106,6 +109,7 @@ type
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
hintMsgOrigin = "MsgOrigin", # since 1.3.5
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
hintUnknownHint = "UnknownHint"
const
MsgKindToStr*: array[TMsgKind, string] = [
@@ -127,6 +131,7 @@ 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",
@@ -182,19 +187,21 @@ const
warnAnyEnumConv: "$1",
warnHoleEnumConv: "$1",
warnCstringConv: "$1",
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; Use a `cast` operation like `cast[cstring](x)`; this will become a compile time error in the future",
warnEffect: "$1",
warnCastSizes: "$1",
warnCastSizes: "$1", # deadcode
warnAboveMaxSizeSet: "$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",
warnGenericsIgnoredInjection: "$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",
@@ -227,6 +234,7 @@ const
hintExtendedContext: "$1",
hintMsgOrigin: "$1",
hintDeclaredLoc: "$1",
hintUnknownHint: "unknown hint: $1"
]
const
@@ -244,7 +252,7 @@ type
TNoteKinds* = set[TNoteKind]
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv}
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept}
result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
result[1] = result[2] - {warnProveField, warnProveIndex,
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
@@ -275,7 +283,7 @@ type
# and parsed; usually "" but is used
# for 'nimsuggest'
hash*: string # the checksum of the file
dirty*: bool # for 'nimfix' / 'nimpretty' like tooling
dirty*: bool # for 'nimpretty' like tooling
when defined(nimpretty):
fullContent*: string
FileIndex* = distinct int32

View File

@@ -95,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(ctx.module) and # ignore foreign packages
ctx.config.belongsToProjectPackage(sym) 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
@@ -136,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(ctx.module) and # ignore foreign packages
ctx.config.belongsToProjectPackage(sym) 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
@@ -147,6 +147,10 @@ proc checkPragmaUseImpl(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragm
if pragmaName != wanted:
lintReport(conf, info, wanted, pragmaName)
template checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
checkPragmaUseImpl(conf, info, w, 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)

View File

@@ -8,14 +8,14 @@
#
# This module implements lookup helpers.
import std/[algorithm, strutils]
import std/[algorithm, strutils, tables]
when defined(nimPreviewSlimSystem):
import std/assertions
import
intsets, ast, astalgo, idents, semdata, types, msgs, options,
renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs, sets
renderer, lineinfos, modulegraphs, astmsgs, sets, wordrecg
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
@@ -94,17 +94,6 @@ 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
@@ -265,6 +254,41 @@ 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
@@ -274,7 +298,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
considerQuotedIdent(c, m)
else:
getIdent(c.cache, "err:" & renderTree(m))
result = newSym(skError, ident, nextSymId(c.idgen), getCurrOwner(c), n.info, {})
result = newSym(skError, ident, 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:
@@ -340,17 +364,18 @@ 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.s == "_": return
if sym.name.id == ord(wUnderscore): return
let conflict = scope.addUniqueSym(sym)
if conflict != nil:
if sym.kind == skModule and conflict.kind == skModule and
sym.position == conflict.position:
if sym.kind == skModule and conflict.kind == skModule:
# 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.
localError(c.config, info, hintDuplicateModuleImport,
"duplicate import of '$1'; previous import here: $2" %
[sym.name.s, c.config $ conflict.info])
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])
else:
wrongRedefinition(c, info, sym.name.s, conflict.info, errGenerated)
@@ -396,11 +421,12 @@ proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) =
if fn.kind notin OverloadableSyms:
internalError(c.config, fn.info, "addOverloadableSymAt")
return
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)
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)
proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
## adds an overloadable symbol on the scope and the interface if appropriate
@@ -437,13 +463,6 @@ 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
@@ -489,12 +508,9 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
let e = list.pop()
if c.config.spellSuggestMax == spellSuggestSecretSauce:
const
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
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
elif count >= c.config.spellSuggestMax: break
if count == 0:
result.add "\ncandidates (edit distance, scope distance); see '--spellSuggest': "
@@ -546,12 +562,20 @@ proc errorUseQualifier*(c: PContext; info:TLineInfo; choices: PNode) =
errorUseQualifier(c, info, candidates, prefix)
proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extra = "") =
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 = ""
var err: string
if name == "_":
err = "the special identifier '_' is ignored in declarations and cannot be used"
else:
err = "undeclared identifier: '" & name & "'"
if "`gensym" in name:
err.add "; if declared in a template, this identifier may be inconsistently marked inject or gensym"
if extra.len != 0:
err.add 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 =
@@ -565,13 +589,13 @@ proc lookUp*(c: PContext, n: PNode): PSym =
var amb = false
case n.kind
of nkIdent:
result = searchInScopes(c, n.ident, amb).skipAlias(n, c.config)
result = searchInScopes(c, n.ident, amb)
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).skipAlias(n, c.config)
result = searchInScopes(c, ident, amb)
if result == nil: result = errorUndeclaredIdentifierHint(c, n, ident)
else:
internalError(c.config, n.info, "lookUp")
@@ -593,9 +617,9 @@ 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).skipAlias(n, c.config)
result = searchInScopes(c, ident, amb)
else:
let candidates = searchInScopesFilterBy(c, ident, allExceptModule) #.skipAlias(n, c.config)
let candidates = searchInScopesFilterBy(c, ident, allExceptModule)
if candidates.len > 0:
result = candidates[0]
amb = candidates.len > 1
@@ -627,13 +651,20 @@ 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).skipAlias(n, c.config)
result = strTableGet(c.topLevelScope.symbols, ident)
else:
result = someSym(c.graph, m, ident).skipAlias(n, c.config)
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)
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: " &
@@ -653,7 +684,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
var scope = c.currentScope
o.mode = oimNoQualifier
while true:
result = initIdentIter(o.it, scope.symbols, ident).skipAlias(n, c.config)
result = initIdentIter(o.it, scope.symbols, ident)
if result != nil:
o.currentScope = scope
break
@@ -661,7 +692,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).skipAlias(n, c.config)
result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph)
if result != nil:
o.currentScope = nil
o.importIdx = i
@@ -684,10 +715,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).skipAlias(n, c.config)
ident)
o.mode = oimSelfModule
else:
result = initModuleIter(o.mit, c.graph, o.m, ident).skipAlias(n, c.config)
result = initModuleIter(o.mit, c.graph, o.m, ident)
else:
noidentError(c.config, n[1], n)
result = errorSym(c, n[1])
@@ -720,7 +751,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym
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).skipAlias(n, c.config)
result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph)
if result != nil:
# oh, we were wrong, some other module had the symbol, so remember that:
o.importIdx = idx
@@ -730,7 +761,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym
proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym =
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).skipAlias(n, c.config)
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
#while result != nil and result.id in o.marked:
# result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx])
if result != nil:
@@ -745,29 +776,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).skipAlias(n, c.config)
result = nextIdentIter(o.it, o.currentScope.symbols)
while result == nil:
o.currentScope = o.currentScope.parent
if o.currentScope != nil:
result = initIdentIter(o.it, o.currentScope.symbols, o.it.name).skipAlias(n, c.config)
result = initIdentIter(o.it, o.currentScope.symbols, o.it.name)
# 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).skipAlias(n, c.config)
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
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).skipAlias(n, c.config)
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph)
if result == nil:
result = nextOverloadIterImports(o, c, n)
else:
result = nil
of oimSelfModule:
result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n, c.config)
result = nextIdentIter(o.it, c.topLevelScope.symbols)
of oimOtherModule:
result = nextModuleIter(o.mit, c.graph).skipAlias(n, c.config)
result = nextModuleIter(o.mit, c.graph)
of oimSymChoice:
if o.symChoiceIndex < n.len:
result = n[o.symChoiceIndex].sym
@@ -778,12 +809,12 @@ 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).skipAlias(n, c.config)
n[0].sym.name, o.marked)
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).skipAlias(n, c.config)
n[0].sym.name, o.marked)
else:
o.importIdx = 0
result = symChoiceExtension(o, c, n)
@@ -792,12 +823,12 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
incl o.marked, result.id
of oimSymChoiceLocalLookup:
if o.currentScope != nil:
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked).skipAlias(n, c.config)
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked)
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).skipAlias(n, c.config)
n[0].sym.name, o.marked)
else:
o.importIdx = 0
result = symChoiceExtension(o, c, n)
@@ -806,10 +837,10 @@ 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).skipAlias(n, c.config)
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph)
#assert result.id notin o.marked
#while result != nil and result.id in o.marked:
# result = nextIdentIter(o.it, c.imports[o.importIdx]).skipAlias(n, c.config)
# result = nextIdentIter(o.it, c.imports[o.importIdx])
if result == nil:
inc o.importIdx
result = symChoiceExtension(o, c, n)

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), nextSymId(idgen),
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), 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), nextSymId(idgen),
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
owner, value.info, g.config.options)
temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flags, sfFromGeneric)
@@ -122,29 +122,10 @@ 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), nextSymId(idgen), owner, n.info, owner.options)
var temp = newSym(skVar, getIdent(g.cache, genPrefix), idgen, owner, n.info, owner.options)
temp.typ = n[1].typ
incl(temp.flags, sfFromGeneric)
incl(temp.flags, sfGenSym)
@@ -171,8 +152,7 @@ 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),
nextSymId(idgen),
owner, info, owner.options)
idgen, owner, info, owner.options)
incl s.flags, sfAnon
s.typ = result
result.sym = s
@@ -234,10 +214,13 @@ 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),
nextSymId(idgen), s.owner, s.info, s.options)
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
@@ -250,7 +233,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), nextSymId(idgen),
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), idgen,
s.owner, s.info, s.options)
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
let t = skipIntLit(s.typ, idgen)
@@ -347,7 +330,8 @@ proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
proc callCodegenProc*(g: ModuleGraph; name: string;
info: TLineInfo = unknownLineInfo;
arg1, arg2, arg3, optionalArgs: PNode = nil): PNode =
arg1: PNode = nil, arg2: PNode = nil,
arg3: PNode = nil, optionalArgs: PNode = nil): PNode =
result = newNodeI(nkCall, info)
let sym = magicsys.getCompilerProc(g, name)
if sym == nil:

View File

@@ -26,9 +26,8 @@ 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), nextSymId(g.idgen), g.systemModule, g.systemModule.info, {})
result = newSym(skError, getIdent(g.cache, name), 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 =
let id = getIdent(g.cache, name)
@@ -39,7 +38,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, nextSymId(g.idgen), g.systemModule, g.systemModule.info, {})
result = newSym(skError, id, 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 =

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, sha1, with, json],
std/[strutils, os, times, tables, with, json],
llstream, ast, lexer, syntaxes, options, msgs,
condsyms,
idents, extccomp,
@@ -29,6 +29,8 @@ 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):
@@ -149,7 +151,7 @@ proc commandCompileToC(graph: ModuleGraph) =
extccomp.callCCompiler(conf)
# for now we do not support writing out a .json file with the build instructions when HCR is on
if not conf.hcrOn:
extccomp.writeJsonBuildInstructions(conf)
extccomp.writeJsonBuildInstructions(conf, graph.cachedFiles)
if optGenScript in graph.config.globalOptions:
writeDepsFile(graph)
if optGenCDeps in graph.config.globalOptions:
@@ -415,7 +417,7 @@ proc mainCommand*(graph: ModuleGraph) =
of cmdJsonscript:
setOutFile(graph.config)
commandJsonScript(graph)
of cmdUnknown, cmdNone, cmdIdeTools, cmdNimfix:
of cmdUnknown, cmdNone, cmdIdeTools:
rawMessage(conf, errGenerated, "invalid command: " & conf.command)
if conf.errorCounter == 0 and conf.cmd notin {cmdTcc, cmdDump, cmdNop}:

View File

@@ -11,7 +11,8 @@
## represents a complete Nim project. Single modules can either be kept in RAM
## or stored in a rod-file.
import intsets, tables, hashes, md5
import std/[intsets, tables, hashes, strtabs]
import ../dist/checksums/src/checksums/md5
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
import ic / [packed_ast, ic]
@@ -56,6 +57,7 @@ type
SymInfoPair* = object
sym*: PSym
info*: TLineInfo
isDecl*: bool
PipelinePass* = enum
NonePass
@@ -78,6 +80,7 @@ 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]
@@ -126,6 +129,8 @@ type
idgen*: IdGenerator
operators*: Operators
cachedFiles*: StringTableRef
TPassContext* = object of RootObj # the pass's context
idgen*: IdGenerator
PPassContext* = ref TPassContext
@@ -411,7 +416,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), nextSymId(idgen), nil, unknownLineInfo, {})
result = newSym(skProc, getIdent(g.cache, name), idgen, nil, unknownLineInfo, {})
result.magic = m
result.flags = {sfNeverRaises}
@@ -477,6 +482,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.symBodyHashes = initTable[int, SigHash]()
result.operators = initOperators(result)
result.emittedTypeInfo = initTable[string, FileIndex]()
result.cachedFiles = newStringTable()
proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result = ModuleGraph()

View File

@@ -36,11 +36,18 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
localError(n.info, "only '/' supported with $package notation")
result = ""
else:
let modname = getModuleName(conf, n[2])
# hacky way to implement 'x / y /../ z':
result = getModuleName(conf, n1)
result.add renderTree(n0, {renderNoComments}).replace(" ")
result.add modname
if n0.kind in nkIdentKinds:
let ident = n0.getPIdent
if ident != nil and ident.s[0] == '/':
let modname = getModuleName(conf, n[2])
# hacky way to implement 'x / y /../ z':
result = getModuleName(conf, n1)
result.add renderTree(n0, {renderNoComments}).replace(" ")
result.add modname
else:
result = ""
else:
result = ""
of nkPrefix:
when false:
if n[0].kind == nkIdent and n[0].ident.s == "$":

View File

@@ -14,6 +14,9 @@ import
idents, lexer, syntaxes, modulegraphs,
lineinfos, pathutils
import ../dist/checksums/src/checksums/sha1
import std/strtabs
proc resetSystemArtifacts*(g: ModuleGraph) =
magicsys.resetSysTypes(g)
@@ -42,6 +45,8 @@ proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode =
result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
graph.addDep(s, fileIdx)
graph.addIncludeDep(s.position.FileIndex, fileIdx)
let path = toFullPath(graph.config, fileIdx)
graph.cachedFiles[path] = $secureHashFile(path)
proc wantMainModule*(conf: ConfigRef) =
if conf.projectFull.isEmpty:

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):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
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):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result = conf.m.fileInfos[fileIdx.int32].hash
else:
shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash)
@@ -429,7 +429,8 @@ To create a stacktrace, rerun compilation with './koch temp $1 <file>', see $2 f
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string, ignoreMsg: bool) =
if msg in fatalMsgs:
if conf.cmd == cmdIdeTools: log(s)
quit(conf, msg)
if conf.cmd != cmdIdeTools or msg != errFatal:
quit(conf, msg)
if msg >= errMin and msg <= errMax or
(msg in warnMin..hintMax and msg in conf.warningAsErrors and not ignoreMsg):
inc(conf.errorCounter)
@@ -437,7 +438,11 @@ proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string,
if conf.errorCounter >= conf.errorMax:
# only really quit when we're not in the new 'nim check --def' mode:
if conf.ideCmd == ideNone:
quit(conf, msg)
when defined(nimsuggest):
#we need to inform the user that something went wrong when initializing NimSuggest
raiseRecoverableError(s)
else:
quit(conf, msg)
elif eh == doAbort and conf.cmd != cmdIdeTools:
quit(conf, msg)
elif eh == doRaise:
@@ -511,7 +516,8 @@ 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) {.gcsafe, noinline.} =
eh: TErrorHandling, info2: InstantiationInfo, isRaw = false,
ignoreError = false) {.gcsafe, noinline.} =
var
title: string
color: ForegroundColor
@@ -552,9 +558,10 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
ignoreMsg = not conf.hasHint(msg)
if not ignoreMsg and msg in conf.warningAsErrors:
title = ErrorTitle
color = ErrorColor
else:
title = HintTitle
color = HintColor
color = HintColor
inc(conf.hintCounter)
let s = if isRaw: arg else: getMessageStr(msg, arg)
@@ -576,7 +583,8 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
" compiler msg initiated here", KindColor,
KindFormat % $hintMsgOrigin,
resetStyle, conf.unitSep)
handleError(conf, msg, eh, s, ignoreMsg)
if not ignoreError:
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
@@ -641,13 +649,16 @@ template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, extraM
let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName
liMessage(conf, info, msg, m, doNothing, instLoc())
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
if i.fileIndex.int32 < 0:
proc quotedFilename*(conf: ConfigRef; fi: FileIndex): Rope =
if fi.int32 < 0:
result = makeCString "???"
elif optExcessiveStackTrace in conf.globalOptions:
result = conf.m.fileInfos[i.fileIndex.int32].quotedFullName
result = conf.m.fileInfos[fi.int32].quotedFullName
else:
result = conf.m.fileInfos[i.fileIndex.int32].quotedName
result = conf.m.fileInfos[fi.int32].quotedName
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
quotedFilename(conf, i.fileIndex)
template listMsg(title, r) =
msgWriteln(conf, title, {msgNoUnitSep})

View File

@@ -909,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), nextSymId ctx.idgen, nil, r.info)
var op = newSym(skVar, cache.getIdent(name), ctx.idgen, nil, r.info)
op.magic = magic
result = nkInfix.newTree(
@@ -920,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"), nextSymId ctx.idgen, nil, node.info)
var op = newSym(skVar, cache.getIdent("not"), ctx.idgen, nil, node.info)
op.magic = mNot
result = nkPrefix.newTree(

View File

@@ -7,6 +7,7 @@ define:nimcore
define:nimPreviewFloatRoundtrip
define:nimPreviewSlimSystem
define:nimPreviewCstringConversion
define:nimPreviewProcConversion
define:nimPreviewRangeDefault
threads:off
@@ -14,7 +15,6 @@ threads:off
@if windows:
cincludes: "$lib/wrappers/libffi/common"
tlsEmulation:off
@end
define:useStdoutAsStdmsg
@@ -31,9 +31,6 @@ define:useStdoutAsStdmsg
warning[ObservableStores]:off
@end
@if nimHasWarnCastSizes:
warning[CastSizes]:on
@end
@if nimHasWarningAsError:
warningAsError[GcUnsafe2]:on

View File

@@ -12,10 +12,7 @@ import std/[os, strutils, parseopt]
when defined(nimPreviewSlimSystem):
import std/assertions
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(windows):
when defined(gcc):
when defined(x86):
{.link: "../icons/nim.res".}

View File

@@ -10,11 +10,13 @@
## Implements some helper procs for Nimble (Nim's package manager) support.
import parseutils, strutils, os, options, msgs, sequtils, lineinfos, pathutils,
std/sha1, tables
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)

View File

@@ -12,7 +12,7 @@ import
ast, modules, condsyms,
options, llstream, lineinfos, vm,
vmdef, modulegraphs, idents, os, pathutils,
scriptconfig, std/compilesettings
scriptconfig, std/[compilesettings, tables]
import pipelines
@@ -78,6 +78,9 @@ 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

View File

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

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

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

@@ -12,6 +12,8 @@
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 s.magic == mWasMoved or name == "=wasmoved":
if name == "=wasmoved":
b.wasMovedLocs.add n
special = true
elif name == "=destroy":

View File

@@ -49,6 +49,7 @@ type # please make sure we have under 32 options
optSinkInference # 'sink T' inference
optCursorInference
optImportHidden
optQuirky
TOptions* = set[TOption]
TGlobalOption* = enum
@@ -102,13 +103,11 @@ type # please make sure we have under 32 options
optBenchmarkVM # Enables cpuTime() in the VM
optProduceAsm # produce assembler code
optPanics # turn panics (sysFatal) into a process termination
optNimV1Emulation # emulate Nim v1.0
optNimV12Emulation # emulate Nim v1.2
optNimV16Emulation # emulate Nim v1.6
optSourcemap
optProfileVM # enable VM profiler
optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types.
optShowNonExportedFields # for documentation: show fields that are not exported
optJsBigInt64 # use bigints for 64-bit integers in JS
TGlobalOptions* = set[TGlobalOption]
@@ -168,7 +167,6 @@ type
cmdInteractive # start interactive session
cmdNop
cmdJsonscript # compile a .json build file
cmdNimfix
# old unused: cmdInterpret, cmdDef: def feature (find definition for IDEs)
const
@@ -186,6 +184,7 @@ type
gcRegions = "regions"
gcArc = "arc"
gcOrc = "orc"
gcAtomicArc = "atomicArc"
gcMarkAndSweep = "markAndSweep"
gcHooks = "hooks"
gcRefc = "refc"
@@ -196,7 +195,7 @@ type
IdeCmd* = enum
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod,
ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols,
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand, ideInlayHints
Feature* = enum ## experimental features; DO NOT RENAME THESE!
dotOperators,
@@ -221,7 +220,8 @@ type
unicodeOperators, # deadcode
flexibleOptionalParams,
strictDefs,
strictCaseObjects
strictCaseObjects,
genericsOpenSym
LegacyFeature* = enum
allowSemcheckedAstModification,
@@ -281,9 +281,24 @@ type
version*: int
endLine*: uint16
endCol*: int
inlayHintInfo*: SuggestInlayHint
Suggestions* = seq[Suggest]
SuggestInlayHintKind* = enum
sihkType = "Type",
sihkParameter = "Parameter"
SuggestInlayHint* = ref object
kind*: SuggestInlayHintKind
line*: int # Starts at 1
column*: int # Starts at 0
label*: string
paddingLeft*: bool
paddingRight*: bool
allowInsert*: bool
tooltip*: string
ProfileInfo* = object
time*: float
count*: int
@@ -335,6 +350,7 @@ type
cppDefines*: HashSet[string] # (*)
headerFile*: string
nimbasePattern*: string # pattern to find nimbase.h
features*: set[Feature]
legacyFeatures*: set[LegacyFeature]
arguments*: string ## the arguments to be passed to the program that
@@ -417,6 +433,9 @@ type
expandNodeResult*: string
expandPosition*: TLineInfo
clientProcessId*: int
proc parseNimVersion*(a: string): NimVer =
# could be moved somewhere reusable
if a.len > 0:
@@ -479,7 +498,8 @@ const
optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck,
optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs`
optTrMacros, optStyleCheck, optCursorInference}
DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace}
DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace,
optJsBigInt64}
proc getSrcTimestamp(): DateTime =
try:
@@ -866,14 +886,6 @@ template patchModule(conf: ConfigRef) {.dirty.} =
let ov = conf.moduleOverrides[key]
if ov.len > 0: result = AbsoluteFile(ov)
when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo):
proc isRelativeTo(path, base: string): bool =
# pending #13212 use os.isRelativeTo
let path = path.normalizedPath
let base = base.normalizedPath
let ret = relativePath(path, base)
result = path.len > 0 and not ret.startsWith ".."
const stdlibDirs* = [
"pure", "core", "arch",
"pure/collections",
@@ -918,6 +930,7 @@ proc findFile*(conf: ConfigRef; f: string; suppressStdlib = false): AbsoluteFile
proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFile =
# returns path to module
var m = addFileExt(modulename, NimExt)
var hasRelativeDot = false
if m.startsWith(pkgPrefix):
result = findFile(conf, m.substr(pkgPrefix.len), suppressStdlib = true)
else:
@@ -931,7 +944,11 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFi
else: # If prefixed with std/ why would we add the current module path!
let currentPath = currentModule.splitFile.dir
result = AbsoluteFile currentPath / m
if not fileExists(result):
if m.startsWith('.') and not fileExists(result):
result = AbsoluteFile ""
hasRelativeDot = true
if not fileExists(result) and not hasRelativeDot:
result = findFile(conf, m)
patchModule(conf)
@@ -1058,6 +1075,7 @@ proc `$`*(c: IdeCmd): string =
of ideRecompile: "recompile"
of ideChanged: "changed"
of ideType: "type"
of ideInlayHints: "inlayHints"
proc floatInt64Align*(conf: ConfigRef): int16 =
## Returns either 4 or 8 depending on reasons.

View File

@@ -8,7 +8,7 @@
#
## Package related procs.
##
##
## See Also:
## * `packagehandling` for package path handling
## * `modulegraphs.getPackage`
@@ -22,7 +22,7 @@ when defined(nimPreviewSlimSystem):
proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym =
## Return a new package symbol.
##
##
## See Also:
## * `modulegraphs.getPackage`
let
@@ -31,7 +31,7 @@ proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym =
info = newLineInfo(fileIdx, 1, 1)
pkgName = getPackageName(conf, filename.string)
pkgIdent = getIdent(cache, pkgName)
newSym(skPackage, pkgIdent, ItemId(module: PackageModuleId, item: int32(fileIdx)), nil, info)
newSym(skPackage, pkgIdent, idGeneratorForPackage(int32(fileIdx)), nil, info)
func getPackageSymbol*(sym: PSym): PSym =
## Return the owning package symbol.
@@ -47,7 +47,7 @@ func getPackageId*(sym: PSym): int =
func belongsToProjectPackage*(conf: ConfigRef, sym: PSym): bool =
## Return whether the symbol belongs to the project's package.
##
##
## See Also:
## * `modulegraphs.belongsToStdlib`
conf.mainPackageId == sym.getPackageId

View File

@@ -301,17 +301,16 @@ proc isRightAssociative(tok: Token): bool {.inline.} =
proc isUnary(tok: Token): bool =
## Check if the given token is a unary operator
tok.tokType in {tkOpr, tkDotDot} and
tok.strongSpaceB == tsNone and
tok.strongSpaceA
tok.spacing == {tsLeading}
proc checkBinary(p: Parser) {.inline.} =
## Check if the current parser token is a binary operator.
# we don't check '..' here as that's too annoying
if p.tok.tokType == tkOpr:
if p.tok.strongSpaceB == tsTrailing and not p.tok.strongSpaceA:
if p.tok.spacing == {tsTrailing}:
parMessage(p, warnInconsistentSpacing, prettyTok(p.tok))
#| module = stmt ^* (';' / IND{=})
#| module = complexOrSimpleStmt ^* (';' / IND{=})
#|
#| comma = ',' COMMENT?
#| semicolon = ';' COMMENT?
@@ -321,7 +320,7 @@ proc checkBinary(p: Parser) {.inline.} =
#| operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9
#| | 'or' | 'xor' | 'and'
#| | 'is' | 'isnot' | 'in' | 'notin' | 'of' | 'as' | 'from'
#| | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..'
#| | 'div' | 'mod' | 'shl' | 'shr' | 'not' | '..'
#|
#| prefixOperator = operator
#|
@@ -362,7 +361,8 @@ template setEndInfo() =
proc parseSymbol(p: var Parser, mode = smNormal): PNode =
#| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
#| | IDENT | KEYW
#| | IDENT | 'addr' | 'type' | 'static'
#| symbolOrKeyword = symbol | KEYW
case p.tok.tokType
of tkSymbol:
result = newIdentNodeP(p.tok.ident, p)
@@ -436,7 +436,8 @@ proc colonOrEquals(p: var Parser, a: PNode): PNode =
result = equals(p, a)
proc exprColonEqExpr(p: var Parser): PNode =
#| exprColonEqExpr = expr (':'|'=' expr)?
#| exprColonEqExpr = expr ((':'|'=') expr
#| / doBlock extraPostExprBlock*)?
var a = parseExpr(p)
if p.tok.tokType == tkDo:
result = postExprBlocks(p, a)
@@ -444,7 +445,8 @@ proc exprColonEqExpr(p: var Parser): PNode =
result = colonOrEquals(p, a)
proc exprEqExpr(p: var Parser): PNode =
#| exprEqExpr = expr ('=' expr)?
#| exprEqExpr = expr ('=' expr
#| / doBlock extraPostExprBlock*)?
var a = parseExpr(p)
if p.tok.tokType == tkDo:
result = postExprBlocks(p, a)
@@ -515,7 +517,7 @@ proc dotExpr(p: var Parser, a: PNode): PNode =
optInd(p, result)
result.add(a)
result.add(parseSymbol(p, smAfterDot))
if p.tok.tokType == tkBracketLeColon and not p.tok.strongSpaceA:
if p.tok.tokType == tkBracketLeColon and tsLeading notin p.tok.spacing:
var x = newNodeI(nkBracketExpr, p.parLineInfo)
# rewrite 'x.y[:z]()' to 'y[z](x)'
x.add result[1]
@@ -524,7 +526,7 @@ proc dotExpr(p: var Parser, a: PNode): PNode =
var y = newNodeI(nkCall, p.parLineInfo)
y.add x
y.add result[0]
if p.tok.tokType == tkParLe and not p.tok.strongSpaceA:
if p.tok.tokType == tkParLe and tsLeading notin p.tok.spacing:
exprColonEqExprListAux(p, tkParRi, y)
result = y
@@ -539,7 +541,7 @@ proc dotLikeExpr(p: var Parser, a: PNode): PNode =
result.add(parseSymbol(p, smAfterDot))
proc qualifiedIdent(p: var Parser): PNode =
#| qualifiedIdent = symbol ('.' optInd symbol)?
#| qualifiedIdent = symbol ('.' optInd symbolOrKeyword)?
result = parseSymbol(p)
if p.tok.tokType == tkDot: result = dotExpr(p, result)
@@ -647,7 +649,8 @@ proc parsePar(p: var Parser): PNode =
#| ( &parKeyw (ifExpr / complexOrSimpleStmt) ^+ ';'
#| | ';' (ifExpr / complexOrSimpleStmt) ^+ ';'
#| | pragmaStmt
#| | simpleExpr ( ('=' expr (';' (ifExpr / complexOrSimpleStmt) ^+ ';' )? )
#| | simpleExpr ( (doBlock extraPostExprBlock*)
#| | ('=' expr (';' (ifExpr / complexOrSimpleStmt) ^+ ';' )? )
#| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) )
#| optPar ')'
#
@@ -869,8 +872,8 @@ proc isDotLike(tok: Token): bool =
proc primarySuffix(p: var Parser, r: PNode,
baseIndent: int, mode: PrimaryMode): PNode =
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')'
#| | '.' optInd symbol ('[:' exprList ']' ( '(' exprColonEqExpr ')' )?)? generalizedLit?
#| | DOTLIKEOP optInd symbol generalizedLit?
#| | '.' optInd symbolOrKeyword ('[:' exprList ']' ( '(' exprColonEqExpr ')' )?)? generalizedLit?
#| | DOTLIKEOP optInd symbolOrKeyword generalizedLit?
#| | '[' optInd exprColonEqExprList optPar ']'
#| | '{' optInd exprColonEqExprList optPar '}'
# XXX strong spaces need to be reflected above
@@ -882,7 +885,7 @@ proc primarySuffix(p: var Parser, r: PNode,
case p.tok.tokType
of tkParLe:
# progress guaranteed
if p.tok.strongSpaceA:
if tsLeading in p.tok.spacing:
result = commandExpr(p, result, mode)
break
result = namedParams(p, result, nkCall, tkParRi)
@@ -894,13 +897,13 @@ proc primarySuffix(p: var Parser, r: PNode,
result = parseGStrLit(p, result)
of tkBracketLe:
# progress guaranteed
if p.tok.strongSpaceA:
if tsLeading in p.tok.spacing:
result = commandExpr(p, result, mode)
break
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
of tkCurlyLe:
# progress guaranteed
if p.tok.strongSpaceA:
if tsLeading in p.tok.spacing:
result = commandExpr(p, result, mode)
break
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
@@ -1005,7 +1008,7 @@ proc parsePragma(p: var Parser): PNode =
proc identVis(p: var Parser; allowDot=false): PNode =
#| identVis = symbol OPR? # postfix position
#| identVisDot = symbol '.' optInd symbol OPR?
#| identVisDot = symbol '.' optInd symbolOrKeyword OPR?
var a = parseSymbol(p)
if p.tok.tokType == tkOpr:
when defined(nimpretty):
@@ -1197,14 +1200,18 @@ proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode =
let pragmas = optPragmas(p)
if p.tok.tokType == tkEquals and isExpr:
getTok(p)
skipComment(p, result)
result = newProcNode(kind, info, body = parseStmt(p),
result = newProcNode(kind, info, body = p.emptyNode,
params = params, name = p.emptyNode, pattern = p.emptyNode,
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
skipComment(p, result)
result[bodyPos] = parseStmt(p)
else:
result = newNodeI(if kind == nkIteratorDef: nkIteratorTy else: nkProcTy, info)
if hasSignature:
result.add(params)
if hasSignature or pragmas.kind != nkEmpty:
if hasSignature:
result.add(params)
else: # pragmas but no param list, implies typeclass with pragmas
result.add(p.emptyNode)
if kind == nkFuncDef:
parMessage(p, "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead")
result.add(pragmas)
@@ -1332,7 +1339,7 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode =
#| simplePrimary = SIGILLIKEOP? identOrLiteral primarySuffix*
#| commandStart = &('`'|IDENT|literal|'cast'|'addr'|'type'|'var'|'out'|
#| 'static'|'enum'|'tuple'|'object'|'proc')
#| primary = simplePrimary (commandStart expr)
#| primary = simplePrimary (commandStart expr (doBlock extraPostExprBlock*)?)?
#| / operatorB primary
#| / routineExpr
#| / rawTypeDesc
@@ -1389,7 +1396,7 @@ proc binaryNot(p: var Parser; a: PNode): PNode =
let notOpr = newIdentNodeP(p.tok.ident, p)
getTok(p)
optInd(p, notOpr)
let b = parseExpr(p)
let b = primary(p, pmTypeDesc)
result = newNodeP(nkInfix, p)
result.add notOpr
result.add a
@@ -1400,8 +1407,8 @@ proc binaryNot(p: var Parser; a: PNode): PNode =
proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
#| rawTypeDesc = (tupleType | routineType | 'enum' | 'object' |
#| ('var' | 'out' | 'ref' | 'ptr' | 'distinct') typeDesc?)
#| ('not' expr)?
#| typeDescExpr = (routineType / simpleExpr) ('not' expr)?
#| ('not' primary)?
#| typeDescExpr = (routineType / simpleExpr) ('not' primary)?
#| typeDesc = rawTypeDesc / typeDescExpr
newlineWasSplitting(p)
if fullExpr:
@@ -1423,6 +1430,7 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
result = newNodeP(nkObjectTy, p)
getTok(p)
of tkConcept:
result = p.emptyNode
parMessage(p, "the 'concept' keyword is only valid in 'type' sections")
of tkVar: result = parseTypeDescKAux(p, nkVarTy, pmTypeDesc)
of tkOut: result = parseTypeDescKAux(p, nkOutTy, pmTypeDesc)
@@ -1437,8 +1445,8 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
proc parseTypeDefValue(p: var Parser): PNode =
#| typeDefValue = ((tupleDecl | enumDecl | objectDecl | conceptDecl |
#| ('ref' | 'ptr' | 'distinct') (tupleDecl | objectDecl))
#| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks)?))
#| ('not' expr)?
#| / (simpleExpr (exprEqExpr ^+ comma postExprBlocks?)?))
#| ('not' primary)?
case p.tok.tokType
of tkTuple: result = parseTuple(p, true)
of tkRef: result = parseTypeDescKAux(p, nkRefTy, pmTypeDef)
@@ -1474,12 +1482,13 @@ proc makeCall(n: PNode): PNode =
result.add n
proc postExprBlocks(p: var Parser, x: PNode): PNode =
#| postExprBlocks = ':' stmt? ( IND{=} doBlock
#| | IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' optionalExprList ':' stmt
#| | IND{=} 'finally' ':' stmt
#| | IND{=} 'else' ':' stmt )*
#| extraPostExprBlock = ( IND{=} doBlock
#| | IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' optionalExprList ':' stmt
#| | IND{=} 'finally' ':' stmt
#| | IND{=} 'else' ':' stmt )
#| postExprBlocks = (doBlock / ':' (extraPostExprBlock / stmt)) extraPostExprBlock*
result = x
if p.tok.indent >= 0: return
@@ -1496,7 +1505,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
result = makeCall(result)
getTok(p)
skipComment(p, result)
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept, tkFinally}:
if not (p.tok.tokType in {tkOf, tkElif, tkElse, tkExcept, tkFinally} and sameInd(p)):
var stmtList = newNodeP(nkStmtList, p)
stmtList.add parseStmt(p)
# to keep backwards compatibility (see tests/vm/tstringnil)
@@ -1713,9 +1722,9 @@ proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode =
setEndInfo()
proc parseIfOrWhenExpr(p: var Parser, kind: TNodeKind): PNode =
#| condExpr = expr colcom expr optInd
#| ('elif' expr colcom expr optInd)*
#| 'else' colcom expr
#| condExpr = expr colcom stmt optInd
#| ('elif' expr colcom stmt optInd)*
#| 'else' colcom stmt
#| ifExpr = 'if' condExpr
#| whenExpr = 'when' condExpr
result = newNodeP(kind, p)
@@ -2277,20 +2286,31 @@ proc parseTypeDef(p: var Parser): PNode =
setEndInfo()
proc parseVarTuple(p: var Parser): PNode =
#| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
#| varTupleLhs = '(' optInd (identWithPragma / varTupleLhs) ^+ comma optPar ')' (':' optInd typeDescExpr)?
#| varTuple = varTupleLhs '=' optInd expr
result = newNodeP(nkVarTuple, p)
getTok(p) # skip '('
optInd(p, result)
# progress guaranteed
while p.tok.tokType in {tkSymbol, tkAccent}:
var a = identWithPragma(p, allowDot=true)
while p.tok.tokType in {tkSymbol, tkAccent, tkParLe}:
var a: PNode
if p.tok.tokType == tkParLe:
a = parseVarTuple(p)
a.add(p.emptyNode)
else:
a = identWithPragma(p, allowDot=true)
result.add(a)
if p.tok.tokType != tkComma: break
getTok(p)
skipComment(p, a)
result.add(p.emptyNode) # no type desc
optPar(p)
eat(p, tkParRi)
if p.tok.tokType == tkColon:
getTok(p)
optInd(p, result)
result.add(parseTypeDesc(p, fullExpr = true))
else:
result.add(p.emptyNode) # no type desc
setEndInfo()
proc parseVariable(p: var Parser): PNode =
@@ -2497,24 +2517,8 @@ proc parseStmt(p: var Parser): PNode =
if err and p.tok.tokType == tkEof: break
setEndInfo()
proc parseAll(p: var Parser): PNode =
## Parses the rest of the input stream held by the parser into a PNode.
result = newNodeP(nkStmtList, p)
while p.tok.tokType != tkEof:
p.hasProgress = false
var a = complexOrSimpleStmt(p)
if a.kind != nkEmpty and p.hasProgress:
result.add(a)
else:
parMessage(p, errExprExpected, p.tok)
# bugfix: consume a token here to prevent an endless loop:
getTok(p)
if p.tok.indent != 0:
parMessage(p, errInvalidIndentation)
setEndInfo()
proc checkFirstLineIndentation*(p: var Parser) =
if p.tok.indent != 0 and p.tok.strongSpaceA:
if p.tok.indent != 0 and tsLeading in p.tok.spacing:
parMessage(p, errInvalidIndentation)
proc parseTopLevelStmt(p: var Parser): PNode =
@@ -2547,6 +2551,16 @@ proc parseTopLevelStmt(p: var Parser): PNode =
break
setEndInfo()
proc parseAll*(p: var Parser): PNode =
## Parses the rest of the input stream held by the parser into a PNode.
result = newNodeP(nkStmtList, p)
while true:
let nextStmt = p.parseTopLevelStmt()
if nextStmt.kind == nkEmpty:
break
result &= nextStmt
setEndInfo()
proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
filename: string = ""; line: int = 0;
errorHandler: ErrorHandler = nil): PNode =

View File

@@ -24,7 +24,7 @@ import ic/replayer
export skipCodegen, resolveMod, prepareConfigNotes
when defined(nimsuggest):
import std/sha1
import ../dist/checksums/src/checksums/sha1
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]

View File

@@ -1,13 +1,16 @@
import sem, cgen, modulegraphs, ast, llstream, parser, msgs,
lineinfos, reorder, options, semdata, cgendata, modules, pathutils,
packages, syntaxes, depends, vm, pragmas, idents, lookups
packages, syntaxes, depends, vm, pragmas, idents, lookups, wordrecg,
liftdestructors
import pipelineutils
import ../dist/checksums/src/checksums/sha1
when not defined(leanCompiler):
import jsgen, docgen2
import std/[syncio, objectdollar, assertions, tables, strutils]
import std/[syncio, objectdollar, assertions, tables, strutils, strtabs]
import renderer
import ic/replayer
@@ -176,7 +179,16 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
case graph.pipelinePass
of CgenPass:
if bModule != nil:
finalCodegenActions(graph, BModule(bModule), finalNode)
let disps = finalCodegenActions(graph, BModule(bModule), finalNode)
if disps != nil:
let ctx = preparePContext(graph, module, idgen)
for disp in disps:
let retTyp = disp.sym.typ[0]
if retTyp != nil:
# todo properly semcheck the code of dispatcher?
createTypeBoundOps(graph, ctx, retTyp, disp.info, idgen)
genProcAux(BModule(bModule), disp.sym)
discard closePContext(graph, ctx, nil)
of JSgenPass:
when not defined(leanCompiler):
discard finalJSCodeGen(graph, bModule, finalNode)
@@ -215,7 +227,10 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
if result == nil:
var cachedModules: seq[FileIndex]
result = moduleFromRodFile(graph, fileIdx, cachedModules)
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
let path = toFullPath(graph.config, fileIdx)
let filename = AbsoluteFile path
if fileExists(filename): # it could be a stdinfile
graph.cachedFiles[path] = $secureHashFile(path)
if result == nil:
result = newModule(graph, fileIdx)
result.flags.incl flags

View File

@@ -31,7 +31,7 @@ proc iterToProcImpl*(c: PContext, n: PNode): PNode =
return
let body = liftIterToProc(c.graph, iter.sym, getBody(c.graph, iter.sym), t, c.idgen)
let prc = newSym(skProc, n[3].ident, nextSymId c.idgen, iter.sym.owner, iter.sym.info)
let prc = newSym(skProc, n[3].ident, c.idgen, iter.sym.owner, iter.sym.info)
prc.typ = copyType(iter.sym.typ, nextTypeId c.idgen, prc)
excl prc.typ.flags, tfCapturesEnv
prc.typ.n.add newSymNode(getEnvParam(iter.sym))

View File

@@ -26,7 +26,7 @@ proc semLocals*(c: PContext, n: PNode): PNode =
{tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyUntyped, tyTyped, tyEmpty}:
if it.owner == owner:
var field = newSym(skField, it.name, nextSymId c.idgen, owner, n.info)
var field = newSym(skField, it.name, c.idgen, owner, n.info)
field.typ = it.typ.skipTypes({tyVar})
field.position = counter
inc(counter)

View File

@@ -12,7 +12,7 @@
import
os, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees,
types, lookups, lineinfos, pathutils, linter
types, lookups, lineinfos, pathutils, linter, modulepaths
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -34,7 +34,7 @@ const
wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl,
wGensym, wInject, wRaises, wEffectsOf, wTags, wForbids, wLocks, wDelegator, wGcSafe,
wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy,
wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect}
wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect, wVirtual, wQuirky}
converterPragmas* = procPragmas
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
@@ -71,7 +71,8 @@ const
wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
wIncompleteStruct, wCompleteStruct, wByCopy, wByRef,
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
wCppNonPod, wBorrow, wGcSafe, wPartial, wExplain, wPackage}
wCppNonPod, wBorrow, wGcSafe, wPartial, wExplain, wPackage, wCodegenDecl,
wSendable}
fieldPragmas* = declPragmas + {wGuard, wBitsize, wCursor,
wRequiresInit, wNoalias, wAlign} - {wExportNims, wNodecl} # why exclude these?
varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
@@ -83,7 +84,7 @@ const
wGensym, wInject,
wIntDefine, wStrDefine, wBoolDefine, wDefine,
wCompilerProc, wCore}
paramPragmas* = {wNoalias, wInject, wGensym}
paramPragmas* = {wNoalias, wInject, wGensym, wByRef, wByCopy, wCodegenDecl}
letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect,
wThread, wRaises, wEffectsOf, wLocks, wTags, wForbids, wGcSafe,
@@ -116,7 +117,15 @@ const
proc invalidPragma*(c: PContext; n: PNode) =
localError(c.config, n.info, "invalid pragma: " & renderTree(n, {renderNoComments}))
proc illegalCustomPragma*(c: PContext, n: PNode, s: PSym) =
localError(c.config, n.info, "cannot attach a custom pragma to '" & s.name.s & "'")
var msg = "cannot attach a custom pragma to '" & s.name.s & "'"
if s != nil:
msg.add("; custom pragmas are not supported for ")
case s.kind
of skForVar: msg.add("`for` loop variables")
of skEnumField: msg.add("enum fields")
of skModule: msg.add("modules")
else: msg.add("symbol kind " & $s.kind)
localError(c.config, n.info, msg)
proc pragmaProposition(c: PContext, n: PNode) =
if n.kind notin nkPragmaCallKinds or n.len != 2:
@@ -131,7 +140,7 @@ proc pragmaEnsures(c: PContext, n: PNode) =
openScope(c)
let o = getCurrOwner(c)
if o.kind in routineKinds and o.typ != nil and o.typ.sons[0] != nil:
var s = newSym(skResult, getIdent(c.cache, "result"), nextSymId(c.idgen), o, n.info)
var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen, o, n.info)
s.typ = o.typ.sons[0]
incl(s.flags, sfUsed)
addDecl(c, s)
@@ -165,9 +174,7 @@ proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
when hasFFI:
s.cname = $s.loc.r
if c.config.cmd == cmdNimfix and '$' notin extname:
# note that '{.importc.}' is transformed into '{.importc: "$1".}'
s.loc.flags.incl(lfFullExternalName)
proc makeExternImport(c: PContext; s: PSym, extname: string, info: TLineInfo) =
setExternName(c, s, extname, info)
@@ -202,9 +209,9 @@ proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) =
let m = s.getModule()
incl(m.flags, sfCompileToObjc)
proc newEmptyStrNode(c: PContext; n: PNode): PNode {.noinline.} =
proc newEmptyStrNode(c: PContext; n: PNode, strVal: string = ""): PNode {.noinline.} =
result = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
result.strVal = ""
result.strVal = strVal
proc getStrLitNode(c: PContext, n: PNode): PNode =
if n.kind notin nkPragmaCallKinds or n.len != 2:
@@ -236,8 +243,17 @@ proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
if n.kind in nkPragmaCallKinds: result = expectStrLit(c, n)
else: result = defaultStr
proc processVirtual(c: PContext, n: PNode, s: PSym) =
s.constraint = newEmptyStrNode(c, n, getOptionalStr(c, n, "$1"))
s.constraint.strVal = s.constraint.strVal % s.name.s
s.flags.incl {sfVirtual, sfInfixCall, sfExportc, sfMangleCpp}
s.typ.callConv = ccNoConvention
incl c.config.globalOptions, optMixedMode
proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
sym.constraint = getStrLitNode(c, n)
sym.flags.incl sfCodegenDecl
proc processMagic(c: PContext, n: PNode, s: PSym) =
#if sfSystemModule notin c.module.flags:
@@ -302,7 +318,7 @@ proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
result.path = path
c.libs.add result
if path.kind in {nkStrLit..nkTripleStrLit}:
result.isOverriden = options.isDynlibOverride(c.config, path.strVal)
result.isOverridden = options.isDynlibOverride(c.config, path.strVal)
proc expectDynlibNode(c: PContext, n: PNode): PNode =
if n.kind notin nkPragmaCallKinds or n.len != 2:
@@ -314,7 +330,7 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
# {.dynlib: myGetProcAddr(...).}
result = c.semExpr(c, n[1])
if result.kind == nkSym and result.sym.kind == skConst:
result = result.sym.astdef # look it up
result = c.semConstExpr(c, result) # fold const
if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
localError(c.config, n.info, errStringLiteralExpected)
result = newEmptyStrNode(c, n)
@@ -322,12 +338,12 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
if (sym == nil) or (sym.kind == skModule):
let lib = getLib(c, libDynamic, expectDynlibNode(c, n))
if not lib.isOverriden:
if not lib.isOverridden:
c.optionStack[^1].dynlib = lib
else:
if n.kind in nkPragmaCallKinds:
var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
if not lib.isOverriden:
if not lib.isOverridden:
addToLib(lib, sym)
incl(sym.loc.flags, lfDynamicLib)
else:
@@ -390,6 +406,7 @@ proc pragmaToOptions*(w: TSpecialWord): TOptions {.inline.} =
of wImplicitStatic: {optImplicitStatic}
of wPatterns, wTrMacros: {optTrMacros}
of wSinkInference: {optSinkInference}
of wQuirky: {optQuirky}
else: {}
proc processExperimental(c: PContext; n: PNode) =
@@ -451,6 +468,18 @@ proc processOption(c: PContext, n: PNode, resOptions: var TOptions) =
# calling conventions (boring...):
localError(c.config, n.info, "option expected")
proc checkPushedPragma(c: PContext, n: PNode) =
let keyDeep = n.kind in nkPragmaCallKinds and n.len > 1
var key = if keyDeep: n[0] else: n
if key.kind in nkIdentKinds:
let ident = considerQuotedIdent(c, key)
var userPragma = strTableGet(c.userPragmas, ident)
if userPragma == nil:
let k = whichKeyword(ident)
# TODO: might as well make a list which is not accepted by `push`: emit, cast etc.
if k == wEmit:
localError(c.config, n.info, "an 'emit' pragma cannot be pushed")
proc processPush(c: PContext, n: PNode, start: int) =
if n[start-1].kind in nkPragmaCallKinds:
localError(c.config, n.info, "'push' cannot have arguments")
@@ -458,6 +487,7 @@ proc processPush(c: PContext, n: PNode, start: int) =
for i in start..<n.len:
if not tryProcessOption(c, n[i], c.config.options):
# simply store it somewhere:
checkPushedPragma(c, n[i])
if x.otherPragmas.isNil:
x.otherPragmas = newNodeI(nkPragma, n.info)
x.otherPragmas.add n[i]
@@ -509,6 +539,10 @@ proc relativeFile(c: PContext; n: PNode; ext=""): AbsoluteFile =
if result.isEmpty: result = AbsoluteFile s
proc processCompile(c: PContext, n: PNode) =
## This pragma can take two forms. The first is a simple file input:
## {.compile: "file.c".}
## The second is a tuple where the second arg is the output name strutils formatter:
## {.compile: ("file.c", "$1.o").}
proc docompile(c: PContext; it: PNode; src, dest: AbsoluteFile; customArgs: string) =
var cf = Cfile(nimname: splitFile(src).name,
cname: src, obj: dest, flags: {CfileFlag.External},
@@ -523,7 +557,7 @@ proc processCompile(c: PContext, n: PNode) =
n[i] = c.semConstExpr(c, n[i])
case n[i].kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
when defined(gcArc) or defined(gcOrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result = n[i].strVal
else:
shallowCopy(result, n[i].strVal)
@@ -557,7 +591,8 @@ proc processCompile(c: PContext, n: PNode) =
else:
found = findFile(c.config, s)
if found.isEmpty: found = AbsoluteFile s
let obj = toObjFile(c.config, completeCfilePath(c.config, found, false))
let mangled = completeCfilePath(c.config, mangleModuleName(c.config, found).AbsoluteFile)
let obj = toObjFile(c.config, mangled)
docompile(c, it, found, obj, customArgs)
proc processLink(c: PContext, n: PNode) =
@@ -609,7 +644,7 @@ proc pragmaEmit(c: PContext, n: PNode) =
if n1.kind == nkBracket:
var b = newNodeI(nkBracket, n1.info, n1.len)
for i in 0..<n1.len:
b[i] = c.semExpr(c, n1[i])
b[i] = c.semExprWithType(c, n1[i], {efTypeAllowed})
n[1] = b
else:
n[1] = c.semConstExpr(c, n1)
@@ -662,7 +697,8 @@ proc processPragma(c: PContext, n: PNode, i: int) =
elif it.safeLen != 2 or it[0].kind != nkIdent or it[1].kind != nkIdent:
invalidPragma(c, n)
var userPragma = newSym(skTemplate, it[1].ident, nextSymId(c.idgen), c.module, it.info, c.config.options)
var userPragma = newSym(skTemplate, it[1].ident, c.idgen, c.module, it.info, c.config.options)
styleCheckDef(c, userPragma)
userPragma.ast = newTreeI(nkPragma, n.info, n.sons[i+1..^1])
strTableAdd(c.userPragmas, userPragma)
@@ -722,19 +758,8 @@ proc deprecatedStmt(c: PContext; outerPragma: PNode) =
return
if pragma.kind != nkBracket:
localError(c.config, pragma.info, "list of key:value pairs expected"); return
for n in pragma:
if n.kind in nkPragmaCallKinds and n.len == 2:
let dest = qualifiedLookUp(c, n[1], {checkUndeclared})
if dest == nil or dest.kind in routineKinds:
localError(c.config, n.info, warnUser, "the .deprecated pragma is unreliable for routines")
let src = considerQuotedIdent(c, n[0])
let alias = newSym(skAlias, src, nextSymId(c.idgen), dest, n[0].info, c.config.options)
incl(alias.flags, sfExported)
if sfCompilerProc in dest.flags: markCompilerProc(c, alias)
addInterfaceDecl(c, alias)
n[1] = newSymNode(dest)
else:
localError(c.config, n.info, "key:value pair expected")
message(c.config, pragma.info, warnDeprecated,
"deprecated statement is now a no-op, use regular deprecated pragma")
proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
if it.kind notin nkPragmaCallKinds or it.len != 2:
@@ -750,12 +775,12 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
# We return a dummy symbol; later passes over the type will repair it.
# Generic instantiation needs to know about this too. But we're lazy
# and perform the lookup on demand instead.
result = newSym(skUnknown, considerQuotedIdent(c, n), nextSymId(c.idgen), nil, n.info,
result = newSym(skUnknown, considerQuotedIdent(c, n), c.idgen, nil, n.info,
c.config.options)
else:
result = qualifiedLookUp(c, n, {checkUndeclared})
proc semCustomPragma(c: PContext, n: PNode): PNode =
proc semCustomPragma(c: PContext, n: PNode, sym: PSym): PNode =
var callNode: PNode
if n.kind in {nkIdent, nkSym}:
@@ -775,6 +800,11 @@ proc semCustomPragma(c: PContext, n: PNode): PNode =
invalidPragma(c, n)
return n
# we have a valid custom pragma
if sym != nil and sym.kind in {skEnumField, skForVar, skModule}:
illegalCustomPragma(c, n, sym)
return n
result = r
# Transform the nkCall node back to its original form if possible
if n.kind == nkIdent and r.len == 1:
@@ -808,7 +838,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
validPragmas: TSpecialWords,
comesFromPush, isStatement: bool): bool =
var it = n[i]
var key = if it.kind in nkPragmaCallKinds and it.len > 1: it[0] else: it
let keyDeep = it.kind in nkPragmaCallKinds and it.len > 1
var key = if keyDeep: it[0] else: it
if key.kind == nkBracketExpr:
processNote(c, it)
return
@@ -822,7 +853,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
else: discard
return
elif key.kind notin nkIdentKinds:
n[i] = semCustomPragma(c, it)
n[i] = semCustomPragma(c, it, sym)
return
let ident = considerQuotedIdent(c, key)
var userPragma = strTableGet(c.userPragmas, ident)
@@ -834,6 +865,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
if c.instCounter > 100:
globalError(c.config, it.info, "recursive dependency: " & userPragma.name.s)
if keyDeep:
localError(c.config, it.info, "user pragma cannot have arguments")
pragma(c, sym, userPragma.ast, validPragmas, isStatement)
n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content
i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
@@ -841,7 +875,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
else:
let k = whichKeyword(ident)
if k in validPragmas:
checkPragmaUse(c.config, key.info, k, ident.s)
checkPragmaUse(c, key.info, k, ident.s, (if sym != nil: sym else: c.module))
case k
of wExportc, wExportCpp:
makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info)
@@ -950,8 +984,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
# only supported for backwards compat, doesn't do anything anymore
noVal(c, it)
of wConstructor:
noVal(c, it)
incl(sym.flags, sfConstructor)
if sfImportc notin sym.flags:
sym.constraint = newEmptyStrNode(c, it, getOptionalStr(c, it, ""))
sym.constraint.strVal = sym.constraint.strVal
sym.flags.incl {sfExportc, sfMangleCpp}
sym.typ.callConv = ccNoConvention
of wHeader:
var lib = getLib(c, libHeader, getStrLitNode(c, it))
addToLib(lib, sym)
@@ -1045,6 +1083,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
if sym.typ != nil:
incl(sym.typ.flags, tfThread)
if sym.typ.callConv == ccClosure: sym.typ.callConv = ccNimCall
of wSendable:
noVal(c, it)
if sym != nil and sym.typ != nil:
incl(sym.typ.flags, tfSendable)
else:
invalidPragma(c, it)
of wGcSafe:
noVal(c, it)
if sym != nil:
@@ -1081,13 +1125,20 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wFatal: fatal(c.config, it.info, expectStrLit(c, it))
of wDefine: processDefine(c, it, sym)
of wUndef: processUndef(c, it)
of wCompile: processCompile(c, it)
of wCompile:
let m = sym.getModule()
incl(m.flags, sfUsed)
processCompile(c, it)
of wLink: processLink(c, it)
of wPassl:
let m = sym.getModule()
incl(m.flags, sfUsed)
let s = expectStrLit(c, it)
extccomp.addLinkOption(c.config, s)
recordPragma(c, it, "passl", s)
of wPassc:
let m = sym.getModule()
incl(m.flags, sfUsed)
let s = expectStrLit(c, it)
extccomp.addCompileOption(c.config, s)
recordPragma(c, it, "passc", s)
@@ -1169,13 +1220,17 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
invalidPragma(c, it)
of wByRef:
noVal(c, it)
if sym == nil or sym.typ == nil:
if sym != nil and sym.kind == skParam:
sym.options.incl optByRef
elif sym == nil or sym.typ == nil:
processOption(c, it, c.config.options)
else:
incl(sym.typ.flags, tfByRef)
of wByCopy:
noVal(c, it)
if sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
if sym.kind == skParam:
incl(sym.flags, sfByCopy)
elif sym.kind != skType or sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ.flags, tfByCopy)
of wPartial:
noVal(c, it)
@@ -1240,21 +1295,19 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
pragmaProposition(c, it)
of wEnsures:
pragmaEnsures(c, it)
of wEnforceNoRaises:
of wEnforceNoRaises, wQuirky:
sym.flags.incl sfNeverRaises
of wSystemRaisesDefect:
sym.flags.incl sfSystemRaisesDefect
of wVirtual:
processVirtual(c, it, sym)
else: invalidPragma(c, it)
elif comesFromPush and whichKeyword(ident) != wInvalid:
discard "ignore the .push pragma; it doesn't apply"
else:
if sym == nil or (sym.kind in {skVar, skLet, skConst, skParam, skIterator,
skField, skProc, skFunc, skConverter, skMethod, skType}):
n[i] = semCustomPragma(c, it)
elif sym != nil:
illegalCustomPragma(c, it, sym)
else:
invalidPragma(c, it)
# semCustomPragma gives appropriate error for invalid pragmas
n[i] = semCustomPragma(c, it, sym)
proc overwriteLineInfo(n: PNode; info: TLineInfo) =
n.info = info

View File

@@ -4,4 +4,4 @@
- Note that this code has been translated from a bootstrapping version written in Pascal.
- So the code is **not** a poster child of good Nim code.
See [Internals of the Nim Compiler](https://nim-lang.org/docs/intern.html) for more information.
See [Internals of the Nim Compiler](https://nim-lang.github.io/Nim/intern.html) for more information.

View File

@@ -14,7 +14,7 @@
{.used.}
import
lexer, options, idents, strutils, ast, msgs, lineinfos
lexer, options, idents, strutils, ast, msgs, lineinfos, wordrecg
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions, formatfloat]
@@ -31,6 +31,10 @@ type
length*: int16
sym*: PSym
Section = enum
GenericParams
ObjectDef
TRenderTokSeq* = seq[TRenderTok]
TSrcGen* = object
indent*: int
@@ -45,7 +49,7 @@ type
pendingWhitespace: int
comStack*: seq[PNode] # comment stack
flags*: TRenderFlags
inGenericParams: bool
inside: set[Section] # Keeps track of contexts we are in
checkAnon: bool # we're in a context that can contain sfAnon
inPragma: int
when defined(nimpretty):
@@ -73,6 +77,16 @@ proc isKeyword*(i: PIdent): bool =
(i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
result = true
proc isExported(n: PNode): bool =
## Checks if an ident is exported.
## This is meant to be used with idents in nkIdentDefs.
case n.kind
of nkPostfix:
n[0].ident.s == "*" and n[1].kind == nkIdent
of nkPragmaExpr:
n[0].isExported()
else: false
proc renderDefinitionName*(s: PSym, noQuotes = false): string =
## Returns the definition name of the symbol.
##
@@ -85,6 +99,25 @@ proc renderDefinitionName*(s: PSym, noQuotes = false): string =
else:
result = '`' & x & '`'
template inside(g: var TSrcGen, section: Section, body: untyped) =
## Runs `body` with `section` included in `g.inside`.
## Removes it at the end of the body if `g` wasn't inside it
## before the template.
let wasntInSection = section notin g.inside
g.inside.incl section
body
if wasntInSection:
g.inside.excl section
template outside(g: var TSrcGen, section: Section, body: untyped) =
## Temporarily removes `section` from `g.inside`. Adds it back
## at the end of the body if `g` was inside it before the template
let wasInSection = section in g.inside
g.inside.excl section
body
if wasInSection:
g.inside.incl section
const
IndentWidth = 2
longIndentWid = IndentWidth * 2
@@ -121,7 +154,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
g.flags = renderFlags
g.pendingNL = -1
g.pendingWhitespace = -1
g.inGenericParams = false
g.inside = {}
g.config = config
proc addTok(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) =
@@ -379,6 +412,7 @@ proc atom(g: TSrcGen; n: PNode): string =
of nkEmpty: result = ""
of nkIdent: result = n.ident.s
of nkSym: result = n.sym.name.s
of nkClosedSymChoice, nkOpenSymChoice: result = n[0].sym.name.s
of nkStrLit: result = ""; result.addQuoted(n.strVal)
of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"'
of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\""
@@ -814,7 +848,7 @@ proc gcase(g: var TSrcGen, n: PNode) =
gsub(g, n[^1], c)
proc genSymSuffix(result: var string, s: PSym) {.inline.} =
if sfGenSym in s.flags:
if sfGenSym in s.flags and s.name.id != ord(wUnderscore):
result.add '_'
result.addInt s.id
@@ -830,19 +864,17 @@ proc gproc(g: var TSrcGen, n: PNode) =
if n[patternPos].kind != nkEmpty:
gpattern(g, n[patternPos])
let oldInGenericParams = g.inGenericParams
g.inGenericParams = true
if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and
n[miscPos][1].kind != nkEmpty:
gsub(g, n[miscPos][1])
else:
gsub(g, n[genericParamsPos])
g.inGenericParams = oldInGenericParams
g.inside(GenericParams):
if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and
n[miscPos][1].kind != nkEmpty:
gsub(g, n[miscPos][1])
else:
gsub(g, n[genericParamsPos])
gsub(g, n[paramsPos])
if renderNoPragmas notin g.flags:
gsub(g, n[pragmasPos])
if renderNoBody notin g.flags:
if n[bodyPos].kind != nkEmpty:
if n.len > bodyPos and n[bodyPos].kind != nkEmpty:
put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=")
indentNL(g)
@@ -915,7 +947,7 @@ proc gasm(g: var TSrcGen, n: PNode) =
gsub(g, n[1])
proc gident(g: var TSrcGen, n: PNode) =
if g.inGenericParams and n.kind == nkSym:
if GenericParams in g.inside and n.kind == nkSym:
if sfAnon in n.sym.flags or
(n.typ != nil and tfImplicitTypeParam in n.typ.flags): return
@@ -939,7 +971,9 @@ proc gident(g: var TSrcGen, n: PNode) =
s.addInt localId
if sfCursor in n.sym.flags:
s.add "_cursor"
elif n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp):
elif n.kind == nkSym and (renderIds in g.flags or
(sfGenSym in n.sym.flags and n.sym.name.id != ord(wUnderscore)) or
n.sym.kind == skTemp):
s.add '_'
s.addInt n.sym.id
when defined(debugMagics):
@@ -1006,7 +1040,7 @@ proc accentedName(g: var TSrcGen, n: PNode) =
gsub(g, n)
proc infixArgument(g: var TSrcGen, n: PNode, i: int) =
if i < 1 and i > 2: return
if i < 1 or i > 2: return
var needsParenthesis = false
let nNext = n[i].skipHiddenNodes
if nNext.kind == nkInfix:
@@ -1303,14 +1337,31 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
gsub(g, n, pragmasPos)
put(g, tkColon, ":")
gsub(g, n, bodyPos)
of nkConstDef, nkIdentDefs:
of nkIdentDefs:
# Skip if this is a property in a type and its not exported
# (While also not allowing rendering of non exported fields)
if ObjectDef in g.inside and (not n[0].isExported() and renderNonExportedFields notin g.flags):
return
# We render the identDef without being inside the section incase we render something like
# y: proc (x: string) # (We wouldn't want to check if x is exported)
g.outside(ObjectDef):
gcomma(g, n, 0, -3)
if n.len >= 2 and n[^2].kind != nkEmpty:
putWithSpace(g, tkColon, ":")
gsub(g, n[^2], c)
elif n.referencesUsing and renderExpandUsing in g.flags:
putWithSpace(g, tkColon, ":")
gsub(g, newSymNode(n.origUsingType), c)
if n.len >= 1 and n[^1].kind != nkEmpty:
put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=")
gsub(g, n[^1], c)
of nkConstDef:
gcomma(g, n, 0, -3)
if n.len >= 2 and n[^2].kind != nkEmpty:
putWithSpace(g, tkColon, ":")
gsub(g, n[^2], c)
elif n.referencesUsing and renderExpandUsing in g.flags:
putWithSpace(g, tkColon, ":")
gsub(g, newSymNode(n.origUsingType), c)
if n.len >= 1 and n[^1].kind != nkEmpty:
put(g, tkSpaces, Space)
@@ -1333,6 +1384,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
putWithSpace(g, tkColon, ":")
gsub(g, n, 1)
of nkInfix:
if n.len < 3:
var i = 0
put(g, tkOpr, "Too few children for nkInfix")
return
let oldLineLen = g.lineLen # we cache this because lineLen gets updated below
infixArgument(g, n, 1)
put(g, tkSpaces, Space)
@@ -1380,15 +1435,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
of nkAccQuoted:
put(g, tkAccent, "`")
for i in 0..<n.len:
proc getStrVal(n: PNode): string =
# pending https://github.com/nim-lang/Nim/pull/17540, use `getStrVal`
case n.kind
of nkIdent: n.ident.s
of nkSym: n.sym.name.s
else: ""
proc isAlpha(n: PNode): bool =
if n.kind in {nkIdent, nkSym}:
let tmp = n.getStrVal
let tmp = n.getPIdent.s
result = tmp.len > 0 and tmp[0] in {'a'..'z', 'A'..'Z'}
var useSpace = false
if i == 1 and n[0].kind == nkIdent and n[0].ident.s in ["=", "'"]:
@@ -1473,22 +1522,20 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
of nkObjectTy:
if n.len > 0:
putWithSpace(g, tkObject, "object")
gsub(g, n[0])
gsub(g, n[1])
gcoms(g)
gsub(g, n[2])
g.inside(ObjectDef):
gsub(g, n[0])
gsub(g, n[1])
gcoms(g)
indentNL(g)
gsub(g, n[2])
dedent(g)
else:
put(g, tkObject, "object")
of nkRecList:
indentNL(g)
for i in 0..<n.len:
if n[i].kind == nkIdentDefs and n[i][0].kind == nkPostfix or
renderNonExportedFields in g.flags:
optNL(g)
gsub(g, n[i], c)
gcoms(g)
dedent(g)
putNL(g)
optNL(g)
gsub(g, n[i], c)
gcoms(g)
of nkOfInherit:
putWithSpace(g, tkOf, "of")
gsub(g, n, 0)

View File

@@ -21,8 +21,8 @@ type
# though it is not necessary)
Rope* = string
proc newRopeAppender*(): string {.inline.} =
result = newString(0)
proc newRopeAppender*(cap = 80): string {.inline.} =
result = newStringOfCap(cap)
proc freeze*(r: Rope) {.inline.} = discard
@@ -102,12 +102,9 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
inc(i)
else:
doAssert false, "invalid format string: " & frmt
var start = i
while i < frmt.len:
if frmt[i] != '$': inc(i)
else: break
if i - 1 >= start:
result.add(substr(frmt, start, i - 1))
else:
result.add(frmt[i])
inc(i)
proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope =
runtimeFormat(frmt, args)

View File

@@ -17,7 +17,7 @@ import
pathutils, pipelines
when defined(nimPreviewSlimSystem):
import std/syncio
import std/[syncio, assertions]
# we support 'cmpIgnoreStyle' natively for efficiency:
from strutils import cmpIgnoreStyle, contains
@@ -207,8 +207,8 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
let oldGlobalOptions = conf.globalOptions
let oldSelectedGC = conf.selectedGC
undefSymbol(conf.symbols, "nimv2")
conf.globalOptions.excl {optTinyRtti, optOwnedRefs, optSeqDestructors}
unregisterArcOrc(conf)
conf.globalOptions.excl optOwnedRefs
conf.selectedGC = gcUnselected
var m = graph.makeModule(scriptName)
@@ -227,9 +227,20 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
if optOwnedRefs in oldGlobalOptions:
conf.globalOptions.incl {optTinyRtti, optOwnedRefs, optSeqDestructors}
defineSymbol(conf.symbols, "nimv2")
if conf.selectedGC in {gcArc, gcOrc}:
if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
conf.globalOptions.incl {optTinyRtti, optSeqDestructors}
defineSymbol(conf.symbols, "nimv2")
defineSymbol(conf.symbols, "gcdestructors")
defineSymbol(conf.symbols, "nimSeqsV2")
case conf.selectedGC
of gcArc:
defineSymbol(conf.symbols, "gcarc")
of gcOrc:
defineSymbol(conf.symbols, "gcorc")
of gcAtomicArc:
defineSymbol(conf.symbols, "gcatomicarc")
else:
doAssert false, "unreachable"
# ensure we load 'system.nim' again for the real non-config stuff!
resetSystemArtifacts(graph)

View File

@@ -9,6 +9,8 @@
# This module implements the semantic checking pass.
import tables
import
ast, strutils, options, astalgo, trees,
wordrecg, ropes, msgs, idents, renderer, types, platform, math,
@@ -19,14 +21,15 @@ import
lowerings, plugins/active, lineinfos, strtabs, int128,
isolation_check, typeallowed, modulegraphs, enumtostr, concepts, astmsgs
when defined(nimfix):
import nimfix/prettybase
when not defined(leanCompiler):
import spawn
when defined(nimPreviewSlimSystem):
import std/formatfloat
import std/[
formatfloat,
assertions,
]
# implementation
@@ -205,13 +208,78 @@ proc commonType*(c: PContext; x, y: PType): PType =
result = newType(k, nextTypeId(c.idgen), r.owner)
result.addSonSkipIntLit(r, c.idgen)
const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool}
proc shouldCheckCaseCovered(caseTyp: PType): bool =
result = false
case caseTyp.kind
of shouldChckCovered:
result = true
of tyRange:
if skipTypes(caseTyp[0], abstractInst).kind in shouldChckCovered:
result = true
else:
discard
proc endsInNoReturn(n: PNode): bool =
# check if expr ends in raise exception or call of noreturn proc
## check if expr ends the block like raising or call of noreturn procs do
result = false # assume it does return
template checkBranch(branch) =
if not endsInNoReturn(branch):
# proved a branch returns
return false
var it = n
# skip these beforehand, no special handling needed
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
it = it.lastSon
result = it.kind in nkLastBlockStmts or
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
case it.kind
of nkIfStmt:
var hasElse = false
for branch in it:
checkBranch:
if branch.len == 2:
branch[1]
elif branch.len == 1:
hasElse = true
branch[0]
else:
raiseAssert "Malformed `if` statement during endsInNoReturn"
# none of the branches returned
result = hasElse # Only truly a no-return when it's exhaustive
of nkCaseStmt:
let caseTyp = skipTypes(it[0].typ, abstractVar-{tyTypeDesc})
# semCase should already have checked for exhaustiveness in this case
# effectively the same as having an else
var hasElse = caseTyp.shouldCheckCaseCovered()
# actual noreturn checks
for i in 1 ..< it.len:
let branch = it[i]
checkBranch:
case branch.kind
of nkOfBranch:
branch[^1]
of nkElifBranch:
branch[1]
of nkElse:
hasElse = true
branch[0]
else:
raiseAssert "Malformed `case` statement in endsInNoReturn"
# Can only guarantee a noreturn if there is an else or it's exhaustive
result = hasElse
of nkTryStmt:
checkBranch(it[0])
for i in 1 ..< it.len:
let branch = it[i]
checkBranch(branch[^1])
# none of the branches returned
result = true
else:
result = it.kind in nkLastBlockStmts or
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
proc commonType*(c: PContext; x: PType, y: PNode): PType =
# ignore exception raising branches in case/if expressions
@@ -219,7 +287,7 @@ proc commonType*(c: PContext; x: PType, y: PNode): PType =
commonType(c, x, y.typ)
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerQuotedIdent(c, n), nextSymId c.idgen, getCurrOwner(c), n.info)
result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info)
when defined(nimsuggest):
suggestDecl(c, n, result)
@@ -242,7 +310,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# template; we must fix it here: see #909
result.owner = getCurrOwner(c)
else:
result = newSym(kind, considerQuotedIdent(c, n), nextSymId c.idgen, getCurrOwner(c), n.info)
result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info)
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
# incl(result.flags, sfGlobal)
when defined(nimsuggest):
@@ -281,7 +349,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
proc symFromType(c: PContext; t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym
result = newSym(skType, getIdent(c.cache, "AnonType"), nextSymId c.idgen, t.owner, info)
result = newSym(skType, getIdent(c.cache, "AnonType"), c.idgen, t.owner, info)
result.flags.incl sfAnon
result.typ = t
@@ -351,6 +419,11 @@ proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
c.config.m.errorOutputs = {}
c.config.errorMax = high(int) # `setErrorMaxHighMaybe` not appropriate here
when defined(nimsuggest):
# Remove the error hook so nimsuggest doesn't report errors there
let tempHook = c.graph.config.structuredErrorHook
c.graph.config.structuredErrorHook = nil
try:
result = evalConstExpr(c.module, c.idgen, c.graph, e)
if result == nil or result.kind == nkEmpty:
@@ -361,6 +434,10 @@ proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
except ERecoverableError:
result = nil
when defined(nimsuggest):
# Restore the error hook
c.graph.config.structuredErrorHook = tempHook
c.config.errorCounter = oldErrorCount
c.config.errorMax = oldErrorMax
c.config.m.errorOutputs = oldErrorOutputs
@@ -405,6 +482,8 @@ proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags; expectedTyp
evaluated = evalAtCompileTime(c, result)
if evaluated != nil: return evaluated
proc semGenericStmt(c: PContext, n: PNode): PNode
include hlo, seminst, semcall
proc resetSemFlag(n: PNode) =
@@ -460,13 +539,22 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
# we now know the supplied arguments
var paramTypes = newIdTable()
for param, value in genericParamsInMacroCall(s, call):
idTablePut(paramTypes, param.typ, value.typ)
var givenType = value.typ
# the sym nodes used for the supplied generic arguments for
# templates and macros leave type nil so regular sem can handle it
# in this case, get the type directly from the sym
if givenType == nil and value.kind == nkSym and value.sym.typ != nil:
givenType = value.sym.typ
idTablePut(paramTypes, param.typ, givenType)
retType = generateTypeInstance(c, paramTypes,
macroResult.info, retType)
result = semExpr(c, result, flags, expectedType)
result = fitNode(c, retType, result, result.info)
if retType.kind == tyVoid:
result = semStmt(c, result, flags)
else:
result = semExpr(c, result, flags, expectedType)
result = fitNode(c, retType, result, result.info)
#globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0]))
dec(c.config.evalTemplateCounter)
discard c.friendModules.pop()
@@ -510,8 +598,6 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
result = forceBool(c, semConstExpr(c, n, getSysType(c.graph, n.info, tyBool)))
if result.kind != nkIntLit:
localError(c.config, n.info, errConstExprExpected)
proc semGenericStmt(c: PContext, n: PNode): PNode
proc semConceptBody(c: PContext, n: PNode): PNode
include semtypes
@@ -550,17 +636,17 @@ proc pickCaseBranchIndex(caseExpr, matched: PNode): int =
if endsWithElse:
return caseExpr.len - 1
proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode]
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode
proc defaultNodeField(c: PContext, a: PNode): PNode
proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault: bool): seq[PNode]
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): PNode
proc defaultNodeField(c: PContext, a: PNode, checkDefault: bool): PNode
const defaultFieldsSkipTypes = {tyGenericInst, tyAlias, tySink}
proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): seq[PNode] =
proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool, checkDefault: bool): seq[PNode] =
case recNode.kind
of nkRecList:
for field in recNode:
result.add defaultFieldsForTuple(c, field, hasDefault)
result.add defaultFieldsForTuple(c, field, hasDefault, checkDefault)
of nkSym:
let field = recNode.sym
let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes)
@@ -569,30 +655,30 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s
result.add newTree(nkExprColonExpr, recNode, field.ast)
else:
if recType.kind in {tyObject, tyArray, tyTuple}:
let asgnExpr = defaultNodeField(c, recNode, recNode.typ)
let asgnExpr = defaultNodeField(c, recNode, recNode.typ, checkDefault)
if asgnExpr != nil:
hasDefault = true
asgnExpr.flags.incl nfSkipFieldChecking
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
return
let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), recType.owner)
rawAddSon(asgnType, recType)
let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), recNode.typ.owner)
rawAddSon(asgnType, recNode.typ)
let asgnExpr = newTree(nkCall,
newSymNode(getSysMagic(c.graph, recNode.info, "zeroDefault", mZeroDefault)),
newNodeIT(nkType, recNode.info, asgnType)
)
asgnExpr.flags.incl nfSkipFieldChecking
asgnExpr.typ = recType
asgnExpr.typ = recNode.typ
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
doAssert false
proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] =
proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault: bool): seq[PNode] =
case recNode.kind
of nkRecList:
for field in recNode:
result.add defaultFieldsForTheUninitialized(c, field)
result.add defaultFieldsForTheUninitialized(c, field, checkDefault)
of nkRecCase:
let discriminator = recNode[0]
var selectedBranch: int
@@ -601,58 +687,60 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] =
# None of the branches were explicitly selected by the user and no value
# was given to the discrimator. We can assume that it will be initialized
# to zero and this will select a particular branch as a result:
if checkDefault: # don't add defaults when checking whether a case branch has default fields
return
defaultValue = newIntNode(nkIntLit#[c.graph]#, 0)
defaultValue.typ = discriminator.typ
selectedBranch = recNode.pickCaseBranchIndex defaultValue
defaultValue.flags.incl nfSkipFieldChecking
result.add newTree(nkExprColonExpr, discriminator, defaultValue)
result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1])
result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1], checkDefault)
of nkSym:
let field = recNode.sym
let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes)
if field.ast != nil: #Try to use default value
result.add newTree(nkExprColonExpr, recNode, field.ast)
elif recType.kind in {tyObject, tyArray, tyTuple}:
let asgnExpr = defaultNodeField(c, recNode, recType)
let asgnExpr = defaultNodeField(c, recNode, recNode.typ, checkDefault)
if asgnExpr != nil:
asgnExpr.typ = recType
asgnExpr.typ = recNode.typ
asgnExpr.flags.incl nfSkipFieldChecking
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
doAssert false
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode =
proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): PNode =
let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes)
if aTypSkip.kind == tyObject:
let child = defaultFieldsForTheUninitialized(c, aTypSkip.n)
let child = defaultFieldsForTheUninitialized(c, aTypSkip.n, checkDefault)
if child.len > 0:
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTypSkip))
asgnExpr.typ = aTypSkip
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTyp))
asgnExpr.typ = aTyp
asgnExpr.sons.add child
result = semExpr(c, asgnExpr)
elif aTypSkip.kind == tyArray:
let child = defaultNodeField(c, a, aTypSkip[1])
let child = defaultNodeField(c, a, aTypSkip[1], checkDefault)
if child != nil:
let node = newNode(nkIntLit)
node.intVal = toInt64(lengthOrd(c.graph.config, aTypSkip))
result = semExpr(c, newTree(nkCall, newSymNode(getCompilerProc(c.graph, "nimArrayWith"), a.info),
semExprWithType(c, child),
node
))
result = semExpr(c, newTree(nkCall, newSymNode(getSysSym(c.graph, a.info, "arrayWith"), a.info),
semExprWithType(c, child),
node
))
result.typ = aTyp
elif aTypSkip.kind == tyTuple:
var hasDefault = false
if aTypSkip.n != nil:
let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault)
let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault, checkDefault)
if hasDefault and children.len > 0:
result = newNodeI(nkTupleConstr, a.info)
result.typ = aTyp
result.sons.add children
result = semExpr(c, result)
proc defaultNodeField(c: PContext, a: PNode): PNode =
result = defaultNodeField(c, a, a.typ)
proc defaultNodeField(c: PContext, a: PNode, checkDefault: bool): PNode =
result = defaultNodeField(c, a, a.typ, checkDefault)
include semtempl, semgnrc, semstmts, semexprs
@@ -675,6 +763,7 @@ proc preparePContext*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PCo
if result.p != nil: internalError(graph.config, module.info, "sem.preparePContext")
result.semConstExpr = semConstExpr
result.semExpr = semExpr
result.semExprWithType = semExprWithType
result.semTryExpr = tryExpr
result.semTryConstExpr = tryConstExpr
result.computeRequiresInit = computeRequiresInit

View File

@@ -132,7 +132,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
# just in case, should be impossible though
if syms.len == 0:
break
if nextSymIndex > high(syms):
# we have reached the end
break
@@ -236,44 +236,89 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
candidates.add("\n")
let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
if n.len > 1 and verboseTypeMismatch in c.config.legacyFeatures:
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
case err.firstMismatch.kind
of kUnknownNamedParam:
if nArg == nil:
candidates.add("\n unknown named parameter")
else:
candidates.add("\n unknown named parameter: " & $nArg[0])
of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0])
of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param")
of kExtraArg: candidates.add("\n extra argument given")
of kMissingParam: candidates.add("\n missing parameter: " & nameParam)
of kTypeMismatch, kVarNeeded:
doAssert nArg != nil
let wanted = err.firstMismatch.formal.typ
doAssert err.firstMismatch.formal != nil
candidates.add("\n required type for " & nameParam & ": ")
candidates.addTypeDeclVerboseMaybe(c.config, wanted)
candidates.add "\n but expression '"
if err.firstMismatch.kind == kVarNeeded:
if n.len > 1:
if verboseTypeMismatch notin c.config.legacyFeatures:
case err.firstMismatch.kind
of kUnknownNamedParam:
if nArg == nil:
candidates.add(" unknown named parameter")
else:
candidates.add(" unknown named parameter: " & $nArg[0])
candidates.add "\n"
of kAlreadyGiven:
candidates.add(" named param already provided: " & $nArg[0])
candidates.add "\n"
of kPositionalAlreadyGiven:
candidates.add(" positional param was already given as named param")
candidates.add "\n"
of kExtraArg:
candidates.add(" extra argument given")
candidates.add "\n"
of kMissingParam:
candidates.add(" missing parameter: " & nameParam)
candidates.add "\n"
of kVarNeeded:
doAssert nArg != nil
doAssert err.firstMismatch.formal != nil
candidates.add " expression '"
candidates.add renderNotLValue(nArg)
candidates.add "' is immutable, not 'var'"
else:
candidates.add renderTree(nArg)
candidates.add "' is of type: "
let got = nArg.typ
candidates.addTypeDeclVerboseMaybe(c.config, got)
candidates.add "\n"
of kTypeMismatch:
doAssert nArg != nil
let wanted = err.firstMismatch.formal.typ
doAssert err.firstMismatch.formal != nil
doAssert wanted != nil
if got != nil:
if got.kind == tyProc and wanted.kind == tyProc:
# These are proc mismatches so,
# add the extra explict detail of the mismatch
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
let got = nArg.typ
if got != nil and got.kind == tyProc and wanted.kind == tyProc:
# These are proc mismatches so,
# add the extra explict detail of the mismatch
candidates.add " expression '"
candidates.add renderTree(nArg)
candidates.add "' is of type: "
candidates.addTypeDeclVerboseMaybe(c.config, got)
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
effectProblem(wanted, got, candidates, c)
candidates.add "\n"
of kUnknown: discard "do not break 'nim check'"
else:
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
case err.firstMismatch.kind
of kUnknownNamedParam:
if nArg == nil:
candidates.add("\n unknown named parameter")
else:
candidates.add("\n unknown named parameter: " & $nArg[0])
of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0])
of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param")
of kExtraArg: candidates.add("\n extra argument given")
of kMissingParam: candidates.add("\n missing parameter: " & nameParam)
of kTypeMismatch, kVarNeeded:
doAssert nArg != nil
let wanted = err.firstMismatch.formal.typ
doAssert err.firstMismatch.formal != nil
candidates.add("\n required type for " & nameParam & ": ")
candidates.addTypeDeclVerboseMaybe(c.config, wanted)
candidates.add "\n but expression '"
if err.firstMismatch.kind == kVarNeeded:
candidates.add renderNotLValue(nArg)
candidates.add "' is immutable, not 'var'"
else:
candidates.add renderTree(nArg)
candidates.add "' is of type: "
let got = nArg.typ
candidates.addTypeDeclVerboseMaybe(c.config, got)
doAssert wanted != nil
if got != nil:
if got.kind == tyProc and wanted.kind == tyProc:
# These are proc mismatches so,
# add the extra explict detail of the mismatch
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
effectProblem(wanted, got, candidates, c)
of kUnknown: discard "do not break 'nim check'"
candidates.add "\n"
of kUnknown: discard "do not break 'nim check'"
candidates.add "\n"
if err.firstMismatch.arg == 1 and nArg.kind == nkTupleConstr and
n.kind == nkCommand:
maybeWrongSpace = true
@@ -293,7 +338,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
const
errTypeMismatch = "type mismatch: got <"
errButExpected = "but expected one of:"
errExpectedPosition = "Expected one of (first mismatch at position [#]):"
errExpectedPosition = "Expected one of (first mismatch at [position]):"
errUndeclaredField = "undeclared field: '$1'"
errUndeclaredRoutine = "attempting to call undeclared routine: '$1'"
errBadRoutine = "attempting to call routine: '$1'$2"
@@ -595,7 +640,12 @@ proc semResolvedCall(c: PContext, x: TCandidate,
else:
x.call.add c.graph.emptyNode
of skType:
x.call.add newSymNode(s, n.info)
var tn = newSymNode(s, n.info)
# this node will be used in template substitution,
# pretend this is an untyped node and let regular sem handle the type
# to prevent problems where a generic parameter is treated as a value
tn.typ = nil
x.call.add tn
else:
internalAssert c.config, false
@@ -627,7 +677,10 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
candidates)
result = semResolvedCall(c, r, n, flags)
else:
if efExplain notin flags:
if efDetermineType in flags and c.inGenericContext > 0 and c.matchedConcept == nil:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
elif efExplain notin flags:
# repeat the overload resolution,
# this time enabling all the diagnostic output (this should fail again)
result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
@@ -662,14 +715,18 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
onUse(info, s)
result = newSymNode(newInst, info)
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
assert n.kind == nkBracketExpr
proc setGenericParams(c: PContext, n: PNode) =
## sems generic params in subscript expression
for i in 1..<n.len:
let e = semExprWithType(c, n[i])
if e.typ == nil:
n[i].typ = errorType(c)
else:
n[i].typ = e.typ.skipTypes({tyTypeDesc})
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
assert n.kind == nkBracketExpr
setGenericParams(c, n)
var s = s
var a = n[0]
if a.kind == nkSym:
@@ -704,17 +761,25 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
else:
result = explicitGenericInstError(c, n)
proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): tuple[s: PSym, state: TBorrowState] =
# Searches for the fn in the symbol table. If the parameter lists are suitable
# for borrowing the sym in the symbol table is returned, else nil.
# New approach: generate fn(x, y, z) where x, y, z have the proper types
# and use the overloading resolution mechanism:
const desiredTypes = abstractVar + {tyCompositeTypeClass} - {tyTypeDesc, tyDistinct}
template getType(isDistinct: bool; t: PType):untyped =
if isDistinct: t.baseOfDistinct(c.graph, c.idgen) else: t
result = default(tuple[s: PSym, state: TBorrowState])
var call = newNodeI(nkCall, fn.info)
var hasDistinct = false
var isDistinct: bool
var x: PType
var t: PType
call.add(newIdentNode(fn.name, fn.info))
for i in 1..<fn.typ.n.len:
let param = fn.typ.n[i]
const desiredTypes = abstractVar + {tyCompositeTypeClass} - {tyTypeDesc, tyDistinct}
#[.
# We only want the type not any modifiers such as `ptr`, `var`, `ref` ...
# tyCompositeTypeClass is here for
@@ -723,22 +788,31 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
proc `$`(f: Foo): string {.borrow.}
# We want to skip the `Foo` to get `int`
]#
let t = skipTypes(param.typ, desiredTypes)
if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true
var x: PType
t = skipTypes(param.typ, desiredTypes)
isDistinct = t.kind == tyDistinct or param.typ.kind == tyDistinct
if t.kind == tyGenericInvocation and t[0].lastSon.kind == tyDistinct:
result.state = bsGeneric
return
if isDistinct: hasDistinct = true
if param.typ.kind == tyVar:
x = newTypeS(param.typ.kind, c)
x.addSonSkipIntLit(t.baseOfDistinct(c.graph, c.idgen), c.idgen)
x.addSonSkipIntLit(getType(isDistinct, t), c.idgen)
else:
x = t.baseOfDistinct(c.graph, c.idgen)
call.add(newNodeIT(nkEmpty, fn.info, x))
x = getType(isDistinct, t)
var s = copySym(param.sym, c.idgen)
s.typ = x
s.info = param.info
call.add(newSymNode(s))
if hasDistinct:
let filter = if fn.kind in {skProc, skFunc}: {skProc, skFunc} else: {fn.kind}
var resolved = semOverloadedCall(c, call, call, filter, {})
if resolved != nil:
result = resolved[0].sym
if not compareTypes(result.typ[0], fn.typ[0], dcEqIgnoreDistinct):
result = nil
elif result.magic in {mArrPut, mArrGet}:
result.s = resolved[0].sym
result.state = bsMatch
if not compareTypes(result.s.typ[0], fn.typ[0], dcEqIgnoreDistinct, {IgnoreFlags}):
result.state = bsReturnNotMatch
elif result.s.magic in {mArrPut, mArrGet}:
# cannot borrow these magics for now
result = nil
result.state = bsNotSupported
else:
result.state = bsNoDistinct

View File

@@ -126,6 +126,7 @@ type
libs*: seq[PLib] # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode {.nimcall.}
semExprWithType*: proc (c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode {.nimcall.}
semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.}
computeRequiresInit*: proc (c: PContext, t: PType): bool {.nimcall.}
@@ -166,6 +167,10 @@ type
lastTLineInfo*: TLineInfo
sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index
inUncheckedAssignSection*: int
importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id])
skipTypes*: seq[PNode] # used to skip types between passes in type section. So far only used for inheritance, sets and generic bodies.
TBorrowState* = enum
bsNone, bsReturnNotMatch, bsNoDistinct, bsGeneric, bsNotSupported, bsMatch
template config*(c: PContext): ConfigRef = c.graph.config
@@ -430,7 +435,7 @@ proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
incl typedesc.flags, tfCheckedForDestructor
internalAssert(c.config, typ != nil)
typedesc.addSonSkipIntLit(typ, c.idgen)
let sym = newSym(skType, c.cache.idAnon, nextSymId(c.idgen), getCurrOwner(c), info,
let sym = newSym(skType, c.cache.idAnon, c.idgen, getCurrOwner(c), info,
c.config.options).linkTo(typedesc)
result = newSymNode(sym, info)

View File

@@ -54,10 +54,6 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# same as 'semExprWithType' but doesn't check for proc vars
result = semExpr(c, n, flags + {efOperand})
if result.typ != nil:
# XXX tyGenericInst here?
if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}):
#and tfUnresolved in result.typ.flags:
localError(c.config, n.info, errProcHasNoConcreteType % n.renderTree)
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
elif {efWantStmt, efAllowStmt} * flags != {}:
result.typ = newTypeS(tyVoid, c)
@@ -85,7 +81,10 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType
proc ambiguousSymChoice(c: PContext, orig, n: PNode): PNode =
let first = n[0].sym
if first.kind == skEnumField:
var foundSym: PSym = nil
if first.kind == skEnumField and
not isAmbiguous(c, first.name, {skEnumField}, foundSym) and
foundSym == first:
# choose the first resolved enum field, i.e. the latest in scope
# to mirror behavior before overloadable enums
if hintAmbiguousEnum in c.config.notes:
@@ -109,7 +108,7 @@ proc ambiguousSymChoice(c: PContext, orig, n: PNode): PNode =
result = n
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
result = semExprCheck(c, n, flags, expectedType)
result = semExprCheck(c, n, flags-{efTypeAllowed}, expectedType)
if result.typ == nil and efInTypeof in flags:
result.typ = c.voidType
elif (result.typ == nil or result.typ.kind == tyNone) and
@@ -123,6 +122,18 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType
elif result.typ.kind == tyError:
# associates the type error to the current owner
result.typ = errorType(c)
elif efTypeAllowed in flags and result.typ.kind == tyProc and
hasUnresolvedParams(result, {}):
# mirrored with semOperand but only on efTypeAllowed
let owner = result.typ.owner
let err =
# consistent error message with evaltempl/semMacroExpr
if owner != nil and owner.kind in {skTemplate, skMacro}:
errMissingGenericParamsForTemplate % n.renderTree
else:
errProcHasNoConcreteType % n.renderTree
localError(c.config, n.info, err)
result.typ = errorType(c)
else:
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
@@ -219,6 +230,9 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus =
result = convNotInRange
else:
# we use d, s here to speed up that operation a bit:
if d.kind == tyFromExpr:
result = convNotLegal
return
case cmpTypes(c, d, s)
of isNone, isGeneric:
if not compareTypes(targetTyp.skipTypes(abstractVar), srcTyp.skipTypes({tyOwned}), dcEqIgnoreDistinct):
@@ -242,7 +256,7 @@ proc isCastable(c: PContext; dst, src: PType, info: TLineInfo): bool =
if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass:
return false
let conf = c.config
if conf.selectedGC in {gcArc, gcOrc}:
if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
let d = skipTypes(dst, abstractInst)
let s = skipTypes(src, abstractInst)
if d.kind == tyRef and s.kind == tyRef and s[0].isFinal != d[0].isFinal:
@@ -261,7 +275,7 @@ proc isCastable(c: PContext; dst, src: PType, info: TLineInfo): bool =
return false
elif srcSize < 0:
return false
elif typeAllowed(dst, skParam, c) != nil:
elif typeAllowed(dst, skParam, c, {taIsCastable}) != nil:
return false
elif dst.kind == tyProc and dst.callConv == ccClosure:
return src.kind == tyProc and src.callConv == ccClosure
@@ -269,11 +283,6 @@ proc isCastable(c: PContext; dst, src: PType, info: TLineInfo): bool =
result = (dstSize >= srcSize) or
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
(skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
if result and (dstSize > srcSize):
var warnMsg = "target type is larger than source type"
warnMsg.add("\n target type: '$1' ($2)" % [$dst, if dstSize == 1: "1 byte" else: $dstSize & " bytes"])
warnMsg.add("\n source type: '$1' ($2)" % [$src, if srcSize == 1: "1 byte" else: $srcSize & " bytes"])
message(conf, info, warnCastSizes, warnMsg)
if result and src.kind == tyNil:
return dst.size <= conf.target.ptrSize
@@ -294,7 +303,7 @@ proc isOwnedSym(c: PContext; n: PNode): bool =
let s = qualifiedLookUp(c, n, {})
result = s != nil and sfSystemModule in s.owner.flags and s.name.s == "owned"
proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType = nil): PNode =
if n.len != 2:
localError(c.config, n.info, "a type conversion takes exactly one argument")
return n
@@ -341,7 +350,10 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
if n[1].kind == nkExprEqExpr and
targetType.skipTypes(abstractPtrs).kind == tyObject:
localError(c.config, n.info, "object construction uses ':', not '='")
var op = semExprWithType(c, n[1])
var op = semExprWithType(c, n[1], flags * {efDetermineType})
if op.kind == nkClosedSymChoice and op.len > 0 and
op[0].sym.kind == skEnumField: # resolves overloadedable enums
op = ambiguousSymChoice(c, n, op)
if targetType.kind != tyGenericParam and targetType.isMetaType:
let final = inferWithMetatype(c, targetType, op, true)
result.add final
@@ -353,7 +365,9 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
# here or needs to be overwritten too then.
result.add op
if targetType.kind == tyGenericParam:
if targetType.kind == tyGenericParam or
(op.typ != nil and op.typ.kind == tyFromExpr and c.inGenericContext > 0):
# expression is compiled early in a generic body
result.typ = makeTypeFromExpr(c, copyTree(result))
return result
@@ -367,7 +381,8 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
elif op.kind in {nkPar, nkTupleConstr} and targetType.kind == tyTuple:
op = fitNode(c, targetType, op, result.info)
of convNotNeedeed:
message(c.config, n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
if efNoSem2Check notin flags:
message(c.config, n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
of convNotLegal:
result = fitNode(c, result.typ, result[1], result.info)
if result == nil:
@@ -469,6 +484,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
res = t.kind == tyProc and
t.callConv == ccClosure
of "iterator":
# holdover from when `is iterator` didn't work
let t = skipTypes(t1, abstractRange)
res = t.kind == tyProc and
t.callConv == ccClosure and
@@ -496,8 +512,9 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.typ = n.typ
proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
if n.len != 3:
if n.len != 3 or n[2].kind == nkEmpty:
localError(c.config, n.info, "'is' operator takes 2 arguments")
return errorNode(c, n)
let boolType = getSysType(c.graph, n.info, tyBool)
result = n
@@ -597,7 +614,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
a.add m
changeType(m, tup[i], check)
of nkCharLit..nkUInt64Lit:
if check and n.kind != nkUInt64Lit and not sameType(n.typ, newType):
if check and n.kind != nkUInt64Lit and not sameTypeOrNil(n.typ, newType):
let value = n.intVal
if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
localError(c.config, n.info, "cannot convert " & $value &
@@ -838,7 +855,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) =
# So we need to make sure we are checking them still when in a converter call
if n[i].kind != nkHiddenAddr or isConverter:
n[i] = analyseIfAddressTaken(c, n[i].skipAddr(), isOutParam(skipTypes(t[i], abstractInst-{tyTypeDesc})))
include semmagic
proc evalAtCompileTime(c: PContext, n: PNode): PNode =
@@ -948,7 +965,8 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
if result != nil:
if result[0].kind != nkSym:
internalError(c.config, "semOverloadedCallAnalyseEffects")
if not (efDetermineType in flags and c.inGenericContext > 0):
internalError(c.config, "semOverloadedCallAnalyseEffects")
return
let callee = result[0].sym
case callee.kind
@@ -977,13 +995,39 @@ proc bracketedMacro(n: PNode): PSym =
if result.kind notin {skMacro, skTemplate}:
result = nil
proc setGenericParams(c: PContext, n: PNode) =
for i in 1..<n.len:
n[i].typ = semTypeNode(c, n[i], nil)
proc finishOperand(c: PContext, a: PNode): PNode =
if a.typ.isNil:
result = c.semOperand(c, a, {efDetermineType})
else:
result = a
# XXX tyGenericInst here?
if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}):
#and tfUnresolved in result.typ.flags:
let owner = result.typ.owner
let err =
# consistent error message with evaltempl/semMacroExpr
if owner != nil and owner.kind in {skTemplate, skMacro}:
errMissingGenericParamsForTemplate % a.renderTree
else:
errProcHasNoConcreteType % a.renderTree
localError(c.config, a.info, err)
considerGenSyms(c, result)
proc semFinishOperands(c: PContext; n: PNode; isBracketExpr = false) =
# this needs to be called to ensure that after overloading resolution every
# argument has been sem'checked
# skip the first argument for operands of `[]` since it may be an unresolved
# generic proc, which is handled in semMagic
let start = 1 + ord(isBracketExpr)
for i in start..<n.len:
n[i] = finishOperand(c, n[i])
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
if efNoSemCheck notin flags and n.typ != nil and n.typ.kind == tyError:
return errorNode(c, n)
if n.typ != nil and n.typ.kind == tyFromExpr and c.inGenericContext > 0:
return n
result = n
@@ -999,7 +1043,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType)
of skTemplate: result = semTemplateExpr(c, result, callee, flags, expectedType)
else:
semFinishOperands(c, result)
semFinishOperands(c, result, isBracketExpr = callee.magic in {mArrGet, mArrPut})
activate(c, result)
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
@@ -1039,7 +1083,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
if s != nil:
setGenericParams(c, n[0])
return semDirectOp(c, n, flags, expectedType)
elif isSymChoice(n[0]):
elif isSymChoice(n[0]) and nfDotField notin n.flags:
# overloaded generic procs e.g. newSeq[int] can end up here
return semDirectOp(c, n, flags, expectedType)
@@ -1048,7 +1092,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
t = skipTypes(n[0].typ, abstractInst+{tyOwned}-{tyTypeDesc, tyDistinct})
if t != nil and t.kind == tyTypeDesc:
if n.len == 1: return semObjConstr(c, n, flags, expectedType)
return semConv(c, n)
return semConv(c, n, flags)
let nOrig = n.copyTree
semOpAux(c, n)
@@ -1085,7 +1129,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
msg.addDeclaredLocMaybe(c.config, typ)
localError(c.config, n.info, msg)
return errorNode(c, n)
result = nil
else:
result = m.call
instGenericConvertersSons(c, result, m)
@@ -1228,7 +1271,7 @@ proc readTypeParameter(c: PContext, typ: PType,
# This seems semantically correct and then we'll be able
# to return the section symbol directly here
let foundType = makeTypeDesc(c, def[2].typ)
return newSymNode(copySym(def[0].sym, nextSymId c.idgen).linkTo(foundType), info)
return newSymNode(copySym(def[0].sym, c.idgen).linkTo(foundType), info)
of nkConstSection:
for def in statement:
@@ -1253,11 +1296,12 @@ proc readTypeParameter(c: PContext, typ: PType,
return c.graph.emptyNode
else:
let foundTyp = makeTypeDesc(c, rawTyp)
return newSymNode(copySym(tParam.sym, nextSymId c.idgen).linkTo(foundTyp), info)
return newSymNode(copySym(tParam.sym, c.idgen).linkTo(foundTyp), info)
return nil
proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
assert n.kind in nkIdentKinds + {nkDotExpr}
let s = getGenSym(c, sym)
case s.kind
of skConst:
@@ -1292,9 +1336,8 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
else:
result = newSymNode(s, n.info)
of skMacro, skTemplate:
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
(n.kind notin nkCallKinds and s.requiredParams > 0) or
sfCustomPragma in sym.flags:
# check if we cannot use alias syntax (no required args or generic params)
if sfNoalias in s.flags:
let info = getCallLineInfo(n)
markUsed(c, info, s)
onUse(info, s)
@@ -1352,6 +1395,12 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
markUsed(c, n.info, s)
onUse(n.info, s)
result = newSymNode(s, n.info)
of skModule:
# make sure type is None and not nil for discard checking
if efWantStmt in flags: s.typ = newTypeS(tyNone, c)
markUsed(c, n.info, s)
onUse(n.info, s)
result = newSymNode(s, n.info)
else:
let info = getCallLineInfo(n)
#if efInCall notin flags:
@@ -1508,7 +1557,9 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
flags.incl efCannotBeDotCall
proc dotTransformation(c: PContext, n: PNode): PNode =
if isSymChoice(n[1]):
if isSymChoice(n[1]) or
# generics usually leave field names as symchoices, but not types
(n[1].kind == nkSym and n[1].sym.kind == skType):
result = newNodeI(nkDotCall, n.info)
result.add n[1]
result.add copyTree(n[0])
@@ -1581,9 +1632,8 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.add(x[0])
return
checkMinSonsLen(n, 2, c.config)
# make sure we don't evaluate generic macros/templates
n[0] = semExprWithType(c, n[0],
{efNoEvaluateGeneric})
# signal that generic parameters may be applied after
n[0] = semExprWithType(c, n[0], {efNoEvaluateGeneric})
var arr = skipTypes(n[0].typ, {tyGenericInst, tyUserTypeClassInst, tyOwned,
tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink})
if arr.kind == tyStatic:
@@ -1633,7 +1683,10 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
{tyInt..tyInt64}:
let idx = getOrdValue(n[1])
if idx >= 0 and idx < arr.len: n.typ = arr[toInt(idx)]
else: localError(c.config, n.info, "invalid index value for tuple subscript")
else:
localError(c.config, n.info,
"invalid index $1 in subscript for tuple of length $2" %
[$idx, $arr.len])
result = n
else:
result = nil
@@ -1786,6 +1839,39 @@ proc goodLineInfo(arg: PNode): TLineInfo =
else:
arg.info
proc makeTupleAssignments(c: PContext; n: PNode): PNode =
## expand tuple unpacking assignment into series of assignments
##
## mirrored with semstmts.makeVarTupleSection
let lhs = n[0]
let value = semExprWithType(c, n[1], {efTypeAllowed})
if value.typ.kind != tyTuple:
localError(c.config, n[1].info, errTupleUnpackingTupleExpected %
[typeToString(value.typ, preferDesc)])
elif lhs.len != value.typ.len:
localError(c.config, n.info, errTupleUnpackingDifferentLengths %
[$lhs.len, typeToString(value.typ, preferDesc), $value.typ.len])
result = newNodeI(nkStmtList, n.info)
let temp = newSym(skTemp, getIdent(c.cache, "tmpTupleAsgn"), c.idgen, getCurrOwner(c), n.info)
temp.typ = value.typ
temp.flags.incl(sfGenSym)
var v = newNodeI(nkLetSection, value.info)
let tempNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart[0] = tempNode
vpart[1] = c.graph.emptyNode
vpart[2] = value
v.add vpart
result.add(v)
for i in 0..<lhs.len:
if lhs[i].kind == nkIdent and lhs[i].ident.id == ord(wUnderscore):
# skip _ assignments if we are using a temp as they are already evaluated
discard
else:
result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempNode, i))
proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
checkSonsLen(n, 2, c.config)
var a = n[0]
@@ -1814,7 +1900,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
result.add(n[1])
if mode == noOverloadedSubscript:
bracketNotFoundError(c, result)
return n
return errorNode(c, n)
else:
result = semExprNoType(c, result)
return result
@@ -1824,11 +1910,11 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
result.add(n[1])
return semExprNoType(c, result)
of nkPar, nkTupleConstr:
if a.len >= 2:
if a.len >= 2 or a.kind == nkTupleConstr:
# unfortunately we need to rewrite ``(x, y) = foo()`` already here so
# that overloading of the assignment operator still works. Usually we
# prefer to do these rewritings in transf.nim:
return semStmt(c, lowerTupleUnpackingForAsgn(c.graph, n, c.idgen, c.p.owner), {})
return semStmt(c, makeTupleAssignments(c, n), {})
else:
a = semExprWithType(c, a, {efLValue})
else:
@@ -2077,10 +2163,11 @@ proc expectString(c: PContext, n: PNode): string =
if n.kind in nkStrKinds:
return n.strVal
else:
result = ""
localError(c.config, n.info, errStringLiteralExpected)
proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym =
result = newSym(kind, c.cache.idAnon, nextSymId c.idgen, getCurrOwner(c), info)
result = newSym(kind, c.cache.idAnon, c.idgen, getCurrOwner(c), info)
proc semExpandToAst(c: PContext, n: PNode): PNode =
let macroCall = n[1]
@@ -2211,8 +2298,9 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[0], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode)
for i in 1..<ids.len:
let typ = semExprWithType(c, quotes[i+1], {}).typ
if tfTriggersCompileTime notin typ.flags and typ.kind != tyTypeDesc:
let exp = semExprWithType(c, quotes[i+1], {})
let typ = exp.typ
if tfTriggersCompileTime notin typ.flags and typ.kind != tyStatic and exp.kind == nkSym and exp.sym.kind notin routineKinds + {skType}:
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[i], newNodeIT(nkType, n.info, typ), c.graph.emptyNode)
else:
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[i], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode)
@@ -2480,9 +2568,10 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
# If semCheck is set to false, ``when`` will return the verbatim AST of
# the correct branch. Otherwise the AST will be passed through semStmt.
result = nil
let flags = if semCheck: {efWantStmt} else: {}
template setResult(e: untyped) =
if semCheck: result = semExpr(c, e) # do not open a new scope!
if semCheck: result = semExpr(c, e, flags) # do not open a new scope!
else: result = e
# Check if the node is "when nimvm"
@@ -2508,7 +2597,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
checkSonsLen(it, 2, c.config)
if whenNimvm:
if semCheck:
it[1] = semExpr(c, it[1])
it[1] = semExpr(c, it[1], flags)
typ = commonType(c, typ, it[1].typ)
result = n # when nimvm is not elimited until codegen
else:
@@ -2524,7 +2613,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
checkSonsLen(it, 1, c.config)
if result == nil or whenNimvm:
if semCheck:
it[0] = semExpr(c, it[0])
it[0] = semExpr(c, it[0], flags)
typ = commonType(c, typ, it[0].typ)
if result == nil:
result = it[0]
@@ -2556,34 +2645,39 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
# only semantic checking for all elements, later type checking:
var typ: PType = nil
for i in 0..<n.len:
let doSetType = typ == nil
if isRange(n[i]):
checkSonsLen(n[i], 3, c.config)
n[i][1] = semExprWithType(c, n[i][1], {efTypeAllowed}, expectedElementType)
n[i][2] = semExprWithType(c, n[i][2], {efTypeAllowed}, expectedElementType)
if typ == nil:
if doSetType:
typ = skipTypes(n[i][1].typ,
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
if expectedElementType == nil:
expectedElementType = typ
n[i].typ = n[i][2].typ # range node needs type too
elif n[i].kind == nkRange:
# already semchecked
if typ == nil:
if doSetType:
typ = skipTypes(n[i][0].typ,
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
if expectedElementType == nil:
expectedElementType = typ
else:
n[i] = semExprWithType(c, n[i], {efTypeAllowed}, expectedElementType)
if typ == nil:
if doSetType:
typ = skipTypes(n[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
if expectedElementType == nil:
expectedElementType = typ
if not isOrdinalType(typ, allowEnumWithHoles=true):
localError(c.config, n.info, errOrdinalTypeExpected % typeToString(typ, preferDesc))
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
elif lengthOrd(c.config, typ) > MaxSetElements:
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
if doSetType:
if not isOrdinalType(typ, allowEnumWithHoles=true):
localError(c.config, n.info, errOrdinalTypeExpected % typeToString(typ, preferDesc))
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
elif isIntLit(typ):
# set of int literal, use a default range smaller than the max range
typ = makeRangeType(c, 0, DefaultSetElements-1, n.info)
elif lengthOrd(c.config, typ) > MaxSetElements:
message(c.config, n.info, warnAboveMaxSizeSet, "type '" &
typeToString(typ, preferDesc) & "' is too big to be a `set` element, " &
"assuming a range of 0.." & $(MaxSetElements - 1) &
", explicitly write this range to get rid of warning")
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
if expectedElementType == nil:
expectedElementType = typ
addSonSkipIntLit(result.typ, typ, c.idgen)
for i in 0..<n.len:
var m: PNode
@@ -2826,6 +2920,18 @@ proc asBracketExpr(c: PContext; n: PNode): PNode =
return result
return nil
proc isOpenArraySym(x: PNode): bool =
var x = x
while true:
case x.kind
of {nkAddr, nkHiddenAddr}:
x = x[0]
of {nkHiddenStdConv, nkHiddenDeref}:
x = x[1]
else:
break
result = x.kind == nkSym
proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode) =
# This takes care of complicated signatures such as:
# proc foo(a: int, b = a)
@@ -2846,8 +2952,11 @@ proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode)
if defExpr.kind == nkSym and defExpr.sym.kind == skParam and defExpr.sym.owner == call[0].sym:
let paramPos = defExpr.sym.position + 1
if call[paramPos].kind != nkSym:
let hoistedVarSym = newSym(skLet, getIdent(c.graph.cache, genPrefix), nextSymId c.idgen,
if call[paramPos].skipAddr.kind != nkSym and not (
skipTypes(call[paramPos].typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
isOpenArraySym(call[paramPos])
):
let hoistedVarSym = newSym(skLet, getIdent(c.graph.cache, genPrefix), c.idgen,
c.p.owner, letSection.info, c.p.owner.options)
hoistedVarSym.typ = call[paramPos].typ
@@ -2872,7 +2981,7 @@ proc getNilType(c: PContext): PType =
result.align = c.config.target.ptrSize.int16
c.nilTypeCache = result
proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym): PNode =
proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym; flags: TExprFlags): PNode =
var o: TOverloadIter
var i = 0
var a = initOverloadIter(o, c, n)
@@ -2885,7 +2994,7 @@ proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym): PNode =
if i <= 1:
if sfGenSym notin s.flags:
result = newSymNode(s, info)
markUsed(c, info, s)
markUsed(c, info, s, efInCall notin flags)
onUse(info, s)
else:
result = n
@@ -2960,6 +3069,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
else:
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
s = qualifiedLookUp(c, n, checks)
if s == nil:
return
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
case s.kind
of skProc, skFunc, skMethod, skConverter, skIterator:
@@ -2973,7 +3084,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if optOwnedRefs in c.config.globalOptions:
result.typ = makeVarType(c, result.typ, tyOwned)
of skEnumField:
result = enumFieldSymChoice(c, n, s)
result = enumFieldSymChoice(c, n, s, flags)
else:
result = semSym(c, n, s, flags)
if expectedType != nil and isSymChoice(result):
@@ -2981,9 +3092,32 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if result.kind == nkSym:
result = semSym(c, result, result.sym, flags)
of nkSym:
let s = n.sym
if nfOpenSym in n.flags:
let id = newIdentNode(s.name, n.info)
c.isAmbiguous = false
let s2 = qualifiedLookUp(c, id, {})
if s2 != nil and s2 != s and not c.isAmbiguous:
# only consider symbols defined under current proc:
var o = s2.owner
while o != nil:
if o == c.p.owner:
if genericsOpenSym in c.features:
result = semExpr(c, id, flags, expectedType)
return
else:
message(c.config, n.info, warnGenericsIgnoredInjection,
"a new symbol '" & s.name.s & "' has been injected during " &
"instantiation of " & c.p.owner.name.s & ", " &
"however " & getSymRepr(c.config, s) & " captured at " &
"the proc declaration will be used instead; " &
"either enable --experimental:genericsOpenSym to use the " &
"injected symbol or `bind` this captured symbol explicitly")
break
o = o.owner
# because of the changed symbol binding, this does not mean that we
# don't have to check the symbol for semantics here again!
result = semSym(c, n, n.sym, flags)
result = semSym(c, n, s, flags)
of nkEmpty, nkNone, nkCommentStmt, nkType:
discard
of nkNilLit:
@@ -3001,7 +3135,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
expected.kind in {tyInt..tyInt64,
tyUInt..tyUInt64,
tyFloat..tyFloat128}):
result.typ = expected
if expected.kind in {tyFloat..tyFloat128}:
n.transitionIntToFloatKind(nkFloatLit)
changeType(c, result, expectedType, check=true)
@@ -3066,8 +3199,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
c.isAmbiguous = false
var s = qualifiedLookUp(c, n[0], mode)
if s != nil:
#if c.config.cmd == cmdNimfix and n[0].kind == nkDotExpr:
# pretty.checkUse(n[0][1].info, s)
case s.kind
of skMacro, skTemplate:
result = semDirectOp(c, n, flags, expectedType)
@@ -3075,7 +3206,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
# XXX think about this more (``set`` procs)
let ambig = c.isAmbiguous
if not (n[0].kind in {nkClosedSymChoice, nkOpenSymChoice, nkIdent} and ambig) and n.len == 2:
result = semConv(c, n, expectedType)
result = semConv(c, n, flags, expectedType)
elif ambig and n.len == 1:
errorUseQualifier(c, n.info, s)
elif n.len == 1:
@@ -3245,7 +3376,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
of nkDefer:
if c.currentScope == c.topLevelScope:
localError(c.config, n.info, "defer statement not supported at top level")
openScope(c)
n[0] = semExpr(c, n[0])
closeScope(c)
if not n[0].typ.isEmptyType and not implicitlyDiscardable(n[0]):
localError(c.config, n.info, "'defer' takes a 'void' expression")
#localError(c.config, n.info, errGenerated, "'defer' not allowed in this context")

View File

@@ -109,7 +109,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
var trueSymbol = systemModuleSym(c.graph, getIdent(c.cache, "true"))
if trueSymbol == nil:
localError(c.config, n.info, "system needs: 'true'")
trueSymbol = newSym(skUnknown, getIdent(c.cache, "true"), nextSymId c.idgen, getCurrOwner(c), n.info)
trueSymbol = newSym(skUnknown, getIdent(c.cache, "true"), c.idgen, getCurrOwner(c), n.info)
trueSymbol.typ = getSysType(c.graph, n.info, tyBool)
result[0] = newSymNode(trueSymbol, n.info)

View File

@@ -230,7 +230,13 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
of mDivF64:
result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
of mIsNil: result = newIntNodeT(toInt128(ord(a.kind == nkNilLit)), n, idgen, g)
of mIsNil:
let val = a.kind == nkNilLit or
# nil closures have the value (nil, nil)
(a.typ != nil and skipTypes(a.typ, abstractRange).kind == tyProc and
a.kind == nkTupleConstr and a.len == 2 and
a[0].kind == nkNilLit and a[1].kind == nkNilLit)
result = newIntNodeT(toInt128(ord(val)), n, idgen, g)
of mLtI, mLtB, mLtEnum, mLtCh:
result = newIntNodeT(toInt128(ord(getOrdValue(a) < getOrdValue(b))), n, idgen, g)
of mLeI, mLeB, mLeEnum, mLeCh:

View File

@@ -50,48 +50,49 @@ proc semGenericStmtScope(c: PContext, n: PNode,
result = semGenericStmt(c, n, flags, ctx)
closeScope(c)
template macroToExpand(s): untyped =
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfAllUntyped in s.flags)
template macroToExpandSym(s): untyped =
sfCustomPragma notin s.flags and s.kind in {skMacro, skTemplate} and
(s.typ.len == 1) and not fromDotExpr
template isMixedIn(sym): bool =
let s = sym
s.name.id in ctx.toMixin or (withinConcept in flags and
s.magic == mNone and
s.kind in OverloadableSyms)
template canOpenSym(s): bool =
{withinMixin, withinConcept} * flags == {withinMixin} and s.id notin ctx.toBind
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
ctx: var GenericCtx; flags: TSemGenericFlags,
fromDotExpr=false): PNode =
semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
incl(s.flags, sfUsed)
template maybeDotChoice(c: PContext, n: PNode, s: PSym, fromDotExpr: bool) =
if fromDotExpr:
result = symChoice(c, n, s, scForceOpen)
if result.kind == nkOpenSymChoice and result.len == 1:
result.transitionSonsKind(nkClosedSymChoice)
else:
result = symChoice(c, n, s, scOpen)
if result.kind == nkSym and canOpenSym(result.sym):
result.flags.incl nfOpenSym
result.typ = nil
case s.kind
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
result = n
of skProc, skFunc, skMethod, skIterator, skConverter, skModule:
result = symChoice(c, n, s, scOpen)
of skTemplate:
if macroToExpandSym(s):
of skProc, skFunc, skMethod, skIterator, skConverter, skModule, skEnumField:
maybeDotChoice(c, n, s, fromDotExpr)
of skTemplate, skMacro:
# alias syntax, see semSym for skTemplate, skMacro
if sfNoalias notin s.flags and not fromDotExpr:
onUse(n.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
case s.kind
of skTemplate: result = semTemplateExpr(c, n, s, {efNoSemCheck})
of skMacro: result = semMacroExpr(c, n, n, s, {efNoSemCheck})
else: discard # unreachable
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, {}, ctx)
discard c.friendModules.pop()
else:
result = symChoice(c, n, s, scOpen)
of skMacro:
if macroToExpandSym(s):
onUse(n.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, {}, ctx)
discard c.friendModules.pop()
else:
result = symChoice(c, n, s, scOpen)
maybeDotChoice(c, n, s, fromDotExpr)
of skGenericParam:
if s.typ != nil and s.typ.kind == tyStatic:
if s.typ.n != nil:
@@ -100,6 +101,9 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = n
else:
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
result.flags.incl nfOpenSym
result.typ = nil
onUse(n.info, s)
of skParam:
result = n
@@ -108,13 +112,17 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
if (s.typ != nil) and
(s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
result.flags.incl nfOpenSym
result.typ = nil
else:
result = n
onUse(n.info, s)
of skEnumField:
result = symChoice(c, n, s, scOpen)
else:
result = newSymNode(s, n.info)
if canOpenSym(result.sym):
result.flags.incl nfOpenSym
result.typ = nil
onUse(n.info, s)
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
@@ -122,7 +130,7 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
result = n
let ident = considerQuotedIdent(c, n)
var amb = false
var s = searchInScopes(c, ident, amb).skipAlias(n, c.config)
var s = searchInScopes(c, ident, amb)
if s == nil:
s = strTableGet(c.pureEnumFields, ident)
#if s != nil and contains(c.ambiguousSymbols, s.id):
@@ -145,7 +153,8 @@ proc newDot(n, b: PNode): PNode =
result.add(b)
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var GenericCtx; isMacro: var bool): PNode =
ctx: var GenericCtx; isMacro: var bool;
inCall = false): PNode =
assert n.kind == nkDotExpr
semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
@@ -153,28 +162,40 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
var s = qualifiedLookUp(c, n, luf)
if s != nil:
isMacro = s.kind in {skTemplate, skMacro}
result = semGenericStmtSymbol(c, n, s, ctx, flags)
else:
n[0] = semGenericStmt(c, n[0], flags, ctx)
result = n
let n = n[1]
let ident = considerQuotedIdent(c, n)
var candidates = searchInScopesFilterBy(c, ident, routineKinds) # .skipAlias(n, c.config)
# could be type conversion if like a.T and not a.T()
let symKinds = if inCall: routineKinds else: routineKinds+{skType}
var candidates = searchInScopesFilterBy(c, ident, symKinds)
if candidates.len > 0:
let s = candidates[0] # XXX take into account the other candidates!
isMacro = s.kind in {skTemplate, skMacro}
if withinBind in flags or s.id in ctx.toBind:
result = newDot(result, symChoice(c, n, s, scClosed))
if s.kind == skType: # don't put types in sym choice
result = newDot(result, semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true))
else:
result = newDot(result, symChoice(c, n, s, scClosed))
elif s.isMixedIn:
result = newDot(result, symChoice(c, n, s, scForceOpen))
else:
if s.kind == skType and candidates.len > 1:
var ambig = false
let s2 = searchInScopes(c, ident, ambig)
if ambig:
# this is a type conversion like a.T where T is ambiguous with
# other types or routines
# in regular code, this never considers a type conversion and
# skips to routine overloading
# so symchoices are used which behave similarly with type symbols
result = newDot(result, symChoice(c, n, s, scForceOpen))
return
let syms = semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true)
if syms.kind == nkSym:
let choice = symChoice(c, n, s, scForceOpen)
choice.transitionSonsKind(nkClosedSymChoice)
result = newDot(result, choice)
else:
result = newDot(result, syms)
result = newDot(result, syms)
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
let s = newSymS(skUnknown, getIdentNode(c, n), c)
@@ -182,6 +203,18 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
styleCheckDef(c, n.info, s, kind)
onDef(n.info, s)
proc addTempDeclToIdents(c: PContext; n: PNode; kind: TSymKind; inCall: bool) =
case n.kind
of nkIdent:
if inCall:
addTempDecl(c, n, kind)
of nkCallKinds:
for s in n:
addTempDeclToIdents(c, s, kind, true)
else:
for s in n:
addTempDeclToIdents(c, s, kind, inCall)
proc semGenericStmt(c: PContext, n: PNode,
flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
result = n
@@ -245,21 +278,14 @@ proc semGenericStmt(c: PContext, n: PNode,
else: scOpen
let sc = symChoice(c, fn, s, whichChoice)
case s.kind
of skMacro:
if macroToExpand(s) and sc.safeLen <= 1:
of skMacro, skTemplate:
# unambiguous macros/templates are expanded if all params are untyped
if sfAllUntyped in s.flags and sc.safeLen <= 1:
onUse(fn.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, flags, ctx)
discard c.friendModules.pop()
else:
n[0] = sc
result = n
mixinContext = true
of skTemplate:
if macroToExpand(s) and sc.safeLen <= 1:
onUse(fn.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck})
case s.kind
of skMacro: result = semMacroExpr(c, n, n, s, {efNoSemCheck})
of skTemplate: result = semTemplateExpr(c, n, s, {efNoSemCheck})
else: discard # unreachable
c.friendModules.add(s.owner.getModule)
result = semGenericStmt(c, result, flags, ctx)
discard c.friendModules.pop()
@@ -296,7 +322,7 @@ proc semGenericStmt(c: PContext, n: PNode,
onUse(fn.info, s)
first = 1
elif fn.kind == nkDotExpr:
result[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
result[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext, inCall = true)
first = 1
# Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
@@ -361,7 +387,9 @@ proc semGenericStmt(c: PContext, n: PNode,
var a = n[i]
checkMinSonsLen(a, 1, c.config)
for j in 0..<a.len-1:
a[j] = semGenericStmt(c, a[j], flags, ctx)
a[j] = semGenericStmt(c, a[j], flags+{withinMixin}, ctx)
addTempDeclToIdents(c, a[j], skVar, false)
a[^1] = semGenericStmtScope(c, a[^1], flags, ctx)
closeScope(c)
of nkForStmt, nkParForStmt:
@@ -458,8 +486,47 @@ proc semGenericStmt(c: PContext, n: PNode,
of nkIdent: a = n[i]
else: illFormedAst(n, c.config)
addDecl(c, newSymS(skUnknown, getIdentNode(c, a), c))
of nkObjectTy, nkTupleTy, nkTupleClassTy:
discard
of nkTupleTy:
for i in 0..<n.len:
var a = n[i]
case a.kind:
of nkCommentStmt, nkNilLit, nkSym, nkEmpty: continue
of nkIdentDefs:
checkMinSonsLen(a, 3, c.config)
a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
a[^1] = semGenericStmt(c, a[^1], flags, ctx)
for j in 0..<a.len-2:
addTempDecl(c, getIdentNode(c, a[j]), skField)
else:
illFormedAst(a, c.config)
of nkObjectTy:
if n.len > 0:
openScope(c)
for i in 0..<n.len:
result[i] = semGenericStmt(c, n[i], flags, ctx)
closeScope(c)
of nkRecList:
for i in 0..<n.len:
var a = n[i]
case a.kind:
of nkCommentStmt, nkNilLit, nkSym, nkEmpty: continue
of nkIdentDefs:
checkMinSonsLen(a, 3, c.config)
a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
a[^1] = semGenericStmt(c, a[^1], flags, ctx)
for j in 0..<a.len-2:
addTempDecl(c, getIdentNode(c, a[j]), skField)
of nkRecCase, nkRecWhen:
n[i] = semGenericStmt(c, a, flags, ctx)
else:
illFormedAst(a, c.config)
of nkRecCase:
checkSonsLen(n[0], 3, c.config)
n[0][^2] = semGenericStmt(c, n[0][^2], flags+{withinTypeDesc}, ctx)
n[0][^1] = semGenericStmt(c, n[0][^1], flags, ctx)
addTempDecl(c, getIdentNode(c, n[0][0]), skField)
for i in 1..<n.len:
n[i] = semGenericStmt(c, n[i], flags, ctx)
of nkFormalParams:
checkMinSonsLen(n, 1, c.config)
for i in 1..<n.len:
@@ -484,7 +551,7 @@ proc semGenericStmt(c: PContext, n: PNode,
flags, ctx)
if n[paramsPos].kind != nkEmpty:
if n[paramsPos][0].kind != nkEmpty:
addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextSymId c.idgen, nil, n.info))
addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), c.idgen, nil, n.info))
n[paramsPos] = semGenericStmt(c, n[paramsPos], flags, ctx)
n[pragmasPos] = semGenericStmt(c, n[pragmasPos], flags, ctx)
var body: PNode

View File

@@ -45,7 +45,7 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym
var q = a.sym
if q.typ.kind in {tyTypeDesc, tyGenericParam, tyStatic, tyConcept}+tyTypeClasses:
let symKind = if q.typ.kind == tyStatic: skConst else: skType
var s = newSym(symKind, q.name, nextSymId(c.idgen), getCurrOwner(c), q.info)
var s = newSym(symKind, q.name, c.idgen, getCurrOwner(c), q.info)
s.flags.incl {sfUsed, sfFromGeneric}
var t = PType(idTableGet(pt, q.typ))
if t == nil:
@@ -60,6 +60,12 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym
elif t.kind in {tyGenericParam, tyConcept}:
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
t = errorType(c)
elif isUnresolvedStatic(t) and c.inGenericContext == 0 and
c.matchedConcept == nil:
# generic/concept type bodies will try to instantiate static values but
# won't actually use them
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
t = errorType(c)
elif t.kind == tyGenericInvocation:
#t = instGenericContainer(c, a, t)
t = generateTypeInstance(c, pt, a, t)
@@ -100,7 +106,7 @@ proc freshGenSyms(c: PContext; n: PNode, owner, orig: PSym, symMap: var TIdTable
n.sym = x
elif s.owner == nil or s.owner.kind == skPackage:
#echo "copied this ", s.name.s
x = copySym(s, nextSymId c.idgen)
x = copySym(s, c.idgen)
x.owner = owner
idTablePut(symMap, s, x)
n.sym = x
@@ -128,7 +134,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
freshGenSyms(c, b, result, orig, symMap)
if sfBorrow notin orig.flags:
if sfBorrow notin orig.flags:
# We do not want to generate a body for generic borrowed procs.
# As body is a sym to the borrowed proc.
let resultType = # todo probably refactor it into a function
@@ -193,7 +199,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
var param: PSym
template paramSym(kind): untyped =
newSym(kind, genParam.sym.name, nextSymId c.idgen, genericTyp.sym, genParam.sym.info)
newSym(kind, genParam.sym.name, c.idgen, genericTyp.sym, genParam.sym.info)
if genParam.kind == tyStatic:
param = paramSym skConst
@@ -263,7 +269,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
internalAssert c.config, originalParams[i].kind == nkSym
let oldParam = originalParams[i].sym
let param = copySym(oldParam, nextSymId c.idgen)
let param = copySym(oldParam, c.idgen)
param.owner = prc
param.typ = result[i]
@@ -272,9 +278,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
# call head symbol, because this leads to infinite recursion.
if oldParam.ast != nil:
var def = oldParam.ast.copyTree
if def.kind == nkCall:
if def.kind in nkCallKinds:
for i in 1..<def.len:
def[i] = replaceTypeVarsN(cl, def[i])
def[i] = replaceTypeVarsN(cl, def[i], 1)
def = semExprWithType(c, def)
if def.referencesAnotherParam(getCurrOwner(c)):
@@ -340,7 +346,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
c.matchedConcept = nil
let oldScope = c.currentScope
while not isTopLevel(c): c.currentScope = c.currentScope.parent
result = copySym(fn, nextSymId c.idgen)
result = copySym(fn, c.idgen)
incl(result.flags, sfFromGeneric)
result.owner = fn
result.ast = n
@@ -352,7 +358,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
openScope(c)
let gp = n[genericParamsPos]
internalAssert c.config, gp.kind == nkGenericParams
if gp.kind != nkGenericParams:
# bug #22137
globalError(c.config, info, "generic instantiation too nested")
n[namePos] = newSymNode(result)
pushInfoContext(c.config, info, fn.detailedInfo)
var entry = TInstantiation.new
@@ -362,10 +370,13 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
# see ttypeor.nim test.
var i = 0
newSeq(entry.concreteTypes, fn.typ.len+gp.len-1)
# let param instantiation know we are in a concept for unresolved statics:
c.matchedConcept = oldMatchedConcept
for s in instantiateGenericParamList(c, gp, pt):
addDecl(c, s)
entry.concreteTypes[i] = s.typ
inc i
c.matchedConcept = nil
pushProcCon(c, result)
instantiateProcType(c, pt, result, info)
for j in 1..<result.typ.len:
@@ -388,8 +399,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
pragma(c, result, n[pragmasPos], allRoutinePragmas)
if isNil(n[bodyPos]):
n[bodyPos] = copyTree(getBody(c.graph, fn))
if c.inGenericContext == 0:
instantiateBody(c, n, fn.typ.n, result, fn)
instantiateBody(c, n, fn.typ.n, result, fn)
sideEffectsCheck(c, result)
if result.magic notin {mSlice, mTypeOf}:
# 'toOpenArray' is special and it is allowed to return 'openArray':

View File

@@ -21,7 +21,7 @@ proc addDefaultFieldForNew(c: PContext, n: PNode): PNode =
asgnExpr.typ = typ
var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0]
while true:
asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n)
asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n, false)
let base = t[0]
if base == nil:
break
@@ -66,7 +66,7 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
x[0] = newIdentNode(getIdent(c.cache, "[]"), n.info)
bracketNotFoundError(c, x)
#localError(c.config, n.info, "could not resolve: " & $n)
result = n
result = errorNode(c, n)
proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
# rewrite `[]=`(a, i, x) back to ``a[i] = x``.
@@ -210,6 +210,15 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
arg = arg.base.skipTypes(skippedTypes + {tyGenericInst})
if not rec: break
result = getTypeDescNode(c, arg, operand.owner, traitCall.info)
of "rangeBase":
# return the base type of a range type
var arg = operand.skipTypes({tyGenericInst})
assert arg.kind == tyRange
result = getTypeDescNode(c, arg.base, operand.owner, traitCall.info)
of "isCyclic":
var operand = operand.skipTypes({tyGenericInst})
let isCyclic = canFormAcycle(c.graph, operand)
result = newIntNodeT(toInt128(ord(isCyclic)), traitCall, c.idgen, c.graph)
else:
localError(c.config, traitCall.info, "unknown trait: " & s)
result = newNodeI(nkEmpty, traitCall.info)
@@ -415,14 +424,14 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym
#if n.kind == nkDerefExpr and sameType(n[0].typ, old):
# result =
result = copySym(orig, nextSymId c.idgen)
result = copySym(orig, c.idgen)
result.info = info
result.flags.incl sfFromGeneric
result.owner = orig
let origParamType = orig.typ[1]
let newParamType = makeVarType(result, origParamType.skipTypes(abstractPtrs), c.idgen)
let oldParam = orig.typ.n[1].sym
let newParam = newSym(skParam, oldParam.name, nextSymId c.idgen, result, result.info)
let newParam = newSym(skParam, oldParam.name, c.idgen, result, result.info)
newParam.typ = newParamType
# proc body:
result.ast = transform(c, orig.ast, origParamType, newParamType, oldParam, newParam)
@@ -488,8 +497,8 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
getAttachedOp(c.graph, t, attachedDestructor).owner == fin:
discard "already turned this one into a finalizer"
else:
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), nextSymId c.idgen, fin.owner, fin.info)
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, nextSymId c.idgen))
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), c.idgen, fin.owner, fin.info)
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, c.idgen))
selfSymNode.typ = fin.typ[1]
wrapperSym.flags.incl sfUsed
@@ -510,12 +519,16 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
selfPtr.add transFormedSym.ast[bodyPos][1]
selfPtr.typ = selfSymbolType
transFormedSym.ast[bodyPos][1] = c.semExpr(c, selfPtr)
bindTypeHook(c, transFormedSym, n, attachedDestructor)
# TODO: suppress var destructor warnings; if newFinalizer is not
# TODO: deprecated, try to implement plain T destructor
bindTypeHook(c, transFormedSym, n, attachedDestructor, suppressVarDestructorWarning = true)
result = addDefaultFieldForNew(c, n)
proc semPrivateAccess(c: PContext, n: PNode): PNode =
let t = n[1].typ[0].toObjectFromRefPtrGeneric
c.currentScope.allowPrivateAccess.add t.sym
if t.kind == tyObject:
assert t.sym != nil
c.currentScope.allowPrivateAccess.add t.sym
result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid))
proc checkDefault(c: PContext, n: PNode): PNode =
@@ -598,12 +611,28 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
let op = getAttachedOp(c.graph, t, attachedDestructor)
if op != nil:
result[0] = newSymNode(op)
if op.typ != nil and op.typ.len == 2 and op.typ[1].kind != tyVar:
if n[1].kind == nkSym and n[1].sym.kind == skParam and
n[1].typ.kind == tyVar:
result[1] = genDeref(n[1])
else:
result[1] = skipAddr(n[1])
of mTrace:
result = n
let t = n[1].typ.skipTypes(abstractVar)
let op = getAttachedOp(c.graph, t, attachedTrace)
if op != nil:
result[0] = newSymNode(op)
of mWasMoved:
result = n
let t = n[1].typ.skipTypes(abstractVar)
let op = getAttachedOp(c.graph, t, attachedWasMoved)
if op != nil:
result[0] = newSymNode(op)
let addrExp = newNodeIT(nkHiddenAddr, result[1].info, makePtrType(c, t))
addrExp.add result[1]
result[1] = addrExp
of mUnown:
result = semUnown(c, n)
of mExists, mForall:
@@ -620,7 +649,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mDefault:
result = checkDefault(c, n)
let typ = result[^1].typ.skipTypes({tyTypeDesc})
let defaultExpr = defaultNodeField(c, result[^1], typ)
let defaultExpr = defaultNodeField(c, result[^1], typ, false)
if defaultExpr != nil:
result = defaultExpr
of mZeroDefault:
@@ -639,5 +668,10 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result = n
if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and expectedType.kind == tySequence and result.typ[0].kind == tyEmpty:
result.typ = expectedType # type inference for empty sequence # bug #21377
of mEnsureMove:
result = n
if n[1].kind in {nkStmtListExpr, nkBlockExpr,
nkIfExpr, nkCaseStmt, nkTryStmt}:
localError(c.config, n.info, "Nested expressions cannot be moved: '" & $n[1] & "'")
else:
result = n

View File

@@ -21,6 +21,7 @@ type
# set this to true while visiting
# parent types.
missingFields: seq[PSym] # Fields that the user failed to specify
checkDefault: bool # Checking defaults
InitStatus = enum # This indicates the result of object construction
initUnknown
@@ -86,10 +87,13 @@ proc semConstrField(c: PContext, flags: TExprFlags,
var initValue = semExprFlagDispatched(c, assignment[1], flags, field.typ)
if initValue != nil:
initValue = fitNodeConsiderViewType(c, field.typ, initValue, assignment.info)
initValue.flags.incl nfSkipFieldChecking
assignment[0] = newSymNode(field)
assignment[1] = initValue
assignment.flags.incl nfSem
return initValue
result = initValue
else:
result = nil
proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
isStmtBranch: bool): IntSet =
@@ -182,6 +186,23 @@ proc collectOrAddMissingCaseFields(c: PContext, branchNode: PNode,
asgnExpr.typ = recTyp
defaults.add newTree(nkExprColonExpr, newSymNode(sym), asgnExpr)
proc collectBranchFields(c: PContext, n: PNode, discriminatorVal: PNode,
constrCtx: var ObjConstrContext, flags: TExprFlags) =
# All bets are off. If any of the branches has a mandatory
# fields we must produce an error:
for i in 1..<n.len:
let branchNode = n[i]
if branchNode != nil:
let oldCheckDefault = constrCtx.checkDefault
constrCtx.checkDefault = true
let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags)
constrCtx.checkDefault = oldCheckDefault
if len(defaults) > 0:
localError(c.config, discriminatorVal.info, "branch initialization " &
"with a runtime discriminator is not supported " &
"for a branch whose fields have default values.")
discard collectMissingCaseFields(c, n[i], constrCtx, @[])
proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
case n.kind
@@ -320,13 +341,27 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
discriminator.sym,
constrCtx.initExpr)
if discriminatorVal == nil:
# None of the branches were explicitly selected by the user and no
# value was given to the discrimator. We can assume that it will be
# initialized to zero and this will select a particular branch as
# a result:
let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0)
let matchedBranch = n.pickCaseBranch defaultValue
discard collectMissingCaseFields(c, matchedBranch, constrCtx, @[])
if discriminator.sym.ast != nil:
# branch is selected by the default field value of discriminator
let discriminatorDefaultVal = discriminator.sym.ast
result.status = initUnknown
result.defaults.add newTree(nkExprColonExpr, n[0], discriminatorDefaultVal)
if discriminatorDefaultVal.kind == nkIntLit:
let matchedBranch = n.pickCaseBranch discriminatorDefaultVal
if matchedBranch != nil:
let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags)
result.defaults.add defaults
collectOrAddMissingCaseFields(c, matchedBranch, constrCtx, result.defaults)
else:
collectBranchFields(c, n, discriminatorDefaultVal, constrCtx, flags)
else:
# None of the branches were explicitly selected by the user and no
# value was given to the discrimator. We can assume that it will be
# initialized to zero and this will select a particular branch as
# a result:
let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0)
let matchedBranch = n.pickCaseBranch defaultValue
discard collectMissingCaseFields(c, matchedBranch, constrCtx, @[])
else:
result.status = initPartial
if discriminatorVal.kind == nkIntLit:
@@ -338,10 +373,8 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
result.defaults.add defaults
collectOrAddMissingCaseFields(c, matchedBranch, constrCtx, result.defaults)
else:
# All bets are off. If any of the branches has a mandatory
# fields we must produce an error:
for i in 1..<n.len:
discard collectMissingCaseFields(c, n[i], constrCtx, @[])
collectBranchFields(c, n, discriminatorVal, constrCtx, flags)
of nkSym:
let field = n.sym
let e = semConstrField(c, flags, field, constrCtx.initExpr)
@@ -352,7 +385,7 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
result.defaults.add newTree(nkExprColonExpr, n, field.ast)
else:
if efWantNoDefaults notin flags: # cannot compute defaults at the typeRightPass
let defaultExpr = defaultNodeField(c, n)
let defaultExpr = defaultNodeField(c, n, constrCtx.checkDefault)
if defaultExpr != nil:
result.status = initUnknown
result.defaults.add newTree(nkExprColonExpr, n, defaultExpr)
@@ -375,7 +408,9 @@ proc semConstructTypeAux(c: PContext,
if status in {initPartial, initNone, initUnknown}:
discard collectMissingFields(c, t.n, constrCtx, result.defaults)
let base = t[0]
if base == nil: break
if base == nil or base.id == t.id or
base.kind in { tyRef, tyPtr } and base[0].id == t.id:
break
t = skipTypes(base, skipPtrs)
if t.kind != tyObject:
# XXX: This is not supposed to happen, but apparently
@@ -437,7 +472,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
result.typ.flags.incl tfHasOwned
if t.kind != tyObject:
return localErrorNode(c, result, if t.kind != tyGenericBody:
"object constructor needs an object type".dup(addDeclaredLoc(c.config, t))
"object constructor needs an object type".dup(addTypeNodeDeclaredLoc(c.config, t))
else: "cannot instantiate: '" &
typeToString(t, preferDesc) &
"'; the object's generic parameters cannot be inferred and must be explicitly given"

View File

@@ -486,7 +486,7 @@ proc liftParallel*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n: PNode): P
checkArgs(a, body)
var varSection = newNodeI(nkVarSection, n.info)
var temp = newSym(skTemp, getIdent(g.cache, "barrier"), nextSymId idgen, owner, n.info)
var temp = newSym(skTemp, getIdent(g.cache, "barrier"), idgen, owner, n.info)
temp.typ = magicsys.getCompilerProc(g, "Barrier").typ
incl(temp.flags, sfFromGeneric)
let tempNode = newSymNode(temp)

View File

@@ -90,7 +90,10 @@ const
errLetNeedsInit = "'let' symbol requires an initialization"
proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
if typ == nil: return
if typ == nil or sfGeneratedOp in tracked.owner.flags:
# don't create type bound ops for anything in a function with a `nodestroy` pragma
# bug #21987
return
when false:
let realType = typ.skipTypes(abstractInst)
if realType.kind == tyRef and
@@ -233,7 +236,7 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
if reason.kind == nkSym:
a.owner.gcUnsafetyReason = reason.sym
else:
a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name, nextSymId a.c.idgen,
a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name, a.c.idgen,
a.owner, reason.info, {})
proc markSideEffect(a: PEffects; reason: PNode | PSym; useLoc: TLineInfo) =
@@ -246,7 +249,7 @@ proc markSideEffect(a: PEffects; reason: PNode | PSym; useLoc: TLineInfo) =
sym = reason.sym
else:
let kind = if reason.kind == nkHiddenDeref: skParam else: skUnknown
sym = newSym(kind, a.owner.name, nextSymId a.c.idgen, a.owner, reason.info, {})
sym = newSym(kind, a.owner.name, a.c.idgen, a.owner, reason.info, {})
else:
sym = reason
a.c.sideEffects.mgetOrPut(a.owner.id, @[]).add (useLoc, sym)
@@ -353,12 +356,15 @@ proc useVar(a: PEffects, n: PNode) =
type
TIntersection = seq[tuple[id, count: int]] # a simple count table
proc addToIntersection(inter: var TIntersection, s: int) =
proc addToIntersection(inter: var TIntersection, s: int, zeroInit: bool) =
for j in 0..<inter.len:
if s == inter[j].id:
inc inter[j].count
return
inter.add((id: s, count: 1))
if zeroInit:
inter.add((id: s, count: 0))
else:
inter.add((id: s, count: 1))
proc throws(tracked, n, orig: PNode) =
if n.typ == nil or n.typ.kind != tyError:
@@ -396,7 +402,7 @@ proc addRaiseEffect(a: PEffects, e, comesFrom: PNode) =
if sameType(a.graph.excType(aa[i]), a.graph.excType(e)): return
if e.typ != nil:
if optNimV1Emulation in a.config.globalOptions or not isDefectException(e.typ):
if not isDefectException(e.typ):
throws(a.exc, e, comesFrom)
proc addTag(a: PEffects, e, comesFrom: PNode) =
@@ -462,7 +468,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
track(tracked, n[0])
dec tracked.inTryStmt
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i])
addToIntersection(inter, tracked.init[i], false)
var branches = 1
var hasFinally = false
@@ -497,7 +503,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
tracked.init.add b[j][2].sym.id
track(tracked, b[^1])
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i])
addToIntersection(inter, tracked.init[i], false)
else:
setLen(tracked.init, oldState)
track(tracked, b[^1])
@@ -693,9 +699,11 @@ proc trackCase(tracked: PEffects, n: PNode) =
addCaseBranchFacts(tracked.guards, n, i)
for i in 0..<branch.len:
track(tracked, branch[i])
if not breaksBlock(branch.lastSon): inc toCover
let hasBreaksBlock = breaksBlock(branch.lastSon)
if not hasBreaksBlock:
inc toCover
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i])
addToIntersection(inter, tracked.init[i], hasBreaksBlock)
setLen(tracked.init, oldState)
if not stringCase or lastSon(n).kind == nkElse:
@@ -715,9 +723,11 @@ proc trackIf(tracked: PEffects, n: PNode) =
var inter: TIntersection = @[]
var toCover = 0
track(tracked, n[0][1])
if not breaksBlock(n[0][1]): inc toCover
let hasBreaksBlock = breaksBlock(n[0][1])
if not hasBreaksBlock:
inc toCover
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i])
addToIntersection(inter, tracked.init[i], hasBreaksBlock)
for i in 1..<n.len:
let branch = n[i]
@@ -729,9 +739,12 @@ proc trackIf(tracked: PEffects, n: PNode) =
setLen(tracked.init, oldState)
for i in 0..<branch.len:
track(tracked, branch[i])
if not breaksBlock(branch.lastSon): inc toCover
let hasBreaksBlock = breaksBlock(branch.lastSon)
if not hasBreaksBlock:
inc toCover
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i])
addToIntersection(inter, tracked.init[i], hasBreaksBlock)
setLen(tracked.init, oldState)
if lastSon(n).len == 1:
for id, count in items(inter):
@@ -833,7 +846,6 @@ proc trackCall(tracked: PEffects; n: PNode) =
# and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner):
markSideEffect(tracked, a, n.info)
# p's effects are ours too:
var a = n[0]
#if canRaise(a):
@@ -876,7 +888,7 @@ proc trackCall(tracked: PEffects; n: PNode) =
mergeRaises(tracked, effectList[exceptionEffects], n)
mergeTags(tracked, effectList[tagEffects], n)
gcsafeAndSideeffectCheck()
if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished, mExpandToAst, mQuoteAst}:
if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished, mExpandToAst, mQuoteAst, mType}:
for i in 1..<n.len:
trackOperandForIndirectCall(tracked, n[i], op, i, a)
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
@@ -1117,7 +1129,7 @@ proc track(tracked: PEffects, n: PNode) =
elif child.kind == nkVarTuple:
for i in 0..<child.len-1:
if child[i].kind == nkEmpty or
child[i].kind == nkSym and child[i].sym.name.s == "_":
child[i].kind == nkSym and child[i].sym.name.id == ord(wUnderscore):
continue
varDecl(tracked, child[i])
if last.kind != nkEmpty:
@@ -1221,6 +1233,7 @@ proc track(tracked: PEffects, n: PNode) =
of nkTupleConstr:
for i in 0..<n.len:
track(tracked, n[i])
notNilCheck(tracked, n[i].skipColon, n[i].typ)
if tracked.owner.kind != skMacro:
if n[i].kind == nkExprColonExpr:
createTypeBoundOps(tracked, n[i][0].typ, n.info)
@@ -1316,6 +1329,7 @@ proc track(tracked: PEffects, n: PNode) =
proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
if spec.typ.kind == tyOr:
result = false
for t in spec.typ.sons:
if safeInheritanceDiff(g.excType(real), t) <= 0:
return true
@@ -1480,7 +1494,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
let param = params[i].sym
let typ = param.typ
if isSinkTypeForParam(typ) or
(t.config.selectedGC in {gcArc, gcOrc} and
(t.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
(isClosure(typ.skipTypes(abstractInst)) or param.id in t.escapingParams)):
createTypeBoundOps(t, typ, param.info)
if isOutParam(typ) and param.id notin t.init:
@@ -1499,7 +1513,8 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
let p = s.ast[pragmasPos]
let raisesSpec = effectSpec(p, wRaises)
if not isNil(raisesSpec):
checkRaisesSpec(g, false, raisesSpec, t.exc, "can raise an unlisted exception: ",
let useWarning = s.name.s == "=destroy"
checkRaisesSpec(g, useWarning, raisesSpec, t.exc, "can raise an unlisted exception: ",
hints=on, subtypeRelation, hintsArg=s.ast[0])
# after the check, use the formal spec:
effects[exceptionEffects] = raisesSpec

View File

@@ -161,18 +161,24 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
if result.typ.kind == tyNone:
localError(c.config, result.info, "expression has no type: " &
renderTree(result, {renderNoComments}))
var n = result
while n.kind in skipForDiscardable:
if n.kind == nkTryStmt: n = n[0]
else: n = n.lastSon
var s = "expression '" & $n & "' is of type '" &
result.typ.typeToString & "' and has to be used (or discarded)"
if result.info.line != n.info.line or
result.info.fileIndex != n.info.fileIndex:
s.add "; start of expression here: " & c.config$result.info
if result.typ.kind == tyProc:
s.add "; for a function call use ()"
localError(c.config, n.info, s)
else:
var n = result
while n.kind in skipForDiscardable:
if n.kind == nkTryStmt: n = n[0]
else: n = n.lastSon
# Ignore noreturn procs since they don't have a type
if n.endsInNoReturn:
return
var s = "expression '" & $n & "' is of type '" &
result.typ.typeToString & "' and has to be used (or discarded)"
if result.info.line != n.info.line or
result.info.fileIndex != n.info.fileIndex:
s.add "; start of expression here: " & c.config$result.info
if result.typ.kind == tyProc:
s.add "; for a function call use ()"
localError(c.config, n.info, s)
proc semIf(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
result = n
@@ -186,13 +192,15 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil):
it[0] = forceBool(c, semExprWithType(c, it[0], expectedType = getSysType(c.graph, n.info, tyBool)))
it[1] = semExprBranch(c, it[1], flags, expectedType)
typ = commonType(c, typ, it[1])
expectedType = typ
if not endsInNoReturn(it[1]):
expectedType = typ
closeScope(c)
elif it.len == 1:
hasElse = true
it[0] = semExprBranchScope(c, it[0], expectedType)
typ = commonType(c, typ, it[0])
expectedType = typ
if not endsInNoReturn(it[0]):
expectedType = typ
else: illFormedAst(it, c.config)
if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped} or
(not hasElse and efInTypeof notin flags):
@@ -232,8 +240,9 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
var typ = commonTypeBegin
var expectedType = expectedType
n[0] = semExprBranchScope(c, n[0], expectedType)
typ = commonType(c, typ, n[0].typ)
expectedType = typ
if not endsInNoReturn(n[0]):
typ = commonType(c, typ, n[0].typ)
expectedType = typ
var last = n.len - 1
var catchAllExcepts = 0
@@ -294,7 +303,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
if a.kind != nkFinally:
a[^1] = semExprBranchScope(c, a[^1], expectedType)
typ = commonType(c, typ, a[^1])
expectedType = typ
if not endsInNoReturn(a[^1]):
expectedType = typ
else:
a[^1] = semExprBranchScope(c, a[^1])
dec last
@@ -307,7 +317,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
result.typ = c.enforceVoidContext
else:
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags)
n[0] = fitNode(c, typ, n[0], n[0].info)
if not endsInNoReturn(n[0]):
n[0] = fitNode(c, typ, n[0], n[0].info)
for i in 1..last:
var it = n[i]
let j = it.len-1
@@ -325,6 +336,8 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
result.typ = typ
if not floatRangeCheck(result.floatVal, typ):
localError(c.config, n.info, errFloatToString % [$result.floatVal, typeToString(typ)])
elif r1.kind == nkSym and typ.skipTypes(abstractRange).kind == tyCstring:
discard "keep nkHiddenStdConv for cstring conversions"
else:
changeType(c, r1, typ, check=true)
result = r1
@@ -392,7 +405,7 @@ proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
result.add identDefs
proc isDiscardUnderscore(v: PSym): bool =
if v.name.s == "_":
if v.name.id == ord(wUnderscore):
v.flags.incl(sfGenSym)
result = true
@@ -459,7 +472,7 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
let y = considerQuotedIdent(c, n[1])
let obj = x.typ.skipTypes(abstractPtrs)
if obj.kind == tyObject and tfPartial in obj.flags:
let field = newSym(skField, getIdent(c.cache, y.s), nextSymId c.idgen, obj.sym, n[1].info)
let field = newSym(skField, getIdent(c.cache, y.s), c.idgen, obj.sym, n[1].info)
field.typ = skipIntLit(typ, c.idgen)
field.position = obj.n.len
obj.n.add newSymNode(field)
@@ -562,8 +575,9 @@ proc semVarMacroPragma(c: PContext, a: PNode, n: PNode): PNode =
return result
template isLocalSym(sym: PSym): bool =
sym.kind in {skVar, skLet} and not
sym.kind in {skVar, skLet, skParam} and not
({sfGlobal, sfPure} * sym.flags != {} or
sym.typ.kind == tyTypeDesc or
sfCompileTime in sym.flags) or
sym.kind in {skProc, skFunc, skIterator} and
sfGlobal notin sym.flags
@@ -583,6 +597,66 @@ proc globalVarInitCheck(c: PContext, n: PNode) =
if n.isLocalVarSym or n.kind in nkCallKinds and usesLocalVar(n):
localError(c.config, n.info, errCannotAssignToGlobal)
const
errTupleUnpackingTupleExpected = "tuple expected for tuple unpacking, but got '$1'"
errTupleUnpackingDifferentLengths = "tuple with $1 elements expected, but got '$2' with $3 elements"
proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSymKind, origResult: var PNode): PNode =
## expand tuple unpacking assignments into new var/let/const section
##
## mirrored with semexprs.makeTupleAssignments
if typ.kind != tyTuple:
localError(c.config, a.info, errTupleUnpackingTupleExpected %
[typeToString(typ, preferDesc)])
elif a.len-2 != typ.len:
localError(c.config, a.info, errTupleUnpackingDifferentLengths %
[$(a.len-2), typeToString(typ, preferDesc), $typ.len])
var
tempNode: PNode = nil
lastDef: PNode
let defkind = if symkind == skConst: nkConstDef else: nkIdentDefs
# temporary not needed if not const and RHS is tuple literal
# const breaks with seqs without temporary
let useTemp = def.kind notin {nkPar, nkTupleConstr} or symkind == skConst
if useTemp:
# use same symkind for compatibility with original section
let temp = newSym(symkind, getIdent(c.cache, "tmpTuple"), c.idgen, getCurrOwner(c), n.info)
temp.typ = typ
temp.flags.incl(sfGenSym)
lastDef = newNodeI(defkind, a.info)
newSons(lastDef, 3)
lastDef[0] = newSymNode(temp)
# NOTE: at the moment this is always ast.emptyNode, see parser.nim
lastDef[1] = a[^2]
lastDef[2] = def
temp.ast = lastDef
addToVarSection(c, origResult, n, lastDef)
tempNode = newSymNode(temp)
result = newNodeI(n.kind, a.info)
for j in 0..<a.len-2:
let name = a[j]
if useTemp and name.kind == nkIdent and name.ident.id == ord(wUnderscore):
# skip _ assignments if we are using a temp as they are already evaluated
continue
if name.kind == nkVarTuple:
# nested tuple
lastDef = newNodeI(nkVarTuple, name.info)
newSons(lastDef, name.len)
for k in 0..<name.len-2:
lastDef[k] = name[k]
else:
lastDef = newNodeI(defkind, name.info)
newSons(lastDef, 3)
lastDef[0] = name
lastDef[^2] = c.graph.emptyNode
if useTemp:
lastDef[^1] = newTupleAccessRaw(tempNode, j)
else:
var val = def[j]
if val.kind == nkExprColonExpr: val = val[1]
lastDef[^1] = val
result.add(lastDef)
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode
result = copyNode(n)
@@ -598,9 +672,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
addToVarSection(c, result, b)
continue
var hasUserSpecifiedType = false
var typ: PType = nil
if a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
hasUserSpecifiedType = true
var typFlags: TTypeAllowedFlags
@@ -629,8 +705,14 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if hasEmpty(typ):
localError(c.config, def.info, errCannotInferTypeOfTheLiteral % typ.kind.toHumanStr)
elif typ.kind == tyProc and def.kind == nkSym and isGenericRoutine(def.sym.ast):
# tfUnresolved in typ.flags:
localError(c.config, def.info, errProcHasNoConcreteType % def.renderTree)
let owner = typ.owner
let err =
# consistent error message with evaltempl/semMacroExpr
if owner != nil and owner.kind in {skTemplate, skMacro}:
errMissingGenericParamsForTemplate % def.renderTree
else:
errProcHasNoConcreteType % def.renderTree
localError(c.config, def.info, err)
when false:
# XXX This typing rule is neither documented nor complete enough to
# justify it. Instead use the newer 'unowned x' until we figured out
@@ -649,43 +731,39 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink})
if a.kind == nkVarTuple:
if tup.kind != tyTuple:
localError(c.config, a.info, errXExpected, "tuple")
elif a.len-2 != tup.len:
localError(c.config, a.info, errWrongNumberOfVariables)
b = newNodeI(nkVarTuple, a.info)
newSons(b, a.len)
# keep type desc for doc generator
# NOTE: at the moment this is always ast.emptyNode, see parser.nim
b[^2] = a[^2]
b[^1] = def
addToVarSection(c, result, n, b)
elif tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and
a.kind == nkIdentDefs and a.len > 3:
message(c.config, a.info, warnEachIdentIsTuple)
# generate new section from tuple unpacking and embed it into this one
let assignments = makeVarTupleSection(c, n, a, def, tup, symkind, result)
let resSection = semVarOrLet(c, assignments, symkind)
for resDef in resSection:
addToVarSection(c, result, n, resDef)
else:
if tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and
a.len > 3:
# var a, b = (1, 2)
message(c.config, a.info, warnEachIdentIsTuple)
for j in 0..<a.len-2:
if a[j].kind == nkDotExpr:
fillPartialObject(c, a[j],
if a.kind != nkVarTuple: typ else: tup[j])
addToVarSection(c, result, n, a)
continue
var v = semIdentDef(c, a[j], symkind, false)
styleCheckDef(c, v)
onDef(a[j].info, v)
if sfGenSym notin v.flags:
if not isDiscardUnderscore(v): addInterfaceDecl(c, v)
else:
if v.owner == nil: v.owner = c.p.owner
when oKeepVariableNames:
if c.inUnrolledContext > 0: v.flags.incl(sfShadowed)
for j in 0..<a.len-2:
if a[j].kind == nkDotExpr:
fillPartialObject(c, a[j], typ)
addToVarSection(c, result, n, a)
continue
var v = semIdentDef(c, a[j], symkind, false)
when defined(nimsuggest):
v.hasUserSpecifiedType = hasUserSpecifiedType
styleCheckDef(c, v)
onDef(a[j].info, v)
if sfGenSym notin v.flags:
if not isDiscardUnderscore(v): addInterfaceDecl(c, v)
else:
let shadowed = findShadowedVar(c, v)
if shadowed != nil:
shadowed.flags.incl(sfShadowed)
if shadowed.kind == skResult and sfGenSym notin v.flags:
message(c.config, a.info, warnResultShadowed)
if a.kind != nkVarTuple:
if v.owner == nil: v.owner = c.p.owner
when oKeepVariableNames:
if c.inUnrolledContext > 0: v.flags.incl(sfShadowed)
else:
let shadowed = findShadowedVar(c, v)
if shadowed != nil:
shadowed.flags.incl(sfShadowed)
if shadowed.kind == skResult and sfGenSym notin v.flags:
message(c.config, a.info, warnResultShadowed)
if def.kind != nkEmpty:
if sfThread in v.flags: localError(c.config, def.info, errThreadvarCannotInit)
setVarType(c, v, typ)
@@ -708,35 +786,26 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
b.add copyTree(def)
addToVarSection(c, result, n, b)
v.ast = b
else:
if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j]
# bug #7663, for 'nim check' this can be a non-tuple:
if tup.kind == tyTuple: setVarType(c, v, tup[j])
else: v.typ = tup
b[j] = newSymNode(v)
if def.kind == nkEmpty:
let actualType = v.typ.skipTypes({tyGenericInst, tyAlias,
tyUserTypeClassInst})
if actualType.kind in {tyObject, tyDistinct} and
actualType.requiresInit:
defaultConstructionError(c, v.typ, v.info)
else:
checkNilable(c, v)
# allow let to not be initialised if imported from C:
if v.kind == skLet and sfImportc notin v.flags and (strictDefs notin c.features or not isLocalSym(v)):
localError(c.config, a.info, errLetNeedsInit)
if sfCompileTime in v.flags:
if a.kind != nkVarTuple:
if def.kind == nkEmpty:
let actualType = v.typ.skipTypes({tyGenericInst, tyAlias,
tyUserTypeClassInst})
if actualType.kind in {tyObject, tyDistinct} and
actualType.requiresInit:
defaultConstructionError(c, v.typ, v.info)
else:
checkNilable(c, v)
# allow let to not be initialised if imported from C:
if v.kind == skLet and sfImportc notin v.flags and (strictDefs notin c.features or not isLocalSym(v)):
localError(c.config, a.info, errLetNeedsInit)
if sfCompileTime in v.flags:
var x = newNodeI(result.kind, v.info)
x.add result[i]
vm.setupCompileTimeVar(c.module, c.idgen, c.graph, x)
else:
localError(c.config, a.info, "cannot destructure to compile time variable")
if v.flags * {sfGlobal, sfThread} == {sfGlobal}:
message(c.config, v.info, hintGlobalVar)
if {sfGlobal, sfPure} <= v.flags:
globalVarInitCheck(c, def)
suggestSym(c.graph, v.info, v, c.graph.usageSym)
if v.flags * {sfGlobal, sfThread} == {sfGlobal}:
message(c.config, v.info, hintGlobalVar)
if {sfGlobal, sfPure} <= v.flags:
globalVarInitCheck(c, def)
suggestSym(c.graph, v.info, v, c.graph.usageSym)
proc semConst(c: PContext, n: PNode): PNode =
result = copyNode(n)
@@ -754,9 +823,11 @@ proc semConst(c: PContext, n: PNode): PNode =
addToVarSection(c, result, b)
continue
var hasUserSpecifiedType = false
var typ: PType = nil
if a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
hasUserSpecifiedType = true
var typFlags: TTypeAllowedFlags
@@ -789,26 +860,28 @@ proc semConst(c: PContext, n: PNode): PNode =
typeAllowedCheck(c, a.info, typ, skConst, typFlags)
if a.kind == nkVarTuple:
if typ.kind != tyTuple:
localError(c.config, a.info, errXExpected, "tuple")
elif a.len-2 != typ.len:
localError(c.config, a.info, errWrongNumberOfVariables)
b = newNodeI(nkVarTuple, a.info)
newSons(b, a.len)
b[^2] = a[^2]
b[^1] = def
# generate new section from tuple unpacking and embed it into this one
let assignments = makeVarTupleSection(c, n, a, def, typ, skConst, result)
let resSection = semConst(c, assignments)
for resDef in resSection:
addToVarSection(c, result, n, resDef)
else:
for j in 0..<a.len-2:
var v = semIdentDef(c, a[j], skConst)
when defined(nimsuggest):
v.hasUserSpecifiedType = hasUserSpecifiedType
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
elif v.owner == nil: v.owner = getCurrOwner(c)
styleCheckDef(c, v)
onDef(a[j].info, v)
for j in 0..<a.len-2:
var v = semIdentDef(c, a[j], skConst)
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
elif v.owner == nil: v.owner = getCurrOwner(c)
styleCheckDef(c, v)
onDef(a[j].info, v)
if a.kind != nkVarTuple:
setVarType(c, v, typ)
when false:
v.ast = def # no need to copy
var fillSymbol = true
if v.typ != nil:
# symbol already has type and probably value
# don't mutate
fillSymbol = false
else:
setVarType(c, v, typ)
b = newNodeI(nkConstDef, a.info)
if importantComments(c.config): b.comment = a.comment
# postfix not generated here (to generate, get rid of it in transf)
@@ -821,13 +894,9 @@ proc semConst(c: PContext, n: PNode): PNode =
b.add newSymNode(v)
b.add a[1]
b.add copyTree(def)
v.ast = b
else:
setVarType(c, v, typ[j])
v.ast = if def[j].kind != nkExprColonExpr: def[j]
else: def[j][1]
b[j] = newSymNode(v)
addToVarSection(c, result, n, b)
if fillSymbol:
v.ast = b
addToVarSection(c, result, n, b)
dec c.inStaticContext
include semfields
@@ -854,7 +923,10 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
if iterAfterVarLent.kind != tyTuple or n.len == 3:
if n.len == 3:
if n[0].kind == nkVarTuple:
if n[0].len-1 != iterAfterVarLent.len:
if iterAfterVarLent.kind != tyTuple:
return localErrorNode(c, n, n[0].info, errTupleUnpackingTupleExpected %
[typeToString(n[1].typ, preferDesc)])
elif n[0].len-1 != iterAfterVarLent.len:
return localErrorNode(c, n, n[0].info, errWrongNumberOfVariables)
for i in 0..<n[0].len-1:
@@ -1034,7 +1106,8 @@ proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
result = n
n[^2] = semExprNoDeref(c, n[^2], {efWantIterator})
var call = n[^2]
if call.kind == nkStmtListExpr and isTrivalStmtExpr(call):
if call.kind == nkStmtListExpr and (isTrivalStmtExpr(call) or (call.lastSon.kind in nkCallKinds and call.lastSon[0].sym.kind == skIterator)):
call = call.lastSon
n[^2] = call
let isCallExpr = call.kind in nkCallKinds
@@ -1072,29 +1145,23 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil
openScope(c)
pushCaseContext(c, n)
n[0] = semExprWithType(c, n[0])
var chckCovered = false
var covered: Int128 = toInt128(0)
var typ = commonTypeBegin
var expectedType = expectedType
var hasElse = false
let caseTyp = skipTypes(n[0].typ, abstractVar-{tyTypeDesc})
const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool}
var chckCovered = caseTyp.shouldCheckCaseCovered()
case caseTyp.kind
of shouldChckCovered:
chckCovered = true
of tyRange:
if skipTypes(caseTyp[0], abstractInst).kind in shouldChckCovered:
chckCovered = true
of tyFloat..tyFloat128, tyString, tyCstring, tyError:
of tyFloat..tyFloat128, tyString, tyCstring, tyError, shouldChckCovered, tyRange:
discard
else:
popCaseContext(c)
closeScope(c)
return handleCaseStmtMacro(c, n, flags)
template invalidOrderOfBranches(n: PNode) =
template invalidOrderOfBranches(n: PNode) =
localError(c.config, n.info, "invalid order of case branches")
break
for i in 1..<n.len:
setCaseContextIdx(c, i)
var x = n[i]
@@ -1109,7 +1176,8 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil
var last = x.len-1
x[last] = semExprBranchScope(c, x[last], expectedType)
typ = commonType(c, typ, x[last])
expectedType = typ
if not endsInNoReturn(x[last]):
expectedType = typ
of nkElifBranch:
if hasElse: invalidOrderOfBranches(x)
chckCovered = false
@@ -1118,13 +1186,15 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil
x[0] = forceBool(c, semExprWithType(c, x[0], expectedType = getSysType(c.graph, n.info, tyBool)))
x[1] = semExprBranch(c, x[1], expectedType = expectedType)
typ = commonType(c, typ, x[1])
expectedType = typ
if not endsInNoReturn(x[1]):
expectedType = typ
closeScope(c)
of nkElse:
checkSonsLen(x, 1, c.config)
x[0] = semExprBranchScope(c, x[0], expectedType)
typ = commonType(c, typ, x[0])
expectedType = typ
if not endsInNoReturn(x[0]):
expectedType = typ
if (chckCovered and covered == toCover(c, n[0].typ)) or hasElse:
message(c.config, x.info, warnUnreachableElse)
hasElse = true
@@ -1417,12 +1487,20 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
# final pass
if a[2].kind in nkCallKinds:
incl a[2].flags, nfSem # bug #10548
if sfExportc in s.flags and s.typ.kind == tyAlias:
localError(c.config, name.info, "{.exportc.} not allowed for type aliases")
if tfBorrowDot in s.typ.flags and s.typ.skipTypes({tyGenericBody}).kind != tyDistinct:
excl s.typ.flags, tfBorrowDot
localError(c.config, name.info, "only a 'distinct' type can borrow `.`")
if sfExportc in s.flags:
if s.typ.kind == tyAlias:
localError(c.config, name.info, "{.exportc.} not allowed for type aliases")
elif s.typ.kind == tyGenericBody:
localError(c.config, name.info, "{.exportc.} not allowed for generic types")
if tfBorrowDot in s.typ.flags:
let body = s.typ.skipTypes({tyGenericBody})
if body.kind != tyDistinct:
# flag might be copied from alias/instantiation:
let t = body.skipTypes({tyAlias, tyGenericInst})
if not (t.kind == tyDistinct and tfBorrowDot in t.flags):
excl s.typ.flags, tfBorrowDot
localError(c.config, name.info, "only a 'distinct' type can borrow `.`")
let aa = a[2]
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
aa[0].kind == nkObjectTy:
@@ -1440,7 +1518,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
if tfInheritable in oldFlags and tfFinal in objTy.flags:
excl(objTy.flags, tfFinal)
let obj = newSym(skType, getIdent(c.cache, s.name.s & ":ObjectType"),
nextSymId c.idgen, getCurrOwner(c), s.info)
c.idgen, getCurrOwner(c), s.info)
obj.flags.incl sfGeneratedType
let symNode = newSymNode(obj)
obj.ast = a.shallowCopy
@@ -1457,22 +1535,30 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
obj.flags.incl sfPure
obj.typ = objTy
objTy.sym = obj
for sk in c.skipTypes:
discard semTypeNode(c, sk, nil)
c.skipTypes = @[]
proc checkForMetaFields(c: PContext; n: PNode) =
proc checkMeta(c: PContext; n: PNode; t: PType) =
if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags:
proc checkForMetaFields(c: PContext; n: PNode; hasError: var bool) =
proc checkMeta(c: PContext; n: PNode; t: PType; hasError: var bool; parent: PType) =
if t != nil and (t.isMetaType or t.kind == tyNone) and tfGenericTypeParam notin t.flags:
if t.kind == tyBuiltInTypeClass and t.len == 1 and t[0].kind == tyProc:
localError(c.config, n.info, ("'$1' is not a concrete type; " &
"for a callback without parameters use 'proc()'") % t.typeToString)
elif t.kind == tyNone and parent != nil:
# TODO: openarray has the `tfGenericTypeParam` flag & generics
# TODO: handle special cases (sink etc.) and views
localError(c.config, n.info, errTIsNotAConcreteType % parent.typeToString)
else:
localError(c.config, n.info, errTIsNotAConcreteType % t.typeToString)
hasError = true
if n.isNil: return
case n.kind
of nkRecList, nkRecCase:
for s in n: checkForMetaFields(c, s)
for s in n: checkForMetaFields(c, s, hasError)
of nkOfBranch, nkElse:
checkForMetaFields(c, n.lastSon)
checkForMetaFields(c, n.lastSon, hasError)
of nkSym:
let t = n.sym.typ
case t.kind
@@ -1480,9 +1566,9 @@ proc checkForMetaFields(c: PContext; n: PNode) =
tyProc, tyGenericInvocation, tyGenericInst, tyAlias, tySink, tyOwned:
let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
for i in start..<t.len:
checkMeta(c, n, t[i])
checkMeta(c, n, t[i], hasError, t)
else:
checkMeta(c, n, t)
checkMeta(c, n, t, hasError, nil)
else:
internalAssert c.config, false
@@ -1517,14 +1603,15 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
assert s.typ != nil
assignType(s.typ, t)
s.typ.itemId = t.itemId # same id
checkConstructedType(c.config, s.info, s.typ)
var hasError = false
if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
checkForMetaFields(c, s.typ.n)
checkForMetaFields(c, s.typ.n, hasError)
if not hasError:
checkConstructedType(c.config, s.info, s.typ)
# fix bug #5170, bug #17162, bug #15526: ensure locally scoped types get a unique name:
if s.typ.kind in {tyEnum, tyRef, tyObject} and not isTopLevel(c):
incl(s.flags, sfGenSym)
#instAllTypeBoundOp(c, n.info)
@@ -1598,18 +1685,27 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind) =
proc semBorrow(c: PContext, n: PNode, s: PSym) =
# search for the correct alias:
var b = searchForBorrowProc(c, c.currentScope.parent, s)
if b != nil:
# store the alias:
n[bodyPos] = newSymNode(b)
# Carry over the original symbol magic, this is necessary in order to ensure
# the semantic pass is correct
s.magic = b.magic
if b.typ != nil and b.typ.len > 0:
s.typ.n[0] = b.typ.n[0]
s.typ.flags = b.typ.flags
else:
localError(c.config, n.info, errNoSymbolToBorrowFromFound)
var (b, state) = searchForBorrowProc(c, c.currentScope.parent, s)
case state
of bsMatch:
# store the alias:
n[bodyPos] = newSymNode(b)
# Carry over the original symbol magic, this is necessary in order to ensure
# the semantic pass is correct
s.magic = b.magic
if b.typ != nil and b.typ.len > 0:
s.typ.n[0] = b.typ.n[0]
s.typ.flags = b.typ.flags
of bsNoDistinct:
localError(c.config, n.info, "borrow proc without distinct type parameter is meaningless")
of bsReturnNotMatch:
localError(c.config, n.info, "borrow from proc return type mismatch: '$1'" % typeToString(b.typ[0]))
of bsGeneric:
localError(c.config, n.info, "borrow with generic parameter is not supported")
of bsNotSupported:
localError(c.config, n.info, "borrow from '$1' is not supported" % $b.name.s)
else:
localError(c.config, n.info, errNoSymbolToBorrowFromFound)
proc swapResult(n: PNode, sRes: PSym, dNode: PNode) =
## Swap nodes that are (skResult) symbols to d(estination)Node.
@@ -1618,9 +1714,19 @@ proc swapResult(n: PNode, sRes: PSym, dNode: PNode) =
n[i] = dNode
swapResult(n[i], sRes, dNode)
proc addThis(c: PContext, n: PNode, t: PType, owner: TSymKind) =
var s = newSym(skResult, getIdent(c.cache, "this"), c.idgen,
getCurrOwner(c), n.info)
s.typ = t
incl(s.flags, sfUsed)
c.p.resultSym = s
n.add newSymNode(c.p.resultSym)
addParamOrResult(c, c.p.resultSym, owner)
proc addResult(c: PContext, n: PNode, t: PType, owner: TSymKind) =
template genResSym(s) =
var s = newSym(skResult, getIdent(c.cache, "result"), nextSymId c.idgen,
var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen,
getCurrOwner(c), n.info)
s.typ = t
incl(s.flags, sfUsed)
@@ -1707,7 +1813,6 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
n[genericParamsPos] = c.graph.emptyNode
# for LL we need to avoid wrong aliasing
let params = copyTree n.typ.n
n[paramsPos] = params
s.typ = n.typ
for i in 1..<params.len:
if params[i].typ.kind in {tyTypeDesc, tyGenericParam,
@@ -1761,7 +1866,7 @@ proc canonType(c: PContext, t: PType): PType =
proc prevDestructor(c: PContext; prevOp: PSym; obj: PType; info: TLineInfo) =
var msg = "cannot bind another '" & prevOp.name.s & "' to: " & typeToString(obj)
if sfOverriden notin prevOp.flags:
if sfOverridden notin prevOp.flags:
msg.add "; previous declaration was constructed here implicitly: " & (c.config $ prevOp.info)
else:
msg.add "; previous declaration was here: " & (c.config $ prevOp.info)
@@ -1776,13 +1881,59 @@ proc whereToBindTypeHook(c: PContext; t: PType): PType =
if result.kind in {tyObject, tyDistinct, tySequence, tyString}:
result = canonType(c, result)
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
let t = s.typ
var noError = false
let cond = if op in {attachedDestructor, attachedWasMoved}:
let cond = t.len == 2 and t[0] != nil
if cond:
var obj = t[1]
while true:
incl(obj.flags, tfHasAsgn)
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon
elif obj.kind == tyGenericInvocation: obj = obj[0]
else: break
var res = t[0]
while true:
if res.kind in {tyGenericBody, tyGenericInst}: res = res.lastSon
elif res.kind == tyGenericInvocation: res = res[0]
else: break
if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, res):
obj = canonType(c, obj)
let ao = getAttachedOp(c.graph, obj, op)
if ao == s:
discard "forward declared destructor"
elif ao.isNil and tfCheckedForDestructor notin obj.flags:
setAttachedOp(c.graph, c.module.position, obj, op, s)
else:
prevDestructor(c, ao, obj, n.info)
noError = true
if obj.owner.getModule != s.getModule:
localError(c.config, n.info, errGenerated,
"type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
if not noError and sfSystemModule notin s.owner.flags:
localError(c.config, n.info, errGenerated,
"signature for '=dup' must be proc[T: object](x: T): T")
incl(s.flags, sfUsed)
incl(s.flags, sfOverridden)
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp; suppressVarDestructorWarning = false) =
let t = s.typ
var noError = false
let cond = case op
of attachedWasMoved:
t.len == 2 and t[0] == nil and t[1].kind == tyVar
elif op == attachedTrace:
of attachedTrace:
t.len == 3 and t[0] == nil and t[1].kind == tyVar and t[2].kind == tyPointer
of attachedDestructor:
if c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
t.len == 2 and t[0] == nil
else:
t.len == 2 and t[0] == nil and t[1].kind == tyVar
else:
t.len >= 2 and t[0] == nil
@@ -1794,6 +1945,9 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
elif obj.kind == tyGenericInvocation: obj = obj[0]
else: break
if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
if (not suppressVarDestructorWarning) and op == attachedDestructor and t[1].kind == tyVar and
c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
message(c.config, n.info, warnDeprecated, "A custom '=destroy' hook which takes a 'var T' parameter is deprecated; it should take a 'T' parameter")
obj = canonType(c, obj)
let ao = getAttachedOp(c.graph, obj, op)
if ao == s:
@@ -1807,20 +1961,33 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
localError(c.config, n.info, errGenerated,
"type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
if not noError and sfSystemModule notin s.owner.flags:
if op == attachedTrace:
case op
of attachedTrace:
localError(c.config, n.info, errGenerated,
"signature for '=trace' must be proc[T: object](x: var T; env: pointer)")
of attachedDestructor:
if c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
localError(c.config, n.info, errGenerated,
"signature for '=destroy' must be proc[T: object](x: var T) or proc[T: object](x: T)")
else:
localError(c.config, n.info, errGenerated,
"signature for '=destroy' must be proc[T: object](x: var T)")
else:
localError(c.config, n.info, errGenerated,
"signature for '" & s.name.s & "' must be proc[T: object](x: var T)")
incl(s.flags, sfUsed)
incl(s.flags, sfOverriden)
incl(s.flags, sfOverridden)
proc semOverride(c: PContext, s: PSym, n: PNode) =
let name = s.name.s.normalize
case name
of "=destroy":
bindTypeHook(c, s, n, attachedDestructor)
if s.ast != nil:
if s.ast[pragmasPos].kind == nkEmpty:
s.ast[pragmasPos] = newNodeI(nkPragma, s.info)
s.ast[pragmasPos].add newTree(nkExprColonExpr,
newIdentNode(c.cache.getIdent("raises"), s.info), newNodeI(nkBracket, s.info))
of "deepcopy", "=deepcopy":
if s.typ.len == 2 and
s.typ[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
@@ -1850,11 +2017,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
localError(c.config, n.info, errGenerated,
"signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
incl(s.flags, sfUsed)
incl(s.flags, sfOverriden)
incl(s.flags, sfOverridden)
of "=", "=copy", "=sink":
if s.magic == mAsgn: return
incl(s.flags, sfUsed)
incl(s.flags, sfOverriden)
incl(s.flags, sfOverridden)
if name == "=":
message(c.config, n.info, warnDeprecated, "Overriding `=` hook is deprecated; Override `=copy` hook instead")
let t = s.typ
@@ -1897,8 +2064,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
of "=wasmoved":
if s.magic != mWasMoved:
bindTypeHook(c, s, n, attachedWasMoved)
of "=dup":
if s.magic != mDup:
bindDupHook(c, s, n, attachedDup)
else:
if sfOverriden in s.flags:
if sfOverridden in s.flags:
localError(c.config, n.info, errGenerated,
"'destroy' or 'deepCopy' expected for 'override'")
@@ -1961,7 +2131,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
case n[namePos].kind
of nkEmpty:
s = newSym(kind, c.cache.idAnon, nextSymId c.idgen, c.getCurrOwner, n.info)
s = newSym(kind, c.cache.idAnon, c.idgen, c.getCurrOwner, n.info)
s.flags.incl sfUsed
n[namePos] = newSymNode(s)
of nkSym:
@@ -1983,6 +2153,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
s.ast = n
s.options = c.config.options
#s.scope = c.currentScope
if s.kind in {skMacro, skTemplate}:
# push noalias flag at first to prevent unwanted recursive calls:
incl(s.flags, sfNoalias)
# before compiling the proc params & body, set as current the scope
# where the proc was declared
@@ -2123,7 +2296,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
pushOwner(c, s)
if not isAnon:
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
if sfOverridden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
elif s.name.s[0] in {'.', '('}:
if s.name.s in [".", ".()", ".="] and {Feature.destructor, dotOperators} * c.features == {}:
localError(c.config, n.info, "the overloaded " & s.name.s &
@@ -2135,6 +2308,34 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if sfBorrow in s.flags and c.config.cmd notin cmdDocLike:
result[bodyPos] = c.graph.emptyNode
if {sfVirtual, sfConstructor} * s.flags != {} and sfImportc notin s.flags:
let isVirtual = sfVirtual in s.flags
let pragmaName = if isVirtual: "virtual" else: "constructor"
if c.config.backend == backendCpp:
if s.typ.sons.len < 2 and isVirtual:
localError(c.config, n.info, "virtual must have at least one parameter")
for son in s.typ.sons:
if son!=nil and son.isMetaType:
localError(c.config, n.info, pragmaName & " unsupported for generic routine")
var typ: PType
if sfConstructor in s.flags:
typ = s.typ.sons[0]
if typ == nil or typ.kind != tyObject:
localError(c.config, n.info, "constructor must return an object")
else:
typ = s.typ.sons[1]
if typ.kind == tyPtr and isVirtual:
typ = typ[0]
if typ.kind != tyObject:
localError(c.config, n.info, "virtual must be either ptr to object or object type.")
if typ.owner.id == s.owner.id and c.module.id == s.owner.id:
c.graph.memberProcsPerType.mgetOrPut(typ.itemId, @[]).add s
else:
localError(c.config, n.info,
pragmaName & " procs must be defined in the same scope as the type they are virtual for and it must be a top level scope")
else:
localError(c.config, n.info, pragmaName & " procs are only supported in C++")
if n[bodyPos].kind != nkEmpty and sfError notin s.flags:
# for DLL generation we allow sfImportc to have a body, for use in VM
if c.config.ideCmd in {ideSug, ideCon} and s.kind notin {skMacro, skTemplate} and not
@@ -2159,15 +2360,19 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# Macros and Templates can have generic parameters, but they are only
# used for overload resolution (there is no instantiation of the symbol)
if s.kind notin {skMacro, skTemplate} and s.magic == mNone: paramsTypeCheck(c, s.typ)
maybeAddResult(c, s, n)
let resultType =
if s.kind == skMacro:
sysTypeFromName(c.graph, n.info, "NimNode")
elif not isInlineIterator(s.typ):
s.typ[0]
else:
nil
var resultType: PType
if sfConstructor in s.flags:
resultType = makePtrType(c, s.typ[0])
addThis(c, n, resultType, skProc)
else:
maybeAddResult(c, s, n)
resultType =
if s.kind == skMacro:
sysTypeFromName(c.graph, n.info, "NimNode")
elif not isInlineIterator(s.typ):
s.typ[0]
else:
nil
# semantic checking also needed with importc in case used in VM
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], resultType))
# unfortunately we cannot skip this step when in 'system.compiles'
@@ -2175,7 +2380,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
trackProc(c, s, s.ast[bodyPos])
else:
if (s.typ[0] != nil and s.kind != skIterator):
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextSymId c.idgen, s, n.info))
addDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), c.idgen, s, n.info))
openScope(c)
n[bodyPos] = semGenericStmt(c, n[bodyPos])
@@ -2275,7 +2480,6 @@ proc semMethod(c: PContext, n: PNode): PNode =
proc semConverterDef(c: PContext, n: PNode): PNode =
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "converter")
checkSonsLen(n, bodyPos + 1, c.config)
result = semProcAux(c, n, skConverter, converterPragmas)
# macros can transform converters to nothing:
if namePos >= result.safeLen: return result
@@ -2290,7 +2494,6 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
addConverterDef(c, LazySym(sym: s))
proc semMacroDef(c: PContext, n: PNode): PNode =
checkSonsLen(n, bodyPos + 1, c.config)
result = semProcAux(c, n, skMacro, macroPragmas)
# macros can transform macros to nothing:
if namePos >= result.safeLen: return result
@@ -2301,10 +2504,16 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
var s = result[namePos].sym
var t = s.typ
var allUntyped = true
var nullary = true
for i in 1..<t.n.len:
let param = t.n[i].sym
if param.typ.kind != tyUntyped: allUntyped = false
# no default value, parameters required in call
if param.ast == nil: nullary = false
if allUntyped: incl(s.flags, sfAllUntyped)
if nullary and n[genericParamsPos].kind == nkEmpty:
# macro can be called with alias syntax, remove pushed noalias flag
excl(s.flags, sfNoalias)
if n[bodyPos].kind == nkEmpty:
localError(c.config, n.info, errImplOfXexpected % s.name.s)
@@ -2459,9 +2668,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType =
var m = n[i]
while m.kind in {nkStmtListExpr, nkStmtList} and m.len > 0: # from templates
m = m.lastSon
if m.kind in nkLastBlockStmts or
m.kind in nkCallKinds and m[0].kind == nkSym and
sfNoReturn in m[0].sym.flags:
if endsInNoReturn(m):
for j in i + 1..<n.len:
case n[j].kind
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkState: discard
@@ -2477,12 +2684,6 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType =
result[0].kind != nkDefer:
result = result[0]
when defined(nimfix):
if result.kind == nkCommentStmt and not result.comment.isNil and
not (result.comment[0] == '#' and result.comment[1] == '#'):
# it is an old-style comment statement: we replace it with 'discard ""':
prettybase.replaceComment(result.info)
proc semStmt(c: PContext, n: PNode; flags: TExprFlags): PNode =
if efInTypeof notin flags:
result = semExprNoType(c, n)

View File

@@ -70,6 +70,9 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
onUse(info, s)
else:
result = n
elif i == 0:
# forced open but symbol not in scope, retain information
result = n
else:
# semantic checking requires a type; ``fitNode`` deals with it
# appropriately
@@ -110,14 +113,10 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
result = copyNode(n)
var count = 0
for i in 0..<n.len:
toMixin.incl(considerQuotedIdent(c, n[i]).id)
let x = symChoice(c, n[i], nil, scForceOpen)
inc count, x.len
result.add x
if count == 0:
result = newNodeI(nkEmpty, n.info)
proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) =
case n.kind
@@ -136,24 +135,32 @@ type
noGenSym: int
inTemplateHeader: int
proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
proc isTemplParam(c: TemplCtx, s: PSym): bool {.inline.} =
result = s.kind == skParam and
s.owner == c.owner and sfTemplateParam in s.flags
proc getIdentReplaceParams(c: var TemplCtx, n: var PNode): tuple[node: PNode, hasParam: bool] =
case n.kind
of nkPostfix: result = getIdentNode(c, n[1])
of nkPragmaExpr: result = getIdentNode(c, n[0])
of nkPostfix: result = getIdentReplaceParams(c, n[1])
of nkPragmaExpr: result = getIdentReplaceParams(c, n[0])
of nkIdent:
result = n
result = (n, false)
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
result = newSymNode(s, n.info)
of nkAccQuoted, nkSym: result = n
if s != nil and isTemplParam(c, s):
n = newSymNode(s, n.info)
result = (n, true)
of nkSym:
result = (n, isTemplParam(c, n.sym))
of nkAccQuoted:
result = (n, false)
for i in 0..<n.safeLen:
let (ident, hasParam) = getIdentReplaceParams(c, n[i])
if hasParam:
result.node[i] = ident
result.hasParam = true
else:
illFormedAst(n, c.c.config)
result = n
proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
result = n.kind == nkSym and n.sym.kind == skParam and
n.sym.owner == c.owner and sfTemplateParam in n.sym.flags
result = (n, false)
proc semTemplBody(c: var TemplCtx, n: PNode): PNode
@@ -168,47 +175,21 @@ proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
result = semTemplBody(c, n)
closeScope(c)
proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
result = n
if n.kind == nkIdent:
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
onUse(n.info, s)
else:
for i in 0..<n.safeLen:
result[i] = onlyReplaceParams(c, n[i])
proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
result = newSym(kind, considerQuotedIdent(c.c, n), nextSymId c.c.idgen, c.owner, n.info)
result = newSym(kind, considerQuotedIdent(c.c, n), c.c.idgen, c.owner, n.info)
incl(result.flags, sfGenSym)
incl(result.flags, sfShadowed)
proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
# locals default to 'gensym':
if n.kind == nkPragmaExpr and symBinding(n[1]) == spInject:
# locals default to 'gensym', fields default to 'inject':
if (n.kind == nkPragmaExpr and symBinding(n[1]) == spInject) or
k == skField:
# even if injected, don't produce a sym choice here:
#n = semTemplBody(c, n)
var x = n[0]
while true:
case x.kind
of nkPostfix: x = x[1]
of nkPragmaExpr: x = x[0]
of nkIdent: break
of nkAccQuoted:
# consider: type `T TemplParam` {.inject.}
# it suffices to return to treat it like 'inject':
n = onlyReplaceParams(c, n)
return
else:
illFormedAst(x, c.c.config)
let ident = getIdentNode(c, x)
if not isTemplParam(c, ident):
c.toInject.incl(x.ident.id)
else:
replaceIdentBySym(c.c, n, ident)
let (ident, hasParam) = getIdentReplaceParams(c, n)
if not hasParam:
if k != skField:
c.toInject.incl(considerQuotedIdent(c.c, ident).id)
else:
if (n.kind == nkPragmaExpr and n.len >= 2 and n[1].kind == nkPragma):
let pragmaNode = n[1]
@@ -218,16 +199,16 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
var found = false
if ni.kind == nkIdent:
for a in templatePragmas:
if ni.ident == getIdent(c.c.cache, $a):
if ni.ident.id == ord(a):
found = true
break
if not found:
openScope(c)
pragmaNode[i] = semTemplBody(c, pragmaNode[i])
closeScope(c)
let ident = getIdentNode(c, n)
if not isTemplParam(c, ident):
if n.kind != nkSym and not (n.kind == nkIdent and n.ident.s == "_"):
let (ident, hasParam) = getIdentReplaceParams(c, n)
if not hasParam:
if n.kind != nkSym and not (n.kind == nkIdent and n.ident.id == ord(wUnderscore)):
let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local)
styleCheckDef(c.c, n.info, local)
@@ -235,8 +216,6 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
replaceIdentBySym(c.c, n, newSymNode(local, n.info))
if k == skParam and c.inTemplateHeader > 0:
local.flags.incl sfTemplateParam
else:
replaceIdentBySym(c.c, n, ident)
proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
incl(s.flags, sfUsed)
@@ -281,7 +260,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
if n.kind == nkIdent:
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
onUse(n.info, s)
@@ -292,20 +271,21 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
result = n
checkSonsLen(n, bodyPos + 1, c.c.config)
# routines default to 'inject':
if n.kind notin nkLambdaKinds and symBinding(n[pragmasPos]) == spGenSym:
let ident = getIdentNode(c, n[namePos])
if not isTemplParam(c, ident):
var s = newGenSym(k, ident, c)
s.ast = n
addPrelimDecl(c.c, s)
styleCheckDef(c.c, n.info, s)
onDef(n.info, s)
n[namePos] = newSymNode(s, n[namePos].info)
if n.kind notin nkLambdaKinds:
# routines default to 'inject':
if symBinding(n[pragmasPos]) == spGenSym:
let (ident, hasParam) = getIdentReplaceParams(c, n[namePos])
if not hasParam:
var s = newGenSym(k, ident, c)
s.ast = n
addPrelimDecl(c.c, s)
styleCheckDef(c.c, n.info, s)
onDef(n.info, s)
n[namePos] = newSymNode(s, n[namePos].info)
else:
n[namePos] = ident
else:
n[namePos] = ident
else:
n[namePos] = semRoutineInTemplName(c, n[namePos])
n[namePos] = semRoutineInTemplName(c, n[namePos])
# open scope for parameters
openScope(c)
for i in patternPos..paramsPos-1:
@@ -327,21 +307,24 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
# close scope for parameters
closeScope(c)
proc semTemplIdentDef(c: var TemplCtx, a: PNode, symKind: TSymKind) =
checkMinSonsLen(a, 3, c.c.config)
when defined(nimsuggest):
inc c.c.inTypeContext
a[^2] = semTemplBody(c, a[^2])
when defined(nimsuggest):
dec c.c.inTypeContext
a[^1] = semTemplBody(c, a[^1])
for j in 0..<a.len-2:
addLocalDecl(c, a[j], symKind)
proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start = 0) =
for i in start..<n.len:
var a = n[i]
case a.kind:
of nkCommentStmt: continue
of nkIdentDefs, nkVarTuple, nkConstDef:
checkMinSonsLen(a, 3, c.c.config)
when defined(nimsuggest):
inc c.c.inTypeContext
a[^2] = semTemplBody(c, a[^2])
when defined(nimsuggest):
dec c.c.inTypeContext
a[^1] = semTemplBody(c, a[^1])
for j in 0..<a.len-2:
addLocalDecl(c, a[j], symKind)
semTemplIdentDef(c, a, symKind)
else:
illFormedAst(a, c.c.config)
@@ -481,6 +464,25 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
closeScope(c)
else:
a[2] = semTemplBody(c, a[2])
of nkObjectTy:
openScope(c)
result = semTemplBodySons(c, n)
closeScope(c)
of nkRecList:
for i in 0..<n.len:
var a = n[i]
case a.kind:
of nkCommentStmt, nkNilLit, nkSym, nkEmpty: continue
of nkIdentDefs:
semTemplIdentDef(c, a, skField)
of nkRecCase, nkRecWhen:
n[i] = semTemplBody(c, a)
else:
illFormedAst(a, c.c.config)
of nkRecCase:
semTemplIdentDef(c, n[0], skField)
for i in 1..<n.len:
n[i] = semTemplBody(c, n[i])
of nkProcDef, nkLambdaKinds:
result = semRoutineInTemplBody(c, n, skProc)
of nkFuncDef:
@@ -504,14 +506,21 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
if x.kind == nkExprColonExpr:
x[1] = semTemplBody(c, x[1])
of nkBracketExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
for i in 0..<n.len: result.add(n[i])
if n.typ == nil:
# if a[b] is nested inside a typed expression, don't convert it
# back to `[]`(a, b), prepareOperand will not typecheck it again
# and so `[]` will not be resolved
# checking if a[b] is typed should be enough to cover this case
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
for i in 0..<n.len: result.add(n[i])
result = semTemplBodySons(c, result)
of nkCurlyExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
for i in 0..<n.len: result.add(n[i])
if n.typ == nil:
# see nkBracketExpr case for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
for i in 0..<n.len: result.add(n[i])
result = semTemplBodySons(c, result)
of nkAsgn, nkFastAsgn, nkSinkAsgn:
checkSonsLen(n, 2, c.c.config)
@@ -521,17 +530,21 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
let k = a.kind
case k
of nkBracketExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
if a.typ == nil:
# see nkBracketExpr case above for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
let a0 = semTemplBody(c, a[0])
result = semTemplBodySons(c, result)
of nkCurlyExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
if a.typ == nil:
# see nkBracketExpr case above for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
result = semTemplBodySons(c, result)
else:
result = semTemplBodySons(c, n)
@@ -544,6 +557,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
# so we use the generic code for nkDotExpr too
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
# mirror the nkIdent case
# do not symchoice a quoted template parameter (bug #2390):
if s.owner == c.owner and s.kind == skParam and
n.kind == nkAccQuoted and n.len == 1:
@@ -555,13 +569,23 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
elif contains(c.toMixin, s.name.id):
return symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0)
else:
return symChoice(c.c, n, s, scOpen, c.noGenSym > 0)
if s.kind in {skType, skVar, skLet, skConst}:
discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule})
return semTemplSymbol(c.c, n, s, c.noGenSym > 0)
if n.kind == nkDotExpr:
result = n
result[0] = semTemplBody(c, n[0])
inc c.noGenSym
result[1] = semTemplBody(c, n[1])
dec c.noGenSym
if result[1].kind == nkSym and result[1].sym.kind in routineKinds:
# prevent `dotTransformation` from rewriting this node to `nkIdent`
# by making it a symchoice
# in generics this becomes `nkClosedSymChoice` but this breaks code
# as the old behavior here was that this became `nkIdent`
var choice = newNodeIT(nkOpenSymChoice, n[1].info, newTypeS(tyNone, c.c))
choice.add result[1]
result[1] = choice
else:
result = semTemplBodySons(c, n)
of nkExprColonExpr, nkExprEqExpr:
@@ -626,6 +650,8 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
onDef(n[namePos].info, s)
# check parameter list:
#s.scope = c.currentScope
# push noalias flag at first to prevent unwanted recursive calls:
incl(s.flags, sfNoalias)
pushOwner(c, s)
openScope(c)
n[namePos] = newSymNode(s)
@@ -635,17 +661,23 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
setGenericParamsMisc(c, n)
# process parameters:
var allUntyped = true
var nullary = true
if n[paramsPos].kind != nkEmpty:
semParamList(c, n[paramsPos], n[genericParamsPos], s)
# a template's parameters are not gensym'ed even if that was originally the
# case as we determine whether it's a template parameter in the template
# body by the absence of the sfGenSym flag:
let retType = s.typ[0]
if retType != nil and retType.kind != tyUntyped:
allUntyped = false
for i in 1..<s.typ.n.len:
let param = s.typ.n[i].sym
if param.name.s != "_":
if param.name.id != ord(wUnderscore):
param.flags.incl sfTemplateParam
param.flags.excl sfGenSym
if param.typ.kind != tyUntyped: allUntyped = false
# no default value, parameters required in call
if param.ast == nil: nullary = false
else:
s.typ = newTypeS(tyProc, c)
# XXX why do we need tyTyped as a return type again?
@@ -657,6 +689,11 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
n[genericParamsPos] = n[miscPos][1]
n[miscPos] = c.graph.emptyNode
if allUntyped: incl(s.flags, sfAllUntyped)
if nullary and
n[genericParamsPos].kind == nkEmpty and
n[bodyPos].kind != nkEmpty:
# template can be called with alias syntax, remove pushed noalias flag
excl(s.flags, sfNoalias)
if n[patternPos].kind != nkEmpty:
n[patternPos] = semPattern(c, n[patternPos], s)

View File

@@ -16,6 +16,7 @@ const
errIntLiteralExpected = "integer literal expected"
errWrongNumberOfVariables = "wrong number of variables"
errInvalidOrderInEnumX = "invalid order in enum '$1'"
errOverflowInEnumX = "The enum '$1' exceeds its maximum value ($2)"
errOrdinalTypeExpected = "ordinal type expected; given: $1"
errSetTooBig = "set is too large; use `std/sets` for ordinal types with more than 2^16 elements"
errBaseTypeMustBeOrdinal = "base type of a set must be an ordinal"
@@ -130,8 +131,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
e.typ = result
e.position = int(counter)
let symNode = newSymNode(e)
if optNimV1Emulation notin c.config.globalOptions and identToReplace != nil and
c.config.cmd notin cmdDocLike: # A hack to produce documentation for enum fields.
if identToReplace != nil and c.config.cmd notin cmdDocLike:
# A hack to produce documentation for enum fields.
identToReplace[] = symNode
if e.position == 0: hasNull = true
if result.sym != nil and sfExported in result.sym.flags:
@@ -140,6 +141,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
result.n.add symNode
styleCheckDef(c, e)
onDef(e.info, e)
suggestSym(c.graph, e.info, e, c.graph.usageSym)
if sfGenSym notin e.flags:
if not isPure:
addInterfaceOverloadableSymAt(c, c.currentScope, e)
@@ -147,7 +149,11 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
declarePureEnumField(c, e)
if (let conflict = strTableInclReportConflict(symbols, e); conflict != nil):
wrongRedefinition(c, e.info, e.name.s, conflict.info)
inc(counter)
if counter == high(typeof(counter)):
if i > 1 and result.n[i-2].sym.position == high(int):
localError(c.config, n[i].info, errOverflowInEnumX % [e.name.s, $high(typeof(counter))])
else:
inc(counter)
if isPure and sfExported in result.sym.flags:
addPureEnum(c, LazySym(sym: result.sym))
if tfNotNil in e.typ.flags and not hasNull:
@@ -161,7 +167,9 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
addSonSkipIntLit(result, base, c.idgen)
if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base)
if base.kind notin {tyGenericParam, tyGenericInvocation}:
if not isOrdinalType(base, allowEnumWithHoles = true):
if base.kind == tyForward:
c.skipTypes.add n
elif not isOrdinalType(base, allowEnumWithHoles = true):
localError(c.config, n.info, errOrdinalTypeExpected % typeToString(base, preferDesc))
elif lengthOrd(c.config, base) > MaxSetElements:
localError(c.config, n.info, errSetTooBig)
@@ -221,16 +229,27 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool =
return false
proc fitDefaultNode(c: PContext, n: PNode): PType =
inc c.inStaticContext
let expectedType = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil
let oldType = n[^1].typ
n[^1] = semConstExpr(c, n[^1], expectedType = expectedType)
let oldType = n[^1].typ
n[^1].flags.incl nfSem
if n[^2].kind != nkEmpty:
if expectedType != nil and oldType != expectedType:
n[^1] = fitNodeConsiderViewType(c, expectedType, n[^1], n[^1].info)
changeType(c, n[^1], expectedType, true) # infer types for default fields value
# bug #22926; be cautious that it uses `semConstExpr` to
# evaulate the default fields; it's only natural to use
# `changeType` to infer types for constant values
# that's also the reason why we don't use `semExpr` to check
# the type since two overlapping error messages might be produced
result = n[^1].typ
else:
result = n[^1].typ
# xxx any troubles related to defaults fields, consult `semConst` for a potential answer
if n[^1].kind != nkNilLit:
typeAllowedCheck(c, n.info, result, skConst, {taProcContextIsNotMacro, taIsDefaultField})
dec c.inStaticContext
proc isRecursiveType*(t: PType): bool =
# handle simple recusive types before typeFinalPass
@@ -264,6 +283,8 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
localError(c.config, n.info, "range is empty")
var range: array[2, PNode]
# XXX this is still a hard compilation in a generic context, this can
# result in unresolved generic parameters being treated like real types
range[0] = semExprWithType(c, n[1], {efDetermineType})
range[1] = semExprWithType(c, n[2], {efDetermineType})
@@ -272,7 +293,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit(c.idgen)
let hasUnknownTypes = c.inGenericContext > 0 and
rangeT[0].kind == tyFromExpr or rangeT[1].kind == tyFromExpr
(rangeT[0].kind == tyFromExpr or rangeT[1].kind == tyFromExpr)
if not hasUnknownTypes:
if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
@@ -280,7 +301,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
elif not isOrdinalType(rangeT[0]) and rangeT[0].kind notin {tyFloat..tyFloat128} or
rangeT[0].kind == tyBool:
localError(c.config, n.info, "ordinal or float type expected")
localError(c.config, n.info, "ordinal or float type expected, but got " & typeToString(rangeT[0]))
elif enumHasHoles(rangeT[0]):
localError(c.config, n.info, "enum '$1' has holes" % typeToString(rangeT[0]))
@@ -291,9 +312,8 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
else:
result.n.add semConstExpr(c, range[i])
if (result.n[0].kind in {nkFloatLit..nkFloat64Lit} and result.n[0].floatVal.isNaN) or
(result.n[1].kind in {nkFloatLit..nkFloat64Lit} and result.n[1].floatVal.isNaN):
localError(c.config, n.info, "NaN is not a valid start or end for a range")
if result.n[i].kind in {nkFloatLit..nkFloat64Lit} and result.n[i].floatVal.isNaN:
localError(c.config, n.info, "NaN is not a valid range " & (if i == 0: "start" else: "end"))
if weakLeValue(result.n[0], result.n[1]) == impNo:
localError(c.config, n.info, "range is empty")
@@ -327,12 +347,22 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
localError(c.config, n.info, errXExpectsOneTypeParam % "range")
result = newOrPrevType(tyError, prev, c)
proc semArrayIndexConst(c: PContext, e: PNode, info: TLineInfo): PType =
let x = semConstExpr(c, e)
if x.kind in {nkIntLit..nkUInt64Lit}:
result = makeRangeType(c, 0, x.intVal-1, info,
x.typ.skipTypes({tyTypeDesc}))
else:
result = x.typ.skipTypes({tyTypeDesc})
proc semArrayIndex(c: PContext, n: PNode): PType =
if isRange(n):
result = semRangeAux(c, n, nil)
elif n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "..<":
result = errorType(c)
else:
# XXX this is still a hard compilation in a generic context, this can
# result in unresolved generic parameters being treated like real types
let e = semExprWithType(c, n, {efDetermineType})
if e.typ.kind == tyFromExpr:
result = makeRangeWithStaticExpr(c, e.typ.n)
@@ -341,19 +371,23 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
localError(c.config, n.info,
"Array length can't be negative, but was " & $e.intVal)
result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
elif e.kind == nkSym and e.typ.kind == tyStatic:
if e.sym.ast != nil:
return semArrayIndex(c, e.sym.ast)
if e.typ.lastSon.kind != tyGenericParam and not isOrdinalType(e.typ.lastSon):
let info = if n.safeLen > 1: n[1].info else: n.info
localError(c.config, info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc))
result = makeRangeWithStaticExpr(c, e)
if c.inGenericContext > 0: result.flags.incl tfUnresolved
elif e.kind == nkSym and (e.typ.kind == tyStatic or e.typ.kind == tyTypeDesc) :
if e.typ.kind == tyStatic:
if e.sym.ast != nil:
return semArrayIndex(c, e.sym.ast)
if e.typ.lastSon.kind != tyGenericParam and not isOrdinalType(e.typ.lastSon):
let info = if n.safeLen > 1: n[1].info else: n.info
localError(c.config, info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc))
result = makeRangeWithStaticExpr(c, e)
if c.inGenericContext > 0: result.flags.incl tfUnresolved
else:
result = e.typ.skipTypes({tyTypeDesc})
result.flags.incl tfImplicitStatic
elif e.kind in (nkCallKinds + {nkBracketExpr}) and hasUnresolvedArgs(c, e):
if not isOrdinalType(e.typ.skipTypes({tyStatic, tyAlias, tyGenericInst, tySink})):
localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc))
# This is an int returning call, depending on an
# yet unknown generic param (see tgenericshardcases).
# yet unknown generic param (see tuninstantiatedgenericcalls).
# We are going to construct a range type that will be
# properly filled-out in semtypinst (see how tyStaticExpr
# is handled there).
@@ -361,12 +395,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
elif e.kind == nkIdent:
result = e.typ.skipTypes({tyTypeDesc})
else:
let x = semConstExpr(c, e)
if x.kind in {nkIntLit..nkUInt64Lit}:
result = makeRangeType(c, 0, x.intVal-1, n.info,
x.typ.skipTypes({tyTypeDesc}))
else:
result = x.typ.skipTypes({tyTypeDesc})
result = semArrayIndexConst(c, e, n.info)
#localError(c.config, n[1].info, errConstExprExpected)
proc semArray(c: PContext, n: PNode, prev: PType): PType =
@@ -376,14 +405,18 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
let indx = semArrayIndex(c, n[1])
var indxB = indx
if indxB.kind in {tyGenericInst, tyAlias, tySink}: indxB = lastSon(indxB)
if indxB.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}:
discard
elif not isOrdinalType(indxB):
if indxB.kind notin {tyGenericParam, tyStatic, tyFromExpr} and
tfUnresolved notin indxB.flags:
if not isOrdinalType(indxB):
localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(indxB, preferDesc))
elif enumHasHoles(indxB):
localError(c.config, n[1].info, "enum '$1' has holes" %
typeToString(indxB.skipTypes({tyRange})))
elif indxB.kind != tyRange and
lengthOrd(c.config, indxB) > high(uint16).int:
# assume range type is intentional
localError(c.config, n[1].info,
"index type '$1' for array is too large" % typeToString(indxB))
base = semTypeNode(c, n[2], nil)
# ensure we only construct a tyArray when there was no error (bug #3048):
result = newOrPrevType(tyArray, prev, c)
@@ -416,68 +449,6 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
localError(c.config, n.info, errXExpectsOneTypeParam % "ordinal")
result = newOrPrevType(tyError, prev, c)
proc semTypeIdent(c: PContext, n: PNode): PSym =
if n.kind == nkSym:
result = getGenSym(c, n.sym)
else:
result = pickSym(c, n, {skType, skGenericParam, skParam})
if result.isNil:
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
if result != nil:
markUsed(c, n.info, result)
onUse(n.info, result)
if result.kind == skParam and result.typ.kind == tyTypeDesc:
# This is a typedesc param. is it already bound?
# it's not bound when it's used multiple times in the
# proc signature for example
if c.inGenericInst > 0:
let bound = result.typ[0].sym
if bound != nil: return bound
return result
if result.typ.sym == nil:
localError(c.config, n.info, errTypeExpected)
return errorSym(c, n)
result = result.typ.sym.copySym(nextSymId c.idgen)
result.typ = exactReplica(result.typ)
result.typ.flags.incl tfUnresolved
if result.kind == skGenericParam:
if result.typ.kind == tyGenericParam and result.typ.len == 0 and
tfWildcard in result.typ.flags:
# collapse the wild-card param to a type
result.transitionGenericParamToType()
result.typ.flags.excl tfWildcard
return
else:
localError(c.config, n.info, errTypeExpected)
return errorSym(c, n)
if result.kind != skType and result.magic notin {mStatic, mType, mTypeOf}:
# this implements the wanted ``var v: V, x: V`` feature ...
var ov: TOverloadIter
var amb = initOverloadIter(ov, c, n)
while amb != nil and amb.kind != skType:
amb = nextOverloadIter(ov, c, n)
if amb != nil: result = amb
else:
if result.kind != skError: localError(c.config, n.info, errTypeExpected)
return errorSym(c, n)
if result.typ.kind != tyGenericParam:
# XXX get rid of this hack!
var oldInfo = n.info
when defined(useNodeIds):
let oldId = n.id
reset(n[])
when defined(useNodeIds):
n.id = oldId
n.transitionNoneToSym()
n.sym = result
n.info = oldInfo
n.typ = result.typ
else:
localError(c.config, n.info, "identifier expected")
result = errorSym(c, n)
proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
if n.len == 0:
localError(c.config, n.info, errTypeExpected)
@@ -565,6 +536,12 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
else: discard
else:
result = semIdentVis(c, kind, n, allowed)
case kind
of skField: implicitPragmas(c, result, n.info, fieldPragmas)
of skVar: implicitPragmas(c, result, n.info, varPragmas)
of skLet: implicitPragmas(c, result, n.info, letPragmas)
of skConst: implicitPragmas(c, result, n.info, constPragmas)
else: discard
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
let ex = t[branchIndex][currentEx].skipConv
@@ -795,7 +772,13 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
if e.kind != nkIntLit: discard "don't report followup error"
elif e.intVal != 0 and branch == nil: branch = it[1]
else:
it[0] = forceBool(c, semExprWithType(c, it[0]))
# XXX this is still a hard compilation in a generic context, this can
# result in unresolved generic parameters being treated like real types
let e = semExprWithType(c, it[0], {efDetermineType})
if e.typ.kind == tyFromExpr:
it[0] = makeStaticExpr(c, e)
else:
it[0] = forceBool(c, e)
of nkElse:
checkSonsLen(it, 1, c.config)
if branch == nil: branch = it[0]
@@ -803,8 +786,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
else: illFormedAst(n, c.config)
if c.inGenericContext > 0:
# use a new check intset here for each branch:
var newCheck: IntSet
assign(newCheck, check)
var newCheck: IntSet = check
var newPos = pos
var newf = newNodeI(nkRecList, n.info)
semRecordNodeAux(c, it[idx], newCheck, newPos, newf, rectype, hasCaseFields)
@@ -912,12 +894,19 @@ proc skipGenericInvocation(t: PType): PType {.inline.} =
while result.kind in {tyGenericInst, tyGenericBody, tyRef, tyPtr, tyAlias, tySink, tyOwned}:
result = lastSon(result)
proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
obj: PType) =
assert obj.kind == tyObject
if (obj.len > 0) and (obj[0] != nil):
addInheritedFields(c, check, pos, obj[0].skipGenericInvocation)
addInheritedFieldsAux(c, check, pos, obj.n)
proc tryAddInheritedFields(c: PContext, check: var IntSet, pos: var int,
obj: PType, n: PNode, isPartial = false, innerObj: PType = nil): bool =
if ((not isPartial) and (obj.kind notin {tyObject, tyGenericParam} or tfFinal in obj.flags)) or
(innerObj != nil and obj.sym.id == innerObj.sym.id):
localError(c.config, n.info, "Cannot inherit from: '" & $obj & "'")
result = false
elif obj.kind == tyObject:
result = true
if (obj.len > 0) and (obj[0] != nil):
result = result and tryAddInheritedFields(c, check, pos, obj[0].skipGenericInvocation, n, false, obj)
addInheritedFieldsAux(c, check, pos, obj.n)
else:
result = true
proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType =
if n.len == 0:
@@ -944,7 +933,11 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
if concreteBase.sym != nil and concreteBase.sym.magic == mException and
sfSystemModule notin c.module.flags:
message(c.config, n.info, warnInheritFromException, "")
addInheritedFields(c, check, pos, concreteBase)
if not tryAddInheritedFields(c, check, pos, concreteBase, n):
return newType(tyError, nextTypeId c.idgen, result.owner)
elif concreteBase.kind == tyForward:
c.skipTypes.add n #we retry in the final pass
else:
if concreteBase.kind != tyError:
localError(c.config, n[1].info, "inheritance only works with non-final objects; " &
@@ -962,7 +955,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
result.n = newNodeI(nkRecList, n.info)
else:
# partial object so add things to the check
addInheritedFields(c, check, pos, result)
if not tryAddInheritedFields(c, check, pos, result, n, isPartial = true):
return newType(tyError, nextTypeId c.idgen, result.owner)
semRecordNodeAux(c, n[2], check, pos, result.n, result)
if n[0].kind != nkEmpty:
# dummy symbol for `pragma`:
@@ -1026,7 +1021,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
t.rawAddSonNoPropagationOfTypeFlags result
result = t
else: discard
if result.kind == tyRef and c.config.selectedGC in {gcArc, gcOrc}:
if result.kind == tyRef and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
result.flags.incl tfHasAsgn
proc findEnforcedStaticType(t: PType): PType =
@@ -1044,7 +1039,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
if kind == skMacro:
let staticType = findEnforcedStaticType(param.typ)
if staticType != nil:
var a = copySym(param, nextSymId c.idgen)
var a = copySym(param, c.idgen)
a.typ = staticType.base
addDecl(c, a)
#elif param.typ != nil and param.typ.kind == tyTypeDesc:
@@ -1052,7 +1047,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
else:
# within a macro, every param has the type NimNode!
let nn = getSysSym(c.graph, param.info, "NimNode")
var a = copySym(param, nextSymId c.idgen)
var a = copySym(param, c.idgen)
a.typ = nn.typ
addDecl(c, a)
else:
@@ -1082,7 +1077,7 @@ proc addImplicitGeneric(c: PContext; typeClass: PType, typId: PIdent;
let owner = if typeClass.sym != nil: typeClass.sym
else: getCurrOwner(c)
var s = newSym(skType, finalTypId, nextSymId c.idgen, owner, info)
var s = newSym(skType, finalTypId, c.idgen, owner, info)
if sfExplain in owner.flags: s.flags.incl sfExplain
if typId == nil: s.flags.incl(sfAnon)
s.linkTo(typeClass)
@@ -1311,6 +1306,16 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if hasDefault:
def = a[^1]
if a.len > 3:
var msg = ""
for j in 0 ..< a.len - 2:
if msg.len != 0: msg.add(", ")
msg.add($a[j])
msg.add(" all have default value '")
msg.add(def.renderTree)
msg.add("', this may be unintentional, " &
"either use ';' (semicolon) or explicitly write each default value")
message(c.config, a.info, warnImplicitDefaultValue, msg)
block determineType:
var defTyp = typ
if genericParams != nil and genericParams.len > 0:
@@ -1359,6 +1364,10 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
for j in 0..<a.len-2:
var arg = newSymG(skParam, if a[j].kind == nkPragmaExpr: a[j][0] else: a[j], c)
if arg.name.id == ord(wUnderscore):
arg.flags.incl(sfGenSym)
elif containsOrIncl(check, arg.name.id):
localError(c.config, a[j].info, "attempt to redefine: '" & arg.name.s & "'")
if a[j].kind == nkPragmaExpr:
pragma(c, arg, a[j][1], paramPragmas)
if not hasType and not hasDefault and kind notin {skTemplate, skMacro}:
@@ -1367,26 +1376,26 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
else:
localError(c.config, a.info, "parameter '$1' requires a type" % arg.name.s)
typ = errorType(c)
var nameForLift = arg.name.s
if sfGenSym in arg.flags:
nameForLift.add("`gensym" & $arg.id)
let lifted = liftParamType(c, kind, genericParams, typ,
arg.name.s, arg.info)
nameForLift, arg.info)
let finalType = if lifted != nil: lifted else: typ.skipIntLit(c.idgen)
arg.typ = finalType
arg.position = counter
arg.constraint = constraint
if constraint != nil:
#only replace the constraint when it has been set as arg could contain codegenDecl
arg.constraint = constraint
inc(counter)
if def != nil and def.kind != nkEmpty:
arg.ast = copyTree(def)
if arg.name.s == "_":
arg.flags.incl(sfGenSym)
elif containsOrIncl(check, arg.name.id):
localError(c.config, a[j].info, "attempt to redefine: '" & arg.name.s & "'")
result.n.add newSymNode(arg)
rawAddSon(result, finalType)
addParamOrResult(c, arg, kind)
styleCheckDef(c, a[j].info, arg)
onDef(a[j].info, arg)
if {optNimV1Emulation, optNimV12Emulation} * c.config.globalOptions == {}:
a[j] = newSymNode(arg)
a[j] = newSymNode(arg)
var r: PType
if n[0].kind != nkEmpty:
@@ -1413,7 +1422,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
"' is only valid for macros and templates")
# 'auto' as a return type does not imply a generic:
elif r.kind == tyAnything:
discard
r = copyType(r, nextTypeId c.idgen, r.owner)
r.flags.incl tfRetType
elif r.kind == tyStatic:
# type allowed should forbid this type
discard
@@ -1481,25 +1491,35 @@ proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
result = semTypeNode(c, n, nil)
n.typ = makeTypeDesc(c, result)
proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) =
proc trySemObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType): bool =
var
check = initIntSet()
pos = 0
let
realBase = t[0]
base = skipTypesOrNil(realBase, skipPtrs)
result = true
if base.isNil:
localError(c.config, n.info, errIllegalRecursionInTypeX % "object")
else:
let concreteBase = skipGenericInvocation(base)
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
addInheritedFields(c, check, pos, concreteBase)
if not tryAddInheritedFields(c, check, pos, concreteBase, n):
return false
else:
if concreteBase.kind != tyError:
localError(c.config, n.info, errInheritanceOnlyWithNonFinalObjects)
var newf = newNodeI(nkRecList, n.info)
semRecordNodeAux(c, t.n, check, pos, newf, t)
proc containsGenericInvocationWithForward(n: PNode): bool =
if n.kind == nkSym and n.sym.ast != nil and n.sym.ast.len > 1 and n.sym.ast[2].kind == nkObjectTy:
for p in n.sym.ast[2][^1]:
if p.kind == nkIdentDefs and p[1].typ != nil and p[1].typ.kind == tyGenericInvocation and
p[1][0].kind == nkSym and p[1][0].typ.kind == tyForward:
return true
return false
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if s.typ == nil:
localError(c.config, n.info, "cannot instantiate the '$1' $2" %
@@ -1509,20 +1529,24 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
var t = s.typ.skipTypes({tyAlias})
if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
t = t.base
result = newOrPrevType(tyGenericInvocation, prev, c)
addSonSkipIntLit(result, t, c.idgen)
template addToResult(typ) =
template addToResult(typ, skip) =
if typ.isNil:
internalAssert c.config, false
rawAddSon(result, typ)
else: addSonSkipIntLit(result, typ, c.idgen)
else:
if skip:
addSonSkipIntLit(result, typ, c.idgen)
else:
rawAddSon(result, makeRangeWithStaticExpr(c, typ.n))
if t.kind == tyForward:
for i in 1..<n.len:
var elem = semGenericParamInInvocation(c, n[i])
addToResult(elem)
addToResult(elem, true)
return
elif t.kind != tyGenericBody:
# we likely got code of the form TypeA[TypeB] where TypeA is
@@ -1542,7 +1566,8 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
return newOrPrevType(tyError, prev, c)
var isConcrete = true
let rType = m.call[0].typ
let mIndex = if rType != nil: rType.len - 1 else: -1
for i in 1..<m.call.len:
var typ = m.call[i].typ
# is this a 'typedesc' *parameter*? If so, use the typedesc type,
@@ -1550,17 +1575,22 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if m.call[i].kind == nkSym and m.call[i].sym.kind == skParam and
typ.kind == tyTypeDesc and containsGenericType(typ):
isConcrete = false
addToResult(typ)
addToResult(typ, true)
else:
typ = typ.skipTypes({tyTypeDesc})
if containsGenericType(typ): isConcrete = false
addToResult(typ)
var skip = true
if mIndex >= i - 1 and tfImplicitStatic in rType[i - 1].flags and isIntLit(typ):
skip = false
addToResult(typ, skip)
if isConcrete:
if s.ast == nil and s.typ.kind != tyCompositeTypeClass:
# XXX: What kind of error is this? is it still relevant?
localError(c.config, n.info, errCannotInstantiateX % s.name.s)
result = newOrPrevType(tyError, prev, c)
elif containsGenericInvocationWithForward(n[0]):
c.skipTypes.add n #fixes 1500
else:
result = instGenericContainer(c, n.info, result,
allowMetaTypes = false)
@@ -1573,7 +1603,8 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
return errorType(c)
if tx != result and tx.kind == tyObject:
if tx[0] != nil:
semObjectTypeForInheritedGenericInst(c, n, tx)
if not trySemObjectTypeForInheritedGenericInst(c, n, tx):
return newOrPrevType(tyError, prev, c)
var position = 0
recomputeFieldPositions(tx, tx.n, position)
@@ -1684,7 +1715,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
internalAssert c.config, dummyName.kind == nkIdent
var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
dummyName.ident, nextSymId c.idgen, owner, param.info)
dummyName.ident, c.idgen, owner, param.info)
dummyParam.typ = dummyType
incl dummyParam.flags, sfUsed
addDecl(c, dummyParam)
@@ -1748,7 +1779,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode,
if n[1].kind != nkEmpty and n[1].len > 0:
pragma(c, s, n[1], procTypePragmas)
when useEffectSystem: setEffectsForProcType(c.graph, result, n[1])
elif c.optionStack.len > 0 and optNimV1Emulation notin c.config.globalOptions:
elif c.optionStack.len > 0:
# we construct a fake 'nkProcDef' for the 'mergePragmas' inside 'implicitPragmas'...
s.ast = newTree(nkProcDef, newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info),
newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info))
@@ -1790,6 +1821,73 @@ proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
fixupTypeOf(c, prev, t)
result = t.typ
proc semTypeIdent(c: PContext, n: PNode): PSym =
if n.kind == nkSym:
result = getGenSym(c, n.sym)
else:
result = pickSym(c, n, {skType, skGenericParam, skParam})
if result.isNil:
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
if result != nil:
markUsed(c, n.info, result)
onUse(n.info, result)
# alias syntax, see semSym for skTemplate, skMacro
if result.kind in {skTemplate, skMacro} and sfNoalias notin result.flags:
let t = semTypeExpr(c, n, nil)
result = symFromType(c, t, n.info)
if result.kind == skParam and result.typ.kind == tyTypeDesc:
# This is a typedesc param. is it already bound?
# it's not bound when it's used multiple times in the
# proc signature for example
if c.inGenericInst > 0:
let bound = result.typ[0].sym
if bound != nil: return bound
return result
if result.typ.sym == nil:
localError(c.config, n.info, errTypeExpected)
return errorSym(c, n)
result = result.typ.sym.copySym(c.idgen)
result.typ = exactReplica(result.typ)
result.typ.flags.incl tfUnresolved
if result.kind == skGenericParam:
if result.typ.kind == tyGenericParam and result.typ.len == 0 and
tfWildcard in result.typ.flags:
# collapse the wild-card param to a type
result.transitionGenericParamToType()
result.typ.flags.excl tfWildcard
return
else:
localError(c.config, n.info, errTypeExpected)
return errorSym(c, n)
if result.kind != skType and result.magic notin {mStatic, mType, mTypeOf}:
# this implements the wanted ``var v: V, x: V`` feature ...
var ov: TOverloadIter
var amb = initOverloadIter(ov, c, n)
while amb != nil and amb.kind != skType:
amb = nextOverloadIter(ov, c, n)
if amb != nil: result = amb
else:
if result.kind != skError: localError(c.config, n.info, errTypeExpected)
return errorSym(c, n)
if result.typ.kind != tyGenericParam:
# XXX get rid of this hack!
var oldInfo = n.info
when defined(useNodeIds):
let oldId = n.id
reset(n[])
when defined(useNodeIds):
n.id = oldId
n.transitionNoneToSym()
n.sym = result
n.info = oldInfo
n.typ = result.typ
else:
localError(c.config, n.info, "identifier expected")
result = errorSym(c, n)
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil
inc c.inTypeContext
@@ -1832,7 +1930,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = semTypeExpr(c, n, prev)
else:
let op = considerQuotedIdent(c, n[0])
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
if op.id == ord(wAnd) or op.id == ord(wOr) or op.s == "|":
checkSonsLen(n, 3, c.config)
var
t1 = semTypeNode(c, n[1], nil)
@@ -1909,6 +2007,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = semTypeExpr(c, n[1], prev)
else:
if c.inGenericContext > 0 and n.kind == nkCall:
let n = semGenericStmt(c, n)
result = makeTypeFromExpr(c, n.copyTree)
else:
result = semTypeExpr(c, n, prev)
@@ -2043,25 +2142,32 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkOutTy: result = semVarOutType(c, n, prev, {tfIsOutParam})
of nkDistinctTy: result = semDistinct(c, n, prev)
of nkStaticTy: result = semStaticType(c, n[0], prev)
of nkIteratorTy:
if n.len == 0:
of nkProcTy, nkIteratorTy:
if n.len == 0 or n[0].kind == nkEmpty:
# 0 length or empty param list with possible pragmas imply typeclass
result = newTypeS(tyBuiltInTypeClass, c)
let child = newTypeS(tyProc, c)
child.flags.incl tfIterator
if n.kind == nkIteratorTy:
child.flags.incl tfIterator
if n.len > 0 and n[1].kind != nkEmpty and n[1].len > 0:
# typeclass with pragma
let symKind = if n.kind == nkIteratorTy: skIterator else: skProc
# dummy symbol for `pragma`:
var s = newSymS(symKind, newIdentNode(getIdent(c.cache, "dummy"), n.info), c)
s.typ = child
# for now only call convention pragmas supported in proc typeclass
pragma(c, s, n[1], {FirstCallConv..LastCallConv})
result.addSonSkipIntLit(child, c.idgen)
else:
result = semProcTypeWithScope(c, n, prev, skIterator)
if result.kind == tyProc:
let symKind = if n.kind == nkIteratorTy: skIterator else: skProc
result = semProcTypeWithScope(c, n, prev, symKind)
if result == nil:
localError(c.config, n.info, "type expected, but got: " & renderTree(n))
result = newOrPrevType(tyError, prev, c)
if n.kind == nkIteratorTy and result.kind == tyProc:
result.flags.incl(tfIterator)
if n.lastSon.kind == nkPragma and hasPragma(n.lastSon, wInline):
result.callConv = ccInline
else:
result.callConv = ccClosure
of nkProcTy:
if n.len == 0:
result = newConstraint(c, tyProc)
else:
result = semProcTypeWithScope(c, n, prev, skProc)
if result.callConv == ccClosure and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
result.flags.incl tfHasAsgn
of nkEnumTy: result = semEnum(c, n, prev)
of nkType: result = n.typ
of nkStmtListType: result = semStmtListType(c, n, prev)

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