Compare commits

...

384 Commits

Author SHA1 Message Date
narimiran
5a598a4945 update makefile.nimf 2026-05-22 09:57:47 +02:00
narimiran
5360d076f3 update actions' versions 2026-05-22 09:31:47 +02:00
Andreas Rumpf
71467ecd86 fixes DOS via malformed HTTP protocol (#25793)
refs https://github.com/nim-lang/Nim/pull/25568

(cherry picked from commit f0077a12b2)
2026-05-22 08:56:00 +02:00
narimiran
ec324ad073 disable failing pacakge 2024-07-09 13:45:16 +02:00
narimiran
9ce81868a8 Revert "fixes #9940; genericAssign does not take care of the importC variables in refc [backport] (#23761)"
This reverts commit fda43d1f0a.
2024-07-09 13:02:30 +02:00
narimiran
d993aff496 Revert "try to fix broken tests"
This reverts commit 786bbff1ae.
2024-07-09 13:02:19 +02:00
narimiran
786bbff1ae try to fix broken tests 2024-06-28 08:31:43 +02:00
ringabout
fda43d1f0a fixes #9940; genericAssign does not take care of the importC variables in refc [backport] (#23761)
fixes #9940

(cherry picked from commit 828cd58d8a)
2024-06-27 14:09:14 +02:00
ringabout
6789859503 Update nimsuggest.nim 2024-06-18 22:46:59 +08:00
Juan M Gómez
d9b1477b81 [Backport 1.6] Nimsuggest handle unknown file (#23702) 2024-06-10 17:14:08 +02:00
Giuliano Mega
3864066408 [Backport 1.6] Fix reset code gen for range types (#22462, #23214) (#23215) (#23638)
This is a backport of https://github.com/nim-lang/Nim/pull/23215. I
thought I'd put a PR instead of [just asking for
it](https://github.com/nim-lang/Nim/pull/23215#issuecomment-2125829028).
🙂
2024-05-23 11:30:15 +02:00
Juan M Gómez
53424c0036 [Backport 1.6] Skips generic owner when mangling instances (#23599) 2024-05-14 11:25:33 +02:00
Nikolay Nikolov
6a63df181f [backport v1.6.x] fixes the discVal register is used after free in vmgen (#22688) (#23553)
follow up https://github.com/nim-lang/Nim/pull/11955

(cherry picked from commit b1a8d6976f)

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2024-05-01 22:56:16 +02:00
bptato
b7b3f87719 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:58:18 +02:00
narimiran
8ebb4dc30a bump NimVersion to 1.6.21 2024-04-16 15:49:03 +02:00
Nikolay Nikolov
19fdbfc173 Converted the 'invalid kind for firstOrd/lastOrd(XXX)' messages from internal errors to fatal errors. (#23443) (#23447)
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-04-06 14:33:03 +02:00
narimiran
8f9fde0615 bump NimVersion to 1.6.20 2024-03-19 16:37:43 +01:00
Nikolay Nikolov
e6ee956845 fixes #22753; Nimsuggest segfault with invalid assignment to table (#22781) (#23314)
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-03-14 18:35:25 +01:00
Juan M Gómez
afced7d9ab [Backport 1.6] When NimScript errors prevents NimSuggest from Init (#23348) 2024-03-03 17:36:34 +01:00
Nikolay Nikolov
51c86fdae7 * fixed nimsuggest crash when opening a .nim file, that contain a {.fatal: "msg".} pragma. (#23325) (#23329)
(cherry picked from commit 773c066634)
2024-02-24 07:40:47 +01:00
Juan M Gómez
d08bba579d [Backport 1.6] Itanium mangling scheme #23301 (#23302) 2024-02-13 08:08:46 +01:00
ringabout
ac1dc03258 fixes regression #23280; Operations on inline toOpenArray len return a wrong result (#23285)
fixes #23280

(cherry picked from commit 4b67cccf50)
2024-02-07 20:26:27 +01:00
Nikolay Nikolov
e8fe9275b5 + show the inferred exception list (as part of the type) for functions that don't have an explicit .raises pragma (#23193) (#23213)
(cherry picked from commit 18b5fb256d)
2024-01-16 15:36:36 +08:00
Juan M Gómez
0f97dd6fb3 backport nimsuggest info:capabilities (#23190) 2024-01-09 22:48:24 +08:00
Juan M Gómez
e3bcbf5f15 makes nimsuggest con work under v3 [Backport_1.6.18] (#23158)
Co-authored-by: Jake Leahy <jake@leahy.dev>
2024-01-08 20:30:46 +01:00
narimiran
d84e2d3f63 update macOS to 12, remove one package from testing 2024-01-08 13:35:26 +01:00
ringabout
7912685905 fixes #23148; restricts infix path concatenation to what starts with / (#23150)
fixes #23148

(cherry picked from commit c7d742e484)
2024-01-03 10:56:47 +01:00
narimiran
2cc4da8fd4 bump NimVersion to 1.6.19 2024-01-03 10:56:24 +01:00
narimiran
a749a8b742 bump NimVersion to 1.6.18 2023-12-14 17:52:25 +01:00
Nikolay Nikolov
9a87057f0b Skip trailing asterisk when placing inlay type hints. Fixes #23067 (backport of #23068) (#23071)
(cherry picked from commit a3739751a8)
2023-12-14 09:26:12 +08:00
Nikolay Nikolov
efd5ed7328 backport to version 1.6: Also show the raises pragma when converting proc types to string (#23026) (#23029)
This affects also nimsuggest hints (e.g. on mouse hover), as well as
compiler messages.

(cherry picked from commit 618ccb6b6a)
2023-12-12 10:36:58 +01:00
Jake Leahy
2e87171e14 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:42 +01:00
tersec
9cbd8695e7 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:57 +01:00
Nikolay Nikolov
6f0cad6843 backport to v 1.6: nimsuggest: Added optional command line option '--clientProcessId:XXX' (#22969) (#22982)
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:37 +01:00
Nikolay Nikolov
ef10224e61 Backport to 1.6: Introduced version 4 of the NimSuggest protocol. The InlayHints feature made V4 or later only. (#22953) (#22962)
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:38 +08:00
Nikolay Nikolov
f3382743dd backport to version 1.6: nimsuggest: Instead of checking for protocol version 3 exactly, check for version 3 or later. (#22945) (#22956)
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:15 +08:00
Nikolay Nikolov
1dab585a26 Added new command line option --info:X to nimsuggest for obtaining … (#22942)
…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-17 17:29:14 +08:00
Nikolay Nikolov
a77ca1a4bf Inlay hints backport to Nim v1.6.x (#22920) 2023-11-08 00:22:40 +01:00
narimiran
0779a5e11b bump NimVersion to 1.6.17 2023-11-01 19:43:25 +01:00
ringabout
a17c077f78 fixes chronicles (#22899) 2023-11-01 17:03:19 +08:00
ringabout
47010a3919 fixes #22874; backport #22088 to version-1-6 2023-11-01 00:51:48 +00:00
ringabout
3c9b68dc15 fixes CI; disable SSL tests on osx for now (#22304)
* test CI

* disable osx

(cherry picked from commit 993fcf5bda)
2023-10-10 08:55:48 +02:00
narimiran
ec72abc7b7 fixes stint CI 2023-10-10 08:53:45 +02:00
narimiran
a08f56f9ba bump NimVersion to 1.6.16 2023-10-09 19:07:36 +02:00
SirOlaf
246267aa52 Exclude block from endsInNoReturn, fix regression (#22632)
Co-authored-by: SirOlaf <>
(cherry picked from commit d2f36c071b)
2023-09-15 19:49:57 +02:00
SirOlaf
ce8d9dd1cb 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-15 12:58:20 +02:00
ringabout
4fc535fbd6 fixes #17197; fixes #22560; fixes the dest of newSeqOfCap in refc (#22594)
(cherry picked from commit 5bd1afc3f9)
2023-09-15 12:58:20 +02:00
ringabout
2d529edf3e fixes #22541; peg matchLen can raise an unlisted exception: Exception (#22545)
The `mopProc` is a recursive function.

(cherry picked from commit c56a712e7d)
2023-09-15 09:10:56 +02:00
metagn
d37901fe06 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-15 09:10:56 +02:00
ringabout
dc59e67a12 fixes bareExcept warnings; catch specific exceptions (#21119)
* fixes bareExcept warnings; catch specific exceptions

* Update lib/pure/coro.nim

(cherry picked from commit 9207d77848)
2023-09-15 08:39:22 +02:00
ringabout
09f7be13b6 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-15 08:37:31 +02:00
Andreas Rumpf
d80397c7d7 fixes #22138 (#22221)
(cherry picked from commit 86ff37fab8)
2023-09-14 17:02:49 +02:00
Juan M Gómez
efa3479e4e reset macrocache after each script evaluation (#22195)
(cherry picked from commit 2f109595e9)
2023-09-14 16:59:13 +02:00
ringabout
e8ec3efd3d allow addressing elements of openArray[char] in VM (#22045)
allow addressing elements of openArray[char]

(cherry picked from commit a8d0dda833)
2023-09-14 14:07:08 +02:00
metagn
8f102f9e62 retain forced open undeclared ident information (#22019)
(cherry picked from commit ce72b564bc)
2023-09-14 14:04:43 +02:00
ringabout
876f6d69a8 fixes #21974; fixes sameConstant fieldDefect (#21981)
* fixes #21974; fixes sameConstant fieldDefect

* add a test case

(cherry picked from commit 8e35b3d577)
2023-09-14 14:04:43 +02:00
heterodoxic
50173ec7ec prevent spamming of thread local forward declarations in C/C++ output (#21955)
(cherry picked from commit f47b27d532)
2023-09-14 14:03:47 +02:00
metagn
ecab260330 underscore as special word (#21766)
* underscore as special word

* fix really hard to notice error

(cherry picked from commit ca82b4ea16)
2023-09-14 13:09:43 +02:00
ringabout
43ce0558b4 handle quoted routine symbols and non symbols expressions as before (#21740)
(cherry picked from commit 560fa9a1fe)
2023-09-14 12:00:47 +02:00
narimiran
19b3f8c0ea Revert "fixes #16790; fixes #19075; put big arrays on the constant seqs; don't inline them in the VM; big performance boost (#21318)"
This reverts commit 7ad8c44e28.
2023-09-14 06:03:34 +02:00
SirOlaf
5ad4b72ac7 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-12 09:24:33 +02:00
Amjad Ben Hedhili
d7dfbf026b Remove some unnecessary initialization in string operations (#22579)
* `prepareAdd`
* `toNimStr`
* `setLengthStrV2`
* `NimAsgnStrV2`
* `prepareMutation`
* Some cleanups

(cherry picked from commit a4df44d9fb)
2023-09-12 09:24:33 +02:00
metagn
79a1990774 use dummy dest for void branches to fix noreturn in VM (#22617)
fixes #22216

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

(cherry picked from commit 6738f44af3)
2023-09-12 09:24:33 +02:00
metagn
965eeb68e2 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-11 21:33:48 +02:00
metagn
0dbac38d12 clearer error for different size int/float cast in VM (#22582)
refs #16547

(cherry picked from commit b6cea7b599)
2023-09-11 21:33:42 +02:00
metagn
f16e4dd22a 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-11 21:33:35 +02:00
metagn
ede6bc4d67 define toList procs after add for lists [backport] (#22573)
fixes #22543

(cherry picked from commit 94454addb2)
2023-09-11 21:33:21 +02:00
ringabout
d2f91ab1b9 newStringOfCap now won't initialize all elements anymore (#22568)
newStringOfCap nows won't initialize all elements anymore

(cherry picked from commit 2e7c8a339f)
2023-09-11 21:33:13 +02:00
Bung
69faab3cf6 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)
2023-09-11 21:32:58 +02:00
SirOlaf
b7a1210964 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-11 21:32:22 +02:00
ringabout
0d5999e6a8 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-11 21:31:40 +02:00
Jason Beetham
60dc41a5e4 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-09-11 21:31:32 +02:00
Emery Hemingway
ba5d873f63 Add Linux constant SO_BINDTODEVICE (#22468)
(cherry picked from commit 1927ae72d0)
2023-09-11 21:31:20 +02:00
Bung
f55f3d6ffd Fix #5780 (#22428)
* fix #5780

(cherry picked from commit 46e94c83d4)
2023-09-11 21:30:06 +02:00
Jake Leahy
118f83f965 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-11 20:41:29 +02:00
Eric N. Vander Weele
72afd29a9a 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.

(cherry picked from commit f1ac979184)
2023-09-11 20:41:29 +02:00
SirOlaf
30921aaff5 Check try block for endsInNoReturn (#22314)
Co-authored-by: SirOlaf <>
(cherry picked from commit 62869a5c68)
2023-09-11 20:41:28 +02:00
SirOlaf
a3b65da80f Open scope for defer (#22315)
Co-authored-by: SirOlaf <>
(cherry picked from commit 3ebe24977c)
2023-09-11 20:41:28 +02:00
ringabout
ba2d8ba468 fixes #22297; return in the finally in the closure iterators (#22300)
ref #22297; return in the finally in the closure iterators

(cherry picked from commit b02c1dd6ca)
2023-09-11 20:41:28 +02:00
Anna
0ac3461c7d Fix #22281 (#22289)
Respect `--gcc.exe` and similar options when `--genScript:on` is used.

(cherry picked from commit 14a9929464)
2023-09-11 20:24:58 +02:00
ringabout
e7fc94e130 gendepends now supports pkgs2 (#22277)
(cherry picked from commit 3b377937de)
2023-09-11 20:24:21 +02:00
ringabout
44708f4b01 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

(cherry picked from commit ecc6ab7ee0)
2023-09-11 20:24:11 +02:00
narimiran
0e9250264b fix wrong import 2023-09-11 16:10:50 +02:00
Jake Leahy
5ffd507014 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

(cherry picked from commit 1b132ddaa2)
2023-09-11 13:52:59 +02:00
Andreas Rumpf
322fc31041 fixes #22137 (#22170)
(cherry picked from commit ce0909f047)
2023-09-11 13:52:59 +02:00
Jacek Sieka
5ab9945345 fix Sigaction struct definition (#22160)
SigInfo is still wrong (most of its fields are in a union)

(cherry picked from commit 47635d3031)
2023-09-11 13:52:59 +02:00
Jacek Sieka
b0cee7c0c5 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

(cherry picked from commit cb40f11e6c)
2023-09-11 13:52:59 +02:00
metagn
5e4648232b 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

(cherry picked from commit 20037a4749)
2023-09-11 13:52:59 +02:00
ringabout
3bd03d71a0 fixes #21110; duplicate proc definitions for inline iters (#21136)
fixes #21110; duplicate proc definitions for iters

(cherry picked from commit 88114948c4)
2023-09-11 13:52:58 +02:00
ringabout
238efc025e 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

(cherry picked from commit ac7b8b678c)
2023-09-11 13:52:58 +02:00
Bung
a66158dd3d 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>
(cherry picked from commit 3ad2e7df1c)
2023-09-11 13:52:58 +02:00
Zoom
6863b5d289 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>
(cherry picked from commit 5e529b3bfa)
2023-09-11 13:52:58 +02:00
Andreas Rumpf
9d573f4a1d 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

(cherry picked from commit e8d0f1c3ae)
2023-09-11 13:52:58 +02:00
ringabout
070ecb036c 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

(cherry picked from commit 77beb15214)
2023-09-11 13:52:58 +02:00
metagn
107ec62baf 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

(cherry picked from commit 3ac2d81601)
2023-09-11 13:52:58 +02:00
ringabout
ffcccd5986 clean up isNilConversion for seqs, strings (#22057)
(cherry picked from commit 49e11d9dcc)
2023-09-11 12:02:29 +02:00
Juan Carlos
c001b11320 Improve compiler messages (#22040)
* Improve compiler messages

(cherry picked from commit ea91cfb305)
2023-09-11 12:02:29 +02:00
Juan Carlos
e4c13c3fd4 Improve compiler messages (#22028)
* Improve compiler messages with simpler code

(cherry picked from commit 9f3d1b1290)
2023-09-11 12:02:29 +02:00
heterodoxic
6b11a9ec28 fixes #15428 by updating deep open array copy codegen (#21935)
* fix #15428

* add test

(cherry picked from commit af3fd5a010)
2023-09-11 12:02:28 +02:00
Bung
173a15b370 fix #21251 Compiler SIGSEGV when using SharedTable (#21876)
fix #21251

(cherry picked from commit 76a98fee65)
2023-09-11 12:02:28 +02:00
Jason Beetham
c4380107d6 Fixed generic parameters failing to be used in inheritance (#21866)
(cherry picked from commit 28a116a477)
2023-09-11 12:02:28 +02:00
narimiran
09fe696fdd disable yaml package testing 2023-09-11 12:02:28 +02:00
metagn
6fbff263e6 just set CallNodes = nnkCallKinds, follows up #21829 (#21833)
These sets are now equal

(cherry picked from commit 9810b8cf7f)
2023-09-11 10:54:35 +02:00
ringabout
fcaacbf374 cursor fields cannot form reference cycles (#21832)
* cursor fields cannot form a reference cycle

* fixes typo

* fixes position

(cherry picked from commit ebbad9e960)
2023-09-11 10:54:35 +02:00
Matt Wilson
2d19520b5c Add nnkHiddenCallConv to nnkCallKinds (#21781) (#21829)
(cherry picked from commit 802d57c237)
2023-09-11 10:54:35 +02:00
Jordan Gillard
1cca8ccca0 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.

(cherry picked from commit b169dad1e5)
2023-09-11 10:54:35 +02:00
Jordan Gillard
a9f1e2dfcd 🚀 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

(cherry picked from commit 71f2e1a502)
2023-09-11 10:54:35 +02:00
ringabout
7a747fe320 fixes #21792; enable checks for sum, prod, cumsummed and cumsum (#21793)
* enable checks for sum, prod, cumsummed  and cumsum

* fixes #21792

* add test cases

(cherry picked from commit 07233ceca0)
2023-09-11 10:54:34 +02:00
metagn
547f205794 error on user pragma args (#21776)
closes #20978

(cherry picked from commit 44736d26cd)
2023-09-11 10:54:34 +02:00
metagn
fa3639ba33 line info for strformat + fix issue with typed templates (#21761)
* line info in strformat

* also fix #20381

(cherry picked from commit e5d0907a42)
2023-09-11 10:54:34 +02:00
metagn
cd0f805832 cheap fix for #10853 + better tuple subscript error message (#21767)
* cheap fix for #10853

* also better tuple subscript error message

* weird

(cherry picked from commit c2bcfd8cd9)
2023-09-11 10:54:34 +02:00
ringabout
579efdabb0 fixes #21703; moveOrCopy should consider when vm (#21721)
(cherry picked from commit 0f226c0e48)
2023-09-11 10:54:34 +02:00
metagn
7b99712bcf 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>
(cherry picked from commit 380dafcc32)
2023-09-11 10:54:34 +02:00
ringabout
58c7474838 static link pthread correctly (#21693)
(cherry picked from commit f9477396a6)
2023-09-11 10:36:10 +02:00
ringabout
a2521b1dc7 Delete parse directory, which was pushed wrongly before [backport] (#22401)
Delete parse directory

(cherry picked from commit 614a18cd05)
2023-08-11 12:46:13 +02:00
ringabout
5d39a8283c fixes #20516; system.create doesn't work with bitfield objects (#20518)
* Revert "fixes #19000 (#19032)"

This reverts commit 2bda4a30a6.

* fixes #20516; add testcase

(cherry picked from commit 5e4dd571d4)
2023-08-11 12:42:20 +02:00
ringabout
01ef1e1500 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

(cherry picked from commit d9a24b9b81)
2023-08-11 12:41:50 +02:00
narimiran
80ece5921f use unsafeAddr 2023-08-11 12:35:56 +02:00
ringabout
bd4609f20e 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:53:36 +02:00
ringabout
b901e94936 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:53:24 +02:00
norrath-hero-cn
0cb84726d0 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:53:01 +02:00
metagn
1cd48e4b2a fix new type inference for noreturn [backport] (#22182)
fixes #22180

Backported since apparently the new type inference was backported

(cherry picked from commit b35942ef83)
2023-07-03 11:58:59 +02:00
Jacek Sieka
bb56a37732 fix controlflow test (#22194)
the function actually returns

(cherry picked from commit 4d2ebbb877)
2023-07-03 11:58:23 +02:00
narimiran
d1b5df06b0 bump NimVersion to 1.6.15 2023-07-03 11:57:42 +02:00
narimiran
71ba2e7f3c bump NimVersion to 1.6.14 2023-06-26 15:17:14 +02:00
Etan Kissling
49271783a3 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.

(cherry picked from commit c6c85f84db)
2023-06-25 18:25:18 +02:00
ringabout
04d0716f37 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>
(cherry picked from commit deaf684375)
2023-06-19 13:12:01 +02:00
Etan Kissling
55776451b4 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`.

(cherry picked from commit 8bba04078c)
2023-06-15 14:45:58 +02:00
heterodoxic
476031f0ed fix #10964 by honoring pointer deref syntax if a reified openarray is used to get an array's length (#21925)
* fix #10964

* add test

(cherry picked from commit 6128ef53c5)
2023-06-15 14:45:58 +02:00
ringabout
c377a5b8a1 fixes #21863; Incorrect enum field access can cause internal error (#21886)
fixes 21863; Incorrect enum field access can cause internal error

(cherry picked from commit 761b927e47)
2023-06-15 14:45:57 +02:00
ringabout
2410580d59 fixes #21847; let parseFloat behave like strtod (#21854)
(cherry picked from commit f22e5067c5)
2023-06-15 13:40:44 +02:00
ringabout
1355083708 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>
(cherry picked from commit 8cf5643621)
2023-06-15 12:43:59 +02:00
quantimnot
6c5d4946e4 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>
(cherry picked from commit 365a753eed)
2023-06-15 12:43:59 +02:00
ringabout
77da35db17 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

(cherry picked from commit 53c15f24e9)
2023-06-15 12:43:59 +02:00
Andreas Rumpf
4fc22cdd4d fixes #21245; warn about destructors that can raise (#21726)
* fixes #21245; warn about destructors that can raise

* doc update

* progress

* typo

(cherry picked from commit 220b450489)
2023-06-15 12:43:59 +02:00
Juan M Gómez
ae83058be2 implements #21620: allowing to import multiple modules with shared names (#21628)
(cherry picked from commit c136ebf1ed)
2023-06-15 10:49:15 +02:00
metagn
0e4758ac30 actually fix #19015 (#21680)
* actually fix #19015

* more tests

* round out

(cherry picked from commit 9dc1f2dd0f)
2023-06-15 10:45:00 +02:00
ringabout
a058dcaf5f 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

(cherry picked from commit 65223e6f59)
2023-06-15 10:44:50 +02:00
Jaremy Creechley
29f44c090e change compile pragma to use mangled compile objects (#21678)
change compile pragma to use mangle

(cherry picked from commit 1af21c2668)
2023-06-15 10:44:44 +02:00
Mamy Ratsimbazafy
147214e18f LTO improvements - fix #15578 (#21679)
(cherry picked from commit 938f5c5e99)
2023-06-15 10:44:39 +02:00
narimiran
503e7b708b Revert "fixes #22058; invalid free with {.noSideEffect.} in template (#22088)"
This reverts commit 7b9b173476.
2023-06-14 21:49:02 +02:00
ringabout
7b9b173476 fixes #22058; invalid free with {.noSideEffect.} in template (#22088)
(cherry picked from commit 2e12d3e26b)
2023-06-14 11:07:27 +02:00
metagn
b686912622 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

(cherry picked from commit 71801c2b8f)
2023-06-13 08:21:51 +02:00
Tanguy
c50adf10d9 Fix: don't track Defect in proc effect compatibility (#22037)
(cherry picked from commit a4f9413a65)
2023-06-12 18:18:36 +02:00
litlighilit
2b6797dc42 Update browsers.nim, fix openDefaultBrowser()'s bug for v1 (#22067)
For details see [the PR for v2](https://github.com/nim-lang/Nim/pull/22052), but this one is specific to v1
2023-06-11 06:56:12 +02:00
narimiran
eaf8977723 disable 'manu' package 2023-06-06 10:10:10 +02:00
ringabout
3601bb81c9 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

(cherry picked from commit 16f42084d3)
2023-06-06 09:32:11 +02:00
ringabout
7142078707 fixes #3770; templates with untyped parameters resolve private fields… (#22014)
fixes #3770; templates with untyped parameters resolve private fields wrongly in generics (#21554)

* fixes #3770; templates with untyped parameters resolve private fields wrongly

* add a test case for #3770

* rename to `nfSkipFieldChecking`
2023-06-06 15:26:17 +08:00
narimiran
b855404c71 Revert "fixes #3748 (#20563)"
This reverts commit 42ff3aa75a.
2023-05-31 07:16:59 +02:00
Andreas Rumpf
653865559a fixes #21734; backport (#21957)
(cherry picked from commit 244565397d)
2023-05-30 09:38:13 +02:00
metagn
ad0e4974c8 support generic void return type for templates (#21934)
fixes #21920

(cherry picked from commit 2dcc7195da)
2023-05-29 08:56:48 +02:00
Andrey Makarov
23d4108773 Allow {.doctype.} in Nim 1.6 w/o implementation (#21909) 2023-05-26 18:56:47 +02:00
ringabout
249551dbfa 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

(cherry picked from commit 71dc929ad7)
2023-05-24 11:23:40 +02:00
Andreas Rumpf
285a18d683 make ORC threadlocal, take two (#21818)
* ORC: make rootsThreshold thread local [backport]

* fixes the regression

(cherry picked from commit f3a4cc584e)
2023-05-24 11:20:00 +02:00
metagn
91fc5cb6c1 ignore inline hint for dynlib procs in codegen [backport] (#21817)
(cherry picked from commit 4b76037e5f)
2023-05-24 11:19:06 +02:00
Andreas Rumpf
1d7ccc0ca6 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

(cherry picked from commit ec3bca8fab)
2023-05-24 11:18:58 +02:00
ringabout
db88ef35dd fixes #14444; add genLineDir before assignment (#21201)
* fixes #14444; add `genLineDir` before raises

* add a test case

* fixes differently

(cherry picked from commit 705da9d452)
2023-05-24 09:06:23 +02:00
Bung
f222625b17 fix #20248;fix #6215;turns into simple CT error (#21141)
(cherry picked from commit 40b5c4c4c3)
2023-05-16 11:19:13 +02:00
Aditya Siram
86a9f2b32f Fix #20416. Enable the recursion limit for ref/ptr types. (#21092)
(cherry picked from commit 2564b5c938)
2023-05-15 15:10:36 +02:00
Aditya Siram
e3275b2040 Fixes #20348; only respect the recursion limit if the symbol's generic type has been generated by the compiler (#20377)
Fixes #20348

(cherry picked from commit be4bd8a0ed)
2023-05-15 15:10:36 +02:00
ringabout
1e72e25410 fixes #9839; fixes noReturn pragma doesn't work for non-simple templates (#21048)
(cherry picked from commit c5eb3fd4f0)
2023-05-15 15:10:35 +02:00
metagn
bc3e964e9d fix #16639 (#21017)
(cherry picked from commit e98efdcc5e)
2023-05-15 15:10:30 +02:00
ringabout
c641273606 fixes isLocalVarSym; an implicit global is a global nonetheless (#21025)
fixes isLocalVarSym; an implicit global is a global nonetheless

(cherry picked from commit a8090f7d65)
2023-05-12 17:33:00 +02:00
Bung
98756bb26b fix semcase on tySequence and tyObject #20283 #19682 (#20339)
* fix semcase on tySequence and tyObject #20283 #19682

* use better arg name

* avoiding returns nil use errorNode instead, clean code

* use efNoDiagnostics flag

* remove tests/errmsgs/t19682.nim

* combine 2 test cases to one file

(cherry picked from commit eec1543baf)
2023-05-12 13:22:08 +02:00
Andreas Rumpf
42ff3aa75a fixes #3748 (#20563)
* fixes #3748

* fix the regression

* don't use the new allocator for the SSL wrapper

* fixes regression

(cherry picked from commit 07b645342a)
2023-05-12 13:22:08 +02:00
Tanguy
5392dbc10e Bootstrap: Allow to override number of CPUs (#21823)
* Allow to override number of cpu

* NCPU -> NIMCORES

(cherry picked from commit c004483581)
2023-05-11 19:00:46 +02:00
ringabout
770a3889fd fixes #21377; fixes @[] and {} type inference as returns in generics (#21475)
* fixes `@[]` type inference in generics

* add issue links

* fixes macros and iterators

* refactor

* add one more test

(cherry picked from commit 64a0355f3f)
2023-05-11 15:13:11 +02:00
metagn
c5d1dc5f69 fixes #20807, refs #20450, regression with seq inference (#20818)
(cherry picked from commit 77e58bf573)
2023-05-11 15:13:04 +02:00
ringabout
553e51ccba closes #6213 #11777; add testcase (#20656)
(cherry picked from commit 2d3e3ab527)
2023-05-11 15:12:58 +02:00
ringabout
751d584b80 closes #11267; closes #11259; closes #11085; add testcases (#20505)
* closes #11267; add testcase

* closes #11259

* closes #11085

(cherry picked from commit a600dfa5b7)
2023-05-11 15:12:53 +02:00
metagn
037f87d904 top-down type inference, implements rfc 149 (#20091)
* micro implementation of rfc 149

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

* number/array/seq literals, more statements

* try fix number literal alias issue

* renew expectedType with if/case/try branch types

* fix (nerf) index type handling and float typed int

* use typeAllowed

* tweaks + const test (tested locally) [skip ci]

* fill out more of the checklist

* more literals, change @ order, type conversions

Not copying the full call tree before the typedesc call check
in `semIndirectOp` is also a small performance improvement.

* disable self-conversion warning

* revert type conversions (maybe separate op later)

* deal with CI for now (seems unrelated), try enums

* workaround CI different way

* proper fix

* again

* see sizes

* lol

* overload selection, simplify int literal -> float

* range, new @ solution, try use fitNode for nil

* use new magic

* try fix ranges, new magic, deal with #20193

* add documentation, support templates

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 0014b9c48e)
2023-05-11 15:12:38 +02:00
ringabout
01ce56ab9e adds koch --skipIntegrityCheck boot support (#21795)
add `koch --skipIntegrityCheck boot` support

(cherry picked from commit 724866b14f)
2023-05-05 15:04:31 +02:00
Andreas Rumpf
c88f58948a fixes #21780 [backport:1.6] (#21785)
* fixes #21780 [backport:1.6]

* complete patch

(cherry picked from commit 79ac242c72)
2023-05-05 14:59:49 +02:00
Jake Leahy
a456c8797f Allow futureLogging in release builds (#21448)
* Add test case

* Fixes 21447: Keeps stackTrace around when using futureLogging

* Remove extra whitespace

(cherry picked from commit d4d28f2ffe)
2023-05-03 18:32:48 +02:00
kraptor
168fcc6965 Add new self-signed 4096 bit certificate to testdata (#19758)
The test tasyncssl may fail on modern linux versions
as they require at least 2048 bit certificates.

A new certificate and private key with default values
has been added to meet this new requirement.

(cherry picked from commit 8c100a37b9)
2023-05-03 18:32:37 +02:00
metagn
c2d098b974 .inheritable fix for 1.6 (#21768) 2023-05-03 18:30:43 +02:00
ringabout
2072eebcea fixes #21731; fixes #21537; disable warnBareExcept by default [backport] (#21728)
* disable warnBareExcept for default

* fixes a typo

(cherry picked from commit 69c193e5e2)
2023-04-27 07:20:35 +02:00
metagn
ae31ed4665 import brackets support as and prefixes [backport] (#21636)
* import brackets support `as` and prefixes

fixes #21635

* copyTree -> copyNode

(cherry picked from commit 2f547afb0f)
2023-04-27 07:18:17 +02:00
metagn
3f85abbd54 fix #15691 (#21623)
`semProcAux` has a check for `checkMinSonsLen(n, bodyPos + 1)`

(cherry picked from commit be06446ffe)
2023-04-26 15:12:32 +02:00
ringabout
6f05abf21c fixes #21638; fromJson should support empty objects (#21641)
* fixes #21638; `fromJson` should supports empty objects

* complete the logic

(cherry picked from commit 5e016e4466)
2023-04-26 15:12:03 +02:00
Jason Beetham
ed21e84f46 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

(cherry picked from commit 686c75cef0)
2023-04-26 15:10:46 +02:00
Jason Beetham
9bc30a1ff8 Fix segfault caused by ensuring valueless statics are not evaluated (#21577)
(cherry picked from commit c06623bf8c)
2023-04-26 15:09:57 +02:00
ringabout
21a26548a4 fixes #14255; Crash in compiler when using system.any by accident. (#21562)
fixes #14255; Crash in compiler when using system.any by accident.

(cherry picked from commit 55636a2913)
2023-04-26 15:09:47 +02:00
Andreas Rumpf
564a88006a mitigates #21272; but it's not the final fix because the first round … (#21462)
mitigates #21272; but it's not the final fix because the first round of overload resolution should already match

(cherry picked from commit f7e3af0c2d)
2023-04-26 15:09:01 +02:00
Jason Beetham
babc9b234d Made generic type classes work with types using static parameters (#21528)
(cherry picked from commit a9d0124b5d)
2023-04-26 15:08:51 +02:00
ringabout
844717f52b fixes explicit globals in macros (#21502)
(cherry picked from commit b2c1dcbbc9)
2023-04-26 15:08:45 +02:00
ringabout
db9442bf84 closes #8295; add a test case (#21486)
(cherry picked from commit 2f89f1eb78)
2023-04-26 15:07:55 +02:00
ringabout
5bddac3e34 closes #6231; add a test case (#21485)
(cherry picked from commit 6ef9430153)
2023-04-26 15:07:47 +02:00
ringabout
87bd753cb3 closes #20704; add a test case (#21480)
(cherry picked from commit 2d9af2bd55)
2023-04-26 15:05:56 +02:00
ringabout
e53e5476a7 closes #16654; add a test case (#21478)
(cherry picked from commit 4d76725299)
2023-04-26 12:48:13 +02:00
ringabout
7ceb4e4c87 fixes #10938; fixes #13312; fixes #13918; fixes #20985; always initializes global variables with null values in VM (#21351)
* fixes #10938; always initialize global variable in VM

* fixes importc vars

* there is a pre-existing issue regarding closure types in the VM

* add tests

(cherry picked from commit 1b1412f3d1)
2023-04-26 12:48:13 +02:00
ringabout
ca620d6089 closes #17864; add a test case (#21434)
(cherry picked from commit d4782c9e42)
2023-04-26 12:48:12 +02:00
ringabout
025ada1809 fixes #21360; discarding empty seqs/arrays now raises errors (#21374)
* discarding empty seqs now raises errors

* the same goes for sets

(cherry picked from commit fc7385bfda)
2023-04-26 12:48:12 +02:00
ringabout
7ad8c44e28 fixes #16790; fixes #19075; put big arrays on the constant seqs; don't inline them in the VM; big performance boost (#21318)
* don't inline arrays in VM

* add a test for #19075

(cherry picked from commit b5f64f55d0)
2023-04-26 12:48:12 +02:00
ringabout
0fc1b79b75 enforce void for nkWhileStmt [backport: 2.0] (#21170)
enforce void for nkWhileStmt

(cherry picked from commit 9323cb7b2a)
2023-04-26 12:48:12 +02:00
Bung
8155b8d3ce fix #11634 (#21146)
(cherry picked from commit ca9c74391a)
2023-04-26 12:48:12 +02:00
Bung
c25621d153 fix #16541 (#21148)
(cherry picked from commit c5a72ebddd)
2023-04-26 12:48:12 +02:00
Bung
24e4099d36 fix #21109 (#21127)
(cherry picked from commit e278a781fc)
2023-04-26 11:00:48 +02:00
ringabout
eaac22b9aa close #11705; add a testcase (#21128)
(cherry picked from commit 53eed2be45)
2023-04-26 11:00:04 +02:00
Bung
f0324e99da fix #20588 (#21104)
(cherry picked from commit 8054be6e52)
2023-04-26 10:57:45 +02:00
Bung
4ea0ce9149 fix #15836 proc arg return type auto unexpectly match proc with concr… (#21065)
* fix #15836 proc arg return type auto unexpectly match proc with concrete type

* fix #16244

* add test case for #12869

(cherry picked from commit 5917c2d5b7)
2023-04-26 10:53:43 +02:00
Jake Leahy
a676c3aeca multisync now allows tuples in return type (#21074)
* Add test case

* Use .toStrLit() on param node first

This means that more complex types are fully rendered

(cherry picked from commit c7493bbdd0)
2023-04-26 10:53:35 +02:00
Bung
918a7d9f54 fix #16758 Nim crashes in fixAbstractType (#20855)
* fix #16758 Nim crashes in fixAbstractType

* Update compiler/semexprs.nim

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

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 1585bfec3b)
2023-04-26 10:53:28 +02:00
ringabout
aae32f5623 fixes broken CI (#21732)
* fixes broken CI

* Update testament/important_packages.nim

(cherry picked from commit 8f79a124c9)
2023-04-26 10:27:04 +02:00
Vindaar
410254b485 fix issue #20922 by handling missing expr in exprList for tkOf (#20930)
* fix issue #20922 by handling missing expr in `exprList` for `tkOf`

* fix line numbers in test case

* rewrite exprList requiring expr, add optionalExprList for except

As suggested by @metagn.

* update test case to reflect new code

* update grammar.txt

* update line numbers in test case taking into account nimout

Given the number of errors that are produced it seems easier to do it
this way instead of using `tt.Error`.

(cherry picked from commit 0a1d4ba842)
2023-04-26 09:31:33 +02:00
Emery Hemingway
4234bbe7bd macros.customPragmaNode: walk brackets on brackets (#21040)
(cherry picked from commit 696def2bf7)
2023-04-26 09:31:33 +02:00
ringabout
71c5bdf6b3 fixes #21027; cast expressions need a type (#21029)
* fixes #21027; cast expressions need a type

* Apply suggestions from code review

Thanks to @beef331

(cherry picked from commit 1564ae650f)
2023-04-26 09:31:33 +02:00
Yuriy Glukhov
149c0ad46f Dont produce initing moves for sfNoInit variables in closure env (#21026)
(cherry picked from commit c47d5196be)
2023-04-26 09:31:33 +02:00
ringabout
57e307f3a8 fixes #20958; fixes the return type of slice function [backport] (#20959)
* fixes #20958; fixes the return type of slice function

* add a testcase

(cherry picked from commit 3d5edb41be)
2023-04-26 09:31:33 +02:00
ringabout
a0eec605ba fixes #13583; enforce void for nkWhileStmt (#20947)
* fixes #13583; enfore void for nkWhileStmt

* one more case

(cherry picked from commit d4afa53fd5)
2023-04-26 09:31:33 +02:00
Ico Doornekamp
7e7b35b5c0 channel send() condition variable lock ordering (#20879)
(cherry picked from commit 79b25a911b)
2023-04-26 09:31:32 +02:00
Bung
7e80df2267 fix #3505 wrong var {.global.} initialization, asign variable to it (#20812)
* fix #3505 wrong var {.global.} initialization, asign variable to it

* fix #5132 as well

* follow suggestions

* handle all call kinds

* Update tests/global/t3505.nim

* Update compiler/semstmts.nim

* Update compiler/semstmts.nim

* Update compiler/semstmts.nim

* follow suggestion

* Update compiler/semstmts.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 1410243d3b)
2023-04-26 09:31:32 +02:00
ringabout
e70379811b fixes regression #17121; adding doc comment in importc proc makes it silently noop at CT (#20766)
* fixes regression #17121; adding doc comment in importc proc makes it silently noop at CT

* Update compiler/vmgen.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit a228e331f3)
2023-04-26 09:31:32 +02:00
Bung
0c9c6d2a68 fix #19149 Invalid codegen when returning var tuple from a template (#20762)
* fix #19149 Invalid codegen when returning var tuple from a template

* fix type

(cherry picked from commit bae0fb720a)
2023-04-26 09:31:32 +02:00
ringabout
4e56bcfc0e closes #14216; add testcase (#20733)
(cherry picked from commit 87f7f50553)
2023-04-25 19:34:04 +02:00
Jacek Sieka
10ca10eb83 fix sighashes for generic ref (#20723)
the `hashType` issue in #12229 was never really fixed - it just stopped
being called in that context

(cherry picked from commit 58f79e7c3e)
2023-04-25 18:31:15 +02:00
Bung
d5be917994 fix #20272 range of uint64 shows signed upper bound (#20702)
(cherry picked from commit 49e793e8c4)
2023-04-25 18:27:54 +02:00
Bung
fe1e09a881 fix #20148 implicit compile time conversion int to ranged float cause… (#20698)
fix #20148 implicit compile time conversion int to ranged float causes compiler fatal error

(cherry picked from commit a51ed90c5d)
2023-04-25 16:27:31 +02:00
Bung
b2b226bb28 fix #16264 low(Time) OverflowDefect (#20552)
fix #16264 regression(0.18.0 => devel): import times; echo low(Time) gives OverflowDefect

(cherry picked from commit 534c97edc5)
2023-04-25 16:27:31 +02:00
metagn
592321c7f5 alternate fix + test for #12094, refs #13804 (#20686)
(cherry picked from commit cb3af8ad39)
2023-04-25 16:27:30 +02:00
Bung
cf12d6fcde fix #6637 array index type depends generic (#20673)
(cherry picked from commit aa6f9d490f)
2023-04-25 16:27:30 +02:00
ringabout
26e52d7c5d fixes #19201; fixes sink causes crash in VM (#20658)
(cherry picked from commit 4b377b07fc)
2023-04-25 16:27:30 +02:00
Bung
628c9c3c7f fix #12094 Use of _ (as var placeholder) inside a template causes XDe… (#20635)
fix #12094 Use of _ (as var placeholder) inside a template causes XDeclaredButNotUsed

(cherry picked from commit 4728c52c78)
2023-04-25 16:27:30 +02:00
ringabout
5c4044cd80 closes #4466; add testcase (#20625)
(cherry picked from commit 684a862526)
2023-04-25 16:27:30 +02:00
ringabout
46543d8e9b enable static tests for topenarray (#20620)
(cherry picked from commit fa1606c6d6)
2023-04-25 16:27:30 +02:00
Jason Beetham
32171fc66d Unpack mSlice tupleconstr for static openarrays (#20615)
(cherry picked from commit da0a2fdca2)
2023-04-25 16:27:29 +02:00
Bung
b220294f13 fix #20152 Illegal capture of closure iterator, when should be legal (#20607)
(cherry picked from commit 66cbcaab84)
2023-04-25 16:27:29 +02:00
Bung
6274bc35dd fix #19426 compile error using when/elif/else and typedesc in template (#20550)
(cherry picked from commit 04c48e3c5b)
2023-04-25 16:27:29 +02:00
Can Lehmann
a76f36b4e5 Fix #12517 Allow single branch when nimvm statements (#20577)
Allow single branch when statements

(cherry picked from commit 2102e3b02f)
2023-04-25 16:27:29 +02:00
Antonis Geralis
b47d12fe0a atomicInc global alloc counters (#20571)
(cherry picked from commit ed26156c99)
2023-04-25 15:34:47 +02:00
Bung
425f828178 fix #19700 Crash when passing a template to a generic functio… (#20567)
fix nim-lang#19700 Crash when passing a template to a generic function expecting a procedure

(cherry picked from commit 0510a2be0d)
2023-04-25 15:34:47 +02:00
Bung
f2b52ec432 fix #7446 Generics: type mismatch 'SomeunsignedInt or Natural' (#20522)
* fix #7446 Generics: type mismatch 'SomeunsignedInt or Natural'

* try fix

(cherry picked from commit 083ea8f10c)
2023-04-25 15:34:47 +02:00
Bung
01d27ef1db fix #18886 crash on ambiguous proc cast (#20472)
* fix #18886 crash on ambiguous proc cast

* follow suggestion

(cherry picked from commit db3d2971cf)
2023-04-25 15:34:47 +02:00
ringabout
6df5fa424a closes #12994; add testcase (#20511)
(cherry picked from commit a132f5502a)
2023-04-25 15:34:47 +02:00
ringabout
ebd6619aaa close #11415; add testcase (#20486)
(cherry picked from commit 852a7c4919)
2023-04-25 15:34:46 +02:00
Bung
0cf39669df Fix #19224 For loops over a hardcoded empty array crash the compiler (#20476)
* Fix #11684 For loops over a hardcoded empty array crash the compiler

* Update t19224.nim

(cherry picked from commit 567c3f055d)
2023-04-25 15:34:46 +02:00
Tomohiro
512aef60ae Use vccexe when generating static lib with vcc (#19843)
(cherry picked from commit 92a0f191bf)
2023-04-25 15:34:46 +02:00
Peter Munch-Ellingsen
2dff0c1a61 Fix issue with fields trying to use wrong name (#12655)
* Fix issue with fields trying to use wrong name

* Fix similar issue in winlean

* Revert accidental csize change

Co-authored-by: Clyybber <darkmine956@gmail.com>
Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
(cherry picked from commit 805186809c)
2023-04-25 15:34:46 +02:00
metagn
5def1fc8f6 temporarily disable badssl tests (#21710)
* temporarily disable badssl tests

refs #21709

* fix

(cherry picked from commit 6ad246b215)
2023-04-25 08:45:43 +02:00
ringabout
07824b3053 close #15955; add a test case (#20414)
(cherry picked from commit 37ca97dd76)
2023-04-24 22:09:42 +02:00
Bung
0dc51dfe47 Improve error message when instantiating generics with object constructor (#20358)
* Improve error message when instantiating generics with object constructor

* follow suggestion

* Update compiler/semobjconstr.nim

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>

* Update tests/errmsgs/t19882_2.nim

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
(cherry picked from commit 2afce84616)
2023-04-24 22:09:34 +02:00
Bung
09be80c857 report expression has no type other than has to be used (or discarded… (#20392)
report expression has no type other than has to be used (or discarded) when typ is tyNone in discardCheck

(cherry picked from commit 08c02f0236)
2023-04-24 22:09:22 +02:00
Bung
82af5c7f6d fix #19882 Improve error message when instantiating generics that lac… (#20356)
* fix #19882 Improve error message when instantiating generics that lack a type

* Update tests/errmsgs/t19882.nim

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
(cherry picked from commit a302b26e0e)
2023-04-24 22:09:13 +02:00
Tomohiro
892b1f7583 Fix #16937; --clib option pass library name to backend C compiler correctly (#19754)
* Fix 16937: Make --clib option works

* Make tests/compiler/tcmdlineclib.nim works from any current dir

* Try to fix link error on macosx

* Add a comment to tests/compiler/tcmdlineclib.nims

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
(cherry picked from commit 2a34d143ac)
2023-04-24 22:09:07 +02:00
ringabout
3e93e00391 remove var for ref parameters in std/tables (#20175)
remove `var` from ref parameters; make it consistent

(cherry picked from commit ea44c5cfed)
2023-04-24 22:08:59 +02:00
ringabout
7acdacb253 fixes #18983 #5282 #13008; recursive types casue infinite type (#20172)
* fixes #18983 #5282 #13008; recursive types casue infinite type

* re

* add testcases

(cherry picked from commit a895bbf714)
2023-04-24 22:08:53 +02:00
ringabout
b92336ab33 fixes #20149; fixes #16762; hintAsError and warningAsError now ignore foreign packages (#20151)
* fixes #20149;  hintAsError/warningAsError ignores foreign packages

* add changelog

* fixes the test

* remove

* fixes tests again

* fix

* I'm careless

Co-authored-by: xflywind <43030857+xflywind@users.noreply.github.com>
(cherry picked from commit 641381e3d4)
2023-04-24 22:08:02 +02:00
ringabout
6f347a82aa closes #6559; add testcase (#20200)
(cherry picked from commit 1a7b33942b)
2023-04-24 22:06:43 +02:00
konsumlamm
f3300c1a9c Warn when casting to a larger type (#20103)
* Warn when casting to a larger type

* Revert change to error message to fix CI

(cherry picked from commit 528b6d1c3f)
2023-04-24 22:06:16 +02:00
Yuriy Glukhov
42020a2331 Fixed noinit pragma for closure variables (#20101)
(cherry picked from commit 424e87fd09)
2023-04-24 22:05:07 +02:00
metagn
e494f1b21e fix #20002 (#20004)
While this fix seems innocent,
this unlocks the hidden behavior of
method calls not being able to call
gensym'ed routines inside templates.

(cherry picked from commit f35c9cf73d)
2023-04-24 22:02:43 +02:00
Juan M Gómez
22d043997c Fixes Compilation error with --app:lib (#19965)
Fixes Compilation error with --app:lib  when a module tries to pull os.paramStr on posix by throwing a runtime exception instead.
More details here: #19964

(cherry picked from commit a90763ebd7)
2023-04-24 22:02:32 +02:00
flywind
81a52fae78 closes #15897; add testcase (#19961)
(cherry picked from commit 4897c47c80)
2023-04-24 22:02:19 +02:00
Tanguy
ab1717984d Allow recursive closure iterators (#19939)
(cherry picked from commit ce4078acd4)
2023-04-24 22:01:28 +02:00
flywind
d6ea7cc49a closes #11042; add testcase (#19935)
close #11042; add testcase

(cherry picked from commit 8a344cb25b)
2023-04-24 21:58:57 +02:00
flywind
fbaeea8adf ref #19830; multiple definition of in Nim generated static libraries (#19934)
* ref #19830; multiple definition of in Nim generated static libraries

* fix compile errors

(cherry picked from commit 0189122d4f)
2023-04-24 21:58:49 +02:00
Khaled Hammouda
85e943db50 Fix distinct requiresInit test and manual (#19901)
fix distinct test and manual

(cherry picked from commit caf6aff06b)
2023-04-24 21:58:34 +02:00
Tanguy
67b94a96f7 Better range error messages (#19867)
* Better range error messages

* Revert to old behavior for arrays

* Small corrections

(cherry picked from commit d33e112766)
2023-04-24 21:58:22 +02:00
Bung
75bc4a9b78 test for #19046 (#19839)
* test for #19046

* add threads flag

(cherry picked from commit ac89eead8a)
2023-04-24 21:58:15 +02:00
Andreas Rumpf
9622c56f37 give a better error message for some template expansions (#19871)
(cherry picked from commit 25d89269eb)
2023-04-24 21:57:47 +02:00
narimiran
9a83cae9dc CI upgrade to Ubuntu 20.04, see #20182 2023-04-24 17:59:38 +02:00
quantimnot
1af76bc5a2 Stop type aliases from inheriting sfUsed (#19861)
Fixes #18201

Co-authored-by: quantimnot <quantimnot@users.noreply.github.com>
(cherry picked from commit f7a13f62d6)
2023-04-24 17:35:02 +02:00
ehmry
840b34684d macros: make hasCustomPragma more permissive (#19747)
Make hasCustomPragma return false rather than fail for invalid
parameters.

(cherry picked from commit 82680a12a7)
2023-04-24 17:34:48 +02:00
Nan Xiao
6602961637 No need to export pos from OptParser (#19688)
Co-authored-by: flywind <xzsflywind@gmail.com>
(cherry picked from commit 065f568470)
2023-04-24 17:34:37 +02:00
Andreas Rumpf
3a685e863e fixes #14318 (#14335)
(cherry picked from commit 7d32425a57)
2023-04-24 17:34:28 +02:00
flywind
2dbceb319c remove tmpFramePtr when optStackTrace is absent (#19649)
(cherry picked from commit 84ac003519)
2023-04-24 17:34:18 +02:00
Andreas Rumpf
b13dba2c19 fixes #19603; some pragmas were really only supported as top level statements. Now this is enforced properly. (#19646)
(cherry picked from commit 51df9ff1c7)
2023-04-24 17:34:11 +02:00
flywind
31f7b17dd0 remove unnecessary framePtr code (#19645)
(cherry picked from commit afbcba909b)
2023-04-24 17:33:59 +02:00
Clyybber
ea69f04cc7 compiler: Handle nkCheckedFieldExpr better in dfa (#19616)
Simply recurse into their first child, which is always
a nkDotExpr instead of treating them seperately.
This fixes the rhs sym of a nkCheckedFieldExpr being
checked twice in aliases. This double checking didn't
cause any issues, but was unintentional and redundant.

(cherry picked from commit 3e83d73f27)
2023-04-24 17:33:53 +02:00
flywind
1779f6aa9a [testcase] genSym fails to make unique identifier for ref object types (#19506)
close #15118

(cherry picked from commit 2ef71c0a46)
2023-04-24 17:33:44 +02:00
Regis Caillaud
a33603925d Clonkk fix2 11923 (#19451)
* fix nnkBracketExpr not compiling for getImpl on customPragmaNode

* fix test import

* fix alias not working with hasCustomPragmas

(cherry picked from commit 486cb09ec2)
2023-04-24 17:33:24 +02:00
Jason Beetham
da325b0822 No longer segfault when using a typeclass with a self referencing type (#19467)
(cherry picked from commit 1830a3b505)
2023-04-24 17:33:13 +02:00
flywind
196e93f9e1 [add testcase] NRVO does not occur with init procedures (#19462)
* [add testcase] NRVO does not occur with init procedures

close #19094

* Update tests/ccgbugs2/tcodegen.nim

(cherry picked from commit 33cd883e27)
2023-04-24 17:33:04 +02:00
Regis Caillaud
70478d34e3 Fix #11923 (#19427)
* Apply commit 5da931fe81 that was never merged (was part of a bigger PR). Should fix issue #11932

* add a generic object for custom pragma

(cherry picked from commit 1563cb2f6e)
2023-04-24 17:31:56 +02:00
metagn
fe5edb7ab0 Don't reject types directly on AST (#19407)
Instead of rejecting type expressions based on node kind,
evaluate the expression as a type.
This is already the behavior for call results, and it has its own error
for non-types, which is the same error you would normally get
with 2 words swapped.

(cherry picked from commit 08261cb9e3)
2023-04-24 17:31:41 +02:00
Jason Beetham
de6d7dcca9 Fixed concept constraints for static types (#19391)
(cherry picked from commit 7bdfeb7819)
2023-04-24 17:31:34 +02:00
Jason Beetham
9e3762b6da Generic parameters now can constrain statics in type definitions (#19362)
* Parameters now can constrain static in type definitions

resolved regression with generic procedures

* Update compiler/sigmatch.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit a93f6e7acc)
2023-04-24 17:31:27 +02:00
flywind
5cd2665c29 Atomic inc/dec should use ATOMIC_SEQ_CST (#19212)
(cherry picked from commit 0992854941)
2023-04-24 17:28:53 +02:00
hlaaftana
4857d9204e treat do with pragmas but no parens as proc (#19191)
fixes #19188

(cherry picked from commit 1ef945668d)
2023-04-24 17:28:15 +02:00
hlaaftana
c5df4ed62a fix #12274 (#19180)
(cherry picked from commit 2859069dbe)
2023-04-24 17:26:18 +02:00
Don-Duong Quach
4728e9d433 fix for #19020, credit to @ElegantBeef (#19021)
(cherry picked from commit f2f15e9726)
2023-04-24 17:26:09 +02:00
Kaushal Modi
2f6dc73342 Add test for issue 15435 (#19079)
* Add test for issue 15435

Closes https://github.com/nim-lang/Nim/issues/15435.

* Specify bug # in comment

Addresses https://github.com/nim-lang/Nim/pull/19079#discussion_r740279547

(cherry picked from commit 539bced70d)
2023-04-24 17:25:59 +02:00
Jason Beetham
48936ab1c0 Fix VM's sametype impl to work for generics/typedescs (#19073)
* Fix vm's sametype implementation to properly handle generics and typedescs

* actually fixed sametype + have test

* added comments and removed unsafe code

(cherry picked from commit cc984217a9)
2023-04-24 17:25:37 +02:00
Andreas Rumpf
26ed32e67e fixes #19000 (#19032)
* fixes #19000

* progress

(cherry picked from commit 2bda4a30a6)
2023-04-24 17:22:44 +02:00
Tomasz Kramkowski
01dc38a05c Fix nimIdentNormalize, fixes #19067 (#19068)
* Make nimIdentNormalize return "" when passed ""; fixes #19067

Fixes #19067

* Add tests for nimIdentNormalize

(cherry picked from commit ee703c5db4)
2023-04-24 17:22:22 +02:00
Jason Beetham
b21f81dade Fixed distinct composite type class proc borrowing (#18904)
* Fixed composite type class proc borrowing

* Moved borrow search into transf

* added borrow check to symbol flag

(cherry picked from commit 8d5a275189)
2023-04-24 17:22:12 +02:00
Jason Beetham
5bb626d4b1 Fixed generic distinct conversions for 'var' (#18837)
* SameTypeAux now properly traverses generic distincts

* Smarter traversal of distincts

* Removed redundant check

* Fixed nkConv for jsgen

* Added test for non distinct nkConv

* using skiptypes for distinct now

* Fixed genaddr for nkconv

(cherry picked from commit 83a2515af7)
2023-04-24 17:22:05 +02:00
flywind
2f247ed1a7 remove exception (#18906)
(cherry picked from commit 4d8108046b)
2023-04-24 17:21:46 +02:00
narimiran
a5a2c57e88 correctly do the JSON backport 2023-04-24 09:43:55 +02:00
Matt Haggard
bce9a9daed Fix long link commands on macOS (v1.6) (#21381)
Handle long link commands on macOS with a script, since ar does not support response files

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-04-23 19:28:54 +08:00
Yardanico
4071b3fad8 Fix json.to for float fields that are not present (#21695)
(cherry picked from commit 418e54452b)
2023-04-21 13:10:49 +02:00
Bung
064ed4846d fix #20997 (#21165)
* fix #20997

* use ptr UncheckedArray[uint8] instead

(cherry picked from commit 0d6b994bee)
2023-04-19 12:18:41 +02:00
Bung
6007b12b30 fix #20997 calling system.card[T](x: set[T]) with T of int8 or uint8 … (#21010)
* fix #20997 calling system.card[T](x: set[T]) with T of int8 or uint8 uses mismatched C array sizes
* fullfil set variant

(cherry picked from commit 0b319fee3d)
2023-04-19 12:18:29 +02:00
Etan Kissling
eecd8373ed 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.

(cherry picked from commit 75205fee93)
2023-04-11 10:05:04 +02:00
tersec
30737676de remove seq[T] setLen undefined behavior (#21582)
remove seq[T] setLen UB

(cherry picked from commit 51ced0d684)
2023-04-05 13:28:47 +02:00
ringabout
65a7496e51 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

(cherry picked from commit 3575f2bf9c)
2023-04-05 08:09:27 +02:00
ringabout
48d18df69c fixes #21496; Ambiguous calls compiles when module name are equal (#21500)
* fixes #21496; Ambiguous calls compiles when module name are equal

* add a test case

(cherry picked from commit ffadc75afe)
2023-04-05 08:08:24 +02:00
tersec
a8c6e36323 don't access void* out of alignment in refc GC to avoid UB (#21560)
(cherry picked from commit e8a70ff179)
2023-03-27 14:50:49 +02:00
Peter Munch-Ellingsen
38dbdc270e Fix infinite recursion introduced in 7031ea6 [backport 1.6] (#21555)
Fix infinite recursion introduced in 7031ea6

(cherry picked from commit c155e20796)
2023-03-23 16:33:43 +01:00
ringabout
79b5f8c4e2 fixes #21306; fixes #20485; don't transform yields in the var section when introducing new local vars [backport: 1.6] (#21489)
* fixes #21306;  don't transform yields in the var section when introducing new local vars

* adds `inVarSection` so the var section in the var section is freshed

* use `isIntroducingNewLocalVars` to avoid yield transformations in var sections

* fixes comments

(cherry picked from commit f2dad94902)
2023-03-23 16:33:30 +01:00
Ivan Yonchovski
f111afc319 Avoid calling build_all* when nim binary is present (#21522)
- `nimble` will build `nim` using `bin/nim` and if it is already present we can
reuse it.

(cherry picked from commit fb00b482eb)
2023-03-21 14:35:53 +01:00
narimiran
b6ed118f0c bump NimVersion to 1.6.13 2023-03-21 14:35:18 +01:00
Joey
43fa8663f7 Add line directives for C code variables (#21466) [backport:1.6] (#21518)
* Add line directives for C code variables

* Refactor genCLineDir to only use toFullPath if necessary

Signed-off-by: Joey Yakimowich-Payne <jyapayne@pm.me>
2023-03-17 17:04:11 +01:00
narimiran
1aa9273640 bump NimVersion to 1.6.12 2023-03-09 20:19:29 +01:00
ringabout
19dd56f018 fixes #20139; hash types based on its path relative to its package path (#21274) [backport:1.6]
* fixes #20139; hash types based on its path relative its project

* add a test case

* fixes procs

* better implementation and test case

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 38d299dfc0)
2023-03-09 18:32:51 +01:00
narimiran
b6333c4a20 disable 'norm' package 2023-03-09 17:57:57 +01:00
Ivan Yonchovski
d723d5ff72 Fix nimble build for 1.6 (#21490) 2023-03-08 14:01:08 +01:00
Ivan Yonchovski
cdbcada3d7 Define the version of nim package without using system module (#21415)
This is follow up from https://github.com/nim-lang/Nim/pull/21313

(cherry picked from commit 9b5ae2b2eb)
2023-03-07 15:39:08 +01:00
Matt Haggard
5c36f24da2 Backport #20466 - macOS use SecRandomCopyBytes instead of getentropy (#21389)
* On macOS use SecRandomCopyBytes instead of getentropy (which is only available on macOS 10.12+)

* Change passL to passl

---------

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-03-02 14:26:04 -05:00
Andreas Rumpf
1cdce314a7 fixes #20422; emit nimPrepareStrMutationV2 for toOpenArray to keep th… (#21459)
fixes #20422; emit nimPrepareStrMutationV2 for toOpenArray to keep the abstraction of mutable strings which have immutable string literals

(cherry picked from commit 50baf21eac)
2023-03-02 10:29:24 +01:00
ringabout
a67f89e643 fixes version-1-6 branch; add nimsuggest.nimble back (#21460) 2023-03-02 12:03:57 +08:00
ringabout
4fbd28a1a4 fixes version-1-6 branch (#21458) 2023-03-02 00:03:03 +08:00
c-blake
69d4e49630 Fix the TODO portion of recently added posix_fallocate on OS X. (#21387)
(cherry picked from commit fdd7520257)
2023-02-24 07:03:10 +01:00
ringabout
60350eca1a fixes #1027; disallow templates to use ambiguous identifiers (#21405)
* Add `nkFastAsgn` into `semExpr` (#20939)

* Add nkFastAsgn into case statement

* Add test case

* fixes #1027; disallow templates to use ambiguous identifiers (#20631)

* test qualifiedLookUp in templates

* check later

* add testcase

* add 4errormsg

* Update tests/template/m1027a.nim

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>

* Update tests/template/m1027b.nim

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>

---------

Co-authored-by: Jake Leahy <jake@leahy.dev>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
2023-02-20 23:50:53 +08:00
narimiran
6af6818fe9 fix memfiles 2023-02-18 10:50:33 +01:00
c-blake
d070ccbc03 Fix closeHandle bug, add setFileSize, make resize work on Windows (#21375)
* Add general purpose `setFileSize` (unexported for now).  Use to simplify
`memfiles.open` as well as make robust (via hard allocation, not merely
`ftruncate` address space allocation) on systems with `posix_fallocate`.

As part of this, fix a bad `closeHandle` return check bug on Windows and
add `MemFile.resize` for Windows now that setFileSize makes that easier.

* Adapt existing test to exercise newly portable `MemFile.resize`.

* Since Apple has never provided `posix_fallocate`, provide a fallback.
This is presently written in terms of `ftruncate`, but it can be
improved to use `F_PREALLOCATE` instead, as mentioned in a comment.

(cherry picked from commit c91ef1a09f)
2023-02-16 16:37:44 +01:00
narimiran
fca6a0bd6a fix func param 2023-02-16 10:56:56 +01:00
c-blake
c546ba5d23 This adds parseutils.parseSize, an inverse to strutils.formatSize (#21349)
* This adds `parseutils.parseSize`, an inverse to `strutils.formatSize`
which has existed since 2017.

It is useful for parsing the compiler's own output logs (like SuccessX)
or many other scenarios where "human readable" units have been chosen.
The doc comment and tests explain accepted syntax in detail.

Big units lead to small numbers, often with a fractional part, but we
parse into an `int64` since that is what `formatSize` stringifies and
this is an inverse over partial function slots.  Although metric
prefixes z & y for zettabyte & yottabyte are accepted, these will
saturate the result at `int64.high` unless the qualified number is a
small fraction.  This should not be much of a problem until such sizes
are common (at which point another overload with the parse result
either `float64` or `int128` could be added).

Tests avoids `test()` because of a weakly related static: test() failure
as mentioned in https://github.com/nim-lang/Nim/pull/21325. This is a
more elemental VM failure.  As such, it needs its own failure exhibition
issue that is a smaller test case.  (I am working on that, but unless
there is a burning need to `parseSize` at compile-time before run-time
it need not hold up this PR.)

* This worked with `int` but fails with `int64`.  Try for green tests.

* Lift 2-result matching into a `checkParseSize` template and format as a
table of input & 2 expected outputs which seems nicer and to address
https://github.com/nim-lang/Nim/pull/21349#pullrequestreview-1294407679

* Fix (probably) the i386 trouble by using `int64` consistently.

* Improve documentation by mentioning saturation.

* Improve documentation with `runnableExamples` and a little more detail in
the main doc comment based on excellent code review by @juancarlospaco:
https://github.com/nim-lang/Nim/pull/21349#pullrequestreview-1294564155

* Address some more @juancarlospaco code review concerns.

* Remove a stray space.

* Mention milli-bytes in docs to maybe help clarify why wild conventions
are so prone to going case-insensitive-metric.

* Add some parens.

(cherry picked from commit 1d06c2b6cf)
2023-02-16 08:47:00 +01:00
Andreas Rumpf
7fa782e3a0 fixes #21333; bad codegen for the at operator; [backport:1.6] (#21344)
(cherry picked from commit 9fb4c2b3c7)
2023-02-14 17:44:30 +01:00
ringabout
b93edcd059 fixes SSL version check logic [backport] (#21324)
* fixed version check logic [backport]

* add ciphersuites

* debug nimble

* fixes returns omission

* finally

* remove debug message

* add ciphersuites

---------

Co-authored-by: Araq <rumpf_a@web.de>
(cherry picked from commit 17115cbc73)
2023-02-14 17:44:30 +01:00
ringabout
28985686c0 fixes #21317; 1.6.4 regression; etyBaseIndex should return fat pointers [backport 1.6] (#21320)
fixes #21317; regression; etyBaseIndex should return fat pointers

(cherry picked from commit cbf3ed9d92)
2023-02-14 17:44:30 +01:00
Ivan Yonchovski
f9b95d1cb4 Rename the package from compiler -> nim (#21369) 2023-02-14 20:18:41 +08:00
Ivan Yonchovski
032512cebd Fix the nimble build on Windows (#21314)
Fix the build on Windows

- `nimble install` fails on Windows, the `./` is not needed.

(cherry picked from commit 43b1b9d077)
2023-02-09 05:29:51 +01:00
Ivan Yonchovski
5e1bffb724 Change nim's nimble files to make it installable (#20179)
- needs #20168 to make the stuff working

I went for this minimal solution because it seems like `compiler.nimble` and
`nimsuggest.nimble` are not in use

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
(cherry picked from commit fb2773411e)
2023-02-09 05:28:43 +01:00
narimiran
e0328e28ee more fixes 2023-01-31 19:52:47 +01:00
narimiran
afdbfd2c7e fix some merge conflict leftovers 2023-01-31 18:01:06 +01:00
Ivan Yonchovski
17d45dfd6a Implemented basic macro expand functionality (#20579)
* Implemented level based macro expand functionality

- it can handle single macro call or expand whole function/proc/etc and it

- In addition, I have altered the parser to provide the endInfo for the node.
The usefulness of the `endInfo` is not limited to the `expandMacro`
functionality but also it is useful for `ideOutline` functionality and I have
altered the ideOutline functionality to use `endInfo`. Note `endInfo` most of
the time is lost during the AST transformation thus in `nimsuggest.nim` I am
using freshly parsed tree to get the location information.

* Make sure we stop expanding correctly

* Test CI

* Fix tv3_outline.nim

(cherry picked from commit 7031ea65cd)
2023-01-31 10:23:52 +01:00
Yardanico
f7c79db846 Always use httpclient in nimgrab (#19767)
(cherry picked from commit 06f02bb771)
2023-01-30 10:38:41 +01:00
ringabout
b1a0467ffd fixes #21273; fixes an io.readLine off by one bug [backport 1.0] (#21276)
fixes #21273; io.readLine off by one

(cherry picked from commit c4d3d650ba)
2023-01-27 11:43:37 +01:00
ghais
2c24ac1849 Add osx support for ODBC driver when linking libodbc (#21291)
Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
2023-01-24 15:52:20 +01:00
ringabout
7a43d00a64 fixes #21278; deques.shrink off by one bug (#21284)
fixes #21278; deques.shrink off ny one bug

(cherry picked from commit b82b5d44af)
2023-01-22 11:58:31 +01:00
Jake Leahy
0cdbf5e04e Add nkFastAsgn into semExpr (#20939)
* Add nkFastAsgn into case statement

* Add test case

(cherry picked from commit d26b1232ee)
2023-01-20 08:35:30 +01:00
Ivan Yonchovski
320a820eb4 Implicitly set noNimblePath when nimble.lock is present (#21266)
Fixes https://github.com/nim-lang/nimble/issues/1004

(cherry picked from commit 7c6dcfd968)
2023-01-19 10:33:49 +01:00
Peter Munch-Ellingsen
ebf0e7ebb1 Implement setLineInfo (#21153)
* Implement setLineInfo

* Add tests

(cherry picked from commit 613829f7a4)
2023-01-19 10:33:13 +01:00
Tanguy
9ee9b4283d Allow std/macros.params to work with nnkProcTy (#19563)
* Allow std/macros.params to work with nnkProcTy

* Add tests for proc params & pragma

(cherry picked from commit ef3f343ec2)
2023-01-18 18:13:58 +01:00
ringabout
213a9f9f34 fixes #20906; update copyright year [backport 1.6] (#21210)
(cherry picked from commit 4032eb4baa)
2023-01-18 18:12:53 +01:00
Jake Leahy
8c0f2f0152 Check file exists in {.compile.} pragma (#21105)
* Add test

* Check file exists before adding it into compilation

* Make error message look like other error messages

i.e. following the format `error msg: file`

(cherry picked from commit d00477dffb)
2022-12-16 08:45:48 +01:00
narimiran
d0d8c95094 don't change code blocks in manual.rst 2022-12-16 08:44:56 +01:00
narimiran
ec13574b19 don't backport the change in compiler/nim.cfg 2022-12-16 05:52:42 +01:00
narimiran
a1165c8231 Revert "fix bare exceptions in excpt.nim"
This reverts commit babd80b446.
2022-12-16 05:51:49 +01:00
narimiran
babd80b446 fix bare exceptions in excpt.nim 2022-12-15 21:58:24 +01:00
ringabout
f01ffbf6f1 fix #19580; add warning for bare except: clause (#21099)
* fix #19580; add warning for bare except: clause

* fixes some easy ones

* Update doc/manual.md

* fixes docs

* Update changelog.md

* addition

* Apply suggestions from code review

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

* Update doc/tut2.md

Co-authored-by: Jacek Sieka <arnetheduck@gmail.com>
(cherry picked from commit 91ce8c385d)
2022-12-15 16:31:37 +01:00
ringabout
0da50cef4f fixes #20954; bounchecks for len(toOpenArray()) [backport] (#20956)
* bounchecks for len(toOpenArray())

* add a testcase

(cherry picked from commit b83bd282dc)
2022-12-15 16:25:56 +01:00
narimiran
76c347515a remove unneeded import in the test 2022-12-01 08:42:19 +01:00
narimiran
7f90bcf5b4 and one more missed error 2022-11-30 19:11:44 +01:00
narimiran
d81484bff9 one more fix 2022-11-30 14:06:32 +01:00
narimiran
27732a4248 fix failing CIs 2022-11-30 12:29:39 +01:00
metagn
3e677a6225 dom: remove X* = ref XObj [backport] (#20910)
dom: remove X* = ref XObj
(cherry picked from commit ce971400c0)
2022-11-30 07:33:54 +01:00
metagn
5cfa3672b3 allow proc expressions in place of statements (#20935)
properly fixes #18714

(cherry picked from commit 15d00ca0e1)
2022-11-30 07:31:35 +01:00
metagn
0683e8f747 fix bugs with dot & call operators [backport] (#20931)
* better error messages for dot operators [backport]

fixes #13063

* also fixes #7777

* fix #6981 and #9831 too

* fix

* minor improvement

* sus test fixes

* make test multiplatform lol

* fix nimsuggest test, extra improvements

(cherry picked from commit 555c5ed1a7)
2022-11-30 07:29:42 +01:00
jfilby
d2de2e7be1 Fix several memory leaks in the Postgres wrapper. (#20940)
(cherry picked from commit 5a848a0707)
2022-11-28 14:29:36 +01:00
ringabout
224319f787 fixes #20914; fixes the alignment of big sets (#20918)
* fixes #20914; fixes the align of bug sets

* add a test for alignof

(cherry picked from commit b57a9637e8)
2022-11-26 09:50:45 +01:00
ringabout
871e90aa4e fixes broken importc for vcc [backport] (#20909)
fixes broken imports for vcc

(cherry picked from commit b7d96cd3f5)
2022-11-26 09:50:35 +01:00
narimiran
ca0757d09f bump NimVersion to 1.6.11 2022-11-26 09:50:03 +01:00
narimiran
f1519259f8 bump NimVersion to 1.6.10 2022-11-20 16:21:55 +01:00
ringabout
eaf43a1bd9 fixes remaining ptr2cstring warnings on version-1-6 (#20861) 2022-11-16 21:19:32 +01:00
ringabout
dd80e968e8 fixes ptr to cstring warnings[backport] (#20848)
* fix =#13790 ptr char (+friends) should not implicitly convert to cstring

* Apply suggestions from code review

* first round; compiles on windows

* nimPreviewSlimSystem

* conversion is unsafe, cast needed

* fixes more tests

* fixes asyncnet

* another try another error

* last one

* true

* one more

* why bugs didn't show at once

* add `nimPreviewCstringConversion` switch

* typo

* fixes ptr to cstring warnings[backport]

* add fixes

Co-authored-by: xflywind <43030857+xflywind@users.noreply.github.com>
(cherry picked from commit 06cd15663d)
2022-11-16 16:16:26 +01:00
ringabout
99528ee295 fixes a CI error (#20834)
(cherry picked from commit 7db0d2bb58)
2022-11-14 09:57:42 +01:00
ringabout
2631e99238 issue a warning for ptr to cstring conversion[backport] (#20814)
* issue a warning for ptr to cstring conversion[backport]

* add a changelog

(cherry picked from commit 8e1181bde5)
2022-11-12 06:06:21 +01:00
ringabout
9dc97ed143 revert #19891; nimRawSetjmp causes problems for mingw 32 bits too [backport] (#20758)
revert https://github.com/nim-lang/Nim/pull/19891

(cherry picked from commit d17b1d475c)
2022-11-11 14:20:08 +01:00
tersec
76b0842994 reduce openArray-related C undefined behavior (#20795)
(cherry picked from commit 6894a00409)
2022-11-10 11:16:33 +01:00
Jacek Sieka
eb42fe51da fix closure iter state table init type [backport] (#20717)
fix closure iter state table init type

It is a well-known fact that using closed intervals for ranges is
logically, objectively and eternally wrong, as evidenced by this
off-by-one.

(cherry picked from commit a0653ae71a)
2022-11-10 10:51:14 +01:00
ringabout
0bc52ddb85 fixes #20426; remove maincommand and m options since they are a no op since 2014 (#20429)
* bump macOS image on Azure CI to macos-11

##[warning]The macOS-10.15 environment is deprecated, consider switching to macos-11(macos-latest), macos-12 instead. For more details see https://github.com/actions/virtual-environments/issues/5583

* fix CI error

* fixes #20426; remove `maincommand` and `m` options since they are a noop since 2014 and causes confusion

fixes #20426

7f7b13a45f (diff-d949f8c356fd2dc9ceedc6f3dbbd01e2c806269dd0a8ad6516facf589fa2c99a) makes it a no op, but it causes a regression because it should add `expectArg(switch, arg, pass, info)` before the discard statement. It causes https://github.com/nim-lang/Nim/issues/20426 to happen. Without `expectArg(switch, arg, pass, info)`, `-mm:orc` is wrongly interpreted as `-m` and compiler, which doesn't make sense. It should either abort compilation or prints `argument for command line option expected: '-m'` message. Since they are a no op since 2014, let's remove it to clear the confusion. Let's wait and see whether it breaks something.

* add a changelog

(cherry picked from commit cb24eea86b)
2022-11-04 18:32:58 +01:00
rockcavera
a1c431c6ab Fixing nimRawSetJmp for vcc and clangcl on Windows (#19959)
* fix vcc rawsetjmp

* changing `_longjmp()` to `longjmp()` and

`_setjmp()` to `setjmp()`

* fix

* fix setjmp to clangcl on Windows

* fix genTrySetjmp() to clangcl on Windows

(cherry picked from commit d2d8f1342b)
2022-11-04 07:02:45 +01:00
metagn
121602e88f openssl 3 support (1.6) (#20669) 2022-11-02 14:23:58 +01:00
Jacek Sieka
565cd4dd25 fix dispatcher call type [backport] (#20696)
fix dispatcher call type

The call node should have the type of the dispatcher, not the static
call

(cherry picked from commit f8b5464f31)
2022-10-30 17:01:02 +01:00
Jacek Sieka
38730862fc fix fwrite prototype (#20644)
* fix fwrite prototype

* Update lib/std/syncio.nim

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

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
(cherry picked from commit e2f412145f)
2022-10-25 13:28:18 +02:00
ringabout
999a4bb750 closes #19969; add testcase for #19969 #15952 #16306 (#20610)
closes #19969; add testcase

(cherry picked from commit 1db25ffcd3)
2022-10-24 13:54:29 +02:00
Jason Beetham
2292ff950a Implemented mSlice on the VM allowing toOpenArray to work at compile time. (#20586)
* Implemented opcSlice to make 'toOpenArray' work on the VM

* Added nkOpenArray for VM to reduce bodgeness

* Fixed range issues and erraneous comments

* Range check correctly for openArrays in opcLdArr

* Inverted logic for ldArr checking

* vm now supports slicing strings

* Added string tests

* Removed usage of 'nkOpenArray' and redundant operations

* Refactored vmSlice implementation, removing redundant and incorrect code

* Made tuples go throw opcWrObj for field assignment

* All strkinds should be considered for openarrays

(cherry picked from commit 4aa67ad7fd)
2022-10-24 13:54:05 +02:00
Bung
c5d62bcbfe fix #19349 incompatible type when mixing float32 and cfloat in generics (#20551)
(cherry picked from commit 84fab7f39b)
2022-10-24 13:53:44 +02:00
Tanguy
8e04112762 Fix double defer with break in closureiterators [backport] (#20630)
Fix double defer with break in closureiterators

Signed-off-by: Tanguy <tanguy@status.im>

Signed-off-by: Tanguy <tanguy@status.im>
(cherry picked from commit 008c3ec76a)
2022-10-24 10:38:27 +02:00
Tanguy
c9df6cfd92 Remove side-effects from sysFatal with panics on (#20632)
(cherry picked from commit 4578e773ce)
2022-10-24 10:38:16 +02:00
ringabout
203c18352a fixes #20391; make of operator work with generics for ORC (#20395)
(cherry picked from commit e0c1159fb3)
2022-10-24 10:37:57 +02:00
Bung
ec674e6d5b fix #18990 Regression in proc symbol resolution; Error: attempting to… (#20554)
fix #18990 Regression in proc symbol resolution; Error: attempting to call routine

(cherry picked from commit ea2f2775a7)
2022-10-21 09:19:53 +02:00
SirOlaf
322d2f8096 [backport] Handle nkOpenSymChoice for nkAccQuoted in considerQuotedIdent (#20578)
* Handle nkOpenSymChoice for nkAccQuoted in considerQuotedIdent

* Add test

* Update compiler/lookups.nim

Co-authored-by: SirOlaf <a>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 2f441ac675)
2022-10-21 09:19:14 +02:00
ringabout
c35cb17b13 fixes #20553; don't format code for stropping identifier (#20561) [backport]
* fixes #20553; don't format code for stropping identifier

* add tests

* Update nimpretty/tests/expected/simple.nim

(cherry picked from commit 6082b9ea5d)
2022-10-21 09:19:03 +02:00
Ivan Yonchovski
8b86ba96f8 Fix/improve handling of forward declarations in nimsuggest (#20493)
* Fix/improve handling of forward declarations in nimsuggest

- ideUse now works fine when invoked on the implementation
- implemented ideDeclaration to make cover lsp feature textDocument/declaration
- fixed performance issue related to deduplicating symbols. Now the
deduplication happens after the symbols are filtered. As a alternative we might
change the way cached symbols are stored(e. g. use set).
- I also fixed the way globalSymbols work. Now it will sort the responses based
on the match location to make sure that the results are sorted in user friendly way.

* Update nimsuggest/nimsuggest.nim

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

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 7caa037936)
2022-10-06 18:23:10 +02:00
Andreas Rumpf
01a0b31167 allocator: disable unnecessary stuff for ORC [backport] (#20489)
(cherry picked from commit 7aaeb75ebd)
2022-10-06 18:22:43 +02:00
ringabout
02ce5a585b add plausibleAnalytics support for koch docs[backport:1.6] (#20454)
add plausibleAnalytics to koch docs[backport:1.6]

(cherry picked from commit 96c5586d03)
2022-10-06 18:22:36 +02:00
ringabout
ce63020110 fix #19500; remove find optimization [backport: 1.6] (#19714)
* remove find optimization

close #19500

* save find to std

* add simple tests

* Apply suggestions from code review

Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>

Co-authored-by: sandytypical <43030857+xflywind@users.noreply.github.com>
Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>
(cherry picked from commit 65c2518d5c)
2022-10-06 18:21:51 +02:00
ringabout
5abf259908 fixes #20141; dereferencing pointer to incomplete type error with cast (#20147)
Co-authored-by: xflywind <43030857+xflywind@users.noreply.github.com>
(cherry picked from commit e33e9e4a32)
2022-09-30 09:49:07 +02:00
ringabout
31fe32afd1 fixes #20397; fixes stylecheck regression (#20398)
* fixes  #20397; fixes stylecheck

* add testcase

(cherry picked from commit 70c25c45d6)
2022-09-30 09:45:18 +02:00
narimiran
fbd99c781f bump NimVersion to 1.6.9 2022-09-30 09:43:36 +02:00
419 changed files with 8987 additions and 2551 deletions

View File

@@ -2,10 +2,10 @@ name: Nim Docs CI
on:
push:
paths:
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'compiler/**.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
- 'doc/nimdoc.css'
- 'lib/**.nim'
- 'nimdoc/testproject/expected/testproject.html'
@@ -13,13 +13,14 @@ on:
- 'tools/kochdocs.nim'
- '.github/workflows/ci_docs.yml'
- 'koch.nim'
pull_request:
# Run only on changes on these files.
paths:
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'compiler/**.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
- 'doc/nimdoc.css'
- 'lib/**.nim'
- 'nimdoc/testproject/expected/testproject.html'
@@ -28,6 +29,10 @@ on:
- '.github/workflows/ci_docs.yml'
- 'koch.nim'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
strategy:
@@ -36,11 +41,11 @@ jobs:
target: [linux, windows, osx]
include:
- target: linux
os: ubuntu-20.04
os: ubuntu-22.04
- target: windows
os: windows-2019
os: windows-latest
- target: osx
os: macos-11
os: macos-15
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
@@ -48,7 +53,7 @@ jobs:
steps:
- name: 'Checkout'
uses: actions/checkout@v2
uses: actions/checkout@v6
with:
fetch-depth: 2
@@ -104,7 +109,7 @@ jobs:
if: |
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
matrix.target == 'linux'
uses: crazy-max/ghaction-github-pages@v1
uses: crazy-max/ghaction-github-pages@v5
with:
build_dir: doc/html
env:

View File

@@ -1,13 +1,24 @@
name: Packages CI
on: [push, pull_request]
on:
pull_request:
push:
branches:
- 'devel'
- 'version-2-2'
- 'version-2-0'
- 'version-1-6'
- 'version-1-2'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-11]
cpu: [amd64]
os: [ubuntu-latest, macos-14]
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'
runs-on: ${{ matrix.os }}
@@ -17,26 +28,27 @@ jobs:
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
steps:
- name: 'Checkout'
uses: actions/checkout@v2
uses: actions/checkout@v6
with:
fetch-depth: 2
- name: 'Install node.js 16.x'
uses: actions/setup-node@v2
- name: 'Install node.js'
uses: actions/setup-node@v6
with:
node-version: '16.x'
node-version: 24
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
run: |
sudo apt-fast update -qq
sudo apt-get update -qq
DEBIAN_FRONTEND='noninteractive' \
sudo apt-fast install --no-install-recommends -yq \
sudo apt-get install --no-install-recommends -yq \
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
valgrind libc6-dbg libblas-dev xorg-dev
valgrind libc6-dbg libblas-dev liblapack-dev libpcre3 xorg-dev
- name: 'Install dependencies (macOS)'
if: runner.os == 'macOS'
run: brew install boehmgc make sfml gtk+3
# XXX can't find boehm and gtk on macos 13
- name: 'Install dependencies (Windows)'
if: runner.os == 'Windows'
shell: bash

View File

@@ -1,7 +1,8 @@
trigger:
branches:
include:
- '*'
- 'devel'
- 'version-*'
pr:
branches:
include:
@@ -19,32 +20,32 @@ jobs:
strategy:
matrix:
Linux_amd64:
vmImage: 'ubuntu-18.04'
vmImage: 'ubuntu-24.04'
CPU: amd64
# regularly breaks, refs bug #17325
Linux_i386:
# on 'ubuntu-16.04' (not supported anymore anyways) it errored with:
# g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
vmImage: 'ubuntu-18.04'
CPU: i386
OSX_amd64:
vmImage: 'macOS-11'
CPU: amd64
OSX_amd64_cpp:
vmImage: 'macOS-11'
CPU: amd64
# 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_arm64:
vmImage: 'macos-15'
CPU: arm64
OSX_arm64_cpp:
vmImage: 'macos-15'
CPU: arm64
NIM_COMPILE_TO_CPP: true
Windows_amd64_batch0_3:
vmImage: 'windows-2019'
vmImage: 'windows-2025'
CPU: amd64
# see also: `NIM_TEST_PACKAGES`
NIM_TESTAMENT_BATCH: "0_3"
Windows_amd64_batch1_3:
vmImage: 'windows-2019'
vmImage: 'windows-2025'
CPU: amd64
NIM_TESTAMENT_BATCH: "1_3"
Windows_amd64_batch2_3:
vmImage: 'windows-2019'
vmImage: 'windows-2025'
CPU: amd64
NIM_TESTAMENT_BATCH: "2_3"
@@ -72,17 +73,19 @@ jobs:
- task: NodeTool@0
inputs:
versionSpec: '16.x'
displayName: 'Install node.js 16.x'
versionSpec: '20.x'
displayName: 'Install node.js 20.x'
condition: and(succeeded(), eq(variables['skipci'], 'false'))
- bash: |
set -e
. ci/funs.sh
echo_run sudo apt-fast update -qq
echo_run sudo add-apt-repository universe
echo_run sudo apt-get update -qq
DEBIAN_FRONTEND='noninteractive' \
echo_run sudo apt-fast install --no-install-recommends -yq \
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
echo_run sudo apt-get install --no-install-recommends -yq \
gcc-14 g++-14 libpcre3 liblapack-dev libpcre3 liblapack-dev libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
echo_run sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 60 --slave /usr/bin/g++ g++ /usr/bin/g++-14
displayName: 'Install dependencies (amd64 Linux)'
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64'))
@@ -99,15 +102,16 @@ jobs:
Pin-Priority: 1001
EOF
# echo_run sudo apt-fast update -qq
echo_run sudo apt-fast update -qq || echo "failed, see bug #17343"
# echo_run sudo apt-get update -qq
echo_run sudo apt-get update -qq || echo "failed, see bug #17343"
# `:i386` (e.g. in `libffi-dev:i386`) is needed otherwise you may get:
# `could not load: libffi.so` during dynamic loading.
DEBIAN_FRONTEND='noninteractive' \
echo_run sudo apt-fast install --no-install-recommends --allow-downgrades -yq \
echo_run sudo apt-get install --no-install-recommends --allow-downgrades -yq \
g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \
libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386 libffi-dev:i386
cat << EOF > bin/gcc
#!/bin/bash
@@ -129,6 +133,7 @@ jobs:
- bash: brew install boehmgc make sfml
displayName: 'Install dependencies (OSX)'
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Darwin'))
# XXX can't find boehm on macos 13
- bash: |
set -e

View File

@@ -3,12 +3,54 @@
## Changes affecting backward compatibility
- `addr` is now available for all addressable locations,
`unsafeAddr` is now deprecated and an alias for `addr`.
- `io`, `assertions`, `formatfloat`, and `` dollars.`$` `` for objects are about to move out of the `system` module. You may instead import `std/syncio`, `std/assertions`, `std/formatfloat` and `std/objectdollar`.
The `-d:nimPreviewSlimSystem` option makes these imports required.
- The `gc:v2` option is removed.
- The `mainmodule` and `m` options are removed.
- The `threads:on` option is now the default.
- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via
`experimental:flexibleOptionalParams`.
## Standard library additions and changes
- 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`.
- Object fields now support default values, see https://nim-lang.github.io/Nim/manual.html#types-default-values-for-object-fields for details.
- 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.
## Standard library additions and changes
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
@@ -58,7 +100,7 @@
- `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` now only applies to the current package.
- `--styleCheck`, `--hintAsError` and `--warningAsError` now only applies to the current package.
## Tool changes

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

@@ -1,9 +0,0 @@
version = system.NimVersion
author = "Andreas Rumpf"
description = "Compiler package providing the compiler sources as a library."
license = "MIT"
installDirs = @["compiler", "nimsuggest"]
requires "nim >= 0.14.0"

View File

@@ -229,7 +229,7 @@ type
TNodeKinds* = set[TNodeKind]
type
TSymFlag* = enum # 48 flags!
TSymFlag* = enum # 49 flags!
sfUsed, # read access of sym (for warnings) or simply used
sfExported, # symbol is exported from module
sfFromGeneric, # symbol is instantiation of a generic; this is needed
@@ -300,6 +300,12 @@ type
sfSingleUsedTemp # For temporaries that we know will only be used once
sfNoalias # 'noalias' annotation, means C's 'restrict'
sfEffectsDelayed # an 'effectsDelayed' parameter
sfGeneratedType # A anonymous generic type that is generated by the compiler for
# objects that do not have generic parameters in case one of the
# object fields has one.
#
# This is disallowed but can cause the typechecking to go into
# an infinite loop, this flag is used as a sentinel to stop it.
TSymFlags* = set[TSymFlag]
@@ -499,6 +505,7 @@ type
nfLastRead # this node is a last read
nfFirstWrite# this node is a first write
nfHasComment # node has a comment
nfSkipFieldChecking # node skips field visable checking
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45)
@@ -670,7 +677,7 @@ type
mInSet, mRepr, mExit,
mSetLengthStr, mSetLengthSeq,
mIsPartOf, mAstToStr, mParallel,
mSwap, mIsNil, mArrToSeq,
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
mNewString, mNewStringOfCap, mParseBiggestFloat,
mMove, mWasMoved, mDestroy, mTrace,
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
@@ -704,8 +711,8 @@ type
mSymIsInstantiationOf, mNodeId, mPrivateAccess
# things that we can evaluate safely at compile time, even if not asked for it:
const
# things that we can evaluate safely at compile time, even if not asked for it:
ctfeWhitelist* = {mNone, mSucc,
mPred, mInc, mDec, mOrd, mLengthOpenArray,
mLengthStr, mLengthArray, mLengthSeq,
@@ -734,6 +741,9 @@ const
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet,
mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInSet, mRepr}
generatedMagics* = {mNone, mIsolate, mFinished, mOpenArrayToSeq}
## magics that are generated as normal procs in the backend
type
ItemId* = object
@@ -777,6 +787,8 @@ type
ident*: PIdent
else:
sons*: TNodeSeq
when defined(nimsuggest):
endInfo*: TLineInfo
TStrTable* = object # a table[PIdent] of PSym
counter*: int
@@ -873,6 +885,9 @@ type
typ*: PType
name*: PIdent
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.:
@@ -1058,7 +1073,8 @@ const
nfDotSetter, nfDotField,
nfIsRef, nfIsPtr, nfPreventCg, nfLL,
nfFromTemplate, nfDefaultRefsParam,
nfExecuteOnReload, nfLastRead, nfFirstWrite}
nfExecuteOnReload, nfLastRead,
nfFirstWrite, nfSkipFieldChecking}
namePos* = 0
patternPos* = 1 # empty except for term rewriting macros
genericParamsPos* = 2
@@ -1098,11 +1114,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
@@ -1503,7 +1518,7 @@ proc assignType*(dest, src: PType) =
# this fixes 'type TLock = TSysLock':
if src.sym != nil:
if dest.sym != nil:
dest.sym.flags.incl src.sym.flags-{sfExported}
dest.sym.flags.incl src.sym.flags-{sfUsed, sfExported}
if dest.sym.annex == nil: dest.sym.annex = src.sym.annex
mergeLoc(dest.sym.loc, src.sym.loc)
else:
@@ -1657,6 +1672,8 @@ proc copyNode*(src: PNode): PNode =
of nkIdent: result.ident = src.ident
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
else: discard
when defined(nimsuggest):
result.endInfo = src.endInfo
template transitionNodeKindCommon(k: TNodeKind) =
let obj {.inject.} = n[]
@@ -1673,6 +1690,10 @@ proc transitionIntKind*(n: PNode, kind: range[nkCharLit..nkUInt64Lit]) =
transitionNodeKindCommon(kind)
n.intVal = obj.intVal
proc transitionIntToFloatKind*(n: PNode, kind: range[nkFloatLit..nkFloat128Lit]) =
transitionNodeKindCommon(kind)
n.floatVal = BiggestFloat(obj.intVal)
proc transitionNoneToSym*(n: PNode) =
transitionNodeKindCommon(nkSym)
@@ -1705,6 +1726,8 @@ template copyNodeImpl(dst, src, processSonsStmt) =
if src == nil: return
dst = newNode(src.kind)
dst.info = src.info
when defined(nimsuggest):
result.endInfo = src.endInfo
dst.typ = src.typ
dst.flags = src.flags * PersistentNodeFlags
dst.comment = src.comment
@@ -2010,6 +2033,9 @@ template detailedInfo*(sym: PSym): string =
proc isInlineIterator*(typ: PType): bool {.inline.} =
typ.kind == tyProc and tfIterator in typ.flags and typ.callConv != ccClosure
proc isIterator*(typ: PType): bool {.inline.} =
typ.kind == tyProc and tfIterator in typ.flags
proc isClosureIterator*(typ: PType): bool {.inline.} =
typ.kind == tyProc and tfIterator in typ.flags and typ.callConv == ccClosure

View File

@@ -155,7 +155,7 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} =
else:
result = true
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope, Rope) =
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
var a, b, c: TLoc
initLocExpr(p, q[1], a)
initLocExpr(p, q[2], b)
@@ -163,6 +163,8 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope,
# but first produce the required index checks:
if optBoundsCheck in p.options:
genBoundsCheck(p, a, b, c)
if prepareForMutation:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
let ty = skipTypes(a.t, abstractVar+{tyPtr})
let dest = getTypeDesc(p.module, destType)
let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)]
@@ -192,10 +194,12 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType): (Rope,
optSeqDestructors in p.config.globalOptions:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
if atyp.kind in {tyVar} and not compileToCpp(p.module):
result = ("($4*)(*$1)$3+($2)" % [rdLoc(a), rdLoc(b), dataField(p), dest],
result = ("(($5) ? (($4*)(*$1)$3+($2)) : NIM_NIL)" %
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, "*" & rdLoc(a))],
lengthExpr)
else:
result = ("($4*)$1$3+($2)" % [rdLoc(a), rdLoc(b), dataField(p), dest],
result = ("(($5) ? (($4*)$1$3+($2)) : NIM_NIL)" %
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, rdLoc(a))],
lengthExpr)
else:
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
@@ -236,9 +240,12 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
if ntyp.kind in {tyVar} and not compileToCpp(p.module):
var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
result = "($4) ? ((*$1)$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, t), dataField(p),
dataFieldAccessor(p, "*" & a.rdLoc)]
else:
result = "$1$3, $2" % [a.rdLoc, lenExpr(p, a), dataField(p)]
result = "($4) ? ($1$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)]
of tyArray:
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
of tyPtr, tyRef:
@@ -246,7 +253,9 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
of tyString, tySequence:
var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
result = "($4) ? ((*$1)$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, t), dataField(p),
dataFieldAccessor(p, "*" & a.rdLoc)]
of tyArray:
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))]
else:

View File

@@ -292,8 +292,8 @@ proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $2Len_0;$n",
[rdLoc(d), a.rdLoc])
of tySequence:
linefmt(p, cpsStmts, "$1.Field0 = $2$3; $1.Field1 = $4;$n",
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)])
linefmt(p, cpsStmts, "$1.Field0 = ($5) ? ($2$3) : NIM_NIL; $1.Field1 = $4;$n",
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a), dataFieldAccessor(p, a.rdLoc)])
of tyArray:
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n",
[rdLoc(d), rdLoc(a), rope(lengthOrd(p.config, a.t))])
@@ -302,8 +302,8 @@ proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
if etyp.kind in {tyVar} and optSeqDestructors in p.config.globalOptions:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
linefmt(p, cpsStmts, "$1.Field0 = $2$3; $1.Field1 = $4;$n",
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)])
linefmt(p, cpsStmts, "$1.Field0 = ($5) ? ($2$3) : NIM_NIL; $1.Field1 = $4;$n",
[rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a), dataFieldAccessor(p, a.rdLoc)])
else:
internalError(p.config, a.lode.info, "cannot handle " & $a.t.kind)
@@ -444,9 +444,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:
@@ -599,7 +600,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) =
@@ -1003,12 +1004,12 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
if reifiedOpenArray(arr.lode):
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " &
"($1 < 0 || $1 >= $3.Field1 || $2 < 0 || $2 >= $3.Field1)){ #raiseIndexError(); $4}$n",
"($1 < 0 || $1 >= $3.Field1 || $2 < 0 || $2 >= $3.Field1)){ #raiseIndexError4($1, $2, $3.Field1); $4}$n",
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)])
else:
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && ($1 < 0 || $1 >= $3Len_0 || $2 < 0 || $2 >= $3Len_0))" &
"{ #raiseIndexError(); $4}$n",
"{ #raiseIndexError4($1, $2, $3Len_0); $4}$n",
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)])
of tyArray:
let first = intLiteral(firstOrd(p.config, ty))
@@ -1019,7 +1020,7 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
of tySequence, tyString:
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " &
"($1 < 0 || $1 >= $3 || $2 < 0 || $2 >= $3)){ #raiseIndexError(); $4}$n",
"($1 < 0 || $1 >= $3 || $2 < 0 || $2 >= $3)){ #raiseIndexError4($1, $2, $3); $4}$n",
[rdLoc(a), rdLoc(b), lenExpr(p, arr), raiseInstr(p)])
else: discard
@@ -1361,7 +1362,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])
@@ -1398,7 +1399,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])
@@ -1446,6 +1447,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
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),
@@ -1577,6 +1579,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
return
if d.k == locNone:
getTemp(p, n.typ, d)
initLocExpr(p, n[1], a)
# generate call to newSeq before adding the elements per hand:
let L = toInt(lengthOrd(p.config, n[1].typ))
if optSeqDestructors in p.config.globalOptions:
@@ -1586,7 +1589,6 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
getSeqPayloadType(p.module, seqtype)])
else:
genNewSeqAux(p, d, intLiteral(L), L == 0)
initLocExpr(p, n[1], a)
# bug #5007; do not produce excessive C source code:
if L < 10:
for i in 0..<L:
@@ -1714,7 +1716,9 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage)
of tyString, tySequence:
putIntoDest(p, b, e,
"$1$3, $2" % [rdLoc(a), lenExpr(p, a), dataField(p)], a.storage)
"($4) ? ($1$3) : NIM_NIL, $2" %
[rdLoc(a), lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)],
a.storage)
of tyArray:
putIntoDest(p, b, e,
"$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))], a.storage)
@@ -1794,20 +1798,33 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
# Bug #9279, len(toOpenArray()) has to work:
if a.kind in nkCallKinds and a[0].kind == nkSym and a[0].sym.magic == mSlice:
# magic: pass slice to openArray:
var m: TLoc
var b, c: TLoc
initLocExpr(p, a[1], m)
initLocExpr(p, a[2], b)
initLocExpr(p, a[3], c)
if optBoundsCheck in p.options:
genBoundsCheck(p, m, b, c)
if op == mHigh:
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)", [rdLoc(b), rdLoc(c)]))
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)")
@@ -1858,7 +1875,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)])
@@ -2030,7 +2047,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)", [rdCharLoc(a), size]))
putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [addrLoc(p.config, a), size]))
of mLtSet, mLeSet:
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter
initLocExpr(p, e[1], a)
@@ -2092,6 +2109,11 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
elif etyp.kind == tyBool and srcTyp.kind in IntegralTypes:
putIntoDest(p, d, e, "(($1) != 0)" % [rdCharLoc(a)], a.storage)
else:
if etyp.kind == tyPtr:
# generates the definition of structs for casts like cast[ptr object](addr x)[]
let internalType = etyp.skipTypes({tyPtr})
if internalType.kind == tyObject:
discard getTypeDesc(p.module, internalType)
putIntoDest(p, d, e, "(($1) ($2))" %
[getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage)
@@ -2288,7 +2310,10 @@ proc genDispose(p: BProc; n: PNode) =
lineCg(p, cpsStmts, ["#nimDestroyAndDispose($#)", rdLoc(a)])
proc genSlice(p: BProc; e: PNode; d: var TLoc) =
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon)
let (x, y) = genOpenArraySlice(p, e, e.typ, e.typ.lastSon,
prepareForMutation = e[1].kind == nkHiddenDeref and
e[1].typ.skipTypes(abstractInst).kind == tyString and
p.config.selectedGC in {gcArc, gcOrc})
if d.k == locNone: getTemp(p, e.typ, d)
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y])
when false:
@@ -2370,7 +2395,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
genDollar(p, e, d, "#nimFloatToStr($1)")
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
of mStrToStr, mUnown: expr(p, e[1], d)
of mIsolate, mFinished: genCall(p, e, d)
of generatedMagics: genCall(p, e, d)
of mEnumToStr:
if optTinyRtti in p.config.globalOptions:
genEnumToStr(p, e, d)
@@ -2543,15 +2568,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
@@ -2965,7 +3005,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
if n[genericParamsPos].kind == nkEmpty:
var prc = n[namePos].sym
if useAliveDataFromDce in p.module.flags:
if p.module.alive.contains(prc.itemId.item) and prc.magic in {mNone, mIsolate, mFinished}:
if p.module.alive.contains(prc.itemId.item) and
prc.magic in generatedMagics:
genProc(p.module, prc)
elif prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags:
if ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or

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

@@ -405,7 +405,7 @@ proc genClosureVar(p: BProc, a: PNode) =
genLineDir(p, a)
if immediateAsgn:
loadInto(p, a[0], a[2], v)
else:
elif sfNoInit notin a[0][1].sym.flags:
constructLoc(p, v)
proc genVarStmt(p: BProc, n: PNode) =
@@ -1367,13 +1367,18 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "$1.status = __builtin_setjmp($1.context);$n", [safePoint])
elif isDefined(p.config, "nimRawSetjmp"):
if isDefined(p.config, "mswindows"):
# The Windows `_setjmp()` takes two arguments, with the second being an
# undocumented buffer used by the SEH mechanism for stack unwinding.
# Mingw-w64 has been trying to get it right for years, but it's still
# prone to stack corruption during unwinding, so we disable that by setting
# it to NULL.
# More details: https://github.com/status-im/nimbus-eth2/issues/3121
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint])
if isDefined(p.config, "vcc") or isDefined(p.config, "clangcl"):
# For the vcc compiler, use `setjmp()` with one argument.
# See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setjmp?view=msvc-170
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
else:
# The Windows `_setjmp()` takes two arguments, with the second being an
# undocumented buffer used by the SEH mechanism for stack unwinding.
# Mingw-w64 has been trying to get it right for years, but it's still
# prone to stack corruption during unwinding, so we disable that by setting
# it to NULL.
# More details: https://github.com/status-im/nimbus-eth2/issues/3121
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint])
else:
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
else:
@@ -1587,6 +1592,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
initLoc(a, locNone, le, OnUnknown)
a.flags.incl(lfEnforceDeref)
a.flags.incl(lfPrepareForMutation)
genLineDir(p, le) # it can be a nkBracketExpr, which may raise
expr(p, le, a)
a.flags.excl(lfPrepareForMutation)
if fastAsgn: incl(a.flags, lfNoDeepCopy)

View File

@@ -35,17 +35,97 @@ proc mangleField(m: BModule; name: PIdent): string =
if isKeyword(name):
result.add "_0"
proc encodeName*(name: string): string =
result = mangle(name)
result = $result.len & result
proc makeUnique(m: BModule; s: PSym, name: string = ""): Rope =
let str = if name == "": s.name.s else: name
result.add str
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
proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
result = "_Z" # Common prefix in Itanium ABI
result.add encodeSym(m, s, makeUnique)
if s.typ.len > 1: #we dont care about the return param
for i in 1..<s.typ.len:
if s.typ[i].isNil: continue
result.add encodeType(m, s.typ[i])
if result in m.g.mangledPrcs:
result = mangleProc(m, s, true)
else:
m.g.mangledPrcs.incl(result)
proc mangleName(m: BModule; s: PSym): Rope =
result = s.loc.r
if result == nil:
result = s.name.s.mangle.rope
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_"
result.add rope s.itemId.item
if $s.loc.r == "":
var result: Rope
if s.kind in routineKinds and optCDebug in m.g.config.globalOptions and
m.g.config.symbolFiles == disabledSf:
result = mangleProc(m, s, false).rope
else:
result = s.name.s.mangle.rope
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.add $s.itemId.item # s.disamb #
if m.hcrOn:
result.add "_"
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts))
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
s.loc.r = result
writeMangledName(m.ndi, s, m.config)
@@ -311,7 +391,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
else: result = nil
if result != nil and typ.isImportedType():
let sig = hashType typ
let sig = hashType(typ, m.config)
if cacheGetType(m.typeCache, sig) == nil:
m.typeCache[sig] = result
@@ -371,10 +451,10 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R
if isImportedCppType(etB) and t.kind == tyGenericInst:
result = getTypeDescAux(m, t, check, kind)
else:
result = getTypeForward(m, t, hashType(t))
result = getTypeForward(m, t, hashType(t, m.config))
pushType(m, t)
of tySequence:
let sig = hashType(t)
let sig = hashType(t, m.config)
if optSeqDestructors in m.config.globalOptions:
if skipTypes(etB[0], typedescInst).kind == tyEmpty:
internalError(m.config, "cannot map the empty seq type to a C type")
@@ -407,7 +487,7 @@ proc getSeqPayloadType(m: BModule; t: PType): Rope =
#result = getTypeForward(m, t, hashType(t)) & "_Content"
proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) =
let sig = hashType(t)
let sig = hashType(t, m.config)
let result = cacheGetType(m.typeCache, sig)
if result == nil:
discard getTypeDescAux(m, t, check, skVar)
@@ -672,7 +752,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
else: result.elemType
proc getOpenArrayDesc(m: BModule, t: PType, check: var IntSet; kind: TSymKind): Rope =
let sig = hashType(t)
let sig = hashType(t, m.config)
if kind == skParam:
result = getTypeDescWeak(m, t[0], check, kind) & "*"
else:
@@ -696,7 +776,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
# C type generation into an analysis and a code generation phase somehow.
if t.sym != nil: useHeader(m, t.sym)
if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
let sig = hashType(origTyp)
let sig = hashType(origTyp, m.config)
defer: # defer is the simplest in this case
if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
@@ -725,7 +805,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
result = getTypeDescAux(m, et, check, kind) & star
else:
# no restriction! We have a forward declaration for structs
let name = getTypeForward(m, et, hashType et)
let name = getTypeForward(m, et, hashType(et, m.config))
result = name & star
m.typeCache[sig] = result
of tySequence:
@@ -734,7 +814,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
m.typeCache[sig] = result
else:
# no restriction! We have a forward declaration for structs
let name = getTypeForward(m, et, hashType et)
let name = getTypeForward(m, et, hashType(et, m.config))
result = name & seqStar(m) & star
m.typeCache[sig] = result
pushType(m, et)
@@ -897,7 +977,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin
discard # addAbiCheck(m, t, result) # already handled elsewhere
of tySet:
# Don't use the imported name as it may be scoped: 'Foo::SomeKind'
result = $t.kind & '_' & t.lastSon.typeName & $t.lastSon.hashType
result = $t.kind & '_' & t.lastSon.typeName & $t.lastSon.hashType(m.config)
m.typeCache[sig] = result
if not isImportedType(t):
let s = int(getSize(m.config, t))
@@ -1026,7 +1106,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
# compute type flags for GC optimization
var flags = 0
if not containsGarbageCollectedRef(typ): flags = flags or 1
if not canFormAcycle(typ): flags = flags or 2
if not canFormAcycle(m.g.graph, typ): flags = flags or 2
#else echo("can contain a cycle: " & typeToString(typ))
if flags != 0:
m.s[cfsTypeInit3].addf("$1.flags = $2;$n", [nameHcr, rope(flags)])
@@ -1070,7 +1150,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
objtype = objtype[0].skipTypes(abstractPtrs)
if objtype.sym == nil:
internalError(m.config, d.info, "anonymous obj with discriminator")
result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)]
result = "NimDT_$1_$2" % [rope($hashType(objtype, m.config)), rope(d.name.s.mangle)]
proc rope(arg: Int128): Rope = rope($arg)
@@ -1278,7 +1358,7 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
var it = t
while it != nil:
it = it.skipTypes(skipPtrs)
if it.sym != nil:
if it.sym != nil and tfFromGeneric notin it.flags:
var m = it.sym.owner
while m != nil and m.kind != skModule: m = m.owner
if m == nil or sfSystemModule in m.flags:
@@ -1291,7 +1371,7 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
res.add m.name.s & "."
res.add it.sym.name.s
else:
res.add $hashType(it)
res.add $hashType(it, m.config)
res.add "|"
it = it[0]
result = makeCString(res)
@@ -1312,7 +1392,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope =
result = theProc.loc.r
when false:
if not canFormAcycle(t) and op == attachedTrace:
if not canFormAcycle(m.g.graph, t) and op == attachedTrace:
echo "ayclic but has this =trace ", t, " ", theProc.ast
else:
when false:
@@ -1339,7 +1419,7 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn
let traceImpl = genHook(m, t, info, attachedTrace)
var flags = 0
if not canFormAcycle(t): flags = flags or 1
if not canFormAcycle(m.g.graph, t): flags = flags or 1
addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.flags = $6;", [
name, destroyImpl, getTypeDesc(m, t), typeName,
@@ -1355,7 +1435,7 @@ proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
let prefixTI = if m.hcrOn: "(" else: "(&"
let sig = hashType(origType)
let sig = hashType(origType, m.config)
result = m.typeInfoMarkerV2.getOrDefault(sig)
if result != nil:
return prefixTI.rope & result & ")".rope
@@ -1426,7 +1506,7 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
let prefixTI = if m.hcrOn: "(" else: "(&"
let sig = hashType(origType)
let sig = hashType(origType, m.config)
result = m.typeInfoMarker.getOrDefault(sig)
if result != nil:
return prefixTI.rope & result & ")".rope

View File

@@ -13,6 +13,11 @@ import
ast, types, hashes, strutils, msgs, wordrecg,
platform, trees, options, cgendata
import std/[hashes, strutils]
when defined(nimPreviewSlimSystem):
import std/assertions
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
case n.kind
of nkStmtList:
@@ -141,4 +146,3 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
if s.position == 0 and retType != nil and retType.kind == tyLent:
result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or
pt.kind == tySet and mapSetType(conf, pt) == ctArray)

View File

@@ -260,7 +260,8 @@ proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
[rope(makeSingleLineCString(filename)), rope(line)])
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
if optLineDir in conf.options:
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
if p.lastLineInfo.line != info.line or
@@ -274,7 +275,7 @@ proc genLineDir(p: BProc, t: PNode) =
if optEmbedOrigSrc in p.config.globalOptions:
p.s(cpsStmts).add(~"//" & sourceLine(p.config, t.info) & "\L")
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
genCLineDir(p.s(cpsStmts), t.info, p.config)
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
if freshLineInfo(p, t.info):
@@ -307,6 +308,12 @@ proc lenExpr(p: BProc; a: TLoc): Rope =
else:
result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)]
proc dataFieldAccessor(p: BProc, sym: Rope): Rope =
if optSeqDestructors in p.config.globalOptions:
result = "(" & sym & ").p"
else:
result = sym
proc dataField(p: BProc): Rope =
if optSeqDestructors in p.config.globalOptions:
result = rope".p->data"
@@ -525,6 +532,9 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
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)
result.add getTypeDesc(p.module, s.typ, skVar)
if s.constraint.isNil:
if sfRegister in s.flags: result.add(" register")
@@ -1162,6 +1172,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
@@ -1180,20 +1204,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])
@@ -1256,10 +1266,10 @@ proc genVarPrototype(m: BModule, n: PNode) =
if sym.owner.id != m.module.id:
# else we already have the symbol generated!
assert(sym.loc.r != nil)
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 ")
@@ -1320,7 +1330,7 @@ proc getSomeInitName(m: BModule, suffix: string): Rope =
proc getInitName(m: BModule): Rope =
if sfMainModule in m.module.flags:
# generate constant name for main module, for "easy" debugging.
result = rope"NimMainModule"
result = rope(m.config.nimMainPrefix) & rope"NimMainModule"
else:
result = getSomeInitName(m, "Init000")
@@ -1353,35 +1363,35 @@ proc genMainProc(m: BModule) =
preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L")
preMainCode.add("\t(*inner)();\L")
else:
preMainCode.add("\tPreMain();\L")
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"
const
# not a big deal if we always compile these 3 global vars... makes the HCR code easier
PosixCmdLine =
"N_LIB_PRIVATE int cmdCount;$N" &
"N_LIB_PRIVATE char** cmdLine;$N" &
"N_LIB_PRIVATE char** gEnv;$N"
# The use of a volatile function pointer to call Pre/NimMainInner
# prevents inlining of the NimMainInner function and dependent
# functions, which might otherwise merge their stack frames.
PreMainVolatileBody =
"\tvoid (*volatile inner)(void);$N" &
"\tinner = PreMainInner;$N" &
"\tinner = $3PreMainInner;$N" &
"$1" &
"\t(*inner)();$N"
PreMainNonVolatileBody =
"$1" &
"\tPreMainInner();$N"
"\t$3PreMainInner();$N"
PreMainBodyStart = "$N" &
"N_LIB_PRIVATE void PreMainInner(void) {$N" &
"N_LIB_PRIVATE void $3PreMainInner(void) {$N" &
"$2" &
"}$N$N" &
PosixCmdLine &
"N_LIB_PRIVATE void PreMain(void) {$N"
"$4" &
"N_LIB_PRIVATE void $3PreMain(void) {$N"
PreMainBodyEnd =
"}$N$N"
@@ -1392,21 +1402,21 @@ proc genMainProc(m: BModule) =
MainProcsWithResult =
MainProcs & ("\treturn $1nim_program_result;$N")
NimMainInner = "N_LIB_PRIVATE N_CDECL(void, NimMainInner)(void) {$N" &
NimMainInner = "N_LIB_PRIVATE N_CDECL(void, $5NimMainInner)(void) {$N" &
"$1" &
"}$N$N"
NimMainVolatileBody =
"\tvoid (*volatile inner)(void);$N" &
"$4" &
"\tinner = NimMainInner;$N" &
"\tinner = $5NimMainInner;$N" &
"$2" &
"\t(*inner)();$N"
NimMainNonVolatileBody =
"$4" &
"$2" &
"\tNimMainInner();$N"
"\t$5NimMainInner();$N"
NimMainProcStart =
"N_CDECL(void, $5NimMain)(void) {$N"
@@ -1486,9 +1496,9 @@ proc genMainProc(m: BModule) =
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])
inc(m.labels)
if m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit])
appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit, m.config.nimMainPrefix, posixCmdLine])
else:
appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainNonVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit])
appcg(m, m.s[cfsProcs], PreMainBodyStart & PreMainNonVolatileBody & PreMainBodyEnd, [m.g.mainDatInit, m.g.otherModsInit, m.config.nimMainPrefix, posixCmdLine])
if m.config.target.targetOS == osWindows and
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
@@ -1594,7 +1604,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
hcrModuleMeta.addf("\t\"\"};$n", [])
hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(void**, HcrGetImportedModules)() { return (void**)hcr_module_list; }$n", [])
hcrModuleMeta.addf("$nN_LIB_EXPORT N_NIMCALL(char*, HcrGetSigHash)() { return \"$1\"; }$n$n",
[($sigHash(m.module)).rope])
[($sigHash(m.module, m.config)).rope])
if sfMainModule in m.module.flags:
g.mainModProcs.add(hcrModuleMeta)
g.mainModProcs.addf("static void* hcr_handle;$N", [])

View File

@@ -138,6 +138,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

View File

@@ -46,6 +46,7 @@ proc methodCall*(n: PNode; conf: ConfigRef): PNode =
# replace ordinary method by dispatcher method:
let disp = getDispatcher(result[0].sym)
if disp != nil:
result[0].typ = disp.typ
result[0].sym = disp
# change the arguments to up/downcasts to fit the dispatcher's parameters:
for i in 1..<result.len:

View File

@@ -852,7 +852,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)
@@ -1152,7 +1154,7 @@ proc newArrayType(g: ModuleGraph; n: int, t: PType; idgen: IdGenerator; owner: P
result = newType(tyArray, nextTypeId(idgen), owner)
let rng = newType(tyRange, nextTypeId(idgen), owner)
rng.n = newTree(nkRange, g.newIntLit(owner.info, 0), g.newIntLit(owner.info, n))
rng.n = newTree(nkRange, g.newIntLit(owner.info, 0), g.newIntLit(owner.info, n - 1))
rng.rawAddSon(t)
result.rawAddSon(rng)
@@ -1369,6 +1371,7 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode =
# detect: 'finally: raises X' which is currently not supported. We produce
# an error for this case for now. All this will be done properly with Yuriy's
# patch.
result = n
case n.kind
of nkTryStmt:
@@ -1385,6 +1388,7 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode =
discard c.finallys.pop()
of nkWhileStmt, nkBlockStmt:
if n.hasYields == false: return n
c.blocks.add((n, c.finallys.len))
for i in 0 ..< n.len:
result[i] = preprocess(c, n[i])

View File

@@ -776,7 +776,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "clib":
expectArg(conf, switch, arg, pass, info)
if pass in {passCmd2, passPP}:
conf.cLinkedLibs.add processPath(conf, arg, info).string
conf.cLinkedLibs.add arg
of "header":
if conf != nil: conf.headerFile = arg
incl(conf.globalOptions, optGenIndex)
@@ -1052,7 +1052,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
processOnOffSwitchG(conf, {optEnableDeepCopy}, arg, pass, info)
of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -)
handleStdinInput(conf)
of "nilseqs", "nilchecks", "mainmodule", "m", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch)
of "nilseqs", "nilchecks", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch)
of "nimmainprefix": conf.nimMainPrefix = arg
else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)

View File

@@ -140,3 +140,5 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasEffectsOf")
defineSymbol("nimHasEnforceNoRaises")
defineSymbol("nimHasWarnBareExcept")
defineSymbol("nimHasTopDownInference")

View File

@@ -58,12 +58,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

@@ -605,11 +605,11 @@ proc aliases*(obj, field: PNode): AliasKind =
var n = n
while true:
case n.kind
of PathKinds0 - {nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}:
of PathKinds0 - {nkDotExpr, nkBracketExpr}:
n = n[0]
of PathKinds1:
n = n[1]
of nkDotExpr, nkCheckedFieldExpr, nkBracketExpr:
of nkDotExpr, nkBracketExpr:
result.add n
n = n[0]
of nkSym:
@@ -642,8 +642,6 @@ proc aliases*(obj, field: PNode): AliasKind =
if currFieldPath.sym != currObjPath.sym: return no
of nkDotExpr:
if currFieldPath[1].sym != currObjPath[1].sym: return no
of nkCheckedFieldExpr:
if currFieldPath[0][1].sym != currObjPath[0][1].sym: return no
of nkBracketExpr:
if currFieldPath[1].kind in nkLiterals and currObjPath[1].kind in nkLiterals:
if currFieldPath[1].intVal != currObjPath[1].intVal:

View File

@@ -275,6 +275,10 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
conf.configVars, filename.string,
docgenFindFile, compilerMsgHandler)
if conf.configVars.hasKey("doc.googleAnalytics") and
conf.configVars.hasKey("doc.plausibleAnalytics"):
doAssert false, "Either use googleAnalytics or plausibleAnalytics"
if conf.configVars.hasKey("doc.googleAnalytics"):
result.analytics = """
<script>
@@ -288,6 +292,10 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
</script>
""" % [conf.configVars.getOrDefault"doc.googleAnalytics"]
elif conf.configVars.hasKey("doc.plausibleAnalytics"):
result.analytics = """
<script defer data-domain="$1" src="https://plausible.io/js/plausible.js"></script>
""" % [conf.configVars.getOrDefault"doc.plausibleAnalytics"]
else:
result.analytics = ""
@@ -521,7 +529,7 @@ proc runAllExamples(d: PDoc) =
proc quoted(a: string): string = result.addQuoted(a)
proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): auto =
proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): (string, int, int) =
# xxx expose in compiler/lineinfos.nim
(conf.toMsgFilename(info), info.line.int, info.col.int + ColOffset)
@@ -1528,7 +1536,7 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
let filename = getOutFile(conf, RelativeFile conf.projectName, JsonExt)
try:
writeFile(filename, content)
except:
except IOError:
rawMessage(conf, errCannotOpenFile, filename.string)
proc commandTags*(cache: IdentCache, conf: ConfigRef) =
@@ -1551,7 +1559,7 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) =
let filename = getOutFile(conf, RelativeFile conf.projectName, TagsExt)
try:
writeFile(filename, content)
except:
except IOError:
rawMessage(conf, errCannotOpenFile, filename.string)
proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") =
@@ -1572,5 +1580,5 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"")
try:
writeFile(filename, code)
except:
except IOError:
rawMessage(conf, errCannotOpenFile, filename.string)

View File

@@ -150,7 +150,7 @@ compiler vcc:
compileTmpl: "/c$vccplatform $options $include /nologo /Fo$objfile $file",
buildGui: " /SUBSYSTEM:WINDOWS user32.lib ",
buildDll: " /LD",
buildLib: "lib /OUT:$libfile $objfiles",
buildLib: "vccexe --command:lib$vccplatform /nologo /OUT:$libfile $objfiles",
linkerExe: "cl",
linkTmpl: "$builddll$vccplatform /Fe$exefile $objfiles $buildgui /nologo $options",
includeCmd: " /I",
@@ -517,7 +517,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
var exe = getConfigVar(conf, conf.cCompiler, ".exe")
if exe.len == 0: exe = CC[conf.cCompiler].compilerExe
# NOTE: should we need the full version, use -dumpfullversion
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except: ("", 1)
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except IOError, OSError, ValueError: ("", 1)
if exitCode == 0:
var major: int
discard parseInt(s, major)
@@ -565,7 +565,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)]))
@@ -665,7 +665,8 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
if removeStaticFile:
removeFile output # fixes: bug #16947
result = CC[conf.cCompiler].buildLib % ["libfile", quoteShell(output),
"objfiles", objfiles]
"objfiles", objfiles,
"vccplatform", vccplatform(conf)]
else:
var linkerExe = getConfigVar(conf, conf.cCompiler, ".linkerexe")
if linkerExe.len == 0: linkerExe = getLinkerExe(conf, conf.cCompiler)
@@ -818,10 +819,22 @@ 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)
proc linkViaShellScript(conf: ConfigRef; cmd: string) =
let linkerScript = conf.projectName & "_" & "linkerScript.sh"
writeFile(linkerScript, cmd)
let shell = getEnv("SHELL")
try:
execLinkCmd(conf, shell & " " & linkerScript)
finally:
removeFile(linkerScript)
proc getObjFilePath(conf: ConfigRef, f: Cfile): string =
if noAbsolutePaths(conf): f.obj.extractFilename
else: f.obj.string
@@ -915,12 +928,16 @@ proc callCCompiler*(conf: ConfigRef) =
linkCmd = getLinkCmd(conf, mainOutput, objfiles, removeStaticFile = true)
extraCmds = getExtraCmds(conf, mainOutput)
if optCompileOnly notin conf.globalOptions:
const MaxCmdLen = when defined(windows): 8_000 else: 32_000
const MaxCmdLen = when defined(windows): 8_000 elif defined(macosx): 260_000 else: 32_000
if linkCmd.len > MaxCmdLen:
# Windows's command line limit is about 8K (don't laugh...) so C compilers on
# Windows support a feature where the command line can be passed via ``@linkcmd``
# to them.
linkViaResponseFile(conf, linkCmd)
when defined(macosx):
# macOS's `ar` does not support response files
linkViaShellScript(conf, linkCmd)
else:
# Windows's command line limit is about 8K (don't laugh...) so C compilers on
# Windows support a feature where the command line can be passed via ``@linkcmd``
# to them.
linkViaResponseFile(conf, linkCmd)
else:
execLinkCmd(conf, linkCmd)
for cmd in extraCmds:
@@ -1006,7 +1023,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
var bcache: BuildCache
try: bcache.fromJson(jsonFile.string.parseFile)
except:
except ValueError, KeyError, JsonKindError:
let e = getCurrentException()
conf.quitOrRaise "\ncaught exception:\n$#\nstacktrace:\n$#error evaluating JSON file: $#" %
[e.msg, e.getStackTrace(), jsonFile.string]

View File

@@ -225,6 +225,11 @@ 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 =
@@ -242,6 +247,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)
@@ -320,22 +326,24 @@ 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]
impMod(c, impAs, result)
else:
imp[2] = x
imp[lastPos] = x
impMod(c, imp, result)
else:
impMod(c, it, result)

View File

@@ -275,7 +275,7 @@ proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode
var op = getAttachedOp(c.graph, t, kind)
if op == nil or op.ast.isGenericRoutine:
# give up and find the canonical type instead:
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
let h = sighashes.hashType(t, c.graph.config, {CoType, CoConsiderOwned, CoDistinct})
let canon = c.graph.canonTypes.getOrDefault(h)
if canon != nil:
op = getAttachedOp(c.graph, canon, kind)
@@ -345,13 +345,13 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) =
if c.graph.config.selectedGC == gcOrc:
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(t):
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:
@@ -706,6 +706,11 @@ 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:
result = shallowCopy(n)
for i in 0 ..< n.len-1:
result[i] = p(n[i], c, s, normal)
result[^1] = maybeVoid(n[^1], s)
else: assert(false)
proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
@@ -735,7 +740,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): 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)
elif mode == sinkArg:
@@ -879,7 +884,10 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
if ri.kind != nkEmpty:
result.add moveOrCopy(v, ri, c, s, isDecl = v.kind == nkSym)
elif ri.kind == nkEmpty and c.inLoop > 0:
result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = v.kind == nkSym)
let skipInit = v.kind == nkDotExpr and # Closure var
sfNoInit in v[1].sym.flags
if not skipInit:
result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = v.kind == nkSym)
else: # keep the var but transform 'ri':
var v = copyNode(n)
var itCopy = copyNode(it)
@@ -912,7 +920,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
result = n
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange:
result = shallowCopy(n)
for i in 0 ..< n.len:
result[i] = p(n[i], c, s, normal)
@@ -994,7 +1002,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
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:
@@ -1051,7 +1059,8 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod
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), isDecl)
of nkBracketExpr:

View File

@@ -141,5 +141,5 @@ shortDesc: "The Nim Compiler"
licenses: "bin/nim,MIT;lib/*,MIT;"
[nimble]
pkgName: "compiler"
pkgName: "nim"
pkgFiles: "compiler/*;doc/basicopt.txt;doc/advopt.txt;doc/nimdoc.css"

View File

@@ -259,7 +259,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
if m.config.hcrOn:
# When hot reloading is enabled, we must ensure that the names
# of functions and types will be preserved across rebuilds:
result.add(idOrSig(s, m.module.name.s, m.sigConflicts))
result.add(idOrSig(s, m.module.name.s, m.sigConflicts, m.config))
else:
result.add("_")
result.add(rope(s.id))
@@ -771,9 +771,6 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
if catchBranchesExist:
p.body.add("++excHandler;\L")
var tmpFramePtr = rope"F"
if optStackTrace notin p.options:
tmpFramePtr = p.getTemp(true)
line(p, tmpFramePtr & " = framePtr;\L")
lineF(p, "try {$n", [])
var a: TCompRes
gen(p, n[0], a)
@@ -782,7 +779,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
if catchBranchesExist:
p.body.addf("--excHandler;$n} catch (EXCEPTION) {$n var prevJSError = lastJSError;$n" &
" lastJSError = EXCEPTION;$n --excHandler;$n", [])
line(p, "framePtr = $1;$n" % [tmpFramePtr])
if hasFrameInfo(p):
line(p, "framePtr = $1;$n" % [tmpFramePtr])
while i < n.len and n[i].kind == nkExceptBranch:
if n[i].len == 1:
# general except section:
@@ -841,7 +839,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
line(p, "}\L")
lineF(p, "lastJSError = prevJSError;$n")
line(p, "} finally {\L")
line(p, "framePtr = $1;$n" % [tmpFramePtr])
if hasFrameInfo(p):
line(p, "framePtr = $1;$n" % [tmpFramePtr])
if i < n.len and n[i].kind == nkFinally:
genStmt(p, n[i][0])
line(p, "}\L")
@@ -1297,75 +1296,89 @@ template isIndirect(x: PSym): bool =
v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator,
skConst, skTemp, skLet})
proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
case n[0].kind
of nkSym:
let s = n[0].sym
if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
case s.kind
of skParam:
r.res = s.loc.r
r.address = nil
r.typ = etyNone
of skVar, skLet, skResult:
r.kind = resExpr
let jsType = mapType(p, n.typ)
if jsType == etyObject:
# make addr() a no-op:
r.typ = etyNone
if isIndirect(s):
r.res = s.loc.r & "[0]"
else:
r.res = s.loc.r
r.address = nil
elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
# for ease of code generation, we do not distinguish between
# sfAddrTaken and sfGlobal.
r.typ = etyBaseIndex
r.address = s.loc.r
r.res = rope("0")
proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
let s = n.sym
if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
case s.kind
of skParam:
r.res = s.loc.r
r.address = nil
r.typ = etyNone
of skVar, skLet, skResult:
r.kind = resExpr
let jsType = mapType(p):
if typ.isNil:
n.typ
else:
# 'var openArray' for instance produces an 'addr' but this is harmless:
gen(p, n[0], r)
#internalError(p.config, n.info, "genAddr: 4 " & renderTree(n))
else: internalError(p.config, n.info, $("genAddr: 2", s.kind))
of nkCheckedFieldExpr:
genCheckedFieldOp(p, n[0], n.typ, r)
of nkDotExpr:
if mapType(p, n.typ) == etyBaseIndex:
genFieldAddr(p, n[0], r)
typ
if jsType == etyObject:
# make addr() a no-op:
r.typ = etyNone
if isIndirect(s):
r.res = s.loc.r & "[0]"
else:
r.res = s.loc.r
r.address = nil
elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
# for ease of code generation, we do not distinguish between
# sfAddrTaken and sfGlobal.
r.typ = etyBaseIndex
r.address = s.loc.r
r.res = rope("0")
else:
genFieldAccess(p, n[0], r)
of nkBracketExpr:
var ty = skipTypes(n[0].typ, abstractVarRange)
if ty.kind in MappedToObject:
gen(p, n[0], r)
else:
let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind
case kindOfIndexedExpr
of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs:
genArrayAddr(p, n[0], r)
of tyTuple:
genFieldAddr(p, n[0], r)
else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
of nkObjDownConv:
gen(p, n[0], r)
of nkHiddenDeref:
gen(p, n[0], r)
of nkHiddenAddr:
gen(p, n[0], r)
of nkStmtListExpr:
if n.len == 1: gen(p, n[0], r)
else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr")
of nkCallKinds:
if n[0].typ.kind == tyOpenArray:
# 'var openArray' for instance produces an 'addr' but this is harmless:
# namely toOpenArray(a, 1, 3)
gen(p, n, r)
#internalError(p.config, n.info, "genAddr: 4 " & renderTree(n))
else: internalError(p.config, n.info, $("genAddr: 2", s.kind))
proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
if n.kind == nkSym:
genSymAddr(p, n, nil, r)
else:
case n[0].kind
of nkSym:
genSymAddr(p, n[0], n.typ, r)
of nkCheckedFieldExpr:
genCheckedFieldOp(p, n[0], n.typ, r)
of nkDotExpr:
if mapType(p, n.typ) == etyBaseIndex:
genFieldAddr(p, n[0], r)
else:
genFieldAccess(p, n[0], r)
of nkBracketExpr:
var ty = skipTypes(n[0].typ, abstractVarRange)
if ty.kind in MappedToObject:
gen(p, n[0], r)
else:
let kindOfIndexedExpr = skipTypes(n[0][0].typ, abstractVarRange).kind
case kindOfIndexedExpr
of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs:
genArrayAddr(p, n[0], r)
of tyTuple:
genFieldAddr(p, n[0], r)
of tyGenericBody:
genAddr(p, n[^1], r)
else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
of nkObjDownConv:
gen(p, n[0], r)
of nkHiddenDeref:
gen(p, n[0], r)
of nkHiddenAddr:
gen(p, n[0], r)
of nkConv:
genAddr(p, n[0], r)
of nkStmtListExpr:
if n.len == 1: gen(p, n[0], r)
else: internalError(p.config, n[0].info, "genAddr for complex nkStmtListExpr")
of nkCallKinds:
if n[0].typ.kind == tyOpenArray:
# 'var openArray' for instance produces an 'addr' but this is harmless:
# namely toOpenArray(a, 1, 3)
gen(p, n[0], r)
else:
internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
else:
internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
else:
internalError(p.config, n[0].info, "genAddr: " & $n[0].kind)
proc attachProc(p: PProc; content: Rope; s: PSym) =
p.g.code.add(content)
@@ -1438,7 +1451,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
s.name.s)
discard mangleName(p.module, s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate} or
if lfNoDecl in s.loc.flags or s.magic notin generatedMagics or
{sfImportc, sfInfixCall} * s.flags != {}:
discard
elif s.kind == skMethod and getBody(p.module.graph, s).kind == nkEmpty:
@@ -2089,6 +2102,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n[1], x)
useMagic(p, "nimCopy")
r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)]
of mOpenArrayToSeq:
genCall(p, n, r)
of mDestroy, mTrace: discard "ignore calls to the default destructor"
of mOrd: genOrd(p, n, r)
of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
@@ -2393,17 +2408,18 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
if prc.typ[0] != nil and sfPure notin prc.flags:
resultSym = prc.ast[resultPos].sym
let mname = mangleName(p.module, resultSym)
let returnAddress = not isIndirect(resultSym) and
# otherwise uses "fat pointers"
let useRawPointer = not isIndirect(resultSym) and
resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and
mapType(p, resultSym.typ) == etyBaseIndex
if returnAddress:
if useRawPointer:
resultAsgn = p.indentLine(("var $# = null;$n") % [mname])
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
else:
let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar])
gen(p, prc.ast[resultPos], a)
if returnAddress:
if mapType(p, resultSym.typ) == etyBaseIndex:
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
else:
returnStmt = "return $#;$n" % [a.res]
@@ -2604,7 +2620,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
let s = n[namePos].sym
discard mangleName(p.module, s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate}: discard
if lfNoDecl in s.loc.flags or s.magic notin generatedMagics: discard
elif not p.g.generatedSyms.containsOrIncl(s.id):
p.locals.add(genProc(p, s))
of nkType: r.res = genTypeInfo(p, n.typ)
@@ -2711,7 +2727,7 @@ proc genModule(p: PProc, n: PNode) =
if p.config.hcrOn and n.kind == nkStmtList:
let moduleSym = p.module.module
var moduleLoadedVar = rope(moduleSym.name.s) & "_loaded" &
idOrSig(moduleSym, moduleSym.name.s, p.module.sigConflicts)
idOrSig(moduleSym, moduleSym.name.s, p.module.sigConflicts, p.config)
lineF(p, "var $1;$n", [moduleLoadedVar])
var inGuardedBlock = false

View File

@@ -298,6 +298,7 @@ type
processed, capturedVars: IntSet
ownerToType: Table[int, PType]
somethingToDo: bool
inTypeOf: bool
graph: ModuleGraph
idgen: IdGenerator
@@ -401,6 +402,9 @@ 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
@@ -437,7 +441,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
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})
@@ -446,7 +451,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 s.typ.callConv == ccClosure) or interestingVar(s):
elif (innerProc and not s.isIterator and s.typ.callConv == ccClosure) or interestingVar(s):
discard """
proc outer() =
var x: int
@@ -463,10 +468,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:
@@ -498,9 +505,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
@@ -780,6 +792,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:

View File

@@ -551,11 +551,15 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
if not preventComment:
emitComment(em, tok, dontIndent = false)
of tkIntLit..tkStrLit, tkRStrLit, tkTripleStrLit, tkGStrLit, tkGTripleStrLit, tkCharLit:
let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB)
if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wrSpace(em)
em.lineSpan = countNewlines(lit)
if em.lineSpan > 0: calcCol(em, lit)
wr em, lit, ltLit
if not em.inquote:
let lit = fileSection(em.config, em.fid, tok.offsetA, tok.offsetB)
if endsInAlpha(em) and tok.tokType notin {tkGStrLit, tkGTripleStrLit}: wrSpace(em)
em.lineSpan = countNewlines(lit)
if em.lineSpan > 0: calcCol(em, lit)
wr em, lit, ltLit
else:
if endsInAlpha(em): wrSpace(em)
wr em, tok.literal, ltLit
of tkEof: discard
else:
let lit = if tok.ident != nil: tok.ident.s else: tok.literal

View File

@@ -121,6 +121,8 @@ type
cache*: IdentCache
when defined(nimsuggest):
previousToken: TLineInfo
tokenEnd*: TLineInfo
previousTokenEnd*: TLineInfo
config*: ConfigRef
proc getLineInfo*(L: Lexer, tok: Token): TLineInfo {.inline.} =
@@ -912,7 +914,7 @@ proc getSymbol(L: var Lexer, tok: var Token) =
else: break
tokenEnd(tok, pos-1)
h = !$h
tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
tok.ident = L.cache.getIdent(cast[cstring](addr(L.buf[L.bufpos])), pos - L.bufpos, h)
if (tok.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
(tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
tok.tokType = tkSymbol
@@ -926,7 +928,7 @@ proc getSymbol(L: var Lexer, tok: var Token) =
proc endOperator(L: var Lexer, tok: var Token, pos: int,
hash: Hash) {.inline.} =
var h = !$hash
tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
tok.ident = L.cache.getIdent(cast[cstring](addr(L.buf[L.bufpos])), pos - L.bufpos, h)
if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr
else: tok.tokType = TokType(tok.ident.id - oprLow + ord(tkColon))
L.bufpos = pos
@@ -1216,6 +1218,10 @@ proc skip(L: var Lexer, tok: var Token) =
proc rawGetTok*(L: var Lexer, tok: var Token) =
template atTokenEnd() {.dirty.} =
when defined(nimsuggest):
L.previousTokenEnd.line = L.tokenEnd.line
L.previousTokenEnd.col = L.tokenEnd.col
L.tokenEnd.line = tok.line.uint16
L.tokenEnd.col = getColNumber(L, L.bufpos).int16
# we attach the cursor to the last *strong* token
if tok.tokType notin weakTokens:
L.previousToken.line = tok.line.uint16

View File

@@ -518,7 +518,7 @@ 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)
@@ -528,7 +528,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# operation here:
var t = t
if t.assignment == nil or t.destructor == nil:
let h = sighashes.hashType(t, {CoType, CoConsiderOwned, CoDistinct})
let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct})
let canon = c.g.canonTypes.getOrDefault(h)
if canon != nil: t = canon
@@ -553,7 +553,7 @@ 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
@@ -574,9 +574,9 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedTrace:
discard "strings are atomic and have no inner elements that are to trace"
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
@@ -604,7 +604,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 tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
@@ -929,7 +929,7 @@ 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)
cycleParam.typ = getSysType(g, info, tyBool)
@@ -1072,7 +1072,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
let h = sighashes.hashType(skipped, {CoType, CoConsiderOwned, CoDistinct})
let h = sighashes.hashType(skipped, g.config, {CoType, CoConsiderOwned, CoDistinct})
var canon = g.canonTypes.getOrDefault(h)
if canon == nil:
g.canonTypes[h] = skipped

View File

@@ -76,7 +76,10 @@ type
warnAnyEnumConv = "AnyEnumConv",
warnHoleEnumConv = "HoleEnumConv",
warnCstringConv = "CStringConv",
warnPtrToCstringConv = "PtrToCstringConv",
warnEffect = "Effect",
warnBareExcept = "BareExcept",
warnCastSizes = "CastSizes"
warnUser = "User",
# hints
hintSuccess = "Success", hintSuccessX = "SuccessX",
@@ -166,7 +169,10 @@ const
warnAnyEnumConv: "$1",
warnHoleEnumConv: "$1",
warnCstringConv: "$1",
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
warnEffect: "$1",
warnBareExcept: "$1",
warnCastSizes: "$1",
warnUser: "$1",
hintSuccess: "operation successful: $#",
# keep in sync with `testament.isSuccess`
@@ -221,7 +227,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, warnUninit, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
result[1] = result[2] - {warnProveField, warnProveIndex,
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,

View File

@@ -93,8 +93,9 @@ proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind) =
## Check symbol definitions adhere to NEP1 style rules.
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
@@ -135,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
@@ -146,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,10 +8,10 @@
#
# This module implements lookup helpers.
import std/[algorithm, strutils]
import std/[algorithm, strutils, tables]
import
intsets, ast, astalgo, idents, semdata, types, msgs, options,
renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs
renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs, wordrecg
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
@@ -44,6 +44,11 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent =
case x.kind
of nkIdent: id.add(x.ident.s)
of nkSym: id.add(x.sym.name.s)
of nkSymChoices:
if x[0].kind == nkSym:
id.add(x[0].sym.name.s)
else:
handleError(n, origin)
of nkLiterals - nkFloatLiterals: id.add(x.renderTree)
else: handleError(n, origin)
result = getIdent(c.cache, id)
@@ -306,13 +311,15 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string;
proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) =
let conflict = scope.addUniqueSym(sym)
if conflict != nil:
if sym.kind == skModule and conflict.kind == skModule and sym.owner == conflict.owner:
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)
@@ -415,7 +422,7 @@ type SpellCandidate = object
msg: string
sym: PSym
template toOrderTup(a: SpellCandidate): auto =
template toOrderTup(a: SpellCandidate): (int, int, string) =
# `dist` is first, to favor nearby matches
# `depth` is next, to favor nearby enclosing scopes among ties
# `sym.name.s` is last, to make the list ordered and deterministic among ties
@@ -486,17 +493,24 @@ proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) =
var amb: bool
discard errorUseQualifier(c, info, s, amb)
proc errorUseQualifier(c: PContext; info: TLineInfo; candidates: seq[PSym]) =
proc errorUseQualifier(c: PContext; info: TLineInfo; candidates: seq[PSym]; prefix = "use one of") =
var err = "ambiguous identifier: '" & candidates[0].name.s & "'"
var i = 0
for candidate in candidates:
if i == 0: err.add " -- use one of the following:\n"
if i == 0: err.add " -- $1 the following:\n" % prefix
else: err.add "\n"
err.add " " & candidate.owner.name.s & "." & candidate.name.s
err.add ": " & typeToString(candidate.typ)
inc i
localError(c.config, info, errGenerated, err)
proc errorUseQualifier*(c: PContext; info:TLineInfo; choices: PNode) =
var candidates = newSeq[PSym](choices.len)
let prefix = if choices[0].typ.kind != tyProc: "use one of" else: "you need a helper proc to disambiguate"
for i, n in choices:
candidates[i] = n.sym
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:
@@ -581,11 +595,18 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
if m == c.module:
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config)
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).skipAlias(n, c.config)
if result == nil and checkUndeclared in flags:
result = errorUndeclaredIdentifierHint(c, n[1], ident)
elif n[1].kind == nkSym:
result = n[1].sym
if result.owner != nil and result.owner != m and checkUndeclared in flags:
# dotExpr in templates can end up here
result = errorUndeclaredIdentifierHint(c, n[1], considerQuotedIdent(c, n[1]))
elif checkUndeclared in flags and
n[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
localError(c.config, n[1].info, "identifier expected, but got: " &

View File

@@ -129,7 +129,7 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; o
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
vpart[0] = tempAsNode
vpart[1] = newNodeI(nkEmpty, value.info)
vpart[1] = newNodeI(nkTupleClassTy, value.info)
vpart[2] = value
v.add vpart
result.add(v)
@@ -235,10 +235,14 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
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
field.flags = s.flags * {sfCursor}
# sfNoInit flag for skField is used in closureiterator codegen
field.flags = s.flags * {sfCursor, sfNoInit}
obj.n.add newSymNode(field)
fieldCheck()
result = field

View File

@@ -53,6 +53,7 @@ type
SymInfoPair* = object
sym*: PSym
info*: TLineInfo
isDecl*: bool
ModuleGraph* {.acyclic.} = ref object
ifaces*: seq[Iface] ## indexed by int32 fileIdx
@@ -645,11 +646,11 @@ proc `==`*(a, b: SymInfoPair): bool =
result = a.sym == b.sym and a.info.exactEquals(b.info)
proc fileSymbols*(graph: ModuleGraph, fileIdx: FileIndex): seq[SymInfoPair] =
result = graph.suggestSymbols.getOrDefault(fileIdx, @[]).deduplicate
result = graph.suggestSymbols.getOrDefault(fileIdx, @[])
iterator suggestSymbolsIter*(g: ModuleGraph): SymInfoPair =
for xs in g.suggestSymbols.values:
for x in xs.deduplicate:
for x in xs:
yield x
iterator suggestErrorsIter*(g: ModuleGraph): Suggest =

View File

@@ -36,11 +36,14 @@ 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 == nkIdent and n0.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 = ""
of nkPrefix:
when false:
if n[0].kind == nkIdent and n[0].ident.s == "$":

View File

@@ -123,6 +123,13 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
var dummy: bool
result = fileInfoIdx(conf, filename, dummy)
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile; isKnownFile: var bool): FileIndex =
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), isKnownFile)
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex =
var dummy: bool
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
result.fileIndex = fileInfoIdx
if line < int high(uint16):
@@ -407,17 +414,21 @@ To create a stacktrace, rerun compilation with './koch temp $1 <file>', see $2 f
[conf.command, "intern.html#debugging-the-compiler".createDocLink], conf.unitSep)
quit 1
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) =
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):
(msg in warnMin..hintMax and msg in conf.warningAsErrors and not ignoreMsg):
inc(conf.errorCounter)
conf.exitcode = 1'i8
if conf.errorCounter >= conf.errorMax:
# only really quit when we're not in the new 'nim check --def' mode:
if conf.ideCmd == ideNone:
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)
@@ -520,8 +531,7 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
of warnMin..warnMax:
sev = Severity.Warning
ignoreMsg = not conf.hasWarn(msg)
if msg in conf.warningAsErrors:
ignoreMsg = false
if not ignoreMsg and msg in conf.warningAsErrors:
title = ErrorTitle
else:
title = WarningTitle
@@ -531,8 +541,7 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
of hintMin..hintMax:
sev = Severity.Hint
ignoreMsg = not conf.hasHint(msg)
if msg in conf.warningAsErrors:
ignoreMsg = false
if not ignoreMsg and msg in conf.warningAsErrors:
title = ErrorTitle
else:
title = HintTitle
@@ -558,7 +567,7 @@ 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)
handleError(conf, msg, eh, s, ignoreMsg)
if msg in fatalMsgs:
# most likely would have died here but just in case, we restore state
conf.m.errorOutputs = errorOutputsOld

View File

@@ -37,6 +37,15 @@ when defined(profiler) or defined(memProfiler):
{.hint: "Profiling support is turned on!".}
import nimprof
proc nimbleLockExists(config: ConfigRef): bool =
const nimbleLock = "nimble.lock"
let pd = if not config.projectPath.isEmpty: config.projectPath else: AbsoluteDir(getCurrentDir())
if optSkipParentConfigFiles notin config.globalOptions:
for dir in parentDirs(pd.string, fromRoot=true, inclusive=false):
if fileExists(dir / nimbleLock):
return true
return fileExists(pd.string / nimbleLock)
proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
var p = parseopt.initOptParser(cmd)
var argsCount = 0
@@ -70,6 +79,11 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
config.arguments.len > 0 and config.cmd notin {cmdTcc, cmdNimscript, cmdCrun}:
rawMessage(config, errGenerated, errArgsNeedRunOption)
if config.nimbleLockExists:
# disable nimble path if nimble.lock is present.
# see https://github.com/nim-lang/nimble/issues/1004
disableNimblePath(config)
proc getNimRunExe(conf: ConfigRef): string =
# xxx consider defining `conf.getConfigVar("nimrun.exe")` to allow users to
# customize the binary to run the command with, e.g. for custom `nodejs` or `wine`.

View File

@@ -12,7 +12,9 @@ import
ast, astalgo, modules, passes, condsyms,
options, sem, llstream, lineinfos, vm,
vmdef, modulegraphs, idents, os, pathutils,
passaux, scriptconfig, std/compilesettings
passaux,
scriptconfig, std/[compilesettings, tables]
type
Interpreter* = ref object ## Use Nim as an interpreter with this object
@@ -72,6 +74,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

@@ -19,7 +19,7 @@ const
useEffectSystem* = true
useWriteTracking* = false
hasFFI* = defined(nimHasLibFFI)
copyrightYear* = "2021"
copyrightYear* = "2023"
nimEnableCovariance* = defined(nimEnableCovariance)
@@ -185,7 +185,7 @@ type
IdeCmd* = enum
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod,
ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols,
ideRecompile, ideChanged, ideType
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand, ideInlayHints
Feature* = enum ## experimental features; DO NOT RENAME THESE!
implicitDeref,
@@ -264,8 +264,26 @@ type
scope*, localUsages*, globalUsages*: int # more usages is better
tokenLen*: int
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
@@ -394,6 +412,13 @@ type
nimMainPrefix*: string
vmProfileData*: ProfileData
expandProgress*: bool
expandLevels*: int
expandNodeResult*: string
expandPosition*: TLineInfo
clientProcessId*: int
proc parseNimVersion*(a: string): NimVer =
# could be moved somewhere reusable
if a.len > 0:
@@ -981,6 +1006,9 @@ proc isDynlibOverride*(conf: ConfigRef; lib: string): bool =
result = optDynlibOverrideAll in conf.globalOptions or
conf.dllOverrides.hasKey(lib.canonDynlibName)
proc expandDone*(conf: ConfigRef): bool =
result = conf.ideCmd == ideExpand and conf.expandLevels == 0 and conf.expandProgress
proc parseIdeCmd*(s: string): IdeCmd =
case s:
of "sug": ideSug
@@ -1019,9 +1047,12 @@ proc `$`*(c: IdeCmd): string =
of ideMsg: "msg"
of ideProject: "project"
of ideGlobalSymbols: "globalSymbols"
of ideDeclaration: "declaration"
of ideExpand: "expand"
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

@@ -331,6 +331,12 @@ proc colcom(p: var Parser, n: PNode) =
const tkBuiltInMagics = {tkType, tkStatic, tkAddr}
template setEndInfo() =
when defined(nimsuggest):
result.endInfo = TLineInfo(fileIndex: p.lex.fileIdx,
line: p.lex.previousTokenEnd.line,
col: p.lex.previousTokenEnd.col)
proc parseSymbol(p: var Parser, mode = smNormal): PNode =
#| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
#| | IDENT | KEYW
@@ -383,6 +389,7 @@ proc parseSymbol(p: var Parser, mode = smNormal): PNode =
# if it is a keyword:
#if not isKeyword(p.tok.tokType): getTok(p)
result = p.emptyNode
setEndInfo()
proc colonOrEquals(p: var Parser, a: PNode): PNode =
if p.tok.tokType == tkColon:
@@ -416,6 +423,24 @@ proc exprList(p: var Parser, endTok: TokType, result: PNode) =
getTok(p)
optInd(p, result)
# progress guaranteed
var a = parseExpr(p)
result.add(a)
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
var a = parseExpr(p)
result.add(a)
when defined(nimpretty):
dec p.em.doIndentMore
proc optionalExprList(p: var Parser, endTok: TokType, result: PNode) =
#| optionalExprList = expr ^* comma
when defined(nimpretty):
inc p.em.doIndentMore
getTok(p)
optInd(p, result)
# progress guaranteed
while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
var a = parseExpr(p)
result.add(a)
@@ -524,6 +549,7 @@ proc parseCast(p: var Parser): PNode =
result.add(exprColonEqExpr(p))
optPar(p)
eat(p, tkParRi)
setEndInfo()
proc setBaseFlags(n: PNode, base: NumericalBase) =
case base
@@ -546,6 +572,7 @@ proc parseGStrLit(p: var Parser, a: PNode): PNode =
getTok(p)
else:
result = a
setEndInfo()
proc complexOrSimpleStmt(p: var Parser): PNode
proc simpleExpr(p: var Parser, mode = pmNormal): PNode
@@ -650,6 +677,7 @@ proc parsePar(p: var Parser): PNode =
skipComment(p, a)
optPar(p)
eat(p, tkParRi)
setEndInfo()
proc identOrLiteral(p: var Parser, mode: PrimaryMode): PNode =
#| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
@@ -896,6 +924,7 @@ proc parseOperators(p: var Parser, headNode: PNode,
a.add(b)
result = a
opPrec = getPrecedence(p.tok)
setEndInfo()
proc simpleExprAux(p: var Parser, limit: int, mode: PrimaryMode): PNode =
result = primary(p, mode)
@@ -942,6 +971,7 @@ proc parsePragma(p: var Parser): PNode =
when defined(nimpretty):
dec p.em.doIndentMore
dec p.em.keepIndents
setEndInfo()
proc identVis(p: var Parser; allowDot=false): PNode =
#| identVis = symbol OPR? # postfix position
@@ -1010,6 +1040,7 @@ proc parseIdentColonEquals(p: var Parser, flags: DeclaredIdentFlags): PNode =
result.add(parseExpr(p))
else:
result.add(newNodeP(nkEmpty, p))
setEndInfo()
proc parseTuple(p: var Parser, indentAllowed = false): PNode =
#| tupleDecl = 'tuple'
@@ -1053,6 +1084,7 @@ proc parseTuple(p: var Parser, indentAllowed = false): PNode =
parMessage(p, errGenerated, "the syntax for tuple types is 'tuple[...]', not 'tuple(...)'")
else:
result = newNodeP(nkTupleClassTy, p)
setEndInfo()
proc parseParamList(p: var Parser, retColon = true): PNode =
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
@@ -1101,6 +1133,7 @@ proc parseParamList(p: var Parser, retColon = true): PNode =
when defined(nimpretty):
dec p.em.doIndentMore
dec p.em.keepIndents
setEndInfo()
proc optPragmas(p: var Parser): PNode =
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
@@ -1110,20 +1143,23 @@ proc optPragmas(p: var Parser): PNode =
proc parseDoBlock(p: var Parser; info: TLineInfo): PNode =
#| doBlock = 'do' paramListArrow pragma? colcom stmt
let params = parseParamList(p, retColon=false)
var params = parseParamList(p, retColon=false)
let pragmas = optPragmas(p)
colcom(p, result)
result = parseStmt(p)
if params.kind != nkEmpty:
if params.kind != nkEmpty or pragmas.kind != nkEmpty:
if params.kind == nkEmpty:
params = newNodeP(nkFormalParams, p)
params.add(p.emptyNode) # return type
result = newProcNode(nkDo, info,
body = result, params = params, name = p.emptyNode, pattern = p.emptyNode,
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
setEndInfo()
proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode =
#| routineExpr = ('proc' | 'func' | 'iterator') paramListColon pragma? ('=' COMMENT? stmt)?
# either a proc type or a anonymous proc
let info = parLineInfo(p)
getTok(p)
let hasSignature = p.tok.tokType in {tkParLe, tkColon} and p.tok.indent < 0
let params = parseParamList(p)
let pragmas = optPragmas(p)
@@ -1134,19 +1170,20 @@ proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode =
params = params, name = p.emptyNode, pattern = p.emptyNode,
genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode)
else:
result = newNodeI(nkProcTy, info)
result = newNodeI(if kind == nkIteratorDef: nkIteratorTy else: nkProcTy, info)
if hasSignature:
result.add(params)
if kind == nkFuncDef:
parMessage(p, "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead")
result.add(pragmas)
setEndInfo()
proc isExprStart(p: Parser): bool =
case p.tok.tokType
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkFor,
tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCustomLit, tkVar, tkRef, tkPtr,
tkTuple, tkObject, tkWhen, tkCase, tkOut:
tkTuple, tkObject, tkWhen, tkCase, tkOut, tkTry, tkBlock:
result = true
else: result = false
@@ -1159,6 +1196,7 @@ proc parseSymbolList(p: var Parser, result: PNode) =
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, s)
setEndInfo()
proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
mode: PrimaryMode): PNode =
@@ -1181,6 +1219,7 @@ proc parseTypeDescKAux(p: var Parser, kind: TNodeKind,
let list = newNodeP(nodeKind, p)
result.add list
parseSymbolList(p, list)
setEndInfo()
proc parseVarTuple(p: var Parser): PNode
@@ -1206,6 +1245,7 @@ proc parseFor(p: var Parser): PNode =
result.add(parseExpr(p))
colcom(p, result)
result.add(parseStmt(p))
setEndInfo()
template nimprettyDontTouch(body) =
when defined(nimpretty):
@@ -1244,6 +1284,7 @@ proc parseExpr(p: var Parser): PNode =
nimprettyDontTouch:
result = parseTry(p, isExpr=true)
else: result = simpleExpr(p)
setEndInfo()
proc parseEnum(p: var Parser): PNode
proc parseObject(p: var Parser): PNode
@@ -1275,12 +1316,15 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode =
case p.tok.tokType
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda)
of tkFunc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkFuncDef)
of tkIterator:
of tkProc:
getTok(p)
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda)
if result.kind == nkLambda: result.transitionSonsKind(nkIteratorDef)
else: result.transitionSonsKind(nkIteratorTy)
of tkFunc:
getTok(p)
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkFuncDef)
of tkIterator:
getTok(p)
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkIteratorDef)
of tkEnum:
if mode == pmTypeDef:
prettySection:
@@ -1337,11 +1381,13 @@ proc parseTypeDesc(p: var Parser): PNode =
newlineWasSplitting(p)
result = simpleExpr(p, pmTypeDesc)
result = binaryNot(p, result)
setEndInfo()
proc parseTypeDefAux(p: var Parser): PNode =
#| typeDefAux = simpleExpr ('not' expr)?
result = simpleExpr(p, pmTypeDef)
result = binaryNot(p, result)
setEndInfo()
proc makeCall(n: PNode): PNode =
## Creates a call if the given node isn't already a call.
@@ -1355,7 +1401,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
#| postExprBlocks = ':' stmt? ( IND{=} doBlock
#| | IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt
#| | IND{=} 'except' optionalExprList ':' stmt
#| | IND{=} 'finally' ':' stmt
#| | IND{=} 'else' ':' stmt )*
result = x
@@ -1381,7 +1427,10 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
if stmtList[0].kind == nkStmtList: stmtList = stmtList[0]
stmtList.flags.incl nfBlockArg
if openingParams.kind != nkEmpty:
if openingParams.kind != nkEmpty or openingPragmas.kind != nkEmpty:
if openingParams.kind == nkEmpty:
openingParams = newNodeP(nkFormalParams, p)
openingParams.add(p.emptyNode) # return type
result.add newProcNode(nkDo, stmtList.info, body = stmtList,
params = openingParams,
name = p.emptyNode, pattern = p.emptyNode,
@@ -1410,7 +1459,7 @@ proc postExprBlocks(p: var Parser, x: PNode): PNode =
nextBlock.add parseExpr(p)
of tkExcept:
nextBlock = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, nextBlock)
optionalExprList(p, tkColon, nextBlock)
of tkFinally:
nextBlock = newNodeP(nkFinally, p)
getTok(p)
@@ -1464,6 +1513,7 @@ proc parseExprStmt(p: var Parser): PNode =
else:
result = a
result = postExprBlocks(p, result)
setEndInfo()
proc parseModuleName(p: var Parser, kind: TNodeKind): PNode =
result = parseExpr(p)
@@ -1475,6 +1525,7 @@ proc parseModuleName(p: var Parser, kind: TNodeKind): PNode =
getTok(p)
result.add(a)
result.add(parseExpr(p))
setEndInfo()
proc parseImport(p: var Parser, kind: TNodeKind): PNode =
#| importStmt = 'import' optInd expr
@@ -1503,6 +1554,7 @@ proc parseImport(p: var Parser, kind: TNodeKind): PNode =
getTok(p)
optInd(p, a)
#expectNl(p)
setEndInfo()
proc parseIncludeStmt(p: var Parser): PNode =
#| includeStmt = 'include' optInd expr ^+ comma
@@ -1519,6 +1571,7 @@ proc parseIncludeStmt(p: var Parser): PNode =
getTok(p)
optInd(p, a)
#expectNl(p)
setEndInfo()
proc parseFromStmt(p: var Parser): PNode =
#| fromStmt = 'from' expr 'import' optInd expr (comma expr)*
@@ -1539,6 +1592,7 @@ proc parseFromStmt(p: var Parser): PNode =
getTok(p)
optInd(p, a)
#expectNl(p)
setEndInfo()
proc parseReturnOrRaise(p: var Parser, kind: TNodeKind): PNode =
#| returnStmt = 'return' optInd expr?
@@ -1560,6 +1614,7 @@ proc parseReturnOrRaise(p: var Parser, kind: TNodeKind): PNode =
var e = parseExpr(p)
e = postExprBlocks(p, e)
result.add(e)
setEndInfo()
proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode =
#| condStmt = expr colcom stmt COMMENT?
@@ -1584,6 +1639,7 @@ proc parseIfOrWhen(p: var Parser, kind: TNodeKind): PNode =
colcom(p, branch)
branch.add(parseStmt(p))
result.add(branch)
setEndInfo()
proc parseIfOrWhenExpr(p: var Parser, kind: TNodeKind): PNode =
#| condExpr = expr colcom expr optInd
@@ -1608,6 +1664,7 @@ proc parseIfOrWhenExpr(p: var Parser, kind: TNodeKind): PNode =
colcom(p, branch)
branch.add(parseStmt(p))
result.add(branch)
setEndInfo()
proc parseWhile(p: var Parser): PNode =
#| whileStmt = 'while' expr colcom stmt
@@ -1617,6 +1674,7 @@ proc parseWhile(p: var Parser): PNode =
result.add(parseExpr(p))
colcom(p, result)
result.add(parseStmt(p))
setEndInfo()
proc parseCase(p: var Parser): PNode =
#| ofBranch = 'of' exprList colcom stmt
@@ -1664,13 +1722,14 @@ proc parseCase(p: var Parser): PNode =
if wasIndented:
p.currInd = oldInd
setEndInfo()
proc parseTry(p: var Parser; isExpr: bool): PNode =
#| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
#| (IND{=}? 'except' exprList colcom stmt)*
#| (IND{=}? 'except' optionalExprList colcom stmt)*
#| (IND{=}? 'finally' colcom stmt)?
#| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
#| (optInd 'except' exprList colcom stmt)*
#| (optInd 'except' optionalExprList colcom stmt)*
#| (optInd 'finally' colcom stmt)?
result = newNodeP(nkTryStmt, p)
getTok(p)
@@ -1681,7 +1740,7 @@ proc parseTry(p: var Parser; isExpr: bool): PNode =
case p.tok.tokType
of tkExcept:
b = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, b)
optionalExprList(p, tkColon, b)
of tkFinally:
b = newNodeP(nkFinally, p)
getTok(p)
@@ -1690,12 +1749,14 @@ proc parseTry(p: var Parser; isExpr: bool): PNode =
b.add(parseStmt(p))
result.add(b)
if b == nil: parMessage(p, "expected 'except'")
setEndInfo()
proc parseExceptBlock(p: var Parser, kind: TNodeKind): PNode =
result = newNodeP(kind, p)
getTok(p)
colcom(p, result)
result.add(parseStmt(p))
setEndInfo()
proc parseBlock(p: var Parser): PNode =
#| blockStmt = 'block' symbol? colcom stmt
@@ -1706,6 +1767,7 @@ proc parseBlock(p: var Parser): PNode =
else: result.add(parseSymbol(p))
colcom(p, result)
result.add(parseStmt(p))
setEndInfo()
proc parseStaticOrDefer(p: var Parser; k: TNodeKind): PNode =
#| staticStmt = 'static' colcom stmt
@@ -1714,6 +1776,7 @@ proc parseStaticOrDefer(p: var Parser; k: TNodeKind): PNode =
getTok(p)
colcom(p, result)
result.add(parseStmt(p))
setEndInfo()
proc parseAsm(p: var Parser): PNode =
#| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
@@ -1730,6 +1793,7 @@ proc parseAsm(p: var Parser): PNode =
result.add(p.emptyNode)
return
getTok(p)
setEndInfo()
proc parseGenericParam(p: var Parser): PNode =
#| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
@@ -1765,6 +1829,7 @@ proc parseGenericParam(p: var Parser): PNode =
result.add(parseExpr(p))
else:
result.add(p.emptyNode)
setEndInfo()
proc parseGenericParamList(p: var Parser): PNode =
#| genericParamList = '[' optInd
@@ -1783,12 +1848,14 @@ proc parseGenericParamList(p: var Parser): PNode =
skipComment(p, a)
optPar(p)
eat(p, tkBracketRi)
setEndInfo()
proc parsePattern(p: var Parser): PNode =
#| pattern = '{' stmt '}'
eat(p, tkCurlyLe)
result = parseStmt(p)
eat(p, tkCurlyRi)
setEndInfo()
proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
#| indAndComment = (IND{>} COMMENT)? | COMMENT?
@@ -1797,6 +1864,12 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
result = newNodeP(kind, p)
getTok(p)
optInd(p, result)
if kind in {nkProcDef, nkLambda, nkIteratorDef, nkFuncDef} and
p.tok.tokType notin {tkSymbol, tokKeywordLow..tokKeywordHigh, tkAccent}:
# no name; lambda or proc type
# in every context that we can parse a routine, we can also parse these
result = parseProcExpr(p, true, if kind == nkProcDef: nkLambda else: kind)
return
result.add(identVis(p))
if p.tok.tokType == tkCurlyLe and p.validInd: result.add(p.parsePattern)
else: result.add(p.emptyNode)
@@ -1827,6 +1900,7 @@ proc parseRoutine(p: var Parser, kind: TNodeKind): PNode =
#else:
# assert false, p.lex.config$body.info # avoids hard to track bugs, fail early.
# Yeah, that worked so well. There IS a bug in this logic, now what?
setEndInfo()
proc newCommentStmt(p: var Parser): PNode =
#| commentStmt = COMMENT
@@ -1862,6 +1936,7 @@ proc parseSection(p: var Parser, kind: TNodeKind,
result.add(defparser(p))
else:
parMessage(p, errIdentifierExpected, p.tok)
setEndInfo()
proc parseEnum(p: var Parser): PNode =
#| enumDecl = 'enum' optInd (symbol pragma? optInd ('=' optInd expr COMMENT?)? comma?)+
@@ -1908,6 +1983,7 @@ proc parseEnum(p: var Parser): PNode =
break
if result.len <= 1:
parMessage(p, errIdentifierExpected, p.tok)
setEndInfo()
proc parseObjectPart(p: var Parser): PNode
proc parseObjectWhen(p: var Parser): PNode =
@@ -1933,6 +2009,7 @@ proc parseObjectWhen(p: var Parser): PNode =
branch.add(parseObjectPart(p))
flexComment(p, branch)
result.add(branch)
setEndInfo()
proc parseObjectCase(p: var Parser): PNode =
#| objectBranch = 'of' exprList colcom objectPart
@@ -1978,6 +2055,7 @@ proc parseObjectCase(p: var Parser): PNode =
if b.kind == nkElse: break
if wasIndented:
p.currInd = oldInd
setEndInfo()
proc parseObjectPart(p: var Parser): PNode =
#| objectPart = IND{>} objectPart^+IND{=} DED
@@ -2010,6 +2088,7 @@ proc parseObjectPart(p: var Parser): PNode =
result = p.emptyNode
else:
result = p.emptyNode
setEndInfo()
proc parseObject(p: var Parser): PNode =
#| objectDecl = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
@@ -2035,6 +2114,7 @@ proc parseObject(p: var Parser): PNode =
result.add(p.emptyNode)
else:
result.add(parseObjectPart(p))
setEndInfo()
proc parseTypeClassParam(p: var Parser): PNode =
let modifier =
@@ -2052,6 +2132,7 @@ proc parseTypeClassParam(p: var Parser): PNode =
result.add(p.parseSymbol)
else:
result = p.parseSymbol
setEndInfo()
proc parseTypeClass(p: var Parser): PNode =
#| conceptParam = ('var' | 'out')? symbol
@@ -2095,6 +2176,7 @@ proc parseTypeClass(p: var Parser): PNode =
result.add(p.emptyNode)
else:
result.add(parseStmt(p))
setEndInfo()
proc parseTypeDef(p: var Parser): PNode =
#|
@@ -2143,6 +2225,7 @@ proc parseTypeDef(p: var Parser): PNode =
else:
result.add(p.emptyNode)
indAndComment(p, result) # special extension!
setEndInfo()
proc parseVarTuple(p: var Parser): PNode =
#| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
@@ -2159,6 +2242,7 @@ proc parseVarTuple(p: var Parser): PNode =
result.add(p.emptyNode) # no type desc
optPar(p)
eat(p, tkParRi)
setEndInfo()
proc parseVariable(p: var Parser): PNode =
#| colonBody = colcom stmt postExprBlocks?
@@ -2171,6 +2255,7 @@ proc parseVariable(p: var Parser): PNode =
else: result = parseIdentColonEquals(p, {withPragma, withDot})
result[^1] = postExprBlocks(p, result[^1])
indAndComment(p, result)
setEndInfo()
proc parseConstant(p: var Parser): PNode =
#| constant = (varTuple / identWithPragma) (colon typeDesc)? '=' optInd expr indAndComment
@@ -2190,6 +2275,7 @@ proc parseConstant(p: var Parser): PNode =
result.add(parseExpr(p))
result[^1] = postExprBlocks(p, result[^1])
indAndComment(p, result)
setEndInfo()
proc parseBind(p: var Parser, k: TNodeKind): PNode =
#| bindStmt = 'bind' optInd qualifiedIdent ^+ comma
@@ -2205,6 +2291,7 @@ proc parseBind(p: var Parser, k: TNodeKind): PNode =
getTok(p)
optInd(p, a)
#expectNl(p)
setEndInfo()
proc parseStmtPragma(p: var Parser): PNode =
#| pragmaStmt = pragma (':' COMMENT? stmt)?
@@ -2216,6 +2303,7 @@ proc parseStmtPragma(p: var Parser): PNode =
skipComment(p, result)
result.add a
result.add parseStmt(p)
setEndInfo()
proc simpleStmt(p: var Parser): PNode =
#| simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt
@@ -2358,6 +2446,7 @@ proc parseStmt(p: var Parser): PNode =
if p.tok.tokType != tkSemiColon: break
getTok(p)
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.
@@ -2373,6 +2462,7 @@ proc parseAll(p: var Parser): PNode =
getTok(p)
if p.tok.indent != 0:
parMessage(p, errInvalidIndentation)
setEndInfo()
proc parseTopLevelStmt(p: var Parser): PNode =
## Implements an iterator which, when called repeatedly, returns the next
@@ -2402,6 +2492,7 @@ proc parseTopLevelStmt(p: var Parser): PNode =
result = complexOrSimpleStmt(p)
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
break
setEndInfo()
proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
filename: string = ""; line: int = 0;
@@ -2413,9 +2504,10 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
var stream = llStreamOpen(s)
stream.lineOffset = line
var parser: Parser
parser.lex.errorHandler = errorHandler
openParser(parser, AbsoluteFile filename, stream, cache, config)
var p: Parser
p.lex.errorHandler = errorHandler
openParser(p, AbsoluteFile filename, stream, cache, config)
result = parser.parseAll
closeParser(parser)
result = p.parseAll
closeParser(p)
setEndInfo()

View File

@@ -10,7 +10,7 @@
## Path handling utilities for Nim. Strictly typed code in order
## to avoid the never ending time sink in getting path handling right.
import os, pathnorm
import os, pathnorm, strutils
type
AbsoluteFile* = distinct string
@@ -99,3 +99,52 @@ when true:
proc addFileExt*(x: RelativeFile; ext: string): RelativeFile {.borrow.}
proc writeFile*(x: AbsoluteFile; content: string) {.borrow.}
proc skipHomeDir(x: string): int =
when defined(windows):
if x.continuesWith("Users/", len("C:/")):
result = 3
else:
result = 0
else:
if x.startsWith("/home/") or x.startsWith("/Users/"):
result = 3
elif x.startsWith("/mnt/") and x.continuesWith("/Users/", len("/mnt/c")):
result = 5
else:
result = 0
proc relevantPart(s: string; afterSlashX: int): string =
result = newStringOfCap(s.len - 8)
var slashes = afterSlashX
for i in 0..<s.len:
if slashes == 0:
result.add s[i]
elif s[i] == '/':
dec slashes
template canonSlashes(x: string): string =
when defined(windows):
x.replace('\\', '/')
else:
x
proc customPathImpl(x: string): string =
# Idea: Encode a "protocol" via "//protocol/path" which is not ambiguous
# as path canonicalization would have removed the double slashes.
# /mnt/X/Users/Y
# X:\\Users\Y
# /home/Y
# -->
# //user/
if not isAbsolute(x):
result = customPathImpl(canonSlashes(getCurrentDir() / x))
else:
let slashes = skipHomeDir(x)
if slashes > 0:
result = "//user/" & relevantPart(x, slashes)
else:
result = x
proc customPath*(x: string): string =
customPathImpl canonSlashes x

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
from ic / ic import addCompilerProc
@@ -44,18 +44,21 @@ const
wDiscardable, wGensym, wInject, wRaises, wEffectsOf,
wTags, wLocks, wGcSafe, wRequires, wEnsures}
exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe, wNoSideEffect}
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangeChecks,
wBoundChecks, wOverflowChecks, wNilChecks, wStaticBoundchecks,
wStyleChecks, wAssertions,
wWarnings, wHints,
wLineDir, wStackTrace, wLineTrace, wOptimization, wHint, wWarning, wError,
stmtPragmas* = {
wHint, wWarning, wError,
wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
wPassl, wPassc, wLocalPassc,
wDeadCodeElimUnused, # deprecated, always on
wDeprecated,
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto,
wExperimental, wThis, wUsed, wInvariant, wAssume, wAssert}
wExperimental, wDoctype, wThis, wUsed, wInvariant, wAssume, wAssert}
stmtPragmasTopLevel* = {wChecks, wObjChecks, wFieldChecks, wRangeChecks,
wBoundChecks, wOverflowChecks, wNilChecks, wStaticBoundchecks,
wStyleChecks, wAssertions,
wWarnings, wHints,
wLineDir, wStackTrace, wLineTrace, wOptimization,
wFloatChecks, wInfChecks, wNanChecks}
lambdaPragmas* = {FirstCallConv..LastCallConv,
wNoSideEffect, wSideEffect, wNoreturn, wNosinks, wDynlib, wHeader,
wThread, wAsmNoStackFrame,
@@ -494,12 +497,19 @@ 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},
customArgs: customArgs)
extccomp.addExternalFileToCompile(c.config, cf)
recordPragma(c, it, "compile", src.string, dest.string, customArgs)
if not fileExists(src):
localError(c.config, n.info, "cannot find: " & src.string)
else:
extccomp.addExternalFileToCompile(c.config, cf)
recordPragma(c, it, "compile", src.string, dest.string, customArgs)
proc getStrLit(c: PContext, n: PNode; i: int): string =
n[i] = c.semConstExpr(c, n[i])
@@ -536,7 +546,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) =
@@ -642,6 +653,7 @@ proc processPragma(c: PContext, n: PNode, i: int) =
invalidPragma(c, n)
var userPragma = newSym(skTemplate, it[1].ident, nextSymId(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)
@@ -651,7 +663,7 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
x.typ = makeTypeFromExpr(c, x)
else:
var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs)
if t.kind != tyObject and not t.isMetaType:
if t.kind notin {tyObject, tyOr}:
localError(c.config, x.info, errGenerated, "invalid type for raises/tags list")
x.typ = t
@@ -804,7 +816,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
@@ -830,6 +843,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
@@ -837,7 +853,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)
@@ -1207,6 +1223,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
if not isTopLevel(c):
localError(c.config, n.info, "'experimental' pragma only valid as toplevel statement or in a 'push' environment")
processExperimental(c, it)
of wDoctype:
if not isTopLevel(c):
localError(c.config, n.info, "\"doctype\" pragma only valid as top-level statement")
message(c.config, it.info, hintUser,
"doctype is not really implemented in Nim 1")
of wThis:
if it.kind in nkPragmaCallKinds and it.len == 2:
c.selfName = considerQuotedIdent(c, it[1])

View File

@@ -376,6 +376,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 & "\"\"\""

View File

@@ -27,11 +27,11 @@ when not defined(leanCompiler):
# implementation
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode
proc semExprNoType(c: PContext, n: PNode): PNode
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semProcBody(c: PContext, n: PNode): PNode
proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode
proc changeType(c: PContext; n: PNode, newType: PType, check: bool)
@@ -48,7 +48,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode
proc finishMethod(c: PContext, s: PSym)
proc evalAtCompileTime(c: PContext, n: PNode): PNode
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
proc semStaticExpr(c: PContext, n: PNode): PNode
proc semStaticExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode
proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType
proc semTypeOf(c: PContext; n: PNode): PNode
proc computeRequiresInit(c: PContext, t: PType): bool
@@ -78,7 +78,7 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode =
let x = arg.skipConv
if (x.kind == nkCurly and formal.kind == tySet and formal.base.kind != tyGenericParam) or
(x.kind in {nkPar, nkTupleConstr}) and formal.kind notin {tyUntyped, tyBuiltInTypeClass}:
(x.kind in {nkPar, nkTupleConstr}) and formal.kind notin {tyUntyped, tyBuiltInTypeClass, tyAnything}:
changeType(c, x, formal, check=true)
result = arg
result = skipHiddenSubConv(result, c.graph, c.idgen)
@@ -203,12 +203,58 @@ proc commonType*(c: PContext; x, y: PType): PType =
result.addSonSkipIntLit(r, c.idgen)
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:
for i in 1 ..< it.len:
let branch = it[i]
checkBranch:
case branch.kind
of nkOfBranch:
branch[^1]
of nkElifBranch:
branch[1]
of nkElse:
branch[0]
else:
raiseAssert "Malformed `case` statement in endsInNoReturn"
# none of the branches returned
result = true
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
@@ -269,12 +315,12 @@ proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
typeAllowedCheck(c, typ.n.info, typ, skProc)
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode
flags: TExprFlags = {}; expectedType: PType = nil): PNode
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode
flags: TExprFlags = {}; expectedType: PType = nil): PNode
proc symFromType(c: PContext; t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym
@@ -334,8 +380,8 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
isArrayConstr(arg):
arg.typ = eOrig.typ
proc tryConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
var e = semExprWithType(c, n, expectedType = expectedType)
if e == nil: return
result = getConstExpr(c.module, e, c.idgen, c.graph)
@@ -365,8 +411,8 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
const
errConstExprExpected = "constant expression expected"
proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
proc semConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
var e = semExprWithType(c, n, expectedType = expectedType)
if e == nil:
localError(c.config, n.info, errConstExprExpected)
return n
@@ -388,14 +434,14 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
else:
result = fixupTypeAfterEval(c, result, e)
proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
if efNeedStatic in flags:
if efPreferNilResult in flags:
return tryConstExpr(c, n)
return tryConstExpr(c, n, expectedType)
else:
return semConstExpr(c, n)
return semConstExpr(c, n, expectedType)
else:
result = semExprWithType(c, n, flags)
result = semExprWithType(c, n, flags, expectedType)
if efPreferStatic in flags:
var evaluated = getConstExpr(c.module, result, c.idgen, c.graph)
if evaluated != nil: return evaluated
@@ -414,7 +460,7 @@ proc resetSemFlag(n: PNode) =
resetSemFlag(n[i])
proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
s: PSym, flags: TExprFlags): PNode =
s: PSym, flags: TExprFlags; expectedType: PType = nil): PNode =
## Semantically check the output of a macro.
## This involves processes such as re-checking the macro output for type
## coherence, making sure that variables declared with 'let' aren't
@@ -436,12 +482,12 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
# does not mean we expect a tyTypeDesc.
retType = retType[0]
case retType.kind
of tyUntyped:
of tyUntyped, tyAnything:
# Not expecting a type here allows templates like in ``tmodulealias.in``.
result = semExpr(c, result, flags)
result = semExpr(c, result, flags, expectedType)
of tyTyped:
# More restrictive version.
result = semExprWithType(c, result, flags)
result = semExprWithType(c, result, flags, expectedType)
of tyTypeDesc:
if result.kind == nkStmtList: result.transitionSonsKind(nkStmtListType)
var typ = semTypeNode(c, result, nil)
@@ -465,8 +511,11 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
retType = generateTypeInstance(c, paramTypes,
macroResult.info, retType)
result = semExpr(c, result, flags)
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()
@@ -476,7 +525,7 @@ const
errFloatToString = "cannot convert '$1' to '$2'"
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode =
flags: TExprFlags = {}; expectedType: PType = nil): PNode =
rememberExpansion(c, nOrig.info, sym)
pushInfoContext(c.config, nOrig.info, sym.detailedInfo)
@@ -496,7 +545,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
# c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.module, c.idgen, c.graph, c.templInstCounter, n, nOrig, sym)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, n, result, sym, flags)
result = semAfterMacroCall(c, n, result, sym, flags, expectedType)
if c.config.macrosToExpand.hasKey(sym.name.s):
message(c.config, nOrig.info, hintExpandMacro, renderTree(result))
result = wrapInComesFrom(nOrig.info, sym, result)
@@ -507,7 +556,7 @@ proc forceBool(c: PContext, n: PNode): PNode =
if result == nil: result = n
proc semConstBoolExpr(c: PContext, n: PNode): PNode =
result = forceBool(c, semConstExpr(c, n))
result = forceBool(c, semConstExpr(c, n, getSysType(c.graph, n.info, tyBool)))
if result.kind != nkIntLit:
localError(c.config, n.info, errConstExprExpected)

View File

@@ -288,8 +288,23 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
# fail fast:
globalError(c.config, n.info, "type mismatch")
return
# see getMsgDiagnostic:
if nfExplicitCall notin n.flags and {nfDotField, nfDotSetter} * n.flags != {}:
let ident = considerQuotedIdent(c, n[0], n).s
let sym = n[1].typ.typSym
var typeHint = ""
if sym == nil:
discard
else:
typeHint = " for type " & getProcHeader(c.config, sym)
localError(c.config, n.info, errUndeclaredField % ident & typeHint)
return
if errors.len == 0:
localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
if n[0].kind in nkIdentKinds:
let ident = considerQuotedIdent(c, n[0], n).s
localError(c.config, n.info, errUndeclaredRoutine % ident)
else:
localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
return
let (prefer, candidates) = presentFailedCandidates(c, n, errors)
@@ -331,7 +346,7 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
sym = nextOverloadIter(o, c, f)
let ident = considerQuotedIdent(c, f, n).s
if {nfDotField, nfExplicitCall} * n.flags == {nfDotField}:
if nfExplicitCall notin n.flags and {nfDotField, nfDotSetter} * n.flags != {}:
let sym = n[1].typ.typSym
var typeHint = ""
if sym == nil:
@@ -364,11 +379,15 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
else:
initialBinding = nil
template pickBest(headSymbol) =
pickBestCandidate(c, f, n, orig, initialBinding,
filter, result, alt, errors, efExplain in flags,
errorsEnabled, flags)
var dummyErrors: CandidateErrors
template pickSpecialOp(headSymbol) =
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
filter, result, alt, errors, efExplain in flags,
errorsEnabled, flags)
pickBest(f)
filter, result, alt, dummyErrors, efExplain in flags,
false, flags)
let overloadsState = result.state
if overloadsState != csMatch:
@@ -380,7 +399,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
n.sons.insert(hiddenArg, 1)
orig.sons.insert(hiddenArg, 1)
pickBest(f)
pickSpecialOp(f)
if result.state != csMatch:
n.sons.delete(1)
@@ -400,7 +419,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
let op = newIdentNode(getIdent(c.cache, x), n.info)
n[0] = op
orig[0] = op
pickBest(op)
pickSpecialOp(op)
if nfExplicitCall in n.flags:
tryOp ".()"
@@ -414,23 +433,13 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
let callOp = newIdentNode(getIdent(c.cache, ".="), n.info)
n.sons[0..1] = [callOp, n[1], calleeName]
orig.sons[0..1] = [callOp, orig[1], calleeName]
pickBest(callOp)
pickSpecialOp(callOp)
if overloadsState == csEmpty and result.state == csEmpty:
if efNoUndeclared notin flags: # for tests/pragmas/tcustom_pragma.nim
template impl() =
# xxx adapt/use errorUndeclaredIdentifierHint(c, n, f.ident)
localError(c.config, n.info, getMsgDiagnostic(c, flags, n, f))
if n[0].kind == nkIdent and n[0].ident.s == ".=" and n[2].kind == nkIdent:
let sym = n[1].typ.sym
if sym == nil:
impl()
else:
let field = n[2].ident.s
let msg = errUndeclaredField % field & " for type " & getProcHeader(c.config, sym)
localError(c.config, orig[2].info, msg)
else:
impl()
result.state = csNoMatch
# xxx adapt/use errorUndeclaredIdentifierHint(c, n, f.ident)
localError(c.config, n.info, getMsgDiagnostic(c, flags, n, f))
return
elif result.state != csMatch:
if nfExprCall in n.flags:
@@ -619,7 +628,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
if efExplain notin flags:
# repeat the overload resolution,
# this time enabling all the diagnostic output (this should fail again)
discard semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
elif efNoUndeclared notin flags:
notFoundError(c, n, errors)
@@ -651,14 +660,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 = semExpr(c, n[i])
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:
@@ -703,7 +716,16 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
call.add(newIdentNode(fn.name, fn.info))
for i in 1..<fn.typ.n.len:
let param = fn.typ.n[i]
let t = skipTypes(param.typ, abstractVar-{tyTypeDesc, tyDistinct})
const desiredTypes = abstractVar + {tyCompositeTypeClass} - {tyTypeDesc, tyDistinct}
#[.
# We only want the type not any modifiers such as `ptr`, `var`, `ref` ...
# tyCompositeTypeClass is here for
# when using something like:
type Foo[T] = distinct int
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
if param.typ.kind == tyVar:

View File

@@ -70,6 +70,7 @@ type
efNoUndeclared
# Use this if undeclared identifiers should not raise an error during
# overload resolution.
efNoDiagnostics
TExprFlags* = set[TExprFlag]
@@ -118,10 +119,10 @@ type
symMapping*: TIdTable # every gensym'ed symbol needs to be mapped
# to some new symbol in a generic instantiation
libs*: seq[PLib] # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
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.}
semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.}
computeRequiresInit*: proc (c: PContext, t: PType): bool {.nimcall.}
hasUnresolvedArgs*: proc (c: PContext, n: PNode): bool
@@ -161,6 +162,7 @@ type
lastTLineInfo*: TLineInfo
sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index
inUncheckedAssignSection*: int
importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id])
template config*(c: PContext): ConfigRef = c.graph.config

View File

@@ -26,7 +26,7 @@ const
errUndeclaredFieldX = "undeclared field: '$1'"
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode =
flags: TExprFlags = {}; expectedType: PType = nil): PNode =
rememberExpansion(c, n.info, s)
let info = getCallLineInfo(n)
markUsed(c, info, s)
@@ -36,7 +36,8 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
pushInfoContext(c.config, n.info, s.detailedInfo)
result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache,
c.templInstCounter, c.idgen, efFromHlo in flags)
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, n, result, s, flags, expectedType)
popInfoContext(c.config)
# XXX: A more elaborate line info rewrite might be needed
@@ -65,9 +66,9 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType = nil): PNode =
rejectEmptyNode(n)
result = semExpr(c, n, flags+{efWantValue})
result = semExpr(c, n, flags+{efWantValue}, expectedType)
let
isEmpty = result.kind == nkEmpty
@@ -82,8 +83,8 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
# do not produce another redundant error message:
result = errorNode(c, n)
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExprCheck(c, n, flags)
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
result = semExprCheck(c, n, flags, expectedType)
if result.typ == nil and efInTypeof in flags:
result.typ = c.voidType
elif result.typ == nil or result.typ == c.enforceVoidContext:
@@ -196,10 +197,10 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus =
else:
discard
proc isCastable(c: PContext; dst, src: PType): bool =
proc isCastable(c: PContext; dst, src: PType, info: TLineInfo): bool =
## Checks whether the source type can be cast to the destination type.
## Casting is very unrestrictive; casts are allowed as long as
## castDest.size >= src.size, and typeAllowed(dst, skParam)
## dst.size >= src.size, and typeAllowed(dst, skParam)
#const
# castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
# tySequence, tyPointer, tyNil, tyOpenArray,
@@ -228,19 +229,21 @@ proc isCastable(c: PContext; dst, src: PType): bool =
# Just assume the programmer knows what he is doing.
return true
if dstSize < 0:
result = false
return false
elif srcSize < 0:
result = false
elif typeAllowed(dst, skParam, c) != nil:
result = false
return false
elif typeAllowed(dst, skParam, c, {taIsCastable}) != nil:
return false
elif dst.kind == tyProc and dst.callConv == ccClosure:
result = src.kind == tyProc and src.callConv == ccClosure
return src.kind == tyProc and src.callConv == ccClosure
else:
result = (dstSize >= srcSize) or
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
(skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
if result and (dstSize > srcSize):
message(conf, info, warnCastSizes, "target type is larger than source type")
if result and src.kind == tyNil:
result = dst.size <= conf.target.ptrSize
return dst.size <= conf.target.ptrSize
proc isSymChoice(n: PNode): bool {.inline.} =
result = n.kind in nkSymChoices
@@ -259,7 +262,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): PNode =
proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
if n.len != 2:
localError(c.config, n.info, "a type conversion takes exactly one argument")
return n
@@ -267,7 +270,7 @@ proc semConv(c: PContext, n: PNode): PNode =
result = newNodeI(nkConv, n.info)
var targetType = semTypeNode(c, n[0], nil)
case targetType.kind
case targetType.skipTypes({tyDistinct}).kind
of tyTypeDesc:
internalAssert c.config, targetType.len > 0
if targetType.base.kind == tyNone:
@@ -275,7 +278,7 @@ proc semConv(c: PContext, n: PNode): PNode =
else:
targetType = targetType.base
of tyStatic:
var evaluated = semStaticExpr(c, n[1])
var evaluated = semStaticExpr(c, n[1], expectedType)
if evaluated.kind == nkType or evaluated.typ.kind == tyTypeDesc:
result = n
result.typ = c.makeTypeDesc semStaticType(c, evaluated, nil)
@@ -284,6 +287,8 @@ proc semConv(c: PContext, n: PNode): PNode =
return evaluated
else:
targetType = targetType.base
of tyAnything, tyUntyped, tyTyped:
localError(c.config, n.info, "illegal type conversion to '$1'" % typeToString(targetType))
else: discard
maybeLiftType(targetType, c, n[0].info)
@@ -357,9 +362,13 @@ proc semCast(c: PContext, n: PNode): PNode =
checkSonsLen(n, 2, c.config)
let targetType = semTypeNode(c, n[0], nil)
let castedExpr = semExprWithType(c, n[1])
if castedExpr.kind == nkClosedSymChoice:
errorUseQualifier(c, n[1].info, castedExpr)
if targetType == nil:
localError(c.config, n.info, "Invalid usage of cast, cast requires a type to convert to, e.g., cast[int](0d).")
if tfHasMeta in targetType.flags:
localError(c.config, n[0].info, "cannot cast to a non concrete type: '$1'" % $targetType)
if not isCastable(c, targetType, castedExpr.typ):
if not isCastable(c, targetType, castedExpr.typ, n.info):
let tar = $targetType
let alt = typeToString(targetType, preferDesc)
let msg = if tar != alt: tar & "=" & alt else: tar
@@ -522,7 +531,7 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
result = newNodeI(nkCall, n.info)
result.add newIdentNode(par, n.info)
for i in 0..<n.len: result.add n[i]
result = semExpr(c, result)
result = semExpr(c, result, flags = {efNoUndeclared})
proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
case n.kind
@@ -581,21 +590,36 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
typ[0] = makeRangeType(c, 0, n.len - 1, n.info)
result = typ
proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = newNodeI(nkBracket, n.info)
result.typ = newTypeS(tyArray, c)
var expectedElementType, expectedIndexType: PType = nil
if expectedType != nil:
let expected = expectedType.skipTypes(abstractRange-{tyDistinct})
case expected.kind
of tyArray:
expectedIndexType = expected[0]
expectedElementType = expected[1]
of tyOpenArray:
expectedElementType = expected[0]
else: discard
rawAddSon(result.typ, nil) # index type
var
firstIndex, lastIndex: Int128
indexType = getSysType(c.graph, n.info, tyInt)
lastValidIndex = lastOrd(c.config, indexType)
if n.len == 0:
rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
rawAddSon(result.typ,
if expectedElementType != nil and
typeAllowed(expectedElementType, skLet, c) == nil:
expectedElementType
else:
newTypeS(tyEmpty, c)) # needs an empty basetype!
lastIndex = toInt128(-1)
else:
var x = n[0]
if x.kind == nkExprColonExpr and x.len == 2:
var idx = semConstExpr(c, x[0])
var idx = semConstExpr(c, x[0], expectedIndexType)
if not isOrdinalType(idx.typ):
localError(c.config, idx.info, "expected ordinal value for array " &
"index, got '$1'" % renderTree(idx))
@@ -606,8 +630,10 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
lastValidIndex = lastOrd(c.config, indexType)
x = x[1]
let yy = semExprWithType(c, x)
let yy = semExprWithType(c, x, expectedType = expectedElementType)
var typ = yy.typ
if expectedElementType == nil:
expectedElementType = typ
result.add yy
#var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
for i in 1..<n.len:
@@ -619,13 +645,13 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
x = n[i]
if x.kind == nkExprColonExpr and x.len == 2:
var idx = semConstExpr(c, x[0])
var idx = semConstExpr(c, x[0], indexType)
idx = fitNode(c, indexType, idx, x.info)
if lastIndex+1 != getOrdValue(idx):
localError(c.config, x.info, "invalid order in array constructor")
x = x[1]
let xx = semExprWithType(c, x, {})
let xx = semExprWithType(c, x, {}, expectedElementType)
result.add xx
typ = commonType(c, typ, xx.typ)
#n[i] = semExprWithType(c, x, {})
@@ -640,6 +666,9 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc fixAbstractType(c: PContext, n: PNode) =
for i in 1..<n.len:
let it = n[i]
if it == nil:
localError(c.config, n.info, "'$1' has nil child at index $2" % [renderTree(n, {renderNoComments}), $i])
return
# do not get rid of nkHiddenSubConv for OpenArrays, the codegen needs it:
if it.kind == nkHiddenSubConv and
skipTypes(it.typ, abstractVar).kind notin {tyOpenArray, tyVarargs}:
@@ -851,10 +880,10 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
#if result != n:
# echo "SUCCESS evaluated at compile time: ", call.renderTree
proc semStaticExpr(c: PContext, n: PNode): PNode =
proc semStaticExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
inc c.inStaticContext
openScope(c)
let a = semExprWithType(c, n)
let a = semExprWithType(c, n, expectedType = expectedType)
closeScope(c)
dec c.inStaticContext
if a.findUnresolvedStatic != nil: return a
@@ -886,7 +915,8 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
case callee.kind
of skMacro, skTemplate: discard
else:
if callee.kind == skIterator and callee.id == c.p.owner.id:
if callee.kind == skIterator and callee.id == c.p.owner.id and
not isClosureIterator(c.p.owner.typ):
localError(c.config, n.info, errRecursiveDependencyIteratorX % callee.name.s)
# error correction, prevents endless for loop elimination in transf.
# See bug #2051:
@@ -897,7 +927,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
rawAddSon(typ, result.typ)
result.typ = typ
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode
proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
t: PType): TCandidate =
@@ -916,26 +946,30 @@ 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 afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
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)
result = n
when defined(nimsuggest):
if c.config.expandProgress:
if c.config.expandLevels == 0:
return n
else:
c.config.expandLevels -= 1
let callee = result[0].sym
case callee.kind
of skMacro: result = semMacroExpr(c, result, orig, callee, flags)
of skTemplate: result = semTemplateExpr(c, result, callee, flags)
of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType)
of skTemplate: result = semTemplateExpr(c, result, callee, flags, expectedType)
else:
semFinishOperands(c, result)
activate(c, result)
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags)
result = magicsAfterOverloadResolution(c, result, flags, expectedType)
when false:
if result.typ != nil and
not (result.typ.kind == tySequence and result.typ[0].kind == tyEmpty):
@@ -944,7 +978,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
if c.matchedConcept == nil:
result = evalAtCompileTime(c, result)
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = nil
checkMinSonsLen(n, 1, c.config)
var prc = n[0]
@@ -969,13 +1003,20 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
let s = bracketedMacro(n[0])
if s != nil:
setGenericParams(c, n[0])
return semDirectOp(c, n, flags)
return semDirectOp(c, n, flags, expectedType)
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)
let nOrig = n.copyTree
semOpAux(c, n)
var t: PType = nil
if n[0].typ != nil:
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)
let nOrig = n.copyTree
semOpAux(c, n)
if t != nil and t.kind == tyProc:
# This is a proc variable, apply normal overload resolution
let m = resolveIndirectCall(c, n, nOrig, t)
@@ -1009,19 +1050,15 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
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)
elif t != nil and t.kind == tyTypeDesc:
if n.len == 1: return semObjConstr(c, n, flags)
return semConv(c, n)
else:
result = overloadedCallOpr(c, n)
result = overloadedCallOpr(c, n) # this uses efNoUndeclared
# Now that nkSym does not imply an iteration over the proc/iterator space,
# the old ``prc`` (which is likely an nkIdent) has to be restored:
if result == nil:
if result == nil or result.kind == nkEmpty:
# XXX: hmm, what kind of symbols will end up here?
# do we really need to try the overload resolution?
n[0] = prc
@@ -1035,17 +1072,17 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
return result
#result = afterCallActions(c, result, nOrig, flags)
if result[0].kind == nkSym:
result = afterCallActions(c, result, nOrig, flags)
result = afterCallActions(c, result, nOrig, flags, expectedType)
else:
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
# this seems to be a hotspot in the compiler!
let nOrig = n.copyTree
#semLazyOpAux(c, n)
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result != nil: result = afterCallActions(c, result, nOrig, flags)
if result != nil: result = afterCallActions(c, result, nOrig, flags, expectedType)
else: result = errorNode(c, n)
proc buildEchoStmt(c: PContext, n: PNode): PNode =
@@ -1585,7 +1622,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
@@ -1618,11 +1658,11 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
discard
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = semSubscript(c, n, flags)
if result == nil:
# overloaded [] operator:
result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "[]")), flags)
result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "[]")), flags, expectedType)
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
var id = considerQuotedIdent(c, a[1], a)
@@ -1763,7 +1803,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
@@ -1796,13 +1836,15 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
renderTree(a, {renderNoComments}))
else:
let lhs = n[0]
let rhs = semExprWithType(c, n[1], {})
let rhs = semExprWithType(c, n[1], {}, le)
if lhs.kind == nkSym and lhs.sym.kind == skResult:
n.typ = c.enforceVoidContext
if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
var rhsTyp = rhs.typ
if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass:
rhsTyp = rhsTyp.lastSon
if lhs.sym.typ.kind == tyAnything:
rhsTyp = rhsTyp.skipIntLit(c.idgen)
if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}:
internalAssert c.config, c.p.resultSym != nil
# Make sure the type is valid for the result variable
@@ -1845,9 +1887,12 @@ proc semReturn(c: PContext, n: PNode): PNode =
else:
localError(c.config, n.info, "'return' not allowed here")
proc semProcBody(c: PContext, n: PNode): PNode =
proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode =
when defined(nimsuggest):
if c.graph.config.expandDone():
return n
openScope(c)
result = semExpr(c, n)
result = semExpr(c, n, expectedType = expectedType)
if c.p.resultSym != nil and not isEmptyType(result.typ):
if result.kind == nkNilLit:
# or ImplicitlyDiscardable(result):
@@ -1876,8 +1921,8 @@ proc semProcBody(c: PContext, n: PNode): PNode =
else:
localError(c.config, c.p.resultSym.info, errCannotInferReturnType %
c.p.owner.name.s)
if isInlineIterator(c.p.owner.typ) and c.p.owner.typ[0] != nil and
c.p.owner.typ[0].kind == tyUntyped:
if isIterator(c.p.owner.typ) and c.p.owner.typ[0] != nil and
c.p.owner.typ[0].kind == tyAnything:
localError(c.config, c.p.owner.info, errCannotInferReturnType %
c.p.owner.name.s)
closeScope(c)
@@ -1903,6 +1948,8 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
tupleConstr[i] = takeImplicitAddr(c, tupleConstr[i], e.kind == tyLent)
else:
localError(c.config, n[0].info, errXExpected, "tuple constructor")
elif e.kind == tyEmpty:
localError(c.config, n[0].info, errTypeExpected)
else:
when false:
# XXX investigate what we really need here.
@@ -2264,7 +2311,7 @@ proc semSizeof(c: PContext, n: PNode): PNode =
n.typ = getSysType(c.graph, n.info, tyInt)
result = foldSizeOf(c.config, n, n)
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: PType = nil): PNode =
# this is a hotspot in the compiler!
result = n
case s.magic # magics that need special treatment
@@ -2380,8 +2427,21 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
of mSizeOf:
markUsed(c, n.info, s)
result = semSizeof(c, setMs(n, s))
of mArrToSeq, mOpenArrayToSeq:
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind in {tySequence, tyOpenArray}):
# seq type inference
var arrayType = newType(tyOpenArray, nextTypeId(c.idgen), expected.owner)
arrayType.rawAddSon(expected[0])
if n[0].kind == nkSym and sfFromGeneric in n[0].sym.flags:
# may have been resolved to `@`[empty] at some point,
# reset to `@` to deal with this
n[0] = newSymNode(n[0].sym.owner, n[0].info)
n[1] = semExpr(c, n[1], flags, arrayType)
result = semDirectOp(c, n, flags, expectedType)
else:
result = semDirectOp(c, n, flags)
result = semDirectOp(c, n, flags, expectedType)
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
# If semCheck is set to false, ``when`` will return the verbatim AST of
@@ -2399,8 +2459,8 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
# ...
var whenNimvm = false
var typ = commonTypeBegin
if n.len == 2 and n[0].kind == nkElifBranch and
n[1].kind == nkElse:
if n.len in 1..2 and n[0].kind == nkElifBranch and (
n.len == 1 or n[1].kind == nkElse):
let exprNode = n[0][0]
if exprNode.kind == nkIdent:
whenNimvm = lookUp(c, exprNode).magic == mNimvm
@@ -2438,35 +2498,54 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
else: illFormedAst(n, c.config)
if result == nil:
result = newNodeI(nkEmpty, n.info)
if whenNimvm: result.typ = typ
if whenNimvm:
result.typ = typ
if n.len == 1:
result.add(newTree(nkElse, newNode(nkStmtList)))
proc semSetConstr(c: PContext, n: PNode): PNode =
proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
result = newNodeI(nkCurly, n.info)
result.typ = newTypeS(tySet, c)
result.typ.flags.incl tfIsConstructor
var expectedElementType: PType = nil
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind == tySet):
expectedElementType = expected[0]
if n.len == 0:
rawAddSon(result.typ, newTypeS(tyEmpty, c))
rawAddSon(result.typ,
if expectedElementType != nil and
typeAllowed(expectedElementType, skLet, c) == nil:
expectedElementType
else:
newTypeS(tyEmpty, c))
else:
# only semantic checking for all elements, later type checking:
var typ: PType = nil
for i in 0..<n.len:
if isRange(n[i]):
checkSonsLen(n[i], 3, c.config)
n[i][1] = semExprWithType(c, n[i][1])
n[i][2] = semExprWithType(c, n[i][2])
n[i][1] = semExprWithType(c, n[i][1], {}, expectedElementType)
n[i][2] = semExprWithType(c, n[i][2], {}, expectedElementType)
if typ == nil:
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:
typ = skipTypes(n[i][0].typ,
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
if expectedElementType == nil:
expectedElementType = typ
else:
n[i] = semExprWithType(c, n[i])
n[i] = semExprWithType(c, n[i], {}, expectedElementType)
if typ == nil:
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)
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
@@ -2485,7 +2564,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
m = fitNode(c, typ, n[i], info)
result.add m
proc semTableConstr(c: PContext, n: PNode): PNode =
proc semTableConstr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
# we simply transform ``{key: value, key2, key3: value}`` to
# ``[(key, value), (key2, value2), (key3, value2)]``
result = newNodeI(nkBracket, n.info)
@@ -2507,7 +2586,7 @@ proc semTableConstr(c: PContext, n: PNode): PNode =
lastKey = i+1
if lastKey != n.len: illFormedAst(n, c.config)
result = semExpr(c, result)
result = semExpr(c, result, expectedType = expectedType)
type
TParKind = enum
@@ -2534,8 +2613,13 @@ proc checkPar(c: PContext; n: PNode): TParKind =
localError(c.config, n[i].info, errNamedExprNotAllowed)
return paNone
proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = newNodeI(nkTupleConstr, n.info)
var expected: PType = nil
if expectedType != nil:
expected = expectedType.skipTypes(abstractRange-{tyDistinct})
if not (expected.kind == tyTuple and expected.len == n.len):
expected = nil
var typ = newTypeS(tyTuple, c)
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
var ids = initIntSet()
@@ -2545,7 +2629,9 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
let id = considerQuotedIdent(c, n[i][0])
if containsOrIncl(ids, id.id):
localError(c.config, n[i].info, errFieldInitTwice % id.s)
n[i][1] = semExprWithType(c, n[i][1], {})
# can check if field name matches expected type here
let expectedElemType = if expected != nil: expected[i] else: nil
n[i][1] = semExprWithType(c, n[i][1], {}, expectedElemType)
if n[i][1].typ.kind == tyTypeDesc:
localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.")
@@ -2560,18 +2646,24 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.add n[i]
result.typ = typ
proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = n # we don't modify n, but compute the type:
result.transitionSonsKind(nkTupleConstr)
var expected: PType = nil
if expectedType != nil:
expected = expectedType.skipTypes(abstractRange-{tyDistinct})
if not (expected.kind == tyTuple and expected.len == n.len):
expected = nil
var typ = newTypeS(tyTuple, c) # leave typ.n nil!
for i in 0..<n.len:
n[i] = semExprWithType(c, n[i], {})
let expectedElemType = if expected != nil: expected[i] else: nil
n[i] = semExprWithType(c, n[i], {}, expectedElemType)
addSonSkipIntLit(typ, n[i].typ, c.idgen)
result.typ = typ
include semobjconstr
proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
proc semBlock(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
result = n
inc(c.p.nestedBlockCounter)
checkSonsLen(n, 2, c.config)
@@ -2586,7 +2678,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
suggestSym(c.graph, n[0].info, labl, c.graph.usageSym)
styleCheckDef(c, labl)
onDef(n[0].info, labl)
n[1] = semExpr(c, n[1], flags)
n[1] = semExpr(c, n[1], flags, expectedType)
n.typ = n[1].typ
if isEmptyType(n.typ): n.transitionSonsKind(nkBlockStmt)
else: n.transitionSonsKind(nkBlockExpr)
@@ -2652,8 +2744,8 @@ proc semExport(c: PContext, n: PNode): PNode =
s = nextOverloadIter(o, c, a)
proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
var tupexp = semTuplePositionsConstr(c, n, flags)
proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
var tupexp = semTuplePositionsConstr(c, n, flags, expectedType)
var isTupleType: bool
if tupexp.len > 0: # don't interpret () as type
isTupleType = tupexp[0].typ.kind == tyTypeDesc
@@ -2772,7 +2864,13 @@ proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym): PNode =
onUse(info, a)
a = nextOverloadIter(o, c, n)
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
proc semPragmaStmt(c: PContext; n: PNode) =
if c.p.owner.kind == skModule:
pragma(c, c.p.owner, n, stmtPragmas+stmtPragmasTopLevel, true)
else:
pragma(c, c.p.owner, n, stmtPragmas, true)
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
when defined(nimCompilerStacktraceHints):
setFrameMsg c.config$n.info & " " & $n.kind
when false: # see `tdebugutils`
@@ -2782,18 +2880,53 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if isCompilerDebug():
echo ("<", c.config$n.info, n, ?.result.typ)
template directLiteral(typeKind: TTypeKind) =
if result.typ == nil:
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind == typeKind):
result.typ = expected
changeType(c, result, expectedType, check=true)
else:
result.typ = getSysType(c.graph, n.info, typeKind)
result = n
when defined(nimsuggest):
var expandStarted = false
if c.config.ideCmd == ideExpand and not c.config.expandProgress and
((n.kind in {nkFuncDef, nkProcDef, nkIteratorDef, nkTemplateDef, nkMethodDef, nkConverterDef} and
n.info.exactEquals(c.config.expandPosition)) or
(n.kind in {nkCall, nkCommand} and
n[0].info.exactEquals(c.config.expandPosition))):
expandStarted = true
c.config.expandProgress = true
if c.config.expandLevels == 0:
c.config.expandNodeResult = $n
suggestQuit()
if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
if nfSem in n.flags: return
case n.kind
of nkIdent, nkAccQuoted:
let checks = if efNoEvaluateGeneric in flags:
{checkUndeclared, checkPureEnumFields}
elif efInCall in flags:
{checkUndeclared, checkModule, checkPureEnumFields}
else:
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
var s = qualifiedLookUp(c, n, checks)
var s: PSym
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind == tyEnum):
let nameId = considerQuotedIdent(c, n).id
for f in expected.n:
if f.kind == nkSym and f.sym.name.id == nameId:
s = f.sym
break
if s == nil:
let checks = if efNoEvaluateGeneric in flags:
{checkUndeclared, checkPureEnumFields}
elif efInCall in flags:
{checkUndeclared, checkModule, checkPureEnumFields}
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:
@@ -2813,6 +2946,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semSym(c, n, s, flags)
else:
result = semSym(c, n, s, flags)
if expectedType != nil and isSymChoice(result):
result = fitNode(c, expectedType, result, n.info)
if result.kind == nkSym:
result = semSym(c, result, result.sym, flags)
of nkSym:
# because of the changed symbol binding, this does not mean that we
# don't have to check the symbol for semantics here again!
@@ -2820,39 +2957,56 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkEmpty, nkNone, nkCommentStmt, nkType:
discard
of nkNilLit:
if result.typ == nil: result.typ = getNilType(c)
if result.typ == nil:
result.typ = getNilType(c)
if expectedType != nil:
var m = newCandidate(c, result.typ)
if typeRel(m, expectedType, result.typ) >= isSubtype:
result.typ = expectedType
# or: result = fitNode(c, expectedType, result, n.info)
of nkIntLit:
if result.typ == nil: setIntLitType(c, result)
of nkInt8Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt8)
of nkInt16Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt16)
of nkInt32Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt32)
of nkInt64Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt64)
of nkUIntLit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt)
of nkUInt8Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt8)
of nkUInt16Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt16)
of nkUInt32Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt32)
of nkUInt64Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt64)
#of nkFloatLit:
# if result.typ == nil: result.typ = getFloatLitType(result)
of nkFloat32Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat32)
of nkFloat64Lit, nkFloatLit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat64)
of nkFloat128Lit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat128)
if result.typ == nil:
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
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)
else:
setIntLitType(c, result)
of nkInt8Lit: directLiteral(tyInt8)
of nkInt16Lit: directLiteral(tyInt16)
of nkInt32Lit: directLiteral(tyInt32)
of nkInt64Lit: directLiteral(tyInt64)
of nkUIntLit: directLiteral(tyUInt)
of nkUInt8Lit: directLiteral(tyUInt8)
of nkUInt16Lit: directLiteral(tyUInt16)
of nkUInt32Lit: directLiteral(tyUInt32)
of nkUInt64Lit: directLiteral(tyUInt64)
of nkFloatLit:
if result.typ == nil:
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind in {tyFloat..tyFloat128}):
result.typ = expected
changeType(c, result, expectedType, check=true)
else:
result.typ = getSysType(c.graph, n.info, tyFloat64)
of nkFloat32Lit: directLiteral(tyFloat32)
of nkFloat64Lit: directLiteral(tyFloat64)
of nkFloat128Lit: directLiteral(tyFloat128)
of nkStrLit..nkTripleStrLit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyString)
of nkCharLit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyChar)
if result.typ == nil:
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind in {tyString, tyCstring}):
result.typ = expectedType
else:
result.typ = getSysType(c.graph, n.info, tyString)
of nkCharLit: directLiteral(tyChar)
of nkDotExpr:
result = semFieldAccess(c, n, flags)
if result.kind == nkDotCall:
@@ -2860,7 +3014,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semExpr(c, result, flags)
of nkBind:
message(c.config, n.info, warnDeprecated, "bind is deprecated")
result = semExpr(c, n[0], flags)
result = semExpr(c, n[0], flags, expectedType)
of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy:
if c.matchedConcept != nil and n.len == 1:
let modifier = n.modifierTypeKindOfNode
@@ -2886,40 +3040,40 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# pretty.checkUse(n[0][1].info, s)
case s.kind
of skMacro, skTemplate:
result = semDirectOp(c, n, flags)
result = semDirectOp(c, n, flags, expectedType)
of skType:
# 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)
result = semConv(c, n, expectedType)
elif ambig and n.len == 1:
errorUseQualifier(c, n.info, s)
elif n.len == 1:
result = semObjConstr(c, n, flags)
elif s.magic == mNone: result = semDirectOp(c, n, flags)
else: result = semMagic(c, n, s, flags)
result = semObjConstr(c, n, flags, expectedType)
elif s.magic == mNone: result = semDirectOp(c, n, flags, expectedType)
else: result = semMagic(c, n, s, flags, expectedType)
of skProc, skFunc, skMethod, skConverter, skIterator:
if s.magic == mNone: result = semDirectOp(c, n, flags)
else: result = semMagic(c, n, s, flags)
else: result = semMagic(c, n, s, flags, expectedType)
else:
#liMessage(n.info, warnUser, renderTree(n));
result = semIndirectOp(c, n, flags)
result = semIndirectOp(c, n, flags, expectedType)
elif (n[0].kind == nkBracketExpr or shouldBeBracketExpr(n)) and
isSymChoice(n[0][0]):
# indirectOp can deal with explicit instantiations; the fixes
# the 'newSeq[T](x)' bug
setGenericParams(c, n[0])
result = semDirectOp(c, n, flags)
result = semDirectOp(c, n, flags, expectedType)
elif nfDotField in n.flags:
result = semDirectOp(c, n, flags)
result = semDirectOp(c, n, flags, expectedType)
elif isSymChoice(n[0]):
let b = asBracketExpr(c, n)
if b != nil:
result = semExpr(c, b, flags)
result = semExpr(c, b, flags, expectedType)
else:
result = semDirectOp(c, n, flags)
result = semDirectOp(c, n, flags, expectedType)
else:
result = semIndirectOp(c, n, flags)
result = semIndirectOp(c, n, flags, expectedType)
if nfDefaultRefsParam in result.flags:
result = result.copyTree #XXX: Figure out what causes default param nodes to be shared.. (sigmatch bug?)
@@ -2938,12 +3092,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# This is a "when nimvm" stmt.
result = semWhen(c, n, true)
else:
result = semExpr(c, result, flags)
result = semExpr(c, result, flags, expectedType)
of nkBracketExpr:
checkMinSonsLen(n, 1, c.config)
result = semArrayAccess(c, n, flags)
result = semArrayAccess(c, n, flags, expectedType)
of nkCurlyExpr:
result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "{}")), flags)
result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "{}")), flags, expectedType)
of nkPragmaExpr:
var
pragma = n[1]
@@ -2965,12 +3119,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkPar, nkTupleConstr:
case checkPar(c, n)
of paNone: result = errorNode(c, n)
of paTuplePositions: result = semTupleConstr(c, n, flags)
of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
of paSingle: result = semExpr(c, n[0], flags)
of nkCurly: result = semSetConstr(c, n)
of nkBracket: result = semArrayConstr(c, n, flags)
of nkObjConstr: result = semObjConstr(c, n, flags)
of paTuplePositions: result = semTupleConstr(c, n, flags, expectedType)
of paTupleFields: result = semTupleFieldsConstr(c, n, flags, expectedType)
of paSingle: result = semExpr(c, n[0], flags, expectedType)
of nkCurly: result = semSetConstr(c, n, expectedType)
of nkBracket: result = semArrayConstr(c, n, flags, expectedType)
of nkObjConstr: result = semObjConstr(c, n, flags, expectedType)
of nkLambdaKinds: result = semProcAux(c, n, skProc, lambdaPragmas, flags)
of nkDerefExpr: result = semDeref(c, n)
of nkAddr:
@@ -2980,9 +3134,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result.typ = makePtrType(c, result[0].typ)
of nkHiddenAddr, nkHiddenDeref:
checkSonsLen(n, 1, c.config)
n[0] = semExpr(c, n[0], flags)
n[0] = semExpr(c, n[0], flags, expectedType)
of nkCast: result = semCast(c, n)
of nkIfExpr, nkIfStmt: result = semIf(c, n, flags)
of nkIfExpr, nkIfStmt: result = semIf(c, n, flags, expectedType)
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
checkSonsLen(n, 2, c.config)
considerGenSyms(c, n)
@@ -2996,15 +3150,15 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
checkMinSonsLen(n, 2, c.config)
considerGenSyms(c, n)
of nkTableConstr:
result = semTableConstr(c, n)
result = semTableConstr(c, n, expectedType)
of nkClosedSymChoice, nkOpenSymChoice:
# handling of sym choices is context dependent
# the node is left intact for now
discard
of nkStaticExpr: result = semStaticExpr(c, n[0])
of nkAsgn: result = semAsgn(c, n)
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags)
of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
of nkStaticExpr: result = semStaticExpr(c, n[0], expectedType)
of nkAsgn, nkFastAsgn: result = semAsgn(c, n)
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags, expectedType)
of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags, expectedType)
of nkRaiseStmt: result = semRaise(c, n)
of nkVarSection: result = semVarOrLet(c, n, skVar)
of nkLetSection: result = semVarOrLet(c, n, skLet)
@@ -3012,15 +3166,15 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkTypeSection: result = semTypeSection(c, n)
of nkDiscardStmt: result = semDiscard(c, n)
of nkWhileStmt: result = semWhile(c, n, flags)
of nkTryStmt, nkHiddenTryStmt: result = semTry(c, n, flags)
of nkTryStmt, nkHiddenTryStmt: result = semTry(c, n, flags, expectedType)
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
of nkForStmt, nkParForStmt: result = semFor(c, n, flags)
of nkCaseStmt: result = semCase(c, n, flags)
of nkCaseStmt: result = semCase(c, n, flags, expectedType)
of nkReturnStmt: result = semReturn(c, n)
of nkUsingStmt: result = semUsing(c, n)
of nkAsmStmt: result = semAsm(c, n)
of nkYieldStmt: result = semYield(c, n)
of nkPragma: pragma(c, c.p.owner, n, stmtPragmas, true)
of nkPragma: semPragmaStmt(c, n)
of nkIteratorDef: result = semIterator(c, n)
of nkProcDef: result = semProc(c, n)
of nkFuncDef: result = semFunc(c, n)
@@ -3054,13 +3208,15 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
result = semExportExcept(c, n)
of nkPragmaBlock:
result = semPragmaBlock(c, n)
result = semPragmaBlock(c, n, expectedType)
of nkStaticStmt:
result = semStaticStmt(c, n)
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")
@@ -3081,3 +3237,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
localError(c.config, n.info, "invalid expression: " &
renderTree(n, {renderNoComments}))
if result != nil: incl(result.flags, nfSem)
when defined(nimsuggest):
if expandStarted:
c.config.expandNodeResult = $result
suggestQuit()

View File

@@ -292,13 +292,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
else: result = newStrNodeT("true", n, g)
of mFloatToStr: result = newStrNodeT($getFloat(a), n, g)
of mCStrToStr, mCharToStr:
if a.kind == nkBracket:
var s = ""
for b in a.sons:
s.add b.getStrOrChar
result = newStrNodeT(s, n, g)
else:
result = newStrNodeT(getStrOrChar(a), n, g)
result = newStrNodeT(getStrOrChar(a), n, g)
of mStrToStr: result = newStrNodeT(getStrOrChar(a), n, g)
of mEnumToStr: result = newStrNodeT(ordinalValToString(a, g), n, g)
of mArrToSeq:
@@ -460,6 +454,7 @@ proc foldArrayAccess(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNo
proc foldFieldAccess(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
# a real field access; proc calls have already been transformed
if n[1].kind != nkSym: return nil
var x = getConstExpr(m, n[0], idgen, g)
if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return

View File

@@ -78,14 +78,18 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
if macroToExpandSym(s):
onUse(n.info, s)
result = semTemplateExpr(c, 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)
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)
of skGenericParam:
@@ -249,7 +253,9 @@ proc semGenericStmt(c: PContext, n: PNode,
if macroToExpand(s) 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
@@ -258,7 +264,9 @@ proc semGenericStmt(c: PContext, n: PNode,
if macroToExpand(s) and sc.safeLen <= 1:
onUse(fn.info, s)
result = semTemplateExpr(c, 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
@@ -497,6 +505,20 @@ proc semGenericStmt(c: PContext, n: PNode,
of nkExprColonExpr, nkExprEqExpr:
checkMinSonsLen(n, 2, c.config)
result[1] = semGenericStmt(c, n[1], flags, ctx)
of nkObjConstr:
for i in 0..<n.len:
result[i] = semGenericStmt(c, n[i], flags, ctx)
if result[0].kind == nkSym:
let fmoduleId = getModule(result[0].sym).id
var isVisable = false
for module in c.friendModules:
if module.id == fmoduleId:
isVisable = true
break
if isVisable:
for i in 1..<result.len:
if result[i].kind == nkExprColonExpr:
result[i][1].flags.incl nfSkipFieldChecking
else:
for i in 0..<n.len:
result[i] = semGenericStmt(c, n[i], flags, ctx)

View File

@@ -73,7 +73,8 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym
# later by semAsgn in return type inference scenario
t = q.typ
else:
localError(c.config, a.info, errCannotInstantiateX % s.name.s)
if q.typ.kind != tyCompositeTypeClass:
localError(c.config, a.info, errCannotInstantiateX % s.name.s)
t = errorType(c)
elif t.kind in {tyGenericParam, tyConcept}:
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
@@ -145,7 +146,18 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
if sfGenSym in param.flags:
idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
freshGenSyms(c, b, result, orig, symMap)
b = semProcBody(c, b)
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
if result.kind == skMacro:
sysTypeFromName(c.graph, n.info, "NimNode")
elif not isInlineIterator(result.typ):
result.typ[0]
else:
nil
b = semProcBody(c, b, resultType)
result.ast[bodyPos] = hloBody(c, b)
excl(result.flags, sfForward)
trackProc(c, result, result.ast[bodyPos])
@@ -359,7 +371,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

View File

@@ -66,6 +66,27 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
if i >= x.len: globalError conf, n.info, "invalid field at index " & $i
else: annotateType(n[i], x[i], conf)
elif x.kind == tyProc and x.callConv == ccClosure:
n.typ = t
elif x.kind == tyOpenArray: # `opcSlice` transforms slices into tuples
if n.kind == nkTupleConstr:
let
bracketExpr = newNodeI(nkBracket, n.info)
left = int n[1].intVal
right = int n[2].intVal
bracketExpr.flags = n.flags
case n[0].kind # is this a string slice or a array slice
of nkStrKinds:
for i in left..right:
bracketExpr.add newIntNode(nkCharLit, BiggestInt n[0].strVal[i])
annotateType(bracketExpr[^1], t[0], conf)
of nkBracket:
for i in left..right:
bracketExpr.add n[0][i]
annotateType(bracketExpr[^1], t[0], conf)
else:
globalError(conf, n.info, "Incorrectly generated tuple constr")
n[] = bracketExpr[]
n.typ = t
else:
globalError(conf, n.info, "() must have a tuple type")

View File

@@ -51,7 +51,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``.
@@ -195,6 +195,10 @@ 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 "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)
@@ -460,7 +464,7 @@ proc semPrivateAccess(c: PContext, n: PNode): PNode =
result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid))
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
flags: TExprFlags): PNode =
flags: TExprFlags; expectedType: PType = nil): PNode =
## This is the preferred code point to implement magics.
## ``c`` the current module, a symbol table to a very good approximation
## ``n`` the ast like it would be passed to a real macro
@@ -583,5 +587,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result = n
of mPrivateAccess:
result = semPrivateAccess(c, n)
of mArrToSeq:
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
else:
result = n

View File

@@ -72,14 +72,17 @@ proc semConstrField(c: PContext, flags: TExprFlags,
let assignment = locateFieldInInitExpr(c, field, initExpr)
if assignment != nil:
if nfSem in assignment.flags: return assignment[1]
if not fieldVisible(c, field):
if nfSkipFieldChecking in assignment[1].flags:
discard
elif not fieldVisible(c, field):
localError(c.config, initExpr.info,
"the field '$1' is not accessible." % [field.name.s])
return
var initValue = semExprFlagDispatched(c, assignment[1], flags)
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
@@ -375,13 +378,19 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
else:
assert false, "Must not enter here."
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
var t = semTypeNode(c, n[0], nil)
result = newNodeIT(nkObjConstr, n.info, t)
for child in n: result.add child
if t == nil:
return localErrorNode(c, result, "object constructor needs an object type")
if t.skipTypes({tyGenericInst,
tyAlias, tySink, tyOwned, tyRef}).kind != tyObject and
expectedType != nil and expectedType.skipTypes({tyGenericInst,
tyAlias, tySink, tyOwned, tyRef}).kind == tyObject:
t = expectedType
t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned})
if t.kind == tyRef:
@@ -392,8 +401,12 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
# multiple times as long as they don't have closures.
result.typ.flags.incl tfHasOwned
if t.kind != tyObject:
return localErrorNode(c, result,
"object constructor needs an object type".dup(addDeclaredLoc(c.config, t)))
return localErrorNode(c, result, if t.kind != tyGenericBody:
"object constructor needs an object type".dup(addDeclaredLoc(c.config, t))
else: "cannot instantiate: '" &
typeToString(t, preferDesc) &
"'; the object's generic parameters cannot be inferred and must be explicitly given"
)
# Check if the object is fully initialized by recursively testing each
# field (if this is a case object, initialized fields in two different

View File

@@ -402,6 +402,9 @@ proc transformSlices(g: ModuleGraph; idgen: IdGenerator; n: PNode): PNode =
let op = n[0].sym
if op.name.s == "[]" and op.fromSystem:
result = copyNode(n)
var typ = newType(tyOpenArray, nextTypeId(g.idgen), result.typ.owner)
typ.add result.typ[0]
result.typ = typ
let opSlice = newSymNode(createMagic(g, idgen, "slice", mSlice))
opSlice.typ = getSysType(g, n.info, tyInt)
result.add opSlice

View File

@@ -1076,7 +1076,7 @@ proc track(tracked: PEffects, n: PNode) =
elif child.kind == nkVarTuple and last.kind != nkEmpty:
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
initVar(tracked, child[i], volatileCheck=false)
if last.kind in {nkPar, nkTupleConstr}:
@@ -1216,6 +1216,11 @@ proc track(tracked: PEffects, n: PNode) =
message(tracked.config, n.info, warnCstringConv,
"implicit conversion to 'cstring' from a non-const location: $1; this will become a compile time error in the future" %
$n[1])
if n.typ.skipTypes(abstractInst).kind == tyCstring and
isCharArrayPtr(n[1].typ, true):
message(tracked.config, n.info, warnPtrToCstringConv,
$n[1].typ)
let t = n.typ.skipTypes(abstractInst)
if t.kind == tyEnum:
@@ -1393,6 +1398,9 @@ proc hasRealBody(s: PSym): bool =
proc trackProc*(c: PContext; s: PSym, body: PNode) =
let g = c.graph
when defined(nimsuggest):
if g.config.expandDone():
return
var effects = s.typ.n[0]
if effects.kind != nkEffectList: return
# effects already computed?
@@ -1429,7 +1437,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

@@ -36,6 +36,16 @@ const
errRecursiveDependencyX = "recursive dependency: '$1'"
errRecursiveDependencyIteratorX = "recursion is not supported in iterators: '$1'"
errPragmaOnlyInHeaderOfProcX = "pragmas are only allowed in the header of a proc; redefinition of $1"
errCannotAssignToGlobal = "cannot assign local to global variable"
proc implicitlyDiscardable(n: PNode): bool
proc hasEmpty(typ: PType): bool =
if typ.kind in {tySequence, tyArray, tySet}:
result = typ.lastSon.kind == tyEmpty
elif typ.kind == tyTuple:
for s in typ.sons:
result = result or hasEmpty(s)
proc semDiscard(c: PContext, n: PNode): PNode =
result = n
@@ -44,7 +54,9 @@ proc semDiscard(c: PContext, n: PNode): PNode =
n[0] = semExprWithType(c, n[0])
let sonType = n[0].typ
let sonKind = n[0].kind
if isEmptyType(sonType) or sonType.kind in {tyNone, tyTypeDesc} or sonKind == nkTypeOfExpr:
if isEmptyType(sonType) or hasEmpty(sonType) or
sonType.kind in {tyNone, tyTypeDesc} or
sonKind == nkTypeOfExpr:
localError(c.config, n.info, errInvalidDiscard)
if sonType.kind == tyProc and sonKind notin nkCallKinds:
# tyProc is disallowed to prevent ``discard foo`` to be valid, when ``discard foo()`` is meant.
@@ -86,7 +98,7 @@ proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
result = n
checkSonsLen(n, 2, c.config)
openScope(c)
n[0] = forceBool(c, semExprWithType(c, n[0]))
n[0] = forceBool(c, semExprWithType(c, n[0], expectedType = getSysType(c.graph, n.info, tyBool)))
inc(c.p.nestedLoopCounter)
n[1] = semStmt(c, n[1], flags)
dec(c.p.nestedLoopCounter)
@@ -95,18 +107,20 @@ proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
result.typ = c.enforceVoidContext
elif efInTypeof in flags:
result.typ = n[1].typ
elif implicitlyDiscardable(n[1]):
result[1].typ = c.enforceVoidContext
proc semProc(c: PContext, n: PNode): PNode
proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}): PNode =
result = semExpr(c, n, flags)
proc semExprBranch(c: PContext, n: PNode; flags: TExprFlags = {}; expectedType: PType = nil): PNode =
result = semExpr(c, n, flags, expectedType)
if result.typ != nil:
# XXX tyGenericInst here?
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
proc semExprBranchScope(c: PContext, n: PNode): PNode =
proc semExprBranchScope(c: PContext, n: PNode; expectedType: PType = nil): PNode =
openScope(c)
result = semExprBranch(c, n)
result = semExprBranch(c, n, expectedType = expectedType)
closeScope(c)
const
@@ -139,8 +153,13 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
var n = newNodeI(nkDiscardStmt, result.info, 1)
n[0] = result
elif result.typ.kind != tyError and c.config.cmd != cmdInteractive:
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: n = n.lastSon
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
@@ -150,22 +169,27 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
s.add "; for a function call use ()"
localError(c.config, n.info, s)
proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
proc semIf(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
result = n
var typ = commonTypeBegin
var expectedType = expectedType
var hasElse = false
for i in 0..<n.len:
var it = n[i]
if it.len == 2:
openScope(c)
it[0] = forceBool(c, semExprWithType(c, it[0]))
it[1] = semExprBranch(c, it[1], flags)
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])
if not endsInNoReturn(it[1]):
expectedType = typ
closeScope(c)
elif it.len == 1:
hasElse = true
it[0] = semExprBranchScope(c, it[0])
it[0] = semExprBranchScope(c, it[0], expectedType)
typ = commonType(c, typ, it[0])
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):
@@ -181,7 +205,7 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
result.transitionSonsKind(nkIfExpr)
result.typ = typ
proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
var check = initIntSet()
template semExceptBranchType(typeNode: PNode): bool =
# returns true if exception type is imported type
@@ -191,6 +215,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
isImported = true
elif not isException(typ):
localError(c.config, typeNode.info, errExprCannotBeRaised)
elif not isDefectOrCatchableError(typ):
message(c.config, a.info, warnBareExcept, "catch a more precise Exception deriving from CatchableError or Defect.")
if containsOrIncl(check, typ.id):
localError(c.config, typeNode.info, errExceptionAlreadyHandled)
@@ -201,8 +227,11 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
checkMinSonsLen(n, 2, c.config)
var typ = commonTypeBegin
n[0] = semExprBranchScope(c, n[0])
typ = commonType(c, typ, n[0].typ)
var expectedType = expectedType
n[0] = semExprBranchScope(c, n[0], expectedType)
if not endsInNoReturn(n[0]):
typ = commonType(c, typ, n[0].typ)
expectedType = typ
var last = n.len - 1
var catchAllExcepts = 0
@@ -230,7 +259,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
elif a.len == 1:
# count number of ``except: body`` blocks
inc catchAllExcepts
message(c.config, a.info, warnBareExcept,
"The bare except clause is deprecated; use `except CatchableError:` instead")
else:
# support ``except KeyError, ValueError, ... : body``
if catchAllExcepts > 0:
@@ -259,9 +289,14 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
localError(c.config, a.info, "Only one general except clause is allowed after more specific exceptions")
# last child of an nkExcept/nkFinally branch is a statement:
a[^1] = semExprBranchScope(c, a[^1])
if a.kind != nkFinally: typ = commonType(c, typ, a[^1])
else: dec last
if a.kind != nkFinally:
a[^1] = semExprBranchScope(c, a[^1], expectedType)
typ = commonType(c, typ, a[^1])
if not endsInNoReturn(a[^1]):
expectedType = typ
else:
a[^1] = semExprBranchScope(c, a[^1])
dec last
closeScope(c)
if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped}:
@@ -271,7 +306,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
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
@@ -352,7 +388,7 @@ proc addToVarSection(c: PContext; result: 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
@@ -379,13 +415,6 @@ proc semUsing(c: PContext; n: PNode): PNode =
if a[^1].kind != nkEmpty:
localError(c.config, a.info, "'using' sections cannot contain assignments")
proc hasEmpty(typ: PType): bool =
if typ.kind in {tySequence, tyArray, tySet}:
result = typ.lastSon.kind == tyEmpty
elif typ.kind == tyTuple:
for s in typ.sons:
result = result or hasEmpty(s)
proc hasUnresolvedParams(n: PNode; flags: TExprFlags): bool =
result = tfUnresolved in n.typ.flags
when false:
@@ -508,6 +537,24 @@ proc errorSymChoiceUseQualifier(c: PContext; n: PNode) =
inc i
localError(c.config, n.info, errGenerated, err)
template isLocalVarSym(n: PNode): bool =
n.kind == nkSym and
n.sym.kind in {skVar, skLet} and not
({sfGlobal, sfPure} * n.sym.flags != {} or
sfCompileTime in n.sym.flags)
proc usesLocalVar(n: PNode): bool =
for z in 1 ..< n.len:
if n[z].isLocalVarSym:
return true
elif n[z].kind in nkCallKinds:
if usesLocalVar(n[z]):
return true
proc globalVarInitCheck(c: PContext, n: PNode) =
if n.isLocalVarSym or n.kind in nkCallKinds and usesLocalVar(n):
localError(c.config, n.info, errCannotAssignToGlobal)
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if n.len == 1:
result = semLowerLetVarCustomPragma(c, n[0], n)
@@ -522,15 +569,17 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if a.kind notin {nkIdentDefs, nkVarTuple}: illFormedAst(a, c.config)
checkMinSonsLen(a, 3, c.config)
var hasUserSpecifiedType = false
var typ: PType = nil
if a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
hasUserSpecifiedType = true
var typFlags: TTypeAllowedFlags
var def: PNode = c.graph.emptyNode
if a[^1].kind != nkEmpty:
def = semExprWithType(c, a[^1], {})
def = semExprWithType(c, a[^1], {}, typ)
if def.kind in nkSymChoices and def[0].typ.skipTypes(abstractInst).kind == tyEnum:
errorSymChoiceUseQualifier(c, def)
@@ -597,6 +646,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
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:
@@ -655,12 +706,16 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if v.kind == skLet and sfImportc notin v.flags:
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)
if a.kind != nkVarTuple:
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)
proc semConst(c: PContext, n: PNode): PNode =
@@ -673,14 +728,16 @@ proc semConst(c: PContext, n: PNode): PNode =
if a.kind notin {nkConstDef, nkVarTuple}: illFormedAst(a, c.config)
checkMinSonsLen(a, 3, c.config)
var hasUserSpecifiedType = false
var typ: PType = nil
if a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
hasUserSpecifiedType = true
var typFlags: TTypeAllowedFlags
# don't evaluate here since the type compatibility check below may add a converter
var def = semExprWithType(c, a[^1])
var def = semExprWithType(c, a[^1], {}, typ)
if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
typFlags.incl taIsTemplateOrMacro
@@ -720,6 +777,8 @@ proc semConst(c: PContext, n: PNode): PNode =
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)
@@ -759,6 +818,9 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
var iterAfterVarLent = iter.skipTypes({tyGenericInst, tyAlias, tyLent, tyVar})
# n.len == 3 means that there is one for loop variable
# and thus no tuple unpacking:
if iterAfterVarLent.kind == tyEmpty:
localError(c.config, n[^2].info, "cannot infer element type of $1" %
renderTree(n[^2], {renderNoComments}))
if iterAfterVarLent.kind != tyTuple or n.len == 3:
if n.len == 3:
if n[0].kind == nkVarTuple:
@@ -907,7 +969,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
toResolve.add n[0]
var errors: CandidateErrors
var r = resolveOverloads(c, toResolve, toResolve, {skTemplate, skMacro}, {},
var r = resolveOverloads(c, toResolve, toResolve, {skTemplate, skMacro}, {efNoDiagnostics},
errors, false)
if r.state == csMatch:
var match = r.calleeSym
@@ -920,7 +982,11 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
case match.kind
of skMacro: result = semMacroExpr(c, toExpand, toExpand, match, flags)
of skTemplate: result = semTemplateExpr(c, toExpand, match, flags)
else: result = nil
else: result = errorNode(c, n[0])
elif r.state == csNoMatch:
result = errorNode(c, n[0])
if result.kind == nkEmpty:
localError(c.config, n[0].info, errSelectorMustBeOfCertainTypes)
# this would be the perfectly consistent solution with 'for loop macros',
# but it kinda sucks for pattern matching as the matcher is not attached to
# a type then:
@@ -935,7 +1001,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
@@ -967,7 +1034,7 @@ proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
result.typ = result.lastSon.typ
closeScope(c)
proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
result = n
checkMinSonsLen(n, 2, c.config)
openScope(c)
@@ -976,6 +1043,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
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}
@@ -990,12 +1058,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
else:
popCaseContext(c)
closeScope(c)
if caseStmtMacros in c.features:
result = handleCaseStmtMacro(c, n, flags)
if result != nil:
return result
localError(c.config, n[0].info, errSelectorMustBeOfCertainTypes)
return
return handleCaseStmtMacro(c, n, flags)
for i in 1..<n.len:
setCaseContextIdx(c, i)
var x = n[i]
@@ -1007,20 +1070,26 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
checkMinSonsLen(x, 2, c.config)
semCaseBranch(c, n, x, i, covered)
var last = x.len-1
x[last] = semExprBranchScope(c, x[last])
x[last] = semExprBranchScope(c, x[last], expectedType)
typ = commonType(c, typ, x[last])
if not endsInNoReturn(x[last]):
expectedType = typ
of nkElifBranch:
chckCovered = false
checkSonsLen(x, 2, c.config)
openScope(c)
x[0] = forceBool(c, semExprWithType(c, x[0]))
x[1] = semExprBranch(c, x[1])
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])
if not endsInNoReturn(x[1]):
expectedType = typ
closeScope(c)
of nkElse:
checkSonsLen(x, 1, c.config)
x[0] = semExprBranchScope(c, x[0])
x[0] = semExprBranchScope(c, x[0], expectedType)
typ = commonType(c, typ, x[0])
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
@@ -1234,6 +1303,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
if s.magic == mNone and a[2].kind == nkEmpty:
localError(c.config, a.info, errImplOfXexpected % s.name.s)
if s.magic != mNone: processMagicType(c, s)
let oldFlags = s.typ.flags
if a[1].kind != nkEmpty:
# We have a generic type declaration here. In generic types,
# symbol lookup needs to be done here.
@@ -1261,6 +1331,13 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
if body != nil:
body.sym = s
body.size = -1 # could not be computed properly
if body.kind == tyObject:
# add flags applied to generic type to object (nominal) type
incl(body.flags, oldFlags)
# {.inheritable, final.} is already disallowed, but
# object might have been assumed to be final
if tfInheritable in oldFlags and tfFinal in body.flags:
excl(body.flags, tfFinal)
s.typ[^1] = body
if tfCovariant in s.typ.flags:
checkCovariantParamsUsages(c, s.typ)
@@ -1312,8 +1389,16 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
internalAssert c.config, st.kind in {tyPtr, tyRef}
internalAssert c.config, st.lastSon.sym == nil
incl st.flags, tfRefsAnonObj
let objTy = st.lastSon
# add flags for `ref object` etc to underlying `object`
incl(objTy.flags, oldFlags)
# {.inheritable, final.} is already disallowed, but
# object might have been assumed to be final
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)
obj.flags.incl sfGeneratedType
let symNode = newSymNode(obj)
obj.ast = a.shallowCopy
case a[0].kind
@@ -1327,8 +1412,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
obj.ast[2] = a[2][0]
if sfPure in s.flags:
obj.flags.incl sfPure
obj.typ = st.lastSon
st.lastSon.sym = obj
obj.typ = objTy
objTy.sym = obj
proc checkForMetaFields(c: PContext; n: PNode) =
proc checkMeta(c: PContext; n: PNode; t: PType) =
@@ -1614,7 +1699,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode {.nosinks.} =
addParams(c, params, skProc)
pushProcCon(c, s)
addResult(c, n, n.typ[0], skProc)
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], n.typ[0]))
trackProc(c, s, s.ast[bodyPos])
popProcCon(c)
popOwner(c)
@@ -1715,6 +1800,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
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
@@ -2036,7 +2126,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# allowed, everything else, including a nullary generic is an error.
pushProcCon(c, s)
addResult(c, n, s.typ[0], skProc)
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], s.typ[0]))
trackProc(c, s, s.ast[bodyPos])
popProcCon(c)
elif efOperand notin flags:
@@ -2049,8 +2139,15 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
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
# semantic checking also needed with importc in case used in VM
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos]))
s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], resultType))
# unfortunately we cannot skip this step when in 'system.compiles'
# context as it may even be evaluated in 'system.compiles':
trackProc(c, s, s.ast[bodyPos])
@@ -2070,8 +2167,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if hasProto: localError(c.config, n.info, errImplOfXexpected % proto.name.s)
if {sfImportc, sfBorrow, sfError} * s.flags == {} and s.magic == mNone:
# this is a forward declaration and we're building the prototype
if s.kind in {skProc, skFunc} and s.typ[0] != nil and s.typ[0].kind == tyUntyped:
# `auto` is represented as `tyUntyped` at this point in compilation.
if s.kind in {skProc, skFunc} and s.typ[0] != nil and s.typ[0].kind == tyAnything:
localError(c.config, n[paramsPos][0].info, "return type 'auto' cannot be used in forward declarations")
incl(s.flags, sfForward)
@@ -2157,7 +2253,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
@@ -2172,7 +2267,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
@@ -2227,7 +2321,7 @@ proc setLine(n: PNode, info: TLineInfo) =
for i in 0..<n.safeLen: setLine(n[i], info)
n.info = info
proc semPragmaBlock(c: PContext, n: PNode): PNode =
proc semPragmaBlock(c: PContext, n: PNode; expectedType: PType = nil): PNode =
checkSonsLen(n, 2, c.config)
let pragmaList = n[0]
pragma(c, nil, pragmaList, exprPragmas, isStatement = true)
@@ -2244,7 +2338,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
localError(c.config, p.info, "invalid pragma block: " & $p)
inc c.inUncheckedAssignSection, inUncheckedAssignSection
n[1] = semExpr(c, n[1])
n[1] = semExpr(c, n[1], expectedType = expectedType)
dec c.inUncheckedAssignSection, inUncheckedAssignSection
result = n
result.typ = n[1].typ
@@ -2293,7 +2387,7 @@ proc inferConceptStaticParam(c: PContext, inferred, n: PNode) =
"attempt to equate '%s' and '%s'." % [inferred.renderTree, $res.typ, $typ.base])
typ.n = res
proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType = nil): PNode =
result = n
result.transitionSonsKind(nkStmtList)
var voidContext = false
@@ -2306,7 +2400,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
# nkNilLit, nkEmpty}:
# dec last
for i in 0..<n.len:
var x = semExpr(c, n[i], flags)
var x = semExpr(c, n[i], flags, if i == n.len - 1: expectedType else: nil)
n[i] = x
if c.matchedConcept != nil and x.typ != nil and
(nfFromTemplate notin n.flags or i != last):
@@ -2338,9 +2432,10 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
n.typ = n[i].typ
if not isEmptyType(n.typ): n.transitionSonsKind(nkStmtListExpr)
if n[i].kind in nkLastBlockStmts or
n[i].kind in nkCallKinds and n[i][0].kind == nkSym and
sfNoReturn in n[i][0].sym.flags:
var m = n[i]
while m.kind in {nkStmtListExpr, nkStmtList} and m.len > 0: # from templates
m = m.lastSon
if endsInNoReturn(m):
for j in i + 1..<n.len:
case n[j].kind
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkState: discard

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
@@ -78,7 +81,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
result = newNodeIT(kind, info, newTypeS(tyNone, c))
a = initOverloadIter(o, c, n)
while a != nil:
if a.kind != skModule and (not isField or sfGenSym notin s.flags):
if a.kind != skModule and (not isField or sfGenSym notin a.flags):
incl(a.flags, sfUsed)
markOwnerModuleAsUsed(c, a)
result.add newSymNode(a, info)
@@ -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
@@ -187,11 +186,12 @@ proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
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]
var x = n
while true:
case x.kind
of nkPostfix: x = x[1]
@@ -206,7 +206,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
illFormedAst(x, c.c.config)
let ident = getIdentNode(c, x)
if not isTemplParam(c, ident):
c.toInject.incl(x.ident.id)
if k != skField: c.toInject.incl(x.ident.id)
else:
replaceIdentBySym(c.c, n, ident)
else:
@@ -227,7 +227,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
closeScope(c)
let ident = getIdentNode(c, n)
if not isTemplParam(c, ident):
if n.kind != nkSym:
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)
@@ -331,21 +331,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)
@@ -380,6 +383,8 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
result = newSymNode(s, n.info)
onUse(n.info, s)
else:
if s.kind in {skType, skVar, skLet, skConst}:
discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule})
result = semTemplSymbol(c.c, n, s, c.noGenSym > 0)
of nkBind:
result = semTemplBody(c, n[0])
@@ -483,6 +488,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:
@@ -546,6 +570,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:
@@ -557,13 +582,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:
@@ -643,6 +678,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# 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
param.flags.incl sfTemplateParam

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"
errSetTooBig = "set is too large"
errBaseTypeMustBeOrdinal = "base type of a set must be an ordinal"
@@ -141,6 +142,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:
if overloadableEnums in c.features:
@@ -151,7 +153,11 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
declarePureEnumField(c, e)
if isPure and (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:
@@ -212,10 +218,34 @@ proc semVarOutType(c: PContext, n: PNode, prev: PType; kind: TTypeKind): PType =
else:
result = newConstraint(c, kind)
proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool =
if t == nil:
return false
if cycleDetector.containsOrIncl(t.id):
return true
case t.kind
of tyAlias, tyGenericInst, tyDistinct:
return isRecursiveType(t.lastSon, cycleDetector)
else:
return false
proc isRecursiveType*(t: PType): bool =
# handle simple recusive types before typeFinalPass
var cycleDetector = initIntSet()
isRecursiveType(t, cycleDetector)
proc addSonSkipIntLitChecked(c: PContext; father, son: PType; it: PNode, id: IdGenerator) =
let s = son.skipIntLit(id)
father.sons.add(s)
if isRecursiveType(s):
localError(c.config, it.info, "illegal recursion in type '" & typeToString(s) & "'")
else:
propagateToOwner(father, s)
proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
if n.len == 0: return newConstraint(c, tyDistinct)
result = newOrPrevType(tyDistinct, prev, c)
addSonSkipIntLit(result, semTypeNode(c, n[0], nil), c.idgen)
addSonSkipIntLitChecked(c, result, semTypeNode(c, n[0], nil), n[0], c.idgen)
if n.len > 1: result.n = n[1]
proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
@@ -247,7 +277,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]))
@@ -258,9 +288,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")
@@ -296,6 +325,8 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
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:
let e = semExprWithType(c, n, {efDetermineType})
if e.typ.kind == tyFromExpr:
@@ -308,7 +339,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
elif e.kind == nkSym and e.typ.kind == tyStatic:
if e.sym.ast != nil:
return semArrayIndex(c, e.sym.ast)
if not isOrdinalType(e.typ.lastSon):
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)
result = makeRangeWithStaticExpr(c, e)
@@ -447,7 +478,8 @@ proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
localError(c.config, n.info, errTypeExpected)
result = newOrPrevType(tyTuple, prev, c)
for it in n:
addSonSkipIntLit(result, semTypeNode(c, it, nil), c.idgen)
let t = semTypeNode(c, it, nil)
addSonSkipIntLitChecked(c, result, t, it, c.idgen)
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
var typ: PType
@@ -729,9 +761,10 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
if n == nil: return
case n.kind
of nkRecWhen:
var a = copyTree(n)
var branch: PNode = nil # the branch to take
for i in 0..<n.len:
var it = n[i]
for i in 0..<a.len:
var it = a[i]
if it == nil: illFormedAst(n, c.config)
var idx = 1
case it.kind
@@ -757,7 +790,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
semRecordNodeAux(c, it[idx], newCheck, newPos, newf, rectype, hasCaseFields)
it[idx] = if newf.len == 1: newf[0] else: newf
if c.inGenericContext > 0:
father.add n
father.add a
elif branch != nil:
semRecordNodeAux(c, branch, check, pos, father, rectype, hasCaseFields)
elif father.kind in {nkElse, nkOfBranch}:
@@ -849,12 +882,18 @@ 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): bool =
if (not isPartial) and (obj.kind notin {tyObject, tyGenericParam} or tfFinal in obj.flags):
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)
addInheritedFieldsAux(c, check, pos, obj.n)
else:
result = true
proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType =
if n.len == 0:
@@ -881,7 +920,9 @@ 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)
else:
if concreteBase.kind != tyError:
localError(c.config, n[1].info, "inheritance only works with non-final objects; " &
@@ -899,7 +940,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`:
@@ -1248,7 +1291,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if hasDefault:
def = a[^1]
block determineType:
if genericParams.isGenericParams:
if genericParams != nil and genericParams.len > 0:
def = semGenericStmt(c, def)
if hasUnresolvedArgs(c, def):
def.typ = makeTypeFromExpr(c, def.copyTree)
@@ -1345,9 +1388,7 @@ 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:
# 'p(): auto' and 'p(): untyped' are equivalent, but the rest of the
# compiler is hardly aware of 'auto':
r = newTypeS(tyUntyped, c)
discard
elif r.kind == tyStatic:
# type allowed should forbid this type
discard
@@ -1376,7 +1417,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
result.flags.excl tfHasMeta
result.n.typ = r
if genericParams.isGenericParams:
if genericParams != nil and genericParams.len > 0:
for n in genericParams:
if {sfUsed, sfAnon} * n.sym.flags == {}:
result.flags.incl tfUnresolved
@@ -1412,19 +1453,21 @@ 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)
@@ -1504,7 +1547,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)
@@ -1993,8 +2037,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkStmtListType: result = semStmtListType(c, n, prev)
of nkBlockType: result = semBlockType(c, n, prev)
else:
localError(c.config, n.info, "type expected, but got: " & renderTree(n))
result = newOrPrevType(tyError, prev, c)
result = semTypeExpr(c, n, prev)
when false:
localError(c.config, n.info, "type expected, but got: " & renderTree(n))
result = newOrPrevType(tyError, prev, c)
n.typ = result
dec c.inTypeContext

View File

@@ -43,7 +43,8 @@ proc searchInstTypes*(g: ModuleGraph; key: PType): PType =
# XXX: This happens for prematurely cached
# types such as Channel[empty]. Why?
# See the notes for PActor in handleGenericInvocation
return
# if this is return the same type gets cached more than it needs to
continue
if not sameFlags(inst, key):
continue
@@ -190,6 +191,24 @@ proc replaceObjBranches(cl: TReplTypeVars, n: PNode): PNode =
for i in 0..<n.len:
n[i] = replaceObjBranches(cl, n[i])
proc hasValuelessStatics(n: PNode): bool =
# We should only attempt to call an expression that has no tyStatics
# As those are unresolved generic parameters, which means in the following
# The compiler attempts to do `T == 300` which errors since the typeclass `MyThing` lacks a parameter
#[
type MyThing[T: static int] = object
when T == 300:
a
proc doThing(_: MyThing)
]#
if n.safeLen == 0 and n.kind != nkEmpty: # Some empty nodes can get in here
n.typ == nil or n.typ.kind == tyStatic
else:
for x in n:
if hasValuelessStatics(x):
return true
false
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
if n == nil: return
result = copyNode(n)
@@ -214,10 +233,11 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
of nkElifBranch:
checkSonsLen(it, 2, cl.c.config)
var cond = prepareNode(cl, it[0])
var e = cl.c.semConstExpr(cl.c, cond)
if e.kind != nkIntLit:
internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool")
if e.intVal != 0 and branch == nil: branch = it[1]
if not cond.hasValuelessStatics:
var e = cl.c.semConstExpr(cl.c, cond)
if e.kind != nkIntLit:
internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool")
if e.intVal != 0 and branch == nil: branch = it[1]
of nkElse:
checkSonsLen(it, 1, cl.c.config)
if branch == nil: branch = it[0]
@@ -496,17 +516,30 @@ proc propagateFieldFlags(t: PType, n: PNode) =
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
template bailout =
if cl.recursionLimit > 100:
# bail out, see bug #2509. But note this caching is in general wrong,
# look at this example where TwoVectors should not share the generic
# instantiations (bug #3112):
# type
# Vector[N: static[int]] = array[N, float64]
# TwoVectors[Na, Nb: static[int]] = (Vector[Na], Vector[Nb])
result = PType(idTableGet(cl.localCache, t))
if result != nil: return result
inc cl.recursionLimit
if (t.sym == nil) or (t.sym != nil and sfGeneratedType in t.sym.flags):
# In the first case 't.sym' can be 'nil' if the type is a ref/ptr, see
# issue https://github.com/nim-lang/Nim/issues/20416 for more details.
# Fortunately for us this works for now because partial ref/ptr types are
# not allowed in object construction, eg.
# type
# Container[T] = ...
# O = object
# val: ref Container
#
# In the second case only consider the recursion limit if the symbol is a
# type with generic parameters that have not been explicitly supplied,
# typechecking should terminate when generic parameters are explicitly
# supplied.
if cl.recursionLimit > 100:
# bail out, see bug #2509. But note this caching is in general wrong,
# look at this example where TwoVectors should not share the generic
# instantiations (bug #3112):
# type
# Vector[N: static[int]] = array[N, float64]
# TwoVectors[Na, Nb: static[int]] = (Vector[Na], Vector[Nb])
result = PType(idTableGet(cl.localCache, t))
if result != nil: return result
inc cl.recursionLimit
result = t
if t == nil: return

View File

@@ -9,14 +9,14 @@
## Computes hash values for routine (proc, method etc) signatures.
import ast, tables, ropes, md5, modulegraphs
import ast, tables, ropes, md5, modulegraphs, options, msgs, packages, pathutils
from hashes import Hash
import types
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
proc `&=`(c: var MD5Context, ch: char) =
# XXX suspicious code here; relies on ch being zero terminated?
md5Update(c, unsafeAddr ch, 1)
md5Update(c, cast[cstring](unsafeAddr ch), 1)
proc `&=`(c: var MD5Context, r: Rope) =
for l in leaves(r): md5Update(c, l.cstring, l.len)
proc `&=`(c: var MD5Context, i: BiggestInt) =
@@ -39,8 +39,7 @@ type
CoDistinct
CoHashTypeInsideNode
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag])
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: ConfigRef)
proc hashSym(c: var MD5Context, s: PSym) =
if sfAnon in s.flags or s.kind == skGenericParam:
c &= ":anon"
@@ -51,20 +50,21 @@ proc hashSym(c: var MD5Context, s: PSym) =
c &= "."
it = it.owner
proc hashTypeSym(c: var MD5Context, s: PSym) =
proc hashTypeSym(c: var MD5Context, s: PSym; conf: ConfigRef) =
if sfAnon in s.flags or s.kind == skGenericParam:
c &= ":anon"
else:
var it = s
c &= customPath(conf.toFullPath(s.info))
while it != nil:
if sfFromGeneric in it.flags and it.kind in routineKinds and
it.typ != nil:
hashType c, it.typ, {CoProc}
hashType c, it.typ, {CoProc}, conf
c &= it.name.s
c &= "."
it = it.owner
proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]) =
proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]; conf: ConfigRef) =
if n == nil:
c &= "\255"
return
@@ -79,7 +79,7 @@ proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]) =
of nkSym:
hashSym(c, n.sym)
if CoHashTypeInsideNode in flags and n.sym.typ != nil:
hashType(c, n.sym.typ, flags)
hashType(c, n.sym.typ, flags, conf)
of nkCharLit..nkUInt64Lit:
let v = n.intVal
lowlevel v
@@ -89,9 +89,9 @@ proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]) =
of nkStrLit..nkTripleStrLit:
c &= n.strVal
else:
for i in 0..<n.len: hashTree(c, n[i], flags)
for i in 0..<n.len: hashTree(c, n[i], flags, conf)
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: ConfigRef) =
if t == nil:
c &= "\254"
return
@@ -99,14 +99,14 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
case t.kind
of tyGenericInvocation:
for i in 0..<t.len:
c.hashType t[i], flags
c.hashType t[i], flags, conf
of tyDistinct:
if CoDistinct in flags:
if t.sym != nil: c.hashSym(t.sym)
if t.sym == nil or tfFromGeneric in t.flags:
c.hashType t.lastSon, flags
c.hashType t.lastSon, flags, conf
elif CoType in flags or t.sym == nil:
c.hashType t.lastSon, flags
c.hashType t.lastSon, flags, conf
else:
c.hashSym(t.sym)
of tyGenericInst:
@@ -116,15 +116,15 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
# value for each instantiation, so we hash the generic parameters here:
let normalizedType = t.skipGenericAlias
for i in 0..<normalizedType.len - 1:
c.hashType t[i], flags
c.hashType t[i], flags, conf
else:
c.hashType t.lastSon, flags
c.hashType t.lastSon, flags, conf
of tyAlias, tySink, tyUserTypeClasses, tyInferred:
c.hashType t.lastSon, flags
c.hashType t.lastSon, flags, conf
of tyOwned:
if CoConsiderOwned in flags:
c &= char(t.kind)
c.hashType t.lastSon, flags
c.hashType t.lastSon, flags, conf
of tyBool, tyChar, tyInt..tyUInt64:
# no canonicalization for integral types, so that e.g. ``pid_t`` is
# produced instead of ``NI``:
@@ -138,7 +138,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
t.typeInst = nil
assert inst.kind == tyGenericInst
for i in 0..<inst.len - 1:
c.hashType inst[i], flags
c.hashType inst[i], flags, conf
t.typeInst = inst
return
c &= char(t.kind)
@@ -150,7 +150,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
# The user has set a specific name for this type
c &= t.sym.loc.r
elif CoOwnerSig in flags:
c.hashTypeSym(t.sym)
c.hashTypeSym(t.sym, conf)
else:
c.hashSym(t.sym)
@@ -169,7 +169,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
# xxx instead, use a hash table to indicate we've already visited a type, which
# would also be more efficient.
symWithFlags.flags.excl {sfAnon, sfGenSym}
hashTree(c, t.n, flags + {CoHashTypeInsideNode})
hashTree(c, t.n, flags + {CoHashTypeInsideNode}, conf)
symWithFlags.flags = oldFlags
else:
# The object has no fields: we _must_ add something here in order to
@@ -179,14 +179,15 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
else:
c &= t.id
if t.len > 0 and t[0] != nil:
hashType c, t[0], flags
hashType c, t[0], flags, conf
of tyRef, tyPtr, tyGenericBody, tyVar:
c &= char(t.kind)
c.hashType t.lastSon, flags
if t.sons.len > 0:
c.hashType t.lastSon, flags, conf
if tfVarIsPtr in t.flags: c &= ".varisptr"
of tyFromExpr:
c &= char(t.kind)
c.hashTree(t.n, {})
c.hashTree(t.n, {}, conf)
of tyTuple:
c &= char(t.kind)
if t.n != nil and CoType notin flags:
@@ -195,19 +196,19 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
assert(t.n[i].kind == nkSym)
c &= t.n[i].sym.name.s
c &= ':'
c.hashType(t[i], flags+{CoIgnoreRange})
c.hashType(t[i], flags+{CoIgnoreRange}, conf)
c &= ','
else:
for i in 0..<t.len: c.hashType t[i], flags+{CoIgnoreRange}
for i in 0..<t.len: c.hashType t[i], flags+{CoIgnoreRange}, conf
of tyRange:
if CoIgnoreRange notin flags:
c &= char(t.kind)
c.hashTree(t.n, {})
c.hashType(t[0], flags)
c.hashTree(t.n, {}, conf)
c.hashType(t[0], flags, conf)
of tyStatic:
c &= char(t.kind)
c.hashTree(t.n, {})
c.hashType(t[0], flags)
c.hashTree(t.n, {}, conf)
c.hashType(t[0], flags, conf)
of tyProc:
c &= char(t.kind)
c &= (if tfIterator in t.flags: "iterator " else: "proc ")
@@ -217,11 +218,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
let param = params[i].sym
c &= param.name.s
c &= ':'
c.hashType(param.typ, flags)
c.hashType(param.typ, flags, conf)
c &= ','
c.hashType(t[0], flags)
c.hashType(t[0], flags, conf)
else:
for i in 0..<t.len: c.hashType(t[i], flags)
for i in 0..<t.len: c.hashType(t[i], flags, conf)
c &= char(t.callConv)
# purity of functions doesn't have to affect the mangling (which is in fact
# problematic for HCR - someone could have cached a pointer to another
@@ -233,10 +234,10 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
if tfVarargs in t.flags: c &= ".varargs"
of tyArray:
c &= char(t.kind)
for i in 0..<t.len: c.hashType(t[i], flags-{CoIgnoreRange})
for i in 0..<t.len: c.hashType(t[i], flags-{CoIgnoreRange}, conf)
else:
c &= char(t.kind)
for i in 0..<t.len: c.hashType(t[i], flags)
for i in 0..<t.len: c.hashType(t[i], flags, conf)
if tfNotNil in t.flags and CoType notin flags: c &= "not nil"
when defined(debugSigHashes):
@@ -253,19 +254,19 @@ when defined(debugSigHashes):
# select hash, type from sighashes where hash in
# (select hash from sighashes group by hash having count(*) > 1) order by hash;
proc hashType*(t: PType; flags: set[ConsiderFlag] = {CoType}): SigHash =
proc hashType*(t: PType; conf: ConfigRef; flags: set[ConsiderFlag] = {CoType}): SigHash =
var c: MD5Context
md5Init c
hashType c, t, flags+{CoOwnerSig}
hashType c, t, flags+{CoOwnerSig}, conf
md5Final c, result.MD5Digest
when defined(debugSigHashes):
db.exec(sql"INSERT OR IGNORE INTO sighashes(type, hash) VALUES (?, ?)",
typeToString(t), $result)
proc hashProc*(s: PSym): SigHash =
proc hashProc*(s: PSym; conf: ConfigRef): SigHash =
var c: MD5Context
md5Init c
hashType c, s.typ, {CoProc}
hashType c, s.typ, {CoProc}, conf
var m = s
while m.kind != skModule: m = m.owner
@@ -311,9 +312,9 @@ proc hashOwner*(s: PSym): SigHash =
md5Final c, result.MD5Digest
proc sigHash*(s: PSym): SigHash =
proc sigHash*(s: PSym; conf: ConfigRef): SigHash =
if s.kind in routineKinds and s.typ != nil:
result = hashProc(s)
result = hashProc(s, conf)
else:
result = hashNonProc(s)
@@ -374,7 +375,7 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash =
var c: MD5Context
md5Init(c)
c.hashType(sym.typ, {CoProc})
c.hashType(sym.typ, {CoProc}, graph.config)
c &= char(sym.kind)
c.md5Final(result.MD5Digest)
graph.symBodyHashes[sym.id] = result # protect from recursion in the body
@@ -387,12 +388,12 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash =
graph.symBodyHashes[sym.id] = result
proc idOrSig*(s: PSym, currentModule: string,
sigCollisions: var CountTable[SigHash]): Rope =
sigCollisions: var CountTable[SigHash]; conf: ConfigRef): Rope =
if s.kind in routineKinds and s.typ != nil:
# signatures for exported routines are reliable enough to
# produce a unique name and this means produced C++ is more stable regarding
# Nim changes:
let sig = hashProc(s)
let sig = hashProc(s, conf)
result = rope($sig)
#let m = if s.typ.callConv != ccInline: findPendingModule(m, s) else: m
let counter = sigCollisions.getOrDefault(sig)

View File

@@ -211,7 +211,7 @@ proc sumGeneric(t: PType): int =
# and Foo[T] has the value 2 so that we know Foo[Foo[T]] is more
# specific than Foo[T].
var t = t
var isvar = 1
var isvar = 0
while true:
case t.kind
of tyGenericInst, tyArray, tyRef, tyPtr, tyDistinct, tyUncheckedArray,
@@ -247,6 +247,8 @@ proc sumGeneric(t: PType): int =
of tyBool, tyChar, tyEnum, tyObject, tyPointer,
tyString, tyCstring, tyInt..tyInt64, tyFloat..tyFloat128,
tyUInt..tyUInt64, tyCompositeTypeClass:
return isvar + 1
of tyBuiltInTypeClass:
return isvar
else:
return 0
@@ -362,7 +364,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
of tyOwned:
# bug #11257: the comparison system.`==`[T: proc](x, y: T) works
# better without the 'owned' type:
if f != nil and f.len > 0 and f[0].skipTypes({tyBuiltInTypeClass}).kind == tyProc:
if f != nil and f.len > 0 and f[0].skipTypes({tyBuiltInTypeClass, tyOr}).kind == tyProc:
result = t.lastSon
else:
result = t
@@ -1169,7 +1171,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
of tyArray:
var fRange = f[0]
var aRange = a[0]
if fRange.kind == tyGenericParam:
if fRange.kind in {tyGenericParam, tyAnything}:
var prev = PType(idTableGet(c.bindings, fRange))
if prev == nil:
put(c, fRange, a[0])
@@ -1264,8 +1266,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
result = isSubtype
else:
result = isNone
elif tfNotNil in f.flags and tfNotNil notin a.flags:
result = isNilConversion
of tyNil: result = isNone
else: discard
of tyOrdinal:
@@ -1362,11 +1362,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
else: discard
of tyString:
case a.kind
of tyString:
if tfNotNil in f.flags and tfNotNil notin a.flags:
result = isNilConversion
else:
result = isEqual
of tyString: result = isEqual
of tyNil: result = isNone
else: discard
of tyCstring:
@@ -1501,6 +1497,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if x.kind == tyGenericInvocation:
if f[0] == x[0]:
for i in 1..<f.len:
# Handle when checking against a generic that isn't fully instantiated
if i >= x.len: return
let tr = typeRel(c, f[i], x[i], flags)
if tr <= isSubtype: return
result = isGeneric
@@ -1584,10 +1582,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
c.inheritancePenalty = 0
let x = typeRel(c, branch, aOrig, flags)
maxInheritance = max(maxInheritance, c.inheritancePenalty)
# 'or' implies maximum matching result:
if x > result: result = x
if result >= isSubtype:
if result >= isIntConv:
if result > isGeneric: result = isGeneric
bindingRet result
else:
@@ -1634,6 +1631,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
bindConcreteTypeToUserTypeClass(matched, a)
if doBind: put(c, f, matched)
result = isGeneric
elif a.len > 0 and a.lastSon == f:
# Needed for checking `Y` == `Addable` in the following
#[
type
Addable = concept a, type A
a + a is A
MyType[T: Addable; Y: static T] = object
]#
result = isGeneric
else:
result = isNone
@@ -1679,7 +1685,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
var aa = a
while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:
aa = lastSon(aa)
if aa.kind == tyGenericParam:
if aa.kind in {tyGenericParam} + tyTypeClasses:
# If the constraint is a genericParam or typeClass this isGeneric
return isGeneric
result = typeRel(c, f.base, aa, flags)
if result > isGeneric: result = isGeneric
@@ -1739,11 +1746,22 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
let prev = PType(idTableGet(c.bindings, f))
if prev == nil:
if aOrig.kind == tyStatic:
if f.base.kind != tyNone:
if f.base.kind notin {tyNone, tyGenericParam}:
result = typeRel(c, f.base, a, flags)
if result != isNone and f.n != nil:
if not exprStructuralEquivalent(f.n, aOrig.n):
result = isNone
elif f.base.kind == tyGenericParam:
# Handling things like `type A[T; Y: static T] = object`
if f.base.len > 0: # There is a constraint, handle it
result = typeRel(c, f.base.lastSon, a, flags)
else:
# No constraint
if tfGenericTypeParam in f.flags:
result = isGeneric
else:
# for things like `proc fun[T](a: static[T])`
result = typeRel(c, f.base, a, flags)
else:
result = isGeneric
if result != isNone: put(c, f, aOrig)
@@ -1875,9 +1893,20 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
result.typ = errorType(c)
else:
result.typ = f.skipTypes({tySink})
# keep varness
if arg.typ != nil and arg.typ.kind == tyVar:
result.typ = toVar(result.typ, tyVar, c.idgen)
else:
result.typ = result.typ.skipTypes({tyVar})
if result.typ == nil: internalError(c.graph.config, arg.info, "implicitConv")
result.add c.graph.emptyNode
result.add arg
if arg.typ != nil and arg.typ.kind == tyLent:
let a = newNodeIT(nkHiddenDeref, arg.info, arg.typ[0])
a.add arg
result.add a
else:
result.add arg
proc isLValue(c: PContext; n: PNode): bool {.inline.} =
let aa = isAssignable(nil, n)
@@ -1993,7 +2022,6 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
arg = argSemantized
a = a
c = m.c
if tfHasStatic in fMaybeStatic.flags:
# XXX: When implicit statics are the default
# this will be done earlier - we just have to
@@ -2101,7 +2129,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
result = c.semInferredLambda(c, m.bindings, arg)
elif arg.kind != nkSym:
return nil
elif arg.sym.kind in {skMacro, skTemplate}:
return nil
else:
if arg.sym.ast == nil:
return nil
let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info)
result = newSymNode(inferred, arg.info)
if r == isInferredConvertible:
@@ -2132,7 +2164,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
of isEqual:
inc(m.exactMatches)
result = arg
if skipTypes(f, abstractVar-{tyTypeDesc}).kind == tyTuple or
let ff = skipTypes(f, abstractVar-{tyTypeDesc})
if ff.kind == tyTuple or
(arg.typ != nil and skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple):
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
of isNone:
@@ -2321,7 +2354,9 @@ proc findFirstArgBlock(m: var TCandidate, n: PNode): int =
# checking `nfBlockArg in n[a2].flags` wouldn't work inside templates
if n[a2].kind != nkStmtList: break
let formalLast = m.callee.n[m.callee.n.len - (n.len - a2)]
if formalLast.kind == nkSym and formalLast.sym.ast == nil:
# parameter has to occupy space (no default value, not void or varargs)
if formalLast.kind == nkSym and formalLast.sym.ast == nil and
formalLast.sym.typ.kind notin {tyVoid, tyVarargs}:
result = a2
else: break

View File

@@ -319,10 +319,10 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
typ.align = int16(conf.floatInt64Align)
elif align(length, 8) mod 8 == 0:
typ.size = align(length, 8) div 8
typ.align = int16(conf.floatInt64Align)
typ.align = 1
else:
typ.size = align(length, 8) div 8 + 1
typ.align = int16(conf.floatInt64Align)
typ.align = 1
of tyRange:
computeSizeAlign(conf, typ[0])
typ.size = typ[0].size
@@ -454,9 +454,9 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
setSize typ, 1
of tyInt16, tyUInt16:
setSize typ, 2
of tyInt32, tyUInt32:
of tyInt32, tyUInt32, tyFloat32:
setSize typ, 4
of tyInt64, tyUInt64:
of tyInt64, tyUInt64, tyFloat64, tyFloat:
setSize typ, 8
else:
typ.size = szUnknownSize

View File

@@ -81,7 +81,16 @@ proc cmpSuggestions(a, b: Suggest): int =
# independent of hashing order:
result = cmp(a.name[], b.name[])
proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int =
proc scanForTrailingAsterisk(line: string, start: int): int =
result = 0
while start+result < line.len and line[start+result] in {' ', '\t'}:
inc result
if start+result < line.len and line[start+result] == '*':
inc result
else:
result = 0
proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo; skipTrailingAsterisk: bool = false): int =
let
line = sourceLine(conf, info)
column = toColumn(info)
@@ -103,8 +112,10 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int
result = 0
elif ident[0] in linter.Letters and ident[^1] != '=':
result = identLen(line, column)
if cmpIgnoreStyle(line[column..column + result - 1], ident) != 0:
if cmpIgnoreStyle(line[column..column + result - 1], ident[0..min(result-1,len(ident)-1)]) != 0:
result = 0
if skipTrailingAsterisk and result > 0:
result += scanForTrailingAsterisk(line, column + result)
else:
var sourceIdent: string
result = parseWhile(line, sourceIdent,
@@ -120,7 +131,9 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int
proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo;
quality: range[0..100]; prefix: PrefixMatch;
inTypeContext: bool; scope: int;
useSuppliedInfo = false): Suggest =
useSuppliedInfo = false,
endLine: uint16 = 0,
endCol = 0): Suggest =
new(result)
result.section = section
result.quality = quality
@@ -152,7 +165,10 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info
result.qualifiedPath.add(s.name.s)
if s.typ != nil:
result.forth = typeToString(s.typ)
if section == ideInlayHints:
result.forth = typeToString(s.typ, preferInlayHint)
else:
result.forth = typeToString(s.typ, preferInferredEffects)
else:
result.forth = ""
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
@@ -164,57 +180,97 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info
result.tokenLen = 0
else:
let infox =
if useSuppliedInfo or section in {ideUse, ideHighlight, ideOutline}:
if useSuppliedInfo or section in {ideUse, ideHighlight, ideOutline, ideDeclaration}:
info
else:
s.info
result.filePath = toFullPath(g.config, infox)
result.line = toLinenumber(infox)
result.column = toColumn(infox)
result.tokenLen = if section != ideHighlight:
result.tokenLen = if section notin {ideHighlight, ideInlayHints}:
s.name.s.len
else:
getTokenLenFromSource(g.config, s.name.s, infox)
getTokenLenFromSource(g.config, s.name.s, infox, section == ideInlayHints)
result.version = g.config.suggestVersion
result.endLine = endLine
result.endCol = endCol
proc `$`*(suggest: SuggestInlayHint): string =
result = $suggest.kind
result.add(sep)
result.add($suggest.line)
result.add(sep)
result.add($suggest.column)
result.add(sep)
result.add(suggest.label)
result.add(sep)
result.add($suggest.paddingLeft)
result.add(sep)
result.add($suggest.paddingRight)
result.add(sep)
result.add($suggest.allowInsert)
result.add(sep)
result.add(suggest.tooltip)
proc `$`*(suggest: Suggest): string =
result = $suggest.section
result.add(sep)
if suggest.section == ideHighlight:
if suggest.symkind.TSymKind == skVar and suggest.isGlobal:
result.add("skGlobalVar")
elif suggest.symkind.TSymKind == skLet and suggest.isGlobal:
result.add("skGlobalLet")
if suggest.section == ideInlayHints:
result = $suggest.inlayHintInfo
else:
result = $suggest.section
result.add(sep)
if suggest.section == ideHighlight:
if suggest.symkind.TSymKind == skVar and suggest.isGlobal:
result.add("skGlobalVar")
elif suggest.symkind.TSymKind == skLet and suggest.isGlobal:
result.add("skGlobalLet")
else:
result.add($suggest.symkind.TSymKind)
result.add(sep)
result.add($suggest.line)
result.add(sep)
result.add($suggest.column)
result.add(sep)
result.add($suggest.tokenLen)
else:
result.add($suggest.symkind.TSymKind)
result.add(sep)
result.add($suggest.line)
result.add(sep)
result.add($suggest.column)
result.add(sep)
result.add($suggest.tokenLen)
else:
result.add($suggest.symkind.TSymKind)
result.add(sep)
if suggest.qualifiedPath.len != 0:
result.add(suggest.qualifiedPath.join("."))
result.add(sep)
result.add(suggest.forth)
result.add(sep)
result.add(suggest.filePath)
result.add(sep)
result.add($suggest.line)
result.add(sep)
result.add($suggest.column)
result.add(sep)
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
result.add(suggest.doc.escape)
if suggest.version in {0, 3}:
result.add(sep)
result.add($suggest.quality)
if suggest.section == ideSug:
if suggest.qualifiedPath.len != 0:
result.add(suggest.qualifiedPath.join("."))
result.add(sep)
result.add(suggest.forth)
result.add(sep)
result.add(suggest.filePath)
result.add(sep)
result.add($suggest.line)
result.add(sep)
result.add($suggest.column)
result.add(sep)
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
result.add(suggest.doc.escape)
if suggest.version in {0, 3}:
result.add(sep)
result.add($suggest.prefix)
result.add($suggest.quality)
if suggest.section == ideSug:
result.add(sep)
result.add($suggest.prefix)
if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}):
result.add(sep)
result.add($suggest.endLine)
result.add(sep)
result.add($suggest.endCol)
proc suggestToSuggestInlayHint*(sug: Suggest): SuggestInlayHint =
SuggestInlayHint(
kind: sihkType,
line: sug.line,
column: sug.column + sug.tokenLen,
label: ": " & sug.forth,
paddingLeft: false,
paddingRight: false,
allowInsert: true,
tooltip: ""
)
proc suggestResult*(conf: ConfigRef; s: Suggest) =
if not isNil(conf.suggestionResultHook):
@@ -429,7 +485,15 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
if t[0] == nil: break
t = skipTypes(t[0], skipPtrs)
elif typ.kind == tyTuple and typ.n != nil:
suggestSymList(c, typ.n, field, n.info, outputs)
# All tuple fields are in scope
# So go through each field and add it to the suggestions (If it passes the filter)
for node in typ.n:
if node.kind == nkSym:
let s = node.sym
var pm: PrefixMatch
if filterSym(s, field, pm):
outputs.add(symToSuggest(c.graph, s, isLocal=true, ideSug, n.info,
s.getQuality, pm, c.inTypeContext > 0, 0))
suggestOperations(c, n, field, orig, outputs)
if typ != orig:
@@ -488,7 +552,7 @@ proc findDefinition(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym
if s.isNil: return
if isTracked(info, g.config.m.trackPos, s.name.s.len) or (s == usageSym and sfForward notin s.flags):
suggestResult(g.config, symToSuggest(g, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0, useSuppliedInfo = s == usageSym))
if sfForward notin s.flags and g.config.suggestVersion != 3:
if sfForward notin s.flags and g.config.suggestVersion < 3:
suggestQuit()
else:
usageSym = s
@@ -503,7 +567,7 @@ proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; i
## misnamed: should be 'symDeclared'
let conf = g.config
when defined(nimsuggest):
g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info)
g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info, isDecl: isDecl)
if conf.suggestVersion == 0:
if s.allUsages.len == 0:
@@ -702,7 +766,7 @@ proc suggestSentinel*(c: PContext) =
when defined(nimsuggest):
proc onDef(graph: ModuleGraph, s: PSym, info: TLineInfo) =
if graph.config.suggestVersion == 3 and info.exactEquals(s.info):
if graph.config.suggestVersion >= 3 and info.exactEquals(s.info):
suggestSym(graph, info, s, graph.usageSym)
template getPContext(): untyped =

View File

@@ -44,6 +44,7 @@ type
transCon: PTransCon # top of a TransCon stack
inlining: int # > 0 if we are in inlining context (copy vars)
nestedProcs: int # > 0 if we are in a nested proc
isIntroducingNewLocalVars: bool # true if we are in `introducingNewLocalVars` (don't transform yields)
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
deferDetected, tooEarly: bool
graph: ModuleGraph
@@ -124,6 +125,14 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
var tc = c.transCon
if sfBorrow in s.flags and s.kind in routineKinds:
# simply exchange the symbol:
var s = s
while true:
# Skips over all borrowed procs getting the last proc symbol without an implementation
let body = getBody(c.graph, s)
if body.kind == nkSym and sfBorrow in body.sym.flags and getBody(c.graph, body.sym).kind == nkSym:
s = body.sym
else:
break
b = getBody(c.graph, s)
if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
b = newSymNode(b.sym, n.info)
@@ -307,6 +316,14 @@ proc introduceNewLocalVars(c: PTransf, n: PNode): PNode =
if a.kind == nkSym:
n[1] = transformSymAux(c, a)
return n
of nkProcDef: # todo optimize nosideeffects?
result = newTransNode(n)
let x = freshVar(c, n[namePos].sym)
idNodeTablePut(c.transCon.mapping, n[namePos].sym, x)
result[namePos] = x # we have to copy proc definitions for iters
for i in 1..<n.len:
result[i] = introduceNewLocalVars(c, n[i])
result[namePos].sym.ast = result
else:
result = newTransNode(n)
for i in 0..<n.len:
@@ -433,7 +450,9 @@ proc transformYield(c: PTransf, n: PNode): PNode =
result.add(c.transCon.forLoopBody)
else:
# we need to introduce new local variables:
c.isIntroducingNewLocalVars = true # don't transform yields when introducing new local vars
result.add(introduceNewLocalVars(c, c.transCon.forLoopBody))
c.isIntroducingNewLocalVars = false
for idx in 0 ..< result.len:
var changeNode = result[idx]
@@ -627,7 +646,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
else:
for i in 0..<n.safeLen: findWrongOwners(c, n[i])
proc isSimpleIteratorVar(c: PTransf; iter: PSym): bool =
proc isSimpleIteratorVar(c: PTransf; iter: PSym; call: PNode; owner: PSym): bool =
proc rec(n: PNode; owner: PSym; dangerousYields: var int) =
case n.kind
of nkEmpty..nkNilLit: discard
@@ -639,9 +658,22 @@ proc isSimpleIteratorVar(c: PTransf; iter: PSym): bool =
else:
for c in n: rec(c, owner, dangerousYields)
proc recSym(n: PNode; owner: PSym; sameOwner: var bool) =
case n.kind
of {nkEmpty..nkNilLit} - {nkSym}: discard
of nkSym:
if n.sym.owner != owner:
sameOwner = false
else:
for c in n: recSym(c, owner, sameOwner)
var dangerousYields = 0
rec(getBody(c.graph, iter), iter, dangerousYields)
result = dangerousYields == 0
# the parameters should be owned by the owner
# bug #22237
for i in 1..<call.len:
recSym(call[i], owner, result)
template destructor(t: PType): PSym = getAttachedOp(c.graph, t, attachedDestructor)
@@ -685,7 +717,7 @@ proc transformFor(c: PTransf, n: PNode): PNode =
for j in 0..<n[i].len-1:
addVar(v, copyTree(n[i][j])) # declare new vars
else:
if n[i].kind == nkSym and isSimpleIteratorVar(c, iter):
if n[i].kind == nkSym and isSimpleIteratorVar(c, iter, call, n[i].sym.owner):
incl n[i].sym.flags, sfCursor
addVar(v, copyTree(n[i])) # declare new vars
stmtList.add(v)
@@ -1012,7 +1044,7 @@ proc transform(c: PTransf, n: PNode): PNode =
else:
result = transformSons(c, n)
of nkYieldStmt:
if c.inlining > 0:
if c.inlining > 0 and not c.isIntroducingNewLocalVars:
result = transformYield(c, n)
else:
result = transformSons(c, n)

View File

@@ -22,6 +22,7 @@ type
taNoUntyped
taIsTemplateOrMacro
taProcContextIsNotMacro
taIsCastable
TTypeAllowedFlags* = set[TTypeAllowedFlag]
@@ -60,7 +61,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
elif taIsOpenArray in flags:
result = t
elif t.kind == tyLent and ((kind != skResult and views notin c.features) or
kind == skParam): # lent can't be used as parameters.
(kind == skParam and {taIsCastable, taField} * flags == {})): # lent cannot be used as parameters.
# except in the cast environment and as the field of an object
result = t
else:
var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc, tySink})

View File

@@ -11,7 +11,7 @@
import
intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options,
lineinfos, int128, modulegraphs, astmsgs
lineinfos, int128, modulegraphs, astmsgs, wordrecg
type
TPreferedDesc* = enum
@@ -25,6 +25,8 @@ type
preferMixed,
# most useful, shows: symbol + resolved symbols if it differs, e.g.:
# tuple[a: MyInt{int}, b: float]
preferInlayHint,
preferInferredEffects,
TTypeRelation* = enum # order is important!
isNone, isConvertible,
@@ -368,41 +370,65 @@ proc containsHiddenPointer*(typ: PType): bool =
# that need to be copied deeply)
result = searchTypeFor(typ, isHiddenPointer)
proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool
proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool =
proc canFormAcycleAux(g: ModuleGraph; marker: var IntSet, typ: PType, orig: PType, withRef: bool, hasTrace: bool): bool
proc canFormAcycleNode(g: ModuleGraph; marker: var IntSet, n: PNode, orig: PType, withRef: bool, hasTrace: bool): bool =
result = false
if n != nil:
result = canFormAcycleAux(marker, n.typ, startId)
if not result:
case n.kind
of nkNone..nkNilLit:
discard
else:
for i in 0..<n.len:
result = canFormAcycleNode(marker, n[i], startId)
if result: return
var hasCursor = n.kind == nkSym and sfCursor in n.sym.flags
# cursor fields don't own the refs, which cannot form reference cycles
if hasTrace or not hasCursor:
result = canFormAcycleAux(g, marker, n.typ, orig, withRef, hasTrace)
if not result:
case n.kind
of nkNone..nkNilLit:
discard
else:
for i in 0..<n.len:
result = canFormAcycleNode(g, marker, n[i], orig, withRef, hasTrace)
if result: return
proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool =
proc sameBackendType*(x, y: PType): bool
proc canFormAcycleAux(g: ModuleGraph, marker: var IntSet, typ: PType, orig: PType, withRef: bool, hasTrace: bool): bool =
result = false
if typ == nil: return
if tfAcyclic in typ.flags: return
var t = skipTypes(typ, abstractInst+{tyOwned}-{tyTypeDesc})
if tfAcyclic in t.flags: return
case t.kind
of tyTuple, tyObject, tyRef, tySequence, tyArray, tyOpenArray, tyVarargs:
if t.id == startId:
of tyRef, tyPtr, tyUncheckedArray:
if t.kind == tyRef or hasTrace:
if withRef and sameBackendType(t, orig):
result = true
elif not containsOrIncl(marker, t.id):
for i in 0..<t.len:
result = canFormAcycleAux(g, marker, t[i], orig, withRef or t.kind != tyUncheckedArray, hasTrace)
if result: return
of tyObject:
if withRef and sameBackendType(t, orig):
result = true
elif not containsOrIncl(marker, t.id):
var hasTrace = hasTrace
let op = getAttachedOp(g, t.skipTypes({tyRef}), attachedTrace)
if op != nil and sfOverriden in op.flags:
hasTrace = true
for i in 0..<t.len:
result = canFormAcycleAux(marker, t[i], startId)
result = canFormAcycleAux(g, marker, t[i], orig, withRef, hasTrace)
if result: return
if t.n != nil: result = canFormAcycleNode(marker, t.n, startId)
if t.n != nil: result = canFormAcycleNode(g, marker, t.n, orig, withRef, hasTrace)
# Inheritance can introduce cyclic types, however this is not relevant
# as the type that is passed to 'new' is statically known!
# er but we use it also for the write barrier ...
if t.kind == tyObject and tfFinal notin t.flags:
if tfFinal notin t.flags:
# damn inheritance may introduce cycles:
result = true
of tyTuple, tySequence, tyArray, tyOpenArray, tyVarargs:
if withRef and sameBackendType(t, orig):
result = true
elif not containsOrIncl(marker, t.id):
for i in 0..<t.len:
result = canFormAcycleAux(g, marker, t[i], orig, withRef, hasTrace)
if result: return
of tyProc: result = typ.callConv == ccClosure
else: discard
@@ -410,10 +436,10 @@ proc isFinal*(t: PType): bool =
let t = t.skipTypes(abstractInst)
result = t.kind != tyObject or tfFinal in t.flags or isPureObject(t)
proc canFormAcycle*(typ: PType): bool =
proc canFormAcycle*(g: ModuleGraph, typ: PType): bool =
var marker = initIntSet()
let t = skipTypes(typ, abstractInst+{tyOwned}-{tyTypeDesc})
result = canFormAcycleAux(marker, t, t.id)
result = canFormAcycleAux(g, marker, t, t, false, false)
proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
closure: RootRef): PType
@@ -448,7 +474,10 @@ proc mutateType(t: PType, iter: TTypeMutator, closure: RootRef): PType =
proc valueToString(a: PNode): string =
case a.kind
of nkCharLit..nkUInt64Lit: result = $a.intVal
of nkCharLit, nkUIntLit..nkUInt64Lit:
result = $cast[uint64](a.intVal)
of nkIntLit..nkInt64Lit:
result = $a.intVal
of nkFloatLit..nkFloat128Lit: result = $a.floatVal
of nkStrLit..nkTripleStrLit: result = a.strVal
else: result = "<invalid value>"
@@ -476,7 +505,7 @@ const
"void", "iterable"]
const preferToResolveSymbols = {preferName, preferTypeName, preferModuleInfo,
preferGenericArg, preferResolved, preferMixed}
preferGenericArg, preferResolved, preferMixed, preferInlayHint, preferInferredEffects}
template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) =
tc.add concrete
@@ -510,7 +539,10 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
if prefer in preferToResolveSymbols and t.sym != nil and
sfAnon notin t.sym.flags and t.kind != tySequence:
if t.kind == tyInt and isIntLit(t):
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
if prefer == preferInlayHint:
result = t.sym.name.s
else:
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
elif t.kind == tyAlias and t[0].kind != tyAlias:
result = typeToString(t[0])
elif prefer in {preferResolved, preferMixed}:
@@ -526,7 +558,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
result = t.sym.name.s
if prefer == preferMixed and result != t.sym.name.s:
result = t.sym.name.s & "{" & result & "}"
elif prefer in {preferName, preferTypeName} or t.sym.owner.isNil:
elif prefer in {preferName, preferTypeName, preferInlayHint, preferInferredEffects} or t.sym.owner.isNil:
# note: should probably be: {preferName, preferTypeName, preferGenericArg}
result = t.sym.name.s
if t.kind == tyGenericParam and t.len > 0:
@@ -545,8 +577,11 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
if not isIntLit(t) or prefer == preferExported:
result = typeToStr[t.kind]
else:
if prefer == preferGenericArg:
case prefer:
of preferGenericArg:
result = $t.n.intVal
of preferInlayHint:
result = "int"
else:
result = "int literal(" & $t.n.intVal & ")"
of tyGenericInst, tyGenericInvocation:
@@ -719,6 +754,15 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
result.add(')')
if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0]))
var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: $t.callConv
var hasImplicitRaises = false
if not isNil(t.owner) and not isNil(t.owner.ast) and (t.owner.ast.len - 1) >= pragmasPos:
let pragmasNode = t.owner.ast[pragmasPos]
let raisesSpec = effectSpec(pragmasNode, wRaises)
if not isNil(raisesSpec):
addSep(prag)
prag.add("raises: ")
prag.add($raisesSpec)
hasImplicitRaises = true
if tfNoSideEffect in t.flags:
addSep(prag)
prag.add("noSideEffect")
@@ -728,6 +772,20 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
if t.lockLevel.ord != UnspecifiedLockLevel.ord:
addSep(prag)
prag.add("locks: " & $t.lockLevel)
if not hasImplicitRaises and prefer == preferInferredEffects and not isNil(t.owner) and not isNil(t.owner.typ) and not isNil(t.owner.typ.n) and (t.owner.typ.n.len > 0):
let effects = t.owner.typ.n[0]
if effects.kind == nkEffectList and effects.len == effectListLen:
var inferredRaisesStr = ""
let effs = effects[exceptionEffects]
if not isNil(effs):
for eff in items(effs):
if not isNil(eff):
addSep(inferredRaisesStr)
inferredRaisesStr.add($eff.typ)
addSep(prag)
prag.add("raises: <inferred> [")
prag.add(inferredRaisesStr)
prag.add("]")
if prag.len != 0: result.add("{." & prag & ".}")
of tyVarargs:
result = typeToStr[t.kind] % typeToString(t[0])
@@ -773,11 +831,11 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 =
result = firstOrd(conf, lastSon(t))
of tyOrdinal:
if t.len > 0: result = firstOrd(conf, lastSon(t))
else: internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')')
else: fatal(conf, unknownLineInfo, "invalid kind for firstOrd(" & $t.kind & ')')
of tyUncheckedArray, tyCstring:
result = Zero
else:
internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')')
fatal(conf, unknownLineInfo, "invalid kind for firstOrd(" & $t.kind & ')')
result = Zero
proc firstFloat*(t: PType): BiggestFloat =
@@ -832,11 +890,11 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
of tyProxy: result = Zero
of tyOrdinal:
if t.len > 0: result = lastOrd(conf, lastSon(t))
else: internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')')
else: fatal(conf, unknownLineInfo, "invalid kind for lastOrd(" & $t.kind & ')')
of tyUncheckedArray:
result = Zero
else:
internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')')
fatal(conf, unknownLineInfo, "invalid kind for lastOrd(" & $t.kind & ')')
result = Zero
proc lastFloat*(t: PType): BiggestFloat =
@@ -1121,15 +1179,20 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
case c.cmp
of dcEq: return false
of dcEqIgnoreDistinct:
while a.kind == tyDistinct: a = a[0]
while b.kind == tyDistinct: b = b[0]
a = a.skipTypes({tyDistinct, tyGenericInst})
b = b.skipTypes({tyDistinct, tyGenericInst})
if a.kind != b.kind: return false
of dcEqOrDistinctOf:
while a.kind == tyDistinct: a = a[0]
a = a.skipTypes({tyDistinct, tyGenericInst})
if a.kind != b.kind: return false
#[
The following code should not run in the case either side is an generic alias,
but it's not presently possible to distinguish the genericinsts from aliases of
objects ie `type A[T] = SomeObject`
]#
# this is required by tunique_type but makes no sense really:
if x.kind == tyGenericInst and IgnoreTupleFields notin c.flags:
if tyDistinct notin {x.kind, y.kind} and x.kind == tyGenericInst and IgnoreTupleFields notin c.flags:
let
lhs = x.skipGenericAlias
rhs = y.skipGenericAlias
@@ -1145,13 +1208,14 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCstring,
tyInt..tyUInt64, tyTyped, tyUntyped, tyVoid:
result = sameFlags(a, b)
if result and PickyCAliases in c.flags:
if result and {PickyCAliases, ExactTypeDescValues} <= c.flags:
# additional requirement for the caching of generics for importc'ed types:
# the symbols must be identical too:
let symFlagsA = if a.sym != nil: a.sym.flags else: {}
let symFlagsB = if b.sym != nil: b.sym.flags else: {}
if (symFlagsA+symFlagsB) * {sfImportc, sfExportc} != {}:
result = symFlagsA == symFlagsB
of tyStatic, tyFromExpr:
result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
if result and a.len == b.len and a.len == 1:
@@ -1193,7 +1257,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
assert a[0].len == 0
assert b.len == 1
assert b[0].len == 0
result = a[0].kind == b[0].kind
result = a[0].kind == b[0].kind and sameFlags(a[0], b[0])
if result and a[0].kind == tyProc and IgnoreCC notin c.flags:
let ecc = a[0].flags * {tfExplicitCallConv}
result = ecc == b[0].flags * {tfExplicitCallConv} and
(ecc == {} or a[0].callConv == b[0].callConv)
of tyGenericInvocation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef,
tyPtr, tyVar, tyLent, tySink, tyUncheckedArray, tyArray, tyProc, tyVarargs,
tyOrdinal, tyCompositeTypeClass, tyUserTypeClass, tyUserTypeClassInst,
@@ -1364,6 +1432,19 @@ proc compatibleEffectsAux(se, re: PNode): bool =
return false
result = true
proc isDefectException*(t: PType): bool
proc compatibleExceptions(se, re: PNode): bool =
if re.isNil: return false
for r in items(re):
block search:
if isDefectException(r.typ):
break search
for s in items(se):
if safeInheritanceDiff(r.typ, s.typ) <= 0:
break search
return false
result = true
type
EffectsCompat* = enum
efCompat
@@ -1395,7 +1476,7 @@ proc compatibleEffects*(formal, actual: PType): EffectsCompat =
if not isNil(se) and se.kind != nkArgList:
# spec requires some exception or tag, but we don't know anything:
if real.len == 0: return efRaisesUnknown
let res = compatibleEffectsAux(se, real[exceptionEffects])
let res = compatibleExceptions(se, real[exceptionEffects])
if not res: return efRaisesDiffer
let st = spec[tagEffects]
@@ -1665,6 +1746,18 @@ proc isDefectException*(t: PType): bool =
t = skipTypes(t[0], abstractPtrs)
return false
proc isDefectOrCatchableError*(t: PType): bool =
var t = t.skipTypes(abstractPtrs)
while t.kind == tyObject:
if t.sym != nil and t.sym.owner != nil and
sfSystemModule in t.sym.owner.flags and
(t.sym.name.s == "Defect" or
t.sym.name.s == "CatchableError"):
return true
if t[0] == nil: break
t = skipTypes(t[0], abstractPtrs)
return false
proc isSinkTypeForParam*(t: PType): bool =
# a parameter like 'seq[owned T]' must not be used only once, but its
# elements must, so we detect this case here:

View File

@@ -491,7 +491,9 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) =
# this list is subtle, we try to answer the question if after 'dest = f(src)'
# there is a connection betwen 'src' and 'dest' so that mutations to 'src'
# also reflect 'dest':
if magic in {mNone, mMove, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mArrToSeq}:
if magic in {mNone, mMove, mSlice,
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mArrToSeq, mOpenArrayToSeq}:
for i in 1..<n.len:
# we always have to assume a 'select(...)' like mechanism.
# But at least we do filter out simple POD types from the

View File

@@ -450,9 +450,12 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType):
else: int(src.intVal != 0)
of tyFloat..tyFloat64:
dest.ensureKind(rkFloat)
case skipTypes(srctyp, abstractRange).kind
let srcKind = skipTypes(srctyp, abstractRange).kind
case srcKind
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar:
dest.floatVal = toBiggestFloat(src.intVal)
elif src.kind == rkInt:
dest.floatVal = toBiggestFloat(src.intVal)
else:
dest.floatVal = src.floatVal
of tyObject:
@@ -525,6 +528,15 @@ template takeAddress(reg, source) =
reg.nodeAddr = addr source
GC_ref source
proc takeCharAddress(c: PCtx, src: PNode, index: BiggestInt, pc: int): TFullReg =
let typ = newType(tyPtr, nextTypeId c.idgen, c.module.owner)
typ.add getSysType(c.graph, c.debug[pc], tyChar)
var node = newNodeIT(nkIntLit, c.debug[pc], typ) # xxx nkPtrLit
node.intVal = cast[int](src.strVal[index].addr)
node.flags.incl nfIsPtr
TFullReg(kind: rkNode, node: node)
proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var pc = start
var tos = tos
@@ -658,6 +670,48 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
else:
ensureKind(rkNode)
regs[ra].node = nb
of opcSlice:
# A bodge, but this takes in `toOpenArray(rb, rc, rc)` and emits
# nkTupleConstr(x, y, z) into the `regs[ra]`. These can later be used for calculating the slice we have taken.
decodeBC(rkNode)
let
collection = regs[ra].node
leftInd = regs[rb].intVal
rightInd = regs[rc].intVal
proc rangeCheck(left, right: BiggestInt, safeLen: BiggestInt) =
if left < 0:
stackTrace(c, tos, pc, formatErrorIndexBound(left, safeLen))
if right > safeLen:
stackTrace(c, tos, pc, formatErrorIndexBound(right, safeLen))
case collection.kind
of nkTupleConstr: # slice of a slice
let safeLen = collection[2].intVal - collection[1].intVal
rangeCheck(leftInd, rightInd, safeLen)
let
leftInd = leftInd + collection[1].intVal # Slice is from the start of the old
rightInd = rightInd + collection[1].intVal
regs[ra].node = newTree(
nkTupleConstr,
collection[0],
newIntNode(nkIntLit, BiggestInt leftInd),
newIntNode(nkIntLit, BiggestInt rightInd)
)
else:
let safeLen = safeArrLen(collection) - 1
rangeCheck(leftInd, rightInd, safeLen)
regs[ra].node = newTree(
nkTupleConstr,
collection,
newIntNode(nkIntLit, BiggestInt leftInd),
newIntNode(nkIntLit, BiggestInt rightInd)
)
of opcLdArr:
# a = b[c]
decodeBC(rkNode)
@@ -665,7 +719,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
stackTrace(c, tos, pc, formatErrorIndexBound(regs[rc].intVal, high(int)))
let idx = regs[rc].intVal.int
let src = regs[rb].node
if src.kind in {nkStrLit..nkTripleStrLit}:
case src.kind
of nkTupleConstr: # refer to `of opcSlice`
let
left = src[1].intVal
right = src[2].intVal
realIndex = left + idx
if idx in 0..(right - left):
case src[0].kind
of nkStrKinds:
regs[ra].node = newIntNode(nkCharLit, ord src[0].strVal[int realIndex])
of nkBracket:
regs[ra].node = src[0][int realIndex]
else:
stackTrace(c, tos, pc, "opcLdArr internal error")
else:
stackTrace(c, tos, pc, formatErrorIndexBound(idx, int right))
of nkStrLit..nkTripleStrLit:
if idx <% src.strVal.len:
regs[ra].node = newNodeI(nkCharLit, c.debug[pc])
regs[ra].node.intVal = src.strVal[idx].ord
@@ -682,10 +753,29 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
stackTrace(c, tos, pc, formatErrorIndexBound(regs[rc].intVal, high(int)))
let idx = regs[rc].intVal.int
let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[]
if src.kind notin {nkEmpty..nkTripleStrLit} and idx <% src.len:
takeAddress regs[ra], src.sons[idx]
case src.kind
of nkTupleConstr:
let
left = src[1].intVal
right = src[2].intVal
realIndex = left + idx
if idx in 0..(right - left): # Refer to `opcSlice`
case src[0].kind
of nkStrKinds:
regs[ra] = takeCharAddress(c, src[0], realIndex, pc)
of nkBracket:
takeAddress regs[ra], src.sons[0].sons[realIndex]
else:
stackTrace(c, tos, pc, "opcLdArrAddr internal error")
else:
stackTrace(c, tos, pc, formatErrorIndexBound(idx, int right))
else:
stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.safeLen-1))
if src.kind notin {nkEmpty..nkTripleStrLit} and idx <% src.len:
takeAddress regs[ra], src.sons[idx]
elif src.kind in nkStrKinds and idx <% src.strVal.len:
regs[ra] = takeCharAddress(c, src, idx, pc)
else:
stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.safeLen-1))
of opcLdStrIdx:
decodeBC(rkInt)
let idx = regs[rc].intVal.int
@@ -702,13 +792,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let idx = regs[rc].intVal.int
let s = regs[rb].node.strVal.addr # or `byaddr`
if idx <% s[].len:
# `makePtrType` not accessible from vm.nim
let typ = newType(tyPtr, nextTypeId c.idgen, c.module.owner)
typ.add getSysType(c.graph, c.debug[pc], tyChar)
let node = newNodeIT(nkIntLit, c.debug[pc], typ) # xxx nkPtrLit
node.intVal = cast[int](s[][idx].addr)
node.flags.incl nfIsPtr
regs[ra].node = node
regs[ra] = takeCharAddress(c, regs[rb].node, idx, pc)
else:
stackTrace(c, tos, pc, formatErrorIndexBound(idx, s[].len-1))
of opcWrArr:
@@ -716,7 +800,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
decodeBC(rkNode)
let idx = regs[rb].intVal.int
let arr = regs[ra].node
if arr.kind in {nkStrLit..nkTripleStrLit}:
case arr.kind
of nkTupleConstr: # refer to `opcSlice`
let
src = arr[0]
left = arr[1].intVal
right = arr[2].intVal
realIndex = left + idx
if idx in 0..(right - left):
case src.kind
of nkStrKinds:
src.strVal[int(realIndex)] = char(regs[rc].intVal)
of nkBracket:
src[int(realIndex)] = regs[rc].node
else:
stackTrace(c, tos, pc, "opcWrArr internal error")
else:
stackTrace(c, tos, pc, formatErrorIndexBound(idx, int right))
of {nkStrLit..nkTripleStrLit}:
if idx <% arr.strVal.len:
arr.strVal[idx] = chr(regs[rc].intVal)
else:
@@ -874,14 +975,21 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcLenSeq:
decodeBImm(rkInt)
#assert regs[rb].kind == nkBracket
let high = (imm and 1) # discard flags
let
high = (imm and 1) # discard flags
node = regs[rb].node
if (imm and nimNodeFlag) != 0:
# used by mNLen (NimNode.len)
regs[ra].intVal = regs[rb].node.safeLen - high
else:
# safeArrLen also return string node len
# used when string is passed as openArray in VM
regs[ra].intVal = regs[rb].node.safeArrLen - high
case node.kind
of nkTupleConstr: # refer to `of opcSlice`
regs[ra].intVal = node[2].intVal - node[1].intVal + 1 - high
else:
# safeArrLen also return string node len
# used when string is passed as openArray in VM
regs[ra].intVal = node.safeArrLen - high
of opcLenStr:
decodeBImm(rkInt)
assert regs[rb].kind == rkNode
@@ -889,7 +997,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcLenCstring:
decodeBImm(rkInt)
assert regs[rb].kind == rkNode
regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm
if regs[rb].node.kind == nkNilLit:
regs[ra].intVal = -imm
else:
regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm
of opcIncl:
decodeB(rkNode)
let b = regs[rb].regToNode
@@ -1059,7 +1170,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
strictSymEquality=true))
of opcSameNodeType:
decodeBC(rkInt)
regs[ra].intVal = ord(regs[rb].node.typ.sameTypeOrNil regs[rc].node.typ)
regs[ra].intVal = ord(regs[rb].node.typ.sameTypeOrNil(regs[rc].node.typ, {ExactTypeDescValues, ExactGenericParams}))
# The types should exactly match which is why we pass `{ExactTypeDescValues..ExactGcSafety}`.
of opcXor:
decodeBC(rkInt)
regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal)
@@ -1086,6 +1198,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcEqStr:
decodeBC(rkInt)
regs[ra].intVal = ord(regs[rb].node.strVal == regs[rc].node.strVal)
of opcEqCString:
decodeBC(rkInt)
let bNil = regs[rb].node.kind == nkNilLit
let cNil = regs[rc].node.kind == nkNilLit
regs[ra].intVal = ord((bNil and cNil) or
(not bNil and not cNil and regs[rb].node.strVal == regs[rc].node.strVal))
of opcLeStr:
decodeBC(rkInt)
regs[ra].intVal = ord(regs[rb].node.strVal <= regs[rc].node.strVal)
@@ -1356,7 +1474,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node
c.currentExceptionA = raised
# Set the `name` field of the exception
c.currentExceptionA[2].skipColon.strVal = c.currentExceptionA.typ.sym.name.s
var exceptionNameNode = newStrNode(nkStrLit, c.currentExceptionA.typ.sym.name.s)
if c.currentExceptionA[2].kind == nkExprColonExpr:
exceptionNameNode.typ = c.currentExceptionA[2][1].typ
c.currentExceptionA[2][1] = exceptionNameNode
else:
exceptionNameNode.typ = c.currentExceptionA[2].typ
c.currentExceptionA[2] = exceptionNameNode
c.exceptionInstr = pc
var frame = tos
@@ -1728,7 +1852,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[rb].node.kind != nkSym:
stackTrace(c, tos, pc, "node is not a symbol")
else:
regs[ra].node.strVal = $sigHash(regs[rb].node.sym)
regs[ra].node.strVal = $sigHash(regs[rb].node.sym, c.config)
of opcSlurp:
decodeB(rkNode)
createStr regs[ra]
@@ -1806,14 +1930,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of 1: # getLine
regs[ra].node = newIntNode(nkIntLit, n.info.line.int)
of 2: # getColumn
regs[ra].node = newIntNode(nkIntLit, n.info.col)
regs[ra].node = newIntNode(nkIntLit, n.info.col.int)
else:
internalAssert c.config, false
regs[ra].node.info = n.info
regs[ra].node.typ = n.typ
of opcNSetLineInfo:
of opcNCopyLineInfo:
decodeB(rkNode)
regs[ra].node.info = regs[rb].node.info
of opcNSetLineInfoLine:
decodeB(rkNode)
regs[ra].node.info.line = regs[rb].intVal.uint16
of opcNSetLineInfoColumn:
decodeB(rkNode)
regs[ra].node.info.col = regs[rb].intVal.int16
of opcNSetLineInfoFile:
decodeB(rkNode)
regs[ra].node.info.fileIndex =
fileInfoIdx(c.config, RelativeFile regs[rb].node.strVal)
of opcEqIdent:
decodeBC(rkInt)
# aliases for shorter and easier to understand code below
@@ -2218,6 +2352,9 @@ const evalPass* = makePass(myOpen, myProcess, myClose)
proc evalConstExprAux(module: PSym; idgen: IdGenerator;
g: ModuleGraph; prc: PSym, n: PNode,
mode: TEvalMode): PNode =
when defined(nimsuggest):
if g.config.expandDone():
return n
#if g.config.errorCounter > 0: return n
let n = transformExpr(g, idgen, module, n)
setupGlobalCtx(module, g, idgen)

View File

@@ -81,6 +81,7 @@ type
opcWrStrIdx,
opcLdStrIdx, # a = b[c]
opcLdStrIdxAddr, # a = addr(b[c])
opcSlice, # toOpenArray(collection, left, right)
opcAddInt,
opcAddImmInt,
@@ -98,7 +99,7 @@ type
opcLeFloat, opcLtFloat, opcLeu, opcLtu,
opcEqRef, opcEqNimNode, opcSameNodeType,
opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
opcEqStr, opcEqCString, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
opcMulSet, opcPlusSet, opcMinusSet, opcConcatStr,
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
opcIsNil, opcOf, opcIs,
@@ -140,7 +141,8 @@ type
opcNError,
opcNWarning,
opcNHint,
opcNGetLineInfo, opcNSetLineInfo,
opcNGetLineInfo, opcNCopyLineInfo, opcNSetLineInfoLine,
opcNSetLineInfoColumn, opcNSetLineInfoFile
opcEqIdent,
opcStrToIdent,
opcGetImpl,

View File

@@ -408,13 +408,19 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
c.gen(it[0], tmp)
elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false
c.clearDest(n, dest)
c.gen(it[1], dest) # then part
if isEmptyType(it[1].typ): # maybe noreturn call, don't touch `dest`
c.gen(it[1])
else:
c.gen(it[1], dest) # then part
if i < n.len-1:
endings.add(c.xjmp(it[1], opcJmp, 0))
c.patch(elsePos)
else:
c.clearDest(n, dest)
c.gen(it[0], dest)
if isEmptyType(it[0].typ): # maybe noreturn call, don't touch `dest`
c.gen(it[0])
else:
c.gen(it[0], dest)
for endPos in endings: c.patch(endPos)
c.clearDest(n, dest)
@@ -445,6 +451,7 @@ proc rawGenLiteral(c: PCtx; n: PNode): int =
result = c.constants.len
#assert(n.kind != nkCall)
n.flags.incl nfAllConst
n.flags.excl nfIsRef
c.constants.add n
internalAssert c.config, result < regBxMax
@@ -507,17 +514,25 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
let it = n[i]
if it.len == 1:
# else stmt:
if it[0].kind != nkNilLit or it[0].typ != nil:
let body = it[0]
if body.kind != nkNilLit or body.typ != nil:
# an nkNilLit with nil for typ implies there is no else branch, this
# avoids unused related errors as we've already consumed the dest
c.gen(it[0], dest)
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
c.gen(body)
else:
c.gen(body, dest)
else:
let b = rawGenLiteral(c, it)
c.gABx(it, opcBranch, tmp, b)
let elsePos = c.xjmp(it.lastSon, opcFJmp, tmp)
c.gen(it.lastSon, dest)
let body = it.lastSon
let elsePos = c.xjmp(body, opcFJmp, tmp)
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
c.gen(body)
else:
c.gen(body, dest)
if i < n.len-1:
endings.add(c.xjmp(it.lastSon, opcJmp, 0))
endings.add(c.xjmp(body, opcJmp, 0))
c.patch(elsePos)
c.clearDest(n, dest)
for endPos in endings: c.patch(endPos)
@@ -533,7 +548,10 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
var endings: seq[TPosition] = @[]
let ehPos = c.xjmp(n, opcTry, 0)
c.gen(n[0], dest)
if isEmptyType(n[0].typ): # maybe noreturn call, don't touch `dest`
c.gen(n[0])
else:
c.gen(n[0], dest)
c.clearDest(n, dest)
# Add a jump past the exception handling code
let jumpToFinally = c.xjmp(n, opcJmp, 0)
@@ -551,7 +569,11 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
if it.len == 1:
# general except section:
c.gABx(it, opcExcept, 0, 0)
c.gen(it.lastSon, dest)
let body = it.lastSon
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
c.gen(body)
else:
c.gen(body, dest)
c.clearDest(n, dest)
if i < n.len:
endings.add(c.xjmp(it, opcJmp, 0))
@@ -643,9 +665,19 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags
proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
case le.kind
of nkBracketExpr:
let dest = c.genx(le[0], {gfNode})
let idx = c.genIndex(le[1], le[0].typ)
c.gABC(le, opcWrArr, dest, idx, value)
let
dest = c.genx(le[0], {gfNode})
idx = c.genIndex(le[1], le[0].typ)
collTyp = le[0].typ.skipTypes(abstractVarRange-{tyTypeDesc})
case collTyp.kind
of tyString, tyCstring:
c.gABC(le, opcWrStrIdx, dest, idx, value)
of tyTuple:
c.gABC(le, opcWrObj, dest, int le[1].intVal, value)
else:
c.gABC(le, opcWrArr, dest, idx, value)
c.freeTemp(dest)
c.freeTemp(idx)
of nkCheckedFieldExpr:
@@ -841,7 +873,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
let targ2 = arg.typ.skipTypes({tyDistinct})
proc implicitConv(): bool =
if sameType(t2, targ2): return true
if sameBackendType(t2, targ2): return true
# xxx consider whether to use t2 and targ2 here
if n.typ.kind == arg.typ.kind and arg.typ.kind == tyProc:
# don't do anything for lambda lifting conversions:
@@ -873,6 +905,8 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
let dst = n[0].typ.skipTypes(abstractRange)#.kind
let srcSize = getSize(c.config, src)
let dstSize = getSize(c.config, dst)
const unsupportedCastDifferentSize =
"VM does not support 'cast' from $1 with size $2 to $3 with size $4 due to different sizes"
if src.kind in allowedIntegers and dst.kind in allowedIntegers:
let tmp = c.genx(n[1])
if dest < 0: dest = c.getTemp(n[0].typ)
@@ -889,8 +923,11 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
# is smaller than source.
c.gABC(n, opcNarrowU, dest, TRegister(dstSize*8))
c.freeTemp(tmp)
elif srcSize == dstSize and src.kind in allowedIntegers and
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
elif src.kind in allowedIntegers and
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
if srcSize != dstSize:
globalError(c.config, n.info, unsupportedCastDifferentSize %
[$src.kind, $srcSize, $dst.kind, $dstSize])
let tmp = c.genx(n[1])
if dest < 0: dest = c.getTemp(n[0].typ)
if dst.kind == tyFloat32:
@@ -899,8 +936,11 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
c.gABC(n, opcCastIntToFloat64, dest, tmp)
c.freeTemp(tmp)
elif srcSize == dstSize and src.kind in {tyFloat, tyFloat32, tyFloat64} and
elif src.kind in {tyFloat, tyFloat32, tyFloat64} and
dst.kind in allowedIntegers:
if srcSize != dstSize:
globalError(c.config, n.info, unsupportedCastDifferentSize %
[$src.kind, $srcSize, $dst.kind, $dstSize])
let tmp = c.genx(n[1])
if dest < 0: dest = c.getTemp(n[0].typ)
if src.kind == tyFloat32:
@@ -1028,7 +1068,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.genAsgnPatch(n[1], d)
c.freeTemp(d)
of mOrd, mChr, mArrToSeq, mUnown: c.gen(n[1], dest)
of mIsolate, mFinished:
of generatedMagics:
genCall(c, n, dest)
of mNew, mNewFinalize:
unused(c, n, dest)
@@ -1053,10 +1093,22 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mLengthOpenArray, mLengthArray, mLengthSeq:
genUnaryABI(c, n, dest, opcLenSeq)
of mLengthStr:
case n[1].typ.kind
case n[1].typ.skipTypes(abstractVarRange).kind
of tyString: genUnaryABI(c, n, dest, opcLenStr)
of tyCstring: genUnaryABI(c, n, dest, opcLenCstring)
else: doAssert false, $n[1].typ.kind
of mSlice:
var
d = c.genx(n[1])
left = c.genIndex(n[2], n[1].typ)
right = c.genIndex(n[3], n[1].typ)
if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opcNodeToReg, dest, d)
c.gABC(n, opcSlice, dest, left, right)
c.freeTemp(left)
c.freeTemp(right)
c.freeTemp(d)
of mIncl, mExcl:
unused(c, n, dest)
var d = c.genx(n[1])
@@ -1130,7 +1182,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
genConv(c, n, n[1], dest)
of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
of mEqCString: genBinaryABC(c, n, dest, opcEqCString)
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
of mEqSet: genBinarySet(c, n, dest, opcEqSet)
@@ -1182,7 +1235,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
var d = c.genx(n[1])
# XXX use ldNullOpcode() here?
c.gABx(n, opcLdNull, d, c.genType(n[1].typ))
c.gABx(n, opcNodeToReg, d, d)
c.gABC(n, opcNodeToReg, d, d)
c.genAsgnPatch(n[1], d)
of mDefault:
if dest < 0: dest = c.getTemp(n.typ)
@@ -1319,7 +1372,19 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of "copyLineInfo":
internalAssert c.config, n.len == 3
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetLineInfo)
genBinaryStmt(c, n, opcNCopyLineInfo)
of "setLine":
internalAssert c.config, n.len == 3
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetLineInfoLine)
of "setColumn":
internalAssert c.config, n.len == 3
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetLineInfoColumn)
of "setFile":
internalAssert c.config, n.len == 3
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetLineInfoFile)
else: internalAssert c.config, false
of mNHint:
unused(c, n, dest)
@@ -1399,7 +1464,7 @@ proc genMarshalStore(c: PCtx, n: PNode, dest: var TDest) =
proc unneededIndirection(n: PNode): bool =
n.typ.skipTypes(abstractInstOwned-{tyTypeDesc}).kind == tyRef
proc canElimAddr(n: PNode): PNode =
proc canElimAddr(n: PNode; idgen: IdGenerator): PNode =
case n[0].kind
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
var m = n[0][0]
@@ -1407,19 +1472,28 @@ proc canElimAddr(n: PNode): PNode =
# addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
result = copyNode(n[0])
result.add m[0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
result.typ = n.typ
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
var m = n[0][1]
if m.kind in {nkDerefExpr, nkHiddenDeref}:
# addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
result = copyNode(n[0])
result.add n[0][0]
result.add m[0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
result.typ = n.typ
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen)
else:
if n[0].kind in {nkDerefExpr, nkHiddenDeref}:
# addr ( deref ( x )) --> x
result = n[0][0]
proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) =
if (let m = canElimAddr(n); m != nil):
if (let m = canElimAddr(n, c.idgen); m != nil):
gen(c, m, dest, flags)
return
@@ -1497,6 +1571,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
# little hack ahead for bug #12612: assume gensym'ed variables
# are in the right scope:
if sfGenSym in s.flags and c.prc.sym == nil: discard
elif s.kind == skParam and s.typ.kind == tyTypeDesc: discard
else: cannotEval(c, n)
elif s.kind in {skProc, skFunc, skConverter, skMethod,
skIterator} and sfForward in s.flags:
@@ -1526,12 +1601,16 @@ proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
case le.kind
of nkBracketExpr:
let dest = c.genx(le[0], {gfNode})
let idx = c.genIndex(le[1], le[0].typ)
let tmp = c.genx(ri)
if le[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
tyString, tyCstring}:
let
dest = c.genx(le[0], {gfNode})
idx = c.genIndex(le[1], le[0].typ)
tmp = c.genx(ri)
collTyp = le[0].typ.skipTypes(abstractVarRange-{tyTypeDesc})
case collTyp.kind
of tyString, tyCstring:
c.preventFalseAlias(le, opcWrStrIdx, dest, idx, tmp)
of tyTuple:
c.preventFalseAlias(le, opcWrObj, dest, int le[1].intVal, tmp)
else:
c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
c.freeTemp(tmp)
@@ -1592,11 +1671,20 @@ proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
n.typ = t
genLit(c, n, dest)
proc isEmptyBody(n: PNode): bool =
case n.kind
of nkStmtList:
for i in 0..<n.len:
if not isEmptyBody(n[i]): return false
result = true
else:
result = n.kind in {nkCommentStmt, nkEmpty}
proc importcCond*(c: PCtx; s: PSym): bool {.inline.} =
## return true to importc `s`, false to execute its body instead (refs #8405)
if sfImportc in s.flags:
if s.kind in routineKinds:
return getBody(c.graph, s).kind == nkEmpty
return isEmptyBody(getBody(c.graph, s))
proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
when hasFFI:
@@ -1695,9 +1783,7 @@ proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
c.freeTemp(a)
c.freeTemp(b)
proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
let a = c.genx(n[0], flags)
let b = genField(c, n[1])
proc genObjAccessAux(c: PCtx; n: PNode; a, b: int, dest: var TDest; flags: TGenFlags) =
if dest < 0: dest = c.getTemp(n.typ)
if {gfNodeAddr} * flags != {}:
c.gABC(n, opcLdObjAddr, dest, a, b)
@@ -1710,6 +1796,11 @@ proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
c.gABC(n, opcLdObj, dest, a, b)
c.freeTemp(a)
proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
genObjAccessAux(c, n, c.genx(n[0], flags), genField(c, n[1]), dest, flags)
proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
internalAssert c.config, n.kind == nkCheckedFieldExpr
# nkDotExpr to access the requested field
@@ -1734,7 +1825,6 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags
let setLit = c.genx(checkExpr[1])
var rs = c.getTemp(getSysType(c.graph, n.info, tyBool))
c.gABC(n, opcContainsSet, rs, setLit, discVal)
c.freeTemp(discVal)
c.freeTemp(setLit)
# If the check fails let the user know
let lab1 = c.xjmp(n, if negCheck: opcFJmp else: opcTJmp, rs)
@@ -1747,6 +1837,7 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags
strLit.typ = strType
c.genLit(strLit, msgReg)
c.gABC(n, opcInvalidField, msgReg, discVal)
c.freeTemp(discVal)
c.freeTemp(msgReg)
c.patch(lab1)
@@ -1777,10 +1868,13 @@ proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
if arrayType in {tyString, tyCstring}:
case arrayType
of tyString, tyCstring:
let opc = if gfNodeAddr in flags: opcLdStrIdxAddr else: opcLdStrIdx
genArrAccessOpcode(c, n, dest, opc, flags)
elif arrayType == tyTypeDesc:
of tyTuple:
c.genObjAccessAux(n, c.genx(n[0], flags), int n[1].intVal, dest, flags)
of tyTypeDesc:
c.genTypeLit(n.typ, dest)
else:
let opc = if gfNodeAddr in flags: opcLdArrAddr else: opcLdArr
@@ -1815,10 +1909,10 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
result = newNodeIT(nkUIntLit, info, t)
of tyFloat..tyFloat128:
result = newNodeIT(nkFloatLit, info, t)
of tyCstring, tyString:
of tyString:
result = newNodeIT(nkStrLit, info, t)
result.strVal = ""
of tyVar, tyLent, tyPointer, tyPtr, tyUntyped,
of tyCstring, tyVar, tyLent, tyPointer, tyPtr, tyUntyped,
tyTyped, tyTypeDesc, tyRef, tyNil:
result = newNodeIT(nkNilLit, info, t)
of tyProc:
@@ -1879,6 +1973,19 @@ proc genVarSection(c: PCtx; n: PNode) =
c.genAdditionalCopy(a[2], opcWrDeref, tmp, 0, val)
c.freeTemp(val)
c.freeTemp(tmp)
elif not importcCondVar(s) and not (s.typ.kind == tyProc and s.typ.callConv == ccClosure) and
sfPure notin s.flags: # fixes #10938
# there is a pre-existing issue with closure types in VM
# if `(var s: proc () = default(proc ()); doAssert s == nil)` works for you;
# you might remove the second condition.
# the problem is that closure types are tuples in VM, but the types of its children
# shouldn't have the same type as closure types.
let tmp = c.genx(a[0], {gfNodeAddr})
let sa = getNullValue(s.typ, a.info, c.config)
let val = c.genx(sa)
c.genAdditionalCopy(sa, opcWrDeref, tmp, 0, val)
c.freeTemp(val)
c.freeTemp(tmp)
else:
setSlot(c, s)
if a[2].kind == nkEmpty:
@@ -2009,8 +2116,13 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
let s = n.sym
checkCanEval(c, n)
case s.kind
of skVar, skForVar, skTemp, skLet, skParam, skResult:
of skVar, skForVar, skTemp, skLet, skResult:
genRdVar(c, n, dest, flags)
of skParam:
if s.typ.kind == tyTypeDesc:
genTypeLit(c, s.typ, dest)
else:
genRdVar(c, n, dest, flags)
of skProc, skFunc, skConverter, skMacro, skTemplate, skMethod, skIterator:
# 'skTemplate' is only allowed for 'getAst' support:
if s.kind == skIterator and s.typ.callConv == TCallingConvention.ccClosure:

View File

@@ -32,6 +32,7 @@ type
wColon = ":", wColonColon = "::", wEquals = "=", wDot = ".", wDotDot = "..",
wStar = "*", wMinus = "-",
wUnderscore = "_",
wMagic = "magic", wThread = "thread", wFinal = "final", wProfiler = "profiler",
wMemTracker = "memtracker", wObjChecks = "objchecks",
wIntDefine = "intdefine", wStrDefine = "strdefine", wBoolDefine = "booldefine",
@@ -80,7 +81,7 @@ type
wLocalPassc = "localPassC", wBorrow = "borrow", wDiscardable = "discardable",
wFieldChecks = "fieldChecks", wSubsChar = "subschar", wAcyclic = "acyclic",
wShallow = "shallow", wUnroll = "unroll", wLinearScanEnd = "linearScanEnd",
wComputedGoto = "computedGoto", wExperimental = "experimental",
wComputedGoto = "computedGoto", wExperimental = "experimental", wDoctype = "doctype",
wWrite = "write", wGensym = "gensym", wInject = "inject", wDirty = "dirty",
wInheritable = "inheritable", wThreadVar = "threadvar", wEmit = "emit",
wAsmNoStackFrame = "asmNoStackFrame", wImplicitStatic = "implicitStatic",

View File

@@ -20,9 +20,4 @@ when defined(nimStrictMode):
switch("hintAsError", "ConvFromXtoItselfNotNeeded")
# future work: XDeclaredButNotUsed
when defined(windows) and not defined(booting):
# Avoid some rare stack corruption while using exceptions with a SEH-enabled
# toolchain: https://github.com/nim-lang/Nim/pull/19197
switch("define", "nimRawSetjmp")
switch("define", "nimVersion:" & NimVersion)

View File

@@ -156,7 +156,10 @@ nimblepath="$home/.nimble/pkgs/"
# Configuration for the GNU C/C++ compiler:
@if windows:
#gcc.path = r"$nim\dist\mingw\bin"
@if gcc or tcc:
@if gcc:
gcc.options.linker %= "-Wl,-Bstatic -lpthread"
@end
@if tcc:
tlsEmulation:on
@end
@end
@@ -309,24 +312,30 @@ tcc.options.always = "-w"
vcc.cpp.options.always%= "${vcc.cpp.options.always} /GL /Gw /Gy"
vcc.options.linker %= "${vcc.options.linker} /link /LTCG:incremental"
vcc.cpp.options.linker %= "${vcc.cpp.options.linker} /link /LTCG:incremental"
clang_cl.options.always%= "${clang_cl.options.always} -flto=thin"
clang_cl.cpp.options.always%= "${clang.cpp.options.always} -flto=thin"
clang.options.always%= "${clang.options.always} -flto=thin"
clang.cpp.options.always%= "${clang.cpp.options.always} -flto=thin"
clang.options.linker %= "${clang.options.linker} -flto=thin"
clang.cpp.options.linker %= "${clang.cpp.options.linker} -flto=thin"
@else:
vcc.options.always%= "${vcc.options.always} /GL"
vcc.cpp.options.always%= "${vcc.cpp.options.always} /GL"
vcc.options.linker %= "${vcc.options.linker} /link /LTCG"
vcc.cpp.options.linker %= "${vcc.cpp.options.linker} /link /LTCG"
clang_cl.options.always%= "${clang_cl.options.always} -flto"
clang_cl.cpp.options.always%= "${clang.cpp.options.always} -flto"
clang.options.always%= "${clang.options.always} -flto"
clang.cpp.options.always%= "${clang.cpp.options.always} -flto"
clang.options.linker %= "${clang.options.linker} -flto"
clang.cpp.options.linker %= "${clang.cpp.options.linker} -flto"
@end
clang_cl.options.always%= "${clang_cl.options.always} -flto"
clang_cl.cpp.options.always%= "${clang.cpp.options.always} -flto"
clang.options.always%= "${clang.options.always} -flto"
clang.cpp.options.always%= "${clang.cpp.options.always} -flto"
icl.options.always %= "${icl.options.always} /Qipo"
icl.cpp.options.always %= "${icl.cpp.options.always} /Qipo"
gcc.options.always %= "${gcc.options.always} -flto"
gcc.cpp.options.always %= "${gcc.cpp.options.always} -flto"
clang.options.linker %= "${clang.options.linker} -fuse-ld=lld -flto"
clang.cpp.options.linker %= "${clang.cpp.options.linker} -fuse-ld=lld -flto"
gcc.options.linker %= "${gcc.options.linker} -flto"
gcc.cpp.options.linker %= "${gcc.cpp.options.linker} -flto"
gcc.options.always %= "${gcc.options.always} -flto=auto"
gcc.cpp.options.always %= "${gcc.cpp.options.always} -flto=auto"
gcc.options.linker %= "${gcc.options.linker} -flto=auto"
gcc.cpp.options.linker %= "${gcc.cpp.options.linker} -flto=auto"
@end
@if strip:
gcc.options.linker %= "${gcc.options.linker} -s"

View File

@@ -1,7 +1,7 @@
=====================================================
Nim -- a Compiler for Nim. https://nim-lang.org/
Copyright (C) 2006-2021 Andreas Rumpf. All rights reserved.
Copyright (C) 2006-2023 Andreas Rumpf. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -13,12 +13,12 @@ Nim Destructors and Move Semantics
About this document
===================
This document describes the upcoming Nim runtime which does
This document describes the ARC/ORC Nim runtime which does
not use classical GC algorithms anymore but is based on destructors and
move semantics. The new runtime's advantages are that Nim programs become
move semantics. The advantages are that Nim programs become
oblivious to the involved heap sizes and programs are easier to write to make
effective use of multi-core machines. As a nice bonus, files and sockets and
the like will not require manual `close` calls anymore.
the like can be written not to require manual `close` calls anymore.
This document aims to be a precise specification about how
move semantics and destructors work in Nim.
@@ -134,6 +134,14 @@ The general pattern in `=destroy` looks like:
freeResource(x.field)
A `=destroy` is implicitly annotated with `.raises: []`; a destructor
should not raise exceptions. For backwards compatibility the compiler
produces a warning for a `=destroy` that does raise.
A `=destroy` can explicitly list the exceptions it can raise, if any,
but this of little utility as a raising destructor is implementation defined
behavior. Later versions of the language specification might cover this case precisely.
`=sink` hook
------------

View File

@@ -29,6 +29,7 @@ symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
| IDENT | KEYW
exprColonEqExpr = expr (':'|'=' expr)?
exprList = expr ^+ comma
optionalExprList = expr ^* comma
exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
qualifiedIdent = symbol ('.' optInd symbol)?
setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
@@ -97,7 +98,7 @@ typeDefAux = simpleExpr ('not' expr)?
postExprBlocks = ':' stmt? ( IND{=} doBlock
| IND{=} 'of' exprList ':' stmt
| IND{=} 'elif' expr ':' stmt
| IND{=} 'except' exprList ':' stmt
| IND{=} 'except' optionalExprList ':' stmt
| IND{=} 'finally' ':' stmt
| IND{=} 'else' ':' stmt )*
exprStmt = simpleExpr
@@ -138,10 +139,10 @@ caseStmt = 'case' expr ':'? COMMENT?
(IND{>} ofBranches DED
| IND{=} ofBranches)
tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
(IND{=}? 'except' exprList colcom stmt)*
(IND{=}? 'except' optionalExprList colcom stmt)*
(IND{=}? 'finally' colcom stmt)?
tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
(optInd 'except' exprList colcom stmt)*
(optInd 'except' optionalExprList colcom stmt)*
(optInd 'finally' colcom stmt)?
blockStmt = 'block' symbol? colcom stmt
blockExpr = 'block' symbol? colcom stmt

View File

@@ -2893,7 +2893,10 @@ Given the following distinct type definitions:
.. code-block:: nim
type
DistinctObject {.requiresInit, borrow: `.`.} = distinct MyObject
Foo = object
x: string
DistinctFoo {.requiresInit, borrow: `.`.} = distinct Foo
DistinctString {.requiresInit.} = distinct string
The following code blocks will fail to compile:
@@ -2906,7 +2909,7 @@ The following code blocks will fail to compile:
.. code-block:: nim
var s: DistinctString
s = "test"
doAssert s == "test"
doAssert string(s) == "test"
But these ones will compile successfully:
@@ -2915,8 +2918,8 @@ But these ones will compile successfully:
doAssert foo.x == "test"
.. code-block:: nim
let s = "test"
doAssert s == "test"
let s = DistinctString("test")
doAssert string(s) == "test"
Let statement
-------------
@@ -3832,6 +3835,42 @@ executable code. The `sugar <sugar.html>`_ module contains the `=>` macro
which enables a more succinct syntax for anonymous procedures resembling
lambdas as they are in languages like JavaScript, C#, etc.
Do notation
-----------
As a special convenience notation that keeps most elements of a
regular proc expression, the `do` keyword can be used to pass
anonymous procedures to routines:
.. code-block:: nim
var cities = @["Frankfurt", "Tokyo", "New York", "Kyiv"]
sort(cities) do (x, y: string) -> int:
cmp(x.len, y.len)
# Less parentheses using the method plus command syntax:
cities = cities.map do (x: string) -> string:
"City of " & x
`do` is written after the parentheses enclosing the regular proc params.
The proc expression represented by the `do` block is appended to the routine
call as the last argument. In calls using the command syntax, the `do` block
will bind to the immediately preceding expression rather than the command call.
`do` with a parameter list or pragma list corresponds to an anonymous `proc`,
however `do` without parameters or pragmas is treated as a normal statement
list. This allows macros to receive both indented statement lists as an
argument in inline calls, as well as a direct mirror of Nim's routine syntax.
.. code-block:: nim
# Passing a statement list to an inline macro:
macroResults.add quote do:
if not `ex`:
echo `info`, ": Check failed: ", `expString`
# Processing a routine definition in a macro:
rpc(router, "add") do (a, b: int) -> int:
result = a + b
Func
----
@@ -4300,13 +4339,10 @@ Closure iterators and inline iterators have some restrictions:
1. For now, a closure iterator cannot be executed at compile time.
2. `return` is allowed in a closure iterator but not in an inline iterator
(but rarely useful) and ends the iteration.
3. Neither inline nor closure iterators can be (directly)* recursive.
3. Inline iterators cannot be recursive.
4. Neither inline nor closure iterators have the special `result` variable.
5. Closure iterators are not supported by the JS backend.
(*) Closure iterators can be co-recursive with a factory proc which results
in similar syntax to a recursive iterator. More details follow.
Iterators that are neither marked `{.closure.}` nor `{.inline.}` explicitly
default to being inline, but this may change in future versions of the
implementation.
@@ -4506,8 +4542,8 @@ Example:
echo "overflow!"
except ValueError, IOError:
echo "catch multiple exceptions!"
except:
echo "Unknown exception!"
except CatchableError:
echo "Catchable exception!"
finally:
close(f)
@@ -4518,9 +4554,6 @@ listed in an `except` clause, the corresponding statements are executed.
The statements following the `except` clauses are called
`exception handlers`:idx:.
The empty `except`:idx: clause is executed if there is an exception that is
not listed otherwise. It is similar to an `else` clause in `if` statements.
If there is a `finally`:idx: clause, it is always executed after the
exception handlers.
@@ -4542,7 +4575,7 @@ branch always has to be `void`:
from std/strutils import parseInt
let x = try: parseInt("133a")
except: -1
except ValueError: -1
finally: echo "hi"
@@ -4550,7 +4583,8 @@ To prevent confusing code there is a parsing limitation; if the `try`
follows a `(` it has to be written as a one liner:
.. code-block:: nim
let x = (try: parseInt("133a") except: -1)
from std/strutils import parseInt
let x = (try: parseInt("133a") except ValueError: -1)
Except clauses
@@ -4594,7 +4628,7 @@ error message from `e`, and for such situations, it is enough to use
.. code-block:: nim
try:
# ...
except:
except CatchableError:
echo getCurrentExceptionMsg()
Custom exceptions
@@ -4784,7 +4818,7 @@ An empty `raises` list (`raises: []`) means that no exception may be raised:
try:
unsafeCall()
result = true
except:
except CatchableError:
result = false

View File

@@ -123,6 +123,65 @@ This feature has to be enabled via `{.experimental: "implicitDeref".}`:
echo n.depth
# no need to write n[].depth either
Top-down type inference
=======================
In expressions such as:
```nim
let a: T = ex
```
Normally, the compiler type checks the expression `ex` by itself, then
attempts to statically convert the type-checked expression to the given type
`T` as much as it can, while making sure it matches the type. The extent of
this process is limited however due to the expression usually having
an assumed type that might clash with the given type.
With top-down type inference, the expression is type checked with the
extra knowledge that it is supposed to be of type `T`. For example,
the following code is does not compile with the former method, but
compiles with top-down type inference:
```nim
let foo: (float, uint8, cstring) = (1, 2, "abc")
```
The tuple expression has an expected type of `(float, uint8, cstring)`.
Since it is a tuple literal, we can use this information to assume the types
of its elements. The expected types for the expressions `1`, `2` and `"abc"`
are respectively `float`, `uint8`, and `cstring`; and these expressions can be
statically converted to these types.
Without this information, the type of the tuple expression would have been
assumed to be `(int, int, string)`. Thus the type of the tuple expression
would not match the type of the variable, and an error would be given.
The extent of this varies, but there are some notable special cases.
Sequence literals
-----------------
Top-down type inference applies to sequence literals.
```nim
let x: seq[seq[float]] = @[@[1, 2, 3], @[4, 5, 6]]
```
This behavior is tied to the `@` overloads in the `system` module,
so overloading `@` can disable this behavior. This can be circumvented by
specifying the `` system.`@` `` overload.
```nim
proc `@`(x: string): string = "@" & x
# does not compile:
let x: seq[float] = @[1, 2, 3]
# compiles:
let x: seq[float] = system.`@`([1, 2, 3])
```
Code reordering
===============

View File

@@ -395,7 +395,7 @@ The `try` statement handles exceptions:
echo "could not convert string to integer"
except IOError:
echo "IO error!"
except:
except CatchableError:
echo "Unknown exception!"
# reraise the unknown exception:
raise
@@ -426,7 +426,7 @@ module. Example:
.. code-block:: nim
try:
doSomethingHere()
except:
except CatchableError:
let
e = getCurrentException()
msg = getCurrentExceptionMsg()

View File

@@ -59,6 +59,7 @@ Options:
--nim:path use specified path for nim binary
--localdocs[:path] only build local documentations. If a path is not
specified (or empty), the default is used.
--skipIntegrityCheck skips integrity check when booting the compiler
Possible Commands:
boot [options] bootstraps with given command line options
distrohelper [bindir] helper for distro packagers
@@ -89,9 +90,6 @@ Commands for core developers:
tests [options] run the testsuite (run a subset of tests by
specifying a category, e.g. `tests cat async`)
temp options creates a temporary compiler for testing
Web options:
--googleAnalytics:UA-... add the given google analytics code to the docs. To
build the official docs, use UA-48159761-1
"""
let kochExe* = when isMainModule: os.getAppFilename() # always correct when koch is main program, even if `koch` exe renamed e.g.: `nim c -o:koch_debug koch.nim`
@@ -292,7 +290,7 @@ proc thVersion(i: int): string =
template doUseCpp(): bool = getEnv("NIM_COMPILE_TO_CPP", "false") == "true"
proc boot(args: string) =
proc boot(args: string, skipIntegrityCheck: bool) =
## bootstrapping is a process that involves 3 steps:
## 1. use csourcesAny to produce nim1.exe. This nim1.exe is buggy but
## rock solid for building a Nim compiler. It shouldn't be used for anything else.
@@ -308,7 +306,8 @@ proc boot(args: string) =
hostOS & "_" & hostCPU
let nimStart = findStartNim().quoteShell()
for i in 0..2:
let times = 2 - ord(skipIntegrityCheck)
for i in 0..times:
# Nim versions < (1, 1) expect Nim's exception type to have a 'raiseId' field for
# C++ interop. Later Nim versions do this differently and removed the 'raiseId' field.
# Thus we always bootstrap the first iteration with "c" and not with "cpp" as
@@ -343,7 +342,9 @@ proc boot(args: string) =
return
copyExe(output, (i+1).thVersion)
copyExe(output, finalDest)
when not defined(windows): echo "[Warning] executables are still not equal"
when not defined(windows):
if not skipIntegrityCheck:
echo "[Warning] executables are still not equal"
# -------------- clean --------------------------------------------------------
@@ -676,6 +677,7 @@ when isMainModule:
latest = false
localDocsOnly = false
localDocsOut = ""
skipIntegrityCheck = false
while true:
op.next()
case op.kind
@@ -689,12 +691,14 @@ when isMainModule:
localDocsOnly = true
if op.val.len > 0:
localDocsOut = op.val.absolutePath
of "skipintegritycheck":
skipIntegrityCheck = true
else: showHelp(success = false)
of cmdArgument:
case normalize(op.key)
of "boot": boot(op.cmdLineRest)
of "boot": boot(op.cmdLineRest, skipIntegrityCheck)
of "clean": clean(op.cmdLineRest)
of "doc", "docs": buildDocs(op.cmdLineRest, localDocsOnly, localDocsOut)
of "doc", "docs": buildDocs(op.cmdLineRest & paCode, localDocsOnly, localDocsOut)
of "doc0", "docs0":
# undocumented command for Araq-the-merciful:
buildDocs(op.cmdLineRest & gaCode)

15
lib/compilation.nim Normal file
View File

@@ -0,0 +1,15 @@
const
NimMajor* {.intdefine.}: int = 1
## is the major number of Nim's version. Example:
##
## .. code-block:: Nim
## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard
# see also std/private/since
NimMinor* {.intdefine.}: int = 6
## is the minor number of Nim's version.
## Odd for devel, even for releases.
NimPatch* {.intdefine.}: int = 21
## is the patch number of Nim's version.
## Odd for devel, even for releases.

View File

@@ -135,8 +135,9 @@ type
const
nnkLiterals* = {nnkCharLit..nnkNilLit}
# see matching set CallNodes below
nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
nnkCallStrLit}
nnkCallStrLit, nnkHiddenCallConv}
nnkPragmaCallKinds = {nnkExprColonExpr, nnkCall, nnkCallStrLit}
{.push warnings: off.}
@@ -508,6 +509,22 @@ proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.}
proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.}
## Copy lineinfo from `info`.
proc setLine(arg: NimNode, line: uint16) {.magic: "NLineInfo", noSideEffect.}
proc setColumn(arg: NimNode, column: int16) {.magic: "NLineInfo", noSideEffect.}
proc setFile(arg: NimNode, file: string) {.magic: "NLineInfo", noSideEffect.}
proc setLineInfo*(arg: NimNode, file: string, line: int, column: int) =
## Sets the line info on the NimNode. The file needs to exists, but can be a
## relative path. If you want to attach line info to a block using `quote`
## you'll need to add the line information after the quote block.
arg.setFile(file)
arg.setLine(line.uint16)
arg.setColumn(column.int16)
proc setLineInfo*(arg: NimNode, lineInfo: LineInfo) =
## See `setLineInfo proc<#setLineInfo,NimNode,string,int,int>`_
setLineInfo(arg, lineInfo.filename, lineInfo.line, lineInfo.column)
proc lineInfoObj*(n: NimNode): LineInfo =
## Returns `LineInfo` of `n`, using absolute path for `filename`.
result = LineInfo(filename: n.getFile, line: n.getLine, column: n.getColumn)
@@ -1158,8 +1175,8 @@ const
RoutineNodes* = {nnkProcDef, nnkFuncDef, nnkMethodDef, nnkDo, nnkLambda,
nnkIteratorDef, nnkTemplateDef, nnkConverterDef, nnkMacroDef}
AtomicNodes* = {nnkNone..nnkNilLit}
CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
nnkCallStrLit, nnkHiddenCallConv}
# see matching set nnkCallKinds above
CallNodes* = nnkCallKinds
proc expectKind*(n: NimNode; k: set[NimNodeKind]) =
## Checks that `n` is of kind `k`. If this is not the case,
@@ -1274,12 +1291,19 @@ proc `name=`*(someProc: NimNode; val: NimNode) =
else: someProc[0] = val
proc params*(someProc: NimNode): NimNode =
someProc.expectRoutine
result = someProc[3]
if someProc.kind == nnkProcTy:
someProc[0]
else:
someProc.expectRoutine
someProc[3]
proc `params=`* (someProc: NimNode; params: NimNode) =
someProc.expectRoutine
expectKind(params, nnkFormalParams)
someProc[3] = params
if someProc.kind == nnkProcTy:
someProc[0] = params
else:
someProc.expectRoutine
someProc[3] = params
proc pragma*(someProc: NimNode): NimNode =
## Get the pragma of a proc type.
@@ -1498,16 +1522,37 @@ macro expandMacros*(body: typed): untyped =
echo body.toStrLit
result = body
proc extractTypeImpl(n: NimNode): NimNode =
## attempts to extract the type definition of the given symbol
case n.kind
of nnkSym: # can extract an impl
result = n.getImpl.extractTypeImpl()
of nnkObjectTy, nnkRefTy, nnkPtrTy: result = n
of nnkBracketExpr:
if n.typeKind == ntyTypeDesc:
result = n[1].extractTypeImpl()
else:
doAssert n.typeKind == ntyGenericInst
result = n[0].getImpl()
of nnkTypeDef:
result = n[2]
else: error("Invalid node to retrieve type implementation of: " & $n.kind)
proc customPragmaNode(n: NimNode): NimNode =
expectKind(n, {nnkSym, nnkDotExpr, nnkBracketExpr, nnkTypeOfExpr, nnkCheckedFieldExpr})
expectKind(n, {nnkSym, nnkDotExpr, nnkBracketExpr, nnkTypeOfExpr, nnkType, nnkCheckedFieldExpr})
let
typ = n.getTypeInst()
if typ.kind == nnkBracketExpr and typ.len > 1 and typ[1].kind == nnkProcTy:
return typ[1][1]
elif typ.typeKind == ntyTypeDesc:
let impl = typ[1].getImpl()
if impl[0].kind == nnkPragmaExpr:
let impl = getImpl(
if kind(typ[1]) == nnkBracketExpr: typ[1][0]
else: typ[1]
)
if impl.kind == nnkNilLit:
return impl
elif impl[0].kind == nnkPragmaExpr:
return impl[0][1]
else:
return impl[0] # handle types which don't have macro at all
@@ -1527,12 +1572,13 @@ proc customPragmaNode(n: NimNode): NimNode =
if n.kind in {nnkDotExpr, nnkCheckedFieldExpr}:
let name = $(if n.kind == nnkCheckedFieldExpr: n[0][1] else: n[1])
let typInst = getTypeInst(if n.kind == nnkCheckedFieldExpr or n[0].kind == nnkHiddenDeref: n[0][0] else: n[0])
var typDef = getImpl(if typInst.kind == nnkVarTy: typInst[0] else: typInst)
var typInst = getTypeInst(if n.kind == nnkCheckedFieldExpr or n[0].kind == nnkHiddenDeref: n[0][0] else: n[0])
while typInst.kind in {nnkVarTy, nnkBracketExpr}: typInst = typInst[0]
var typDef = getImpl(typInst)
while typDef != nil:
typDef.expectKind(nnkTypeDef)
let typ = typDef[2]
typ.expectKind({nnkRefTy, nnkPtrTy, nnkObjectTy})
let typ = typDef[2].extractTypeImpl()
if typ.kind notin {nnkRefTy, nnkPtrTy, nnkObjectTy}: break
let isRef = typ.kind in {nnkRefTy, nnkPtrTy}
if isRef and typ[0].kind in {nnkSym, nnkBracketExpr}: # defines ref type for another object(e.g. X = ref X)
typDef = getImpl(typ[0])
@@ -1613,7 +1659,7 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped =
let pragmaNode = customPragmaNode(n)
for p in pragmaNode:
if p.kind in nnkPragmaCallKinds and p.len > 0 and p[0].kind == nnkSym and p[0] == cp:
if p.len == 2:
if p.len == 2 or (p.len == 3 and p[1].kind == nnkSym and p[1].symKind == nskType):
result = p[1]
else:
let def = p[0].getImpl[3]

View File

@@ -133,7 +133,7 @@ proc getErrInfo(db: var DbConn): tuple[res: int, ss, ne, msg: string] {.
511.TSqlSmallInt, retSz.addr)
except:
discard
return (res.int, $(addr sqlState), $(addr nativeErr), $(addr errMsg))
return (res.int, $(cast[cstring](addr sqlState)), $cast[cstring](addr nativeErr), $cast[cstring](addr errMsg))
proc dbError*(db: var DbConn) {.
tags: [ReadDbEffect, WriteDbEffect], raises: [DbError] .} =
@@ -183,7 +183,7 @@ proc sqlGetDBMS(db: var DbConn): string {.
db.sqlCheck(SQLGetInfo(db.hDb, SQL_DBMS_NAME, cast[SqlPointer](buf.addr),
4095.TSqlSmallInt, sz.addr))
except: discard
return $(addr buf)
return $(cast[cstring](addr buf))
proc dbQuote*(s: string): string {.noSideEffect.} =
## DB quotes the string.
@@ -294,7 +294,7 @@ iterator fastRows*(db: var DbConn, query: SqlQuery,
buf[0] = '\0'
db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
cast[cstring](buf.addr), 4095, sz.addr))
rowRes[colId-1] = $(addr buf)
rowRes[colId-1] = $cast[cstring]((addr buf))
yield rowRes
res = SQLFetch(db.stmt)
properFreeResult(SQL_HANDLE_STMT, db.stmt)
@@ -322,7 +322,7 @@ iterator instantRows*(db: var DbConn, query: SqlQuery,
buf[0] = '\0'
db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
cast[cstring](buf.addr), 4095, sz.addr))
rowRes[colId-1] = $(addr buf)
rowRes[colId-1] = $cast[cstring](addr buf)
yield (row: rowRes, len: cCnt.int)
res = SQLFetch(db.stmt)
properFreeResult(SQL_HANDLE_STMT, db.stmt)
@@ -361,7 +361,7 @@ proc getRow*(db: var DbConn, query: SqlQuery,
buf[0] = '\0'
db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
cast[cstring](buf.addr), 4095, sz.addr))
rowRes[colId-1] = $(addr buf)
rowRes[colId-1] = $cast[cstring](addr buf)
res = SQLFetch(db.stmt)
result = rowRes
properFreeResult(SQL_HANDLE_STMT, db.stmt)
@@ -389,7 +389,7 @@ proc getAllRows*(db: var DbConn, query: SqlQuery,
buf[0] = '\0'
db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
cast[cstring](buf.addr), 4095, sz.addr))
rowRes[colId-1] = $(addr buf)
rowRes[colId-1] = $cast[cstring](addr buf)
rows.add(rowRes)
res = SQLFetch(db.stmt)
result = rows

View File

@@ -207,7 +207,8 @@ proc prepare*(db: DbConn; stmtName: string, query: SqlQuery;
dbError("parameter substitution expects \"$1\"")
var res = pqprepare(db, stmtName, query.string, int32(nParams), nil)
if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
return SqlPrepared(stmtName)
result = SqlPrepared(stmtName)
pqclear(res)
proc setRow(res: PPGresult, r: var Row, line, cols: int32) =
for col in 0'i32..cols-1:
@@ -474,12 +475,12 @@ proc getRow*(db: DbConn, query: SqlQuery,
## retrieves a single row. If the query doesn't return any rows, this proc
## will return a Row with empty strings for each column.
let res = setupQuery(db, query, args)
getRow(res)
result = getRow(res)
proc getRow*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
let res = setupQuery(db, stmtName, args)
getRow(res)
result = getRow(res)
proc getAllRows(res: PPGresult): seq[Row] =
let N = pqntuples(res)
@@ -496,14 +497,14 @@ proc getAllRows*(db: DbConn, query: SqlQuery,
tags: [ReadDbEffect].} =
## executes the query and returns the whole result dataset.
let res = setupQuery(db, query, args)
getAllRows(res)
result = getAllRows(res)
proc getAllRows*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): seq[Row] {.tags:
[ReadDbEffect].} =
## executes the prepared query and returns the whole result dataset.
let res = setupQuery(db, stmtName, args)
getAllRows(res)
result = getAllRows(res)
iterator rows*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
@@ -529,7 +530,8 @@ proc getValue*(db: DbConn, query: SqlQuery,
## result dataset. Returns "" if the dataset contains no rows or the database
## value is NULL.
let res = setupQuery(db, query, args)
getValue(res)
result = getValue(res)
pqclear(res)
proc getValue*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string, `$`]): string {.
@@ -538,7 +540,8 @@ proc getValue*(db: DbConn, stmtName: SqlPrepared,
## result dataset. Returns "" if the dataset contains no rows or the database
## value is NULL.
let res = setupQuery(db, stmtName, args)
getValue(res)
result = getValue(res)
pqclear(res)
proc tryInsertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.
@@ -547,12 +550,14 @@ proc tryInsertID*(db: DbConn, query: SqlQuery,
## generated ID for the row or -1 in case of an error. For Postgre this adds
## `RETURNING id` to the query, so it only works if your primary key is
## named `id`.
var x = pqgetvalue(setupQuery(db, SqlQuery(string(query) & " RETURNING id"),
args), 0, 0)
let res = setupQuery(db, SqlQuery(string(query) & " RETURNING id"),
args)
var x = pqgetvalue(res, 0, 0)
if not isNil(x):
result = parseBiggestInt($x)
else:
result = -1
pqclear(res)
proc insertID*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): int64 {.
@@ -569,12 +574,14 @@ proc tryInsert*(db: DbConn, query: SqlQuery,pkName: string,
{.tags: [WriteDbEffect], since: (1, 3).}=
## executes the query (typically "INSERT") and returns the
## generated ID for the row or -1 in case of an error.
var x = pqgetvalue(setupQuery(db, SqlQuery(string(query) & " RETURNING " & pkName),
args), 0, 0)
let res = setupQuery(db, SqlQuery(string(query) & " RETURNING " & pkName),
args)
var x = pqgetvalue(res, 0, 0)
if not isNil(x):
result = parseBiggestInt($x)
else:
result = -1
pqclear(res)
proc insert*(db: DbConn, query: SqlQuery, pkName: string,
args: varargs[string, `$`]): int64

View File

@@ -17,8 +17,7 @@ const
DomApiVersion* = 3 ## the version of DOM API we try to follow. No guarantees though.
type
EventTarget* = ref EventTargetObj
EventTargetObj {.importc.} = object of RootObj
EventTarget* {.importc.} = ref object of RootObj
onabort*: proc (event: Event) {.closure.}
onblur*: proc (event: Event) {.closure.}
onchange*: proc (event: Event) {.closure.}
@@ -129,8 +128,7 @@ type
Storage* {.importc.} = ref object
Window* = ref WindowObj
WindowObj {.importc.} = object of EventTargetObj
Window* {.importc.} = ref object of EventTarget
document*: Document
event*: Event
history*: History
@@ -159,11 +157,9 @@ type
sessionStorage*: Storage
parent*: Window
Frame* = ref FrameObj
FrameObj {.importc.} = object of WindowObj
Frame* {.importc.} = ref object of Window
ClassList* = ref ClassListObj
ClassListObj {.importc.} = object of RootObj
ClassList* {.importc.} = ref object of RootObj
NodeType* = enum
ElementNode = 1,
@@ -179,8 +175,7 @@ type
DocumentFragmentNode,
NotationNode
Node* = ref NodeObj
NodeObj {.importc.} = object of EventTargetObj
Node* {.importc.} = ref object of EventTarget
attributes*: seq[Node]
childNodes*: seq[Node]
children*: seq[Node]
@@ -204,8 +199,7 @@ type
parentElement*: Element
isConnected*: bool
Document* = ref DocumentObj
DocumentObj {.importc.} = object of NodeObj
Document* {.importc.} = ref object of Node
activeElement*: Element
documentElement*: Element
alinkColor*: cstring
@@ -230,8 +224,7 @@ type
links*: seq[LinkElement]
fonts*: FontFaceSet
Element* = ref ElementObj
ElementObj {.importc.} = object of NodeObj
Element* {.importc.} = ref object of Node
className*: cstring
classList*: ClassList
checked*: bool
@@ -252,8 +245,7 @@ type
offsetLeft*: int
offsetTop*: int
ValidityState* = ref ValidityStateObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/ValidityState>`_
ValidityStateObj {.importc.} = object
ValidityState* {.importc.} = ref object ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/ValidityState>`_
badInput*: bool
customError*: bool
patternMismatch*: bool
@@ -266,25 +258,21 @@ type
valid*: bool
valueMissing*: bool
Blob* = ref BlobObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/Blob>`_
BlobObj {.importc.} = object of RootObj
Blob* {.importc.} = ref object of RootObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/Blob>`_
size*: int
`type`*: cstring
File* = ref FileObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/File>`_
FileObj {.importc.} = object of Blob
File* {.importc.} = ref object of Blob ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/File>`_
lastModified*: int
name*: cstring
TextAreaElement* = ref TextAreaElementObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement>`_
TextAreaElementObj {.importc.} = object of Element
TextAreaElement* {.importc.} = ref object of Element ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement>`_
value*: cstring
selectionStart*, selectionEnd*: int
selectionDirection*: cstring
rows*, cols*: int
InputElement* = ref InputElementObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement>`_
InputElementObj {.importc.} = object of Element
InputElement* {.importc.} = ref object of Element ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement>`_
# Properties related to the parent form
formAction*: cstring
formEncType*: cstring
@@ -336,15 +324,13 @@ type
valueAsDate*: cstring
valueAsNumber*: float
LinkElement* = ref LinkObj
LinkObj {.importc.} = object of ElementObj
LinkElement* {.importc.} = ref object of Element
target*: cstring
text*: cstring
x*: int
y*: int
EmbedElement* = ref EmbedObj
EmbedObj {.importc.} = object of ElementObj
EmbedElement* {.importc.} = ref object of Element
height*: int
hspace*: int
src*: cstring
@@ -352,21 +338,18 @@ type
`type`*: cstring
vspace*: int
AnchorElement* = ref AnchorObj
AnchorObj {.importc.} = object of ElementObj
AnchorElement* {.importc.} = ref object of Element
text*: cstring
x*, y*: int
OptionElement* = ref OptionObj
OptionObj {.importc.} = object of ElementObj
OptionElement* {.importc.} = ref object of Element
defaultSelected*: bool
selected*: bool
selectedIndex*: int
text*: cstring
value*: cstring
FormElement* = ref FormObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement>`_
FormObj {.importc.} = object of ElementObj
FormElement* {.importc.} = ref object of Element ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement>`_
acceptCharset*: cstring
action*: cstring
autocomplete*: cstring
@@ -378,8 +361,7 @@ type
noValidate*: bool
target*: cstring
ImageElement* = ref ImageObj
ImageObj {.importc.} = object of ElementObj
ImageElement* {.importc.} = ref object of Element
border*: int
complete*: bool
height*: int
@@ -389,8 +371,7 @@ type
vspace*: int
width*: int
Style* = ref StyleObj
StyleObj {.importc.} = object of RootObj
Style* {.importc.} = ref object of RootObj
alignContent*: cstring
alignItems*: cstring
alignSelf*: cstring
@@ -766,8 +747,7 @@ type
AtTarget,
BubblingPhase
Event* = ref EventObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/Event>`_
EventObj {.importc.} = object of RootObj
Event* {.importc.} = ref object of RootObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/Event>`_
bubbles*: bool
cancelBubble*: bool
cancelable*: bool
@@ -779,13 +759,11 @@ type
`type`*: cstring
isTrusted*: bool
UIEvent* = ref UIEventObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/UIEvent>`_
UIEventObj {.importc.} = object of Event
UIEvent* {.importc.} = ref object of Event ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/UIEvent>`_
detail*: int64
view*: Window
KeyboardEvent* = ref KeyboardEventObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent>`_
KeyboardEventObj {.importc.} = object of UIEvent
KeyboardEvent* {.importc.} = ref object of UIEvent ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent>`_
altKey*, ctrlKey*, metaKey*, shiftKey*: bool
code*: cstring
isComposing*: bool
@@ -1147,8 +1125,7 @@ type
FourthButton = 8,
FifthButton = 16
MouseEvent* = ref MouseEventObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent>`_
MouseEventObj {.importc.} = object of UIEvent
MouseEvent* {.importc.} = ref object of UIEvent ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent>`_
altKey*, ctrlKey*, metaKey*, shiftKey*: bool
button*: int
buttons*: int
@@ -1165,13 +1142,11 @@ type
File = "file",
String = "string"
DataTransferItem* = ref DataTransferItemObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem>`_
DataTransferItemObj {.importc.} = object of RootObj
DataTransferItem* {.importc.} = ref object of RootObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem>`_
kind*: cstring
`type`*: cstring
DataTransfer* = ref DataTransferObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer>`_
DataTransferObj {.importc.} = object of RootObj
DataTransfer* {.importc.} = ref object of RootObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer>`_
dropEffect*: cstring
effectAllowed*: cstring
files*: seq[Element]
@@ -1213,8 +1188,7 @@ type
## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent>`_
clipboardData*: DataTransfer
StorageEvent* = ref StorageEventObj ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/StorageEvent>`_
StorageEventObj {.importc.} = object of Event
StorageEvent* {.importc.} = ref object of Event ## see `docs<https://developer.mozilla.org/en-US/docs/Web/API/StorageEvent>`_
key*: cstring
newValue*, oldValue*: cstring
storageArea*: Storage
@@ -1223,8 +1197,7 @@ type
TouchList* {.importc.} = ref object of RootObj
length*: int
Touch* = ref TouchObj
TouchObj {.importc.} = object of RootObj
Touch* {.importc.} = ref object of RootObj
identifier*: int
screenX*, screenY*, clientX*, clientY*, pageX*, pageY*: int
target*: Element
@@ -1232,12 +1205,10 @@ type
rotationAngle*: int
force*: float
TouchEvent* = ref TouchEventObj
TouchEventObj {.importc.} = object of UIEvent
TouchEvent* {.importc.} = ref object of UIEvent
changedTouches*, targetTouches*, touches*: seq[Touch]
Location* = ref LocationObj
LocationObj {.importc.} = object of RootObj
Location* {.importc.} = ref object of RootObj
hash*: cstring
host*: cstring
hostname*: cstring
@@ -1248,12 +1219,10 @@ type
search*: cstring
origin*: cstring
History* = ref HistoryObj
HistoryObj {.importc.} = object of RootObj
History* {.importc.} = ref object of RootObj
length*: int
Navigator* = ref NavigatorObj
NavigatorObj {.importc.} = object of RootObj
Navigator* {.importc.} = ref object of RootObj
appCodeName*: cstring
appName*: cstring
appVersion*: cstring
@@ -1291,8 +1260,7 @@ type
ToolBar* = LocationBar
StatusBar* = LocationBar
Screen = ref ScreenObj
ScreenObj {.importc.} = object of RootObj
Screen* {.importc.} = ref object of RootObj
availHeight*: int
availWidth*: int
colorDepth*: int
@@ -1332,31 +1300,26 @@ since (1, 3):
## let prsr = newDomParser()
## discard prsr.parseFromString("<html><marquee>Hello World</marquee></html>".cstring, "text/html".cstring)
DomException* = ref DOMExceptionObj
DomException* {.importc.} = ref object
## The DOMException interface represents an abnormal event (called an exception)
## which occurs as a result of calling a method or accessing a property of a web API.
## Each exception has a name, which is a short "CamelCase" style string identifying
## the error or abnormal condition.
## https://developer.mozilla.org/en-US/docs/Web/API/DOMException
DOMExceptionObj {.importc.} = object
FileReader* = ref FileReaderObj
FileReader* {.importc.} = ref object of EventTarget
## The FileReader object lets web applications asynchronously read the contents of files
## (or raw data buffers) stored on the user's computer, using File or Blob objects to specify
## the file or data to read.
## https://developer.mozilla.org/en-US/docs/Web/API/FileReader
FileReaderObj {.importc.} = object of EventTargetObj
FileReaderState* = distinct range[0'u16..2'u16]
RootNodeOptions* = object of RootObj
composed*: bool
DocumentOrShadowRoot* {.importc.} = object of RootObj
activeElement*: Element
# styleSheets*: StyleSheetList
ShadowRoot* = ref ShadowRootObj
ShadowRootObj {.importc.} = object of DocumentOrShadowRoot
ShadowRoot* {.importc.} = ref object of DocumentOrShadowRoot
delegatesFocus*: bool
host*: Element
innerHTML*: cstring
@@ -1365,8 +1328,7 @@ since (1, 3):
mode*: cstring
delegatesFocus*: bool
HTMLSlotElement* = ref HTMLSlotElementObj
HTMLSlotElementObj {.importc.} = object of RootObj
HTMLSlotElement* {.importc.} = ref object of RootObj
name*: cstring
SlotOptions* = object of RootObj
flatten*: bool

View File

@@ -125,7 +125,13 @@ __AVR__
NIM_THREADVAR declaration based on
http://stackoverflow.com/questions/18298280/how-to-declare-a-variable-as-thread-local-portably
*/
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
#if defined _WIN32
# if defined _MSC_VER || defined __DMC__ || defined __BORLANDC__
# define NIM_THREADVAR __declspec(thread)
# else
# define NIM_THREADVAR __thread
# endif
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
# define NIM_THREADVAR _Thread_local
#elif defined _WIN32 && ( \
defined _MSC_VER || \

View File

@@ -1513,7 +1513,7 @@ proc getFootnoteType(label: PRstNode): (FootnoteType, int) =
elif label.len == 1 and label.sons[0].kind == rnLeaf:
try:
result = (fnManualNumber, parseInt(label.sons[0].text))
except:
except ValueError:
result = (fnCitation, -1)
else:
result = (fnCitation, -1)
@@ -2420,13 +2420,13 @@ proc parseEnumList(p: var RstParser): PRstNode =
let enumerator = p.tok[p.idx + 1 + wildIndex[w]].symbol
# check that it's in sequence: enumerator == next(prevEnum)
if "n" in wildcards[w]: # arabic numeral
let prevEnumI = try: parseInt(prevEnum) except: 1
let prevEnumI = try: parseInt(prevEnum) except ValueError: 1
if enumerator in autoEnums:
if prevAE != "" and enumerator != prevAE:
break
prevAE = enumerator
curEnum = prevEnumI + 1
else: curEnum = (try: parseInt(enumerator) except: 1)
else: curEnum = (try: parseInt(enumerator) except ValueError: 1)
if curEnum - prevEnumI != 1:
break
prevEnum = enumerator

View File

@@ -198,8 +198,29 @@ proc open*(a1: cstring, a2: cint, mode: Mode | cint = 0.Mode): cint {.inline.} =
proc posix_fadvise*(a1: cint, a2, a3: Off, a4: cint): cint {.
importc, header: "<fcntl.h>".}
proc posix_fallocate*(a1: cint, a2, a3: Off): cint {.
importc, header: "<fcntl.h>".}
proc ftruncate*(a1: cint, a2: Off): cint {.importc, header: "<unistd.h>".}
when defined(osx): # 2001 POSIX evidently does not concern Apple
type FStore {.importc: "fstore_t", header: "<fcntl.h>", bycopy.} = object
fst_flags: uint32 ## IN: flags word
fst_posmode: cint ## IN: indicates offset field
fst_offset, ## IN: start of the region
fst_length, ## IN: size of the region
fst_bytesalloc: Off ## OUT: number of bytes allocated
var F_PEOFPOSMODE {.importc, header: "<fcntl.h>".}: cint
var F_ALLOCATEALL {.importc, header: "<fcntl.h>".}: uint32
var F_PREALLOCATE {.importc, header: "<fcntl.h>".}: cint
proc posix_fallocate*(a1: cint, a2, a3: Off): cint =
var fst = FStore(fst_flags: F_ALLOCATEALL, fst_posmode: F_PEOFPOSMODE,
fst_offset: a2, fst_length: a3)
# Must also call ftruncate to match what POSIX does. Unlike posix_fallocate,
# this can shrink files. Could guard w/getFileSize, but caller likely knows
# present size & has no good reason to call this unless it is growing.
if fcntl(a1, F_PREALLOCATE, fst.addr) != cint(-1): ftruncate(a1, a2 + a3)
else: cint(-1)
else:
proc posix_fallocate*(a1: cint, a2, a3: Off): cint {.
importc, header: "<fcntl.h>".}
when not defined(haiku) and not defined(openbsd):
proc fmtmsg*(a1: int, a2: cstring, a3: cint,
@@ -488,7 +509,6 @@ proc fpathconf*(a1, a2: cint): int {.importc, header: "<unistd.h>".}
proc fsync*(a1: cint): cint {.importc, header: "<unistd.h>".}
## synchronize a file's buffer cache to the storage device
proc ftruncate*(a1: cint, a2: Off): cint {.importc, header: "<unistd.h>".}
proc getcwd*(a1: cstring, a2: int): cstring {.importc, header: "<unistd.h>", sideEffect.}
proc getuid*(): Uid {.importc, header: "<unistd.h>", sideEffect.}
## returns the real user ID of the calling process

View File

@@ -309,7 +309,7 @@ type
sa_mask*: Sigset ## Set of signals to be blocked during execution of
## the signal handling function.
sa_flags*: cint ## Special flags.
sa_sigaction*: proc (x: cint, y: ptr SigInfo, z: pointer) {.noconv.}
sa_restorer: proc() {.noconv.} ## not intended for application use.
Stack* {.importc: "stack_t",
header: "<signal.h>", final, pure.} = object ## stack_t
@@ -325,9 +325,9 @@ type
SigInfo* {.importc: "siginfo_t",
header: "<signal.h>", final, pure.} = object ## siginfo_t
si_signo*: cint ## Signal number.
si_code*: cint ## Signal code.
si_errno*: cint ## If non-zero, an errno value associated with
## this signal, as defined in <errno.h>.
si_code*: cint ## Signal code.
si_pid*: Pid ## Sending process ID.
si_uid*: Uid ## Real user ID of sending process.
si_addr*: pointer ## Address of faulting instruction.
@@ -336,6 +336,12 @@ type
si_value*: SigVal ## Signal value.
pad {.importc: "_pad".}: array[128 - 56, uint8]
template sa_sigaction*(v: Sigaction): proc (x: cint, y: ptr SigInfo, z: pointer) {.noconv.} =
cast[proc (x: cint, y: ptr SigInfo, z: pointer) {.noconv.}](v.sa_handler)
proc `sa_sigaction=`*(v: var Sigaction, x: proc (x: cint, y: ptr SigInfo, z: pointer) {.noconv.}) =
v.sa_handler = cast[proc (x: cint) {.noconv.}](x)
type
Nl_item* {.importc: "nl_item", header: "<nl_types.h>".} = cint
Nl_catd* {.importc: "nl_catd", header: "<nl_types.h>".} = pointer
@@ -428,8 +434,8 @@ type
header: "<sys/socket.h>",
pure, final.} = object ## struct sockaddr_storage
ss_family*: TSa_Family ## Address family.
ss_padding: array[128 - sizeof(cshort) - sizeof(culong), char]
ss_align: clong
ss_padding {.importc: "__ss_padding".}: array[128 - sizeof(cshort) - sizeof(culong), char]
ss_align {.importc: "__ss_align".}: clong
Tif_nameindex* {.importc: "struct if_nameindex", final,
pure, header: "<net/if.h>".} = object ## struct if_nameindex

View File

@@ -464,6 +464,7 @@ const MSG_EOR* = cint(128)
const MSG_OOB* = cint(1)
const SCM_RIGHTS* = cint(1)
const SO_ACCEPTCONN* = cint(30)
const SO_BINDTODEVICE* = cint(25)
const SO_BROADCAST* = cint(6)
const SO_DEBUG* = cint(1)
const SO_DONTROUTE* = cint(5)

View File

@@ -473,6 +473,7 @@ var MSG_EOR* {.importc: "MSG_EOR", header: "<sys/socket.h>".}: cint
var MSG_OOB* {.importc: "MSG_OOB", header: "<sys/socket.h>".}: cint
var SCM_RIGHTS* {.importc: "SCM_RIGHTS", header: "<sys/socket.h>".}: cint
var SO_ACCEPTCONN* {.importc: "SO_ACCEPTCONN", header: "<sys/socket.h>".}: cint
var SO_BINDTODEVICE* {.importc: "SO_BINDTODEVICE", header: "<sys/socket.h>".}: cint
var SO_BROADCAST* {.importc: "SO_BROADCAST", header: "<sys/socket.h>".}: cint
var SO_DEBUG* {.importc: "SO_DEBUG", header: "<sys/socket.h>".}: cint
var SO_DONTROUTE* {.importc: "SO_DONTROUTE", header: "<sys/socket.h>".}: cint

View File

@@ -18,7 +18,7 @@ type Uname* = object
sysname*, nodename*, release*, version*, machine*: string
template charArrayToString(input: typed): string =
$cstring(addr input)
$cast[cstring](addr input)
proc uname*(): Uname =
## Provides system information in a `Uname` struct with sysname, nodename,

View File

@@ -25,7 +25,7 @@ type
finished: bool
error*: ref Exception ## Stored exception
errorStackTrace*: string
when not defined(release):
when not defined(release) or defined(futureLogging):
stackTrace: seq[StackTraceEntry] ## For debugging purposes only.
id: int
fromProc: string

View File

@@ -149,13 +149,13 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
protocol)
result.orig = protocol
i.inc protocol.parseSaturatedNatural(result.major, i)
i.inc # Skip .
if i < protocol.len: inc i # Skip .
i.inc protocol.parseSaturatedNatural(result.minor, i)
proc sendStatus(client: AsyncSocket, status: string): Future[void] =
client.send("HTTP/1.1 " & status & "\c\L\c\L")
func hasChunkedEncoding(request: Request): bool =
func hasChunkedEncoding(request: Request): bool =
## Searches for a chunked transfer encoding
const transferEncoding = "Transfer-Encoding"
@@ -294,7 +294,7 @@ proc processRequest(
while true:
lineFut.mget.setLen(0)
lineFut.clean()
# The encoding format alternates between specifying a number of bytes to read
# and the data to be read, of the previously specified size
if sizeOrData mod 2 == 0:
@@ -375,7 +375,7 @@ const
proc listen*(server: AsyncHttpServer; port: Port; address = ""; domain = AF_INET) =
## Listen to the given port and address.
when declared(maxDescriptors):
server.maxFDs = try: maxDescriptors() except: nimMaxDescriptorsFallback
server.maxFDs = try: maxDescriptors() except OSError: nimMaxDescriptorsFallback
else:
server.maxFDs = nimMaxDescriptorsFallback
server.socket = newAsyncSocket(domain)

View File

@@ -265,8 +265,8 @@ macro async*(prc: untyped): untyped =
proc splitParamType(paramType: NimNode, async: bool): NimNode =
result = paramType
if paramType.kind == nnkInfix and paramType[0].strVal in ["|", "or"]:
let firstAsync = "async" in paramType[1].strVal.normalize
let secondAsync = "async" in paramType[2].strVal.normalize
let firstAsync = "async" in paramType[1].toStrLit().strVal.normalize
let secondAsync = "async" in paramType[2].toStrLit().strVal.normalize
if firstAsync:
result = paramType[if async: 1 else: 2]

View File

@@ -226,7 +226,7 @@ when defineSsl:
let len = bioCtrlPending(socket.bioOut)
if len > 0:
var data = newString(len)
let read = bioRead(socket.bioOut, addr data[0], len)
let read = bioRead(socket.bioOut, cast[cstring](addr data[0]), len)
assert read != 0
if read < 0:
raiseSSLError()
@@ -244,7 +244,7 @@ when defineSsl:
var data = await recv(socket.fd.AsyncFD, BufferSize, flags)
let length = len(data)
if length > 0:
let ret = bioWrite(socket.bioIn, addr data[0], length.cint)
let ret = bioWrite(socket.bioIn, cast[cstring](addr data[0]), length.cint)
if ret < 0:
raiseSSLError()
elif length == 0:
@@ -455,7 +455,7 @@ proc send*(socket: AsyncSocket, data: string,
when defineSsl:
var copy = data
sslLoop(socket, flags,
sslWrite(socket.sslHandle, addr copy[0], copy.len.cint))
sslWrite(socket.sslHandle, cast[cstring](addr copy[0]), copy.len.cint))
await sendPendingSslData(socket, flags)
else:
await send(socket.fd.AsyncFD, data, flags)

View File

@@ -66,14 +66,10 @@ template cbBase(a, b): untyped = [
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', a, b]
let
const
cb64 = cbBase('+', '/')
cb64safe = cbBase('-', '_')
const
cb64VM = cbBase('+', '/')
cb64safeVM = cbBase('-', '_')
const
invalidChar = 255
@@ -132,14 +128,10 @@ template encodeInternal(s, alphabet: typed): untyped =
result.setLen(outputIndex)
template encodeImpl() {.dirty.} =
when nimvm:
block:
let lookupTableVM = if safe: cb64safeVM else: cb64VM
encodeInternal(s, lookupTableVM)
if safe:
encodeInternal(s, cb64safe)
else:
block:
let lookupTable = if safe: unsafeAddr(cb64safe) else: unsafeAddr(cb64)
encodeInternal(s, lookupTable)
encodeInternal(s, cb64)
proc encode*[T: SomeInteger|char](s: openArray[T], safe = false): string =
## Encodes `s` into base64 representation.
@@ -247,7 +239,7 @@ proc decode*(s: string): string =
inputLen = s.len
inputEnds = 0
# strip trailing characters
while s[inputLen - 1] in {'\n', '\r', ' ', '='}:
while inputLen > 0 and s[inputLen - 1] in {'\n', '\r', ' ', '='}:
dec inputLen
# hot loop: read 4 characters at at time
inputEnds = inputLen - 4

View File

@@ -35,15 +35,17 @@ proc prepare(s: string): string =
else:
result = "file://" & absolutePath(s)
proc openDefaultBrowserImpl(url: string) =
proc openDefaultBrowserImplPrep(url: string) =
## note the url argument should be alreadly prepared, i.e. the url is passed "AS IS"
when defined(windows):
var o = newWideCString(osOpenCmd)
var u = newWideCString(prepare url)
var u = newWideCString(url)
discard shellExecuteW(0'i32, o, u, nil, nil, SW_SHOWNORMAL)
elif defined(macosx):
discard execShellCmd(osOpenCmd & " " & quoteShell(prepare url))
discard execShellCmd(osOpenCmd & " " & quoteShell(url))
else:
var u = quoteShell(prepare url)
var u = quoteShell(url)
if execShellCmd(osOpenCmd & " " & u) == 0: return
for b in getEnv("BROWSER").split(PathSep):
try:
@@ -53,6 +55,9 @@ proc openDefaultBrowserImpl(url: string) =
except OSError:
discard
proc openDefaultBrowserImpl(url: string) =
openDefaultBrowserImplPrep(prepare url)
proc openDefaultBrowser*(url: string) =
## Opens `url` with the user's default browser. This does not block.
## The URL must not be empty string, to open on a blank page see `openDefaultBrowser()`.
@@ -86,4 +91,4 @@ proc openDefaultBrowser*() {.since: (1, 1).} =
##
## .. code-block:: nim
## block: openDefaultBrowser()
openDefaultBrowserImpl("http:about:blank") # See IETF RFC-6694 Section 3.
openDefaultBrowserImplPrep("about:blank") # See IETF RFC-6694 Section 3.

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