Compare commits

...

203 Commits

Author SHA1 Message Date
ringabout
6c34f62785 fixes #24666; Compilation error when formatting a complex number (#24667)
fixes #24666

ref https://github.com/nim-lang/Nim/pull/22924

(cherry picked from commit 485b414fce)
2025-02-05 21:04:43 +01:00
narimiran
46e1322d29 bump NimVersion to 2.2.2 2025-02-04 20:03:53 +01:00
ringabout
27b54fdc76 fixes #24658; cpp compilation failure on Nim 2.2.x (#24663)
fixes #24658

(cherry picked from commit 7695d51fc4)
2025-02-04 20:03:39 +01:00
lit
d594e70d57 doc(tempfiles): update link of getTempDir (#24661)
- tempfiles: update `getTempDir` link... from os.html to appdirs.html
<https://nim-lang.org/docs/appdirs.html#getTempDir>

- ~~nims.md: rm three `std/`, which are out of place~~ (ref
https://github.com/nim-lang/Nim/pull/24661#discussion_r1937293833)

(cherry picked from commit e2bed72b72)
2025-02-04 20:03:30 +01:00
metagn
6bf9265d24 add ambiguous identifier message to generic instantiations (#24646)
fixes #24644

Another option is to include the symbol names and owners in the type
listing as in #24645 but this is a bit verbose.

(cherry picked from commit 0861dabfa7)
2025-01-31 09:37:46 +01:00
metagn
a627c9ba9c don't mark captured field sym in template as fully used (#24660)
fixes #24657

(cherry picked from commit 647c6687f1)
2025-01-31 09:37:31 +01:00
lit
7cec03eb1b fix doc format: testament.md (#24654)
- **doc(format): testament: fix `Commands` not regarded as table**

![image](https://github.com/user-attachments/assets/85238dd5-e199-41ca-a8cb-05849415097a)

- **doc(format): testament: row `--target` not splited as columns**

![image](https://github.com/user-attachments/assets/230ec693-c459-4fee-bc57-f3ab6c34a9b6)

(cherry picked from commit af5fd3fea3)
2025-01-31 09:37:26 +01:00
Peter Munch-Ellingsen
123a7ff29f Fix check for Nintendo Switch target (#24652)
This should fix ringabouts comment here:
https://github.com/nim-lang/Nim/pull/24639#issuecomment-2615107496

I wasn't aware that `nintendoswitch` and `posix` would be active at the
same time, so I falsely inverted a check.

(cherry picked from commit cab3342a2d)
2025-01-27 16:58:20 +01:00
Leon Lysak
c0d50ddc26 Update dom.nim (removeEventListener function) (#24650)
Essentially just an update for the `removeEventListener` function as per
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener

(cherry picked from commit 8c3e62e6de)
2025-01-27 08:50:13 +01:00
Tomohiro
2193c3fb70 Fix parseBiggestUInt to detect overflow (#24649)
With some inputs larger than `BiggestUInt.high`, `parseBiggestUInt` proc
in `parseutils.nim` fails to detect overflow and returns random value.
This is because `rawParseUInt` try to detects overflow with `if prev >
res:` but it doesn't detects the overflow from multiplication.
It is possible that `x *= 10` causes overflow and resulting value is
larger than original value.
Here is example values larger than `BiggestUInt.high` but
`parseBiggestUInt` returns without detecting overflow:
```
22751622367522324480000000
41404969074137497600000000
20701551093035827200000000000000000
22546225502460313600000000000000000
204963831854661632000000000000000000
```

Following code search for values larger than `BiggestUInt.high` and
`parseBiggestUInt` cannot detect overflow:
```nim
import std/[strutils]

const
  # Increase this to extend search range
  NBits = 34'u
  NBitsMax1 = 1'u shl NBits
  NBitsMax = NBitsMax1 - 1'u

  # Increase this when there are too many results and want to see only larger result.
  MinMultiply10 = 14

var nfound = 0
for i in (NBitsMax div 10'u + 1'u) .. NBitsMax:
  var
    x = i
    n10 = 0
  for j in 0 ..< NBits:
    let px = x
    x = (x * 10'u) and NBitsMax
    if x < px:
      break
    inc n10
  if n10 >= MinMultiply10:
    echo "i =   ", i
    echo "uint: ", (i shl (64'u - NBits)), '0'.repeat n10
    inc nfound
    if nfound > 15:
      break

echo "found: ", nfound
```

(cherry picked from commit 95b1dda1db)
2025-01-27 08:50:04 +01:00
Peter Munch-Ellingsen
c2b825713c Enable macros to use certain things from the OS module when the target OS is not supported (#24639)
Essentially this PR removes the `{.error.}` pragmas littered around in
the OS module and submodules which prevents them from being imported if
the target OS is not supported. This made it impossible to use certain
supported features of the OS module in macros from a supported host OS.
Instead of the `{.error.}` pragmas the `oscommon` module now has a
constant `supportedSystem` which is false in the cases where the
`{.error.}` pragmas where generated. All procedures which can't be run
by macros is also not declared when `supportedSystem` is false.

It would be possible to create dummy versions of the omitted functions
with an `{.error.}` pragma that would trigger upon their use, but this
is currently not done.

This properly fixes #19414

(cherry picked from commit 1f9cac1f5c)
2025-01-27 08:49:58 +01:00
ringabout
ae011eaeea fixes #21923; nimsuggest "outline" output does not list templates (#24643)
fixes #21923

---------

Co-authored-by: Louis Berube <louis.p.berube@gmail.com>
(cherry picked from commit 67f9bc2f4b)
2025-01-27 08:49:33 +01:00
ringabout
8fe518ed47 fixes #24623; fixes #23692; size pragma only allowed for imported types and enum types (#24640)
fixes #24623
fixes #23692

ref
https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-size-pragma

confines `size` pragma to `enums` and imported `objects` for now

The `typeDefLeftSidePass` carries out the check for pragmas, but the
type is not complete yet. So the `size` pragma checking is postponed at
the final pass.

(cherry picked from commit d6d28a9c79)
2025-01-24 05:10:42 +01:00
metagn
64927c6ae7 don't try to transform objconstr/cast type nodes (#24636)
fixes #24631

[Object
constructors](793baf34ff/compiler/semobjconstr.nim (L462)),
[casts](793baf34ff/compiler/semexprs.nim (L494))
and [type
conversions](793baf34ff/compiler/semexprs.nim (L419))
copy their type nodes verbatim instead of producing semchecked type
nodes. This causes a crash in transf when an untyped expression in the
type node has `nil` type. To deal with this, don't try to transform the
type node in these expressions at all. I couldn't reproduce the problem
with type conversion nodes though so those are unchanged in transf.

(cherry picked from commit 6d59680217)
2025-01-24 05:10:36 +01:00
ringabout
21c0564573 fixes #24630; static openArray backed by seq cannot be passed to another function (#24638)
fixes #24630

(cherry picked from commit 2f402fcb82)
2025-01-24 05:10:28 +01:00
metagn
12347eae74 generate destructor in nodestroy proc for explicit destructor call (#24627)
fixes #24626

`createTypeboundOps` in sempass2 is called when generating destructors
for types including for explicit destructor calls, however it blocks
destructors from getting generated in a `nodestroy` proc. This causes
issues when a destructor is explicitly called in a `nodestroy` proc. To
fix this, allow destructors to get generated only for explicit
destructor calls in nodestroy procs.

(cherry picked from commit 793baf34ff)
2025-01-20 18:46:41 +01:00
Antonis Geralis
52cadfc3d7 Optimize storing into uninit locations for arrays and seqs. (#24619)
(cherry picked from commit 6481482e0e)
2025-01-20 12:48:37 +01:00
ringabout
528e2b2271 fixes compile crashes with one parameter (#24618)
`{.compile("foo.c").}` makes Nim compiler crash

(cherry picked from commit 70d057fcc6)
2025-01-20 12:48:17 +01:00
metagn
0c0df28619 ignore match errors to expected types of tuple constructor elements (#24611)
fixes #24609

A tuple may have an incompatible expected type if there is a converter
match to it. So the compiler should not error when trying to match the
individual elements in the constructor to the elements of the expected
tuple type, this will be checked when the tuple is entirely constructed
anyway.

(cherry picked from commit 8d0e853e0a)
2025-01-20 12:48:10 +01:00
ringabout
a2a1c2b7f1 ci: update to ubuntu 22.04 (#24608)
(cherry picked from commit 41c447b5f4)
2025-01-15 15:31:59 +01:00
Bilog WEB3
41c4ed8dca Update changelog_1_2_0.md (#24607)
(cherry picked from commit 26ed469996)
2025-01-15 15:31:45 +01:00
Loïc Bartoletti
f6167cb0c8 math: Add cumprod and cumproded (#23416)
This pull request adds the `cumproded` function along with its in-place
equivalent, `cumprod`, to the math library. These functions provide
functionality similar to `cumsum` and `cumsummed`, allowing users to
calculate the cumulative sum of elements.

The `cumprod` function computes the cumulative product of elements
in-place, while `cumproded` additionally returns the prod seq.

(cherry picked from commit 4aff12408c)
2025-01-15 15:31:25 +01:00
planetBoy
72ce16990b docs fix spelling issues (#24597)
Hey !
I fixed several spelling issues.Glad I could help .
Br, Guayaba221.

(cherry picked from commit 8ed0a63973)
2025-01-15 15:31:20 +01:00
ringabout
ea3a4203fa fixes #24599; misleading error message with large array bounds (#24601)
fixes #24599

(cherry picked from commit aeeccee50a)
2025-01-15 15:31:13 +01:00
Jacek Sieka
24b24c17b1 fix c_memchr, c_strstr definitions (#24587)
One correct definition is enough

(cherry picked from commit e8bf6af0da)
2025-01-15 15:31:04 +01:00
Jacek Sieka
e80884665d varints: no need for emit (#24585)
(cherry picked from commit 78835562b1)
2025-01-15 15:30:58 +01:00
ringabout
f4009f0957 Update copyright year 2025 (#24593)
(cherry picked from commit 3dda60a8ce)
2025-01-15 10:22:25 +01:00
Skylar Ray
728a99d5cd chore: docs fix spelling issues (#24581)
**handle - handles**
**sensitiviy - sensitivity**

(cherry picked from commit dcc4e07e54)
2025-01-15 10:22:18 +01:00
futreall
019a3180f8 chore: correct typos docs (#24580)
(cherry picked from commit 0df351bf50)
2025-01-15 10:22:07 +01:00
Antonis Geralis
fb13e3608b Consider iterator types (#24577)
According to the macros doc nnkIteratorTy trees use the same structure
as nnkProcTy

(cherry picked from commit d3b6dba616)
2025-01-15 10:21:53 +01:00
Antonis Geralis
f5804a36b9 Support tuple parameter types (#24576)
(cherry picked from commit e1be29942e)
2025-01-15 10:21:37 +01:00
chloefeal
a83c535ed4 docs: fix typos (#24573)
Signed-off-by: chloefeal <188809157+chloefeal@users.noreply.github.com>
(cherry picked from commit cd220fe3e1)
2025-01-15 10:21:20 +01:00
Jake Leahy
3c71429eca Doc search improvements (#24567)
- `/` is now a hotkey to jump to the search
- Search results now are in line with the page (previously on small
screens it would be off centre)
- Jumping to a search result inside the page or via TOC will now hide
the search results (previously the results got in the way)

Example site here: https://tranquil-scone-c159b6.netlify.app/main.html

(cherry picked from commit 86d6f71f5a)
2025-01-15 10:21:11 +01:00
Jake Leahy
9e1b199e78 Minor std/strscans improvements (#24566)
#### Removes UnInit warnings when using `scanTuple`

e.g. this would emit a warning
```nim
import std/strscans

proc main() =
  let (ok, number) = "123".scanTuple()
```

![image](https://github.com/user-attachments/assets/68170ac6-402d-48b0-b8b6-69e71f4b70ae)

#### Error for wrong type now points to the passed in variable

```nim
import std/strscans

var str: string
discard "123".scanf("$i", str)
```

it gave this warning before

![image](https://github.com/user-attachments/assets/096e56d2-0eb5-4c67-9725-25caa97afebd)
now it returns

![image](https://github.com/user-attachments/assets/736a4292-2f56-4cf3-a27a-677045377171)

(cherry picked from commit 5b9ff963c5)
2025-01-15 10:21:00 +01:00
ringabout
b2f2b34fe5 adds a test case (#24565)
closes #19531

(cherry picked from commit 65b26401bc)
2025-01-15 10:20:50 +01:00
Esteban C Borsani
7be1bb572e Improve async stacktraces (#24563)
This makes await point to the caller line instead of asyncmacro. It also
reworks the "Async traceback:" section of the traceback. Follow up PR
#21091 (issue #19931) so it works if there is asynchronous work done.

(cherry picked from commit 2f127bf99f)
2025-01-15 10:20:29 +01:00
ringabout
40476fa24f fixes #23114; Nim v2 regression emit / asm var param dereference inconsistency (#24547)
fixes #23114

As in https://github.com/nim-lang/Nim/pull/22074, expressions in
bracketed emit are strictly typechecked, this PR applies the same check
for symbols in asm statements in order to keep them consistent.

(cherry picked from commit 3c4246dd24)
2025-01-15 10:20:18 +01:00
Tomohiro
3054cbe422 Add inline assembler tests for i386, arm, arm64, riscv32 and riscv64 (#24564)
This fixes one error in https://github.com/nim-lang/Nim/issues/24544 .
I tested this on Raspberry Pi Pico (arm) and Raspberry Pi 3(arm64).
It is not tested on i386, riscv32 and riscv64 CPU.

(cherry picked from commit fc806710cb)
2025-01-15 10:20:08 +01:00
ringabout
b31aed01f1 adds a test case (#24561)
closes #18616

(cherry picked from commit e2a306355c)
2025-01-15 10:19:57 +01:00
metagn
9c7f04dacb fix jsonutils with generic sandwiches, don't use strformat (#24560)
fixes #24559

The strformat macros have the problem that they don't capture symbols,
so don't use them in the generic `fromJson` proc here. Also `fromJson`
refers to `jsonTo` before it is declared which doesn't capture it, so
it's now forward declared.

(cherry picked from commit 5c71fbab30)
2025-01-15 10:19:51 +01:00
Jake Leahy
c5ee216c42 Make 'field is not accessible' and 'field initialized twice' errors point to the field inside the obj construction (#24557)
Fixes two line infos to make the error's clearer inside editors

- 'field is not accessible' would point to the whole object construction
instead of just the field inside the construction
- 'field initialized twice' would point to the colon instead of the
field

(cherry picked from commit 6bc52737b3)
2025-01-15 10:19:40 +01:00
Esteban C Borsani
ede6540c55 fixes #23212; Asyncdispatch leaks under --mm:arc (#24556)
Fixes #23212

Inspired by [this chronos
PR](https://github.com/status-im/nim-chronos/pull/243)

(cherry picked from commit f29234b40f)
2025-01-15 10:19:26 +01:00
ringabout
0c14372a8c remove zippy data from tarballs (#24551)
fixes https://github.com/nim-lang/nightlies/issues/95

(cherry picked from commit 63c884038d)
2025-01-15 10:19:04 +01:00
metagn
6deb3a90ae check if unused import warning is enabled before adding import to stack (#24554)
fixes #24552

Could also implement `{.used.}` for imports but this wouldn't be
backwards compatible. The same problem as #24552 also exists for
`{.hint[XDeclaredButNotUsed].}` but this isn't as much of a problem
since `{.used.}`/`{.push used.}` exist.

(cherry picked from commit 986ca7dcd4)
2025-01-15 10:18:58 +01:00
Daniel Stuart
e0e1061562 Use long int builtins for risc-v 32-bit targets (#24553)
Solves compilation using riscv32-unknown-elf-gcc, compiler defines
int32_t as long int.

(cherry picked from commit 50ed43df42)
2025-01-15 10:18:00 +01:00
ringabout
d96c5b2396 fixes strictdefs warnings (#24550)
(cherry picked from commit ce4304ce97)
2025-01-15 10:17:51 +01:00
Jake Leahy
09835a1d9e Make expandMacro show private fields (#24522)
Was debugging with `--expandMacro` and noticed that private fields
weren't exported.
Passes extra flags to the renderer to make them be shown

(cherry picked from commit f80ce139d5)
2025-01-15 10:17:43 +01:00
ringabout
0823b9d177 fixes #17681; enforce codegen for exportc consts (#24546)
fixes #17681

(cherry picked from commit d5c7abe3d2)
2025-01-15 10:17:37 +01:00
Juan M Gómez
b5068f427a Adds skipParentCfg back. Bump nimble to a commit where it doesnt rely in the parent config (#24545)
(cherry picked from commit 8ce58fab26)
2025-01-15 10:17:27 +01:00
ringabout
1cee3c7f18 fixes #24536; fixes nightlies regression caused by nimble update (#24542)
follow up #24537

Because `nimble` is a bundled repo so it is bundled in the tarballs

i.e.
82421fd705/.github/workflows/nightlies.yml (L264)
has bundled `dist/nimble`, but it only copies the data without `.git`.
So in this PR, we ignore bundled nimble repo.

(cherry picked from commit 70b3232d3a)
2025-01-15 10:17:17 +01:00
ringabout
844ba2168b fixes #20908; Unknown warnings and hints now give a warning (#24543)
fixes #20908

This PR unifies the treatment of unknown warnings and hints, which now
gives an `warnUnknownNotes` instead of an error.

(cherry picked from commit 81d8c0fc17)
2025-01-15 10:17:07 +01:00
ringabout
d5437b7a4a fixes #24538 (#24541)
fixes #24538

(cherry picked from commit 91d1933ea2)
2025-01-15 10:16:20 +01:00
metagn
faa9ae08b0 proper error for const defines with unsupported types (#24540)
fixes #24539

(cherry picked from commit b9c593404c)
2025-01-15 10:16:12 +01:00
Juan M Gómez
7b596b4e1f #Fixes #24536 building nimble 0.16.4 fails when running build_all.sh (#24537)
(cherry picked from commit 556f217b4c)
2025-01-14 13:24:21 +01:00
ringabout
cd06f0769f more strictdef fixes for stdlibs (#24535)
(cherry picked from commit d31cce557b)
2025-01-14 13:23:44 +01:00
Juan M Gómez
0cce145dac Bumps nimble v0.16.4 (#24437)
(cherry picked from commit be4d19e562)
2025-01-14 13:23:38 +01:00
Ryan McConnell
43f7e160ba couple cases of valid concept bindings (#24513)
see tests

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit e0197a8380)
2025-01-14 13:23:26 +01:00
ringabout
5a71c36d25 fixes strictdefs warnings continue (#24520)
(cherry picked from commit d2d810585c)
2025-01-14 13:23:18 +01:00
ringabout
1299dd4651 adds a test case (#24534)
closes #16845

(cherry picked from commit 80af252025)
2025-01-14 13:23:12 +01:00
bptato
51a0f3de6e Fix exitnow signature, mark as .noreturn (#24533)
Like quit, this function never returns.

Also, "code" was marked as "int", even though POSIX _exit takes a C int.

(cherry picked from commit f485973459)
2025-01-14 13:23:06 +01:00
ringabout
e2b6021630 fixes #22101; std/pegs with nim cpp --mm:orc --exceptions:goto creates invalid C++ (#24531)
fixes #22101

The old implementation generates

`auto T = value;` for the cpp backend which causes problems for goto
exceptions. This PR puts the declaration of `T` to the cpsLocals parts
and makes it compatible with goto exceptions.

(cherry picked from commit f7a461a30c)
2025-01-14 13:22:32 +01:00
ringabout
428b64251f adds a test case (#24532)
closes #18070

(cherry picked from commit f796c01e3c)
2025-01-14 13:20:04 +01:00
ringabout
5b0b90fb49 fixes #22153; UB calling allocCStringArray([""]) with --mm:refc (#24529)
fixes #22153

It's a problem for refc because you cannot index a nil string: i.e.
`[""]` is `{((NimStringDesc*) NIM_NIL)}` which cannot be indexed

(cherry picked from commit 9bb7e53e7f)
2025-01-14 13:19:56 +01:00
Jake Leahy
2f5481ce88 Make error appear in user code with invalid format string in strformat (#24528)
With this example
```nim
import std/strformat

echo fmt"{invalid, code}"
```

We get the error message
```
stack trace: (most recent call last)
/home/jake/.choosenim/toolchains/nim-hashdevel/lib/pure/strformat.nim(750, 16) fmt
/home/jake/.choosenim/toolchains/nim-hashdevel/lib/pure/strformat.nim(714, 16) strformatImpl
/home/jake/Documents/projects/Nim/temp.nim(3, 9) template/generic instantiation of `fmt` from here
/home/jake/.choosenim/toolchains/nim-hashdevel/lib/pure/strformat.nim(714, 16) Error: could not parse `invalid, code` in `{invalid, code}`.
(1, 8) Error: invalid indentation
```
After PR it now shortens it to just appear in user code
```
/home/jake/Documents/projects/Nim/lib/pure/strformat.nim(750, 16) fmt
/home/jake/Documents/projects/Nim/lib/pure/strformat.nim(714, 16) strformatImpl
/home/jake/Documents/projects/Nim/temp.nim(3, 9) Error: could not parse `invalid, code` in `{invalid, code}`.
(1, 8) Error: invalid indentation
```

(cherry picked from commit da9f7f671b)
2025-01-14 13:19:50 +01:00
Jake Leahy
9aeb5c254c Fix line info for import (#24523)
Refs #24158

Fixes the line info of the module symbol (cases like `import as` and
grouped imports had wrong line info). Since that symbol's line info is
now used for the warnings, there isn't a separate line info stored for
`unusedImports`

Examples of fixed cases
```nim
import strutils as test #[
                ^ before
                   ^ after ]#

# This case was fixed by #24158, but only for unused imports
import std/[strutils, strutils] #[
        ^ before
                      ^ after ]#

from strutils import split #[
^ before
     ^ after ]#
```

(cherry picked from commit 69e0cdb6c0)
2025-01-14 13:17:34 +01:00
metagn
4e1bc4216a fix nil node in sym ast of exported ref objects [backport:2.2] (#24527)
fixes #24526, follows up #23101

The `shallowCopy` calls do not keep the original node's children, they
just make a new seq with the same length, so the `Ident "*"` node from
the original postfix nodes was not carried over, making it `nil` and
causing the segfault.

(cherry picked from commit b529f69518)
2025-01-14 13:17:24 +01:00
metagn
316141162b test case haul to prevent pileup (#24525)
closes #6013, closes #7009, closes #9190, closes #12487, closes #12831,
closes #13184, closes #13252, closes #14860, closes #14877, closes
#14894, closes #14917, closes #16153, closes #16439, closes #17779,
closes #18074, closes #18202, closes #18314, closes #18648, closes
#19063, closes #19446, closes #20065, closes #20367, closes #22126,
closes #22820, closes #22888, closes #23020, closes #23287, closes
#23510

(cherry picked from commit aeb3fe9505)
2025-01-14 13:17:11 +01:00
ringabout
8d8a90e079 fixes nightlies regression (#24519)
follows up https://github.com/nim-lang/Nim/pull/24507

(cherry picked from commit d408b94063)
2025-01-14 13:17:04 +01:00
ringabout
105e134c3f adds a test case (#24518)
closes #19698

(cherry picked from commit 801733f286)
2025-01-14 13:16:38 +01:00
metagn
85c8b5b304 track call depth separately from loop count in VM (#24512)
refs #24503

Infinite recursions currently are not tracked separately from infinite
loops, because they also increase the loop counter. However the max
infinite loop count is very high by default (10 million) and does not
reliably catch infinite recursions before consuming a lot of memory. So
to protect against infinite recursions, we separately track call depth,
and add a separate option for the maximum call depth, much lower than
the maximum iteration count by default (2000, the same as
`nimCallDepthLimit`).

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 6f4106bf5d)
2025-01-14 13:16:21 +01:00
ringabout
2d470c9afd fixes strictdefs warnings for stdlibs [part two] (#24514)
After some cleanups for stdlibs, then we should enable warningaserror
for all tests

(cherry picked from commit c0861142f8)
2025-01-14 13:15:55 +01:00
ringabout
94a6b85538 fixes #24504; fixes ensureMove for refs (#24505)
fixes #24504

(cherry picked from commit d0288d3b57)
2025-01-14 13:15:46 +01:00
ringabout
90c5dfc32c adds a test case (#24515)
closes #17733

(cherry picked from commit 02fb0476ce)
2025-01-14 13:15:39 +01:00
ringabout
a7b671dad5 don't track result initialization if it is marked noinit (#24499)
We don't track `noinit` for variables introduced in
https://github.com/nim-lang/Nim/pull/10566. It should be applied to
`result` if the function is marked `noinit`

(cherry picked from commit 2e9e7f13ee)
2025-01-14 13:15:25 +01:00
Tomohiro
fb11c4404e fixes #24506; calculate timeout correctly (#24507)
`curTimeout` is calculated incorrectly. So this PR fixes it.
This PR also replaces `now()` with `getMonoTime()`.

(cherry picked from commit bbf6a62c90)
2025-01-14 13:13:35 +01:00
ringabout
1adcab885b remove unnecessary await (#24501)
There is already a when condition, so `await` is not needed to split the
function

(cherry picked from commit 6bbf9c3117)
2025-01-14 13:13:10 +01:00
ringabout
5ddbf2372e fixes some strictdefs warnings (#24502)
(cherry picked from commit 8f4bfda5f4)
2025-01-14 13:12:39 +01:00
ringabout
8f668c2373 adds a test case (#24500)
closes #24040

(cherry picked from commit c3120b6121)
2025-01-14 13:12:29 +01:00
metagn
3daf7dd2ac remove inserted derefs for ref object fields when transforming to dot call (#24498)
fixes #24492

Kind of a goofy way of doing this, but we count how many derefs were
used for the first parameter before calling `builtinFieldAccess`, then
count after, and if there are more now than before, we remove the added
derefs. I thought maybe getting rid of #18298 would simplify it but
maybe this would still be the best way.

For better encapsulation we could make `dotTransformation` take an
`nOrig` param instead but this would be less efficient since it would
need a copy, though `semAsgn` already makes one.

(cherry picked from commit 2529f33760)
2025-01-14 13:12:22 +01:00
ringabout
4b4b97018b prefix NimDestroyGlobals with nimMainPrefix (#24493)
ref https://github.com/nim-lang/Nim/issues/24471

---------

Co-authored-by: metagn <metagngn@gmail.com>
(cherry picked from commit 3bee04d9f3)
2025-01-14 13:11:55 +01:00
metagn
aa5fc4af58 install older version of nimcuda for arraymancer (#24496)
Attempt to fix CI failure, refs
https://github.com/nim-lang/Nim/pull/24495#issuecomment-2511299112,
alternative is to use a commit version like
bc65375ff5

(cherry picked from commit 33dc2367e7)
2025-01-14 13:11:44 +01:00
ringabout
062e77bce0 adds a test case (#24486)
closes #23680

(cherry picked from commit ddf5a9f6c5)
2025-01-14 13:11:16 +01:00
metagn
d04f9c426e fix crash with undeclared proc type pragma macro in generics (#24490)
fixes #24489

(cherry picked from commit 05bba15623)
2025-01-14 12:24:22 +01:00
ringabout
52809cd3dd fixes #24476; remove proc type cast if they are same types for backends (#24480)
fixes #24476

closes https://github.com/nim-lang/Nim/pull/24479

(cherry picked from commit 5340005869)
2025-01-14 12:24:00 +01:00
Andreas Rumpf
05a8b65eea stdlib: minor refactorings and updates (#24482)
(cherry picked from commit 8881017c80)
2025-01-14 12:16:21 +01:00
ringabout
b1a555dd52 Add support for parsing parameterised sql types (#24483)
Co-authored-by: Cletus Igwe <me@cletusigwe.com>
(cherry picked from commit dcd0793f2b)
2025-01-14 12:16:07 +01:00
Ryan McConnell
f5453e453e Fixes 3 small issues with concepts (#24481)
issue 1 - statics in the type:
This probably only handles simple cases. It's probably too accepting
only comparing the base, but that should only affect candidate selection
I think.
issue 2 - `tyArray` of length 3:
This is just a work around since I couldn't get the fix right in
previous PR
issue 3 - shadowing:
The part in `concepts.nim` that iterates candidates does not consider
imported idents if at least once module level ident matches. It does not
have to match in any other way then name.

EDIT: 2 more
issue 4 - composite typeclasses:
when declared in both the concept and the `proc` can cause problems
issue 5 - recursion:
simple recursion and scenarios where more than one concepts recurse
together (only tested two)

(cherry picked from commit e479151473)
2025-01-14 12:15:59 +01:00
ringabout
7d425e712e fixes #24472; let symbol created by template is reused in nimvm branch (#24473)
fixes #24472

Excluding variables which are initialized in the nimvm branch so that
they won't interfere the other branch

(cherry picked from commit e7f48cdd5c)
2025-01-14 12:15:51 +01:00
ringabout
e6f5e49184 minor fix for the command line helper (#24475)
(cherry picked from commit 1a901bd94e)
2025-01-14 12:15:21 +01:00
Judd
cd370e4725 Fix highlite.nim (#24457)
When parsing `a = 1` with `langPython`, Eof is reported unexpectedly.

Fix: allow other languages to fallback to "Identifier" when it is not a
keyword.

This patch is useful as this is a highlighter. `Eof` as annoying.

(cherry picked from commit 6112c51e78)
2025-01-14 12:15:09 +01:00
ringabout
42184227aa fix #19600; No error checking on fclose (#24468)
fix #19600

(cherry picked from commit 555191a3f0)
2025-01-14 12:11:57 +01:00
metagn
14ce1a91ce fix crash with tyBuiltInTypeClass matching itself (#24462)
fixes #24449

The standalone `seq` type is a `tyBuiltInTypeClass` with a single child
of kind `tySequence`, which itself has no children. This is also the
case for most other `tyBuiltInTypeClass` kinds. However this can cause a
crash in sigmatch when calling `isEmptyContainer` on this child type,
which expects the sequence type to have children. This check was added
in #5557 to prevent empty collections like `@[]` from matching their
respective typeclass, but it's not useful when matching against another
typeclass (which is done here to resolve an ambiguity). So to avoid the
crash, this empty container check is disabled when matching against
another typeclass.

(cherry picked from commit 96043bdbb7)
2025-01-14 09:11:14 +01:00
ringabout
ff7b83f266 adds a test case (#24469)
closes #13945

(cherry picked from commit af3181e75b)
2025-01-14 09:11:07 +01:00
metagn
522b184d5a retry thttpclient_ssl twice (#24467)
Flaky on linux_amd64

(cherry picked from commit 652edb229a)
2025-01-14 09:11:01 +01:00
Ryan McConnell
d339c58628 fixes #24451; concept matching generic body (#24458)
I think this might not be a comprehensive solution to dealing with
`tyGenericBody` but we take a step forward
#24451

(cherry picked from commit 08c2a1741d)
2025-01-14 09:10:45 +01:00
metagn
01b6c5d0d1 fix unix stdlib install location after #21328 (#24460)
closes #22369, closes #23197, closes #24385, refs #21328

According to #21328 the standard library on Unix should be installed in
`/usr/lib/nim/lib`, however the installer was not updated for this
change, hence the problem as described in
https://github.com/nim-lang/Nim/issues/23197#issuecomment-2031386896.

Have not tested if this fixes the problem but the comment heavily
implies it does. The problem is also in 2.0 so it could be backported
but I can't say for sure that it works and doesn't break anything.

(cherry picked from commit 33e455c986)
2025-01-14 09:10:40 +01:00
ringabout
1bc501f8ce adds a test case (#24466)
closes https://github.com/nim-lang/Nim/issues/23770 ref
https://github.com/nim-lang/Nim/pull/24442

(cherry picked from commit 9fcc3b0599)
2025-01-14 09:08:50 +01:00
ringabout
aa8d62f89c remove unnecessary imports (#24465)
ref https://github.com/nim-lang/Nim/issues/24272

(cherry picked from commit a788bae318)
2025-01-14 09:08:40 +01:00
ringabout
60a8eaaaa5 adds a test case (#24464)
closes #7784

(cherry picked from commit 3eddb64909)
2025-01-14 09:08:32 +01:00
metagn
f3da96d880 include new concepts in typeclasses, makes containsGenericType work (#24453)
fixes #24450

The new concepts were previously not included in
[containsGenericType][1] which prevents them from being instantiated.
Here they are included by being added to `tyTypeClasses` though this
doesn't have to be done, they can also be added manually to
`containsGenericTypeIter`, but this might be too specific.

[1]:
a2031ec6cf/compiler/types.nim (L1507-L1517)

(cherry picked from commit e28d2f42e9)
2025-01-14 09:08:13 +01:00
metagn
87c306061b disable weird type inference for object constructors (#24455)
closes #24372, refs #20091

This was added in #20091 for some reason but doesn't actually work and
only makes error messages more obscure. So for now, it's disabled.

Can also be backported to 2.0 if necessary.

(cherry picked from commit a610f23060)
2025-01-14 09:08:06 +01:00
metagn
2b1885a0fa remove structural equality check for objects and distinct types (#24448)
follows up #24425, fixes #18861, fixes #22445

Since #24425 generic object and distinct types now accurately link back
to their generic instantiations. To work around this issue previously,
type matching checked if generic objects/distinct types were
*structurally* equal, which caused false positives with types that
didn't use generic parameters in their structures. This structural check
is now removed, in cases where generic objects/distinct types require a
nontrivial equality check, the generic parameters of the `typeInst`
fields are checked for equality instead.

The check is copied from `tyGenericInst`, but the check in
`tyGenericInst` is not always sufficient as this type can be skipped or
unreachable in the case of `ref object`s.

(cherry picked from commit a2031ec6cf)
2025-01-14 09:07:30 +01:00
metagn
9c87f2cb4b always reinstantiate nominal values of generic instantiations (#24425)
fixes #22479, fixes #24374, depends on #24429 and #24430

When instantiating generic types which directly have nominal types
(object, distinct, ref/ptr object but not enums[^1]) as their values,
the nominal type is now copied (in the case of ref objects, its child as
well) so that it receives a fresh ID and `typeInst` field. Previously
this only happened if it contained any generic types in its structure,
as is the case for all other types.

This solves #22479 and #24374 by virtue of the IDs being unique, which
is what destructors check for. Technically types containing generic
param fields work for the same reason. There is also the benefit that
the `typeInst` field is correct. However issues like #22445 aren't
solved because the compiler still uses structural object equality checks
for inheritance etc. which could be removed in a later PR.

Also fixes a pre-existing issue where destructors bound to object types
with generic fields would not error when attempting to define a user
destructor after the fact, but the error message doesn't show where the
implicit destructor was created now since it was only created for
another instance. To do this, a type flag is used that marks the generic
type symbol when a generic instance has a destructor created. Reusing
`tfCheckedForDestructor` for this doesn't work.

Maybe there is a nicer design that isn't an overreliance on the ID
mechanism, but the shortcomings of `tyGenericInst` are too ingrained in
the compiler to use for this. I thought about maybe adding something
like `tyNominalGenericInst`, but it's really much easier if the nominal
type itself directly contains the information of its generic parameters,
or at least its "symbol", which the design is heading towards.

[^1]: See [this
test](21420d8b09/lib/std/enumutils.nim (L102))
in enumutils. The field symbols `b0`/`b1` always have the uninstantiated
type `B` because enum fields don't expect to be generic, so no generic
instance of `B` matches its own symbols. Wouldn't expect anyone to use
generic enums but maybe someone does.

(cherry picked from commit 05c74d6844)
2025-01-14 09:07:03 +01:00
metagn
03b6999499 prevent codegen of inactive case fields in VM object constructor nodes (#24442)
fixes #17571

Objects in the VM are represented as object constructor nodes that
contain every single field, including ones in different case branches.
This is so that every field has a unique invariant index in the object
constructor that can be written to and read from. However when
converting this node back into semantic code, fields from inactive case
branches can remain in the constructor which causes bad codegen,
generating assignments to fields from other case branches.

To fix this, fields from inactive branches are now detected in
`semmacrosanity.annotateType` (called in `fixupTypeAfterEval`) and
marked to prevent the codegen of their assignments. In #24441 these
fields were excluded from the resulting node, but this causes issues
when the node is directly supposed to go back into the VM, for example
as `const` values. I don't know if this is the only case where this
happens, so I wasn't sure about how to keep that implementation working.

(cherry picked from commit 75b512bc6a)
2025-01-14 09:06:58 +01:00
metagn
2690ab01c0 fix wrong error for iterators with no body and pragma macro (#24440)
fixes #16413

`semIterator` checks if the original iterator passed to it has no body,
but it should check the processed node created by `semProcAux`.

(cherry picked from commit e239968b80)
2025-01-14 09:06:49 +01:00
ringabout
c79fb859f1 adds some test cases (#24436)
closes #24043
closes #24045

(cherry picked from commit cc696f18c0)
2025-01-14 09:05:48 +01:00
ringabout
2d658e8de5 fixes #24402; Memory leak under Arc/Orc on inline iterators with nested seq (#24419)
fixes #24402

```nim
iterator myPairsInline*[T](twoDarray: seq[seq[T]]): (int, seq[T]) {.inline.} =
  for indexValuePair in twoDarray.pairs:
    yield indexValuePair

proc innerTestTotalMem() =
  var my2dArray: seq[seq[int32]] = @[]

  # fill with some data...
  for i in 0'i32..100:
    var z = @[i, i+1]
    my2dArray.add z

  for oneDindex, innerArray in myPairsInline(my2dArray):
    discard

innerTestTotalMem()
```

In `for oneDindex, innerArray in myPairsInline(my2dArray)`, `oneDindex`
and `innerArray` becomes `cursors` because they satisfy the criterion of
`isSimpleIteratorVar`. On the one hand, it is not correct to have them
point to the temporary generated by tuple unpacking, which left the
memory of the temporary uncleaned up. On the other hand, we don't need
to generate a temporary for a symbol node when unpacking the tuple.

(cherry picked from commit 21420d8b09)
2025-01-14 09:05:36 +01:00
metagn
0036bb976b fix subtype match of generic object types (#24430)
split from #24425

Matching `tyGenericBody` performs a match on the last child of the
generic body, in this case the uninstantied `tyObject` type. If the
object contains no generic fields, this ends up being the same type as
all instantiated ones, but if it does, a new type is created. This fails
the `sameObjectTypes` check that subtype matching for object types uses.
To fix this, also consider that the pattern type could be the generic
uninstantiated object type of the matched type in subtype matching.

(cherry picked from commit 511ab72342)
2025-01-14 09:05:28 +01:00
metagn
b0f3d1e874 fix jsonutils macro with generic case object (#24429)
split from #24425

The added test did not work previously. The result of `getTypeImpl` is
the uninstantiated AST of the original type symbol, and the macro
attempts to use this type for the result. To fix the issue, the provided
`typedesc` argument is used instead.

(cherry picked from commit 45e21ce8f1)
2025-01-14 09:05:24 +01:00
metagn
9f03b98de5 stricter skip for conversions in array indices in transf (#24424)
fixes #17958

In `transf`, conversions in subscript expressions are skipped (with
`skipConv`'s rules). This is because array indexing can produce
conversions to the range type that is the array's index type, which
causes a `RangeDefect` rather than an `IndexDefect` (and also
`--rangeChecks` and `--indexChecks` are both considered). However this
causes problems when explicit conversions are used, between types of
different bitsizes, because those also get skipped.

To fix this, we only skip the conversion if:

* it's a hidden (implicit) conversion
* it's a range check conversion (produces `nkChckRange`)
* the subscript is on an array type and the result type of the
conversion has the same bounds as the array index type

And `skipConv` rules also still apply (int/float classification).

Another idea would be to prevent the implicit conversion to the array
index type from being generated. But there is no good way to do this:
matching to the base type instead prevents types like `uint32` from
implicitly converting (i.e. it can convert to `range[0..3]` but not
`int`), and analyzing whether this is an array bound check is easier in
`transf`, since `sigmatch` just produces a type conversion.

The rules for skipping the conversion could also receive some other
tweaks: We could add a rule that changing bitsizes also doesn't skip the
conversion, but this breaks the `uint32` case. We could simplify it to
only removing implicit skips to specifically fix #17958, but this is
wrong in general.

We could also add something like `nkChckIndex` that generates index
errors instead but this is weird when it doesn't have access to the
collection type and it might be overkill.

(cherry picked from commit 76c5f16ac5)
2025-01-14 09:05:18 +01:00
Sam
0b7e22635e Fixes #24369 (#24370)
Hope this fixes #24369, happy for any feedback on the PR.

(cherry picked from commit 1fddb61b3b)
2025-01-14 09:05:07 +01:00
metagn
3642f4d375 gensym anonymous proc symbols (#24422)
fixes #14067, fixes #15004, fixes #19019

Anonymous procs are [added to
scope](8091d76306/compiler/semstmts.nim (L2466))
with the name `:anonymous`. This means that if they have the same
signature in a scope, they can consider each other as redefinitions. To
prevent this, mark their symbols as `sfGenSym` so they do not get added
to scope or cause any name conflicts. The commented out `and not isAnon`
check wouldn't work because `isAnon` would not be true if the proc is
being resemmed, in which case the name field in the proc AST would have
the symbol of the anonymous proc rather than being empty.

There is a separate problem of default values in generic/normal procs
not opening new scopes which is partially responsible for #19019.

(cherry picked from commit 3e47725c08)
2025-01-14 09:05:01 +01:00
metagn
f292393816 skip tyAlias in generic alias checks [backport:2.0] (#24417)
fixes #24415

Since #23978 (which is in 2.0), all generic types that alias to another
type now insert a `tyAlias` layer in their value. However the
`skipGenericAlias` etc code which `sigmatch` uses is not updated for
this, so `tyAlias` is now skipped in these.

The relevant code in sigmatch is:
67ad1ae159/compiler/sigmatch.nim (L1668-L1673)

This behavior is also suspicious IMO, not skipping a structural
`tyGenericInst` alias can be useful for code like #10220, but this is
currently arbitrarily decided based on "depth" and whether the alias is
to another `tyGenericInst` type or not. Maybe in the future we could
enforce the use of a nominal type.

(cherry picked from commit 45b8434c7d)
2025-01-14 09:04:54 +01:00
metagn
6ec663f7bc fix standalone explicit generic procs with unresolved arguments (#24404)
fixes issue described in https://forum.nim-lang.org/t/12579

In #24065 explicit generic parameter matching was made to fail matches
on arguments with unresolved types in generic contexts (the sigmatch
diff, following #24010), similar to what is done for regular calls since
#22029. However unlike regular calls, a failed match in a generic
context for a standalone explicit generic instantiation did not convert
the expression into one with `tyFromExpr` type, which means it would
error immediately given any unresolved parameter. This is now done to
fix the issue.

For explicit generic instantiations on single non-overloaded symbols, a
successful match is still instantiated. For multiple overloads (i.e.
symchoice), if any of the overloads fail the match, the entire
expression is considered untyped and any instantiations are not used, so
as to not void overloads that would match later. This means even
symchoices without unresolved arguments aren't instantiated, which may
be too restrictive, but it could also be too lenient and we might need
to make symchoice instantiations always untyped. The behavior for
symchoice is not sound anyway given it causes #9997 so this is something
to consider for a redesign.

Diff follows #24276.

(cherry picked from commit 67ad1ae159)
2025-01-14 09:04:44 +01:00
ringabout
6d02ac1ba0 fixes strictdefs with when nimvm (#24409)
ref https://github.com/nim-lang/Nim/pull/24225
related https://github.com/nim-lang/Nim/pull/24306

> Code in branches must not affect semantics of the code that follows
the
`when nimvm` statement. E.g. it must not define symbols that are used in
  the following code.

The test shouldn't have passed when
https://github.com/nim-lang/Nim/pull/24306
would be implemented somehow. Some third packages have already misused
`when nimvm` by defining symbols in the other branch of `when nimvm`.

e.g. in https://github.com/status-im/nim-unittest2/pull/34

```nim
when nimvm:
  discard
else:
  let suiteName {.inject.} = nameParam

use(suiteName)
```

(cherry picked from commit c71de10608)
2025-01-14 09:04:35 +01:00
metagn
ce1fa86095 disable sfml test on osx (#24615)
Tried installing sfml 2 in #24614 but didn't work

(cherry picked from commit d83ff81695)
2025-01-14 08:40:02 +01:00
metagn
4900550e9c disable all badssl tests indefinitely (#24403)
Flaky not just due to recent ubuntu 24/GCC 14 upgrades, windows fails as
well, assuming the issue is with badssl or it's just not worth testing
here.

(cherry picked from commit 5f056f87b2)
2025-01-14 07:53:56 +01:00
Phil Krylov
9fe2356e74 std/parsesql: Fix JOIN parsing (#22890)
This commit fixes/adds tests for and fixes several issues with `JOIN`
operator parsing:

- For OUTER joins, LEFT | RIGHT | FULL specifier is not optional
```nim
doAssertRaises(SqlParseError): discard parseSql("""
SELECT id FROM a
OUTER JOIN b
ON a.id = b.id
""")
```

- For NATURAL JOIN and CROSS JOIN, ON and USING clauses are forbidden
```nim
doAssertRaises(SqlParseError): discard parseSql("""
SELECT id FROM a
CROSS JOIN b
ON a.id = b.id
""")
```

- JOIN should parse as part of FROM, not after WHERE
```nim
doAssertRaises(SqlParseError): discard parseSql("""
SELECT id FROM a
WHERE a.id IS NOT NULL
INNER JOIN b
ON a.id = b.id
""")
```

- LEFT JOIN should parse
```nim
doAssert $parseSql("""
SELECT id FROM a
LEFT JOIN b
ON a.id = b.id
""") == "select id from a left join b on a.id = b.id;"
```

- NATURAL JOIN should parse
```nim
doAssert $parseSql("""
SELECT id FROM a
NATURAL JOIN b
""") == "select id from a natural join b;"
```

- USING should parse
```nim
doAssert $parseSql("""
SELECT id FROM a
JOIN b
USING (id)
""") == "select id from a join b using (id );"
```

- Multiple JOINs should parse
```nim
doAssert $parseSql("""
SELECT id FROM a
JOIN b
ON a.id = b.id
LEFT JOIN c
USING (id)
""") == "select id from a join b on a.id = b.id left join c using (id );"
```

(cherry picked from commit 46bb47a444)
2025-01-14 07:53:44 +01:00
ringabout
37ab27bd99 improve httpclient docuementation (#24398)
ref https://github.com/nim-lang/Nim/issues/24394

(cherry picked from commit 08b82c90f5)
2025-01-14 07:53:36 +01:00
ringabout
5e22d8bc3c fixes #24395; remove ndi (#24396)
fixes  #24395

(cherry picked from commit 8b88b5fdd8)
2025-01-14 07:53:29 +01:00
ringabout
6b102d5c13 azure-pipelines update to ubuntu 24.04 gcc 14 (#24386)
(cherry picked from commit 7b47987341)
2025-01-14 07:53:23 +01:00
ringabout
51f8649e36 trigger package CI for version-2-2 (#24393)
(cherry picked from commit d55cd40642)
2025-01-14 07:53:11 +01:00
ringabout
df27b427af fixes #24378; supportsCopyMem can fail from macro context with tuples (#24383)
fixes #24378

```nim
type Win = typeof(`body`)
doAssert not supportsCopyMem((int, Win))
```

`semAfterMacroCall` doesn't skip the children aliases types in the tuple
typedesc construction while the normal program seem to skip the aliases
types somewhere

`(int, Win)` is kept as `(int, alias string)` instead of expected `(int,
string)`

(cherry picked from commit 5e56f0a356)
2025-01-14 07:52:42 +01:00
ringabout
e57f755b78 fixes #24371; incorrect importc wrapper incompatible with gcc 14 on Windows (#24388)
fixes #24371

(cherry picked from commit 74df699ff1)
2025-01-14 07:52:35 +01:00
ringabout
d78c7aa697 disable Test on aarch64 (#24389)
ref https://github.com/nim-lang/Nim/issues/24287

(cherry picked from commit 1576563775)
2025-01-14 07:52:28 +01:00
metagn
435a152c66 implement generic default values for object fields (#24384)
fixes #21941, fixes #23594

(cherry picked from commit 4091576ab7)
2025-01-14 07:52:18 +01:00
ringabout
6c2de9b294 fixes #24379; better error messages for ill-formed type symbols from macros (#24380)
fixes #24379

(cherry picked from commit d61897459d)
2025-01-14 07:52:09 +01:00
ringabout
babc7d8c16 fixes #23545; C compiler error when default initializing an object field function (#24375)
fixes #23545

(cherry picked from commit 815bbf0e73)
2025-01-14 07:52:02 +01:00
ringabout
022bd12e82 improve passes.nim (#24376)
(cherry picked from commit 3fc87259bd)
2025-01-14 07:51:55 +01:00
ringabout
3c528c987c fixes #24359; VM problem: dest register is not set with const-bound proc (#24364)
fixes #24359

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

It should not try to evaluate the const proc if the proc doesn't have a
return value.

(cherry picked from commit 031ad957ba)
2025-01-14 07:51:44 +01:00
metagn
52d94c1c86 include static types in type bound ops (#24366)
refs https://github.com/nim-lang/Nim/pull/24315#discussion_r1816332587

(cherry picked from commit 40fc2d0e76)
2025-01-14 07:51:38 +01:00
metagn
87de7f9193 don't cascade vmgen errors in nim check without error outputs (#24365)
refs #23625, refs #24289

Encountered in #24360 but could not reproduce minimally: overloading on
static parameters can work with the normal compile commands but crash
`nim check`. Static overloading relies on `tryConstExpr` which recovers
from things like `globalError` and fails softly, in this case this can
happen when a variable etc. is not available to evaluate in the VM. But
with `nim check`, the compiler does not throw an exception in this case,
and instead tries to keep generating the entire expression in the VM,
which can cause crashes.

To fix this, when the compiler has no error outputs even on `nim check`,
we raise a global error so that the VM code generation stops early. This
fixes both `tryConstExpr` and speeds up `nim check`, because no error
outputs means we don't need cascading errors.

(cherry picked from commit efd603eb28)
2025-01-14 07:51:32 +01:00
Jake Leahy
520b16b81e Fix links for succ/pred/inc/dec in system docs (#24363)
Links for succ/pred/inc/dec were incorrect since they link to a symbol
with `int` as their second type.
Uses local referencing instead so that it links to the correct symbol.

Doesn't change the other links since they worked and doing the same
local referencing for `high`/`low` would've make them link to the group
of procs instead of the specific ones for ordinals

(cherry picked from commit 79ce3fe6b7)
2025-01-14 07:51:26 +01:00
ringabout
98403a06e7 fixes #18081; fixes #18079; fixes #18080; nested ref/deref'd types (#24335)
fixes #18081;
fixes https://github.com/nim-lang/Nim/issues/18080
fixes #18079

reverts https://github.com/nim-lang/Nim/pull/20738

It is probably more reasonable to use the type node from `nkObjConstr`
since it is barely changed unlike the external type, which is
susceptible to code transformation e.g. `addr(deref objconstr)`.

(cherry picked from commit aa90d00caf)
2025-01-14 07:50:41 +01:00
ringabout
4bdeddcac5 deprecate NewFinalize with the ref T finalizer (#24354)
pre-existing issues:

```nim
block:
  type
    FooObj = object
      data: int
    Foo = ref ref FooObj

  proc delete(self: Foo) =
    echo self.data

  var s: Foo
  new(s, delete)
```
it crashed with arc/orc in 1.6.x and 2.x.x

```nim
block:
  type
    Foo = ref int

  proc delete(self: Foo) =
    echo self[]

  var s: Foo
  new(s, delete)
```

The simple fix is to add a type restriction for the type `T` for arc/orc
versions
```nim
  proc new*[T: object](a: var ref T, finalizer: proc (x: T) {.nimcall.})
```

(cherry picked from commit 2af602a5c8)
2025-01-14 07:50:33 +01:00
metagn
9be3559ed2 consider calls as complex openarray assignment to iterator params (#24333)
fixes #13417, fixes #19703

When passing an expression to an `openarray` iterator parameter: If the
expression is a statement list (considered "complex"), it's assigned in
a non-deep-copying way to a temporary variable first, then this variable
is used as a parameter. If it's not a statement list, i.e. a call or a
symbol, the parameter is substituted directly with the given expression.
In the case of calls, this results in the call potentially being
executed more than once, or can cause redefined variables in the
codegen.

To fix this, calls are also considered as "complex" assignments to
openarrays, as long as the return type of the call is not `openarray` as
the generated assignment in that case has issues/is unimplemented
(caused a segfault [here in
datamancer](47ba4d81bf/src/datamancer/dataframe.nim (L1580))).

As for why creating a temporary isn't the default only with exceptions
for things like `nkSym`, the "non-deep-copying" way of assignment
apparently still causes arrays to be copied according to a comment in
the code. I'm not sure to what extent this is true: if it still happens
on ARC/ORC, if it happens for every array length, or if we can fix it by
passing arrays by reference. Otherwise, a more general way to assign to
openarrays might be needed, but I'm not sure if the compiler can easily
do this.

(cherry picked from commit d303c289fa)
2025-01-14 07:50:24 +01:00
ringabout
f2a9765014 fixes #23952; Size/Signedness issues with unordered enums (#24356)
fixes #23952

It reorders `type Foo = enum A, B = -1` to `type Foo = enum B = -1, A`
so that `firstOrd` etc. continue to work.

(cherry picked from commit 294b1566e7)
2025-01-14 07:50:17 +01:00
metagn
ac8c44e08d implement type bound operation RFC (#24315)
closes https://github.com/nim-lang/RFCs/issues/380, fixes #4773, fixes
#14729, fixes #16755, fixes #18150, fixes #22984, refs #11167 (only some
comments fixed), refs #12620 (needs tiny workaround)

The compiler gains a concept of root "nominal" types (i.e. objects,
enums, distincts, direct `Foo = ref object`s, generic versions of all of
these). Exported top-level routines in the same module as the nominal
types that their parameter types derive from (i.e. with
`var`/`sink`/`typedesc`/generic constraints) are considered attached to
the respective type, as the RFC states. This happens for every argument
regardless of placement.

When a call is overloaded and overload matching starts, for all
arguments in the call that already have a type, we add any operation
with the same name in the scope of the root nominal type of each
argument (if it exists) to the overload match. This also happens as
arguments gradually get typed after every overload match. This restricts
the considered overloads to ones attached to the given arguments, as
well as preventing `untyped` arguments from being forcefully typed due
to unrelated overloads. There are some caveats:

* If no overloads with a name are in scope, type bound ops are not
triggered, i.e. if `foo` is not declared, `foo(x)` will not consider a
type bound op for `x`.
* If overloads in scope do not have enough parameters up to the argument
which needs its type bound op considered, then type bound ops are also
not added. For example, if only `foo()` is in scope, `foo(x)` will not
consider a type bound op for `x`.

In the cases of "generic interfaces" like `hash`, `$`, `items` etc. this
is not really a problem since any code using it will have at least one
typed overload imported. For arbitrary versions of these though, as in
the test case for #12620, a workaround is to declare a temporary
"template" overload that never matches:

```nim
# neither have to be exported, just needed for any use of `foo`:
type Placeholder = object
proc foo(_: Placeholder) = discard
```

I don't know what a "proper" version of this could be, maybe something
to do with the new concepts.

Possible directions:

A limitation with the proposal is that parameters like `a: ref Foo` are
not attached to any type, even if `Foo` is nominal. Fixing this for just
`ptr`/`ref` would be a special case, parameters like `seq[Foo]` would
still not be attached to `Foo`. We could also skip any *structural* type
but this could produce more than one nominal type, i.e. `(Foo, Bar)`
(not that this is hard to implement, it just might be unexpected).

Converters do not use type bound ops, they still need to be in scope to
implicitly convert. But maybe they could also participate in the nominal
type consideration: if `Generic[T] = distinct T` has a converter to `T`,
both `Generic` and `T` can be considered as nominal roots.

The other restriction in the proposal, being in the same scope as the
nominal type, could maybe be worked around by explicitly attaching to
the type, i.e.: `proc foo(x: T) {.attach: T.}`, similar to class
extensions in newer OOP languages. The given type `T` needs to be
obtainable from the type of the given argument `x` however, i.e.
something like `proc foo(x: ref T) {.attach: T.}` doesn't work to fix
the `ref` issue since the compiler never obtains `T` from a given `ref
T` argument. Edit: Since the module is queried now, this is likely not
possible.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 2864830941)
2025-01-14 07:50:04 +01:00
metagn
850132d37c define flexible array without size for tcc & all C99 (#24355)
fixes #24236

Locally tested to generate a 100 KB file for TCC. Empty flexible array
size is standard in C99 but maybe some compilers still don't support it.
At the very least an array size of 1000000 should be rare.

(cherry picked from commit dd3a4b2aba)
2025-01-14 07:49:52 +01:00
ringabout
a1ee2ee566 adds noise to important_packages (#24352)
ref https://github.com/jangko/nim-noise

(cherry picked from commit b534f34e95)
2025-01-14 07:49:45 +01:00
ringabout
9306b5e917 std/nre now uses destructors instead of finializer (#24353)
Similar to changes in
bafb4f119c

(cherry picked from commit 3aaaed1acf)
2025-01-14 07:49:23 +01:00
ringabout
67a636bec8 closes #19984; adds a test case (#24349)
closes #19984

(cherry picked from commit baf3695c76)
2025-01-14 07:48:09 +01:00
metagn
9a6230ee5a wrap fields iterations in if true scope [backport] (#24343)
fixes #24338

When unrolling each iteration of a `fields` iterator, the compiler only
opens a new scope for semchecking, but doesn't generate a node that
signals to the codegen that a new scope should be created. This causes
issues for reused template instantiations that reuse variable symbols
between each iteration, which causes the codegen to generate multiple
declarations for them in the same scope (regardless of `inject` or
`gensym`). To fix this, we wrap the unrolled iterations in an `if true:
body` node, which both opens a new scope and doesn't interfere with
`break`.

(cherry picked from commit ca5df9ab25)
2025-01-14 07:48:01 +01:00
bptato
7e840e0164 Fix broken poll and nfds_t bindings (#24331)
This fixes several cases of the Nim binding of nfds_t being inconsistent
with the target platform signedness and/or size.

Additionally, it fixes poll's third argument (timeout) being set to Nim
"int" when it should have been "cint".

The former is the same issue that #23045 had attempted to fix, but
failed because it only considered Linux. (Also, it was only applied to
version 2.0, so the two branches now have incompatible versions of the
same bug.)

Notes:

* SVR4's original "unsigned long" definition is cloned by Linux and
Haiku. Nim got this right for Haiku and Linux-amd64, but it was wrong on
non-amd64 Linux.
* Zephyr does not have nfds_t, but simply uses (signed) "int". This was
already correctly reflected by Nim.
* OpenBSD poll.h uses "unsigned int", and other BSD derivatives follow
suit. This being the most commonly copied definition, the fallback case
now returns cuint. (This also seems to be correct for the OS X headers I
could find on the web.)
* This changes Nintendo Switch nfds_t to cuint from culong. It is
purportedly a FreeBSD derivative, so I *think* this is correct, but I
can't tell because I don't have access to the Nintendo Switch headers.

I have also moved the platform-specific Tnfds to posix.nim so that we
can reuse the fallback logic on all platforms. (e.g. specifying the size
in posix_linux_amd64 only to then use when defined(linux) in posix_other
seems redundant.)

(cherry picked from commit 67442471ae)
2025-01-14 07:47:40 +01:00
metagn
cd760b00c2 clean up stdlib with --jsbigint64 (#24255)
refs #6978, refs #6752, refs #21613, refs #24234

The `jsNoInt64`, `whenHasBigInt64`, `whenJsNoBigInt64` templates are
replaced with bool constants to use with `when`. Weird that I didn't do
this in the first place.

The `whenJsNoBigInt64` template was also slightly misleading. The first
branch was compiled for both no bigint64 on JS as well as on C/C++. It
seems only `trandom` depended on this by mistake.

The workaround for #6752 added in #6978 to `times` is also removed with
`--jsbigint64:on`, but #24233 was also encountered with this, so this PR
depends on #24234.

(cherry picked from commit 041098e882)
2025-01-14 07:47:30 +01:00
Jake Leahy
0cce80071b Fix quoted idents in ctags (#24317)
Running `ctags` on files with quoted symbols (e.g. `$`) would list \`
instead of the full ident. Issue was the result getting reassigned at
the end to a \` instead of appending

(cherry picked from commit 93c24fe1c5)
2025-01-14 07:47:19 +01:00
metagn
5aeabdac8f symmetric difference operation for sets via xor (#24286)
closes https://github.com/nim-lang/RFCs/issues/554

Adds a symmetric difference operation to the language bitset type. This
maps to a simple `xor` operation on the backend and thus is likely
faster than the current alternatives, namely `(a - b) + (b - a)` or `a +
b - a * b`. The compiler VM implementation of bitsets already
implemented this via `symdiffSets` but it was never used.

The standalone binary operation is added to `setutils`, named
`symmetricDifference` in line with [hash
sets](https://nim-lang.org/docs/sets.html#symmetricDifference%2CHashSet%5BA%5D%2CHashSet%5BA%5D).
An operator version `-+-` and an in-place version like `toggle` as
described in the RFC are also added, implemented as trivial sugar.

(cherry picked from commit ae9287c4f3)
2025-01-14 07:47:13 +01:00
metagn
2d678fa45c better errors for standalone explicit generic instantiations (#24276)
refs #8064, refs #24010

Error messages for standalone explicit generic instantiations are
revamped. Failing standalone explicit generic instantiations now only
error after overloading has finished and resolved to the default `[]`
magic (this means `[]` can now be overloaded for procs but this isn't
necessarily intentional, in #24010 it was documented that it isn't
possible). The error messages for failed instantiations are also no
longer a simple `cannot instantiate: foo` message, instead they now give
the same type mismatch error message as overloads with mismatching
explicit generic parameters.

This is now possible due to the changes in #24010 that delegate all
explicit generic proc instantiations to overload resolution. Old code
that worked around this is now removed. `maybeInstantiateGeneric` could
maybe also be removed in favor of just `explicitGenericSym`, the `result
== n` case is due to `explicitGenericInstError` which is only for niche
cases.

Also, to cause "ambiguous identifier" error messages when the explicit
instantiation is a symchoice and the expression context doesn't allow
symchoices, we semcheck the sym/symchoice created by
`explicitGenericSym` with the given expression flags.

#8064 isn't entirely fixed because the error message is still misleading
for the original case which does `values[1]`, as a consequence of
#12664.

(cherry picked from commit 0a058a6b8f)
2025-01-14 07:47:08 +01:00
ringabout
ee1c4de48a build documentation for repr_v2 (#24325)
(cherry picked from commit 0806fb0b6f)
2025-01-14 07:47:01 +01:00
ringabout
b3e02ef0c3 make PNode.typ a private field (#24326)
(cherry picked from commit 68b2e9eb6a)
2025-01-14 07:46:40 +01:00
Yuriy Glukhov
893c638485 Fixes #3824, fixes #19154, and hopefully #24094. Re-applies #23787. (#24316)
The first commit reverts the revert of #23787.
The second fixes lambdalifting in convolutedly nested
closures/closureiters. This is considered to be the reason of #24094,
though I can't tell for sure, as I was not able to reproduce #24094 for
complicated but irrelevant reasons. Therefore I ask @jmgomez, @metagn or
anyone who could reproduce it to try it again with this PR.

I would suggest this PR to not be squashed if possible, as the history
is already messy enough.

Some theory behind the lambdalifting fix:
- A closureiter that captures anything outside its body will always have
`:up` in its env. This property is now used as a trigger to lift any
proc that captures such a closureiter.
- Instantiating a closureiter involves filling out its `:up`, which was
previously done incorrectly. The fixed algorithm is to use "current" env
if it is the owner of the iter declaration, or traverse through `:up`s
of env param until the common ancestor is found.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 5fa96ef270)
2025-01-14 07:46:30 +01:00
Tomohiro
9f51b52f5f Document about noinline calling convention and exportcpp pragma in Nim manual (#24323)
It seems exportcpp was implemented in v1.0 but there is no documentation
about it excepts changelog.
`noinline` is used in many procedures in Nim code but there is also no
documentation about it.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit b8f6088ac0)
2025-01-14 07:46:21 +01:00
metagn
bcfb30a8be shallow fold prevention for addr, nkHiddenAddr (#24322)
fixes #24305, refs #23807

Since #23014 `nkHiddenAddr` is produced to fast assign array elements in
iterators. However the array access inside this `nkHiddenAddr` can get
folded at compile time, generating invalid code. In #23807, compile time
folding of regular `addr` expressions was changed to be prevented in
`transf` but `nkHiddenAddr` was not updated alongside it.

The method for preventing folding in `addr` in #23807 was also faulty,
it should only trigger on the immediate child node of the address rather
than all nodes nested inside it. This caused a regression as outlined in
[this
comment](https://github.com/nim-lang/Nim/pull/24322#issuecomment-2419560182).

To fix both issues, `addr` and `nkHiddenAddr` now both shallowly prevent
constant folding for their immediate children.

(cherry picked from commit 52cf7dfde0)
2025-01-14 07:46:13 +01:00
ringabout
7948e2f2c2 fixes #24319; move doesn't work well with (deref (var array)) (#24321)
fixes #24319

`byRefLoc` (`mapType`) requires the Loc `a` to have the right type.
Without `lfEnforceDeref`, it produces the wrong type for `deref (var
array)`, which may come from `mitems`.

(cherry picked from commit 0347536ff2)
2025-01-14 07:46:07 +01:00
ringabout
6b31400ade adds a getter/setter for owner (#24318)
(cherry picked from commit d0b6b9346e)
2025-01-14 07:45:59 +01:00
ringabout
a713aee682 fixes #18896; fixes #20886; importc types alias doesn't work with distinct (#24313)
fixes #18896
fixes #20886

```nim
type
  PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer
    # import C's FILE* type; Nim will treat it as a new pointer type
```
This is an excerpt from the Nim manual. In the old Nim versions, it
produces a void pointer type instead of the `FILE*` type that should
have been generated. Because these C types tend to be opaque and adapt
to changes on different platforms. It might affect the portability of
Nim on various OS, i.e. `csource_v2` cannot build on the apline platform
because of `Time` relies on Nim types instead of the `time_t` type.

ref https://github.com/nim-lang/Nim/pull/18851

(cherry picked from commit 8be82c36c9)
2025-01-14 07:45:50 +01:00
ringabout
aa7e7f5f63 make owner a private field of PType (#24314)
follow up https://github.com/nim-lang/Nim/pull/24311

(cherry picked from commit a3aea224c9)
2025-01-14 07:45:39 +01:00
ringabout
8d7b3baf9f make owner a private field of PSym (#24311)
(cherry picked from commit 53460f312c)
2025-01-14 07:45:34 +01:00
ringabout
274cdba334 closes #19585; adds a test case for #21648 (#24310)
closes #19585
follow up #21648

(cherry picked from commit 922f7dfd71)
2025-01-14 07:45:25 +01:00
ringabout
a04dada93d fixes ci_generate produces unnecessary spaces on Windows (#24309)
follow up https://github.com/nim-lang/Nim/pull/17899

(cherry picked from commit 3e8f44b232)
2025-01-14 07:45:19 +01:00
ringabout
4d170ac586 fixes #24258; compiler crash on len of varargs[untyped] (#24307)
fixes #24258

It uses conditionals to guard against ill formed AST to produce better
error messages, rather than crashing

(cherry picked from commit 8b39b2df7d)
2025-01-14 07:39:32 +01:00
ringabout
e3a8d98626 define -d:nimHasDefaultFloatRoundtrip and enable datamancer (#24300)
ref https://github.com/SciNim/Datamancer/pull/73
ref https://github.com/SciNim/Datamancer/issues/72

(cherry picked from commit d4b9c147ab)
2025-01-14 07:37:18 +01:00
ringabout
41145210a8 templates/macros use no expected types when return types are specified (#24298)
fixes #24296
fixes #24295

Templates use `expectedType` for type inference. It's justified that
when templates don't have an actual return type, i.e., `untyped` etc.

When the return type of templates is specified, we should not infer the
type

```nim
template g(): string = ""

let c: cstring = g()
```
In this example, it is not reasonable to annotate the templates
expression with the `cstring` type before the `fitNode` check with its
specified return type.

(cherry picked from commit 80e6b35721)
2025-01-14 07:36:48 +01:00
Aryo
3c2b32aebe Expand enum example tut1.md (#24268)
I couldn't understand why there is "x" declaration. Comparison make it
easier to understand to people not familiar to enums.

(cherry picked from commit 1dbf614858)
2025-01-14 07:36:05 +01:00
metagn
613f1e94ae clean up testament retries, add some comments (#24294)
follows up #24279

`discard finishTest` was wrong if the test still had a `retries` option:
it would just ignore the result of the test. This is an unlikely mistake
but we safeguard against it by splitting `finishTest` into two, one that
completely ignores the retries option and `finishTestRetryable` which
has to be checked for a retry. This also makes the code look slightly
better.

(cherry picked from commit 2f7586c066)
2025-01-14 07:35:59 +01:00
metagn
660a9cecf0 add retries to testament, use it for GC tests (#24279)
Testament now retries a test by a specified amount if it fails in any
way other than an invalid spec. This is to deal with the flaky GC tests
on Windows CI that fail in many different ways, from the linker randomly
erroring, segfaults, etc.

Unfortunately I couldn't do this cleanly in testament's current code.
The proc `addResult`, which is the "final" proc called in a test run's
lifetime, is now wrapped in a proc `finishTest` that returns a bool
`true` if the test failed and has to be retried. This result is
propagated up from `cmpMsgs` and `compilerOutputTests` until it reaches
`testSpecHelper`, which handles these results by recursing if the test
has to be retried. Since calling `testSpecHelper` means "run this test
with one given configuration", this means every single matrix
option/target etc. receive an equal amount of retries each.

The result of `finishTest` is ignored in cases where it's known that it
won't be retried due to passing, being skipped, having an invalid spec
etc. It's also ignored in `testNimblePackages` because it's not
necessary for those specific tests yet and similar retry behavior is
already implemented for part of it.

This was a last resort for the flaky GC tests but they've been a problem
for years at this point, they give us more work to do and turn off
contributors. Ideally GC tests failing should mark as "needs review" in
the CI rather than "failed" but I don't know if Github supports
something like this.

(cherry picked from commit 720d0aee5c)
2025-01-14 07:35:50 +01:00
metagn
bffd2e0330 don't evaluate "cannot eval" errors with nim check (#24289)
fixes #24288, refs #23625

Since #23625 "cannot evaluate" errors during VM code generation are
"soft" errors with `nim check`, i.e. the code generation isn't halted
(except for the current proc which `return`s which can cause wrong
codegen) and the expression is still attempted to be evaluated. Now,
these errors signal to the VM that the current generated VM code cannot
be evaluated, and so instead of evaluating, an error node is returned.
This keeps the benefit of the "soft" errors without potentially crashing
the compiler on improperly generated VM code. Although maybe the
compiler might not be able to handle the generated error node in some
cases.

This fixes the chame example in #24288 but this is not tested in CI.
Presumably it or the compiler was doing something like `compiles()` on
code that can't run in the VM.

I would accept nicer ways of tracking non-evaluability than
`c.cannotEval = true` but I tried to keep it as harmless as possible.

(cherry picked from commit def1fea43a)
2025-01-14 07:35:43 +01:00
Andreas Rumpf
d357a2e9a5 modulegraphs: added a flag useful for gear2 (#24293)
(cherry picked from commit 25c068c070)
2025-01-14 07:35:36 +01:00
metagn
fca3504105 fix type of reconstructed kind field node in field checking analysis [backport] (#24290)
fixes #24021

The field checking for case object branches at some point generates a
negated set `contains` check for the object discriminator. For enum
types, this tries to generate a complement set and convert to a
`contains` check in that instead. It obtains this type from the type of
the element node in the `contains` check.

`buildProperFieldCheck` creates the element node by changing a field
access expression like `foo.z` into `foo.kind`. In order to do this, it
copies the node `foo.z` and sets the field name in the node to the
symbol `kind`. But when copying the node, the type of the original
`foo.z` is retained. This means that the complement is performed on the
type of the accessed field rather than the type of the discriminator,
which causes problems when the accessed field is also an enum.

To fix this, we properly set the type of the copied node to the type of
the kind field. An alternative is just to make a new node instead.

A lot of text for a single line change, I know, but this part of the
codebase could use more explanation.

(cherry picked from commit 1bebc236bd)
2025-01-14 07:35:24 +01:00
metagn
bf45efb1ea use /link before each library linker option on MSVC (#24291)
fixes #24087, refs https://forum.nim-lang.org/t/341, refs #14222, refs
#14221

The Nim compiler calls `cl` for linking as well as compilation. This
means that options to the linker have to be passed after a `/link`
argument. But the Nim compiler doesn't include this option normally,
because users may still want to pass non-linker options to `cl` at link
time.

To deal with this, a workaround is used: every single library link
option adds `/link` before it. The linker simply ignores extraneous
`/link` arguments and gives a warning instead, since it's an
unrecognized option to the linker. This is really hacky but otherwise we
need to separate linker arguments into arguments passed either to the
compiler or to the linker at link time, and this behavior wouldn't be
meaningful outside of MSVC.

I can't really test this manually but I did test that the linker ignores
`/link`. I also can't really do more than this, I don't really use MSVC
so I wouldn't know how to navigate it, or how people use it. Ideally
someone who knows more about/uses MSVC can give their input or take
over.

(cherry picked from commit 449106a5a4)
2025-01-14 07:35:19 +01:00
metagn
517a2fc275 add tables.getOrDefault param name change to changelog (#24271)
refs
https://github.com/nim-lang/Nim/issues/23587#issuecomment-2404406187

(cherry picked from commit bb0006598d)
2025-01-14 07:35:11 +01:00
Miran
4c56f9d675 make package testing faster (#24284)
There's no need to run benchmarks for cow- and sso-strings: they take 15
minutes each to run.

(cherry picked from commit f5cb39289b)
2025-01-14 07:34:56 +01:00
Juan M Gómez
de93f82d6e Bumps nimble to v0.16.2 (#24283)
(cherry picked from commit af23bc2941)
2025-01-14 07:34:39 +01:00
metagn
fa1819eb2d make linter use lineinfo to check originating package (#24270)
fixes #24269, refs #20095

Instead of checking the package of the *used sym* to determine whether a
stylecheck should trigger, we check the package of the lineinfo instead.
Before #20095 this checked for the current compilation context module
instead which caused issues with generic procs, but the lineinfo should
more closely match the AST.

I figured this might cause issues with includes etc but the foreign
package test specifically tests for an include and passes, so maybe the
package determining logic accounts for this already. This still might
not be the correct logic, I'm not too familiar with the package handling
in the compiler.

Package PRs, both merged:

- json_rpc: https://github.com/status-im/nim-json-rpc/pull/226
- json_serialization:
https://github.com/status-im/nim-json-serialization/pull/99

(cherry picked from commit aaf6c408c6)
2025-01-14 07:34:32 +01:00
metagn
0fde5a0cc2 use case instead of set of int in osproc (#24277)
As said in the warning after #21659, a set of ints defaults to
`set[range[0..65535]]` which is very large. So in osproc, a `case`
statement is used instead of an int set to check for an int being one of
2 values.

Also tested all of CI with the warning from #21659 as an error, this
seems to be the only remaining case in CI.

(cherry picked from commit 706985997e)
2025-01-14 07:34:23 +01:00
metagn
090139eb6f fix deref/addr pair deleting assignment location in C++ (#24280)
fixes #24274

The code in the `if` branch replaces the current destination `d` with a
new one. But the location `d` can be an assignment location, in which
case the provided expression isn't generated. To fix this, don't trigger
this code for when the location already exists. An alternative would be
to call `putIntoDest` in this case as is done below.

(cherry picked from commit 9c85f4fd07)
2025-01-14 07:34:03 +01:00
Miran
ee4bf757ea test more Status' packages, refs #24266 (#24275)
This adds several new Status packages to the CIs:

- confutils
- eth
- metrics
- nat_traversal
- toml_serialization

Other packages mentioned in https://github.com/nim-lang/Nim/issues/24266
are currently not ready to test with `devel` for various reasons.

----

This also enables `criterion`, and removes other packages that had been
in the `allowFailure` category — even without them we have plenty of
packages (145) that we test, there's no point in spending CI time on
them just to see them fail every time.
If/when the authors of those packages make them work with Nim devel, we
can re-introduce them then.

(cherry picked from commit 274762638f)
2025-01-14 07:33:52 +01:00
dlesnoff
b0b4b498c8 std/math: Add ^ overload for float32 and float64 (#20898)
I have added a new overload of `^` for float exponents.
Is two overloads for `float32` and `float64` better than just one
overload with `SomeFloat` type ?
I guess this would not work with `SomeFloat`, as `pow` is not defined
for `float`.

Another remark. Maybe we should catch exponents with 0.5 and call `sqrt`
instead ?

---------

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
Co-authored-by: metagn <metagngn@gmail.com>
(cherry picked from commit e9a4d096ab)
2025-01-14 07:33:42 +01:00
metagn
d102571d78 don't allow instantiations resolving to generic body types (#24273)
fixes #24091, refs #24092

Any instantiations resolving to a generic body type now gives an error.
Due to #24092, this does not error in cases like matching against `type
M` in generics because generic body type symbols are just not
instantiated. But this prevents parameters with type `type M` from being
used, although there doesn't seem to be any code which does this. Just
in case such code exists, we still allow `typedesc` types resolving to
generic body types.

(cherry picked from commit 2f904535d0)
2025-01-14 07:33:27 +01:00
metagn
1f418de2cc fix workaround for protobuf not installing combparser fork in CI (#24267)
fixes CI after #24265, the CI passed in the original PR somehow

(cherry picked from commit 96d6eee9bc)
2025-01-14 07:33:20 +01:00
metagn
21bdc8ff0f remove conflicting default call in tables.getOrDefault (#24265)
fixes #23587

As explained in the issue, `getOrDefault` has a parameter named
`default` that can be a proc after generic instantiation. But the
parameter having a proc type [overrides all other
overloads](f73e03b132/compiler/semexprs.nim (L1203))
including the magic `system.default` overload and causes a compile error
if the proc doesn't match the normal use of `default`. To fix this, the
`result = default(B)` initializer call is removed because it's not
needed, `result` is always set in `getOrDefaultImpl` when a default
value is provided.

This is still a suspicious behavior of the compiler but `tables` working
has a higher priority.

(cherry picked from commit 67ea754b7f)
2025-01-14 07:33:10 +01:00
ringabout
9f7b664836 documentation and comments use HTTPS when possible (#24264)
(cherry picked from commit 95a7695810)
2025-01-14 07:33:01 +01:00
ringabout
b24f58183d fixes obsolete documentations about the JS backend (#24263)
ref https://github.com/nim-lang/Nim/pull/21849
ref https://github.com/nim-lang/Nim/pull/21613

(cherry picked from commit f73e03b132)
2025-01-14 07:32:55 +01:00
metagn
b8efee444c process non-language pragma nodes in generics (#24254)
fixes #18649, refs #24183

Same as in #24183 for templates, we now process pragma nodes in generics
so that macro symbols are captured and the pragma arguments are checked,
but ignoring language pragma keywords.

A difference is that we cannot process call nodes as is, we have to
process their children individually so that the early untyped
macro/template instantiation in generics does not kick in.

(cherry picked from commit d72b848d17)
2025-01-14 07:32:47 +01:00
Tomohiro
336549c49d Change how to multiply 1.5 to ints to reduce overflow (#24257)
(cherry picked from commit d6633ae1da)
2025-01-14 07:32:40 +01:00
ringabout
2d4e1f981e improves the 2.2.0 changelog (#24256)
(cherry picked from commit 30e552e3d3)
2025-01-14 07:32:27 +01:00
metagn
13110fc5d3 give int literals matched type on generic match (#24234)
fixes #24233

Integer literals with type `int` can match `int64` with a generic match.
Normally this would generate an conversion via `isFromIntLit`, but when
it matches with a generic match (`isGeneric`) the node is left alone and
continues to have type `int` (related to #4858, but separate; since
`isFromIntLit > isGeneric` it doesn't propagate). This did not cause
problems on the C backend up to this point because either the compiler
generated a cast when generating the C code or it was implicitly casted
in the C code itself. On the JS backend however, we need to generate
`int64` and `int` values differently, so we copy the integer literal and
give it the matched type now instead.

This is somewhat risky even if CI passes but it's required to make the
times module work without [this
workaround](7dfadb8b4e/lib/pure/times.nim (L219-L238))
on `--jsbigint64:on` (the default).

CI exposed an issue: When matching an int literal to a generic parameter
in a generic instantiation, the literal is only treated like a value if
it has `int literal` type, but if it has the type `int`, it gets
transformed into literally the type `int` (#12664, #13906), which breaks
the tests t14193 and t12938. To deal with this, we don't give it the
type `int` if we are in a generic instantiation and preserve the `int
literal` type.

(cherry picked from commit c73eedfe6e)
2025-01-14 07:32:18 +01:00
metagn
700ca2eb60 process non-language pragma nodes in templates (#24183)
fixes #24186

When encountering pragma nodes in templates, if it's a language pragma,
we don't process the name, and only any values if they exist. If it's
not a language pragma, we process the full node. Previously only the
values of colon expressions were processed.

To make this simpler, `whichPragma` is patched to consider bracketed
hint/warning etc pragmas like `{.hint[HintName]: off.}` as being a
pragma of kind `wHint` rather than an invalid pragma which would have to
be checked separately. From looking at the uses of `whichPragma` this
doesn't seem like it would cause problems.

Generics have [the same
problem](a27542195c/compiler/semgnrc.nim (L619))
(causing #18649), but to make it work we need to make sure the
templates/macros don't get evaluated or get evaluated correctly (i.e.
passing the proc node as the final argument), either with #23094 or by
completely disabling template/macro evaluation when processing the
pragma node, which would also cover `{.pragma.}` templates.

(cherry picked from commit 911cef1621)
2025-01-14 07:32:12 +01:00
metagn
5945ad41a1 reset inTypeofContext in generic instantiations (#24229)
fixes #24228, refs #22022

As described in
https://github.com/nim-lang/Nim/issues/24228#issuecomment-2392462221,
instantiating generic routines inside `typeof` causes all code inside to
be treated as being in a typeof context, and thus preventing compile
time proc folding, causing issues when code is generated for the
instantiated routine. Now, instantiated generic procs are treated as
never being inside a `typeof` context.

This is probably an arbitrary special case and more issues with the
`typeof` behavior from #22022 are likely. Ideally this behavior would be
removed but it's necessary to accomodate the current [proc `declval` in
the package `stew`](https://github.com/status-im/nim-stew/pull/190), at
least without changes to `compileTime` that would either break other
code (making it not eagerly fold by default) or still require a change
in stew (adding an option to disable the eager folding).

Alternatively we could also make the eager folding opt-in only for
generic compileTime procs so that #22022 breaks nothing whatsoever, but
a universal solution would be better. Edit: Done in #24230 via
experimental switch

(cherry picked from commit ea9811a4d2)
2025-01-14 07:31:57 +01:00
Andreas Rumpf
7f113dc875 exports more helpers that are needed by nif-gear2 (#24247)
(cherry picked from commit 7f2e6a1359)
2025-01-14 07:31:51 +01:00
ringabout
e13f86a596 enable nimExperimentalLinenoiseExtra (#24227)
follow up https://github.com/nim-lang/Nim/pull/16977

it was added in 1.6.0

(cherry picked from commit a65501325c)
2025-01-14 07:31:40 +01:00
metagn
6c96892d5e refactor to make sigmatch use LayeredIdTable for bindings (#24216)
split from #24198

This is a required refactor for the only good solution I've been able to
think of for #4858 etc. Explanation:

---

`sigmatch` currently [disables
bindings](d6a71a1067/compiler/sigmatch.nim (L1956))
(except for binding to other generic parameters) when matching against
constraints of generic parameters. This is so when the constraint is a
general metatype like `seq`, the type matching will not treat all
following uses of `seq` as the type matched against that generic
parameter.

However to solve #4858 etc we need to bind `or` types with a conversion
match to the type they are supposed to be converted to (i.e. matching
`int literal(123)` against `int8 | int16` should bind `int8`[^1], not
`int`). The generic parameter constraint binding needs some way to keep
track of this so that matching `int literal(123)` against `T: int8 |
int16` also binds `T` to `int8`[^1].

The only good way to do this IMO is to generate a new "binding context"
when matching against constraints, then binding the generic param to
what the constraint was bound to in that context (in #24198 this is
restricted to just `or` types & concrete types with convertible matches,
it doesn't work in general).

---

`semtypinst` already does something similar for bindings of generic
invocations using `LayeredIdTable`, so `LayeredIdTable` is now split
into its own module and used in `sigmatch` for type bindings as well,
rather than a single-layer `TypeMapping`. Other modules which act on
`sigmatch`'s binding map are also updated to use this type instead.

The type is also made into an `object` type rather than a `ref object`
to reduce the pointer indirection when embedding it inside
`TCandidate`/`TReplTypeVars`, but only on arc/orc since there are some
weird aliasing bugs on refc/markAndSweep that cause a segfault when
setting a layer to its previous layer. If we want we can also just
remove the conditional compilation altogether and always use `ref
object` at the cost of some performance.

[^1]: `int8` binding here and not `int16` might seem weird, since they
match equally well. But we need to resolve the ambiguity here, in #24012
I tested disallowing ambiguities like this and it broke many packages
that tries to match int literals to things like `int16 | uint16` or
`int8 | int16`. Instead of making these packages stop working I think
it's better we resolve the ambiguity with a rule like "the earliest `or`
branch with the best match, matches". This is the rule used in #24198.

(cherry picked from commit cad8726907)
2025-01-14 07:31:33 +01:00
ringabout
dd0cc389bb -d:nimPreviewFloatRoundtrip becomes the default (#24217)
(cherry picked from commit aa605da92a)
2025-01-14 07:31:27 +01:00
metagn
75e50f804a delay markUsed for converters until call is resolved (#24243)
fixes #24241

(cherry picked from commit 09043f409f)
2025-01-14 07:31:22 +01:00
metagn
599f1ad6b3 make new concepts match themselves (#24244)
fixes #22839

(cherry picked from commit 9e30b39412)
2025-01-14 07:31:14 +01:00
metagn
d991600a00 update CI to macos 13 (#24157)
Followup to #24154, packages aren't ready for macos 14 (M1/ARM CPU) yet
and it seems to be preview on azure, so upgrade to macos 13 for now.

Macos 12 gives a warning:

```
You are using macOS 12.
We (and Apple) do not provide support for this old version.
It is expected behaviour that some formulae will fail to build in this old version.
It is expected behaviour that Homebrew will be buggy and slow.
Do not create any issues about this on Homebrew's GitHub repositories.
Do not create any issues even if you think this message is unrelated.
Any opened issues will be immediately closed without response.
Do not ask for help from Homebrew or its maintainers on social media.
You may ask for help in Homebrew's discussions but are unlikely to receive a response.
Try to figure out the problem yourself and submit a fix as a pull request.
We will review it but may or may not accept it.
```

(cherry picked from commit 4a63186cda)
2025-01-14 07:30:58 +01:00
tersec
b873eaedf5 update minimum recommended gcc version and fix manual typos (#24240)
ref https://github.com/nim-lang/Nim/issues/24235

(cherry picked from commit 782b75cc08)
2025-01-14 07:30:43 +01:00
Alex
39a6106e8b Update sequtils.nim authors (#24238)
Hello, I am the original developer credited in this file.

I no longer wish to be credited for the it so I've updated it to say
"Nim Contributors".

This is a quick edit from the GitHub Web UI so let me know if I need to
make any changes to get this merged.

Thank you.

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
(cherry picked from commit f420a5a273)
2025-01-14 07:30:33 +01:00
metagn
e262d9506d stricter set type match, implicit conversion for literals (#24176)
fixes #18396, fixes #20142

Set types with base types matching less than a generic match (so
subrange matches, conversion matches, int conversion matches) are now
considered mismatching, as their representation is different on the
backends (except VM and JS), causing codegen issues. An exception is
granted for set literal types, which now implicitly convert each element
to the matched base type, so things like `s == {'a', 'b'}` are still
possible where `s` is `set[range['a'..'z']]`. Also every conversion
match in this case is unified under the normal "conversion" match, so a
literal doesn't match one set type better than the other, unless it's
equal.

However `{'a', 'b'} == s` or `{'a', 'b'} - s` etc is now not possible.
when it used to work in the VM. So this is somewhat breaking, and needs
a changelog entry.

(cherry picked from commit 7dfadb8b4e)
2025-01-14 07:30:25 +01:00
metagn
ddc7f35e05 don't typecheck untyped + allow void typed template param default values (#24219)
Previously, the compiler never differentiated between `untyped`/`typed`
argument default values and other types, it considered any parameter
with a type as typed and called `semExprWithType`, which both
typechecked it and disallowed `void` expressions. Now, we perform no
typechecking at all on `untyped` template param default values, and call
`semExpr` instead for `typed` params, which allows expressions with
`void` type.

(cherry picked from commit 4eed341ba5)
2025-01-14 07:30:19 +01:00
metagn
f70a17f885 don't construct array type for already typed nkBracket node (#24224)
fixes #23010, split from #24195

When resemming bracket nodes, the compiler currently unconditionally
makes a new node with an array type based on the node. However the VM
can generate bracket nodes with `seq` types, which this erases. To fix
this, if a bracket node already has a type, we still resem the bracket
node, but don't construct a new type for it, instead using the type of
the original node.

A version of this was rejected that didn't resem the node at all if it
was typed, but I can't find it. The difference with this one is that the
individual elements are still resemmed.

This should fix the break caused by #24184 so we could redo it after
this PR but it might still have issues, not to mention the related
pre-existing issues like #22793, #12559 etc.

(cherry picked from commit d98ef312f0)
2025-01-14 07:30:06 +01:00
Miran
7a79f465fa bump NimVersion to 2.2.1 (#24215)
(cherry picked from commit d6a71a1067)
2025-01-14 07:28:14 +01:00
ringabout
b6450a98ea improve error messages for illegalCapture (#24214)
ref https://forum.nim-lang.org/t/12536

Use a general recommendation to avoid some weird error messages like
`<ref ref var Test>` etc.

(cherry picked from commit f7cb0322c2)
2025-01-14 07:28:10 +01:00
515 changed files with 8120 additions and 3197 deletions

View File

@@ -41,11 +41,11 @@ jobs:
target: [linux, windows, osx]
include:
- target: linux
os: ubuntu-20.04
os: ubuntu-22.04
- target: windows
os: windows-2019
- target: osx
os: macos-12
os: macos-13
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}

View File

@@ -1,76 +0,0 @@
name: GCC 14
on:
pull_request:
push:
branches:
- 'devel'
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04]
cpu: [amd64]
name: '${{ matrix.os }}'
runs-on: ${{ matrix.os }}
timeout-minutes: 60 # refs bug #18178
steps:
- name: 'Checkout'
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: 'Install node.js 20.x'
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
run: |
sudo apt update -qq
sudo apt remove needrestart
DEBIAN_FRONTEND='noninteractive' \
sudo apt install --no-install-recommends -yq \
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
valgrind libc6-dbg libblas-dev xorg-dev
- name: 'Install dependencies (Linux amd64 gcc 14)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
run: |
sudo add-apt-repository universe
sudo apt update -qq
sudo apt install -y gcc-14 g++-14 libpcre3 liblapack-dev
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 60 --slave /usr/bin/g++ g++ /usr/bin/g++-14
- name: 'Install dependencies (macOS)'
if: runner.os == 'macOS'
run: brew install boehmgc make sfml gtk+3
- name: 'Install dependencies (Windows)'
if: runner.os == 'Windows'
shell: bash
run: |
set -e
. ci/funs.sh
nimInternalInstallDepsWindows
echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
- name: 'Add build binaries to PATH'
shell: bash
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
- name: 'NIM_TESTAMENT_DISABLE_SSL'
shell: bash
run: echo "NIM_TESTAMENT_DISABLE_SSL=1" >> $GITHUB_ENV
- name: 'System information'
shell: bash
run: . ci/funs.sh && nimCiSystemInfo
- name: 'Build csourcesAny'
shell: bash
run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}'
- name: 'koch, Run CI'
shell: bash
run: . ci/funs.sh && nimInternalBuildKochAndRunCI

View File

@@ -4,6 +4,7 @@ on:
push:
branches:
- 'devel'
- 'version-2-2'
- 'version-2-0'
- 'version-1-6'
- 'version-1-2'
@@ -17,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-12]
os: [ubuntu-22.04, macos-13]
cpu: [amd64]
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'
@@ -48,6 +49,7 @@ jobs:
- 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

@@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
os: [ubuntu-22.04]
cpu: [amd64]
name: '${{ matrix.os }}'
runs-on: ${{ matrix.os }}
@@ -21,10 +21,10 @@ jobs:
with:
fetch-depth: 2
- name: 'Install node.js 20.x'
- name: 'Install node.js'
uses: actions/setup-node@v4
with:
node-version: '20.x'
node-version: ''
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
@@ -34,17 +34,6 @@ jobs:
sudo apt-fast install --no-install-recommends -yq \
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
valgrind libc6-dbg libblas-dev xorg-dev
- name: 'Install dependencies (macOS)'
if: runner.os == 'macOS'
run: brew install boehmgc make sfml gtk+3
- name: 'Install dependencies (Windows)'
if: runner.os == 'Windows'
shell: bash
run: |
set -e
. ci/funs.sh
nimInternalInstallDepsWindows
echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
- name: 'Add build binaries to PATH'
shell: bash

View File

@@ -20,7 +20,7 @@ jobs:
strategy:
matrix:
Linux_amd64:
vmImage: 'ubuntu-20.04'
vmImage: 'ubuntu-24.04'
CPU: amd64
# regularly breaks, refs bug #17325
# Linux_i386:
@@ -29,10 +29,10 @@ jobs:
# vmImage: 'ubuntu-18.04'
# CPU: i386
OSX_amd64:
vmImage: 'macOS-12'
vmImage: 'macOS-13'
CPU: amd64
OSX_amd64_cpp:
vmImage: 'macOS-12'
vmImage: 'macOS-13'
CPU: amd64
NIM_COMPILE_TO_CPP: true
Windows_amd64_batch0_3:
@@ -80,10 +80,12 @@ jobs:
- 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'))
@@ -100,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
@@ -130,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

@@ -24,6 +24,6 @@ if not exist %nim_csources% (
cd ..
copy /y bin\nim.exe %nim_csources%
)
bin\nim.exe c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch
koch boot -d:release --skipUserCfg --skipParentCfg --hints:off
koch tools --skipUserCfg --skipParentCfg --hints:off
bin\nim.exe c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch
koch boot -d:release --skipUserCfg --skipParentCfg --hints:off
koch tools --skipUserCfg --skipParentCfg --hints:off

View File

@@ -3,12 +3,68 @@
## Changes affecting backward compatibility
- `-d:nimPreviewFloatRoundtrip` becomes the default. `system.addFloat` and `system.$` now can produce string representations of
floating point numbers that are minimal in size and possess round-trip and correct
rounding guarantees (via the
[Dragonbox](https://raw.githubusercontent.com/jk-jeon/dragonbox/master/other_files/Dragonbox.pdf) algorithm). Use `-d:nimLegacySprintf` to emulate old behaviors.
- The `default` parameter of `tables.getOrDefault` has been renamed to `def` to
avoid conflicts with `system.default`, so named argument usage for this
parameter like `getOrDefault(..., default = ...)` will have to be changed.
- With `-d:nimPreviewCheckedClose`, the `close` function in the `std/syncio` module now raises an IO exception in case of an error.
- Unknown warnings and hints now gives warnings `warnUnknownNotes` instead of
errors.
- With `-d:nimPreviewAsmSemSymbol`, backticked symbols are type checked in the `asm/emit` statements.
## Standard library additions and changes
[//]: # "Additions:"
- `setutils.symmetricDifference` along with its operator version
`` setutils.`-+-` `` and in-place version `setutils.toggle` have been added
to more efficiently calculate the symmetric difference of bitsets.
[//]: # "Changes:"
- `std/math` The `^` symbol now supports floating-point as exponent in addition to the Natural type.
## Language changes
- An experimental option `--experimental:typeBoundOps` has been added that
implements the RFC https://github.com/nim-lang/RFCs/issues/380.
This makes the behavior of interfaces like `hash`, `$`, `==` etc. more
reliable for nominal types across indirect/restricted imports.
```nim
# objs.nim
import std/hashes
type
Obj* = object
x*, y*: int
z*: string # to be ignored for equality
proc `==`*(a, b: Obj): bool =
a.x == b.x and a.y == b.y
proc hash*(a: Obj): Hash =
$!(hash(a.x) &! hash(a.y))
```
```nim
# main.nim
{.experimental: "typeBoundOps".}
from objs import Obj # objs.hash, objs.`==` not imported
import std/tables
var t: Table[Obj, int]
t[Obj(x: 3, y: 4, z: "debug")] = 34
echo t[Obj(x: 3, y: 4, z: "ignored")] # 34
```
See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#typeminusbound-overloads)
for more information.
## Compiler changes

View File

@@ -53,7 +53,7 @@
- [``joyent_http_parser``](https://github.com/nim-lang/joyent_http_parser)
- Proc [toCountTable](https://nim-lang.org/docs/tables.html#toCountTable,openArray[A])
now produces a `CountTable` with values correspoding to the number of occurrences
now produces a `CountTable` with values corresponding to the number of occurrences
of the key in the input. It used to produce a table with all values set to `1`.
Counting occurrences in a sequence used to be:
@@ -339,7 +339,7 @@ for i in a..b:
- Fixed "ReraiseError when using try/except within finally block"
([#5871](https://github.com/nim-lang/Nim/issues/5871))
- Fixed "Range type inference leads to counter-intuitive behvaiour"
- Fixed "Range type inference leads to counter-intuitive behaviour"
([#5854](https://github.com/nim-lang/Nim/issues/5854))
- Fixed "JSON % operator can fail in extern procs with dynamic types"
([#6385](https://github.com/nim-lang/Nim/issues/6385))
@@ -403,7 +403,7 @@ for i in a..b:
([#6589](https://github.com/nim-lang/Nim/issues/6589))
- Fixed "Generated c code calls function twice"
([#6292](https://github.com/nim-lang/Nim/issues/6292))
- Fixed "Range type inference leads to counter-intuitive behvaiour"
- Fixed "Range type inference leads to counter-intuitive behaviour"
([#5854](https://github.com/nim-lang/Nim/issues/5854))
- Fixed "New backward indexing is too limited"
([#6631](https://github.com/nim-lang/Nim/issues/6631))

View File

@@ -22,7 +22,7 @@
- We removed `unicode.Rune16` without any deprecation period as the name
was wrong (see the [RFC](https://github.com/nim-lang/RFCs/issues/151) for details)
and we didn't find any usages of it in the wild. If you still need it, add this
and we didn't find any usage of it in the wild. If you still need it, add this
piece of code to your project:
```nim
type

View File

@@ -11,7 +11,7 @@
* Fixed "Assertion error when running `nim check` on compiler/nim.nim" [#12281](https://github.com/nim-lang/Nim/issues/12281)
* Fixed "Compiler crash with empty array and generic instantiation with int as parameter" [#12264](https://github.com/nim-lang/Nim/issues/12264)
* Fixed "Regression in JS backend codegen "Error: request to generate code for .compileTime proc"" [#12240](https://github.com/nim-lang/Nim/issues/12240)
* Fix how `relativePath` handle case sensitiviy
* Fix how `relativePath` handles case sensitivity
* Fixed "SIGSEGV in compiler when using generic types and seqs" [#12336](https://github.com/nim-lang/Nim/issues/12336)
* Fixed "[1.0.0] weird interaction between `import os` and casting integer to char on macosx trigger bad codegen" [#12291](https://github.com/nim-lang/Nim/issues/12291)
* VM: no special casing for big endian machines
@@ -43,7 +43,7 @@
* threadpool: fix link in docs (#12258)
* Fix spellings (#12277)
* fix #12278, don't expose internal PCRE documentation
* Fixed "Documentation of quitprocs is wrong" [#12279(https://github.com/nim-lang/Nim/issues/12279)
* Fixed "Documentation of quitprocs is wrong" [#12279](https://github.com/nim-lang/Nim/issues/12279)
* Fix typo in docs
* Fix reference to parseSpec proc in readme
* [doc/tut1] removed discard discussion in comments

View File

@@ -169,7 +169,7 @@ echo f
- The Nim compiler now supports a new pragma called ``.localPassc`` to
pass specific compiler options to the C(++) backend for the C(++) file
that was produced from the current Nim module.
- The compiler now inferes "sink parameters". To disable this for a specific routine,
- The compiler now infers "sink parameters". To disable this for a specific routine,
annotate it with `.nosinks`. To disable it for a section of code, use
`{.push sinkInference: off.}`...`{.pop.}`.
- The compiler now supports a new switch `--panics:on` that turns runtime
@@ -261,7 +261,7 @@ echo f
([#12812](https://github.com/nim-lang/Nim/issues/12812))
- Fixed "Produce static/const initializations for variables when possible"
([#12216](https://github.com/nim-lang/Nim/issues/12216))
- Fixed "Assigning descriminator field leads to internal assert with --gc:destructors"
- Fixed "Assigning discriminator field leads to internal assert with --gc:destructors"
([#12821](https://github.com/nim-lang/Nim/issues/12821))
- Fixed "nimsuggest `use` command does not return all instances of symbol"
([#12832](https://github.com/nim-lang/Nim/issues/12832))

View File

@@ -283,7 +283,7 @@ The definition of `"strictFuncs"` was changed.
The old definition was roughly: "A store to a ref/ptr deref is forbidden unless it's coming from a `var T` parameter".
The new definition is: "A store to a ref/ptr deref is forbidden."
This new definition is much easier to understand, the price is some expressitivity. The following code used to be
This new definition is much easier to understand, the price is some expressiveness. The following code used to be
accepted:
```nim

View File

@@ -22,9 +22,9 @@
- `bindMethod` in `std/jsffi` is deprecated, don't use it with closures.
- JS backend now supports lambda lifting for closures. Use `--legacy:jsNoLambdaLifting` to emulate old behaviors.
- The JS backend now supports lambda lifting for closures. Use `--legacy:jsNoLambdaLifting` to emulate old behaviors.
- JS backend now supports closure iterators.
- The JS backend now supports closure iterators.
- `owner` in `std/macros` is deprecated.
@@ -125,7 +125,7 @@ is often an easy workaround.
- `member` can be used to attach a procedure to a C++ type.
- C++ `constructor` now reuses `result` instead creating `this`.
- Inside a C++ constructor, `result` can be used to access the created object rather than `this`.
- Tuple unpacking changes:
- Tuple unpacking assignment now supports using underscores to discard values.

View File

@@ -279,7 +279,7 @@ const
GcTypeKinds* = {tyRef, tySequence, tyString}
tyTypeClasses* = {tyBuiltInTypeClass, tyCompositeTypeClass,
tyUserTypeClass, tyUserTypeClassInst,
tyUserTypeClass, tyUserTypeClassInst, tyConcept,
tyAnd, tyOr, tyNot, tyAnything}
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyUntyped} + tyTypeClasses
@@ -447,6 +447,8 @@ const
tfReturnsNew* = tfInheritable
tfNonConstExpr* = tfExplicitCallConv
## tyFromExpr where the expression shouldn't be evaluated as a static value
tfGenericHasDestructor* = tfExplicitCallConv
## tyGenericBody where an instance has a generated destructor
skError* = skUnknown
var
@@ -491,7 +493,7 @@ type
mAnd, mOr,
mImplies, mIff, mExists, mForall, mOld,
mEqStr, mLeStr, mLtStr,
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet,
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mXorSet,
mConStrStr, mSlice,
mDotDot, # this one is only necessary to give nice compile time warnings
mFields, mFieldPairs, mOmpParFor,
@@ -559,7 +561,7 @@ const
mStrToStr, mEnumToStr,
mAnd, mOr,
mEqStr, mLeStr, mLtStr,
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet,
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mXorSet,
mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInSet, mRepr, mOpenArrayToSeq}
@@ -591,7 +593,7 @@ type
TNode*{.final, acyclic.} = object # on a 32bit machine, this takes 32 bytes
when defined(useNodeIds):
id*: int
typ*: PType
typField: PType
info*: TLineInfo
flags*: TNodeFlags
case kind*: TNodeKind
@@ -706,7 +708,7 @@ type
when defined(nimsuggest):
endInfo*: TLineInfo
hasUserSpecifiedType*: bool # used for determining whether to display inlay type hints
owner*: PSym
ownerField: PSym
flags*: TSymFlags
ast*: PNode # syntax tree of proc, iterator, etc.:
# the whole proc including header; this is used
@@ -775,7 +777,7 @@ type
# formal param list
# for concepts, the concept body
# else: unused
owner*: PSym # the 'owner' of the type
ownerField: PSym # the 'owner' of the type
sym*: PSym # types have the sym associated with them
# it is used for converting types to strings
size*: BiggestInt # the size of the type in bytes
@@ -814,6 +816,15 @@ type
template nodeId(n: PNode): int = cast[int](n)
template typ*(n: PNode): PType =
n.typField
proc owner*(s: PSym|PType): PSym {.inline.} =
result = s.ownerField
proc setOwner*(s: PSym|PType, owner: PSym) {.inline.} =
s.ownerField = owner
type Gconfig = object
# we put comments in a side channel to avoid increasing `sizeof(TNode)`, which
# reduces memory usage given that `PNode` is the most allocated type by far.
@@ -1132,7 +1143,7 @@ proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
## new node with line info, type, and no children
result = newNode(kind)
result.info = info
result.typ = typ
result.typ() = typ
proc newNode*(kind: TNodeKind, info: TLineInfo): PNode =
## new node with line info, no type, and no children
@@ -1197,7 +1208,7 @@ proc newSym*(symKind: TSymKind, name: PIdent, idgen: IdGenerator; owner: PSym,
assert not name.isNil
let id = nextSymId idgen
result = PSym(name: name, kind: symKind, flags: {}, info: info, itemId: id,
options: options, owner: owner, offset: defaultOffset,
options: options, ownerField: owner, offset: defaultOffset,
disamb: getOrDefault(idgen.disambTable, name).int32)
idgen.disambTable.inc name
when false:
@@ -1278,13 +1289,13 @@ proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
proc newSymNode*(sym: PSym): PNode =
result = newNode(nkSym)
result.sym = sym
result.typ = sym.typ
result.typ() = sym.typ
result.info = sym.info
proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
result = newNode(nkSym)
result.sym = sym
result.typ = sym.typ
result.typ() = sym.typ
result.info = info
proc newOpenSym*(n: PNode): PNode {.inline.} =
@@ -1364,7 +1375,7 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
result = newNode(nkIntLit)
else: raiseAssert $kind
result.intVal = intVal
result.typ = typ
result.typ() = typ
proc newIntTypeNode*(intVal: Int128, typ: PType): PNode =
# XXX: introduce range check
@@ -1503,7 +1514,7 @@ iterator signature*(t: PType): PType =
proc newType*(kind: TTypeKind; idgen: IdGenerator; owner: PSym; son: sink PType = nil): PType =
let id = nextTypeId idgen
result = PType(kind: kind, owner: owner, size: defaultSize,
result = PType(kind: kind, ownerField: owner, size: defaultSize,
align: defaultAlignment, itemId: id,
uniqueId: id, sons: @[])
if son != nil: result.sons.add son
@@ -1558,7 +1569,7 @@ proc copyType*(t: PType, idgen: IdGenerator, owner: PSym): PType =
result.sym = t.sym # backend-info should not be copied
proc exactReplica*(t: PType): PType =
result = PType(kind: t.kind, owner: t.owner, size: defaultSize,
result = PType(kind: t.kind, ownerField: t.owner, size: defaultSize,
align: defaultAlignment, itemId: t.itemId,
uniqueId: t.uniqueId)
assignType(result, t)
@@ -1636,7 +1647,7 @@ proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) =
if mask != {} and propagateHasAsgn:
let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink})
if o2.kind in {tyTuple, tyObject, tyArray,
tySequence, tySet, tyDistinct}:
tySequence, tyString, tySet, tyDistinct}:
o2.flags.incl mask
owner.flags.incl mask
@@ -1666,7 +1677,7 @@ proc copyNode*(src: PNode): PNode =
return nil
result = newNode(src.kind)
result.info = src.info
result.typ = src.typ
result.typ() = src.typ
result.flags = src.flags * PersistentNodeFlags
result.comment = src.comment
when defined(useNodeIds):
@@ -1684,7 +1695,7 @@ proc copyNode*(src: PNode): PNode =
template transitionNodeKindCommon(k: TNodeKind) =
let obj {.inject.} = n[]
n[] = TNode(kind: k, typ: obj.typ, info: obj.info, flags: obj.flags)
n[] = TNode(kind: k, typField: n.typ, info: obj.info, flags: obj.flags)
# n.comment = obj.comment # shouldn't be needed, the address doesnt' change
when defined(useNodeIds):
n.id = obj.id
@@ -1707,7 +1718,7 @@ proc transitionNoneToSym*(n: PNode) =
template transitionSymKindCommon*(k: TSymKind) =
let obj {.inject.} = s[]
s[] = TSym(kind: k, itemId: obj.itemId, magic: obj.magic, typ: obj.typ, name: obj.name,
info: obj.info, owner: obj.owner, flags: obj.flags, ast: obj.ast,
info: obj.info, ownerField: obj.ownerField, flags: obj.flags, ast: obj.ast,
options: obj.options, position: obj.position, offset: obj.offset,
loc: obj.loc, annex: obj.annex, constraint: obj.constraint)
when hasFFI:
@@ -1735,7 +1746,7 @@ template copyNodeImpl(dst, src, processSonsStmt) =
dst.info = src.info
when defined(nimsuggest):
result.endInfo = src.endInfo
dst.typ = src.typ
dst.typ() = src.typ
dst.flags = src.flags * PersistentNodeFlags
dst.comment = src.comment
when defined(useNodeIds):

View File

@@ -135,7 +135,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
d.snippet = pl
excl d.flags, lfSingleUse
else:
if d.k == locNone and p.splitDecls == 0:
if d.k == locNone and p.splitDecls == 0 and p.config.exc != excGoto:
d = getTempCpp(p, typ.returnType, pl)
else:
if d.k == locNone: d = getTemp(p, typ.returnType)
@@ -336,7 +336,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
# variable. Thus, we create a temporary pointer variable instead.
let needsIndirect = mapType(p.config, n[0].typ, mapTypeChooser(n[0]) == skParam) != ctArray
if needsIndirect:
n.typ = n.typ.exactReplica
n.typ() = n.typ.exactReplica
n.typ.flags.incl tfVarIsPtr
a = initLocExprSingleUse(p, n)
a = withTmpIfNeeded(p, a, needsTmp)

View File

@@ -758,7 +758,10 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass:
typ = typ.last
typ = typ.skipTypes(abstractInstOwned)
if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr:
if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and
p.module.compileToCpp and e[0].kind == nkHiddenAddr and
# don't override existing location:
d.k == locNone:
d = initLocExprSingleUse(p, e[0][0])
return
else:
@@ -1569,6 +1572,10 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
discard getTypeDesc(p.module, t)
let ty = getUniqueType(t)
for i in 1..<e.len:
if nfPreventCg in e[i].flags:
# this is an object constructor node generated by the VM and
# this field is in an inactive case branch, don't generate assignment
continue
var check: PNode = nil
if e[i].len == 3 and optFieldCheck in p.options:
check = e[i][2]
@@ -1623,7 +1630,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
var elem, arr: TLoc
if n[1].kind == nkBracket:
n[1].typ = n.typ
n[1].typ() = n.typ
genSeqConstr(p, n[1], d)
return
if d.k == locNone:
@@ -2041,7 +2048,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
const
lookupOpr: array[mLeSet..mMinusSet, string] = [
lookupOpr: array[mLeSet..mXorSet, string] = [
"for ($1 = 0; $1 < $2; $1++) { $n" &
" $3 = (($4[$1] & ~ $5[$1]) == 0);$n" &
" if (!$3) break;}$n",
@@ -2051,7 +2058,8 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"if ($3) $3 = (#nimCmpMem($4, $5, $2) != 0);$n",
"&",
"|",
"& ~"]
"& ~",
"^"]
var a, b: TLoc
var i: TLoc
var setType = skipTypes(e[1].typ, abstractVar)
@@ -2082,6 +2090,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mMulSet: binaryExpr(p, e, d, "($1 & $2)")
of mPlusSet: binaryExpr(p, e, d, "($1 | $2)")
of mMinusSet: binaryExpr(p, e, d, "($1 & ~ $2)")
of mXorSet: binaryExpr(p, e, d, "($1 ^ $2)")
of mInSet:
genInOp(p, e, d)
else: internalError(p.config, e.info, "genSetOp()")
@@ -2109,7 +2118,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var a = initLocExpr(p, e[1])
var b = initLocExpr(p, e[2])
putIntoDest(p, d, e, ropecg(p.module, "(#nimCmpMem($1, $2, $3)==0)", [a.rdCharLoc, b.rdCharLoc, size]))
of mMulSet, mPlusSet, mMinusSet:
of mMulSet, mPlusSet, mMinusSet, mXorSet:
# we inline the simple for loop for better code generation:
i = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter
a = initLocExpr(p, e[1])
@@ -2150,6 +2159,8 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
[getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage)
elif etyp.kind == tyBool and srcTyp.kind in IntegralTypes:
putIntoDest(p, d, e, "(($1) != 0)" % [rdCharLoc(a)], a.storage)
elif etyp.kind == tyProc and srcTyp.kind == tyProc and sameBackendType(etyp, srcTyp):
expr(p, e[1], d)
else:
if etyp.kind == tyPtr:
# generates the definition of structs for casts like cast[ptr object](addr x)[]
@@ -2318,7 +2329,7 @@ proc genWasMoved(p: BProc; n: PNode) =
# [addrLoc(p.config, a), getTypeDesc(p.module, a.t)])
proc genMove(p: BProc; n: PNode; d: var TLoc) =
var a: TLoc = initLocExpr(p, n[1].skipAddr)
var a: TLoc = initLocExpr(p, n[1].skipAddr, {lfEnforceDeref})
if n.len == 4:
# generated by liftdestructors:
var src: TLoc = initLocExpr(p, n[2])
@@ -2545,7 +2556,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mSetLengthStr: genSetLengthStr(p, e, d)
of mSetLengthSeq: genSetLengthSeq(p, e, d)
of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
mInSet:
mInSet, mXorSet:
genSetOp(p, e, d, op)
of mNewString, mNewStringOfCap, mExit, mParseBiggestFloat:
var opr = e[0].sym
@@ -3069,16 +3080,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkObjConstr: genObjConstr(p, n, d)
of nkCast: genCast(p, n, d)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d)
of nkHiddenAddr:
if n[0].kind == nkDerefExpr:
# addr ( deref ( x )) --> x
var x = n[0][0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
x.typ = n.typ
expr(p, x, d)
return
genAddr(p, n, d)
of nkAddr: genAddr(p, n, d)
of nkAddr, nkHiddenAddr: genAddr(p, n, d)
of nkBracketExpr: genBracketExpr(p, n, d)
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
of nkDotExpr: genRecordField(p, n, d)
@@ -3109,6 +3111,12 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkConstSection:
if useAliveDataFromDce in p.module.flags:
genConstStmt(p, n)
else: # enforce addressable consts for exportc
let m = p.module
for it in n:
let symNode = skipPragmaExpr(it[0])
if symNode.kind == nkSym and sfExportc in symNode.sym.flags:
requestConstImpl(p, symNode.sym)
# else: consts generated lazily on use
of nkForStmt: internalError(p.config, n.info, "for statement not eliminated")
of nkCaseStmt: genCase(p, n, d)

View File

@@ -81,7 +81,6 @@ proc fillBackendName(m: BModule; s: PSym) =
result.add '_'
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
s.loc.snippet = result
writeMangledName(m.ndi, s, m.config)
proc fillParamName(m: BModule; s: PSym) =
if s.loc.snippet == "":
@@ -105,7 +104,6 @@ proc fillParamName(m: BModule; s: PSym) =
# That would lead to either needing to reload `proxy` or to overwrite the
# executable file for the main module, which is running (or both!) -> error.
s.loc.snippet = res.rope
writeMangledName(m.ndi, s, m.config)
proc fillLocalName(p: BProc; s: PSym) =
assert s.kind in skLocalVars+{skTemp}
@@ -121,7 +119,6 @@ proc fillLocalName(p: BProc; s: PSym) =
result.add "_" & rope(counter+1)
p.sigConflicts.inc(key)
s.loc.snippet = result
if s.kind != skTemp: writeMangledName(p.module.ndi, s, p.config)
proc scopeMangledParam(p: BProc; param: PSym) =
## parameter generation only takes BModule, not a BProc, so we have to
@@ -349,7 +346,12 @@ proc getSimpleTypeDesc(m: BModule; typ: PType): Rope =
of tyNil: result = typeNameOrLiteral(m, typ, "void*")
of tyInt..tyUInt64:
result = typeNameOrLiteral(m, typ, NumericalTypeToStr[typ.kind])
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.skipModifier)
of tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.skipModifier)
of tyDistinct:
result = getSimpleTypeDesc(m, typ.skipModifier)
if isImportedType(typ) and result != "":
useHeader(m, typ.sym)
result = typ.sym.loc.snippet
of tyStatic:
if typ.n != nil: result = getSimpleTypeDesc(m, skipModifier typ)
else:
@@ -860,7 +862,8 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
let sig = hashType(origTyp, m.config)
result = getTypePre(m, t, sig)
# tyDistinct matters if it is an importc type
result = getTypePre(m, origTyp.skipTypes(irrelevantForBackend-{tyOwned, tyDistinct}), sig)
defer: # defer is the simplest in this case
if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
addAbiCheck(m, t, result)

View File

@@ -14,7 +14,7 @@ import
nversion, nimsets, msgs, bitsets, idents, types,
ccgutils, ropes, wordrecg, treetab, cgmeth,
rodutils, renderer, cgendata, aliases,
lowerings, ndi, lineinfos, pathutils, transf,
lowerings, lineinfos, pathutils, transf,
injectdestructors, astmsgs, modulepaths, pushpoppragmas,
mangleutils
@@ -97,7 +97,7 @@ proc t(a: TLoc): PType {.inline.} =
proc lodeTyp(t: PType): PNode =
result = newNode(nkEmpty)
result.typ = t
result.typ() = t
proc isSimpleConst(typ: PType): bool =
let t = skipTypes(typ, abstractVar)
@@ -2085,9 +2085,6 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
if sfSystemModule in module.flags:
incl result.flags, preventStackTrace
excl(result.preInitProc.options, optStackTrace)
let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCfilePath(g.config, filename), "ndi")
else: AbsoluteFile""
open(result.ndi, ndiName, g.config)
proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex))
@@ -2217,7 +2214,6 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
# it would generate multiple 'main' procs, for instance.
proc writeModule(m: BModule, pending: bool) =
template onExit() = close(m.ndi, m.config)
let cfile = getCFile(m)
if moduleHasChanged(m.g.graph, m.module):
genInitCode(m)
@@ -2235,12 +2231,10 @@ proc writeModule(m: BModule, pending: bool) =
when hasTinyCBackend:
if m.config.cmd == cmdTcc:
tccgen.compileCCode($code, m.config)
onExit()
return
if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached}
addFileToCompile(m.config, cf)
onExit()
proc updateCachedModule(m: BModule) =
let cfile = getCFile(m)
@@ -2252,12 +2246,13 @@ proc updateCachedModule(m: BModule) =
addFileToCompile(m.config, cf)
proc generateLibraryDestroyGlobals(graph: ModuleGraph; m: BModule; body: PNode; isDynlib: bool): PSym =
let procname = getIdent(graph.cache, "NimDestroyGlobals")
let prefixedName = m.config.nimMainPrefix & "NimDestroyGlobals"
let procname = getIdent(graph.cache, prefixedName)
result = newSym(skProc, procname, m.idgen, m.module.owner, m.module.info)
result.typ = newProcType(m.module.info, m.idgen, m.module.owner)
result.typ.callConv = ccCDecl
incl result.flags, sfExportc
result.loc.snippet = "NimDestroyGlobals"
result.loc.snippet = prefixedName
if isDynlib:
incl(result.loc.flags, lfExportLib)

View File

@@ -11,7 +11,7 @@
import
ast, ropes, options,
ndi, lineinfos, pathutils, modulegraphs
lineinfos, pathutils, modulegraphs
import std/[intsets, tables, sets]
@@ -172,7 +172,6 @@ type
# OpenGL wrapper
sigConflicts*: CountTable[SigHash]
g*: BModuleList
ndi*: NdiFile
template config*(m: BModule): ConfigRef = m.g.config
template config*(p: BProc): ConfigRef = p.module.g.config

View File

@@ -55,7 +55,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].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

@@ -161,10 +161,6 @@ type
# is their finally. For finally it is parent finally. Otherwise -1
idgen: IdGenerator
varStates: Table[ItemId, int] # Used to detect if local variable belongs to multiple states
stateVarSym: PSym # :state variable. nil if env already introduced by lambdalifting
# remove if -d:nimOptIters is default, treating it as always nil
nimOptItersEnabled: bool # tracks if -d:nimOptIters is enabled
# should be default when issues are fixed, see #24094
const
nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
@@ -174,11 +170,8 @@ const
localRequiresLifting = -2
proc newStateAccess(ctx: var Ctx): PNode =
if ctx.stateVarSym.isNil:
result = rawIndirectAccess(newSymNode(getEnvParam(ctx.fn)),
result = rawIndirectAccess(newSymNode(getEnvParam(ctx.fn)),
getStateField(ctx.g, ctx.fn), ctx.fn.info)
else:
result = newSymNode(ctx.stateVarSym)
proc newStateAssgn(ctx: var Ctx, toValue: PNode): PNode =
# Creates state assignment:
@@ -196,22 +189,12 @@ proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
result.flags.incl sfNoInit
assert(not typ.isNil, "Env var needs a type")
if not ctx.stateVarSym.isNil:
# We haven't gone through labmda lifting yet, so just create a local var,
# it will be lifted later
if ctx.tempVars.isNil:
ctx.tempVars = newNodeI(nkVarSection, ctx.fn.info)
addVar(ctx.tempVars, newSymNode(result))
else:
let envParam = getEnvParam(ctx.fn)
# let obj = envParam.typ.lastSon
result = addUniqueField(envParam.typ.elementType, result, ctx.g.cache, ctx.idgen)
let envParam = getEnvParam(ctx.fn)
# let obj = envParam.typ.lastSon
result = addUniqueField(envParam.typ.elementType, result, ctx.g.cache, ctx.idgen)
proc newEnvVarAccess(ctx: Ctx, s: PSym): PNode =
if ctx.stateVarSym.isNil:
result = rawIndirectAccess(newSymNode(getEnvParam(ctx.fn)), s, ctx.fn.info)
else:
result = newSymNode(s)
result = rawIndirectAccess(newSymNode(getEnvParam(ctx.fn)), s, ctx.fn.info)
proc newTempVarAccess(ctx: Ctx, s: PSym): PNode =
result = newSymNode(s, ctx.fn.info)
@@ -263,20 +246,12 @@ proc newTempVarDef(ctx: Ctx, s: PSym, initialValue: PNode): PNode =
v = ctx.g.emptyNode
newTree(nkVarSection, newTree(nkIdentDefs, newSymNode(s), ctx.g.emptyNode, v))
proc newEnvVarAsgn(ctx: Ctx, s: PSym, v: PNode): PNode
proc newTempVar(ctx: var Ctx, typ: PType, parent: PNode, initialValue: PNode = nil): PSym =
if ctx.nimOptItersEnabled:
result = newSym(skVar, getIdent(ctx.g.cache, ":tmpSlLower" & $ctx.tempVarId), ctx.idgen, ctx.fn, ctx.fn.info)
else:
result = ctx.newEnvVar(":tmpSlLower" & $ctx.tempVarId, typ)
result = newSym(skVar, getIdent(ctx.g.cache, ":tmpSlLower" & $ctx.tempVarId), ctx.idgen, ctx.fn, ctx.fn.info)
inc ctx.tempVarId
result.typ = typ
assert(not typ.isNil, "Temp var needs a type")
if ctx.nimOptItersEnabled:
parent.add(ctx.newTempVarDef(result, initialValue))
elif initialValue != nil:
parent.add(ctx.newEnvVarAsgn(result, initialValue))
parent.add(ctx.newTempVarDef(result, initialValue))
proc hasYields(n: PNode): bool =
# TODO: This is very inefficient. It traverses the node, looking for nkYieldStmt.
@@ -336,12 +311,12 @@ proc newNullifyCurExc(ctx: var Ctx, info: TLineInfo): PNode =
let curExc = ctx.newCurExcAccess()
curExc.info = info
let nilnode = newNode(nkNilLit)
nilnode.typ = curExc.typ
nilnode.typ() = curExc.typ
result = newTree(nkAsgn, curExc, nilnode)
proc newOr(g: ModuleGraph, a, b: PNode): PNode {.inline.} =
result = newTree(nkCall, newSymNode(g.getSysMagic(a.info, "or", mOr)), a, b)
result.typ = g.getSysType(a.info, tyBool)
result.typ() = g.getSysType(a.info, tyBool)
result.info = a.info
proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
@@ -359,7 +334,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
newSymNode(g.getSysMagic(c.info, "of", mOf)),
g.callCodegenProc("getCurrentException"),
c[i])
nextCond.typ = ctx.g.getSysType(c.info, tyBool)
nextCond.typ() = ctx.g.getSysType(c.info, tyBool)
nextCond.info = c.info
if cond.isNil:
@@ -455,24 +430,13 @@ proc newTempVarAsgn(ctx: Ctx, s: PSym, v: PNode): PNode =
result = newTree(nkFastAsgn, ctx.newTempVarAccess(s), v)
result.info = v.info
proc newEnvVarAsgn(ctx: Ctx, s: PSym, v: PNode): PNode =
# unused with -d:nimOptIters
if isEmptyType(v.typ):
result = v
else:
result = newTree(nkFastAsgn, ctx.newEnvVarAccess(s), v)
result.info = v.info
proc addExprAssgn(ctx: Ctx, output, input: PNode, sym: PSym) =
var input = input
if input.kind == nkStmtListExpr:
let (st, res) = exprToStmtList(input)
output.add(st)
input = res
if ctx.nimOptItersEnabled:
output.add(ctx.newTempVarAsgn(sym, input))
output.add(ctx.newTempVarAsgn(sym, res))
else:
output.add(ctx.newEnvVarAsgn(sym, input))
output.add(ctx.newTempVarAsgn(sym, input))
proc convertExprBodyToAsgn(ctx: Ctx, exprBody: PNode, res: PSym): PNode =
result = newNodeI(nkStmtList, exprBody.info)
@@ -480,11 +444,11 @@ proc convertExprBodyToAsgn(ctx: Ctx, exprBody: PNode, res: PSym): PNode =
proc newNotCall(g: ModuleGraph; e: PNode): PNode =
result = newTree(nkCall, newSymNode(g.getSysMagic(e.info, "not", mNot), e.info), e)
result.typ = g.getSysType(e.info, tyBool)
result.typ() = g.getSysType(e.info, tyBool)
proc boolLit(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
result = newIntLit(g, info, ord value)
result.typ = getSysType(g, info, tyBool)
result.typ() = getSysType(g, info, tyBool)
proc captureVar(c: var Ctx, s: PSym) =
if c.varStates.getOrDefault(s.itemId) != localRequiresLifting:
@@ -522,7 +486,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
result = newNodeI(nkStmtListExpr, n.info)
if n.typ.isNil: internalError(ctx.g.config, "lowerStmtListExprs: constr typ.isNil")
result.typ = n.typ
result.typ() = n.typ
for i in 0..<n.len:
case n[i].kind
@@ -549,7 +513,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
let isExpr = not isEmptyType(n.typ)
if isExpr:
result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ
result.typ() = n.typ
tmp = ctx.newTempVar(n.typ, result)
else:
result = newNodeI(nkStmtList, n.info)
@@ -601,11 +565,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
else:
internalError(ctx.g.config, "lowerStmtListExpr(nkIf): " & $branch.kind)
if isExpr:
if ctx.nimOptItersEnabled:
result.add(ctx.newTempVarAccess(tmp))
else:
result.add(ctx.newEnvVarAccess(tmp))
if isExpr: result.add(ctx.newTempVarAccess(tmp))
of nkTryStmt, nkHiddenTryStmt:
var ns = false
@@ -618,7 +578,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if isExpr:
result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ
result.typ() = n.typ
let tmp = ctx.newTempVar(n.typ, result)
n[0] = ctx.convertExprBodyToAsgn(n[0], tmp)
@@ -635,10 +595,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
else:
internalError(ctx.g.config, "lowerStmtListExpr(nkTryStmt): " & $branch.kind)
result.add(n)
if ctx.nimOptItersEnabled:
result.add(ctx.newTempVarAccess(tmp))
else:
result.add(ctx.newEnvVarAccess(tmp))
result.add(ctx.newTempVarAccess(tmp))
of nkCaseStmt:
var ns = false
@@ -652,7 +609,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if isExpr:
result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ
result.typ() = n.typ
let tmp = ctx.newTempVar(n.typ, result)
if n[0].kind == nkStmtListExpr:
@@ -670,10 +627,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
else:
internalError(ctx.g.config, "lowerStmtListExpr(nkCaseStmt): " & $branch.kind)
result.add(n)
if ctx.nimOptItersEnabled:
result.add(ctx.newTempVarAccess(tmp))
else:
result.add(ctx.newEnvVarAccess(tmp))
result.add(ctx.newTempVarAccess(tmp))
elif n[0].kind == nkStmtListExpr:
result = newNodeI(nkStmtList, n.info)
let (st, ex) = exprToStmtList(n[0])
@@ -692,7 +646,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if isExpr:
result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ
result.typ() = n.typ
else:
result = newNodeI(nkStmtList, n.info)
@@ -706,11 +660,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
let tmp = ctx.newTempVar(cond.typ, result, cond)
# result.add(ctx.newTempVarAsgn(tmp, cond))
var check: PNode
if ctx.nimOptItersEnabled:
check = ctx.newTempVarAccess(tmp)
else:
check = ctx.newEnvVarAccess(tmp)
var check = ctx.newTempVarAccess(tmp)
if n[0].sym.magic == mOr:
check = ctx.g.newNotCall(check)
@@ -720,18 +670,12 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
let (st, ex) = exprToStmtList(cond)
ifBody.add(st)
cond = ex
if ctx.nimOptItersEnabled:
ifBody.add(ctx.newTempVarAsgn(tmp, cond))
else:
ifBody.add(ctx.newEnvVarAsgn(tmp, cond))
ifBody.add(ctx.newTempVarAsgn(tmp, cond))
let ifBranch = newTree(nkElifBranch, check, ifBody)
let ifNode = newTree(nkIfStmt, ifBranch)
result.add(ifNode)
if ctx.nimOptItersEnabled:
result.add(ctx.newTempVarAccess(tmp))
else:
result.add(ctx.newEnvVarAccess(tmp))
result.add(ctx.newTempVarAccess(tmp))
else:
for i in 0..<n.len:
if n[i].kind == nkStmtListExpr:
@@ -742,10 +686,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if n[i].kind in nkCallKinds: # XXX: This should better be some sort of side effect tracking
let tmp = ctx.newTempVar(n[i].typ, result, n[i])
# result.add(ctx.newTempVarAsgn(tmp, n[i]))
if ctx.nimOptItersEnabled:
n[i] = ctx.newTempVarAccess(tmp)
else:
n[i] = ctx.newEnvVarAccess(tmp)
n[i] = ctx.newTempVarAccess(tmp)
result.add(n)
@@ -791,7 +732,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if ns:
needsSplit = true
result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ
result.typ() = n.typ
let (st, ex) = exprToStmtList(n[^1])
result.add(st)
n[^1] = ex
@@ -861,7 +802,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if ns:
needsSplit = true
result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ
result.typ() = n.typ
let (st, ex) = exprToStmtList(n[0])
result.add(st)
n[0] = ex
@@ -873,10 +814,10 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if ns:
needsSplit = true
result = newNodeI(nkStmtListExpr, n.info)
result.typ = n.typ
result.typ() = n.typ
let (st, ex) = exprToStmtList(n[1])
n.transitionSonsKind(nkBlockStmt)
n.typ = nil
n.typ() = nil
n[1] = st
result.add(n)
result.add(ex)
@@ -897,9 +838,9 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
# raise
let curExc = ctx.newCurExcAccess()
let nilnode = newNode(nkNilLit)
nilnode.typ = curExc.typ
nilnode.typ() = curExc.typ
let cmp = newTree(nkCall, newSymNode(ctx.g.getSysMagic(info, "==", mEqRef), info), curExc, nilnode)
cmp.typ = ctx.g.getSysType(info, tyBool)
cmp.typ() = ctx.g.getSysType(info, tyBool)
let retStmt =
if ctx.nearestFinally == 0:
@@ -1244,11 +1185,11 @@ proc newArrayType(g: ModuleGraph; n: int, t: PType; idgen: IdGenerator; owner: P
proc createExceptionTable(ctx: var Ctx): PNode {.inline.} =
result = newNodeI(nkBracket, ctx.fn.info)
result.typ = ctx.g.newArrayType(ctx.exceptionTable.len, ctx.g.getSysType(ctx.fn.info, tyInt16), ctx.idgen, ctx.fn)
result.typ() = ctx.g.newArrayType(ctx.exceptionTable.len, ctx.g.getSysType(ctx.fn.info, tyInt16), ctx.idgen, ctx.fn)
for i in ctx.exceptionTable:
let elem = newIntNode(nkIntLit, i)
elem.typ = ctx.g.getSysType(ctx.fn.info, tyInt16)
elem.typ() = ctx.g.getSysType(ctx.fn.info, tyInt16)
result.add(elem)
proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
@@ -1271,7 +1212,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
let getNextState = newTree(nkBracketExpr,
ctx.createExceptionTable(),
ctx.newStateAccess())
getNextState.typ = intTyp
getNextState.typ() = intTyp
# :state = exceptionTable[:state]
result.add(ctx.newStateAssgn(getNextState))
@@ -1282,7 +1223,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
ctx.g.getSysMagic(info, "==", mEqI).newSymNode(),
ctx.newStateAccess(),
newIntTypeNode(0, intTyp))
cond.typ = boolTyp
cond.typ() = boolTyp
let raiseStmt = newTree(nkRaiseStmt, ctx.g.emptyNode)
let ifBranch = newTree(nkElifBranch, cond, raiseStmt)
@@ -1295,7 +1236,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
ctx.g.getSysMagic(info, "<", mLtI).newSymNode,
newIntTypeNode(0, intTyp),
ctx.newStateAccess())
cond.typ = boolTyp
cond.typ() = boolTyp
let asgn = newTree(nkAsgn, ctx.newUnrollFinallyAccess(info), cond)
result.add(asgn)
@@ -1306,12 +1247,12 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
ctx.g.getSysMagic(info, "<", mLtI).newSymNode,
ctx.newStateAccess(),
newIntTypeNode(0, intTyp))
cond.typ = boolTyp
cond.typ() = boolTyp
let negateState = newTree(nkCall,
ctx.g.getSysMagic(info, "-", mUnaryMinusI).newSymNode,
ctx.newStateAccess())
negateState.typ = intTyp
negateState.typ() = intTyp
let ifBranch = newTree(nkElifBranch, cond, ctx.newStateAssgn(negateState))
let ifStmt = newTree(nkIfStmt, ifBranch)
@@ -1343,13 +1284,6 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
result.info = n.info
let localVars = newNodeI(nkStmtList, n.info)
if not ctx.stateVarSym.isNil:
let varSect = newNodeI(nkVarSection, n.info)
addVar(varSect, newSymNode(ctx.stateVarSym))
localVars.add(varSect)
if not ctx.tempVars.isNil:
localVars.add(ctx.tempVars)
let blockStmt = newNodeI(nkBlockStmt, n.info)
blockStmt.add(newSymNode(ctx.stateLoopLabel))
@@ -1552,21 +1486,11 @@ proc liftLocals(c: var Ctx, n: PNode): PNode =
n[i] = liftLocals(c, n[i])
proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n: PNode): PNode =
var ctx = Ctx(g: g, fn: fn, idgen: idgen,
# should be default when issues are fixed, see #24094:
nimOptItersEnabled: isDefined(g.config, "nimOptIters"))
var ctx = Ctx(g: g, fn: fn, idgen: idgen)
if getEnvParam(fn).isNil:
if ctx.nimOptItersEnabled:
# The transformation should always happen after at least partial lambdalifting
# is performed, so that the closure iter environment is always created upfront.
doAssert(false, "Env param not created before iter transformation")
else:
# Lambda lifting was not done yet. Use temporary :state sym, which will
# be handled specially by lambda lifting. Local temp vars (if needed)
# should follow the same logic.
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), idgen, fn, fn.info)
ctx.stateVarSym.typ = g.createClosureIterStateType(fn, idgen)
# The transformation should always happen after at least partial lambdalifting
# is performed, so that the closure iter environment is always created upfront.
doAssert(getEnvParam(fn) != nil, "Env param not created before iter transformation")
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), idgen, fn, fn.info)
var pc = PreprocessContext(finallys: @[], config: g.config, idgen: idgen)
@@ -1592,10 +1516,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
let caseDispatcher = newTreeI(nkCaseStmt, n.info,
ctx.newStateAccess())
if ctx.nimOptItersEnabled:
# Lamdalifting will not touch our locals, it is our responsibility to lift those that
# need it.
detectCapturedVars(ctx)
# Lamdalifting will not touch our locals, it is our responsibility to lift those that
# need it.
detectCapturedVars(ctx)
for s in ctx.states:
let body = ctx.transformStateAssignments(s.body)
@@ -1604,8 +1527,7 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
caseDispatcher.add newTreeI(nkElse, n.info, newTreeI(nkReturnStmt, n.info, g.emptyNode))
result = wrapIntoStateLoop(ctx, caseDispatcher)
if ctx.nimOptItersEnabled:
result = liftLocals(ctx, result)
result = liftLocals(ctx, result)
when false:
echo "TRANSFORM TO STATES: "

View File

@@ -203,13 +203,14 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
else: invalidCmdLineOption(conf, pass, orig, info)
let isSomeHint = state in {wHint, wHintAsError}
let isSomeWarning = state in {wWarning, wWarningAsError}
template findNote(noteMin, noteMax, name) =
# unfortunately, hintUser and warningUser clash, otherwise implementation would simplify a bit
let x = findStr(noteMin, noteMax, id, errUnknown)
if x != errUnknown: notes = {TNoteKind(x)}
else:
if isSomeHint:
message(conf, info, hintUnknownHint, id)
if isSomeHint or isSomeWarning:
message(conf, info, warnUnknownNotes, "unknown $#: $#" % [name, id])
else:
localError(conf, info, "unknown $#: $#" % [name, id])
case id.normalize
@@ -919,6 +920,12 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
discard parseSaturatedNatural(arg, value)
if not value > 0: localError(conf, info, "maxLoopIterationsVM must be a positive integer greater than zero")
conf.maxLoopIterationsVM = value
of "maxcalldepthvm":
expectArg(conf, switch, arg, pass, info)
var value: int = 2_000
discard parseSaturatedNatural(arg, value)
if value <= 0: localError(conf, info, "maxCallDepthVM must be a positive integer greater than zero")
conf.maxCallDepthVM = value
of "errormax":
expectArg(conf, switch, arg, pass, info)
# Note: `nim check` (etc) can overwrite this.

View File

@@ -11,7 +11,7 @@
## for details. Note this is a first implementation and only the "Concept matching"
## section has been implemented.
import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types
import ast, semdata, lookups, lineinfos, idents, msgs, renderer, types, layeredtable
import std/intsets
@@ -78,6 +78,7 @@ type
magic: TMagic ## mArrGet and mArrPut is wrong in system.nim and
## cannot be fixed that easily.
## Thus we special case it here.
concpt: PType
proc existingBinding(m: MatchCon; key: PType): PType =
## checks if we bound the type variable 'key' already to some
@@ -88,22 +89,52 @@ proc existingBinding(m: MatchCon; key: PType): PType =
proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool
proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
proc matchType(c: PContext; f, ao: PType; m: var MatchCon): bool
proc acceptsAllTypes(t: PType): bool=
result = false
if t.kind == tyAnything:
result = true
elif t.kind == tyGenericParam:
if tfImplicitTypeParam in t.flags:
result = true
if not t.hasElementType or t.elementType.kind == tyNone:
result = true
proc matchKids(c: PContext; f, a: PType; m: var MatchCon, start=0): bool=
result = true
for i in start..<f.kidsLen - ord(f.kind == tyGenericInst):
if not matchType(c, f[i], a[i], m): return false
proc matchType(c: PContext; f, ao: PType; m: var MatchCon): bool =
## The heart of the concept matching process. 'f' is the formal parameter of some
## routine inside the concept that we're looking for. 'a' is the formal parameter
## of a routine that might match.
const
ignorableForArgType = {tyVar, tySink, tyLent, tyOwned, tyGenericInst, tyAlias, tyInferred}
var a = ao
case a.kind
of tyGenericParam:
let binding = m.existingBinding(a)
if binding != nil:
a = binding
else:
discard
case f.kind
of tyAlias:
result = matchType(c, f.skipModifier, a, m)
of tyTypeDesc:
if isSelf(f):
#let oldLen = m.inferred.len
result = matchType(c, a, m.potentialImplementation, m)
#echo "self is? ", result, " ", a.kind, " ", a, " ", m.potentialImplementation, " ", m.potentialImplementation.kind
#m.inferred.setLen oldLen
#echo "A for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
if m.magic in {mArrPut, mArrGet}:
result = false
if m.potentialImplementation.reduceToBase.kind in arrPutGetMagicApplies:
m.inferred.add((a, last m.potentialImplementation))
result = true
else:
result = matchType(c, a, m.potentialImplementation, m)
else:
if a.kind == tyTypeDesc and f.hasElementType == a.hasElementType:
if f.hasElementType:
@@ -112,14 +143,11 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
result = true # both lack it
else:
result = false
of tyGenericInvocation:
result = false
if a.kind == tyGenericInst and a.genericHead.kind == tyGenericBody:
if sameType(f.genericHead, a.genericHead) and f.kidsLen == a.kidsLen-1:
for i in FirstGenericParamAt ..< f.kidsLen:
if not matchType(c, f[i], a[i], m): return false
return true
result = matchKids(c, f, a, m, start=FirstGenericParamAt)
of tyGenericParam:
let ak = a.skipTypes({tyVar, tySink, tyLent, tyOwned})
if ak.kind in {tyTypeDesc, tyStatic} and not isSelf(ak):
@@ -136,7 +164,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
when logBindings: echo "A adding ", f, " ", ak
m.inferred.add((f, ak))
elif m.magic == mArrGet and ak.kind in {tyArray, tyOpenArray, tySequence, tyVarargs, tyCstring, tyString}:
when logBindings: echo "B adding ", f, " ", lastSon ak
when logBindings: echo "B adding ", f, " ", last ak
m.inferred.add((f, last ak))
result = true
else:
@@ -151,7 +179,6 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
else:
result = false
#echo "B for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
of tyVar, tySink, tyLent, tyOwned:
# modifiers in the concept must be there in the actual implementation
# too but not vice versa.
@@ -170,22 +197,43 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
result = ak.kind == f.kind or ak.kind == tyOrdinal or
(ak.kind == tyGenericParam and ak.hasElementType and ak.elementType.kind == tyOrdinal)
of tyConcept:
let oldLen = m.inferred.len
let oldPotentialImplementation = m.potentialImplementation
m.potentialImplementation = a
result = conceptMatchNode(c, f.n.lastSon, m)
m.potentialImplementation = oldPotentialImplementation
if not result:
m.inferred.setLen oldLen
if a.kind == tyConcept and f.n == a.n:
result = true
elif m.concpt.size == szIllegalRecursion:
result = false
else:
let oldLen = m.inferred.len
let oldPotentialImplementation = m.potentialImplementation
m.potentialImplementation = a
m.concpt.size = szIllegalRecursion
let oldConcept = m.concpt
m.concpt = f
result = conceptMatchNode(c, f.n.lastSon, m)
m.potentialImplementation = oldPotentialImplementation
m.concpt = oldConcept
m.concpt.size = szUnknownSize
if not result:
m.inferred.setLen oldLen
of tyGenericBody:
var ak = a
if a.kind == tyGenericBody:
ak = last(a)
result = matchType(c, last(f), ak, m)
of tyCompositeTypeClass:
var ak = if a.kind == tyCompositeTypeClass: a.last else: a
result = matchType(c, last(f), ak, m)
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr,
tyGenericInst:
# ^ XXX Rewrite this logic, it's more complex than it needs to be.
result = false
let ak = a.skipTypes(ignorableForArgType - {f.kind})
if ak.kind == f.kind and f.kidsLen == ak.kidsLen:
for i in 0..<ak.kidsLen:
if not matchType(c, f[i], ak[i], m): return false
return true
if f.kind == tyArray and f.kidsLen == 3:
# XXX: this is a work-around!
# system.nim creates these for the magic array typeclass
result = true
else:
result = false
let ak = a.skipTypes(ignorableForArgType - {f.kind})
if ak.kind == f.kind and f.kidsLen == ak.kidsLen:
result = matchKids(c, f, ak, m)
of tyOr:
let oldLen = m.inferred.len
if a.kind == tyOr:
@@ -221,6 +269,16 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
result = true
of tyOrdinal:
result = isOrdinalType(a, allowEnumWithHoles = false) or a.kind == tyGenericParam
of tyStatic:
result = false
var scomp = f.base
if scomp.kind == tyGenericParam:
if f.base.kidsLen > 0:
scomp = scomp.base
if a.kind == tyStatic:
result = matchType(c, scomp, a.base, m)
else:
result = matchType(c, scomp, a, m)
else:
result = false
@@ -271,7 +329,8 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
proc matchSyms(c: PContext, n: PNode; kinds: set[TSymKind]; m: var MatchCon): bool =
## Walk the current scope, extract candidates which the same name as 'n[namePos]',
## 'n' is the nkProcDef or similar from the concept that we try to match.
let candidates = searchInScopesAllCandidatesFilterBy(c, n[namePos].sym.name, kinds)
var candidates = searchScopes(c, n[namePos].sym.name, kinds)
searchImportsAll(c, n[namePos].sym.name, kinds, candidates)
for candidate in candidates:
#echo "considering ", typeToString(candidate.typ), " ", candidate.magic
m.magic = candidate.magic
@@ -309,7 +368,7 @@ proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
# error was reported earlier.
result = false
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var TypeMapping; invocation: PType): bool =
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var LayeredIdTable; invocation: PType): bool =
## Entry point from sigmatch. 'concpt' is the concept we try to match (here still a PType but
## we extract its AST via 'concpt.n.lastSon'). 'arg' is the type that might fulfill the
## concept's requirements. If so, we return true and fill the 'bindings' with pairs of
@@ -318,7 +377,9 @@ proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var TypeMapping; i
## `C[S, T]` parent type that we look for. We need this because we need to store bindings
## for 'S' and 'T' inside 'bindings' on a successful match. It is very important that
## we do not add any bindings at all on an unsuccessful match!
var m = MatchCon(inferred: @[], potentialImplementation: arg)
if arg.containsUnresolvedType:
return false
var m = MatchCon(inferred: @[], potentialImplementation: arg, concpt: concpt)
result = conceptMatchNode(c, concpt.n.lastSon, m)
if result:
for (a, b) in m.inferred:
@@ -328,16 +389,16 @@ proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var TypeMapping; i
dest = existingBinding(m, dest)
if dest == nil or dest.kind != tyGenericParam: break
if dest != nil:
bindings.idTablePut(a, dest)
bindings.put(a, dest)
when logBindings: echo "A bind ", a, " ", dest
else:
bindings.idTablePut(a, b)
bindings.put(a, b)
when logBindings: echo "B bind ", a, " ", b
# we have a match, so bind 'arg' itself to 'concpt':
bindings.idTablePut(concpt, arg)
bindings.put(concpt, arg)
# invocation != nil means we have a non-atomic concept:
if invocation != nil and arg.kind == tyGenericInst and invocation.kidsLen == arg.kidsLen-1:
# bind even more generic parameters
assert invocation.kind == tyGenericInvocation
for i in FirstGenericParamAt ..< invocation.kidsLen:
bindings.idTablePut(invocation[i], arg[i])
bindings.put(invocation[i], arg[i])

View File

@@ -169,3 +169,5 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasGenericsOpenSym2")
defineSymbol("nimHasGenericsOpenSym3")
defineSymbol("nimHasJsNoLambdaLifting")
defineSymbol("nimHasDefaultFloatRoundtrip")
defineSymbol("nimHasXorSet")

View File

@@ -115,7 +115,7 @@ proc add(dest: var ItemPre, str: string) = dest.add ItemFragment(isRst: false, s
proc addRstFileIndex(d: PDoc, fileIndex: lineinfos.FileIndex): rstast.FileIndex =
let invalid = rstast.FileIndex(-1)
result = d.nimToRstFid.getOrDefault(fileIndex, default = invalid)
result = d.nimToRstFid.getOrDefault(fileIndex, invalid)
if result == invalid:
let fname = toFullPath(d.conf, fileIndex)
result = addFilename(d.sharedState, fname)
@@ -830,7 +830,7 @@ proc getName(n: PNode): string =
of nkAccQuoted:
result = "`"
for i in 0..<n.len: result.add(getName(n[i]))
result = "`"
result.add('`')
of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
result = getName(n[0])
else:
@@ -1320,7 +1320,7 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id
if t.startsWith("ref "): t = substr(t, 4)
effects[i] = newIdentNode(getIdent(cache, t), n.info)
# set the type so that the following analysis doesn't screw up:
effects[i].typ = real[i].typ
effects[i].typ() = real[i].typ
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, $effectType), n.info), effects)

View File

@@ -275,7 +275,7 @@ proc unpackObject(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
# the nkPar node:
if n.isNil:
result = newNode(nkTupleConstr)
result.typ = typ
result.typ() = typ
if typ.n.isNil:
internalError(conf, "cannot unpack unnamed tuple")
unpackObjectAdd(conf, x, typ.n, result)
@@ -298,7 +298,7 @@ proc unpackObject(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
proc unpackArray(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
if n.isNil:
result = newNode(nkBracket)
result.typ = typ
result.typ() = typ
newSeq(result.sons, lengthOrd(conf, typ).toInt)
else:
result = n
@@ -319,7 +319,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
template aw(k, v, field: untyped): untyped =
if n.isNil:
result = newNode(k)
result.typ = typ
result.typ() = typ
else:
# check we have the right field:
result = n
@@ -333,12 +333,12 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode =
template setNil() =
if n.isNil:
result = newNode(nkNilLit)
result.typ = typ
result.typ() = typ
else:
reset n[]
result = n
result[] = TNode(kind: nkNilLit)
result.typ = typ
result.typ() = typ
template awi(kind, v: untyped): untyped = aw(kind, v, intVal)
template awf(kind, v: untyped): untyped = aw(kind, v, floatVal)
@@ -427,7 +427,7 @@ proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode =
# cast through a pointer needs a new inner object:
let y = if x.kind == nkRefTy: newNodeI(nkRefTy, x.info, 1)
else: x.copyTree
y.typ = x.typ
y.typ() = x.typ
result = unpack(conf, a, destTyp, y)
dealloc a
@@ -481,7 +481,7 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
if aTyp.isNil:
internalAssert conf, i+1 < fntyp.len
aTyp = fntyp[i+1]
args[i+start].typ = aTyp
args[i+start].typ() = aTyp
sig[i] = mapType(conf, aTyp)
if sig[i].isNil: globalError(conf, info, "cannot map FFI type")

View File

@@ -64,7 +64,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
if x == nil:
x = copySym(s, c.idgen)
# sem'check needs to set the owner properly later, see bug #9476
x.owner = nil # c.genSymOwner
setOwner(x, nil) # c.genSymOwner
#if x.kind == skParam and x.owner.kind == skModule:
# internalAssert c.config, false
idTablePut(c.mapping, s, x)
@@ -182,7 +182,7 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
d.add newSymNode(sym, info)
result.add d
result.add res
result.typ = res.typ
result.typ() = res.typ
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
conf: ConfigRef;

View File

@@ -63,7 +63,7 @@ type
# Configuration settings for various compilers.
# When adding new compilers, the cmake sources could be a good reference:
# http://cmake.org/gitweb?p=cmake.git;a=tree;f=Modules/Platform;
# https://cmake.org/gitweb?p=cmake.git;a=tree;f=Modules/Platform;
template compiler(name, settings: untyped): untyped =
proc name: TInfoCC {.compileTime.} = settings
@@ -162,7 +162,11 @@ compiler vcc:
linkerExe: "cl",
linkTmpl: "$builddll$vccplatform /Fe$exefile $objfiles $buildgui /nologo $options",
includeCmd: " /I",
linkDirCmd: " /LIBPATH:",
# HACK: we call `cl` so we have to pass `/link` for linker options,
# but users may still want to pass arguments to `cl` (see #14221)
# to deal with this, we add `/link` before each `/LIBPATH`,
# the linker ignores extra `/link`s since it's an unrecognized argument
linkDirCmd: " /link /LIBPATH:",
linkLibCmd: " $1.lib",
debug: " /RTC1 /Z7 ",
pic: "",
@@ -777,7 +781,7 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
# https://blog.molecular-matters.com/2017/05/09/deleting-pdb-files-locked-by-visual-studio/
# and a bit about the .pdb format in case that is ever needed:
# https://github.com/crosire/blink
# http://www.debuginfo.com/articles/debuginfomatch.html#pdbfiles
# https://www.debuginfo.com/articles/debuginfomatch.html#pdbfiles
if conf.hcrOn and isVSCompatible(conf):
let t = now()
let pdb = output.string & "." & format(t, "MMMM-yyyy-HH-mm-") & $t.nanosecond & ".pdb"

View File

@@ -1104,7 +1104,7 @@ proc settype(n: PNode): PType =
proc buildOf(it, loc: PNode; o: Operators): PNode =
var s = newNodeI(nkCurly, it.info, it.len-1)
s.typ = settype(loc)
s.typ() = settype(loc)
for i in 0..<it.len-1: s[i] = it[i]
result = newNodeI(nkCall, it.info, 3)
result[0] = newSymNode(o.opContains)
@@ -1165,8 +1165,12 @@ proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode =
if check[1].kind == nkCurly:
result = copyTree(check)
if access.kind == nkDotExpr:
# change the access to the discriminator field access
var a = copyTree(access)
# set field name to discriminator field name
a[1] = check[2]
# set discriminator field type: important for `neg`
a.typ() = check[2].typ
result[2] = a
# 'access.kind != nkDotExpr' can happen for object constructors
# which we don't check yet

View File

@@ -838,7 +838,7 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
of nkSym:
result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree[n].soperand))
if result.typ == nil:
result.typ = result.sym.typ
result.typ() = result.sym.typ
of externIntLit:
result.intVal = g[thisModule].fromDisk.numbers[n.litId]
of nkStrLit..nkTripleStrLit:
@@ -852,7 +852,7 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
transitionNoneToSym(result)
result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree[n2].soperand))
if result.typ == nil:
result.typ = result.sym.typ
result.typ() = result.sym.typ
else:
for n0 in sonsReadonly(tree, n):
result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
@@ -942,7 +942,7 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
result.guard = loadSym(c, g, si, s.guard)
result.bitsize = s.bitsize
result.alignment = s.alignment
result.owner = loadSym(c, g, si, s.owner)
setOwner(result, loadSym(c, g, si, s.owner))
let externalName = g[si].fromDisk.strings[s.externalName]
if externalName != "":
result.loc.snippet = externalName
@@ -998,7 +998,7 @@ proc typeHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
t: PackedType; si, item: int32; result: PType) =
result.sym = loadSym(c, g, si, t.sym)
result.owner = loadSym(c, g, si, t.owner)
setOwner(result, loadSym(c, g, si, t.owner))
when false:
for op, item in pairs t.attachedOps:
result.attachedOps[op] = loadSym(c, g, si, item)
@@ -1062,7 +1062,7 @@ proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCa
name: getIdent(cache, splitFile(filename).name),
info: newLineInfo(fileIdx, 1, 1),
position: int(fileIdx))
m.module.owner = getPackage(conf, cache, fileIdx)
setOwner(m.module, getPackage(conf, cache, fileIdx))
m.module.flags = m.fromDisk.moduleFlags
proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;

View File

@@ -231,7 +231,7 @@ 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 importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym =
proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden, trackUnusedImport: bool): PSym =
result = realModule
template createModuleAliasImpl(ident): untyped =
createModuleAlias(realModule, c.idgen, ident, n.info, c.config.options)
@@ -246,8 +246,10 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool)
result = createModuleAliasImpl(realModule.name)
if importHidden:
result.options.incl optImportHidden
let moduleIdent = if n.kind == nkInfix: n[^1] else: n
c.unusedImports.add((result, moduleIdent.info))
let moduleIdent = if n.kind in {nkInfix, nkImportAs}: n[^1] else: n
result.info = moduleIdent.info
if trackUnusedImport:
c.unusedImports.add((result, result.info))
c.importModuleMap[result.id] = realModule.id
c.importModuleLookup.mgetOrPut(result.name.id, @[]).addUnique realModule.id
@@ -288,10 +290,11 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
toFullPath(c.config, c.graph.importStack[i+1])
c.recursiveDep = err
let trackUnusedImport = warnUnusedImportX in c.config.notes
var realModule: PSym
discard pushOptionEntry(c)
realModule = c.graph.importModuleCallback(c.graph, c.module, f)
result = importModuleAs(c, n, realModule, transf.importHidden)
result = importModuleAs(c, n, realModule, transf.importHidden, trackUnusedImport)
popOptionEntry(c)
#echo "set back to ", L
@@ -335,7 +338,7 @@ proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
let m = myImportModule(c, it, importStmtResult)
if m != nil:
# ``addDecl`` needs to be done before ``importAllSymbols``!
addDecl(c, m, it.info) # add symbol to symbol table of module
addDecl(c, m) # add symbol to symbol table of module
importAllSymbols(c, m)
#importForwarded(c, m.ast, emptySet, m)
afterImport(c, m)
@@ -372,7 +375,7 @@ proc evalFrom*(c: PContext, n: PNode): PNode =
var m = myImportModule(c, n[0], result)
if m != nil:
n[0] = newSymNode(m)
addDecl(c, m, n.info) # add symbol to symbol table of module
addDecl(c, m) # add symbol to symbol table of module
var im = ImportedModule(m: m, mode: importSet, imported: initIntSet())
for i in 1..<n.len:
@@ -387,7 +390,7 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
var m = myImportModule(c, n[0], result)
if m != nil:
n[0] = newSymNode(m)
addDecl(c, m, n.info) # add symbol to symbol table of module
addDecl(c, m) # add symbol to symbol table of module
importAllSymbolsExcept(c, m, readExceptSet(c, n))
#importForwarded(c, m.ast, exceptSet, m)
afterImport(c, m)

View File

@@ -332,7 +332,7 @@ proc genMarkCyclic(c: var Con; result, dest: PNode) =
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest)
else:
let xenv = genBuiltin(c.graph, c.idgen, mAccessEnv, "accessEnv", dest)
xenv.typ = getSysType(c.graph, dest.info, tyPointer)
xenv.typ() = getSysType(c.graph, dest.info, tyPointer)
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, xenv)
proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode =
@@ -408,7 +408,7 @@ proc genWasMoved(c: var Con, n: PNode): PNode =
proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
result = newNodeI(nkCall, info)
result.add(newSymNode(createMagic(c.graph, c.idgen, "default", mDefault)))
result.typ = t
result.typ() = t
proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
# generate: (let tmp = v; reset(v); tmp)
@@ -802,15 +802,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
result = passCopyToSink(n, c, s)
elif n.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure, nkNilLit} +
nkCallKinds + nkLiterals:
if n.kind in nkCallKinds and n[0].kind == nkSym:
if n[0].sym.magic == mEnsureMove:
inc c.inEnsureMove
result = p(n[1], c, s, sinkArg)
dec c.inEnsureMove
else:
result = p(n, c, s, consumed)
else:
result = p(n, c, s, consumed)
result = p(n, c, s, consumed)
elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and
isLastRead(n, c, s) and not (n.kind == nkSym and isCursor(n)):
# Sinked params can be consumed only once. We need to reset the memory
@@ -822,9 +814,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
n[1].typ.skipTypes(abstractInst-{tyOwned}).kind == tyOwned:
# allow conversions from owned to unowned via this little hack:
let nTyp = n[1].typ
n[1].typ = n.typ
n[1].typ() = n.typ
result[1] = p(n[1], c, s, sinkArg)
result[1].typ = nTyp
result[1].typ() = nTyp
else:
result[1] = p(n[1], c, s, sinkArg)
elif n.kind in {nkObjDownConv, nkObjUpConv}:
@@ -886,12 +878,6 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if mode == normal and (isRefConstr or hasCustomDestructor(c, t)):
result = ensureDestruction(result, n, c, s)
of nkCallKinds:
if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
inc c.inEnsureMove
result = p(n[1], c, s, sinkArg)
dec c.inEnsureMove
return
let inSpawn = c.inSpawn
if n[0].kind == nkSym and n[0].sym.magic == mSpawn:
c.inSpawn.inc
@@ -909,13 +895,19 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
isDangerous = true
result = shallowCopy(n)
for i in 1..<n.len:
if i < L and isCompileTimeOnly(parameters[i]):
result[i] = n[i]
elif i < L and (isSinkTypeForParam(parameters[i]) or inSpawn > 0):
result[i] = p(n[i], c, s, sinkArg)
else:
result[i] = p(n[i], c, s, normal)
if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
inc c.inEnsureMove
result[1] = p(n[1], c, s, sinkArg)
dec c.inEnsureMove
else:
for i in 1..<n.len:
if i < L and isCompileTimeOnly(parameters[i]):
result[i] = n[i]
elif i < L and (isSinkTypeForParam(parameters[i]) or inSpawn > 0):
result[i] = p(n[i], c, s, sinkArg)
else:
result[i] = p(n[i], c, s, normal)
when false:
if isDangerous:
@@ -1022,9 +1014,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
n[1].typ.skipTypes(abstractInst-{tyOwned}).kind == tyOwned:
# allow conversions from owned to unowned via this little hack:
let nTyp = n[1].typ
n[1].typ = n.typ
n[1].typ() = n.typ
result[1] = p(n[1], c, s, mode)
result[1].typ = nTyp
result[1].typ() = nTyp
else:
result[1] = p(n[1], c, s, mode)

View File

@@ -166,7 +166,7 @@ proc containsVariable(n: PNode): bool =
proc checkIsolate*(n: PNode): bool =
if types.containsTyRef(n.typ):
# XXX Maybe require that 'n.typ' is acyclic. This is not much
# worse than the already exisiting inheritance and closure restrictions.
# worse than the already existing inheritance and closure restrictions.
case n.kind
of nkCharLit..nkNilLit:
result = true

View File

@@ -1585,15 +1585,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
of nkObjDownConv:
gen(p, n[0], r)
of nkHiddenDeref:
of nkHiddenDeref, nkDerefExpr:
gen(p, n[0], r)
of nkDerefExpr:
var x = n[0]
if n.kind == nkHiddenAddr:
x = n[0][0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
x.typ = n.typ
gen(p, x, r)
of nkHiddenAddr:
gen(p, n[0], r)
of nkConv:
@@ -2458,6 +2451,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mMulSet: binaryExpr(p, n, r, "SetMul", "SetMul($1, $2)")
of mPlusSet: binaryExpr(p, n, r, "SetPlus", "SetPlus($1, $2)")
of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)")
of mXorSet: binaryExpr(p, n, r, "SetXor", "SetXor($1, $2)")
of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]")
of mInSet:

View File

@@ -150,7 +150,7 @@ template isIterator*(owner: PSym): bool =
proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType =
result = createObj(g, idgen, owner, info, final=false)
if owner.isIterator or not isDefined(g.config, "nimOptIters"):
if owner.isIterator:
rawAddField(result, createStateField(g, owner, idgen))
proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym =
@@ -175,6 +175,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
#echo "produced environment: ", param.id, " for ", routine.id
proc getEnvParam*(routine: PSym): PSym =
if routine.ast.isNil: return nil
let params = routine.ast[paramsPos]
let hidden = lastSon(params)
if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName:
@@ -228,13 +229,6 @@ proc makeClosure*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; env: PNode; inf
if tfHasAsgn in result.typ.flags or optSeqDestructors in g.config.globalOptions:
prc.flags.incl sfInjectDestructors
proc interestingIterVar(s: PSym): bool {.inline.} =
# unused with -d:nimOptIters
# XXX optimization: Only lift the variable if it lives across
# yield/return boundaries! This can potentially speed up
# closure iterators quite a bit.
result = s.kind in {skResult, skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
template liftingHarmful(conf: ConfigRef; owner: PSym): bool =
## lambda lifting can be harmful for JS-like code generators.
let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
@@ -281,16 +275,6 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
createTypeBoundOpsLL(g, env.typ, n.info, idgen, owner)
result.add makeClosure(g, idgen, iter, env, n.info)
proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner: PSym): PNode =
# unused with -d:nimOptIters
let envParam = getHiddenParam(g, owner)
let obj = envParam.typ.skipTypes({tyOwned, tyRef, tyPtr})
let field = addField(obj, s, g.cache, idgen)
var access = newSymNode(envParam)
assert obj.kind == tyObject
result = rawIndirectAccess(access, field, s.info)
# ------------------ new stuff -------------------------------------------
proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
@@ -300,8 +284,8 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
localError(g.config, n.info,
("'$1' is of type <$2> which cannot be captured as it would violate memory" &
" safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases." &
" Consider using a <ref $2> which can be captured.") %
[s.name.s, typeToString(s.typ), g.config$s.info])
" Consider using a <ref T> which can be captured.") %
[s.name.s, typeToString(s.typ.skipTypes({tyVar})), g.config$s.info])
elif not (owner.typ.isClosure or owner.isNimcall and not owner.isExplicitCallConv or isEnv):
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
[s.name.s, owner.name.s, $owner.typ.callConv])
@@ -339,7 +323,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
result = c.ownerToType.getOrDefault(owner.id)
if result.isNil:
let env = getEnvParam(owner)
if env.isNil or not owner.isIterator or not isDefined(c.graph.config, "nimOptIters"):
if env.isNil or not owner.isIterator:
result = newType(tyRef, c.idgen, owner)
let obj = createEnvObj(c.graph, c.idgen, owner, info)
rawAddSon(result, obj)
@@ -436,6 +420,12 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
localError(c.graph.config, fn.info, "internal error: inconsistent environment type")
#echo "adding closure to ", fn.name.s
proc iterEnvHasUpField(g: ModuleGraph, iter: PSym): bool =
let cp = getEnvParam(iter)
doAssert(cp != nil, "Env param not present in iter")
let upField = lookupInRecord(cp.typ.skipTypes({tyOwned, tyRef, tyPtr}).n, getIdent(g.cache, upName))
upField != nil
proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
case n.kind
of nkSym:
@@ -454,23 +444,12 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
let body = transformBody(c.graph, c.idgen, s, {useCache})
detectCapturedVars(body, s, c)
let ow = s.skipGenericOwner
let innerClosure = innerProc and s.typ.callConv == ccClosure and not s.isIterator
let innerClosure = innerProc and s.typ.callConv == ccClosure and (not s.isIterator or iterEnvHasUpField(c.graph, s))
let interested = interestingVar(s)
if ow == owner:
if owner.isIterator:
c.somethingToDo = true
addClosureParam(c, owner, n.info)
if not isDefined(c.graph.config, "nimOptIters") and interestingIterVar(s):
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})
if s.name.id == getIdent(c.graph.cache, ":state").id:
obj.n[0].sym.flags.incl sfNoInit
obj.n[0].sym.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
else:
discard addField(obj, s, c.graph.cache, c.idgen)
# direct or indirect dependency:
elif innerClosure or interested:
discard """
@@ -630,7 +609,7 @@ proc rawClosureCreation(owner: PSym;
let unowned = c.unownedEnvVars[owner.id]
assert unowned != nil
let env2 = copyTree(env)
env2.typ = unowned.typ
env2.typ() = unowned.typ
result.add newAsgnStmt(unowned, env2, env.info)
createTypeBoundOpsLL(d.graph, unowned.typ, env.info, d.idgen, owner)
@@ -670,16 +649,27 @@ proc finishClosureCreation(owner: PSym; d: var DetectionPass; c: LiftingPass;
res.add newAsgnStmt(unowned, nilLit, info)
createTypeBoundOpsLL(d.graph, unowned.typ, info, d.idgen, owner)
proc closureCreationForIter(iter: PNode;
proc getUpForIter(g: ModuleGraph; owner, iterOwner: PSym, expectedUpTyp: PType): PNode =
var p = getHiddenParam(g, owner)
var res = p.newSymNode
while res.typ.skipTypes({tyOwned, tyRef, tyPtr}) != expectedUpTyp:
let upField = lookupInRecord(p.typ.skipTypes({tyOwned, tyRef, tyPtr}).n, getIdent(g.cache, upName))
if upField == nil:
return nil
p = upField
res = rawIndirectAccess(res, upField, p.info)
res
proc closureCreationForIter(owner: PSym, iter: PNode;
d: var DetectionPass; c: var LiftingPass): PNode =
result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ)
let owner = iter.sym.skipGenericOwner
var v = newSym(skVar, getIdent(d.graph.cache, envName), d.idgen, owner, iter.info)
let iterOwner = iter.sym.skipGenericOwner
var v = newSym(skVar, getIdent(d.graph.cache, envName), d.idgen, iterOwner, iter.info)
incl(v.flags, sfShadowed)
v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ)
var vnode: PNode
if owner.isIterator:
let it = getHiddenParam(d.graph, owner)
if iterOwner.isIterator:
let it = getHiddenParam(d.graph, iterOwner)
addUniqueField(it.typ.skipTypes({tyOwned, tyRef, tyPtr}), v, d.graph.cache, d.idgen)
vnode = indirectAccess(newSymNode(it), v, v.info)
else:
@@ -688,12 +678,14 @@ proc closureCreationForIter(iter: PNode;
addVar(vs, vnode)
result.add(vs)
result.add genCreateEnv(vnode)
createTypeBoundOpsLL(d.graph, vnode.typ, iter.info, d.idgen, owner)
createTypeBoundOpsLL(d.graph, vnode.typ, iter.info, d.idgen, iterOwner)
let upField = lookupInRecord(v.typ.skipTypes({tyOwned, tyRef, tyPtr}).n, getIdent(d.graph.cache, upName))
if upField != nil:
let u = setupEnvVar(owner, d, c, iter.info)
if u.typ.skipTypes({tyOwned, tyRef, tyPtr}) == upField.typ.skipTypes({tyOwned, tyRef, tyPtr}):
let expectedUpTyp = upField.typ.skipTypes({tyOwned, tyRef, tyPtr})
let u = if iterOwner == owner: setupEnvVar(iterOwner, d, c, iter.info)
else: getUpForIter(d.graph, owner, iterOwner, expectedUpTyp)
if u != nil and u.typ.skipTypes({tyOwned, tyRef, tyPtr}) == expectedUpTyp:
result.add(newAsgnStmt(rawIndirectAccess(vnode, upField, iter.info),
u, iter.info))
else:
@@ -727,7 +719,7 @@ proc symToClosure(n: PNode; owner: PSym; d: var DetectionPass;
let available = getHiddenParam(d.graph, owner)
result = makeClosure(d.graph, d.idgen, s, available.newSymNode, n.info)
elif s.isIterator:
result = closureCreationForIter(n, d, c)
result = closureCreationForIter(owner, n, d, c)
elif s.skipGenericOwner == owner:
# direct dependency, so use the outer's env variable:
result = makeClosure(d.graph, d.idgen, s, setupEnvVar(owner, d, c, n.info), n.info)
@@ -774,8 +766,6 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
elif s.id in d.capturedVars:
if s.owner != owner:
result = accessViaEnvParam(d.graph, n, owner)
elif owner.isIterator and not isDefined(d.graph.config, "nimOptIters") and interestingIterVar(s):
result = accessViaEnvParam(d.graph, n, owner)
else:
result = accessViaEnvVar(n, owner, d, c)
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
@@ -796,7 +786,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
let oldInContainer = c.inContainer
c.inContainer = 0
let m = newSymNode(n[namePos].sym)
m.typ = n.typ
m.typ() = n.typ
result = liftCapturedVars(m, owner, d, c)
c.inContainer = oldInContainer
of nkHiddenStdConv:
@@ -893,7 +883,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
# ignore forward declaration:
result = body
tooEarly = true
if fn.isIterator and isDefined(g.config, "nimOptIters"):
if fn.isIterator:
var d = initDetectionPass(g, fn, idgen)
addClosureParam(d, fn, body.info)
else:

82
compiler/layeredtable.nim Normal file
View File

@@ -0,0 +1,82 @@
import std/tables
import ast
type
LayeredIdTableObj* {.acyclic.} = object
## stack of type binding contexts implemented as a linked list
topLayer*: TypeMapping
## the mappings on the current layer
nextLayer*: ref LayeredIdTableObj
## the parent type binding context, possibly `nil`
previousLen*: int
## total length of the bindings up to the parent layer,
## used to track if new bindings were added
const useRef = not defined(gcDestructors)
# implementation detail, only arc/orc doesn't cause issues when
# using LayeredIdTable as an object and not a ref
when useRef:
type LayeredIdTable* = ref LayeredIdTableObj
else:
type LayeredIdTable* = LayeredIdTableObj
proc initLayeredTypeMap*(pt: sink TypeMapping = initTypeMapping()): LayeredIdTable =
result = LayeredIdTable(topLayer: pt, nextLayer: nil)
proc shallowCopy*(pt: LayeredIdTable): LayeredIdTable {.inline.} =
## copies only the type bindings of the current layer, but not any parent layers,
## useful for write-only bindings
result = LayeredIdTable(topLayer: pt.topLayer, nextLayer: pt.nextLayer, previousLen: pt.previousLen)
proc currentLen*(pt: LayeredIdTable): int =
## the sum of the cached total binding count of the parents and
## the current binding count, just used to track if bindings were added
pt.previousLen + pt.topLayer.len
proc newTypeMapLayer*(pt: LayeredIdTable): LayeredIdTable =
result = LayeredIdTable(topLayer: initTable[ItemId, PType](), previousLen: pt.currentLen)
when useRef:
result.nextLayer = pt
else:
new(result.nextLayer)
result.nextLayer[] = pt
proc setToPreviousLayer*(pt: var LayeredIdTable) {.inline.} =
when useRef:
pt = pt.nextLayer
else:
when defined(gcDestructors):
pt = pt.nextLayer[]
else:
# workaround refc
let tmp = pt.nextLayer[]
pt = tmp
proc lookup(typeMap: ref LayeredIdTableObj, key: ItemId): PType =
result = nil
var tm = typeMap
while tm != nil:
result = getOrDefault(tm.topLayer, key)
if result != nil: return
tm = tm.nextLayer
template lookup*(typeMap: ref LayeredIdTableObj, key: PType): PType =
## recursively looks up binding of `key` in all parent layers
lookup(typeMap, key.itemId)
when not useRef:
proc lookup(typeMap: LayeredIdTableObj, key: ItemId): PType {.inline.} =
result = getOrDefault(typeMap.topLayer, key)
if result == nil and typeMap.nextLayer != nil:
result = lookup(typeMap.nextLayer, key)
template lookup*(typeMap: LayeredIdTableObj, key: PType): PType =
lookup(typeMap, key.itemId)
proc put(typeMap: var LayeredIdTable, key: ItemId, value: PType) {.inline.} =
typeMap.topLayer[key] = value
template put*(typeMap: var LayeredIdTable, key, value: PType) =
## binds `key` to `value` only in current layer
put(typeMap, key.itemId, value)

View File

@@ -49,7 +49,7 @@ proc at(a, i: PNode, elemType: PType): PNode =
result = newNodeI(nkBracketExpr, a.info, 2)
result[0] = a
result[1] = i
result.typ = elemType
result.typ() = elemType
proc destructorOverridden(g: ModuleGraph; t: PType): bool =
let op = getAttachedOp(g, t, attachedDestructor)
@@ -68,7 +68,7 @@ proc dotField(x: PNode, f: PSym): PNode =
else:
result[0] = x
result[1] = newSymNode(f, x.info)
result.typ = f.typ
result.typ() = f.typ
proc newAsgnStmt(le, ri: PNode): PNode =
result = newNodeI(nkAsgn, le.info, 2)
@@ -88,7 +88,7 @@ proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newAsgnStmt(x, y)
elif c.kind == attachedDestructor and c.addMemReset:
let call = genBuiltin(c, mDefault, "default", x)
call.typ = t
call.typ() = t
body.add newAsgnStmt(x, call)
elif c.kind == attachedWasMoved:
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
@@ -105,7 +105,7 @@ proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
result = newNodeI(nkWhileStmt, c.info, 2)
let cmp = genBuiltin(c, mLtI, "<", i)
cmp.add genLen(c.g, dest)
cmp.typ = getSysType(c.g, c.info, tyBool)
cmp.typ() = getSysType(c.g, c.info, tyBool)
result[0] = cmp
result[1] = newNodeI(nkStmtList, c.info)
@@ -127,10 +127,10 @@ proc genContainerOf(c: var TLiftCtx; objType: PType, field, x: PSym): PNode =
dotExpr.add newSymNode(field)
let offsetOf = genBuiltin(c, mOffsetOf, "offsetof", dotExpr)
offsetOf.typ = intType
offsetOf.typ() = intType
let minusExpr = genBuiltin(c, mSubI, "-", castExpr1)
minusExpr.typ = intType
minusExpr.typ() = intType
minusExpr.add offsetOf
let objPtr = makePtrType(objType.owner, objType, c.idgen)
@@ -265,7 +265,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
# because the wasMoved(dest) call would zero out src, if dest aliases src.
var cond = newTree(nkCall, newSymNode(c.g.getSysMagic(c.info, "==", mEqRef)),
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x), newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y))
cond.typ = getSysType(c.g, x.info, tyBool)
cond.typ() = getSysType(c.g, x.info, tyBool)
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
temp.typ = x.typ
@@ -296,7 +296,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
result = newIntLit(g, info, ord value)
result.typ = getSysType(g, info, tyBool)
result.typ() = getSysType(g, info, tyBool)
proc getCycleParam(c: TLiftCtx): PNode =
assert c.kind in {attachedAsgn, attachedDup}
@@ -545,18 +545,18 @@ proc newSeqCall(c: var TLiftCtx; x, y: PNode): PNode =
# don't call genAddr(c, x) here:
result = genBuiltin(c, mNewSeq, "newSeq", x)
let lenCall = genBuiltin(c, mLengthSeq, "len", y)
lenCall.typ = getSysType(c.g, x.info, tyInt)
lenCall.typ() = getSysType(c.g, x.info, tyInt)
result.add lenCall
proc setLenStrCall(c: var TLiftCtx; x, y: PNode): PNode =
let lenCall = genBuiltin(c, mLengthStr, "len", y)
lenCall.typ = getSysType(c.g, x.info, tyInt)
lenCall.typ() = getSysType(c.g, x.info, tyInt)
result = genBuiltin(c, mSetLengthStr, "setLen", x) # genAddr(g, x))
result.add lenCall
proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
let lenCall = genBuiltin(c, mLengthSeq, "len", y)
lenCall.typ = getSysType(c.g, x.info, tyInt)
lenCall.typ() = getSysType(c.g, x.info, tyInt)
var op = getSysMagic(c.g, x.info, "setLen", mSetLengthSeq)
op = instantiateGeneric(c, op, t, t)
result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
@@ -579,7 +579,7 @@ proc checkSelfAssignment(c: var TLiftCtx; t: PType; body, x, y: PNode) =
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x),
newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y)
)
cond.typ = getSysType(c.g, c.info, tyBool)
cond.typ() = getSysType(c.g, c.info, tyBool)
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
@@ -720,7 +720,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isFinal(elemType):
addDestructorCall(c, elemType, actions, genDeref(tmp, nkDerefExpr))
var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
alignOf.typ = getSysType(c.g, c.info, tyInt)
alignOf.typ() = getSysType(c.g, c.info, tyInt)
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, tmp, alignOf)
else:
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(tmp, nkDerefExpr))
@@ -730,7 +730,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isCyclic:
if isFinal(elemType):
let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
typInfo.typ = getSysType(c.g, c.info, tyPointer)
typInfo.typ() = getSysType(c.g, c.info, tyPointer)
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo)
else:
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp)
@@ -738,7 +738,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
cond = callCodegenProc(c.g, "nimDecRefIsLastDyn", c.info, x)
else:
cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x)
cond.typ = getSysType(c.g, x.info, tyBool)
cond.typ() = getSysType(c.g, x.info, tyBool)
case c.kind
of attachedSink:
@@ -765,7 +765,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isCyclic:
if isFinal(elemType):
let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
typInfo.typ = getSysType(c.g, c.info, tyPointer)
typInfo.typ() = getSysType(c.g, c.info, tyPointer)
body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x, c.idgen), typInfo, y)
else:
# If the ref is polymorphic we have to account for this
@@ -786,7 +786,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
## Closures are really like refs except they always use a virtual destructor
## and we need to do the refcounting only on the ref field which we call 'xenv':
let xenv = genBuiltin(c, mAccessEnv, "accessEnv", x)
xenv.typ = getSysType(c.g, c.info, tyPointer)
xenv.typ() = getSysType(c.g, c.info, tyPointer)
let isCyclic = c.g.config.selectedGC == gcOrc
let tmp =
@@ -802,7 +802,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isCyclic: "nimDecRefIsLastCyclicDyn"
else: "nimDecRefIsLast"
let cond = callCodegenProc(c.g, decRefProc, c.info, tmp)
cond.typ = getSysType(c.g, x.info, tyBool)
cond.typ() = getSysType(c.g, x.info, tyBool)
case c.kind
of attachedSink:
@@ -814,7 +814,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newAsgnStmt(x, y)
of attachedAsgn:
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
yenv.typ = getSysType(c.g, c.info, tyPointer)
yenv.typ() = getSysType(c.g, c.info, tyPointer)
if isCyclic:
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
body.add newAsgnStmt(x, y)
@@ -826,7 +826,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newAsgnStmt(x, y)
of attachedDup:
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
yenv.typ = getSysType(c.g, c.info, tyPointer)
yenv.typ() = getSysType(c.g, c.info, tyPointer)
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
@@ -878,7 +878,7 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isFinal(elemType):
addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr))
var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
alignOf.typ = getSysType(c.g, c.info, tyInt)
alignOf.typ() = getSysType(c.g, c.info, tyInt)
actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x, alignOf)
else:
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr))
@@ -901,14 +901,14 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# a big problem is that we don't know the environment's type here, so we
# have to go through some indirection; we delegate this to the codegen:
let call = newNodeI(nkCall, c.info, 2)
call.typ = t
call.typ() = t
call[0] = newSymNode(createMagic(c.g, c.idgen, "deepCopy", mDeepCopy))
call[1] = y
body.add newAsgnStmt(x, call)
elif (optOwnedRefs in c.g.config.globalOptions and
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.g, c.info, tyPointer)
xx.typ() = getSysType(c.g, c.info, tyPointer)
case c.kind
of attachedSink:
# we 'nil' y out afterwards so we *need* to take over its reference
@@ -917,13 +917,13 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add newAsgnStmt(x, y)
of attachedAsgn:
let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
yy.typ = getSysType(c.g, c.info, tyPointer)
yy.typ() = getSysType(c.g, c.info, tyPointer)
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
body.add newAsgnStmt(x, y)
of attachedDup:
let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
yy.typ = getSysType(c.g, c.info, tyPointer)
yy.typ() = getSysType(c.g, c.info, tyPointer)
body.add newAsgnStmt(x, y)
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
of attachedDestructor:
@@ -938,7 +938,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.g, c.info, tyPointer)
xx.typ() = getSysType(c.g, c.info, tyPointer)
var actions = newNodeI(nkStmtList, c.info)
#discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(xx))
actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xx)
@@ -1152,8 +1152,8 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x)
let yy = genBuiltin(c, mAccessTypeField, "accessTypeField", y)
xx.typ = getSysType(c.g, c.info, tyPointer)
yy.typ = xx.typ
xx.typ() = getSysType(c.g, c.info, tyPointer)
yy.typ() = xx.typ
body.add newAsgnStmt(xx, yy)
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
@@ -1276,6 +1276,10 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
## The later 'injectdestructors' pass depends on it.
if orig == nil or {tfCheckedForDestructor, tfHasMeta} * orig.flags != {}: return
incl orig.flags, tfCheckedForDestructor
# for user defined generic destructors:
let origRoot = genericRoot(orig)
if origRoot != nil:
incl origRoot.flags, tfGenericHasDestructor
let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return

View File

@@ -32,12 +32,12 @@ proc interestingVar(s: PSym): bool {.inline.} =
proc lookupOrAdd(c: var Ctx; s: PSym; info: TLineInfo): PNode =
let field = addUniqueField(c.objType, s, c.cache, c.idgen)
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = c.objType
deref.typ() = c.objType
deref.add(newSymNode(c.partialParam, info))
result = newNodeI(nkDotExpr, info)
result.add(deref)
result.add(newSymNode(field))
result.typ = field.typ
result.typ() = field.typ
proc liftLocals(n: PNode; i: int; c: var Ctx) =
let it = n[i]

View File

@@ -94,6 +94,7 @@ type
warnImplicitDefaultValue = "ImplicitDefaultValue",
warnIgnoredSymbolInjection = "IgnoredSymbolInjection",
warnStdPrefix = "StdPrefix"
warnUnknownNotes = "UnknownNotes"
warnUser = "User",
warnGlobalVarConstructorTemporary = "GlobalVarConstructorTemporary",
# hints
@@ -111,7 +112,6 @@ type
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
hintMsgOrigin = "MsgOrigin", # since 1.3.5
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
hintUnknownHint = "UnknownHint"
const
MsgKindToStr*: array[TMsgKind, string] = [
@@ -200,6 +200,7 @@ const
warnImplicitDefaultValue: "$1",
warnIgnoredSymbolInjection: "$1",
warnStdPrefix: "$1 needs the 'std' prefix",
warnUnknownNotes: "$1",
warnUser: "$1",
warnGlobalVarConstructorTemporary: "global variable '$1' initialization requires a temporary variable",
hintSuccess: "operation successful: $#",
@@ -236,8 +237,7 @@ const
hintUserRaw: "$1",
hintExtendedContext: "$1",
hintMsgOrigin: "$1",
hintDeclaredLoc: "$1",
hintUnknownHint: "unknown hint: $1"
hintDeclaredLoc: "$1"
]
const
@@ -268,6 +268,7 @@ const
NotesVerbosity* = computeNotesVerbosity()
errXMustBeCompileTime* = "'$1' can only be used in compile-time context"
errArgsNeedRunOption* = "arguments can only be given if the '--run' option is selected"
errFloatToString* = "cannot convert '$1' to '$2'"
type
TFileInfo* = object

View File

@@ -12,7 +12,7 @@
import std/strutils
from std/sugar import dup
import options, ast, msgs, idents, lineinfos, wordrecg, astmsgs, semdata, packages
import options, ast, msgs, idents, lineinfos, wordrecg, astmsgs, semdata, packages, modulegraphs
export packages
const
@@ -97,7 +97,7 @@ template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind)
if optStyleCheck in ctx.config.options and # ignore if styleChecks are off
{optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # check only if hint/error is enabled
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
ctx.config.belongsToProjectPackageMaybeNil(getModule(ctx.graph, info.fileIndex)) and # ignore foreign packages
optStyleUsages notin ctx.config.globalOptions and # ignore if requested to only check name usage
sym.kind != skResult and # ignore `result`
sym.kind != skTemp and # ignore temporary variables created by the compiler
@@ -138,7 +138,7 @@ template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) =
## Check symbol uses match their definition's style.
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
ctx.config.belongsToProjectPackageMaybeNil(getModule(ctx.graph, info.fileIndex)) 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
@@ -154,5 +154,5 @@ template checkPragmaUse*(ctx: PContext; info: TLineInfo; w: TSpecialWord; pragma
## 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
ctx.config.belongsToProjectPackageMaybeNil(getModule(ctx.graph, info.fileIndex)): # ignore foreign packages
checkPragmaUseImpl(ctx.config, info, w, pragmaName)

View File

@@ -221,7 +221,14 @@ proc debugScopes*(c: PContext; limit=0, max = int.high) {.deprecated.} =
if i == limit: return
inc i
proc searchInScopesAllCandidatesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
proc searchImportsAll*(c: PContext, s: PIdent, filter: TSymKinds, holding: var seq[PSym]) =
var marked = initIntSet()
for im in c.imports.mitems:
for s in symbols(im, marked, s, c.graph):
if s.kind in filter:
holding.add s
proc searchScopes*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
result = @[]
for scope in allScopes(c.currentScope):
var ti: TIdentIter = default(TIdentIter)
@@ -231,14 +238,12 @@ proc searchInScopesAllCandidatesFilterBy*(c: PContext, s: PIdent, filter: TSymKi
result.add candidate
candidate = nextIdentIter(ti, scope.symbols)
proc searchScopesAll*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
result = searchScopes(c,s,filter)
if result.len == 0:
var marked = initIntSet()
for im in c.imports.mitems:
for s in symbols(im, marked, s, c.graph):
if s.kind in filter:
result.add s
searchImportsAll(c, s, filter, result)
proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
proc selectFromScopesElseAll*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
result = @[]
block outer:
for scope in allScopes(c.currentScope):
@@ -252,11 +257,7 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
candidate = nextIdentIter(ti, scope.symbols)
if result.len == 0:
var marked = initIntSet()
for im in c.imports.mitems:
for s in symbols(im, marked, s, c.graph):
if s.kind in filter:
result.add s
searchImportsAll(c, s, filter, result)
proc cmpScopes*(ctx: PContext, s: PSym): int =
# Do not return a negative number
@@ -644,7 +645,7 @@ const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage}
proc lookUpCandidates*(c: PContext, ident: PIdent, filter: set[TSymKind],
includePureEnum = false): seq[PSym] =
result = searchInScopesFilterBy(c, ident, filter)
result = selectFromScopesElseAll(c, ident, filter)
if skEnumField in filter and (result.len == 0 or includePureEnum):
result.add allPureEnumFields(c, ident)
@@ -725,7 +726,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if n.kind == nkOpenSym:
# maybe the logic in semexprs should be mirrored here instead
# for now it only seems this is called for `pickSym` in `getTypeIdent`
# for now it only seems this is called for `pickSym` in `getTypeIdent`
return initOverloadIter(o, c, n[0])
o.importIdx = -1
o.marked = initIntSet()

View File

@@ -174,12 +174,12 @@ proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
# returns a[].field as a node
assert field.kind == skField
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.skipTypes(abstractInst)[0]
deref.typ() = a.typ.skipTypes(abstractInst)[0]
deref.add a
result = newNodeI(nkDotExpr, info)
result.add deref
result.add newSymNode(field)
result.typ = field.typ
result.typ() = field.typ
proc rawDirectAccess*(obj, field: PSym): PNode =
# returns a.field as a node
@@ -187,7 +187,7 @@ proc rawDirectAccess*(obj, field: PSym): PNode =
result = newNodeI(nkDotExpr, field.info)
result.add newSymNode(obj)
result.add newSymNode(field)
result.typ = field.typ
result.typ() = field.typ
proc lookupInRecord(n: PNode, id: ItemId): PSym =
result = nil
@@ -250,12 +250,12 @@ proc newDotExpr*(obj, b: PSym): PNode =
assert field != nil, b.name.s
result.add newSymNode(obj)
result.add newSymNode(field)
result.typ = field.typ
result.typ() = field.typ
proc indirectAccess*(a: PNode, b: ItemId, info: TLineInfo): PNode =
# returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.skipTypes(abstractInst).elementType
deref.typ() = a.typ.skipTypes(abstractInst).elementType
var t = deref.typ.skipTypes(abstractInst)
var field: PSym
while true:
@@ -273,12 +273,12 @@ proc indirectAccess*(a: PNode, b: ItemId, info: TLineInfo): PNode =
result = newNodeI(nkDotExpr, info)
result.add deref
result.add newSymNode(field)
result.typ = field.typ
result.typ() = field.typ
proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): PNode =
# returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.skipTypes(abstractInst).elementType
deref.typ() = a.typ.skipTypes(abstractInst).elementType
var t = deref.typ.skipTypes(abstractInst)
var field: PSym
let bb = getIdent(cache, b)
@@ -297,7 +297,7 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo; cache: IdentCache): P
result = newNodeI(nkDotExpr, info)
result.add deref
result.add newSymNode(field)
result.typ = field.typ
result.typ() = field.typ
proc getFieldFromObj*(t: PType; v: PSym): PSym =
assert v.kind != skField
@@ -320,7 +320,7 @@ proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
proc genAddrOf*(n: PNode; idgen: IdGenerator; typeKind = tyPtr): PNode =
result = newNodeI(nkAddr, n.info, 1)
result[0] = n
result.typ = newType(typeKind, idgen, n.typ.owner)
result.typ() = newType(typeKind, idgen, n.typ.owner)
result.typ.rawAddSon(n.typ)
proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
@@ -344,18 +344,18 @@ proc callCodegenProc*(g: ModuleGraph; name: string;
if optionalArgs != nil:
for i in 1..<optionalArgs.len-2:
result.add optionalArgs[i]
result.typ = sym.typ.returnType
result.typ() = sym.typ.returnType
proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
result = nkIntLit.newIntNode(value)
result.typ = getSysType(g, info, tyInt)
result.typ() = getSysType(g, info, tyInt)
proc genHigh*(g: ModuleGraph; n: PNode): PNode =
if skipTypes(n.typ, abstractVar).kind == tyArray:
result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar))))
else:
result = newNodeI(nkCall, n.info, 2)
result.typ = getSysType(g, n.info, tyInt)
result.typ() = getSysType(g, n.info, tyInt)
result[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
result[1] = n
@@ -364,7 +364,7 @@ proc genLen*(g: ModuleGraph; n: PNode): PNode =
result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar)) + 1))
else:
result = newNodeI(nkCall, n.info, 2)
result.typ = getSysType(g, n.info, tyInt)
result.typ() = getSysType(g, n.info, tyInt)
result[0] = newSymNode(getSysMagic(g, n.info, "len", mLengthSeq))
result[1] = n

View File

@@ -166,4 +166,4 @@ proc makeAddr*(n: PNode; idgen: IdGenerator): PNode =
result = n
else:
result = newTree(nkHiddenAddr, n)
result.typ = makePtrType(n.typ, idgen)
result.typ() = makePtrType(n.typ, idgen)

View File

@@ -88,6 +88,7 @@ type
suggestMode*: bool # whether we are in nimsuggest mode or not.
invalidTransitiveClosure: bool
interactive*: bool
withinSystem*: bool # in system.nim or a module imported by system.nim
inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the
# first module that included it
importStack*: seq[FileIndex] # The current import stack. Used for detecting recursive

View File

@@ -25,7 +25,7 @@ template getModuleIdent(graph: ModuleGraph, filename: AbsoluteFile): PIdent =
proc partialInitModule*(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: AbsoluteFile) =
let packSym = getPackage(graph, fileIdx)
result.owner = packSym
setOwner(result, packSym)
result.position = int fileIdx
proc newModule*(graph: ModuleGraph; fileIdx: FileIndex): PSym =

View File

@@ -1,52 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2017 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the generation of ``.ndi`` files for better debugging
## support of Nim code. "ndi" stands for "Nim debug info".
import ast, msgs, ropes, options, pathutils
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
type
NdiFile* = object
enabled: bool
f: File
buf: string
filename: AbsoluteFile
syms: seq[PSym]
proc doWrite(f: var NdiFile; s: PSym; conf: ConfigRef) =
f.buf.setLen 0
f.buf.addInt s.info.line.int
f.buf.add "\t"
f.buf.addInt s.info.col.int
f.f.write(s.name.s, "\t")
f.f.writeRope(s.loc.snippet)
f.f.writeLine("\t", toFullPath(conf, s.info), "\t", f.buf)
template writeMangledName*(f: NdiFile; s: PSym; conf: ConfigRef) =
if f.enabled: f.syms.add s
proc open*(f: var NdiFile; filename: AbsoluteFile; conf: ConfigRef) =
f.enabled = not filename.isEmpty
if f.enabled:
f.filename = filename
f.buf = newStringOfCap(20)
proc close*(f: var NdiFile, conf: ConfigRef) =
if f.enabled:
f.f = open(f.filename.string, fmWrite, 8000)
doAssert f.f != nil, f.filename.string
for s in f.syms:
doWrite(f, s, conf)
close(f.f)
f.syms.reset
f.filename.reset

View File

@@ -919,7 +919,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
newSymNode(op, r.info),
l,
r)
result.typ = newType(tyBool, ctx.idgen, nil)
result.typ() = newType(tyBool, ctx.idgen, nil)
proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
var cache = newIdentCache()
@@ -929,7 +929,7 @@ proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
result = nkPrefix.newTree(
newSymNode(op, node.info),
node)
result.typ = newType(tyBool, ctx.idgen, nil)
result.typ() = newType(tyBool, ctx.idgen, nil)
proc infixEq(ctx: NilCheckerContext, l: PNode, r: PNode): PNode =
infix(ctx, l, r, mEqRef)

View File

@@ -4,12 +4,13 @@ hint[XDeclaredButNotUsed]:off
define:booting
define:nimcore
define:nimPreviewFloatRoundtrip
define:nimPreviewSlimSystem
define:nimPreviewCstringConversion
define:nimPreviewProcConversion
define:nimPreviewRangeDefault
define:nimPreviewNonVarDestructor
define:nimPreviewCheckedClose
define:nimPreviewAsmSemSymbol
threads:off
#import:"$projectpath/testability"

View File

@@ -84,7 +84,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
elemType = settype[0]
first = firstOrd(conf, elemType).toInt64
result = newNodeI(nkCurly, info)
result.typ = settype
result.typ() = settype
result.info = info
e = 0
while e < s.len * ElemSize:
@@ -101,7 +101,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
result.add aa
else:
n = newNodeI(nkRange, info)
n.typ = elemType
n.typ() = elemType
n.add aa
let bb = newIntTypeNode(b + first, elemType)
bb.info = info

View File

@@ -25,7 +25,7 @@ const
useEffectSystem* = true
useWriteTracking* = false
hasFFI* = defined(nimHasLibFFI)
copyrightYear* = "2024"
copyrightYear* = "2025"
nimEnableCovariance* = defined(nimEnableCovariance)
@@ -229,6 +229,7 @@ type
# alternative to above:
genericsOpenSym
vtables
typeBoundOps
LegacyFeature* = enum
allowSemcheckedAstModification,
@@ -382,6 +383,7 @@ type
warnCounter*: int
errorMax*: int
maxLoopIterationsVM*: int ## VM: max iterations of all loops
maxCallDepthVM*: int ## VM: max call depth
isVmTrace*: bool
configVars*: StringTableRef
symbols*: StringTableRef ## We need to use a StringTableRef here as defined
@@ -597,6 +599,7 @@ proc newConfigRef*(): ConfigRef =
arguments: "",
suggestMaxResults: 10_000,
maxLoopIterationsVM: 10_000_000,
maxCallDepthVM: 2_000,
vmProfileData: newProfileData(),
spellSuggestMax: spellSuggestSecretSauce,
currentConfigDir: ""

View File

@@ -51,3 +51,11 @@ func belongsToProjectPackage*(conf: ConfigRef, sym: PSym): bool =
## See Also:
## * `modulegraphs.belongsToStdlib`
conf.mainPackageId == sym.getPackageId
func belongsToProjectPackageMaybeNil*(conf: ConfigRef, sym: PSym): bool =
## Return whether the symbol belongs to the project's package.
## Returns `false` if `sym` is nil.
##
## See Also:
## * `modulegraphs.belongsToStdlib`
sym != nil and conf.mainPackageId == sym.getPackageId

View File

@@ -42,10 +42,7 @@ proc makePass*(open: TPassOpen = nil,
process: TPassProcess = nil,
close: TPassClose = nil,
isFrontend = false): TPass =
result.open = open
result.close = close
result.process = process
result.isFrontend = isFrontend
result = (open, process, close, isFrontend)
const
maxPasses = 10
@@ -100,8 +97,8 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
stream: PLLStream): bool {.discardable.} =
if graph.stopCompile(): return true
var
p: Parser
a: TPassContextArray
p: Parser = default(Parser)
a: TPassContextArray = default(TPassContextArray)
s: PLLStream
fileIdx = module.fileIdx
prepareConfigNotes(graph, module)

View File

@@ -47,9 +47,8 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
of NonePass:
raiseAssert "use setPipeLinePass to set a proper PipelinePass"
proc processImplicitImports(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind,
m: PSym, ctx: PContext, bModule: PPassContext, idgen: IdGenerator,
) =
proc processImplicitImports*(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind,
m: PSym, ctx: PContext, bModule: PPassContext, idgen: IdGenerator) =
# XXX fixme this should actually be relative to the config file!
let relativeTo = toFullPath(graph.config, m.info)
for module in items(implicits):
@@ -64,7 +63,7 @@ proc processImplicitImports(graph: ModuleGraph; implicits: seq[string], nodeKind
if semNode == nil or processPipeline(graph, semNode, bModule) == nil:
break
proc prePass(c: PContext; n: PNode) =
proc prePass*(c: PContext; n: PNode) =
for son in n:
if son.kind == nkPragma:
for s in son:

View File

@@ -590,7 +590,7 @@ proc processCompile(c: PContext, n: PNode) =
var customArgs = ""
if n.kind in nkCallKinds:
s = getStrLit(c, n, 1)
if n.len <= 3:
if n.len == 3:
customArgs = getStrLit(c, n, 2)
else:
localError(c.config, n.info, "'.compile' pragma takes up 2 arguments")
@@ -637,7 +637,10 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
# XXX what to do here if 'amb' is true?
if e != nil:
incl(e.flags, sfUsed)
result.add newSymNode(e)
if isDefined(con.config, "nimPreviewAsmSemSymbol"):
result.add con.semExprWithType(con, newSymNode(e), {efTypeAllowed})
else:
result.add newSymNode(e)
else:
result.add newStrNode(nkStrLit, sub)
else:
@@ -722,12 +725,12 @@ proc processPragma(c: PContext, n: PNode, i: int) =
proc pragmaRaisesOrTags(c: PContext, n: PNode) =
proc processExc(c: PContext, x: PNode) =
if c.hasUnresolvedArgs(c, x):
x.typ = makeTypeFromExpr(c, x)
x.typ() = makeTypeFromExpr(c, x)
else:
var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs)
if t.kind notin {tyObject, tyOr}:
localError(c.config, x.info, errGenerated, "invalid type for raises/tags list")
x.typ = t
x.typ() = t
if n.kind in nkPragmaCallKinds and n.len == 2:
let it = n[1]

View File

@@ -1311,10 +1311,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
put(g, tkCustomLit, n[0].strVal)
gsub(g, n, 1)
else:
gsub(g, n, 0)
for i in 0..<n.len-1:
gsub(g, n, i)
put(g, tkDot, ".")
assert n.len == 2, $n.len
accentedName(g, n[1])
if n.len > 1:
accentedName(g, n[^1])
of nkBind:
putWithSpace(g, tkBind, "bind")
gsub(g, n, 0)

View File

@@ -18,7 +18,7 @@ import
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
lowerings, plugins/active, lineinfos, int128,
isolation_check, typeallowed, modulegraphs, enumtostr, concepts, astmsgs,
extccomp
extccomp, layeredtable
import vtables
import std/[strtabs, math, tables, intsets, strutils, packedsets]
@@ -89,6 +89,11 @@ proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode =
changeType(c, x, formal, check=true)
result = arg
result = skipHiddenSubConv(result, c.graph, c.idgen)
# mark inserted converter as used:
var a = result
if a.kind == nkHiddenDeref: a = a[0]
if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
markUsed(c, a.info, a[0].sym)
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
@@ -97,7 +102,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
renderTree(arg, {renderNoComments}))
# error correction:
result = copyTree(arg)
result.typ = formal
result.typ() = formal
elif arg.kind in nkSymChoices and formal.skipTypes(abstractInst).kind == tyEnum:
# Pick the right 'sym' from the sym choice by looking at 'formal' type:
result = nil
@@ -111,7 +116,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
typeMismatch(c.config, info, formal, arg.typ, arg)
# error correction:
result = copyTree(arg)
result.typ = formal
result.typ() = formal
else:
result = fitNodePostMatch(c, formal, result)
@@ -251,7 +256,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# when there is a nested proc inside a template, semtmpl
# will assign a wrong owner during the first pass over the
# template; we must fix it here: see #909
result.owner = getCurrOwner(c)
setOwner(result, getCurrOwner(c))
else:
result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info)
if find(result.name.s, '`') >= 0:
@@ -465,7 +470,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
renderTree(result, {renderNoComments}))
result = newSymNode(errorSym(c, result))
else:
result.typ = makeTypeDesc(c, typ)
result.typ() = makeTypeDesc(c, typ)
#result = symNodeFromType(c, typ, n.info)
else:
if s.ast[genericParamsPos] != nil and retType.isMetaType:
@@ -473,7 +478,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
# e.g. template foo(T: typedesc): seq[T]
# We will instantiate the return type here, because
# we now know the supplied arguments
var paramTypes = initTypeMapping()
var paramTypes = initLayeredTypeMap()
for param, value in genericParamsInMacroCall(s, call):
var givenType = value.typ
# the sym nodes used for the supplied generic arguments for
@@ -481,7 +486,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
# in this case, get the type directly from the sym
if givenType == nil and value.kind == nkSym and value.sym.typ != nil:
givenType = value.sym.typ
idTablePut(paramTypes, param.typ, givenType)
put(paramTypes, param.typ, givenType)
retType = generateTypeInstance(c, paramTypes,
macroResult.info, retType)
@@ -489,15 +494,29 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
if retType.kind == tyVoid:
result = semStmt(c, result, flags)
else:
result = semExpr(c, result, flags, expectedType)
result = semExpr(c, result, flags)
result = fitNode(c, retType, result, result.info)
#globalError(s.info, errInvalidParamKindX, typeToString(s.typ.returnType))
dec(c.config.evalTemplateCounter)
discard c.friendModules.pop()
proc getLineInfo(n: PNode): TLineInfo =
case n.kind
of nkPostfix:
if len(n) > 1:
result = getLineInfo(n[1])
else:
result = n.info
of nkAccQuoted, nkPragmaExpr:
if len(n) > 0:
result = getLineInfo(n[0])
else:
result = n.info
else:
result = n.info
const
errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"
errFloatToString = "cannot convert '$1' to '$2'"
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}; expectedType: PType = nil): PNode =
@@ -522,7 +541,9 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
if efNoSemCheck notin 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))
message(c.config, nOrig.info, hintExpandMacro, renderTree(result, {
renderNonExportedFields, renderDocComments, renderNoComments
}))
result = wrapInComesFrom(nOrig.info, sym, result)
popInfoContext(c.config)
@@ -608,7 +629,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool, ch
newNodeIT(nkType, recNode.info, asgnType)
)
asgnExpr.flags.incl nfSkipFieldChecking
asgnExpr.typ = recNode.typ
asgnExpr.typ() = recNode.typ
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
raiseAssert "unreachable"
@@ -630,7 +651,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault:
if checkDefault: # don't add defaults when checking whether a case branch has default fields
return
defaultValue = newIntNode(nkIntLit#[c.graph]#, 0)
defaultValue.typ = discriminator.typ
defaultValue.typ() = discriminator.typ
selectedBranch = recNode.pickCaseBranchIndex defaultValue
defaultValue.flags.incl nfSkipFieldChecking
result.add newTree(nkExprColonExpr, discriminator, defaultValue)
@@ -643,7 +664,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault:
elif recType.kind in {tyObject, tyArray, tyTuple}:
let asgnExpr = defaultNodeField(c, recNode, recNode.typ, checkDefault)
if asgnExpr != nil:
asgnExpr.typ = recNode.typ
asgnExpr.typ() = recNode.typ
asgnExpr.flags.incl nfSkipFieldChecking
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
else:
@@ -656,7 +677,7 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
let child = defaultFieldsForTheUninitialized(c, aTypSkip.n, checkDefault)
if child.len > 0:
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTyp))
asgnExpr.typ = aTyp
asgnExpr.typ() = aTyp
asgnExpr.sons.add child
result = semExpr(c, asgnExpr)
else:
@@ -667,11 +688,12 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
if child != nil:
let node = newNode(nkIntLit)
node.intVal = toInt64(lengthOrd(c.graph.config, aTypSkip))
result = semExpr(c, newTree(nkCall, newSymNode(getSysSym(c.graph, a.info, "arrayWith"), a.info),
semExprWithType(c, child),
let typeNode = newNode(nkType)
typeNode.typ() = makeTypeDesc(c, aTypSkip[1])
result = semExpr(c, newTree(nkCall, newTree(nkBracketExpr, newSymNode(getSysSym(c.graph, a.info, "arrayWithDefault"), a.info), typeNode),
node
))
result.typ = aTyp
result.typ() = aTyp
else:
result = nil
of tyTuple:
@@ -680,7 +702,7 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault, checkDefault)
if hasDefault and children.len > 0:
result = newNodeI(nkTupleConstr, a.info)
result.typ = aTyp
result.typ() = aTyp
result.sons.add children
result = semExpr(c, result)
else:
@@ -729,6 +751,7 @@ proc preparePContext*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PCo
result.semInferredLambda = semInferredLambda
result.semGenerateInstance = generateInstance
result.instantiateOnlyProcType = instantiateOnlyProcType
result.fitDefaultNode = fitDefaultNode
result.semTypeNode = semTypeNode
result.instTypeBoundOp = sigmatch.instTypeBoundOp
result.hasUnresolvedArgs = hasUnresolvedArgs
@@ -849,9 +872,9 @@ proc semWithPContext*(c: PContext, n: PNode): PNode =
proc reportUnusedModules(c: PContext) =
if c.config.cmd == cmdM: return
for i in 0..high(c.unusedImports):
if sfUsed notin c.unusedImports[i][0].flags:
message(c.config, c.unusedImports[i][1], warnUnusedImportX, c.unusedImports[i][0].name.s)
for (s, info) in c.unusedImports:
if sfUsed notin s.flags:
message(c.config, info, warnUnusedImportX, s.name.s)
proc closePContext*(graph: ModuleGraph; c: PContext, n: PNode): PNode =
if c.config.cmd == cmdIdeTools and not c.suggestionsMade:

View File

@@ -56,7 +56,7 @@ proc initCandidateSymbols(c: PContext, headSymbol: PNode,
proc name[T: static proc()]() = T()
name[proc() = echo"hello"]()
]#
for paramSym in searchInScopesAllCandidatesFilterBy(c, symx.name, {skConst}):
for paramSym in searchScopesAll(c, symx.name, {skConst}):
let paramTyp = paramSym.typ
if paramTyp.n.kind == nkSym and paramTyp.n.sym.kind in filter:
result.add((paramTyp.n.sym, o.lastOverloadScope))
@@ -69,6 +69,39 @@ proc initCandidateSymbols(c: PContext, headSymbol: PNode,
result[0].scope, diagnostics)
best.state = csNoMatch
proc isAttachableRoutineTo(prc: PSym, arg: PType): bool =
result = false
if arg.owner != prc.owner: return false
for i in 1 ..< prc.typ.len:
if prc.typ.n[i].kind == nkSym and prc.typ.n[i].sym.ast != nil:
# has default value, parameter is not considered in type attachment
continue
let t = nominalRoot(prc.typ[i])
if t != nil and t.itemId == arg.itemId:
# parameter `i` is a nominal type in this module
# attachable if the nominal root `t` has the same id as `arg`
return true
proc addTypeBoundSymbols(graph: ModuleGraph, arg: PType, name: PIdent,
filter: TSymKinds, marker: var IntSet,
syms: var seq[tuple[s: PSym, scope: int]]) =
# add type bound ops for `name` based on the argument type `arg`
if arg != nil:
# argument must be typed first, meaning arguments always
# matching `untyped` are ignored
let t = nominalRoot(arg)
if t != nil and t.owner.kind == skModule:
# search module for routines attachable to `t`
let module = t.owner
var iter = default(ModuleIter)
var s = initModuleIter(iter, graph, module, name)
while s != nil:
if s.kind in filter and s.isAttachableRoutineTo(t) and
not containsOrIncl(marker, s.id):
# least priority scope, less than explicit imports:
syms.add((s, -2))
s = nextModuleIter(iter, graph)
proc pickBestCandidate(c: PContext, headSymbol: PNode,
n, orig: PNode,
initialBinding: PNode,
@@ -88,10 +121,23 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
best, alt, o, diagnosticsFlag)
if len(syms) == 0:
return
let allowTypeBoundOps = typeBoundOps in c.features and
# qualified or bound symbols cannot refer to type bound ops
headSymbol.kind in {nkIdent, nkAccQuoted, nkOpenSymChoice, nkOpenSym}
var symMarker = initIntSet()
for s in syms:
symMarker.incl(s.s.id)
# current overload being considered
var sym = syms[0].s
let name = sym.name
var scope = syms[0].scope
if allowTypeBoundOps:
for a in 1 ..< n.len:
# for every already typed argument, add type bound ops
let arg = n[a]
addTypeBoundSymbols(c.graph, arg.typ, name, filter, symMarker, syms)
# starts at 1 because 0 is already done with setup, only needs checking
var nextSymIndex = 1
var z: TCandidate # current candidate
@@ -106,6 +152,14 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
# may introduce new symbols with caveats described in recalc branch
matches(c, n, orig, z)
if allowTypeBoundOps:
# this match may have given some arguments new types,
# in which case add their type bound ops as well
# type bound ops of arguments always matching `untyped` are not considered
for x in z.newlyTypedOperands:
let arg = n[x]
addTypeBoundSymbols(c.graph, arg.typ, name, filter, symMarker, syms)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind == skIterator:
@@ -136,7 +190,14 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
# before any further candidate init and compare. SLOW, but rare case.
syms = initCandidateSymbols(c, headSymbol, initialBinding, filter,
best, alt, o, diagnosticsFlag)
symMarker = initIntSet()
for s in syms:
symMarker.incl(s.s.id)
if allowTypeBoundOps:
for a in 1 ..< n.len:
# for every already typed argument, add type bound ops
let arg = n[a]
addTypeBoundSymbols(c.graph, arg.typ, name, filter, symMarker, syms)
# reset counter because syms may be in a new order
symCount = c.currentScope.symbols.counter
nextSymIndex = 0
@@ -636,7 +697,7 @@ proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
if s.isGenericRoutineStrict:
let finalCallee = generateInstance(c, s, x.bindings, a.info)
a[0].sym = finalCallee
a[0].typ = finalCallee.typ
a[0].typ() = finalCallee.typ
#a.typ = finalCallee.typ.returnType
proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
@@ -645,6 +706,15 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
for i in 1..<n.len:
instGenericConvertersArg(c, n[i], x)
proc markConvertersUsed*(c: PContext, n: PNode) =
assert n.kind in nkCallKinds
for i in 1..<n.len:
var a = n[i]
if a == nil: continue
if a.kind == nkHiddenDeref: a = a[0]
if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
markUsed(c, a.info, a[0].sym)
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
var m = newCandidate(c, f)
result = paramTypesMatch(m, f, a, arg, nil)
@@ -662,13 +732,13 @@ proc inferWithMetatype(c: PContext, formal: PType,
# This almost exactly replicates the steps taken by the compiler during
# param matching. It performs an embarrassing amount of back-and-forth
# type jugling, but it's the price to pay for consistency and correctness
result.typ = generateTypeInstance(c, m.bindings, arg.info,
result.typ() = generateTypeInstance(c, m.bindings, arg.info,
formal.skipTypes({tyCompositeTypeClass}))
else:
typeMismatch(c.config, arg.info, formal, arg.typ, arg)
# error correction:
result = copyTree(arg)
result.typ = formal
result.typ() = formal
proc updateDefaultParams(c: PContext, call: PNode) =
# In generic procs, the default parameter may be unique for each
@@ -691,7 +761,7 @@ proc updateDefaultParams(c: PContext, call: PNode) =
pushInfoContext(c.config, call.info, call[0].sym.detailedInfo)
typeMismatch(c.config, def.info, formal.typ, def.typ, formal.ast)
popInfoContext(c.config)
def.typ = errorType(c)
def.typ() = errorType(c)
call[i] = def
proc getCallLineInfo(n: PNode): TLineInfo =
@@ -748,7 +818,7 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) =
if t[i] == nil or u[i] == nil: return
stackPut(t[i], u[i])
of tyGenericParam:
let prebound = x.bindings.idTableGet(t)
let prebound = x.bindings.lookup(t)
if prebound != nil:
continue # Skip param, already bound
@@ -760,7 +830,7 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) =
discard
# update bindings
for i in 0 ..< flatUnbound.len():
x.bindings.idTablePut(flatUnbound[i], flatBound[i])
x.bindings.put(flatUnbound[i], flatBound[i])
proc semResolvedCall(c: PContext, x: var TCandidate,
n: PNode, flags: TExprFlags;
@@ -775,7 +845,7 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
result = x.call
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
if containsGenericType(result.typ):
result.typ = newTypeS(tyError, c)
result.typ() = newTypeS(tyError, c)
incl result.typ.flags, tfCheckedForDestructor
return
let gp = finalCallee.ast[genericParamsPos]
@@ -802,16 +872,17 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
# this node will be used in template substitution,
# pretend this is an untyped node and let regular sem handle the type
# to prevent problems where a generic parameter is treated as a value
tn.typ = nil
tn.typ() = nil
x.call.add tn
else:
internalAssert c.config, false
result = x.call
instGenericConvertersSons(c, result, x)
markConvertersUsed(c, result)
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
if finalCallee.magic notin {mArrGet, mArrPut}:
result.typ = finalCallee.typ.returnType
result.typ() = finalCallee.typ.returnType
updateDefaultParams(c, result)
proc canDeref(n: PNode): bool {.inline.} =
@@ -820,7 +891,7 @@ proc canDeref(n: PNode): bool {.inline.} =
proc tryDeref(n: PNode): PNode =
result = newNodeI(nkHiddenDeref, n.info)
result.typ = n.typ.skipTypes(abstractInst)[0]
result.typ() = n.typ.skipTypes(abstractInst)[0]
result.add n
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
@@ -839,7 +910,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
else:
if c.inGenericContext > 0 and c.matchedConcept == nil:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
result.typ() = makeTypeFromExpr(c, result.copyTree)
elif efExplain notin flags:
# repeat the overload resolution,
# this time enabling all the diagnostic output (this should fail again)
@@ -854,7 +925,7 @@ proc explicitGenericInstError(c: PContext; n: PNode): PNode =
localError(c.config, getCallLineInfo(n), errCannotInstantiateX % renderTree(n))
result = n
proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
proc explicitGenericSym(c: PContext, n: PNode, s: PSym, errors: var CandidateErrors, doError: bool): PNode =
if s.kind in {skTemplate, skMacro}:
internalError c.config, n.info, "cannot get explicitly instantiated symbol of " &
(if s.kind == skTemplate: "template" else: "macro")
@@ -864,6 +935,11 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
if m.state != csMatch:
# state is csMatch only if *all* generic params were matched,
# including implicit parameters
if doError:
errors.add(CandidateError(
sym: s,
firstMismatch: m.firstMismatch,
diagnostics: m.diagnostics))
return nil
var newInst = generateInstance(c, s, m.bindings, n.info)
newInst.typ.flags.excl tfUnresolved
@@ -883,46 +959,57 @@ proc setGenericParams(c: PContext, n, expectedParams: PNode) =
nil
e = semExprWithType(c, n[i], expectedType = constraint)
if e.typ == nil:
n[i].typ = errorType(c)
n[i].typ() = errorType(c)
else:
n[i].typ = e.typ.skipTypes({tyTypeDesc})
n[i].typ() = e.typ.skipTypes({tyTypeDesc})
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym, doError: bool): PNode =
assert n.kind == nkBracketExpr
setGenericParams(c, n, s.ast[genericParamsPos])
var s = s
var a = n[0]
var errors: CandidateErrors = @[]
if a.kind == nkSym:
# common case; check the only candidate has the right
# number of generic type parameters:
if s.ast[genericParamsPos].safeLen != n.len-1:
let expected = s.ast[genericParamsPos].safeLen
localError(c.config, getCallLineInfo(n), errGenerated, "cannot instantiate: '" & renderTree(n) &
"'; got " & $(n.len-1) & " typeof(s) but expected " & $expected)
return n
result = explicitGenericSym(c, n, s)
if result == nil: result = explicitGenericInstError(c, n)
result = explicitGenericSym(c, n, s, errors, doError)
if result == nil:
if c.inGenericContext > 0:
# same as in semOverloadedCall, make expression untyped,
# may have failed match due to unresolved types
result = semGenericStmt(c, n)
result.typ() = makeTypeFromExpr(c, result.copyTree)
elif doError:
notFoundError(c, n, errors)
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
# choose the generic proc with the proper number of type parameters.
# XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
# It's good enough for now.
result = newNodeI(a.kind, getCallLineInfo(n))
for i in 0..<a.len:
var candidate = a[i].sym
if candidate.kind in {skProc, skMethod, skConverter,
skFunc, skIterator}:
# it suffices that the candidate has the proper number of generic
# type parameters:
if candidate.ast[genericParamsPos].safeLen == n.len-1:
let x = explicitGenericSym(c, n, candidate)
if x != nil: result.add(x)
let x = explicitGenericSym(c, n, candidate, errors, doError)
if x != nil: result.add(x)
elif c.inGenericContext > 0:
# same as in semOverloadedCall, make expression untyped,
# may have failed match due to unresolved types
# any failing match stops building the symchoice for correctness,
# can also make it untyped from the start
result = semGenericStmt(c, n)
result.typ() = makeTypeFromExpr(c, result.copyTree)
return
# get rid of nkClosedSymChoice if not ambiguous:
if result.len == 1 and a.kind == nkClosedSymChoice:
result = result[0]
elif result.len == 0: result = explicitGenericInstError(c, n)
# candidateCount != 1: return explicitGenericInstError(c, n)
if result.len == 0:
result = nil
if doError:
notFoundError(c, n, errors)
else:
result = explicitGenericInstError(c, n)
# probably unreachable: we are trying to instantiate `a` which is not
# a sym/symchoice
if doError:
result = explicitGenericInstError(c, n)
else:
result = nil
proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): tuple[s: PSym, state: TBorrowState] =
# Searches for the fn in the symbol table. If the parameter lists are suitable

View File

@@ -15,8 +15,8 @@ when defined(nimPreviewSlimSystem):
import std/assertions
import
options, ast, astalgo, msgs, idents, renderer,
magicsys, vmdef, modulegraphs, lineinfos, pathutils
options, ast, msgs, idents, renderer,
magicsys, vmdef, modulegraphs, lineinfos, pathutils, layeredtable
import ic / ic
@@ -136,12 +136,13 @@ type
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
filter: TSymKinds, flags: TExprFlags, expectedType: PType = nil): PNode {.nimcall.}
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
semInferredLambda*: proc(c: PContext, pt: Table[ItemId, PType], n: PNode): PNode
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: Table[ItemId, PType],
semInferredLambda*: proc(c: PContext, pt: LayeredIdTable, n: PNode): PNode
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: LayeredIdTable,
info: TLineInfo): PSym
instantiateOnlyProcType*: proc (c: PContext, pt: TypeMapping,
instantiateOnlyProcType*: proc (c: PContext, pt: LayeredIdTable,
prc: PSym, info: TLineInfo): PType
# used by sigmatch for explicit generic instantiations
fitDefaultNode*: proc (c: PContext, n: var PNode, expectedType: PType)
includedFiles*: IntSet # used to detect recursive include files
pureEnumFields*: TStrTable # pure enum fields that can be used unambiguously
userPragmas*: TStrTable
@@ -195,29 +196,29 @@ proc getIntLitType*(c: PContext; literal: PNode): PType =
proc setIntLitType*(c: PContext; result: PNode) =
let i = result.intVal
case c.config.target.intSize
of 8: result.typ = getIntLitType(c, result)
of 8: result.typ() = getIntLitType(c, result)
of 4:
if i >= low(int32) and i <= high(int32):
result.typ = getIntLitType(c, result)
result.typ() = getIntLitType(c, result)
else:
result.typ = getSysType(c.graph, result.info, tyInt64)
result.typ() = getSysType(c.graph, result.info, tyInt64)
of 2:
if i >= low(int16) and i <= high(int16):
result.typ = getIntLitType(c, result)
result.typ() = getIntLitType(c, result)
elif i >= low(int32) and i <= high(int32):
result.typ = getSysType(c.graph, result.info, tyInt32)
result.typ() = getSysType(c.graph, result.info, tyInt32)
else:
result.typ = getSysType(c.graph, result.info, tyInt64)
result.typ() = getSysType(c.graph, result.info, tyInt64)
of 1:
# 8 bit CPUs are insane ...
if i >= low(int8) and i <= high(int8):
result.typ = getIntLitType(c, result)
result.typ() = getIntLitType(c, result)
elif i >= low(int16) and i <= high(int16):
result.typ = getSysType(c.graph, result.info, tyInt16)
result.typ() = getSysType(c.graph, result.info, tyInt16)
elif i >= low(int32) and i <= high(int32):
result.typ = getSysType(c.graph, result.info, tyInt32)
result.typ() = getSysType(c.graph, result.info, tyInt32)
else:
result.typ = getSysType(c.graph, result.info, tyInt64)
result.typ() = getSysType(c.graph, result.info, tyInt64)
else:
internalError(c.config, result.info, "invalid int size")
@@ -449,7 +450,7 @@ when false:
proc makeStaticExpr*(c: PContext, n: PNode): PNode =
result = newNodeI(nkStaticExpr, n.info)
result.sons = @[n]
result.typ = if n.typ != nil and n.typ.kind == tyStatic: n.typ
result.typ() = if n.typ != nil and n.typ.kind == tyStatic: n.typ
else: newTypeS(tyStatic, c, n.typ)
proc makeAndType*(c: PContext, t1, t2: PType): PType =
@@ -508,7 +509,7 @@ proc errorType*(c: PContext): PType =
proc errorNode*(c: PContext, n: PNode): PNode =
result = newNodeI(nkEmpty, n.info)
result.typ = errorType(c)
result.typ() = errorType(c)
# These mimic localError
template localErrorNode*(c: PContext, n: PNode, info: TLineInfo, msg: TMsgKind, arg: string): PNode =
@@ -529,10 +530,11 @@ template localErrorNode*(c: PContext, n: PNode, arg: string): PNode =
liMessage(c.config, n2.info, errGenerated, arg, doNothing, instLoc())
errorNode(c, n2)
proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) =
dest.kind = kind
dest.owner = getCurrOwner(c)
dest.size = - 1
when false:
proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) =
dest.kind = kind
dest.owner = getCurrOwner(c)
dest.size = - 1
proc makeRangeType*(c: PContext; first, last: BiggestInt;
info: TLineInfo; intType: PType = nil): PType =
@@ -563,7 +565,7 @@ proc symFromType*(c: PContext; t: PType, info: TLineInfo): PSym =
proc symNodeFromType*(c: PContext, t: PType, info: TLineInfo): PNode =
result = newSymNode(symFromType(c, t, info), info)
result.typ = makeTypeDesc(c, t)
result.typ() = makeTypeDesc(c, t)
proc markIndirect*(c: PContext, s: PSym) {.inline.} =
if s.kind in {skProc, skFunc, skConverter, skMethod, skIterator}:

View File

@@ -56,11 +56,11 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.typ != nil:
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
elif {efWantStmt, efAllowStmt} * flags != {}:
result.typ = newTypeS(tyVoid, c)
result.typ() = newTypeS(tyVoid, c)
else:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
result.typ() = errorType(c)
proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType = nil): PNode =
rejectEmptyNode(n)
@@ -82,14 +82,14 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
result = semExprCheck(c, n, flags-{efTypeAllowed}, expectedType)
if result.typ == nil and efInTypeof in flags:
result.typ = c.voidType
result.typ() = c.voidType
elif result.typ == nil or result.typ == c.enforceVoidContext:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
result.typ() = errorType(c)
elif result.typ.kind == tyError:
# associates the type error to the current owner
result.typ = errorType(c)
result.typ() = errorType(c)
elif efTypeAllowed in flags and result.typ.kind == tyProc and
hasUnresolvedParams(result, {}):
# mirrored with semOperand but only on efTypeAllowed
@@ -101,7 +101,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType
else:
errProcHasNoConcreteType % n.renderTree
localError(c.config, n.info, err)
result.typ = errorType(c)
result.typ() = errorType(c)
else:
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
@@ -110,7 +110,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.typ == nil:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
result.typ() = errorType(c)
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = symChoice(c, n, s, scClosed)
@@ -194,7 +194,7 @@ proc semOpenSym(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType,
result = nil
if not isSym:
# set symchoice node type back to None
n.typ = newTypeS(tyNone, c)
n.typ() = newTypeS(tyNone, c)
proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
if n.kind == nkOpenSymChoice:
@@ -216,7 +216,7 @@ proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: P
err.add " " & candidate.owner.name.s & "." & candidate.name.s
err.add ": " & typeToString(candidate.typ) & "\n"
localError(c.config, n.info, err)
n.typ = errorType(c)
n.typ() = errorType(c)
result = n
if result.kind == nkSym:
result = semSym(c, result, result.sym, flags)
@@ -227,7 +227,7 @@ proc inlineConst(c: PContext, n: PNode, s: PSym): PNode {.inline.} =
localError(c.config, n.info, "constant of type '" & typeToString(s.typ) & "' has no value")
result = newSymNode(s)
else:
result.typ = s.typ
result.typ() = s.typ
result.info = n.info
type
@@ -395,7 +395,7 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
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)
result.typ() = c.makeTypeDesc semStaticType(c, evaluated, nil)
return
elif targetType.base.kind == tyNone:
return evaluated
@@ -413,7 +413,7 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
if targetType.kind == tyOwned:
t.flags.incl tfHasOwned
result = newNodeI(nkType, n.info)
result.typ = makeTypeDesc(c, t)
result.typ() = makeTypeDesc(c, t)
return
result.add copyTree(n[0])
@@ -429,10 +429,10 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
if targetType.kind != tyGenericParam and targetType.isMetaType:
let final = inferWithMetatype(c, targetType, op, true)
result.add final
result.typ = final.typ
result.typ() = final.typ
return
result.typ = targetType
result.typ() = targetType
# XXX op is overwritten later on, this is likely added too early
# here or needs to be overwritten too then.
result.add op
@@ -440,7 +440,7 @@ proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType
if targetType.kind == tyGenericParam or
(op.typ != nil and op.typ.kind == tyFromExpr and c.inGenericContext > 0):
# expression is compiled early in a generic body
result.typ = makeTypeFromExpr(c, copyTree(result))
result.typ() = makeTypeFromExpr(c, copyTree(result))
return result
if not isSymChoice(op):
@@ -490,7 +490,7 @@ proc semCast(c: PContext, n: PNode): PNode =
if not isCastable(c, targetType, castedExpr.typ, n.info):
localError(c.config, n.info, "expression cannot be cast to '$1'" % $targetType)
result = newNodeI(nkCast, n.info)
result.typ = targetType
result.typ() = targetType
result.add copyTree(n[0])
result.add castedExpr
@@ -504,18 +504,18 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
var typ = skipTypes(n[1].typ, abstractVarRange + {tyTypeDesc, tyUserTypeClassInst})
case typ.kind
of tySequence, tyString, tyCstring, tyOpenArray, tyVarargs:
n.typ = getSysType(c.graph, n.info, tyInt)
n.typ() = getSysType(c.graph, n.info, tyInt)
of tyArray:
n.typ = typ.indexType
n.typ() = typ.indexType
if n.typ.kind == tyRange and emptyRange(n.typ.n[0], n.typ.n[1]): #Invalid range
n.typ = getSysType(c.graph, n.info, tyInt)
n.typ() = getSysType(c.graph, n.info, tyInt)
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt..tyUInt64, tyFloat..tyFloat64:
n.typ = n[1].typ.skipTypes({tyTypeDesc})
n.typ() = n[1].typ.skipTypes({tyTypeDesc})
of tyGenericParam:
# prepare this for resolving in semtypinst:
# we must use copyTree here in order to avoid creating a cycle
# that could easily turn into an infinite recursion in semtypinst
n.typ = makeTypeFromExpr(c, n.copyTree)
n.typ() = makeTypeFromExpr(c, n.copyTree)
else:
localError(c.config, n.info, "invalid argument for: " & opToStr[m])
result = n
@@ -531,7 +531,7 @@ proc fixupStaticType(c: PContext, n: PNode) =
# apply this measure only in code that is enlightened to work
# with static types.
if n.typ.kind != tyStatic:
n.typ = newTypeS(tyStatic, c, n.typ)
n.typ() = newTypeS(tyStatic, c, n.typ)
n.typ.n = n # XXX: cycles like the one here look dangerous.
# Consider using `n.copyTree`
@@ -581,7 +581,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
# `res = sameType(t1, t2)` would be wrong, e.g. for `int is (int|float)`
result = newIntNode(nkIntLit, ord(res))
result.typ = n.typ
result.typ() = n.typ
proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
if n.len != 3 or n[2].kind == nkEmpty:
@@ -590,7 +590,7 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
let boolType = getSysType(c.graph, n.info, tyBool)
result = n
n.typ = boolType
n.typ() = boolType
var liftLhs = true
n[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
@@ -604,7 +604,7 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
n[1] = evaluated
else:
result = newIntNode(nkIntLit, 0)
result.typ = boolType
result.typ() = boolType
return
elif t2.kind == tyTypeDesc and
(t2.base.kind == tyNone or tfExplicit in t2.flags):
@@ -634,7 +634,7 @@ proc semOpAux(c: PContext, n: PNode) =
let info = a[0].info
a[0] = newIdentNode(considerQuotedIdent(c, a[0], a), info)
a[1] = semExprWithType(c, a[1], flags)
a.typ = a[1].typ
a.typ() = a[1].typ
else:
n[i] = semExprWithType(c, a, flags)
@@ -707,7 +707,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
localError(c.config, n.info, "cannot convert '" & n.sym.name.s &
"' to '" & typeNameAndDesc(newType) & "'")
else: discard
n.typ = newType
n.typ() = newType
proc arrayConstrType(c: PContext, n: PNode): PType =
var typ = newTypeS(tyArray, c)
@@ -722,29 +722,41 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = newNodeI(nkBracket, n.info)
result.typ = newTypeS(tyArray, c)
# nkBracket nodes can also be produced by the VM as seq constant nodes
# in which case, we cannot produce a new array type for the node,
# as this might lose type info even when the node has array type
let constructType = n.typ.isNil
var expectedElementType, expectedIndexType: PType = nil
if expectedType != nil:
let expected = expectedType.skipTypes(abstractRange-{tyDistinct})
case expected.kind
var expectedBase: PType = nil
if constructType:
result.typ() = newTypeS(tyArray, c)
rawAddSon(result.typ, nil) # index type
if expectedType != nil:
expectedBase = expectedType.skipTypes(abstractRange-{tyDistinct})
else:
result.typ() = n.typ
expectedBase = n.typ.skipTypes(abstractRange) # include tyDistinct this time
if expectedBase != nil:
case expectedBase.kind
of tyArray:
expectedIndexType = expected[0]
expectedElementType = expected[1]
of tyOpenArray:
expectedElementType = expected[0]
expectedIndexType = expectedBase[0]
expectedElementType = expectedBase[1]
of tyOpenArray, tySequence:
# typed bracket expressions can also have seq type
expectedElementType = expectedBase[0]
else: discard
rawAddSon(result.typ, nil) # index type
var
firstIndex, lastIndex: Int128 = Zero
indexType = getSysType(c.graph, n.info, tyInt)
lastValidIndex = lastOrd(c.config, indexType)
if n.len == 0:
rawAddSon(result.typ,
if expectedElementType != nil and
typeAllowed(expectedElementType, skLet, c) == nil:
expectedElementType
else:
newTypeS(tyEmpty, c)) # needs an empty basetype!
if constructType:
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]
@@ -761,9 +773,13 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
x = x[1]
let yy = semExprWithType(c, x, {efTypeAllowed}, expectedElementType)
var typ = yy.typ
if expectedElementType == nil:
expectedElementType = typ
var typ: PType
if constructType:
typ = yy.typ
if expectedElementType == nil:
expectedElementType = typ
else:
typ = expectedElementType
result.add yy
#var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
for i in 1..<n.len:
@@ -783,15 +799,20 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
let xx = semExprWithType(c, x, {efTypeAllowed}, expectedElementType)
result.add xx
typ = commonType(c, typ, xx.typ)
if constructType:
typ = commonType(c, typ, xx.typ)
#n[i] = semExprWithType(c, x, {})
#result.add fitNode(c, typ, n[i])
inc(lastIndex)
addSonSkipIntLit(result.typ, typ, c.idgen)
if constructType:
addSonSkipIntLit(result.typ, typ, c.idgen)
for i in 0..<result.len:
result[i] = fitNode(c, typ, result[i], result[i].info)
result.typ.setIndexType makeRangeType(c, toInt64(firstIndex), toInt64(lastIndex), n.info,
indexType)
if constructType:
result.typ.setIndexType(
makeRangeType(c,
toInt64(firstIndex), toInt64(lastIndex),
n.info, indexType))
proc fixAbstractType(c: PContext, n: PNode) =
for i in 1..<n.len:
@@ -981,13 +1002,13 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
if n[i].typ.isNil or n[i].typ.kind != tyStatic or
tfUnresolved notin n[i].typ.flags:
break maybeLabelAsStatic
n.typ = newTypeS(tyStatic, c, n.typ)
n.typ() = newTypeS(tyStatic, c, n.typ)
n.typ.flags.incl tfUnresolved
# optimization pass: not necessary for correctness of the semantic pass
if callee.kind == skConst or
if (callee.kind == skConst or
{sfNoSideEffect, sfCompileTime} * callee.flags != {} and
{sfForward, sfImportc} * callee.flags == {} and n.typ != nil:
{sfForward, sfImportc} * callee.flags == {}) and n.typ != nil:
if callee.kind != skConst and
sfCompileTime notin callee.flags and
@@ -1070,7 +1091,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
if efWantIterable in flags:
let typ = newTypeS(tyIterable, c)
rawAddSon(typ, result.typ)
result.typ = typ
result.typ() = typ
proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
t: PType): TCandidate =
@@ -1157,7 +1178,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
elif n0.typ.kind == tyFromExpr and c.inGenericContext > 0:
# don't make assumptions, entire expression needs to be tyFromExpr
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
result.typ() = makeTypeFromExpr(c, result.copyTree)
return
else:
n[0] = n0
@@ -1215,6 +1236,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
else:
result = m.call
instGenericConvertersSons(c, result, m)
markConvertersUsed(c, result)
else:
result = overloadedCallOpr(c, n) # this uses efNoUndeclared
@@ -1414,7 +1436,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
of tyStatic:
if typ.n != nil:
result = typ.n
result.typ = typ.base
result.typ() = typ.base
else:
result = newSymNode(s, n.info)
else:
@@ -1460,20 +1482,22 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
onUse(n.info, s)
if s.typ.kind == tyStatic:
result = newSymNode(s, n.info)
result.typ = s.typ
result.typ() = s.typ
elif s.ast != nil:
result = semExpr(c, s.ast)
else:
n.typ = s.typ
n.typ() = s.typ
return n
of skType:
if n.kind != nkDotExpr: # dotExpr is already checked by builtinFieldAccess
markUsed(c, n.info, s)
onUse(n.info, s)
if s.typ == nil:
return localErrorNode(c, n, "symbol '$1' has no type" % [s.name.s])
if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
return s.typ.n
result = newSymNode(s, n.info)
result.typ = makeTypeDesc(c, s.typ)
result.typ() = makeTypeDesc(c, s.typ)
of skField:
# old code, not sure if it's live code:
markUsed(c, n.info, s)
@@ -1499,7 +1523,7 @@ proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
if result == c.graph.emptyNode:
if c.inGenericContext > 0:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
result.typ() = makeTypeFromExpr(c, result.copyTree)
else:
result = nil
of tyUserTypeClasses:
@@ -1507,7 +1531,7 @@ proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
result = readTypeParameter(c, t, i, n.info)
elif c.inGenericContext > 0:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, copyTree(result))
result.typ() = makeTypeFromExpr(c, copyTree(result))
else:
result = nil
of tyGenericBody, tyCompositeTypeClass:
@@ -1516,12 +1540,12 @@ proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
if result != nil:
# generic parameter exists, stop here but delay until instantiation
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, copyTree(result))
result.typ() = makeTypeFromExpr(c, copyTree(result))
else:
result = nil
elif c.inGenericContext > 0 and t.containsUnresolvedType:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, copyTree(result))
result.typ() = makeTypeFromExpr(c, copyTree(result))
else:
result = nil
@@ -1539,14 +1563,14 @@ proc tryReadingTypeField(c: PContext, n: PNode, i: PIdent, ty: PType): PNode =
if f != nil:
result = newSymNode(f)
result.info = n.info
result.typ = ty
result.typ() = ty
markUsed(c, n.info, f)
onUse(n.info, f)
of tyObject, tyTuple:
if ty.n != nil and ty.n.kind == nkRecList:
let field = lookupInRecord(ty.n, i)
if field != nil:
n.typ = makeTypeDesc(c, field.typ)
n.typ() = makeTypeDesc(c, field.typ)
result = n
of tyGenericInst:
result = tryReadingTypeField(c, n, i, ty.skipModifier)
@@ -1593,7 +1617,7 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
# tyFromExpr, but when this happen in a macro this is not a built-in
# field access and we leave the compiler to compile a normal call:
if getCurrOwner(c).kind != skMacro:
n.typ = makeTypeFromExpr(c, n.copyTree)
n.typ() = makeTypeFromExpr(c, n.copyTree)
flags.incl efCannotBeDotCall
return n
else:
@@ -1633,12 +1657,12 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
n[0] = makeDeref(n[0])
n[1] = newSymNode(f) # we now have the correct field
n[1].info = info # preserve the original info
n.typ = f.typ
n.typ() = f.typ
if check == nil:
result = n
else:
check[0] = n
check.typ = n.typ
check.typ() = n.typ
result = check
elif ty.kind == tyTuple and ty.n != nil:
f = getSymFromList(ty.n, i)
@@ -1647,7 +1671,7 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
onUse(n[1].info, f)
n[0] = makeDeref(n[0])
n[1] = newSymNode(f)
n.typ = f.typ
n.typ() = f.typ
result = n
# we didn't find any field, let's look for a generic param
@@ -1656,29 +1680,46 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
result = tryReadingGenericParam(c, n, i, t)
flags.incl efCannotBeDotCall
proc dotTransformation(c: PContext, n: PNode): PNode =
proc hiddenDerefDepth(n: PNode): int =
result = 0
var n = n
while n.kind == nkHiddenDeref:
inc result
n = n[0]
proc dotTransformation(c: PContext, n: PNode, initialDerefs: int): PNode =
var root = n[0]
let currentDerefs = hiddenDerefDepth(root)
if currentDerefs > initialDerefs:
# hidden derefs were inserted by `builtinFieldAccess` for fields of
# `ref object` etc.
# undo the derefs for overload resolution
for _ in initialDerefs ..< currentDerefs:
root = root[0]
root = copyTree(root)
if isSymChoice(n[1]) or
# generics usually leave field names as symchoices, but not types
(n[1].kind == nkSym and n[1].sym.kind == skType):
result = newNodeI(nkDotCall, n.info)
result.add n[1]
result.add copyTree(n[0])
result.add root
else:
var i = considerQuotedIdent(c, n[1], n)
result = newNodeI(nkDotCall, n.info)
result.flags.incl nfDotField
result.add newIdentNode(i, n[1].info)
result.add copyTree(n[0])
result.add root
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# this is difficult, because the '.' is used in many different contexts
# in Nim. We first allow types in the semantic checking.
var f = flags - {efIsDotCall}
let initialDerefDepth = hiddenDerefDepth(n[0])
result = builtinFieldAccess(c, n, f)
if result == nil or ((result.typ == nil or result.typ.skipTypes(abstractInst).kind != tyProc) and
efIsDotCall in flags and callOperator notin c.features and
efCannotBeDotCall notin f):
result = dotTransformation(c, n)
result = dotTransformation(c, n, initialDerefDepth)
proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode =
result = newNodeI(nkCall, n.info)
@@ -1696,33 +1737,21 @@ proc semDeref(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = n
var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink, tyOwned})
case t.kind
of tyRef, tyPtr: n.typ = t.elementType
of tyRef, tyPtr: n.typ() = t.elementType
of tyMetaTypes, tyFromExpr:
n.typ = makeTypeFromExpr(c, n.copyTree)
n.typ() = makeTypeFromExpr(c, n.copyTree)
else: result = nil
#GlobalError(n[0].info, errCircumNeedsPointer)
proc maybeInstantiateGeneric(c: PContext, n: PNode, s: PSym): PNode =
## Instantiates generic if not lacking implicit generics,
## otherwise returns n.
let
neededGenParams = s.ast[genericParamsPos].len
heldGenParams = n.len - 1
var implicitParams = 0
for x in s.ast[genericParamsPos]:
if tfImplicitTypeParam in x.typ.flags:
inc implicitParams
if heldGenParams != neededGenParams and implicitParams + heldGenParams == neededGenParams:
# This is an implicit + explicit generic procedure without all args passed,
# kicking back the sem'd symbol fixes #17212
# Uncertain the hackiness of this solution.
result = n
else:
result = explicitGenericInstantiation(c, n, s)
if result == n:
n[0] = copyTree(result[0])
proc maybeInstantiateGeneric(c: PContext, n: PNode, s: PSym, doError: bool): PNode =
## Attempts to instantiate generic proc symbol(s) with given parameters.
## If instantiation causes errors; if `doError` is `true`, a type mismatch
## error is given, otherwise `nil` is returned.
result = explicitGenericInstantiation(c, n, s, doError)
if result == n:
n[0] = copyTree(result[0])
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags, afterOverloading = false): PNode =
## returns nil if not a built-in subscript operator; also called for the
## checking of assignments
result = nil
@@ -1743,10 +1772,10 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
if arr.kind == tyStatic:
if arr.base.kind == tyNone:
result = n
result.typ = semStaticType(c, n[1], nil)
result.typ() = semStaticType(c, n[1], nil)
return
elif arr.n != nil:
return semSubscript(c, arr.n, flags)
return semSubscript(c, arr.n, flags, afterOverloading)
else:
arr = arr.base
@@ -1765,18 +1794,18 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
if arg != nil:
n[1] = arg
result = n
result.typ = elemType(arr)
result.typ() = elemType(arr)
# Other types have a bit more of leeway
elif n[1].typ.skipTypes(abstractRange-{tyDistinct}).kind in
{tyInt..tyInt64, tyUInt..tyUInt64}:
result = n
result.typ = elemType(arr)
result.typ() = elemType(arr)
of tyTypeDesc:
# The result so far is a tyTypeDesc bound
# a tyGenericBody. The line below will substitute
# it with the instantiated type.
result = n
result.typ = makeTypeDesc(c, semTypeNode(c, n, nil))
result.typ() = makeTypeDesc(c, semTypeNode(c, n, nil))
#result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
of tyTuple:
if n.len != 2: return nil
@@ -1786,7 +1815,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
if skipTypes(n[1].typ, {tyGenericInst, tyRange, tyOrdinal, tyAlias, tySink}).kind in
{tyInt..tyInt64}:
let idx = getOrdValue(n[1])
if idx >= 0 and idx < arr.len: n.typ = arr[toInt(idx)]
if idx >= 0 and idx < arr.len: n.typ() = arr[toInt(idx)]
else:
localError(c.config, n.info,
"invalid index $1 in subscript for tuple of length $2" %
@@ -1803,7 +1832,12 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
of skProc, skFunc, skMethod, skConverter, skIterator:
# type parameters: partial generic specialization
n[0] = semSymGenericInstantiation(c, n[0], s)
result = maybeInstantiateGeneric(c, n, s)
result = maybeInstantiateGeneric(c, n, s, doError = afterOverloading)
if result != nil and
# leave untyped generic expression alone:
(result.typ == nil or result.typ.kind != tyFromExpr):
# check newly created sym/symchoice
result = semExpr(c, result, flags)
of skMacro, skTemplate:
if efInCall in flags:
# We are processing macroOrTmpl[] in macroOrTmpl[](...) call.
@@ -1878,7 +1912,7 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
localError(c.config, n.info, errExprHasNoAddress)
result = newNodeIT(nkHiddenAddr, n.info, if n.typ.kind in {tyVar, tyLent}: n.typ else: makePtrType(c, n.typ))
if n.typ.kind in {tyVar, tyLent}:
n.typ = n.typ.elementType
n.typ() = n.typ.elementType
result.add(n)
proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
@@ -1987,13 +2021,14 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
# --> `f=` (r, x)
let nOrig = n.copyTree
var flags = {efLValue}
let initialDerefDepth = hiddenDerefDepth(a[0])
a = builtinFieldAccess(c, a, flags)
if a == nil:
a = propertyWriteAccess(c, n, nOrig, n[0])
if a != nil: return a
# we try without the '='; proc that return 'var' or macros are still
# possible:
a = dotTransformation(c, n[0])
a = dotTransformation(c, n[0], initialDerefDepth)
if a.kind == nkDotCall:
a.transitionSonsKind(nkCall)
a = semExprWithType(c, a, {efLValue})
@@ -2046,7 +2081,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
let lhs = n[0]
let rhs = semExprWithType(c, n[1], {efTypeAllowed}, le)
if lhs.kind == nkSym and lhs.sym.kind == skResult:
n.typ = c.enforceVoidContext
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:
@@ -2057,7 +2092,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
internalAssert c.config, c.p.resultSym != nil
# Make sure the type is valid for the result variable
typeAllowedCheck(c, n.info, rhsTyp, skResult)
lhs.typ = rhsTyp
lhs.typ() = rhsTyp
c.p.resultSym.typ = rhsTyp
c.p.owner.typ.setReturnType rhsTyp
else:
@@ -2105,7 +2140,7 @@ proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode =
if result.kind == nkNilLit:
# or ImplicitlyDiscardable(result):
# new semantic: 'result = x' triggers the void context
result.typ = nil
result.typ() = nil
elif result.kind == nkStmtListExpr and result.typ.kind == tyNil:
# to keep backwards compatibility bodies like:
# nil
@@ -2208,7 +2243,7 @@ proc semDefined(c: PContext, n: PNode): PNode =
result = newIntNode(nkIntLit, 0)
result.intVal = ord isDefined(c.config, considerQuotedIdentOrDot(c, n[1], n).s)
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
result.typ() = getSysType(c.graph, n.info, tyBool)
proc lookUpForDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
case n.kind
@@ -2246,7 +2281,7 @@ proc semDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
result = newIntNode(nkIntLit, 0)
result.intVal = ord lookUpForDeclared(c, n[1], onlyCurrentScope) != nil
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
result.typ() = getSysType(c.graph, n.info, tyBool)
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym =
## The argument to the proc should be nkCall(...) or similar
@@ -2319,10 +2354,10 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
localError(c.config, n.info, "getAst takes a call, but got " & n.renderTree)
# Preserve the magic symbol in order to be handled in evals.nim
internalAssert c.config, n[0].sym.magic == mExpandToAst
#n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType
#n.typ() = getSysSym("NimNode").typ # expandedSym.getReturnType
if n.kind == nkStmtList and n.len == 1: result = n[0]
else: result = n
result.typ = sysTypeFromName(c.graph, n.info, "NimNode")
result.typ() = sysTypeFromName(c.graph, n.info, "NimNode")
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
flags: TExprFlags = {}): PNode =
@@ -2492,7 +2527,7 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil))
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
result.typ() = getSysType(c.graph, n.info, tyBool)
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
if n.len == 3:
@@ -2516,8 +2551,8 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
let sym = magicsys.getCompilerProc(c.graph, "nimCreateFlowVar")
if sym == nil:
localError(c.config, info, "system needs: nimCreateFlowVar")
var bindings = initTypeMapping()
bindings.idTablePut(sym.ast[genericParamsPos][0].typ, t)
var bindings = initLayeredTypeMap()
bindings.put(sym.ast[genericParamsPos][0].typ, t)
result = c.semGenerateInstance(c, sym, bindings, info)
# since it's an instantiation, we unmark it as a compilerproc. Otherwise
# codegen would fail:
@@ -2536,7 +2571,7 @@ proc semSizeof(c: PContext, n: PNode): PNode =
else:
n[1] = semExprWithType(c, n[1], {efDetermineType})
#restoreOldStyleType(n[1])
n.typ = getSysType(c.graph, n.info, tyInt)
n.typ() = getSysType(c.graph, n.info, tyInt)
result = foldSizeOf(c.config, n, n)
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: PType = nil): PNode =
@@ -2578,7 +2613,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
markUsed(c, n.info, s)
checkSonsLen(n, 2, c.config)
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
result.typ = getSysType(c.graph, n.info, tyString)
result.typ() = getSysType(c.graph, n.info, tyString)
of mParallel:
markUsed(c, n.info, s)
if parallel notin c.features:
@@ -2604,9 +2639,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
let typ = result[^1].typ
if not typ.isEmptyType:
if spawnResult(typ, c.inParallelStmt > 0) == srFlowVar:
result.typ = createFlowVar(c, typ, n.info)
result.typ() = createFlowVar(c, typ, n.info)
else:
result.typ = typ
result.typ() = typ
result.add instantiateCreateFlowVarCall(c, typ, n.info).newSymNode
else:
result.add c.graph.emptyNode
@@ -2614,7 +2649,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
markUsed(c, n.info, s)
result = setMs(n, s)
result[1] = semExpr(c, n[1])
result.typ = n[1].typ
result.typ() = n[1].typ
of mPlugin:
markUsed(c, n.info, s)
# semDirectOp with conditional 'afterCallActions':
@@ -2745,18 +2780,18 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
else: illFormedAst(n, c.config)
if cannotResolve:
result = semGenericStmt(c, n)
result.typ = makeTypeFromExpr(c, result.copyTree)
result.typ() = makeTypeFromExpr(c, result.copyTree)
return
if result == nil:
result = newNodeI(nkEmpty, n.info)
if whenNimvm:
result.typ = typ
result.typ() = typ
if n.len == 1:
result.add(newTree(nkElse, newNode(nkStmtList)))
proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
result = newNodeI(nkCurly, n.info)
result.typ = newTypeS(tySet, c)
result.typ() = newTypeS(tySet, c)
result.typ.flags.incl tfIsConstructor
var expectedElementType: PType = nil
if expectedType != nil and (
@@ -2782,7 +2817,7 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
if doSetType:
typ = skipTypes(n[i][1].typ,
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
n[i].typ = n[i][2].typ # range node needs type too
n[i].typ() = n[i][2].typ # range node needs type too
elif n[i].kind == nkRange:
# already semchecked
if doSetType:
@@ -2893,11 +2928,14 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType
# hasEmpty/nil check is to not break existing code like
# `const foo = [(1, {}), (2, {false})]`,
# `const foo = if true: (0, nil) else: (1, new(int))`
n[i][1] = fitNode(c, expectedElemType, n[i][1], n[i][1].info)
let conversion = indexTypesMatch(c, expectedElemType, n[i][1].typ, n[i][1])
# ignore matching error, full tuple will be matched later which may call converter, see #24609
if conversion != nil:
n[i][1] = conversion
if n[i][1].typ.kind == tyTypeDesc:
localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.")
n[i][1].typ = errorType(c)
n[i][1].typ() = errorType(c)
var f = newSymS(skField, n[i][0], c)
f.typ = skipIntLit(n[i][1].typ.skipTypes({tySink}), c.idgen)
@@ -2906,7 +2944,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType
typ.n.add newSymNode(f)
n[i][0] = newSymNode(f)
result.add n[i]
result.typ = typ
result.typ() = typ
proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
result = n # we don't modify n, but compute the type:
@@ -2927,7 +2965,7 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedT
# `const foo = if true: (0, nil) else: (1, new(int))`
n[i] = fitNode(c, expectedElemType, n[i], n[i].info)
addSonSkipIntLit(typ, n[i].typ.skipTypes({tySink}), c.idgen)
result.typ = typ
result.typ() = typ
include semobjconstr
@@ -2943,13 +2981,13 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = ni
if sfGenSym notin labl.flags:
addDecl(c, labl)
elif labl.owner == nil:
labl.owner = c.p.owner
setOwner(labl, c.p.owner)
n[0] = newSymNode(labl, n[0].info)
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, expectedType)
n.typ = n[1].typ
n.typ() = n[1].typ
if isEmptyType(n.typ): n.transitionSonsKind(nkBlockStmt)
else: n.transitionSonsKind(nkBlockExpr)
closeScope(c)
@@ -3027,7 +3065,7 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
if isTupleType: # expressions as ``(int, string)`` are reinterpret as type expressions
result = n
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
result.typ = makeTypeDesc(c, typ)
result.typ() = makeTypeDesc(c, typ)
else:
result = tupexp
@@ -3249,10 +3287,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind == typeKind):
result.typ = expected
result.typ() = expected
changeType(c, result, expectedType, check=true)
else:
result.typ = getSysType(c.graph, n.info, typeKind)
result.typ() = getSysType(c.graph, n.info, typeKind)
result = n
when defined(nimsuggest):
@@ -3287,7 +3325,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
# localError(c.config, n.info, errInstantiateXExplicitly, s.name.s)
# "procs literals" are 'owned'
if optOwnedRefs in c.config.globalOptions:
result.typ = makeVarType(c, result.typ, tyOwned)
result.typ() = makeVarType(c, result.typ, tyOwned)
of skEnumField:
result = enumFieldSymChoice(c, n, s, flags)
else:
@@ -3316,11 +3354,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
discard
of nkNilLit:
if result.typ == nil:
result.typ = getNilType(c)
result.typ() = getNilType(c)
if expectedType != nil and expectedType.kind notin {tyUntyped, tyTyped}:
var m = newCandidate(c, result.typ)
if typeRel(m, expectedType, result.typ) >= isSubtype:
result.typ = expectedType
result.typ() = expectedType
# or: result = fitNode(c, expectedType, result, n.info)
of nkIntLit:
if result.typ == nil:
@@ -3348,10 +3386,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind in {tyFloat..tyFloat128}):
result.typ = expected
result.typ() = expected
changeType(c, result, expectedType, check=true)
else:
result.typ = getSysType(c.graph, n.info, tyFloat64)
result.typ() = getSysType(c.graph, n.info, tyFloat64)
of nkFloat32Lit: directLiteral(tyFloat32)
of nkFloat64Lit: directLiteral(tyFloat64)
of nkFloat128Lit: directLiteral(tyFloat128)
@@ -3360,9 +3398,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind in {tyString, tyCstring}):
result.typ = expectedType
result.typ() = expectedType
else:
result.typ = getSysType(c.graph, n.info, tyString)
result.typ() = getSysType(c.graph, n.info, tyString)
of nkCharLit: directLiteral(tyChar)
of nkDotExpr:
result = semFieldAccess(c, n, flags)
@@ -3377,13 +3415,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
let modifier = n.modifierTypeKindOfNode
if modifier != tyNone:
var baseType = semExpr(c, n[0]).typ.skipTypes({tyTypeDesc})
result.typ = c.makeTypeDesc(newTypeS(modifier, c, baseType))
result.typ() = c.makeTypeDesc(newTypeS(modifier, c, baseType))
return
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
result.typ = makeTypeDesc(c, typ)
result.typ() = makeTypeDesc(c, typ)
of nkStmtListType:
let typ = semTypeNode(c, n, nil)
result.typ = makeTypeDesc(c, typ)
result.typ() = makeTypeDesc(c, typ)
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
# check if it is an expression macro:
checkMinSonsLen(n, 1, c.config)

View File

@@ -18,6 +18,15 @@ type
replaceByFieldName: bool
c: PContext
proc wrapNewScope(c: PContext, n: PNode): PNode {.inline.} =
# use `if true` to not interfere with `break`
# just opening scope via `openScope(c)` isn't enough,
# a scope has to be opened in the codegen as well for reused
# template instantiations
let trueLit = newIntLit(c.graph, n.info, 1)
trueLit.typ() = getSysType(c.graph, n.info, tyBool)
result = newTreeI(nkIfStmt, n.info, newTreeI(nkElifBranch, n.info, trueLit, n))
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
if c.field != nil and isEmptyType(c.field.typ):
result = newNode(nkEmpty)
@@ -72,7 +81,9 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
)
openScope(c.c)
inc c.c.inUnrolledContext
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
var body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
# new scope for each field that codegen should know about:
body = wrapNewScope(c.c, body)
father.add(semStmt(c.c, body, {}))
dec c.c.inUnrolledContext
closeScope(c.c)
@@ -148,6 +159,8 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
replaceByFieldName: m == mFieldPairs
)
var body = instFieldLoopBody(fc, loopBody, n)
# new scope for each field that codegen should know about:
body = wrapNewScope(c, body)
inc c.inUnrolledContext
stmts.add(semStmt(c, body, {}))
dec c.inUnrolledContext

View File

@@ -38,7 +38,7 @@ proc newIntNodeT*(intVal: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph):
# original type was 'int', not a distinct int etc.
if n.typ.kind == tyInt:
# access cache for the int lit type
result.typ = getIntLitTypeG(g, result, idgen)
result.typ() = getIntLitTypeG(g, result, idgen)
result.info = n.info
proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
@@ -46,12 +46,12 @@ proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
result = newFloatNode(nkFloat32Lit, floatVal)
else:
result = newFloatNode(nkFloatLit, floatVal)
result.typ = n.typ
result.typ() = n.typ
result.info = n.info
proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode =
result = newStrNode(nkStrLit, strVal)
result.typ = n.typ
result.typ() = n.typ
result.info = n.info
proc getConstExpr*(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
@@ -302,6 +302,9 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
of mMinusSet:
result = nimsets.diffSets(g.config, a, b)
result.info = n.info
of mXorSet:
result = nimsets.symdiffSets(g.config, a, b)
result.info = n.info
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g)
of mInSet: result = newIntNodeT(toInt128(ord(inSet(a, b))), n, idgen, g)
of mRepr:
@@ -316,7 +319,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
of mEnumToStr: result = newStrNodeT(ordinalValToString(a, g), n, g)
of mArrToSeq:
result = copyTree(a)
result.typ = n.typ
result.typ() = n.typ
of mCompileOption:
result = newIntNodeT(toInt128(ord(commands.testCompileOption(g.config, a.getStr, n.info))), n, idgen, g)
of mCompileOptionArg:
@@ -411,7 +414,7 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
result = newIntNodeT(toInt128(a.getOrdValue != 0), n, idgen, g)
of tyBool, tyEnum: # xxx shouldn't we disallow `tyEnum`?
result = a
result.typ = n.typ
result.typ() = n.typ
else:
raiseAssert $srcTyp.kind
of tyInt..tyInt64, tyUInt..tyUInt64:
@@ -428,7 +431,7 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
result = newIntNodeT(val, n, idgen, g)
else:
result = a
result.typ = n.typ
result.typ() = n.typ
if check and result.kind in {nkCharLit..nkUInt64Lit} and
dstTyp.kind notin {tyUInt..tyUInt64}:
rangeCheck(n, getInt(result), g)
@@ -438,12 +441,12 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
result = newFloatNodeT(toFloat64(getOrdValue(a)), n, g)
else:
result = a
result.typ = n.typ
result.typ() = n.typ
of tyOpenArray, tyVarargs, tyProc, tyPointer:
result = nil
else:
result = a
result.typ = n.typ
result.typ() = n.typ
proc getArrayConstr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
if n.kind == nkBracket:
@@ -514,10 +517,10 @@ proc foldConStrStr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
proc newSymNodeTypeDesc*(s: PSym; idgen: IdGenerator; info: TLineInfo): PNode =
result = newSymNode(s, info)
if s.typ.kind != tyTypeDesc:
result.typ = newType(tyTypeDesc, idgen, s.owner)
result.typ() = newType(tyTypeDesc, idgen, s.owner)
result.typ.addSonSkipIntLit(s.typ, idgen)
else:
result.typ = s.typ
result.typ() = s.typ
proc foldDefine(m, s: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode =
result = nil
@@ -586,7 +589,7 @@ proc foldDefine(m, s: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
raise newException(ValueError, "invalid enum value: " & str)
else:
localError(g.config, s.info, "unsupported type $1 for define '$2'" %
[name, typeToString(rawTyp)])
[typeToString(rawTyp), name])
except ValueError as e:
localError(g.config, s.info,
"could not process define '$1' of type $2; $3" %
@@ -636,7 +639,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
if s.typ.kind == tyStatic:
if s.typ.n != nil and tfUnresolved notin s.typ.flags:
result = s.typ.n
result.typ = s.typ.base
result.typ() = s.typ.base
elif s.typ.isIntLit:
result = s.typ.n
else:
@@ -749,7 +752,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
if a == nil: return
if leValueConv(n[1], a) and leValueConv(a, n[2]):
result = a # a <= x and x <= b
result.typ = n.typ
result.typ() = n.typ
elif n.typ.kind in {tyUInt..tyUInt64}:
discard "don't check uints"
else:
@@ -760,7 +763,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
var a = getConstExpr(m, n[0], idgen, g)
if a == nil: return
result = a
result.typ = n.typ
result.typ() = n.typ
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
var a = getConstExpr(m, n[1], idgen, g)
if a == nil: return
@@ -777,7 +780,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
not (n.typ.kind == tyProc and a.typ.kind == tyProc):
# we allow compile-time 'cast' for pointer types:
result = a
result.typ = n.typ
result.typ() = n.typ
of nkBracketExpr: result = foldArrayAccess(m, n, idgen, g)
of nkDotExpr: result = foldFieldAccess(m, n, idgen, g)
of nkCheckedFieldExpr:

View File

@@ -78,10 +78,10 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
if result.kind == nkSym:
result = newOpenSym(result)
else:
result.typ = nil
result.typ() = nil
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
case s.kind
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
@@ -116,7 +116,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
else:
result = n
else:
@@ -126,7 +126,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
onUse(n.info, s)
of skParam:
result = n
@@ -145,7 +145,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
elif c.inGenericContext > 0 and withinConcept notin flags:
# don't leave generic param as identifier node in generic type,
# sigmatch will try to instantiate generic type AST without all params
@@ -157,7 +157,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
else:
result = n
onUse(n.info, s)
@@ -168,7 +168,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
onUse(n.info, s)
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
@@ -218,7 +218,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
let ident = considerQuotedIdent(c, n)
# could be type conversion if like a.T and not a.T()
let symKinds = if inCall: routineKinds else: routineKinds+{skType}
var candidates = searchInScopesFilterBy(c, ident, symKinds)
var candidates = selectFromScopesElseAll(c, ident, symKinds)
if candidates.len > 0:
let s = candidates[0] # XXX take into account the other candidates!
isMacro = s.kind in {skTemplate, skMacro}
@@ -616,7 +616,24 @@ proc semGenericStmt(c: PContext, n: PNode,
let bodyFlags = if n.kind == nkTemplateDef: flags + {withinMixin} else: flags
n[bodyPos] = semGenericStmtScope(c, body, bodyFlags, ctx)
closeScope(c)
of nkPragma, nkPragmaExpr: discard
of nkPragmaExpr:
result[1] = semGenericStmt(c, n[1], flags, ctx)
of nkPragma:
for i in 0 ..< n.len:
let x = n[i]
let prag = whichPragma(x)
if x.kind in nkPragmaCallKinds:
# process each child individually to prevent untyped macros/templates
# from instantiating
# if pragma is language-level pragma, skip name node:
let start = ord(prag != wInvalid)
for j in start ..< x.len:
# treat as mixin context for user pragmas & macro args
x[j] = semGenericStmt(c, x[j], flags+{withinMixin}, ctx)
elif prag == wInvalid:
# only sem if not a language-level pragma
# treat as mixin context for user pragmas & macro args
result[i] = semGenericStmt(c, x, flags+{withinMixin}, ctx)
of nkExprColonExpr, nkExprEqExpr:
checkMinSonsLen(n, 2, c.config)
result[1] = semGenericStmt(c, n[1], flags, ctx)

View File

@@ -34,7 +34,7 @@ proc pushProcCon*(c: PContext; owner: PSym) =
const
errCannotInstantiateX = "cannot instantiate: '$1'"
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TypeMapping): PSym =
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: LayeredIdTable): PSym =
internalAssert c.config, n.kind == nkGenericParams
for a in n.items:
internalAssert c.config, a.kind == nkSym
@@ -43,7 +43,7 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TypeMapping): PS
let symKind = if q.typ.kind == tyStatic: skConst else: skType
var s = newSym(symKind, q.name, c.idgen, getCurrOwner(c), q.info)
s.flags.incl {sfUsed, sfFromGeneric}
var t = idTableGet(pt, q.typ)
var t = lookup(pt, q.typ)
if t == nil:
if tfRetType in q.typ.flags:
# keep the generic type and allow the return type to be bound
@@ -53,7 +53,9 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TypeMapping): PS
if q.typ.kind != tyCompositeTypeClass:
localError(c.config, a.info, errCannotInstantiateX % s.name.s)
t = errorType(c)
elif t.kind in {tyGenericParam, tyConcept, tyFromExpr}:
elif t.kind in {tyGenericParam, tyConcept, tyFromExpr} or
# generic body types are accepted as typedesc arguments
(t.kind == tyGenericBody and q.typ.kind != tyTypeDesc):
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
t = errorType(c)
elif isUnresolvedStatic(t) and (q.typ.kind == tyStatic or
@@ -109,7 +111,7 @@ proc freshGenSyms(c: PContext; n: PNode, owner, orig: PSym, symMap: var SymMappi
elif s.owner == nil or s.owner.kind == skPackage:
#echo "copied this ", s.name.s
x = copySym(s, c.idgen)
x.owner = owner
setOwner(x, owner)
idTablePut(symMap, s, x)
n.sym = x
else:
@@ -220,7 +222,7 @@ proc referencesAnotherParam(n: PNode, p: PSym): bool =
if referencesAnotherParam(n[i], p): return true
return false
proc instantiateProcType(c: PContext, pt: TypeMapping,
proc instantiateProcType(c: PContext, pt: LayeredIdTable,
prc: PSym, info: TLineInfo) =
# XXX: Instantiates a generic proc signature, while at the same
# time adding the instantiated proc params into the current scope.
@@ -237,7 +239,7 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
# will need to use openScope, addDecl, etc.
#addDecl(c, prc)
pushInfoContext(c.config, info)
var typeMap = initLayeredTypeMap(pt)
var typeMap = shallowCopy(pt) # use previous bindings without writing to them
var cl = initTypeVars(c, typeMap, info, nil)
var result = instCopyType(cl, prc.typ)
let originalParams = result.n
@@ -271,7 +273,7 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
internalAssert c.config, originalParams[i].kind == nkSym
let oldParam = originalParams[i].sym
let param = copySym(oldParam, c.idgen)
param.owner = prc
setOwner(param, prc)
param.typ = result[i]
# The default value is instantiated and fitted against the final
@@ -300,7 +302,7 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
# the only way the default value might be inserted).
param.ast = errorNode(c, def)
# we know the node is empty, we need the actual type for error message
param.ast.typ = def.typ
param.ast.typ() = def.typ
else:
param.ast = fitNodePostMatch(c, typeToFit, converted)
param.typ = result[i]
@@ -324,7 +326,7 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
prc.typ = result
popInfoContext(c.config)
proc instantiateOnlyProcType(c: PContext, pt: TypeMapping, prc: PSym, info: TLineInfo): PType =
proc instantiateOnlyProcType(c: PContext, pt: LayeredIdTable, prc: PSym, info: TLineInfo): PType =
# instantiates only the type of a given proc symbol
# used by sigmatch for explicit generics
# wouldn't be needed if sigmatch could handle complex cases,
@@ -360,7 +362,7 @@ proc getLocalPassC(c: PContext, s: PSym): string =
for p in n:
extractPassc(p)
proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
proc generateInstance(c: PContext, fn: PSym, pt: LayeredIdTable,
info: TLineInfo): PSym =
## Generates a new instance of a generic procedure.
## The `pt` parameter is a type-unsafe mapping table used to link generic
@@ -371,7 +373,11 @@ proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
if c.instCounter > 50:
globalError(c.config, info, "generic instantiation too nested")
inc c.instCounter
defer: dec c.instCounter
let currentTypeofContext = c.inTypeofContext
c.inTypeofContext = 0
defer:
dec c.instCounter
c.inTypeofContext = currentTypeofContext
# careful! we copy the whole AST including the possibly nil body!
var n = copyTree(fn.ast)
# NOTE: for access of private fields within generics from a different module
@@ -389,9 +395,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
let passc = getLocalPassC(c, producer)
if passc != "": #pass the local compiler options to the consumer module too
extccomp.addLocalCompileOption(c.config, passc, toFullPathConsiderDirty(c.config, c.module.info.fileIndex))
result.owner = c.module
setOwner(result, c.module)
else:
result.owner = fn
setOwner(result, fn)
result.ast = n
pushOwner(c, result)

View File

@@ -10,9 +10,28 @@
## Implements type sanity checking for ASTs resulting from macros. Lots of
## room for improvement here.
import ast, msgs, types, options
import ast, msgs, types, options, trees, nimsets
proc ithField(n: PNode, field: var int): PSym =
type
FieldTracker = object
index: int
remaining: int
constr: PNode
delete: bool # to delete fields from inactive case branches
FieldInfo = ref object
sym: PSym
delete: bool
proc caseBranchMatchesExpr(branch, matched: PNode): bool =
# copied from sem
result = false
for i in 0 ..< branch.len-1:
if branch[i].kind == nkRange:
if overlap(branch[i], matched): return true
elif exprStructuralEquivalent(branch[i], matched):
return true
proc ithField(n: PNode, field: var FieldTracker): FieldInfo =
result = nil
case n.kind
of nkRecList:
@@ -23,18 +42,42 @@ proc ithField(n: PNode, field: var int): PSym =
if n[0].kind != nkSym: return
result = ithField(n[0], field)
if result != nil: return
# value of the discriminator field, from (index - remaining - 1 + 1):
# - 1 because the `ithField` call above decreased it by 1,
# + 1 because the constructor node has an initial type child
let val = field.constr[field.index - field.remaining][1]
var branchFound = false
for i in 1..<n.len:
let previousDelete = field.delete
case n[i].kind
of nkOfBranch, nkElse:
of nkOfBranch:
if branchFound or previousDelete or
not caseBranchMatchesExpr(n[i], val):
# if this is not the active case branch,
# mark all fields inside as deleted
field.delete = true
else:
branchFound = true
result = ithField(lastSon(n[i]), field)
if result != nil: return
field.delete = previousDelete
of nkElse:
if branchFound:
# if this is not the active case branch,
# mark all fields inside as deleted
field.delete = true
result = ithField(lastSon(n[i]), field)
if result != nil: return
field.delete = previousDelete
else: discard
of nkSym:
if field == 0: result = n.sym
else: dec(field)
if field.remaining == 0:
result = FieldInfo(sym: n.sym, delete: field.delete)
else:
dec(field.remaining)
else: discard
proc ithField(t: PType, field: var int): PSym =
proc ithField(t: PType, field: var FieldTracker): FieldInfo =
var base = t.baseClass
while base != nil:
let b = skipTypes(base, skipPtrs)
@@ -50,24 +93,27 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
case n.kind
of nkObjConstr:
let x = t.skipTypes(abstractPtrs)
n.typ = t
n[0].typ = t
n.typ() = t
n[0].typ() = t
for i in 1..<n.len:
var j = i-1
let field = x.ithField(j)
var tracker = FieldTracker(index: i-1, remaining: i-1, constr: n, delete: false)
let field = x.ithField(tracker)
if field.isNil:
globalError conf, n.info, "invalid field at index " & $i
else:
internalAssert(conf, n[i].kind == nkExprColonExpr)
annotateType(n[i][1], field.typ, conf)
annotateType(n[i][1], field.sym.typ, conf)
if field.delete:
# only codegen fields from active case branches
incl(n[i].flags, nfPreventCg)
of nkPar, nkTupleConstr:
if x.kind == tyTuple:
n.typ = t
n.typ() = t
for i in 0..<n.len:
if i >= x.kidsLen: 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
n.typ() = t
elif x.kind == tyOpenArray: # `opcSlice` transforms slices into tuples
if n.kind == nkTupleConstr:
let
@@ -88,39 +134,39 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
globalError(conf, n.info, "Incorrectly generated tuple constr")
n[] = bracketExpr[]
n.typ = t
n.typ() = t
else:
globalError(conf, n.info, "() must have a tuple type")
of nkBracket:
if x.kind in {tyArray, tySequence, tyOpenArray}:
n.typ = t
n.typ() = t
for m in n: annotateType(m, x.elemType, conf)
else:
globalError(conf, n.info, "[] must have some form of array type")
of nkCurly:
if x.kind in {tySet}:
n.typ = t
n.typ() = t
for m in n: annotateType(m, x.elemType, conf)
else:
globalError(conf, n.info, "{} must have the set type")
of nkFloatLit..nkFloat128Lit:
if x.kind in {tyFloat..tyFloat128}:
n.typ = t
n.typ() = t
else:
globalError(conf, n.info, "float literal must have some float type")
of nkCharLit..nkUInt64Lit:
if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
n.typ = t
n.typ() = t
else:
globalError(conf, n.info, "integer literal must have some int type")
of nkStrLit..nkTripleStrLit:
if x.kind in {tyString, tyCstring}:
n.typ = t
n.typ() = t
else:
globalError(conf, n.info, "string literal must be of some string type")
of nkNilLit:
if x.kind in NilableTypes+{tyString, tySequence}:
n.typ = t
n.typ() = t
else:
globalError(conf, n.info, "nil literal must be of some pointer type")
else: discard

View File

@@ -18,7 +18,7 @@ proc addDefaultFieldForNew(c: PContext, n: PNode): PNode =
let typ = result[1].typ # new(x)
if typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyRef and typ.skipTypes({tyGenericInst, tyAlias, tySink})[0].kind == tyObject:
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[1].info, typ))
asgnExpr.typ = typ
asgnExpr.typ() = typ
var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0]
while true:
asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n, false)
@@ -38,7 +38,7 @@ proc semAddr(c: PContext; n: PNode): PNode =
if isAssignable(c, x) notin {arLValue, arLocalLValue, arAddressableConst, arLentValue}:
localError(c.config, n.info, errExprHasNoAddress)
result.add x
result.typ = makePtrType(c, x.typ)
result.typ() = makePtrType(c, x.typ)
proc semTypeOf(c: PContext; n: PNode): PNode =
var m = BiggestInt 1 # typeOfIter
@@ -55,18 +55,18 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
result.add typExpr
if typExpr.typ.kind == tyFromExpr:
typExpr.typ.flags.incl tfNonConstExpr
result.typ = makeTypeDesc(c, typExpr.typ)
result.typ() = makeTypeDesc(c, typExpr.typ)
type
SemAsgnMode = enum asgnNormal, noOverloadedSubscript, noOverloadedAsgn
proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags, afterOverloading = false): PNode
proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
result = newNodeI(nkBracketExpr, n.info)
for i in 1..<n.len: result.add(n[i])
result = semSubscript(c, result, flags)
result = semSubscript(c, result, flags, afterOverloading = true)
if result.isNil:
let x = copyTree(n)
x[0] = newIdentNode(getIdent(c.cache, "[]"), n.info)
@@ -76,12 +76,23 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
if a.typ != nil and a.typ.kind in {tyGenericParam, tyFromExpr}:
# expression is compiled early in a generic body
result = semGenericStmt(c, x)
result.typ = makeTypeFromExpr(c, copyTree(result))
result.typ() = makeTypeFromExpr(c, copyTree(result))
result.typ.flags.incl tfNonConstExpr
return
bracketNotFoundError(c, x, flags)
#localError(c.config, n.info, "could not resolve: " & $n)
result = errorNode(c, n)
let s = # extract sym from first arg
if n.len > 1:
if n[1].kind == nkSym: n[1].sym
elif n[1].kind in nkSymChoices + {nkOpenSym} and n[1].len != 0:
n[1][0].sym
else: nil
else: nil
if s != nil and s.kind in routineKinds:
# this is a failed generic instantiation
# semSubscript should already error but this is better for cascading errors
result = explicitGenericInstError(c, n)
else:
bracketNotFoundError(c, x, flags)
result = errorNode(c, n)
proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
# rewrite `[]=`(a, i, x) back to ``a[i] = x``.
@@ -189,15 +200,15 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
let preferStr = traitCall[2].strVal
prefer = parseEnum[TPreferedDesc](preferStr)
result = newStrNode(nkStrLit, operand.typeToString(prefer))
result.typ = getSysType(c.graph, traitCall[1].info, tyString)
result.typ() = getSysType(c.graph, traitCall[1].info, tyString)
result.info = traitCall.info
of "name", "$":
result = newStrNode(nkStrLit, operand.typeToString(preferTypeName))
result.typ = getSysType(c.graph, traitCall[1].info, tyString)
result.typ() = getSysType(c.graph, traitCall[1].info, tyString)
result.info = traitCall.info
of "arity":
result = newIntNode(nkIntLit, operand.len - ord(operand.kind==tyProc))
result.typ = newType(tyInt, c.idgen, context)
result.typ() = newType(tyInt, c.idgen, context)
result.info = traitCall.info
of "genericHead":
var arg = operand
@@ -267,7 +278,7 @@ proc semOrd(c: PContext, n: PNode): PNode =
discard
else:
localError(c.config, n.info, errOrdinalTypeExpected % typeToString(parType, preferDesc))
result.typ = errorType(c)
result.typ() = errorType(c)
proc semBindSym(c: PContext, n: PNode): PNode =
result = copyNode(n)
@@ -383,7 +394,7 @@ proc semOf(c: PContext, n: PNode): PNode =
message(c.config, n.info, hintConditionAlwaysTrue, renderTree(n))
result = newIntNode(nkIntLit, 1)
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
result.typ() = getSysType(c.graph, n.info, tyBool)
return result
elif diff == high(int):
if commonSuperclass(a, b) == nil:
@@ -392,10 +403,10 @@ proc semOf(c: PContext, n: PNode): PNode =
message(c.config, n.info, hintConditionAlwaysFalse, renderTree(n))
result = newIntNode(nkIntLit, 0)
result.info = n.info
result.typ = getSysType(c.graph, n.info, tyBool)
result.typ() = getSysType(c.graph, n.info, tyBool)
else:
localError(c.config, n.info, "'of' takes 2 arguments")
n.typ = getSysType(c.graph, n.info, tyBool)
n.typ() = getSysType(c.graph, n.info, tyBool)
result = n
proc semUnown(c: PContext; n: PNode): PNode =
@@ -430,9 +441,9 @@ proc semUnown(c: PContext; n: PNode): PNode =
result = t
result = copyTree(n[1])
result.typ = unownedType(c, result.typ)
result.typ() = unownedType(c, result.typ)
# little hack for injectdestructors.nim (see bug #11350):
#result[0].typ = nil
#result[0].typ() = nil
proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym =
# We need to do 2 things: Replace n.typ which is a 'ref T' by a 'var T' type.
@@ -442,7 +453,7 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym
proc transform(c: PContext; n: PNode; old, fresh: PType; oldParam, newParam: PSym): PNode =
result = shallowCopy(n)
if sameTypeOrNil(n.typ, old):
result.typ = fresh
result.typ() = fresh
if n.kind == nkSym and n.sym == oldParam:
result.sym = newParam
for i in 0 ..< safeLen(n):
@@ -453,7 +464,7 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym
result = copySym(orig, c.idgen)
result.info = info
result.flags.incl sfFromGeneric
result.owner = orig
setOwner(result, orig)
let origParamType = orig.typ.firstParamType
let newParamType = makeVarType(result, origParamType.skipTypes(abstractPtrs), c.idgen)
let oldParam = orig.typ.n[1].sym
@@ -524,32 +535,34 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
discard "already turned this one into a finalizer"
else:
if fin.instantiatedFrom != nil and fin.instantiatedFrom != fin.owner: #undo move
fin.owner = fin.instantiatedFrom
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), c.idgen, fin.owner, fin.info)
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, c.idgen))
selfSymNode.typ = fin.typ.firstParamType
wrapperSym.flags.incl sfUsed
setOwner(fin, fin.instantiatedFrom)
let wrapper = c.semExpr(c, newProcNode(nkProcDef, fin.info, body = newTree(nkCall, newSymNode(fin), selfSymNode),
params = nkFormalParams.newTree(c.graph.emptyNode,
newTree(nkIdentDefs, selfSymNode, newNodeIT(nkType,
fin.ast[paramsPos][1][1].info, fin.typ.firstParamType), c.graph.emptyNode)
),
name = newSymNode(wrapperSym), pattern = fin.ast[patternPos],
genericParams = fin.ast[genericParamsPos], pragmas = fin.ast[pragmasPos], exceptions = fin.ast[miscPos]), {})
if fin.typ[1].skipTypes(abstractInst).kind != tyRef:
bindTypeHook(c, fin, n, attachedDestructor)
else:
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), c.idgen, fin.owner, fin.info)
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, c.idgen))
selfSymNode.typ() = fin.typ.firstParamType
wrapperSym.flags.incl sfUsed
var transFormedSym = turnFinalizerIntoDestructor(c, wrapperSym, wrapper.info)
transFormedSym.owner = fin
if c.config.backend == backendCpp or sfCompileToCpp in c.module.flags:
let origParamType = transFormedSym.ast[bodyPos][1].typ
let selfSymbolType = makePtrType(c, origParamType.skipTypes(abstractPtrs))
let selfPtr = newNodeI(nkHiddenAddr, transFormedSym.ast[bodyPos][1].info)
selfPtr.add transFormedSym.ast[bodyPos][1]
selfPtr.typ = selfSymbolType
transFormedSym.ast[bodyPos][1] = c.semExpr(c, selfPtr)
# TODO: suppress var destructor warnings; if newFinalizer is not
# TODO: deprecated, try to implement plain T destructor
bindTypeHook(c, transFormedSym, n, attachedDestructor, suppressVarDestructorWarning = true)
let wrapper = c.semExpr(c, newProcNode(nkProcDef, fin.info, body = newTree(nkCall, newSymNode(fin), selfSymNode),
params = nkFormalParams.newTree(c.graph.emptyNode,
newTree(nkIdentDefs, selfSymNode, newNodeIT(nkType,
fin.ast[paramsPos][1][1].info, fin.typ.firstParamType), c.graph.emptyNode)
),
name = newSymNode(wrapperSym), pattern = fin.ast[patternPos],
genericParams = fin.ast[genericParamsPos], pragmas = fin.ast[pragmasPos], exceptions = fin.ast[miscPos]), {})
var transFormedSym = turnFinalizerIntoDestructor(c, wrapperSym, wrapper.info)
setOwner(transFormedSym, fin)
if c.config.backend == backendCpp or sfCompileToCpp in c.module.flags:
let origParamType = transFormedSym.ast[bodyPos][1].typ
let selfSymbolType = makePtrType(c, origParamType.skipTypes(abstractPtrs))
let selfPtr = newNodeI(nkHiddenAddr, transFormedSym.ast[bodyPos][1].info)
selfPtr.add transFormedSym.ast[bodyPos][1]
selfPtr.typ() = selfSymbolType
transFormedSym.ast[bodyPos][1] = c.semExpr(c, selfPtr)
bindTypeHook(c, transFormedSym, n, attachedDestructor)
result = addDefaultFieldForNew(c, n)
proc semPrivateAccess(c: PContext, n: PNode): PNode =
@@ -601,7 +614,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mTypeTrait: result = semTypeTraits(c, n)
of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
result.typ = getSysType(c.graph, n.info, tyString)
result.typ() = getSysType(c.graph, n.info, tyString)
of mInstantiationInfo: result = semInstantiationInfo(c, n)
of mOrd: result = semOrd(c, n)
of mOf: result = semOf(c, n)
@@ -614,7 +627,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result = semDynamicBindSym(c, n)
of mProcCall:
result = n
result.typ = n[1].typ
result.typ() = n[1].typ
of mDotDot:
result = n
of mPlugin:
@@ -657,7 +670,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result[0] = newSymNode(op)
if op.typ.len == 3:
let boolLit = newIntLit(c.graph, n.info, 1)
boolLit.typ = getSysType(c.graph, n.info, tyBool)
boolLit.typ() = getSysType(c.graph, n.info, tyBool)
result.add boolLit
of mWasMoved:
result = n
@@ -699,7 +712,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result = n
if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and
expectedType.kind == tySequence and result.typ.elementType.kind == tyEmpty:
result.typ = expectedType # type inference for empty sequence # bug #21377
result.typ() = expectedType # type inference for empty sequence # bug #21377
of mEnsureMove:
result = n
if n[1].kind in {nkStmtListExpr, nkBlockExpr,

View File

@@ -79,7 +79,7 @@ proc semConstrField(c: PContext, flags: TExprFlags,
if nfSkipFieldChecking in assignment[1].flags:
discard
elif not fieldVisible(c, field):
localError(c.config, initExpr.info,
localError(c.config, assignment[0].info,
"the field '$1' is not accessible." % [field.name.s])
return
@@ -188,7 +188,7 @@ proc collectOrAddMissingCaseFields(c: PContext, branchNode: PNode,
newNodeIT(nkType, constrCtx.initExpr.info, asgnType)
)
asgnExpr.flags.incl nfSkipFieldChecking
asgnExpr.typ = recTyp
asgnExpr.typ() = recTyp
defaults.add newTree(nkExprColonExpr, newSymNode(sym), asgnExpr)
proc collectBranchFields(c: PContext, n: PNode, discriminatorVal: PNode,
@@ -465,17 +465,20 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
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
when false:
# attempted type inference for generic object types,
# doesn't work since n[0] isn't set and seems underspecified
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:
t = skipTypes(t.elementType, {tyGenericInst, tyAlias, tySink, tyOwned})
if optOwnedRefs in c.config.globalOptions:
result.typ = makeVarType(c, result.typ, tyOwned)
result.typ() = makeVarType(c, result.typ, tyOwned)
# we have to watch out, there are also 'owned proc' types that can be used
# multiple times as long as they don't have closures.
result.typ.flags.incl tfHasOwned
@@ -518,7 +521,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
for j in 1..<i:
let prevId = considerQuotedIdent(c, result[j][0])
if prevId.id == id.id:
localError(c.config, field.info, errFieldInitTwice % id.s)
localError(c.config, field[0].info, errFieldInitTwice % id.s)
hasError = true
break
# 2) No such field exists in the constructed type

View File

@@ -407,9 +407,9 @@ proc transformSlices(g: ModuleGraph; idgen: IdGenerator; n: PNode): PNode =
result = copyNode(n)
var typ = newType(tyOpenArray, idgen, result.typ.owner)
typ.add result.typ.elementType
result.typ = typ
result.typ() = typ
let opSlice = newSymNode(createMagic(g, idgen, "slice", mSlice))
opSlice.typ = getSysType(g, n.info, tyInt)
opSlice.typ() = getSysType(g, n.info, tyInt)
result.add opSlice
result.add n[1]
let slice = n[2].skipStmtList

View File

@@ -124,10 +124,11 @@ proc collectObjectTree(graph: ModuleGraph, n: PNode) =
else:
graph.objectTree[root].add (depthLevel, typ)
proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
if typ == nil or sfGeneratedOp in tracked.owner.flags:
proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo; explicit = false) =
if typ == nil or (sfGeneratedOp in tracked.owner.flags and not explicit):
# don't create type bound ops for anything in a function with a `nodestroy` pragma
# bug #21987
# unless this is an explicit call, bug #24626
return
when false:
let realType = typ.skipTypes(abstractInst)
@@ -193,7 +194,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
let dot = newNodeI(nkDotExpr, n.info, 2)
dot[0] = n[0]
dot[1] = newSymNode(g)
dot.typ = g.typ
dot.typ() = g.typ
for L in a.locked:
#if a.guards.sameSubexprs(dot, L): return
if guards.sameTree(dot, L): return
@@ -212,6 +213,7 @@ proc varDecl(a: PEffects; n: PNode) {.inline.} =
proc skipHiddenDeref(n: PNode): PNode {.inline.} =
result = if n.kind == nkHiddenDeref: n[0] else: n
proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
let n = skipHiddenDeref(n)
if n.kind != nkSym: return
@@ -411,7 +413,7 @@ proc throws(tracked, n, orig: PNode) =
if n.typ == nil or n.typ.kind != tyError:
if orig != nil:
let x = copyTree(orig)
x.typ = n.typ
x.typ() = n.typ
tracked.add x
else:
tracked.add n
@@ -426,12 +428,12 @@ proc excType(g: ModuleGraph; n: PNode): PType =
proc createRaise(g: ModuleGraph; n: PNode): PNode =
result = newNode(nkType)
result.typ = getEbase(g, n.info)
result.typ() = getEbase(g, n.info)
if not n.isNil: result.info = n.info
proc createTag(g: ModuleGraph; n: PNode): PNode =
result = newNode(nkType)
result.typ = g.sysTypeFromName(n.info, "RootEffect")
result.typ() = g.sysTypeFromName(n.info, "RootEffect")
if not n.isNil: result.info = n.info
proc addRaiseEffect(a: PEffects, e, comesFrom: PNode) =
@@ -1071,7 +1073,7 @@ proc trackCall(tracked: PEffects; n: PNode) =
# rebind type bounds operations after createTypeBoundOps call
let t = n[1].typ.skipTypes({tyAlias, tyVar})
if a.sym != getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind)):
createTypeBoundOps(tracked, t, n.info)
createTypeBoundOps(tracked, t, n.info, explicit = true)
let op = getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind))
if op != nil:
n[0].sym = op
@@ -1210,7 +1212,7 @@ proc track(tracked: PEffects, n: PNode) =
if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags:
tracked.owner.flags.incl sfInjectDestructors
# bug #15038: ensure consistency
if n.typ == nil or (not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ)): n.typ = n.sym.typ
if n.typ == nil or (not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ)): n.typ() = n.sym.typ
of nkHiddenAddr, nkAddr:
if n[0].kind == nkSym and isLocalSym(tracked, n[0].sym) and
n.typ.kind notin {tyVar, tyLent}:
@@ -1301,7 +1303,12 @@ proc track(tracked: PEffects, n: PNode) =
let last = lastSon(child)
track(tracked, last)
of nkCaseStmt: trackCase(tracked, n)
of nkWhen, nkIfStmt, nkIfExpr: trackIf(tracked, n)
of nkWhen: # This should be a "when nimvm" node.
let oldState = tracked.init.len
track(tracked, n[0][1])
tracked.init.setLen(oldState)
track(tracked, n[1][0])
of nkIfStmt, nkIfExpr: trackIf(tracked, n)
of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n[1])
of nkWhileStmt:
# 'while true' loop?
@@ -1638,6 +1645,9 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
s.kind in {skProc, skFunc, skConverter, skMethod}:
var res = s.ast[resultPos].sym # get result symbol
t.scopes[res.id] = t.currentBlock
if sfNoInit in s.flags:
# marks result "noinit"
incl res.flags, sfNoInit
track(t, body)
@@ -1650,13 +1660,14 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
(t.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
(isClosure(typ.skipTypes(abstractInst)) or param.id in t.escapingParams)):
createTypeBoundOps(t, typ, param.info)
if isOutParam(typ) and param.id notin t.init:
if isOutParam(typ) and param.id notin t.init and s.magic == mNone:
message(g.config, param.info, warnProveInit, param.name.s)
if not isEmptyType(s.typ.returnType) and
(s.typ.returnType.requiresInit or s.typ.returnType.skipTypes(abstractInst).kind == tyVar or
strictDefs in c.features) and
s.kind in {skProc, skFunc, skConverter, skMethod} and s.magic == mNone:
s.kind in {skProc, skFunc, skConverter, skMethod} and s.magic == mNone and
sfNoInit notin s.flags:
var res = s.ast[resultPos].sym # get result symbol
if res.id notin t.init and breaksBlock(body) != bsNoReturn:
if tfRequiresInit in s.typ.returnType.flags:

View File

@@ -112,11 +112,11 @@ proc semWhile(c: PContext, n: PNode; flags: TExprFlags): PNode =
dec(c.p.nestedLoopCounter)
closeScope(c)
if n[1].typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
result.typ() = c.enforceVoidContext
elif efInTypeof in flags:
result.typ = n[1].typ
result.typ() = n[1].typ
elif implicitlyDiscardable(n[1]):
result[1].typ = c.enforceVoidContext
result[1].typ() = c.enforceVoidContext
proc semProc(c: PContext, n: PNode): PNode
@@ -275,7 +275,7 @@ proc fixNilType(c: PContext; n: PNode) =
elif n.kind in {nkStmtList, nkStmtListExpr}:
n.transitionSonsKind(nkStmtList)
for it in n: fixNilType(c, it)
n.typ = nil
n.typ() = nil
proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
if c.matchedConcept != nil or efInTypeof in flags: return
@@ -331,14 +331,14 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil):
for it in n: discardCheck(c, it.lastSon, flags)
result.transitionSonsKind(nkIfStmt)
# propagate any enforced VoidContext:
if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext
if typ == c.enforceVoidContext: result.typ() = c.enforceVoidContext
else:
for it in n:
let j = it.len-1
if not endsInNoReturn(it[j]):
it[j] = fitNode(c, typ, it[j], it[j].info)
result.transitionSonsKind(nkIfExpr)
result.typ = typ
result.typ() = typ
proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
var check = initIntSet()
@@ -438,7 +438,7 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
discardCheck(c, n[0], flags)
for i in 1..<n.len: discardCheck(c, n[i].lastSon, flags)
if typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
result.typ() = c.enforceVoidContext
else:
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags)
if not endsInNoReturn(n[0]):
@@ -448,7 +448,7 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
let j = it.len-1
if not endsInNoReturn(it[j]):
it[j] = fitNode(c, typ, it[j], it[j].info)
result.typ = typ
result.typ() = typ
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
result = fitNode(c, typ, n, n.info)
@@ -457,7 +457,7 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
if r1.kind in {nkCharLit..nkUInt64Lit} and typ.skipTypes(abstractRange).kind in {tyFloat..tyFloat128}:
result = newFloatNode(nkFloatLit, BiggestFloat r1.intVal)
result.info = n.info
result.typ = typ
result.typ() = typ
if not floatRangeCheck(result.floatVal, typ):
localError(c.config, n.info, errFloatToString % [$result.floatVal, typeToString(typ)])
elif r1.kind == nkSym and typ.skipTypes(abstractRange).kind == tyCstring:
@@ -492,19 +492,8 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind, reportToNimsuggest = tru
incl(result.flags, sfGlobal)
result.options = c.config.options
proc getLineInfo(n: PNode): TLineInfo =
case n.kind
of nkPostfix:
if len(n) > 1:
return getLineInfo(n[1])
of nkAccQuoted, nkPragmaExpr:
if len(n) > 0:
return getLineInfo(n[0])
else:
discard
result = n.info
let info = getLineInfo(n)
if reportToNimsuggest:
let info = getLineInfo(n)
suggestSym(c.graph, info, result, c.graph.usageSym)
proc checkNilable(c: PContext; v: PSym) =
@@ -605,18 +594,45 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
obj.n.add newSymNode(field)
n[0] = makeDeref x
n[1] = newSymNode(field)
n.typ = field.typ
n.typ() = field.typ
else:
localError(c.config, n.info, "implicit object field construction " &
"requires a .partial object, but got " & typeToString(obj))
else:
localError(c.config, n.info, "nkDotNode requires 2 children")
proc checkDefineType(c: PContext; v: PSym; t: PType) =
# see semfold.foldDefine for acceptable types
let typeKinds =
case v.magic
of mStrDefine: {tyString, tyCstring}
# this used to be not typechecked, so anything that accepts int nodes for compatbility:
of mIntDefine: {tyInt..tyInt64, tyUInt..tyUInt64, tyBool, tyChar, tyEnum}
of mBoolDefine: {tyBool}
of mGenericDefine: {tyString, tyCstring, tyInt..tyInt64, tyUInt..tyUInt64, tyBool, tyEnum}
else: raiseAssert("unreachable")
var skipped = abstractVarRange
if v.magic == mGenericDefine:
# no distinct types for generic define
skipped.excl tyDistinct
if t.skipTypes(skipped).kind notin typeKinds:
let name =
case v.magic
of mStrDefine: "strdefine"
of mIntDefine: "intdefine"
of mBoolDefine: "booldefine"
of mGenericDefine: "define"
else: raiseAssert("unreachable")
localError(c.config, v.info, "unsupported type for constant '" & v.name.s &
"' with ." & name & " pragma: " & typeToString(t))
proc setVarType(c: PContext; v: PSym, typ: PType) =
if v.typ != nil and not sameTypeOrNil(v.typ, typ):
localError(c.config, v.info, "inconsistent typing for reintroduced symbol '" &
v.name.s & "': previous type was: " & typeToString(v.typ, preferDesc) &
"; new type is: " & typeToString(typ, preferDesc))
if v.kind == skConst and v.magic in {mGenericDefine, mIntDefine, mStrDefine, mBoolDefine}:
checkDefineType(c, v, typ)
v.typ = typ
proc isPossibleMacroPragma(c: PContext, it: PNode, key: PNode): bool =
@@ -908,7 +924,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if sfGenSym notin v.flags:
if not isDiscardUnderscore(v): addInterfaceDecl(c, v)
else:
if v.owner == nil: v.owner = c.p.owner
if v.owner == nil: setOwner(v, c.p.owner)
when oKeepVariableNames:
if c.inUnrolledContext > 0: v.flags.incl(sfShadowed)
else:
@@ -1026,7 +1042,7 @@ proc semConst(c: PContext, n: PNode): PNode =
when defined(nimsuggest):
v.hasUserSpecifiedType = hasUserSpecifiedType
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
elif v.owner == nil: v.owner = getCurrOwner(c)
elif v.owner == nil: setOwner(v, getCurrOwner(c))
styleCheckDef(c, v)
onDef(a[j].info, v)
@@ -1097,7 +1113,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
v.typ = iter[i]
n[0][i] = newSymNode(v)
if sfGenSym notin v.flags and not isDiscardUnderscore(v): addDecl(c, v)
elif v.owner == nil: v.owner = getCurrOwner(c)
elif v.owner == nil: setOwner(v, getCurrOwner(c))
else:
var v = symForVar(c, n[0])
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
@@ -1107,7 +1123,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
v.typ = iterBase
n[0] = newSymNode(v)
if sfGenSym notin v.flags and not isDiscardUnderscore(v): addDecl(c, v)
elif v.owner == nil: v.owner = getCurrOwner(c)
elif v.owner == nil: setOwner(v, getCurrOwner(c))
else:
localError(c.config, n.info, errWrongNumberOfVariables)
elif n.len-2 != iterAfterVarLent.len:
@@ -1141,7 +1157,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
v.typ = iter[i][j]
n[i][j] = newSymNode(v)
if not isDiscardUnderscore(v): addDecl(c, v)
elif v.owner == nil: v.owner = getCurrOwner(c)
elif v.owner == nil: setOwner(v, getCurrOwner(c))
else:
var v = symForVar(c, n[i])
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
@@ -1156,7 +1172,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
n[i] = newSymNode(v)
if sfGenSym notin v.flags:
if not isDiscardUnderscore(v): addDecl(c, v)
elif v.owner == nil: v.owner = getCurrOwner(c)
elif v.owner == nil: setOwner(v, getCurrOwner(c))
inc(c.p.nestedLoopCounter)
let oldBreakInLoop = c.p.breakInLoop
c.p.breakInLoop = true
@@ -1291,9 +1307,9 @@ proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode =
result = semForVars(c, n, flags)
# propagate any enforced VoidContext:
if n[^1].typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
result.typ() = c.enforceVoidContext
elif efInTypeof in flags:
result.typ = result.lastSon.typ
result.typ() = result.lastSon.typ
closeScope(c)
proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
@@ -1373,14 +1389,14 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil
for i in 1..<n.len: discardCheck(c, n[i].lastSon, flags)
# propagate any enforced VoidContext:
if typ == c.enforceVoidContext:
result.typ = c.enforceVoidContext
result.typ() = c.enforceVoidContext
else:
for i in 1..<n.len:
var it = n[i]
let j = it.len-1
if not endsInNoReturn(it[j]):
it[j] = fitNode(c, typ, it[j], it[j].info)
result.typ = typ
result.typ() = typ
proc semRaise(c: PContext, n: PNode): PNode =
result = n
@@ -1475,7 +1491,7 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) =
s = typsym
# add it here, so that recursive types are possible:
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
elif s.owner == nil: s.owner = getCurrOwner(c)
elif s.owner == nil: setOwner(s, getCurrOwner(c))
if name.kind == nkPragmaExpr:
if name[0].kind == nkPostfix:
@@ -1698,12 +1714,14 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
obj.ast[0] = a[0].shallowCopy
if a[0][0].kind == nkPostfix:
obj.ast[0][0] = a[0][0].shallowCopy
obj.ast[0][0][0] = a[0][0][0] # ident "*"
obj.ast[0][0][1] = symNode
else:
obj.ast[0][0] = symNode
obj.ast[0][1] = a[0][1]
of nkPostfix:
obj.ast[0] = a[0].shallowCopy
obj.ast[0][0] = a[0][0] # ident "*"
obj.ast[0][1] = symNode
else: assert(false)
obj.ast[1] = a[1]
@@ -1758,6 +1776,17 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
# check the style here after the pragmas have been processed:
styleCheckDef(c, s)
# compute the type's size and check for illegal recursions:
if a[0].kind == nkPragmaExpr:
let pragmas = a[0][1]
for i in 0 ..< pragmas.len:
if pragmas[i].kind == nkExprColonExpr and
pragmas[i][0].kind == nkIdent and
whichKeyword(pragmas[i][0].ident) == wSize:
if s.typ.kind != tyEnum and sfImportc notin s.flags:
# EventType* {.size: sizeof(uint32).} = enum
# AtomicFlag* {.importc: "atomic_flag", header: "<stdatomic.h>", size: 1.} = object
localError(c.config, pragmas[i].info, "size pragma only allowed for enum types and imported types")
if a[1].kind == nkEmpty:
var x = a[2]
if x.kind in nkCallKinds and nfSem in x.flags:
@@ -1969,13 +1998,13 @@ proc semProcAnnotation(c: PContext, prc: PNode;
return result
proc semInferredLambda(c: PContext, pt: TypeMapping, n: PNode): PNode =
proc semInferredLambda(c: PContext, pt: LayeredIdTable, n: PNode): PNode =
## used for resolving 'auto' in lambdas based on their callsite
var n = n
let original = n[namePos].sym
let s = original #copySym(original, false)
#incl(s.flags, sfFromGeneric)
#s.owner = original
#s.owner() = original
n = replaceTypesInBody(c, pt, n, original)
result = n
@@ -1990,7 +2019,7 @@ proc semInferredLambda(c: PContext, pt: TypeMapping, n: PNode): PNode =
tyFromExpr}+tyTypeClasses:
localError(c.config, params[i].info, "cannot infer type of parameter: " &
params[i].sym.name.s)
#params[i].sym.owner = s
#params[i].sym.owner() = s
openScope(c)
pushOwner(c, s)
addParams(c, params, skProc)
@@ -2002,7 +2031,7 @@ proc semInferredLambda(c: PContext, pt: TypeMapping, n: PNode): PNode =
popOwner(c)
closeScope(c)
if optOwnedRefs in c.config.globalOptions and result.typ != nil:
result.typ = makeVarType(c, result.typ, tyOwned)
result.typ() = makeVarType(c, result.typ, tyOwned)
# alternative variant (not quite working):
# var prc = arg[0].sym
# let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
@@ -2035,14 +2064,27 @@ proc canonType(c: PContext, t: PType): PType =
else:
result = t
proc prevDestructor(c: PContext; prevOp: PSym; obj: PType; info: TLineInfo) =
var msg = "cannot bind another '" & prevOp.name.s & "' to: " & typeToString(obj)
if sfOverridden notin prevOp.flags:
proc prevDestructor(c: PContext; op: TTypeAttachedOp; prevOp: PSym; obj: PType; info: TLineInfo) =
var msg = "cannot bind another '" & AttachedOpToStr[op] & "' to: " & typeToString(obj)
if prevOp == nil:
# happens if the destructor was implicitly constructed for a specific instance,
# not the entire generic type
msg.add "; previous declaration was constructed implicitly"
elif sfOverridden notin prevOp.flags:
msg.add "; previous declaration was constructed here implicitly: " & (c.config $ prevOp.info)
else:
msg.add "; previous declaration was here: " & (c.config $ prevOp.info)
localError(c.config, info, errGenerated, msg)
proc checkedForDestructor(t: PType): bool =
if tfCheckedForDestructor in t.flags:
return true
# maybe another instance was instantiated, marking the generic root:
let root = genericRoot(t)
if root != nil and tfGenericHasDestructor in root.flags:
return true
result = false
proc whereToBindTypeHook(c: PContext; t: PType): PType =
result = t
while true:
@@ -2076,10 +2118,10 @@ proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
let ao = getAttachedOp(c.graph, obj, op)
if ao == s:
discard "forward declared destructor"
elif ao.isNil and tfCheckedForDestructor notin obj.flags:
elif ao.isNil and not checkedForDestructor(obj):
setAttachedOp(c.graph, c.module.position, obj, op, s)
else:
prevDestructor(c, ao, obj, n.info)
prevDestructor(c, op, ao, obj, n.info)
noError = true
if obj.owner.getModule != s.getModule:
localError(c.config, n.info, errGenerated,
@@ -2092,7 +2134,7 @@ proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
incl(s.flags, sfUsed)
incl(s.flags, sfOverridden)
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp; suppressVarDestructorWarning = false) =
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
let t = s.typ
var noError = false
let cond = case op
@@ -2116,17 +2158,17 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp; suppressV
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
else: break
if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
if (not suppressVarDestructorWarning) and op == attachedDestructor and t.firstParamType.kind == tyVar and
if op == attachedDestructor and t.firstParamType.kind == tyVar and
c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
message(c.config, n.info, warnDeprecated, "A custom '=destroy' hook which takes a 'var T' parameter is deprecated; it should take a 'T' parameter")
obj = canonType(c, obj)
let ao = getAttachedOp(c.graph, obj, op)
if ao == s:
discard "forward declared destructor"
elif ao.isNil and tfCheckedForDestructor notin obj.flags:
elif ao.isNil and not checkedForDestructor(obj):
setAttachedOp(c.graph, c.module.position, obj, op, s)
else:
prevDestructor(c, ao, obj, n.info)
prevDestructor(c, op, ao, obj, n.info)
noError = true
if obj.owner.getModule != s.getModule:
localError(c.config, n.info, errGenerated,
@@ -2217,10 +2259,10 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
let ao = getAttachedOp(c.graph, obj, k)
if ao == s:
discard "forward declared op"
elif ao.isNil and tfCheckedForDestructor notin obj.flags:
elif ao.isNil and not checkedForDestructor(obj):
setAttachedOp(c.graph, c.module.position, obj, k, s)
else:
prevDestructor(c, ao, obj, n.info)
prevDestructor(c, k, ao, obj, n.info)
if obj.owner.getModule != s.getModule:
localError(c.config, n.info, errGenerated,
"type bound operation `" & name & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
@@ -2309,7 +2351,7 @@ proc semCppMember(c: PContext; s: PSym; n: PNode) =
isInitializer = false
break
var j = 0
while p[j].sym.kind == skParam:
while p[j].kind == nkSym and p[j].sym.kind == skParam:
initializerCall.add val
inc j
if isInitializer:
@@ -2359,10 +2401,11 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
of nkEmpty:
s = newSym(kind, c.cache.idAnon, c.idgen, c.getCurrOwner, n.info)
s.flags.incl sfUsed
s.flags.incl sfGenSym
n[namePos] = newSymNode(s)
of nkSym:
s = n[namePos].sym
s.owner = c.getCurrOwner
setOwner(s, c.getCurrOwner)
else:
# Highlighting needs to be done early so the position for
# name isn't changed (see taccent_highlight). We don't want to check if this is the
@@ -2608,9 +2651,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
c.patterns.add(s)
if isAnon:
n.transitionSonsKind(nkLambda)
result.typ = s.typ
result.typ() = s.typ
if optOwnedRefs in c.config.globalOptions:
result.typ = makeVarType(c, result.typ, tyOwned)
result.typ() = makeVarType(c, result.typ, tyOwned)
elif isTopLevel(c) and s.kind != skIterator and s.typ.callConv == ccClosure:
localError(c.config, s.info, "'.closure' calling convention for top level routines is invalid")
@@ -2629,7 +2672,7 @@ proc semIterator(c: PContext, n: PNode): PNode =
# gensym'ed iterator?
if n[namePos].kind == nkSym:
# gensym'ed iterators might need to become closure iterators:
n[namePos].sym.owner = getCurrOwner(c)
setOwner(n[namePos].sym, getCurrOwner(c))
n[namePos].sym.transitionRoutineSymKind(skIterator)
result = semProcAux(c, n, skIterator, iteratorPragmas)
# bug #7093: if after a macro transformation we don't have an
@@ -2647,10 +2690,10 @@ proc semIterator(c: PContext, n: PNode): PNode =
incl(s.typ.flags, tfCapturesEnv)
else:
s.typ.callConv = ccInline
if n[bodyPos].kind == nkEmpty and s.magic == mNone and c.inConceptDecl == 0:
if result[bodyPos].kind == nkEmpty and s.magic == mNone and c.inConceptDecl == 0:
localError(c.config, n.info, errImplOfXexpected % s.name.s)
if optOwnedRefs in c.config.globalOptions and result.typ != nil:
result.typ = makeVarType(c, result.typ, tyOwned)
result.typ() = makeVarType(c, result.typ, tyOwned)
result.typ.callConv = ccClosure
proc semProc(c: PContext, n: PNode): PNode =
@@ -2781,7 +2824,7 @@ proc semPragmaBlock(c: PContext, n: PNode; expectedType: PType = nil): PNode =
n[1] = semExpr(c, n[1], expectedType = expectedType)
dec c.inUncheckedAssignSection, inUncheckedAssignSection
result = n
result.typ = n[1].typ
result.typ() = n[1].typ
for i in 0..<pragmaList.len:
case whichPragma(pragmaList[i])
of wLine: setInfoRecursive(result, pragmaList[i].info)
@@ -2866,14 +2909,14 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType =
else: discard
if n[i].typ == c.enforceVoidContext: #or usesResult(n[i]):
voidContext = true
n.typ = c.enforceVoidContext
n.typ() = c.enforceVoidContext
if i == last and (n.len == 1 or ({efWantValue, efInTypeof} * flags != {})):
n.typ = n[i].typ
n.typ() = n[i].typ
if not isEmptyType(n.typ): n.transitionSonsKind(nkStmtListExpr)
elif i != last or voidContext:
discardCheck(c, n[i], flags)
else:
n.typ = n[i].typ
n.typ() = n[i].typ
if not isEmptyType(n.typ): n.transitionSonsKind(nkStmtListExpr)
var m = n[i]
while m.kind in {nkStmtListExpr, nkStmtList} and m.len > 0: # from templates

View File

@@ -67,7 +67,12 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
if not isField or sfGenSym notin s.flags:
result = newSymNode(s, info)
markUsed(c, info, s)
if isField:
# possibly not final field sym
incl(s.flags, sfUsed)
markOwnerModuleAsUsed(c, s)
else:
markUsed(c, info, s)
onUse(info, s)
else:
result = n
@@ -237,10 +242,10 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
if result.kind == nkSym:
result = newOpenSym(result)
else:
result.typ = nil
result.typ() = nil
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
of skGenericParam:
if isField and sfGenSym in s.flags: result = n
else:
@@ -250,7 +255,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
of skParam:
result = n
of skType:
@@ -268,10 +273,10 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
if result.kind == nkSym:
result = newOpenSym(result)
else:
result.typ = nil
result.typ() = nil
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
else:
if isField and sfGenSym in s.flags: result = n
else:
@@ -281,7 +286,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
result.typ() = nil
# Issue #12832
when defined(nimsuggest):
suggestSym(c.c.graph, n.info, s, c.c.graph.usageSym, false)
@@ -535,13 +540,20 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
of nkConverterDef:
result = semRoutineInTemplBody(c, n, skConverter)
of nkPragmaExpr:
result[0] = semTemplBody(c, n[0])
result = semTemplBodySons(c, n)
of nkPostfix:
result[1] = semTemplBody(c, n[1])
of nkPragma:
for x in n:
if x.kind == nkExprColonExpr:
x[1] = semTemplBody(c, x[1])
for i in 0 ..< n.len:
let x = n[i]
let prag = whichPragma(x)
if prag == wInvalid:
# only sem if not a language-level pragma
result[i] = semTemplBody(c, x)
elif x.kind in nkPragmaCallKinds:
# is pragma, but value still needs to be checked
for j in 1 ..< x.len:
x[j] = semTemplBody(c, x[j])
of nkBracketExpr:
if n.typ == nil:
# if a[b] is nested inside a typed expression, don't convert it
@@ -684,6 +696,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
s = semIdentVis(c, skTemplate, n[namePos], {})
assert s.kind == skTemplate
let info = getLineInfo(n[namePos])
suggestSym(c.graph, info, s, c.graph.usageSym)
styleCheckDef(c, s)
onDef(n[namePos].info, s)
# check parameter list:

View File

@@ -84,6 +84,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
let isPure = result.sym != nil and sfPure in result.sym.flags
var symbols: TStrTable = initStrTable()
var hasNull = false
var needsReorder = false
for i in 1..<n.len:
if n[i].kind == nkEmpty: continue
var useAutoCounter = false
@@ -122,7 +123,9 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
else:
localError(c.config, v.info, errOrdinalTypeExpected % typeToString(v.typ, preferDesc))
if i != 1:
if x != counter: incl(result.flags, tfEnumHasHoles)
if x != counter:
needsReorder = true
incl(result.flags, tfEnumHasHoles)
e.ast = strVal # might be nil
counter = x
of nkSym:
@@ -173,6 +176,13 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
localError(c.config, n[i].info, errOverflowInEnumX % [e.name.s, $high(typeof(counter))])
else:
inc(counter)
if needsReorder:
result.n.sons.sort(
proc (x, y: PNode): int =
result = cmp(x.sym.position, y.sym.position)
)
if isPure and sfExported in result.sym.flags:
addPureEnum(c, LazySym(sym: result.sym))
if tfNotNil in e.typ.flags and not hasNull:
@@ -247,27 +257,39 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool =
else:
return false
proc fitDefaultNode(c: PContext, n: PNode): PType =
inc c.inStaticContext
let expectedType = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil
n[^1] = semConstExpr(c, n[^1], expectedType = expectedType)
let oldType = n[^1].typ
n[^1].flags.incl nfSem
if n[^2].kind != nkEmpty:
if expectedType != nil and oldType != expectedType:
n[^1] = fitNodeConsiderViewType(c, expectedType, n[^1], n[^1].info)
changeType(c, n[^1], expectedType, true) # infer types for default fields value
# bug #22926; be cautious that it uses `semConstExpr` to
# evaulate the default fields; it's only natural to use
# `changeType` to infer types for constant values
# that's also the reason why we don't use `semExpr` to check
# the type since two overlapping error messages might be produced
result = n[^1].typ
proc annotateClosureConv(n: PNode) =
case n.kind
of {nkNone..nkNilLit}:
discard
of nkTupleConstr:
if n.typ.kind == tyProc and n.typ.callConv == ccClosure and
n[0].typ.kind == tyProc and n[0].typ.callConv != ccClosure:
# restores `transf.generateThunk`
n[0] = newTreeIT(nkHiddenSubConv, n[0].info, n.typ,
newNodeI(nkEmpty, n[0].info), n[0])
n.transitionSonsKind(nkClosure)
n.flags.incl nfTransf
else:
result = n[^1].typ
for i in 0..<n.len:
annotateClosureConv(n[i])
proc fitDefaultNode(c: PContext, n: var PNode, expectedType: PType) =
inc c.inStaticContext
n = semConstExpr(c, n, expectedType = expectedType)
let oldType = n.typ
n.flags.incl nfSem
if expectedType != nil and oldType != expectedType:
n = fitNodeConsiderViewType(c, expectedType, n, n.info)
changeType(c, n, expectedType, true) # infer types for default fields value
# bug #22926; be cautious that it uses `semConstExpr` to
# evaulate the default fields; it's only natural to use
# `changeType` to infer types for constant values
# that's also the reason why we don't use `semExpr` to check
# the type since two overlapping error messages might be produced
annotateClosureConv(n)
# xxx any troubles related to defaults fields, consult `semConst` for a potential answer
if n[^1].kind != nkNilLit:
typeAllowedCheck(c, n.info, result, skConst, {taProcContextIsNotMacro, taIsDefaultField})
if n.kind != nkNilLit:
typeAllowedCheck(c, n.info, n.typ, skConst, {taProcContextIsNotMacro, taIsDefaultField})
dec c.inStaticContext
proc isRecursiveType*(t: PType): bool =
@@ -387,8 +409,12 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
result = makeRangeWithStaticExpr(c, e.typ.n)
elif e.kind in {nkIntLit..nkUInt64Lit}:
if e.intVal < 0:
localError(c.config, n.info,
"Array length can't be negative, but was " & $e.intVal)
if e.kind in {nkIntLit..nkInt64Lit}:
localError(c.config, n.info,
"Array length can't be negative, but was " & $e.intVal)
else:
localError(c.config, n.info,
"Array length can't exceed its maximum value (9223372036854775807), but was " & $cast[BiggestUInt](e.intVal))
result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
elif e.kind == nkSym and (e.typ.kind == tyStatic or e.typ.kind == tyTypeDesc):
if e.typ.kind == tyStatic:
@@ -480,7 +506,7 @@ proc firstRange(config: ConfigRef, t: PType): PNode =
result = newFloatNode(nkFloatLit, firstFloat(t))
else:
result = newIntNode(nkIntLit, firstOrd(config, t))
result.typ = t
result.typ() = t
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
var typ: PType
@@ -494,7 +520,14 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(a, 3, c.config)
var hasDefaultField = a[^1].kind != nkEmpty
if hasDefaultField:
typ = fitDefaultNode(c, a)
typ = if a[^2].kind != nkEmpty: semTypeNode(c, a[^2], nil) else: nil
if c.inGenericContext > 0:
a[^1] = semExprWithType(c, a[^1], {efDetermineType, efAllowSymChoice}, typ)
if typ == nil:
typ = a[^1].typ
else:
fitDefaultNode(c, a[^1], typ)
typ = a[^1].typ
elif a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange:
@@ -858,8 +891,15 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
var typ: PType
var hasDefaultField = n[^1].kind != nkEmpty
if hasDefaultField:
typ = fitDefaultNode(c, n)
propagateToOwner(rectype, typ)
typ = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil
if c.inGenericContext > 0:
n[^1] = semExprWithType(c, n[^1], {efDetermineType, efAllowSymChoice}, typ)
if typ == nil:
typ = n[^1].typ
else:
fitDefaultNode(c, n[^1], typ)
typ = n[^1].typ
propagateToOwner(rectype, typ)
elif n[^2].kind == nkEmpty:
localError(c.config, n.info, errTypeExpected)
typ = errorType(c)
@@ -1096,7 +1136,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
if sfGenSym in param.flags:
# bug #XXX, fix the gensym'ed parameters owner:
if param.owner == nil:
param.owner = getCurrOwner(c)
setOwner(param, getCurrOwner(c))
else: addDecl(c, param)
template shouldHaveMeta(t) =
@@ -1372,14 +1412,25 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
"either use ';' (semicolon) or explicitly write each default value")
message(c.config, a.info, warnImplicitDefaultValue, msg)
block determineType:
if kind == skTemplate and hasUnresolvedArgs(c, def):
# template default value depends on other parameter
# don't do any typechecking
def.typ = makeTypeFromExpr(c, def.copyTree)
break determineType
var canBeVoid = false
if kind == skTemplate:
if typ != nil and typ.kind == tyUntyped:
# don't do any typechecking or assign a type for
# `untyped` parameter default value
break determineType
elif hasUnresolvedArgs(c, def):
# template default value depends on other parameter
# don't do any typechecking
def.typ() = makeTypeFromExpr(c, def.copyTree)
break determineType
elif typ != nil and typ.kind == tyTyped:
canBeVoid = true
let isGeneric = isCurrentlyGeneric()
inc c.inGenericContext, ord(isGeneric)
def = semExprWithType(c, def, {efDetermineType, efAllowSymChoice}, typ)
if canBeVoid:
def = semExpr(c, def, {efDetermineType, efAllowSymChoice}, typ)
else:
def = semExprWithType(c, def, {efDetermineType, efAllowSymChoice}, typ)
dec c.inGenericContext, ord(isGeneric)
if def.referencesAnotherParam(getCurrOwner(c)):
def.flags.incl nfDefaultRefsParam
@@ -1399,7 +1450,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
typ = newTypeS(tyTypeDesc, c, newTypeS(tyNone, c))
typ.flags.incl tfCheckedForDestructor
elif def.typ.kind != tyFromExpr:
elif def.typ != nil and def.typ.kind != tyFromExpr: # def.typ can be void
# if def.typ != nil and def.typ.kind != tyNone:
# example code that triggers it:
# proc sort[T](cmp: proc(a, b: T): int = cmp)
@@ -1508,7 +1559,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# XXX This rather hacky way keeps 'tflatmap' compiling:
if tfHasMeta notin oldFlags:
result.flags.excl tfHasMeta
result.n.typ = r
result.n.typ() = r
if isCurrentlyGeneric():
for n in genericParams:
@@ -1525,8 +1576,8 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
n[i] = semStmt(c, n[i], {})
if n.len > 0:
result = semTypeNode(c, n[^1], prev)
n.typ = result
n[^1].typ = result
n.typ() = result
n[^1].typ() = result
else:
result = nil
@@ -1539,15 +1590,15 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
if n[0].kind notin {nkEmpty, nkSym}:
addDecl(c, newSymS(skLabel, n[0], c))
result = semStmtListType(c, n[1], prev)
n[1].typ = result
n.typ = result
n[1].typ() = result
n.typ() = result
closeScope(c)
c.p.breakInLoop = oldBreakInLoop
dec(c.p.nestedBlockCounter)
proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
result = semTypeNode(c, n, nil)
n.typ = makeTypeDesc(c, result)
n.typ() = makeTypeDesc(c, result)
proc trySemObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType): bool =
var
@@ -1620,6 +1671,11 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
var err = "cannot instantiate "
err.addTypeHeader(c.config, t)
err.add "\ngot: <$1>\nbut expected: <$2>" % [describeArgs(c, n), describeArgs(c, t.n, 0)]
if m.firstMismatch.kind == kTypeMismatch and m.firstMismatch.arg < n.len:
let nArg = n[m.firstMismatch.arg]
if nArg.kind in nkSymChoices:
err.add "\n"
err.add ambiguousIdentifierMsg(nArg)
localError(c.config, n.info, errGenerated, err)
return newOrPrevType(tyError, prev, c)
@@ -1820,7 +1876,7 @@ proc applyTypeSectionPragmas(c: PContext; pragmas, operand: PNode): PNode =
x.add(operand.copyTreeWithoutNode(p))
# recursion assures that this works for multiple macro annotations too:
var r = semOverloadedCall(c, x, x, {skMacro, skTemplate}, {efNoUndeclared})
if r != nil:
if r != nil and (r.typ == nil or r.typ.kind != tyFromExpr):
doAssert r[0].kind == nkSym
let m = r[0].sym
case m.kind
@@ -1959,7 +2015,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
n.transitionNoneToSym()
n.sym = result
n.info = oldInfo
n.typ = result.typ
n.typ() = result.typ
else:
localError(c.config, n.info, "identifier expected")
result = errorSym(c, n)
@@ -2258,7 +2314,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
when false:
localError(c.config, n.info, "type expected, but got: " & renderTree(n))
result = newOrPrevType(tyError, prev, c)
n.typ = result
n.typ() = result
dec c.inTypeContext
proc setMagicType(conf: ConfigRef; m: PSym, kind: TTypeKind, size: int) =
@@ -2405,7 +2461,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
else:
# the following line fixes ``TV2*[T:SomeNumber=TR] = array[0..1, T]``
# from manyloc/named_argument_bug/triengine:
def.typ = def.typ.skipTypes({tyTypeDesc})
def.typ() = def.typ.skipTypes({tyTypeDesc})
if not containsGenericType(def.typ):
def = fitNode(c, typ, def, def.info)

View File

@@ -12,7 +12,7 @@
import std / tables
import ast, astalgo, msgs, types, magicsys, semdata, renderer, options,
lineinfos, modulegraphs
lineinfos, modulegraphs, layeredtable
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -65,10 +65,6 @@ proc cacheTypeInst(c: PContext; inst: PType) =
addToGenericCache(c, gt.sym, inst)
type
LayeredIdTable* {.acyclic.} = ref object
topLayer*: TypeMapping
nextLayer*: LayeredIdTable
TReplTypeVars* = object
c*: PContext
typeMap*: LayeredIdTable # map PType to PType
@@ -84,27 +80,12 @@ type
owner*: PSym # where this instantiation comes from
recursionLimit: int
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType, isInstValue = false): PType
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym
proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PType = nil): PNode
proc initLayeredTypeMap*(pt: sink TypeMapping): LayeredIdTable =
result = LayeredIdTable()
result.topLayer = pt
proc newTypeMapLayer*(cl: var TReplTypeVars): LayeredIdTable =
result = LayeredIdTable(nextLayer: cl.typeMap, topLayer: initTable[ItemId, PType]())
proc lookup(typeMap: LayeredIdTable, key: PType): PType =
result = nil
var tm = typeMap
while tm != nil:
result = getOrDefault(tm.topLayer, key.itemId)
if result != nil: return
tm = tm.nextLayer
template put(typeMap: LayeredIdTable, key, value: PType) =
typeMap.topLayer[key.itemId] = value
result = newTypeMapLayer(cl.typeMap)
template checkMetaInvariants(cl: TReplTypeVars, t: PType) = # noop code
when false:
@@ -114,8 +95,8 @@ template checkMetaInvariants(cl: TReplTypeVars, t: PType) = # noop code
debug t
writeStackTrace()
proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
result = replaceTypeVarsTAux(cl, t)
proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType, isInstValue = false): PType =
result = replaceTypeVarsTAux(cl, t, isInstValue)
checkMetaInvariants(cl, result)
proc prepareNode*(cl: var TReplTypeVars, n: PNode): PNode =
@@ -129,7 +110,7 @@ proc prepareNode*(cl: var TReplTypeVars, n: PNode): PNode =
return if tfUnresolved in t.flags: prepareNode(cl, t.n)
else: t.n
result = copyNode(n)
result.typ = t
result.typ() = t
if result.kind == nkSym:
result.sym =
if n.typ != nil and n.typ == n.sym.typ:
@@ -283,7 +264,7 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PT
if n.typ.kind == tyFromExpr:
# type of node should not be evaluated as a static value
n.typ.flags.incl tfNonConstExpr
result.typ = replaceTypeVarsT(cl, n.typ)
result.typ() = replaceTypeVarsT(cl, n.typ)
checkMetaInvariants(cl, result.typ)
case n.kind
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
@@ -295,6 +276,11 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PT
replaceTypeVarsS(cl, n.sym, result.typ)
else:
replaceTypeVarsS(cl, n.sym, replaceTypeVarsT(cl, n.sym.typ))
if result.sym.kind == skField and result.sym.ast != nil and
(cl.owner == nil or result.sym.owner == cl.owner):
# instantiate default value of object/tuple field
cl.c.fitDefaultNode(cl.c, result.sym.ast, result.sym.typ)
result.sym.typ = result.sym.ast.typ
# sym type can be nil if was gensym created by macro, see #24048
if result.sym.typ != nil and result.sym.typ.kind == tyVoid:
# don't add the 'void' field
@@ -358,7 +344,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym =
#[
We cannot naively check for symbol recursions, because otherwise
object types A, B whould share their fields!
object types A, B would share their fields!
import tables
@@ -377,7 +363,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym =
result = copySym(s, cl.c.idgen)
incl(result.flags, sfFromGeneric)
#idTablePut(cl.symMap, s, result)
result.owner = s.owner
setOwner(result, s.owner)
result.typ = t
if result.kind != skType:
result.ast = replaceTypeVarsN(cl, s.ast)
@@ -495,12 +481,12 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
return
let bbody = last body
var newbody = replaceTypeVarsT(cl, bbody)
var newbody = replaceTypeVarsT(cl, bbody, isInstValue = true)
cl.skipTypedesc = oldSkipTypedesc
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
result.flags = result.flags + newbody.flags - tfInstClearedFlags
cl.typeMap = cl.typeMap.nextLayer
setToPreviousLayer(cl.typeMap)
# This is actually wrong: tgeneric_closure fails with this line:
#newbody.callConv = body.callConv
@@ -592,7 +578,7 @@ proc propagateFieldFlags(t: PType, n: PNode) =
propagateFieldFlags(t, son)
else: discard
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType, isInstValue = false): PType =
template bailout =
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
@@ -715,7 +701,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
if not cl.allowMetaTypes and result.n != nil and
result.base.kind != tyNone:
result.n = cl.c.semConstExpr(cl.c, result.n)
result.n.typ = result.base
result.n.typ() = result.base
of tyGenericInst, tyUserTypeClassInst:
bailout()
@@ -726,13 +712,17 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
propagateToOwner(result, result.last)
else:
if containsGenericType(t):
if containsGenericType(t) or
# nominal types as direct generic instantiation values
# are re-instantiated even if they don't contain generic fields
(isInstValue and (t.kind in {tyDistinct, tyObject} or isRefPtrObject(t))):
#if not cl.allowMetaTypes:
bailout()
result = instCopyType(cl, t)
result.size = -1 # needs to be recomputed
#if not cl.allowMetaTypes:
cl.localCache[t.itemId] = result
let propagateInstValue = isInstValue and isRefPtrObject(t)
for i, resulti in result.ikids:
if resulti != nil:
@@ -742,7 +732,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
typeToString(result[i], preferDesc) &
"' inside of type definition: '" &
t.owner.name.s & "'; Maybe generic arguments are missing?")
var r = replaceTypeVarsT(cl, resulti)
var r = replaceTypeVarsT(cl, resulti, isInstValue = propagateInstValue)
if result.kind == tyObject:
# carefully coded to not skip the precious tyGenericInst:
let r2 = r.skipTypes({tyAlias, tySink, tyOwned})
@@ -791,19 +781,19 @@ proc initTypeVars*(p: PContext, typeMap: LayeredIdTable, info: TLineInfo;
localCache: initTypeMapping(), typeMap: typeMap,
info: info, c: p, owner: owner)
proc replaceTypesInBody*(p: PContext, pt: TypeMapping, n: PNode;
proc replaceTypesInBody*(p: PContext, pt: LayeredIdTable, n: PNode;
owner: PSym, allowMetaTypes = false,
fromStaticExpr = false, expectedType: PType = nil): PNode =
var typeMap = initLayeredTypeMap(pt)
var typeMap = shallowCopy(pt) # use previous bindings without writing to them
var cl = initTypeVars(p, typeMap, n.info, owner)
cl.allowMetaTypes = allowMetaTypes
pushInfoContext(p.config, n.info)
result = replaceTypeVarsN(cl, n, expectedType = expectedType)
popInfoContext(p.config)
proc prepareTypesInBody*(p: PContext, pt: TypeMapping, n: PNode;
proc prepareTypesInBody*(p: PContext, pt: LayeredIdTable, n: PNode;
owner: PSym = nil): PNode =
var typeMap = initLayeredTypeMap(pt)
var typeMap = shallowCopy(pt) # use previous bindings without writing to them
var cl = initTypeVars(p, typeMap, n.info, owner)
pushInfoContext(p.config, n.info)
result = prepareNode(cl, n)
@@ -836,13 +826,13 @@ proc recomputeFieldPositions*(t: PType; obj: PNode; currPosition: var int) =
inc currPosition
else: discard "cannot happen"
proc generateTypeInstance*(p: PContext, pt: TypeMapping, info: TLineInfo,
proc generateTypeInstance*(p: PContext, pt: LayeredIdTable, info: TLineInfo,
t: PType): PType =
# Given `t` like Foo[T]
# pt: Table with type mappings: T -> int
# Desired result: Foo[int]
# proc (x: T = 0); T -> int ----> proc (x: int = 0)
var typeMap = initLayeredTypeMap(pt)
var typeMap = shallowCopy(pt) # use previous bindings without writing to them
var cl = initTypeVars(p, typeMap, info, nil)
pushInfoContext(p.config, info)
result = replaceTypeVarsT(cl, t)
@@ -852,15 +842,15 @@ proc generateTypeInstance*(p: PContext, pt: TypeMapping, info: TLineInfo,
var position = 0
recomputeFieldPositions(objType, objType.n, position)
proc prepareMetatypeForSigmatch*(p: PContext, pt: TypeMapping, info: TLineInfo,
proc prepareMetatypeForSigmatch*(p: PContext, pt: LayeredIdTable, info: TLineInfo,
t: PType): PType =
var typeMap = initLayeredTypeMap(pt)
var typeMap = shallowCopy(pt) # use previous bindings without writing to them
var cl = initTypeVars(p, typeMap, info, nil)
cl.allowMetaTypes = true
pushInfoContext(p.config, info)
result = replaceTypeVarsT(cl, t)
popInfoContext(p.config)
template generateTypeInstance*(p: PContext, pt: TypeMapping, arg: PNode,
template generateTypeInstance*(p: PContext, pt: LayeredIdTable, arg: PNode,
t: PType): untyped =
generateTypeInstance(p, pt, arg.info, t)

View File

@@ -13,7 +13,7 @@
import
ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
magicsys, idents, lexer, options, parampatterns, trees,
linter, lineinfos, lowerings, modulegraphs, concepts
linter, lineinfos, lowerings, modulegraphs, concepts, layeredtable
import std/[intsets, strutils, tables]
@@ -56,7 +56,7 @@ type
calleeScope*: int # scope depth:
# is this a top-level symbol or a nested proc?
call*: PNode # modified call
bindings*: TypeMapping # maps types to types
bindings*: LayeredIdTable # maps types to types
magic*: TMagic # magic of operation
baseTypeMatch: bool # needed for conversions from T to openarray[T]
# for example
@@ -85,6 +85,9 @@ type
inheritancePenalty: int
firstMismatch*: MismatchInfo # mismatch info for better error messages
diagnosticsEnabled*: bool
newlyTypedOperands*: seq[int]
## indexes of arguments that are newly typechecked in this match
## used for type bound op additions
TTypeRelFlag* = enum
trDontBind
@@ -114,21 +117,21 @@ proc initCandidateAux(ctx: PContext,
proc initCandidate*(ctx: PContext, callee: PType): TCandidate =
result = initCandidateAux(ctx, callee)
result.calleeSym = nil
result.bindings = initTypeMapping()
result.bindings = initLayeredTypeMap()
proc put(c: var TCandidate, key, val: PType) {.inline.} =
## Given: proc foo[T](x: T); foo(4)
## key: 'T'
## val: 'int' (typeof(4))
when false:
let old = idTableGet(c.bindings, key)
let old = lookup(c.bindings, key)
if old != nil:
echo "Putting ", typeToString(key), " ", typeToString(val), " and old is ", typeToString(old)
if typeToString(old) == "float32":
writeStackTrace()
if c.c.module.name.s == "temp3":
echo "binding ", key, " -> ", val
idTablePut(c.bindings, key, val.skipIntLit(c.c.idgen))
put(c.bindings, key, val.skipIntLit(c.c.idgen))
proc typeRel*(c: var TCandidate, f, aOrig: PType,
flags: TTypeRelFlags = {}): TTypeRelation
@@ -138,7 +141,7 @@ proc matchGenericParam(m: var TCandidate, formal: PType, n: PNode) =
if m.c.inGenericContext > 0:
# don't match yet-unresolved generic instantiations
while arg != nil and arg.kind == tyGenericParam:
arg = idTableGet(m.bindings, arg)
arg = lookup(m.bindings, arg)
if arg == nil or arg.containsUnresolvedType:
m.state = csNoMatch
return
@@ -200,6 +203,9 @@ proc matchGenericParams*(m: var TCandidate, binding: PNode, callee: PSym) =
elif tfImplicitTypeParam in paramSym.typ.flags:
# not a mismatch, but can't create sym
m.state = csEmpty
m.firstMismatch.kind = kMissingGenericParam
m.firstMismatch.arg = i + 1
m.firstMismatch.formal = paramSym
return
else:
m.state = csNoMatch
@@ -218,7 +224,7 @@ proc copyingEraseVoidParams(m: TCandidate, t: var PType) =
var f = original[i]
var isVoidParam = f.kind == tyVoid
if not isVoidParam:
let prev = idTableGet(m.bindings, f)
let prev = lookup(m.bindings, f)
if prev != nil: f = prev
isVoidParam = f.kind == tyVoid
if isVoidParam:
@@ -246,7 +252,7 @@ proc initCandidate*(ctx: PContext, callee: PSym,
result.diagnostics = @[] # if diagnosticsEnabled: @[] else: nil
result.diagnosticsEnabled = diagnosticsEnabled
result.magic = result.calleeSym.magic
result.bindings = initTypeMapping()
result.bindings = initLayeredTypeMap()
if binding != nil and callee.kind in routineKinds:
matchGenericParams(result, binding, callee)
let genericMatch = result.state
@@ -270,7 +276,7 @@ proc newCandidate*(ctx: PContext, callee: PSym,
proc newCandidate*(ctx: PContext, callee: PType): TCandidate =
result = initCandidate(ctx, callee)
proc copyCandidate(dest: var TCandidate, src: TCandidate) =
proc shallowCopyCandidate(dest: var TCandidate, src: TCandidate) =
dest.c = src.c
dest.exactMatches = src.exactMatches
dest.subtypeMatches = src.subtypeMatches
@@ -282,7 +288,7 @@ proc copyCandidate(dest: var TCandidate, src: TCandidate) =
dest.calleeSym = src.calleeSym
dest.call = copyTree(src.call)
dest.baseTypeMatch = src.baseTypeMatch
dest.bindings = src.bindings
dest.bindings = shallowCopy(src.bindings)
proc checkGeneric(a, b: TCandidate): int =
let c = a.c
@@ -444,11 +450,11 @@ template describeArgImpl(c: PContext, n: PNode, i: int, startIdx = 1; prefer = p
arg = c.semTryExpr(c, n[i][1])
if arg == nil:
arg = n[i][1]
arg.typ = newTypeS(tyUntyped, c)
arg.typ() = newTypeS(tyUntyped, c)
else:
if arg.typ == nil:
arg.typ = newTypeS(tyVoid, c)
n[i].typ = arg.typ
arg.typ() = newTypeS(tyVoid, c)
n[i].typ() = arg.typ
n[i][1] = arg
else:
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo, nkElse,
@@ -457,10 +463,10 @@ template describeArgImpl(c: PContext, n: PNode, i: int, startIdx = 1; prefer = p
arg = c.semTryExpr(c, n[i])
if arg == nil:
arg = n[i]
arg.typ = newTypeS(tyUntyped, c)
arg.typ() = newTypeS(tyUntyped, c)
else:
if arg.typ == nil:
arg.typ = newTypeS(tyVoid, c)
arg.typ() = newTypeS(tyVoid, c)
n[i] = arg
if arg.typ != nil and arg.typ.kind == tyError: return
result.add argTypeToString(arg, prefer)
@@ -487,7 +493,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
result = t
if c.isNoCall: return
while true:
result = idTableGet(c.bindings, t)
result = lookup(c.bindings, t)
if result == nil:
break # it's ok, no match
# example code that triggers it:
@@ -589,59 +595,30 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
else: result = isIntConv
else: result = isNone
proc reduceToBase(f: PType): PType =
#[
Returns the lowest order (most general) type that that is compatible with the input.
E.g.
A[T] = ptr object ... A -> ptr object
A[N: static[int]] = array[N, int] ... A -> array
]#
case f.kind:
of tyGenericParam:
if f.len <= 0 or f.skipModifier == nil:
result = f
else:
result = reduceToBase(f.skipModifier)
of tyGenericInvocation:
result = reduceToBase(f.baseClass)
of tyCompositeTypeClass, tyAlias:
if not f.hasElementType or f.elementType == nil:
result = f
else:
result = reduceToBase(f.elementType)
of tyGenericInst:
result = reduceToBase(f.skipModifier)
of tyGenericBody:
result = reduceToBase(f.typeBodyImpl)
of tyUserTypeClass:
if f.isResolvedUserTypeClass:
result = f.base # ?? idk if this is right
else:
result = f.skipModifier
of tyStatic, tyOwned, tyVar, tyLent, tySink:
result = reduceToBase(f.base)
of tyInferred:
# This is not true "After a candidate type is selected"
result = reduceToBase(f.base)
of tyRange:
result = f.elementType
else:
result = f
proc genericParamPut(c: var TCandidate; last, fGenericOrigin: PType) =
if fGenericOrigin != nil and last.kind == tyGenericInst and
last.kidsLen-1 == fGenericOrigin.kidsLen:
for i in FirstGenericParamAt..<fGenericOrigin.kidsLen:
let x = idTableGet(c.bindings, fGenericOrigin[i])
let x = lookup(c.bindings, fGenericOrigin[i])
if x == nil:
put(c, fGenericOrigin[i], last[i])
proc isGenericObjectOf(f, a: PType): bool =
## checks if `f` is an unparametrized generic type
## that `a` is an instance of
if not (f.sym != nil and f.sym.typ.kind == tyGenericBody):
# covers the case where `f` is the last child (body) of the `tyGenericBody`
return false
let aRoot = genericRoot(a)
# use sym equality to check if the `tyGenericBody` types are equal
result = aRoot != nil and f.sym == aRoot.sym
proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
var t = a
assert t.kind == tyObject
var depth = 0
var last = a
while t != nil and not sameObjectTypes(f, t):
while t != nil and not (sameObjectTypes(f, t) or isGenericObjectOf(f, t)):
if t.kind != tyObject: # avoid entering generic params etc
return -1
t = t.baseClass
@@ -770,7 +747,7 @@ proc procParamTypeRel(c: var TCandidate; f, a: PType): TTypeRelation =
a = a
if a.isMetaType:
let aResolved = idTableGet(c.bindings, a)
let aResolved = lookup(c.bindings, a)
if aResolved != nil:
a = aResolved
if a.isMetaType:
@@ -896,7 +873,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
typeParamName = ff.base[i-1].sym.name
typ = ff[i]
param: PSym = nil
alreadyBound = idTableGet(m.bindings, typ)
alreadyBound = lookup(m.bindings, typ)
if alreadyBound != nil: typ = alreadyBound
@@ -1081,7 +1058,7 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
else: discard
elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and
(lhs.typ.n == nil or idTableGet(c.bindings, lhs.typ) == nil):
(lhs.typ.n == nil or lookup(c.bindings, lhs.typ) == nil):
var inferred = newTypeS(tyStatic, c.c, lhs.typ.elementType)
inferred.n = newIntNode(nkIntLit, rhs)
put(c, lhs.typ, inferred)
@@ -1237,7 +1214,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
case f.kind
of tyGenericParam:
var prev = idTableGet(c.bindings, f)
var prev = lookup(c.bindings, f)
if prev != nil: candidate = prev
of tyFromExpr:
let computedType = tryResolvingStaticExpr(c, f.n).typ
@@ -1287,7 +1264,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
return res
template considerPreviousT(body: untyped) =
var prev = idTableGet(c.bindings, f)
var prev = lookup(c.bindings, f)
if prev == nil: body
else: return typeRel(c, prev, a, flags)
@@ -1421,7 +1398,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
var fRange = f.indexType
var aRange = a.indexType
if fRange.kind in {tyGenericParam, tyAnything}:
var prev = idTableGet(c.bindings, fRange)
var prev = lookup(c.bindings, fRange)
if prev == nil:
if typeRel(c, fRange, aRange) == isNone:
return isNone
@@ -1561,11 +1538,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
else:
result = typeRel(c, f[0], a[0], flags)
if result < isGeneric:
if result <= isConvertible:
result = isNone
elif tfIsConstructor notin a.flags:
# set constructors are a bit special...
if tfIsConstructor notin a.flags:
# set['a'..'z'] and set[char] have different representations
result = isNone
else:
# but we can convert individual elements of the constructor
result = isConvertible
of tyPtr, tyRef:
a = reduceToBase(a)
if a.kind == f.kind:
@@ -1654,7 +1632,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
else:
result = isNone
of tyGenericInst:
var prev = idTableGet(c.bindings, f)
var prev = lookup(c.bindings, f)
let origF = f
var f = if prev == nil: f else: prev
@@ -1786,14 +1764,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
#
# we steal the generic parameters from the tyGenericBody:
for i in 1..<f.len:
let x = idTableGet(c.bindings, genericBody[i-1])
let x = lookup(c.bindings, genericBody[i-1])
if x == nil:
discard "maybe fine (for e.g. a==tyNil)"
elif x.kind in {tyGenericInvocation, tyGenericParam}:
internalError(c.c.graph.config, "wrong instantiated type!")
else:
let key = f[i]
let old = idTableGet(c.bindings, key)
let old = lookup(c.bindings, key)
if old == nil:
put(c, key, x)
elif typeRel(c, old, x, flags + {trDontBind}) == isNone:
@@ -1861,9 +1839,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
let target = f.genericHead
let targetKind = target.kind
var effectiveArgType = reduceToBase(a)
# the skipped child of tyBuiltInTypeClass can be structured differently,
# newConstraint constructs them with no children
let typeClassArg = effectiveArgType.kind == tyBuiltInTypeClass
effectiveArgType = effectiveArgType.skipTypes({tyBuiltInTypeClass})
if targetKind == effectiveArgType.kind:
if effectiveArgType.isEmptyContainer:
if not typeClassArg and effectiveArgType.isEmptyContainer:
return isNone
if targetKind == tyProc:
if target.flags * {tfIterator} != effectiveArgType.flags * {tfIterator}:
@@ -1898,8 +1879,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
else:
result = isNone
of tyConcept:
result = if concepts.conceptMatch(c.c, f, a, c.bindings, nil): isGeneric
else: isNone
if a.kind == tyConcept and sameType(f, a):
result = isGeneric
else:
result = if concepts.conceptMatch(c.c, f, a, c.bindings, nil): isGeneric
else: isNone
of tyCompositeTypeClass:
considerPreviousT:
let roota = a.skipGenericAlias
@@ -1918,7 +1902,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
result = isGeneric
of tyGenericParam:
let doBindGP = doBind or trBindGenericParam in flags
var x = idTableGet(c.bindings, f)
var x = lookup(c.bindings, f)
if x == nil:
if c.callee.kind == tyGenericBody and not c.typedescMatched:
# XXX: The fact that generic types currently use tyGenericParam for
@@ -1998,7 +1982,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
c.inheritancePenalty = inheritancePenaltyOld
if result > isGeneric: result = isGeneric
of tyStatic:
let prev = idTableGet(c.bindings, f)
let prev = lookup(c.bindings, f)
if prev == nil:
if aOrig.kind == tyStatic:
if c.c.inGenericContext > 0 and aOrig.n == nil and not c.isNoCall:
@@ -2060,7 +2044,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
c.inferredTypes.add f
f.add a
of tyTypeDesc:
var prev = idTableGet(c.bindings, f)
var prev = lookup(c.bindings, f)
if prev == nil:
# proc foo(T: typedesc, x: T)
# when `f` is an unresolved typedesc, `a` could be any
@@ -2151,7 +2135,7 @@ proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
f: PType): PType =
result = idTableGet(m.bindings, f)
result = lookup(m.bindings, f)
if result == nil:
result = generateTypeInstance(c, m.bindings, arg, f)
if result == nil:
@@ -2163,16 +2147,16 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
result = newNodeI(kind, arg.info)
if containsGenericType(f):
if not m.matchedErrorType:
result.typ = getInstantiatedType(c, arg, m, f).skipTypes({tySink})
result.typ() = getInstantiatedType(c, arg, m, f).skipTypes({tySink})
else:
result.typ = errorType(c)
result.typ() = errorType(c)
else:
result.typ = f.skipTypes({tySink})
result.typ() = f.skipTypes({tySink})
# keep varness
if arg.typ != nil and arg.typ.kind == tyVar:
result.typ = toVar(result.typ, tyVar, c.idgen)
result.typ() = toVar(result.typ, tyVar, c.idgen)
else:
result.typ = result.typ.skipTypes({tyVar})
result.typ() = result.typ.skipTypes({tyVar})
if result.typ == nil: internalError(c.graph.config, arg.info, "implicitConv")
result.add c.graph.emptyNode
@@ -2183,6 +2167,81 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
else:
result.add arg
proc convertLiteral(kind: TNodeKind, c: PContext, m: TCandidate; n: PNode, newType: PType): PNode =
# based off changeType but generates implicit conversions instead
template addConsiderNil(s, node) =
let val = node
if val.isNil: return nil
s.add(val)
case n.kind
of nkCurly:
result = copyNode(n)
for i in 0..<n.len:
if n[i].kind == nkRange:
var x = copyNode(n[i])
x.addConsiderNil convertLiteral(kind, c, m, n[i][0], elemType(newType))
x.addConsiderNil convertLiteral(kind, c, m, n[i][1], elemType(newType))
result.add x
else:
result.addConsiderNil convertLiteral(kind, c, m, n[i], elemType(newType))
result.typ() = newType
return
of nkBracket:
result = copyNode(n)
for i in 0..<n.len:
result.addConsiderNil convertLiteral(kind, c, m, n[i], elemType(newType))
result.typ() = newType
return
of nkPar, nkTupleConstr:
let tup = newType.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
if tup.kind == tyTuple:
result = copyNode(n)
if n.len > 0 and n[0].kind == nkExprColonExpr:
# named tuple?
for i in 0..<n.len:
var name = n[i][0]
if name.kind != nkSym:
#globalError(c.config, name.info, "invalid tuple constructor")
return nil
if tup.n != nil:
var f = getSymFromList(tup.n, name.sym.name)
if f == nil:
#globalError(c.config, name.info, "unknown identifier: " & name.sym.name.s)
return nil
result.addConsiderNil convertLiteral(kind, c, m, n[i][1], f.typ)
else:
result.addConsiderNil convertLiteral(kind, c, m, n[i][1], tup[i])
else:
for i in 0..<n.len:
result.addConsiderNil convertLiteral(kind, c, m, n[i], tup[i])
result.typ() = newType
return
of nkCharLit..nkUInt64Lit:
if n.kind != nkUInt64Lit and not sameTypeOrNil(n.typ, newType) and isOrdinalType(newType):
let value = n.intVal
if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
return nil
result = copyNode(n)
result.typ() = newType
return
of nkFloatLit..nkFloat64Lit:
if newType.skipTypes(abstractVarRange-{tyTypeDesc}).kind == tyFloat:
if not floatRangeCheck(n.floatVal, newType):
return nil
result = copyNode(n)
result.typ() = newType
return
of nkSym:
if n.sym.kind == skEnumField and not sameTypeOrNil(n.sym.typ, newType) and isOrdinalType(newType):
let value = n.sym.position
if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
return nil
result = copyNode(n)
result.typ() = newType
return
else: discard
return implicitConv(kind, newType, n, m, c)
proc isLValue(c: PContext; n: PNode, isOutParam = false): bool {.inline.} =
let aa = isAssignable(nil, n)
case aa
@@ -2220,9 +2279,11 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
dest = generateTypeInstance(c, m.bindings, arg, dest)
let fdest = typeRel(m, f, dest)
if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind in {tyVar}):
markUsed(c, arg.info, c.converters[i])
# can't fully mark used yet, may not be used in final call
incl(c.converters[i].flags, sfUsed)
markOwnerModuleAsUsed(c, c.converters[i])
var s = newSymNode(c.converters[i])
s.typ = c.converters[i].typ
s.typ() = c.converters[i].typ
s.info = arg.info
result = newNodeIT(nkHiddenCallConv, arg.info, dest)
result.add s
@@ -2275,7 +2336,7 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
if result.kind == nkCall: result.transitionSonsKind(nkHiddenCallConv)
inc(m.convMatches)
if r == isGeneric:
result.typ = getInstantiatedType(c, arg, m, base(f))
result.typ() = getInstantiatedType(c, arg, m, base(f))
m.baseTypeMatch = true
proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
@@ -2331,7 +2392,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
let typ = newTypeS(tyStatic, c, son = evaluated.typ)
typ.n = evaluated
arg = copyTree(arg) # fix #12864
arg.typ = typ
arg.typ() = typ
a = typ
else:
if m.callee.kind == tyGenericBody:
@@ -2371,9 +2432,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
var instantiationCounter = 0
var lastBindingCount = -1
while r in {isBothMetaConvertible, isInferred, isInferredConvertible} and
lastBindingCount != m.bindings.len and
lastBindingCount != m.bindings.currentLen and
instantiationCounter < 100:
lastBindingCount = m.bindings.len
lastBindingCount = m.bindings.currentLen
inc(instantiationCounter)
if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds:
result = c.semInferredLambda(c, m.bindings, arg)
@@ -2394,7 +2455,20 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
if f.skipTypes({tyRange}).kind in {tyInt, tyUInt}:
inc(m.convMatches)
inc(m.convMatches)
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
if skipTypes(f, abstractVar-{tyTypeDesc}).kind == tySet:
if tfIsConstructor in a.flags and arg.kind == nkCurly:
# we marked the set as convertible only because the arg is a literal
# in which case we individually convert each element
let t =
if containsGenericType(f):
getInstantiatedType(c, arg, m, f).skipTypes({tySink})
else:
f.skipTypes({tySink})
result = convertLiteral(nkHiddenStdConv, c, m, arg, t)
else:
result = nil
else:
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
of isIntConv:
# I'm too lazy to introduce another ``*matches`` field, so we conflate
# ``isIntConv`` and ``isIntLit`` here:
@@ -2429,9 +2503,15 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
result = arg
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or cmpInheritancePenalty(oldInheritancePenalty, m.inheritancePenalty) > 0:
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
elif arg.typ.isEmptyContainer:
elif arg.typ.isEmptyContainer or
# XXX `and not m.isNoCall` is a workaround
# passing an int to generic types converts it to the type `int`
# but this isn't done for int literal types, so we preserve the type
# i.e. works: `type Foo[T] = array[T, int]; var x: Foo[3]` (see t12938, t14193)
# doesn't work: `proc foo[T](): array[T, int] = ...; foo[3]()` (see #23204)
(arg.typ.isIntLit and not m.isNoCall):
result = arg.copyTree
result.typ = getInstantiatedType(c, arg, m, f)
result.typ() = getInstantiatedType(c, arg, m, f).skipTypes({tySink})
else:
result = arg
of isBothMetaConvertible:
@@ -2487,7 +2567,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
of isGeneric:
inc(m.convMatches)
result = copyTree(arg)
result.typ = getInstantiatedType(c, arg, m, base(f))
result.typ() = getInstantiatedType(c, arg, m, base(f))
m.baseTypeMatch = true
of isFromIntLit:
inc(m.intConvMatches, 256)
@@ -2513,7 +2593,7 @@ proc staticAwareTypeRel(m: var TCandidate, f: PType, arg: var PNode): TTypeRelat
# The ast of the type does not point to the symbol.
# Without this we will never resolve a `static proc` with overloads
let copiedNode = copyNode(arg)
copiedNode.typ = exactReplica(copiedNode.typ)
copiedNode.typ() = exactReplica(copiedNode.typ)
copiedNode.typ.n = arg
arg = copiedNode
typeRel(m, f, arg.typ)
@@ -2568,7 +2648,8 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
for i in 0..<arg.len:
if arg[i].sym.kind in matchSet:
copyCandidate(z, m)
# we can shallow copy the bindings since they won't be used
shallowCopyCandidate(z, m)
z.callee = arg[i].typ
if arg[i].sym.kind == skType and z.callee.kind != tyTypeDesc:
# creating the symchoice with the type sym having typedesc type
@@ -2624,7 +2705,7 @@ proc setSon(father: PNode, at: int, son: PNode) =
# father[i] = newNodeIT(nkEmpty, son.info, getSysType(tyVoid))
# we are allowed to modify the calling node in the 'prepare*' procs:
proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
proc prepareOperand(c: PContext; formal: PType; a: PNode, newlyTyped: var bool): PNode =
if formal.kind == tyUntyped and formal.len != 1:
# {tyTypeDesc, tyUntyped, tyTyped, tyError}:
# a.typ == nil is valid
@@ -2642,15 +2723,17 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
#elif formal.kind == tyTyped: {efDetermineType, efWantStmt}
#else: {efDetermineType}
result = c.semOperand(c, a, flags)
newlyTyped = true
else:
result = a
considerGenSyms(c, result)
if result.kind != nkHiddenDeref and result.typ.kind in {tyVar, tyLent} and c.matchedConcept == nil:
result = newDeref(result)
proc prepareOperand(c: PContext; a: PNode): PNode =
proc prepareOperand(c: PContext; a: PNode, newlyTyped: var bool): PNode =
if a.typ.isNil:
result = c.semOperand(c, a, {efDetermineType})
newlyTyped = true
else:
result = a
considerGenSyms(c, result)
@@ -2776,8 +2859,10 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
noMatch()
m.baseTypeMatch = false
m.typedescMatched = false
n[a][1] = prepareOperand(c, formal.typ, n[a][1])
n[a].typ = n[a][1].typ
var newlyTyped = false
n[a][1] = prepareOperand(c, formal.typ, n[a][1], newlyTyped)
if newlyTyped: m.newlyTypedOperands.add(a)
n[a].typ() = n[a][1].typ
arg = paramTypesMatch(m, formal.typ, n[a].typ,
n[a][1], n[a][1])
m.firstMismatch.kind = kTypeMismatch
@@ -2800,7 +2885,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
if tfVarargs in m.callee.flags:
# is ok... but don't increment any counters...
# we have no formal here to snoop at:
n[a] = prepareOperand(c, n[a])
var newlyTyped = false
n[a] = prepareOperand(c, n[a], newlyTyped)
if newlyTyped: m.newlyTypedOperands.add(a)
if skipTypes(n[a].typ, abstractVar-{tyTypeDesc}).kind==tyString:
m.call.add implicitConv(nkHiddenStdConv,
getSysType(c.graph, n[a].info, tyCstring),
@@ -2814,7 +2901,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
m.baseTypeMatch = false
m.typedescMatched = false
incl(marker, formal.position)
n[a] = prepareOperand(c, formal.typ, n[a])
var newlyTyped = false
n[a] = prepareOperand(c, formal.typ, n[a], newlyTyped)
if newlyTyped: m.newlyTypedOperands.add(a)
arg = paramTypesMatch(m, formal.typ, n[a].typ,
n[a], nOrig[a])
if arg != nil and m.baseTypeMatch and container != nil:
@@ -2850,7 +2939,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
else:
m.baseTypeMatch = false
m.typedescMatched = false
n[a] = prepareOperand(c, formal.typ, n[a])
var newlyTyped = false
n[a] = prepareOperand(c, formal.typ, n[a], newlyTyped)
if newlyTyped: m.newlyTypedOperands.add(a)
arg = paramTypesMatch(m, formal.typ, n[a].typ,
n[a], nOrig[a])
if arg == nil:
@@ -2951,7 +3042,7 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
if m.calleeSym != nil: m.calleeSym.detailedInfo else: "")
typeMismatch(c.config, formal.ast.info, formal.typ, formal.ast.typ, formal.ast)
popInfoContext(c.config)
formal.ast.typ = errorType(c)
formal.ast.typ() = errorType(c)
if nfDefaultRefsParam in formal.ast.flags:
m.call.flags.incl nfDefaultRefsParam
var defaultValue = copyTree(formal.ast)
@@ -2960,7 +3051,7 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
# proc foo(x: T = 0.0)
# foo()
if {tfImplicitTypeParam, tfGenericTypeParam} * formal.typ.flags != {}:
let existing = idTableGet(m.bindings, formal.typ)
let existing = lookup(m.bindings, formal.typ)
if existing == nil or existing.kind == tyTypeDesc:
# see bug #11600:
put(m, formal.typ, defaultValue.typ)

View File

@@ -477,7 +477,7 @@ template foldSizeOf*(conf: ConfigRef; n: PNode; fallback: PNode): PNode =
if size >= 0:
let res = newIntNode(nkIntLit, size)
res.info = node.info
res.typ = node.typ
res.typ() = node.typ
res
else:
fallback
@@ -491,7 +491,7 @@ template foldAlignOf*(conf: ConfigRef; n: PNode; fallback: PNode): PNode =
if align >= 0:
let res = newIntNode(nkIntLit, align)
res.info = node.info
res.typ = node.typ
res.typ() = node.typ
res
else:
fallback
@@ -519,7 +519,7 @@ template foldOffsetOf*(conf: ConfigRef; n: PNode; fallback: PNode): PNode =
if offset >= 0:
let tmp = newIntNode(nkIntLit, offset)
tmp.info = node.info
tmp.typ = node.typ
tmp.typ() = node.typ
tmp
else:
fallback

View File

@@ -16,7 +16,7 @@ from trees import getMagic, getRoot
proc callProc(a: PNode): PNode =
result = newNodeI(nkCall, a.info)
result.add a
result.typ = a.typ.returnType
result.typ() = a.typ.returnType
# we have 4 cases to consider:
# - a void proc --> nothing to do
@@ -117,7 +117,7 @@ proc castToVoidPointer(g: ModuleGraph, n: PNode, fvField: PNode): PNode =
result = newNodeI(nkCast, fvField.info)
result.add newNodeI(nkEmpty, fvField.info)
result.add fvField
result.typ = ptrType
result.typ() = ptrType
proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
varSection, varInit, call, barrier, fv: PNode;
@@ -200,7 +200,7 @@ proc createCastExpr(argsParam: PSym; objType: PType; idgen: IdGenerator): PNode
result = newNodeI(nkCast, argsParam.info)
result.add newNodeI(nkEmpty, argsParam.info)
result.add newSymNode(argsParam)
result.typ = newType(tyPtr, idgen, objType.owner)
result.typ() = newType(tyPtr, idgen, objType.owner)
result.typ.rawAddSon(objType)
template checkMagicProcs(g: ModuleGraph, n: PNode, formal: PNode) =
@@ -266,9 +266,9 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType;
if argType.kind in {tyVarargs, tyOpenArray}:
# important special case: we always create a zero-copy slice:
let slice = newNodeI(nkCall, n.info, 4)
slice.typ = n.typ
slice.typ() = n.typ
slice[0] = newSymNode(createMagic(g, idgen, "slice", mSlice))
slice[0].typ = getSysType(g, n.info, tyInt) # fake type
slice[0].typ() = getSysType(g, n.info, tyInt) # fake type
var fieldB = newSym(skField, tmpName, idgen, objType.owner, n.info, g.config.options)
fieldB.typ = getSysType(g, n.info, tyInt)
discard objType.addField(fieldB, g.cache, idgen)

View File

@@ -56,7 +56,6 @@ type
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
deferDetected, tooEarly: bool
isIntroducingNewLocalVars: bool # true if we are in `introducingNewLocalVars` (don't transform yields)
inAddr: bool
flags: TransformFlags
graph: ModuleGraph
idgen: IdGenerator
@@ -98,17 +97,21 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
r.typ = typ #skipTypes(typ, {tyGenericInst, tyAlias, tySink})
incl(r.flags, sfFromGeneric)
let owner = getCurrOwner(c)
if owner.isIterator and not c.tooEarly and not isDefined(c.graph.config, "nimOptIters"):
result = freshVarForClosureIter(c.graph, r, c.idgen, owner)
else:
result = newSymNode(r)
result = newSymNode(r)
proc transform(c: PTransf, n: PNode): PNode
proc transform(c: PTransf, n: PNode, noConstFold = false): PNode
proc transformSons(c: PTransf, n: PNode): PNode =
proc transformSons(c: PTransf, n: PNode, noConstFold = false): PNode =
result = newTransNode(n)
for i in 0..<n.len:
result[i] = transform(c, n[i])
result[i] = transform(c, n[i], noConstFold)
proc transformSonsAfterType(c: PTransf, n: PNode, noConstFold = false): PNode =
result = newTransNode(n)
assert n.len != 0
result[0] = copyTree(n[0])
for i in 1..<n.len:
result[i] = transform(c, n[i], noConstFold)
proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode; isFirstWrite: bool): PNode =
result = newTransNode(kind, ri.info, 2)
@@ -177,13 +180,10 @@ proc transformSym(c: PTransf, n: PNode): PNode =
proc freshVar(c: PTransf; v: PSym): PNode =
let owner = getCurrOwner(c)
if owner.isIterator and not c.tooEarly and not isDefined(c.graph.config, "nimOptIters"):
result = freshVarForClosureIter(c.graph, v, c.idgen, owner)
else:
var newVar = copySym(v, c.idgen)
incl(newVar.flags, sfFromGeneric)
newVar.owner = owner
result = newSymNode(newVar)
var newVar = copySym(v, c.idgen)
incl(newVar.flags, sfFromGeneric)
setOwner(newVar, owner)
result = newSymNode(newVar)
proc transformVarSection(c: PTransf, v: PNode): PNode =
result = newTransNode(v)
@@ -363,7 +363,7 @@ proc transformAsgn(c: PTransf, n: PNode): PNode =
# given tuple type
newTupleConstr[i] = def[0]
newTupleConstr.typ = rhs.typ
newTupleConstr.typ() = rhs.typ
let asgnNode = newTransNode(nkAsgn, n.info, 2)
asgnNode[0] = transform(c, n[0])
@@ -373,6 +373,19 @@ proc transformAsgn(c: PTransf, n: PNode): PNode =
result[0] = letSection
result[1] = asgnNode
template assignTupleUnpacking(c: PTransf, e: PNode) =
for i in 0..<c.transCon.forStmt.len - 2:
if c.transCon.forStmt[i].kind == nkVarTuple:
for j in 0..<c.transCon.forStmt[i].len-1:
let lhs = c.transCon.forStmt[i][j]
let rhs = transform(c, newTupleAccess(c.graph, newTupleAccess(c.graph, e, i), j))
result.add(asgnTo(lhs, rhs))
else:
let lhs = c.transCon.forStmt[i]
let rhs = transform(c, newTupleAccess(c.graph, e, i))
result.add(asgnTo(lhs, rhs))
proc transformYield(c: PTransf, n: PNode): PNode =
proc asgnTo(lhs: PNode, rhs: PNode): PNode =
# Choose the right assignment instruction according to the given ``lhs``
@@ -407,7 +420,8 @@ proc transformYield(c: PTransf, n: PNode): PNode =
let lhs = c.transCon.forStmt[i]
let rhs = transform(c, v)
result.add(asgnTo(lhs, rhs))
elif e.kind notin {nkAddr, nkHiddenAddr}: # no need to generate temp for address operation
elif e.kind notin {nkAddr, nkHiddenAddr} and e.kind != nkSym:
# no need to generate temp for address operation + nodes without sideeffects
# TODO do not use temp for nodes which cannot have side-effects
var tmp = newTemp(c, e.typ, e.info)
let v = newNodeI(nkVarSection, e.info)
@@ -415,21 +429,9 @@ proc transformYield(c: PTransf, n: PNode): PNode =
result.add transform(c, v)
for i in 0..<c.transCon.forStmt.len - 2:
if c.transCon.forStmt[i].kind == nkVarTuple:
for j in 0..<c.transCon.forStmt[i].len-1:
let lhs = c.transCon.forStmt[i][j]
let rhs = transform(c, newTupleAccess(c.graph, newTupleAccess(c.graph, tmp, i), j))
result.add(asgnTo(lhs, rhs))
else:
let lhs = c.transCon.forStmt[i]
let rhs = transform(c, newTupleAccess(c.graph, tmp, i))
result.add(asgnTo(lhs, rhs))
assignTupleUnpacking(c, tmp)
else:
for i in 0..<c.transCon.forStmt.len - 2:
let lhs = c.transCon.forStmt[i]
let rhs = transform(c, newTupleAccess(c.graph, e, i))
result.add(asgnTo(lhs, rhs))
assignTupleUnpacking(c, e)
else:
if c.transCon.forStmt[0].kind == nkVarTuple:
var notLiteralTuple = false # we don't generate temp for tuples with const value: (1, 2, 3)
@@ -442,7 +444,8 @@ proc transformYield(c: PTransf, n: PNode): PNode =
else:
notLiteralTuple = true
if e.kind notin {nkAddr, nkHiddenAddr} and notLiteralTuple:
if e.kind notin {nkAddr, nkHiddenAddr} and notLiteralTuple and e.kind != nkSym:
# no need to generate temp for address operation + nodes without sideeffects
# TODO do not use temp for nodes which cannot have side-effects
var tmp = newTemp(c, e.typ, e.info)
let v = newNodeI(nkVarSection, e.info)
@@ -481,8 +484,8 @@ proc transformYield(c: PTransf, n: PNode): PNode =
result.add(introduceNewLocalVars(c, c.transCon.forLoopBody))
c.isIntroducingNewLocalVars = false
proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
result = transformSons(c, n)
proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds, isAddr = false): PNode =
result = transformSons(c, n, noConstFold = isAddr)
# inlining of 'var openarray' iterators; bug #19977
if n.typ.kind != tyOpenArray and (c.graph.config.backend == backendCpp or sfCompileToCpp in c.module.flags): return
var n = result
@@ -494,9 +497,9 @@ proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
n[0][0] = m[0]
result = n[0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
result.typ = n.typ
result.typ() = n.typ
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, c.idgen)
result.typ() = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, c.idgen)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
var m = n[0][1]
if m.kind in kinds:
@@ -504,9 +507,9 @@ proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
n[0][1] = m[0]
result = n[0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
result.typ = n.typ
result.typ() = n.typ
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, c.idgen)
result.typ() = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, c.idgen)
else:
if n[0].kind in kinds and
not (n[0][0].kind == nkSym and n[0][0].sym.kind == skForVar and
@@ -514,13 +517,15 @@ proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
) and not (n[0][0].kind == nkSym and n[0][0].sym.kind == skParam and
n.typ.kind == tyVar and
n.typ.skipTypes(abstractVar).kind == tyOpenArray and
n[0][0].typ.skipTypes(abstractVar).kind == tyString)
n[0][0].typ.skipTypes(abstractVar).kind == tyString) and
not (isAddr and n.typ.kind == tyVar and n[0][0].typ.kind == tyRef and
n[0][0].kind == nkObjConstr)
: # elimination is harmful to `for tuple unpack` because of newTupleAccess
# it is also harmful to openArrayLoc (var openArray) for strings
# addr ( deref ( x )) --> x
result = n[0][0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
result.typ = n.typ
result.typ() = n.typ
proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
## Converts 'prc' into '(thunk, nil)' so that it's compatible with
@@ -579,7 +584,7 @@ proc transformConv(c: PTransf, n: PNode): PNode =
else:
result = transform(c, n[1])
#result = transformSons(c, n)
result.typ = takeType(n.typ, n[1].typ, c.graph, c.idgen)
result.typ() = takeType(n.typ, n[1].typ, c.graph, c.idgen)
#echo n.info, " came here and produced ", typeToString(result.typ),
# " from ", typeToString(n.typ), " and ", typeToString(n[1].typ)
of tyCstring:
@@ -607,7 +612,7 @@ proc transformConv(c: PTransf, n: PNode): PNode =
result[0] = transform(c, n[1])
else:
result = transform(c, n[1])
result.typ = n.typ
result.typ() = n.typ
else:
result = transformSons(c, n)
of tyObject:
@@ -620,7 +625,7 @@ proc transformConv(c: PTransf, n: PNode): PNode =
result[0] = transform(c, n[1])
else:
result = transform(c, n[1])
result.typ = n.typ
result.typ() = n.typ
of tyGenericParam, tyOrdinal:
result = transform(c, n[1])
# happens sometimes for generated assignments, etc.
@@ -644,6 +649,12 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
case arg.kind
of nkStmtListExpr:
return paComplexOpenarray
of nkCall:
if skipTypes(arg.typ, abstractInst).kind in {tyOpenArray, tyVarargs}:
# XXX incorrect, causes #13417 when `arg` has side effects.
return paDirectMapping
else:
return paComplexOpenarray
of nkBracket:
return paFastAsgnTakeTypeFromArg
else:
@@ -810,7 +821,7 @@ proc transformFor(c: PTransf, n: PNode): PNode =
stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, addrExp, true))
newC.mapping[formal.itemId] = newDeref(temp)
of paComplexOpenarray:
# arrays will deep copy here (pretty bad).
# XXX arrays will deep copy here (pretty bad).
var temp = newTemp(c, arg.typ, formal.info)
addVar(v, temp)
stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg, true))
@@ -840,7 +851,7 @@ proc transformCase(c: PTransf, n: PNode): PNode =
# as an expr
let kind = if n.typ != nil: nkIfExpr else: nkIfStmt
ifs = newTransNode(kind, it.info, 0)
ifs.typ = n.typ
ifs.typ() = n.typ
ifs.add(e)
of nkElse:
if ifs == nil: result.add(e)
@@ -864,9 +875,18 @@ proc transformArrayAccess(c: PTransf, n: PNode): PNode =
if n[0].kind == nkSym and n[0].sym.kind == skType:
result = n
else:
result = newTransNode(n)
for i in 0..<n.len:
result[i] = transform(c, skipConv(n[i]))
result = transformSons(c, n)
if n.len >= 2 and result[1].kind in {nkChckRange, nkChckRange64} and
n[1].kind in {nkHiddenStdConv, nkHiddenSubConv}:
# implicit conversion, was transformed into range check
# remove in favor of index check if conversion to array index type
# has to be done here because the array index type needs to be relaxed
# i.e. a uint32 index can implicitly convert to range[0..3] but not int
let arr = skipTypes(n[0].typ, abstractVarRange)
if arr.kind == tyArray and
firstOrd(c.graph.config, arr) == getOrdValue(result[1][1]) and
lastOrd(c.graph.config, arr) == getOrdValue(result[1][2]):
result[1] = result[1].skipConv
proc getMergeOp(n: PNode): PSym =
case n.kind
@@ -948,7 +968,7 @@ proc transformExceptBranch(c: PTransf, n: PNode): PNode =
let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
convNode[0] = newNodeI(nkEmpty, n.info)
convNode[1] = excCall
convNode.typ = excTypeNode.typ.toRef(c.idgen)
convNode.typ() = excTypeNode.typ.toRef(c.idgen)
# -> let exc = ...
let identDefs = newTransNode(nkIdentDefs, n[1].info, 3)
identDefs[0] = n[0][2]
@@ -1005,12 +1025,12 @@ proc transformDerefBlock(c: PTransf, n: PNode): PNode =
# We transform (block: x)[] to (block: x[])
let e0 = n[0]
result = shallowCopy(e0)
result.typ = n.typ
result.typ() = n.typ
for i in 0 ..< e0.len - 1:
result[i] = e0[i]
result[e0.len-1] = newTreeIT(nkHiddenDeref, n.info, n.typ, e0[e0.len-1])
proc transform(c: PTransf, n: PNode): PNode =
proc transform(c: PTransf, n: PNode, noConstFold = false): PNode =
when false:
var oldDeferAnchor: PNode
if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
@@ -1076,13 +1096,8 @@ proc transform(c: PTransf, n: PNode): PNode =
of nkBreakStmt: result = transformBreak(c, n)
of nkCallKinds:
result = transformCall(c, n)
of nkHiddenAddr:
result = transformAddrDeref(c, n, {nkHiddenDeref})
of nkAddr:
let oldInAddr = c.inAddr
c.inAddr = true
result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref})
c.inAddr = oldInAddr
of nkAddr, nkHiddenAddr:
result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref}, isAddr = true)
of nkDerefExpr:
result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
of nkHiddenDeref:
@@ -1094,6 +1109,9 @@ proc transform(c: PTransf, n: PNode): PNode =
result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
result = transformConv(c, n)
of nkObjConstr, nkCast:
# don't try to transform type node
result = transformSonsAfterType(c, n)
of nkDiscardStmt:
result = n
if n[0].kind != nkEmpty:
@@ -1162,7 +1180,7 @@ proc transform(c: PTransf, n: PNode): PNode =
let exprIsPointerCast = n.kind in {nkCast, nkConv, nkHiddenStdConv} and
n.typ != nil and
n.typ.kind == tyPointer
if not exprIsPointerCast and not c.inAddr:
if not exprIsPointerCast and not noConstFold:
var cnst = getConstExpr(c.module, result, c.idgen, c.graph)
# we inline constants if they are not complex constants:
if cnst != nil and not dontInlineConstant(n, cnst):
@@ -1212,7 +1230,7 @@ proc liftDeferAux(n: PNode) =
tryStmt.add deferPart
n[i] = tryStmt
n.sons.setLen(i+1)
n.typ = tryStmt.typ
n.typ() = tryStmt.typ
goOn = true
break
for i in 0..n.safeLen-1:

View File

@@ -147,6 +147,13 @@ proc whichPragma*(n: PNode): TSpecialWord =
of nkCast: return wCast
of nkClosedSymChoice, nkOpenSymChoice:
return whichPragma(key[0])
of nkBracketExpr:
if n.kind notin nkPragmaCallKinds: return wInvalid
result = whichPragma(key[0])
if result notin {wHint, wHintAsError, wWarning, wWarningAsError}:
# note bracket pragmas, see processNote
result = wInvalid
return
else: return wInvalid
if result in nonPragmaWordsLow..nonPragmaWordsHigh:
result = wInvalid

View File

@@ -209,9 +209,6 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
result = typeAllowedAux(marker, t.skipModifier, kind, c, flags+{taHeap})
else:
result = t
of tyConcept:
if kind != skParam: result = t
else: result = nil
proc typeAllowed*(t: PType, kind: TSymKind; c: PContext; flags: TTypeAllowedFlags = {}): PType =
# returns 'nil' on success and otherwise the part of the type that is

View File

@@ -102,6 +102,9 @@ const
# typedescX is used if we're sure tyTypeDesc should be included (or skipped)
typedescPtrs* = abstractPtrs + {tyTypeDesc}
typedescInst* = abstractInst + {tyTypeDesc, tyOwned, tyUserTypeClass}
# incorrect definition of `[]` and `[]=` for these types in system.nim
arrPutGetMagicApplies* = {tyArray, tyOpenArray, tyString, tySequence, tyCstring, tyTuple}
proc invalidGenericInst*(f: PType): bool =
result = f.kind == tyGenericInst and skipModifier(f) == nil
@@ -1201,17 +1204,19 @@ proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool =
if not result: return
proc isGenericAlias*(t: PType): bool =
return t.kind == tyGenericInst and t.skipModifier.kind == tyGenericInst
return t.kind == tyGenericInst and t.skipModifier.skipTypes({tyAlias}).kind == tyGenericInst
proc genericAliasDepth*(t: PType): int =
result = 0
var it = t
var it = t.skipTypes({tyAlias})
while it.isGenericAlias:
it = it.skipModifier
it = it.skipModifier.skipTypes({tyAlias})
inc result
proc skipGenericAlias*(t: PType): PType =
return if t.isGenericAlias: t.skipModifier else: t
result = t.skipTypes({tyAlias})
if result.isGenericAlias:
result = result.skipModifier.skipTypes({tyAlias})
proc sameFlags*(a, b: PType): bool {.inline.} =
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
@@ -1304,16 +1309,34 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
cycleCheck()
result = sameTypeAux(a.skipModifier, b.skipModifier, c)
of tyObject:
withoutShallowFlags:
result = sameFlags(a, b)
if result:
ifFastObjectTypeCheckFailed(a, b):
cycleCheck()
result = sameObjectStructures(a, b, c) and sameFlags(a, b)
# should be generic, and belong to the same generic head type:
assert a.typeInst != nil, "generic object " & $a & " has no typeInst"
assert b.typeInst != nil, "generic object " & $b & " has no typeInst"
if result:
withoutShallowFlags:
# this is required because of generic `ref object`s,
# the value of their dereferences are not wrapped in `tyGenericInst`,
# so we need to check the generic parameters here
for ff, aa in underspecifiedPairs(a.typeInst, b.typeInst, 1, -1):
if not sameTypeAux(ff, aa, c): return false
of tyDistinct:
cycleCheck()
if c.cmp == dcEq:
if sameFlags(a, b):
result = sameFlags(a, b)
if result:
ifFastObjectTypeCheckFailed(a, b):
result = sameTypeAux(a.elementType, b.elementType, c)
# should be generic, and belong to the same generic head type:
assert a.typeInst != nil, "generic distinct type " & $a & " has no typeInst"
assert b.typeInst != nil, "generic distinct type " & $b & " has no typeInst"
withoutShallowFlags:
# just in case `tyGenericInst` was skipped at some point,
# we need to check the generic parameters here
for ff, aa in underspecifiedPairs(a.typeInst, b.typeInst, 1, -1):
if not sameTypeAux(ff, aa, c): return false
else:
result = sameTypeAux(a.elementType, b.elementType, c) and sameFlags(a, b)
of tyEnum, tyForward:
@@ -1685,7 +1708,7 @@ proc skipHidden*(n: PNode): PNode =
proc skipConvTakeType*(n: PNode): PNode =
result = n.skipConv
result.typ = n.typ
result.typ() = n.typ
proc isEmptyContainer*(t: PType): bool =
case t.kind
@@ -1725,7 +1748,7 @@ proc skipHiddenSubConv*(n: PNode; g: ModuleGraph; idgen: IdGenerator): PNode =
result = n
else:
result = copyTree(result)
result.typ = dest
result.typ() = dest
else:
result = n
@@ -1935,3 +1958,125 @@ proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool =
result = false
else:
result = false
proc isRefPtrObject*(t: PType): bool =
t.kind in {tyRef, tyPtr} and tfRefsAnonObj in t.flags
proc nominalRoot*(t: PType): PType =
## the "name" type of a given instance of a nominal type,
## i.e. the type directly associated with the symbol where the root
## nominal type of `t` was defined, skipping things like generic instances,
## aliases, `var`/`sink`/`typedesc` modifiers
##
## instead of returning the uninstantiated body of a generic type,
## returns the type of the symbol instead (with tyGenericBody type)
result = nil
case t.kind
of tyAlias, tyVar, tySink:
# varargs?
result = nominalRoot(t.skipModifier)
of tyTypeDesc:
# for proc foo(_: type T)
result = nominalRoot(t.skipModifier)
of tyGenericInvocation, tyGenericInst:
result = t
# skip aliases, so this works in the same module but not in another module:
# type Foo[T] = object
# type Bar[T] = Foo[T]
# proc foo[T](x: Bar[T]) = ... # attached to type
while result.skipModifier.kind in {tyGenericInvocation, tyGenericInst}:
result = result.skipModifier
result = nominalRoot(result[0])
of tyGenericBody:
result = t
# this time skip the aliases but take the generic body
while result.skipModifier.kind in {tyGenericInvocation, tyGenericInst}:
result = result.skipModifier[0]
let val = result.skipModifier
if val.kind in {tyDistinct, tyEnum, tyObject} or
isRefPtrObject(val):
# atomic nominal types, this generic body is attached to them
discard
else:
result = nominalRoot(val)
of tyCompositeTypeClass:
# parameter with type Foo
result = nominalRoot(t.skipModifier)
of tyGenericParam:
if t.genericParamHasConstraints:
# T: Foo
result = nominalRoot(t.genericConstraint)
else:
result = nil
of tyDistinct, tyEnum, tyObject:
result = t
of tyPtr, tyRef:
if tfRefsAnonObj in t.flags:
# in the case that we have `type Foo = ref object` etc
result = t
else:
# we could allow this in general, but there's things like `seq[Foo]`
#result = nominalRoot(t.skipModifier)
result = nil
of tyStatic:
result = nominalRoot(t.base)
else:
# skips all typeclasses
# is this correct for `concept`?
result = nil
proc genericRoot*(t: PType): PType =
## gets the root generic type (`tyGenericBody`) from `t`,
## if `t` is a generic type or the body of a generic instantiation
case t.kind
of tyGenericBody:
result = t
of tyGenericInst, tyGenericInvocation:
result = t.genericHead
else:
if t.typeInst != nil:
result = t.typeInst.genericHead
elif t.sym != nil and t.sym.typ.kind == tyGenericBody:
# can happen if `t` is the last child (body) of the generic body
result = t.sym.typ
else:
result = nil
proc reduceToBase*(f: PType): PType =
#[
Returns the lowest order (most general) type that that is compatible with the input.
E.g.
A[T] = ptr object ... A -> ptr object
A[N: static[int]] = array[N, int] ... A -> array
]#
case f.kind:
of tyGenericParam:
if f.len <= 0 or f.skipModifier == nil:
result = f
else:
result = reduceToBase(f.skipModifier)
of tyGenericInvocation:
result = reduceToBase(f.baseClass)
of tyCompositeTypeClass, tyAlias:
if not f.hasElementType or f.elementType == nil:
result = f
else:
result = reduceToBase(f.elementType)
of tyGenericInst:
result = reduceToBase(f.skipModifier)
of tyGenericBody:
result = reduceToBase(f.typeBodyImpl)
of tyUserTypeClass:
if f.isResolvedUserTypeClass:
result = f.base # ?? idk if this is right
else:
result = f.skipModifier
of tyStatic, tyOwned, tyVar, tyLent, tySink:
result = reduceToBase(f.base)
of tyInferred:
# This is not true "After a candidate type is selected"
result = reduceToBase(f.base)
of tyRange:
result = f.elementType
else:
result = f

View File

@@ -202,7 +202,7 @@ proc copyValue(src: PNode): PNode =
return src
result = newNode(src.kind)
result.info = src.info
result.typ = src.typ
result.typ() = src.typ
result.flags = src.flags * PersistentNodeFlags
result.comment = src.comment
when defined(useNodeIds):
@@ -516,6 +516,8 @@ const
errIllegalConvFromXtoY = "illegal conversion from '$1' to '$2'"
errTooManyIterations = "interpretation requires too many iterations; " &
"if you are sure this is not a bug in your code, compile with `--maxLoopIterationsVM:number` (current value: $1)"
errCallDepthExceeded = "maximum call depth for the VM exceeded; " &
"if you are sure this is not a bug in your code, compile with `--maxCallDepthVM:number` (current value: $1)"
errFieldXNotFound = "node lacks field: "
@@ -590,6 +592,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let newPc = c.cleanUpOnReturn(tos)
# Perform any cleanup action before returning
if newPc < 0:
inc(c.callDepth)
pc = tos.comesFrom
let retVal = regs[0]
tos = tos.next
@@ -1276,6 +1279,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
createSet(regs[ra])
move(regs[ra].node.sons,
nimsets.diffSets(c.config, regs[rb].node, regs[rc].node).sons)
of opcXorSet:
decodeBC(rkNode)
createSet(regs[ra])
move(regs[ra].node.sons,
nimsets.symdiffSets(c.config, regs[rb].node, regs[rc].node).sons)
of opcConcatStr:
decodeBC(rkNode)
createStr regs[ra]
@@ -1440,6 +1448,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
newFrame.slots[i] = regs[rb+i]
if isClosure:
newFrame.slots[rc] = TFullReg(kind: rkNode, node: regs[rb].node[1])
if c.callDepth <= 0:
if allowInfiniteRecursion in c.features:
c.callDepth = c.config.maxCallDepthVM
else:
msgWriteln(c.config, "stack trace: (most recent call last)", {msgNoUnitSep})
stackTraceAux(c, tos, pc)
globalError(c.config, c.debug[pc], errCallDepthExceeded % $c.config.maxCallDepthVM)
dec(c.callDepth)
tos = newFrame
updateRegsAlias
# -1 for the following 'inc pc'
@@ -1532,10 +1548,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
# Set the `name` field of the exception
var exceptionNameNode = newStrNode(nkStrLit, c.currentExceptionA.typ.sym.name.s)
if c.currentExceptionA[2].kind == nkExprColonExpr:
exceptionNameNode.typ = c.currentExceptionA[2][1].typ
exceptionNameNode.typ() = c.currentExceptionA[2][1].typ
c.currentExceptionA[2][1] = exceptionNameNode
else:
exceptionNameNode.typ = c.currentExceptionA[2].typ
exceptionNameNode.typ() = c.currentExceptionA[2].typ
c.currentExceptionA[2] = exceptionNameNode
c.exceptionInstr = pc
@@ -1577,7 +1593,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let instr2 = c.code[pc]
let count = regs[instr2.regA].intVal.int
regs[ra].node = newNodeI(nkBracket, c.debug[pc])
regs[ra].node.typ = typ
regs[ra].node.typ() = typ
newSeq(regs[ra].node.sons, count)
for i in 0..<count:
regs[ra].node[i] = getNullValue(c, typ.elementType, c.debug[pc], c.config)
@@ -1992,7 +2008,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
else:
internalAssert c.config, false
regs[ra].node.info = n.info
regs[ra].node.typ = n.typ
regs[ra].node.typ() = n.typ
of opcNCopyLineInfo:
decodeB(rkNode)
regs[ra].node.info = regs[rb].node.info
@@ -2072,7 +2088,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
ensureKind(rkNode)
regs[ra].node = temp
regs[ra].node.info = c.debug[pc]
regs[ra].node.typ = typ
regs[ra].node.typ() = typ
of opcConv:
let rb = instr.regB
inc pc
@@ -2306,6 +2322,7 @@ proc execute(c: PCtx, start: int): PNode =
proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
c.loopIterations = c.config.maxLoopIterationsVM
c.callDepth = c.config.maxCallDepthVM
if sym.kind in routineKinds:
if sym.typ.paramsLen != args.len:
result = nil
@@ -2332,9 +2349,17 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
localError(c.config, sym.info,
"NimScript: attempt to call non-routine: " & sym.name.s)
proc errorNode(idgen: IdGenerator; owner: PSym, n: PNode): PNode =
result = newNodeI(nkEmpty, n.info)
result.typ() = newType(tyError, idgen, owner)
result.typ.flags.incl tfCheckedForDestructor
proc evalStmt*(c: PCtx, n: PNode) =
let n = transformExpr(c.graph, c.idgen, c.module, n)
let start = genStmt(c, n)
if c.cannotEval:
c.cannotEval = false
return
# execute new instructions; this redundant opcEof check saves us lots
# of allocations in 'execute':
if c.code[start].opcode != opcEof:
@@ -2345,7 +2370,10 @@ proc evalExpr*(c: PCtx, n: PNode): PNode =
# `nim --eval:"expr"` might've used it at some point for idetools; could
# be revived for nimsuggest
let n = transformExpr(c.graph, c.idgen, c.module, n)
c.cannotEval = false
let start = genExpr(c, n)
if c.cannotEval:
return errorNode(c.idgen, c.module, n)
assert c.code[start].opcode != opcEof
result = execute(c, start)
@@ -2398,7 +2426,10 @@ proc evalConstExprAux(module: PSym; idgen: IdGenerator;
var c = PCtx g.vm
let oldMode = c.mode
c.mode = mode
c.cannotEval = false
let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
if c.cannotEval:
return errorNode(idgen, prc, n)
if c.code[start].opcode == opcEof: return newNodeI(nkEmpty, n.info)
assert c.code[start].opcode != opcEof
when debugEchoCode: c.echoCode start
@@ -2455,7 +2486,7 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
var n = x
if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n[1]
n.flags.incl nfIsRef
n.typ = x.typ
n.typ() = x.typ
result = TFullReg(kind: rkNode, node: n)
iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
@@ -2469,11 +2500,6 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
# to prevent endless recursion in macro instantiation
const evalMacroLimit = 1000
#proc errorNode(idgen: IdGenerator; owner: PSym, n: PNode): PNode =
# result = newNodeI(nkEmpty, n.info)
# result.typ = newType(tyError, idgen, owner)
# result.typ.flags.incl tfCheckedForDestructor
proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstCounter: ref int;
n, nOrig: PNode, sym: PSym): PNode =
#if g.config.errorCounter > 0: return errorNode(idgen, module, n)
@@ -2497,7 +2523,10 @@ proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstC
c.comesFromHeuristic.line = 0'u16
c.callsite = nOrig
c.templInstCounter = templInstCounter
c.cannotEval = false
let start = genProc(c, sym)
if c.cannotEval:
return errorNode(idgen, module, n)
var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil)
let maxSlots = sym.offset

View File

@@ -100,7 +100,7 @@ type
opcEqRef, opcEqNimNode, opcSameNodeType,
opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
opcEqStr, opcEqCString, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
opcMulSet, opcPlusSet, opcMinusSet, opcConcatStr,
opcMulSet, opcPlusSet, opcMinusSet, opcXorSet, opcConcatStr,
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
opcIsNil, opcOf, opcIs,
opcParseFloat, opcConv, opcCast,
@@ -201,6 +201,7 @@ type
TSandboxFlag* = enum ## what the evaluation engine should allow
allowCast, ## allow unsafe language feature: 'cast'
allowInfiniteLoops ## allow endless loops
allowInfiniteRecursion ## allow infinite recursion
TSandboxFlags* = set[TSandboxFlag]
TSlotKind* = enum # We try to re-use slots in a smart way to
@@ -257,7 +258,7 @@ type
mode*: TEvalMode
features*: TSandboxFlags
traceActive*: bool
loopIterations*: int
loopIterations*, callDepth*: int
comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces
callbacks*: seq[VmCallback]
callbackIndex*: Table[string, int]
@@ -270,6 +271,7 @@ type
templInstCounter*: ref int # gives every template instantiation a unique ID, needed here for getAst
vmstateDiff*: seq[(PSym, PNode)] # we remember the "diff" to global state here (feature for IC)
procToCodePos*: Table[int, int]
cannotEval*: bool
PStackFrame* = ref TStackFrame
TStackFrame* {.acyclic.} = object
@@ -293,6 +295,7 @@ proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph; idgen: IdGenerator
PCtx(code: @[], debug: @[],
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
prc: PProc(blocks: @[]), module: module, loopIterations: g.config.maxLoopIterationsVM,
callDepth: g.config.maxCallDepthVM,
comesFromHeuristic: unknownLineInfo, callbacks: @[], callbackIndex: initTable[string, int](), errorFlag: "",
cache: cache, config: g.config, graph: g, idgen: idgen)
@@ -300,6 +303,7 @@ proc refresh*(c: PCtx, module: PSym; idgen: IdGenerator) =
c.module = module
c.prc = PProc(blocks: @[])
c.loopIterations = c.config.maxLoopIterationsVM
c.callDepth = c.config.maxCallDepthVM
c.idgen = idgen
proc reverseName(s: string): string =

View File

@@ -35,7 +35,7 @@ proc atomicTypeX(cache: IdentCache; name: string; m: TMagic; t: PType; info: TLi
sym.magic = m
sym.typ = t
result = newSymNode(sym)
result.typ = t
result.typ() = t
proc atomicTypeX(s: PSym; info: TLineInfo): PNode =
result = newSymNode(s)
@@ -52,7 +52,7 @@ proc mapTypeToBracketX(cache: IdentCache; name: string; m: TMagic; t: PType; inf
for a in t.kids:
if a == nil:
let voidt = atomicTypeX(cache, "void", mVoid, t, info, idgen)
voidt.typ = newType(tyVoid, idgen, t.owner)
voidt.typ() = newType(tyVoid, idgen, t.owner)
result.add voidt
else:
result.add mapTypeToAstX(cache, a, info, idgen, inst)
@@ -136,7 +136,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
if allowRecursion:
result = mapTypeToAstR(t.skipModifier, info)
# keep original type info for getType calls on the output node:
result.typ = t
result.typ() = t
else:
result = newNodeX(nkBracketExpr)
#result.add mapTypeToAst(t.last, info)
@@ -146,7 +146,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
else:
result = mapTypeToAstX(cache, t.skipModifier, info, idgen, inst, allowRecursion)
# keep original type info for getType calls on the output node:
result.typ = t
result.typ() = t
of tyGenericBody:
if inst:
result = mapTypeToAstR(t.typeBodyImpl, info)

View File

@@ -1212,6 +1212,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMag
of mMulSet: genBinarySet(c, n, dest, opcMulSet)
of mPlusSet: genBinarySet(c, n, dest, opcPlusSet)
of mMinusSet: genBinarySet(c, n, dest, opcMinusSet)
of mXorSet: genBinarySet(c, n, dest, opcXorSet)
of mConStrStr: genVarargsABC(c, n, dest, opcConcatStr)
of mInSet: genBinarySet(c, n, dest, opcContainsSet)
of mRepr: genUnaryABC(c, n, dest, opcRepr)
@@ -1473,9 +1474,9 @@ proc canElimAddr(n: PNode; idgen: IdGenerator): PNode =
result = copyNode(n[0])
result.add m[0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
result.typ = n.typ
result.typ() = n.typ
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen)
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}:
@@ -1484,9 +1485,9 @@ proc canElimAddr(n: PNode; idgen: IdGenerator): PNode =
result.add n[0][0]
result.add m[0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
result.typ = n.typ
result.typ() = n.typ
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen)
result.typ() = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen)
else:
if n[0].kind in {nkDerefExpr, nkHiddenDeref}:
# addr ( deref ( x )) --> x
@@ -1542,9 +1543,12 @@ proc setSlot(c: PCtx; v: PSym) =
v.position = getFreeRegister(c, if v.kind == skLet: slotFixedLet else: slotFixedVar, start = 1)
template cannotEval(c: PCtx; n: PNode) =
if c.config.cmd == cmdCheck:
if c.config.cmd == cmdCheck and c.config.m.errorOutputs != {}:
# nim check command with no error outputs doesn't need to cascade here,
# includes `tryConstExpr` case which should not continue generating code
localError(c.config, n.info, "cannot evaluate at compile time: " &
n.renderTree)
c.cannotEval = true
return
globalError(c.config, n.info, "cannot evaluate at compile time: " &
n.renderTree)
@@ -1678,7 +1682,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
var n = newNode(nkType)
n.typ = t
n.typ() = t
genLit(c, n, dest)
proc isEmptyBody(n: PNode): bool =
@@ -1847,7 +1851,7 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags
let fieldName = $accessExpr[1]
let msg = genFieldDefect(c.config, fieldName, disc.sym)
let strLit = newStrNode(msg, accessExpr[1].info)
strLit.typ = strType
strLit.typ() = strType
c.genLit(strLit, msgReg)
c.gABC(n, opcInvalidField, msgReg, discVal)
c.freeTemp(discVal)
@@ -2036,7 +2040,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
c.gABx(n, opcLdNull, dest, c.genType(n.typ))
let intType = getSysType(c.graph, n.info, tyInt)
let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
let seqType = n.typ.skipTypes(abstractVar+{tyStatic}-{tyTypeDesc})
if seqType.kind == tySequence:
var tmp = c.getTemp(intType)
c.gABx(n, opcLdImmInt, tmp, n.len)

View File

@@ -263,7 +263,7 @@ proc registerAdditionalOps*(c: PCtx) =
wrap2si(readLines, ioop)
systemop getCurrentExceptionMsg
systemop getCurrentException
registerCallback c, "stdlib.osdirs.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
registerCallback c, "stdlib.staticos.staticWalkDir", proc (a: VmArgs) {.nimcall.} =
setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1)))
registerCallback c, "stdlib.staticos.staticDirExists", proc (a: VmArgs) {.nimcall.} =
setResult(a, dirExists(getString(a, 0)))

View File

@@ -15,7 +15,6 @@ proc dispatch(x: Base, params: ...) =
var disp = newNodeI(nkIfStmt, base.info)
var vTableAccess = newNodeIT(nkBracketExpr, base.info, base.typ)
let nimGetVTableSym = getCompilerProc(g, "nimGetVTable")
let ptrPNimType = nimGetVTableSym.typ.n[1].sym.typ
@@ -33,13 +32,13 @@ proc dispatch(x: Base, params: ...) =
dispatchObject,
newIntNode(nkIntLit, index)
)
getVTableCall.typ = base.typ
getVTableCall.typ() = getSysType(g, unknownLineInfo, tyPointer)
var vTableCall = newNodeIT(nkCall, base.info, base.typ.returnType)
var castNode = newTree(nkCast,
newNodeIT(nkType, base.info, base.typ),
getVTableCall)
castNode.typ = base.typ
castNode.typ() = base.typ
vTableCall.add castNode
for col in 1..<paramLen:
let param = base.typ.n[col].sym

View File

@@ -1,7 +1,7 @@
=====================================================
Nim -- a Compiler for Nim. https://nim-lang.org/
Copyright (C) 2006-2024 Andreas Rumpf. All rights reserved.
Copyright (C) 2006-2025 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
@@ -21,4 +21,4 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
[ MIT license: http://www.opensource.org/licenses/mit-license.php ]
[ MIT license: https://www.opensource.org/licenses/mit-license.php ]

View File

@@ -51,7 +51,7 @@ Advanced options:
--spellSuggest:num show at most `num >= 0` spelling suggestions on typos.
if `num` is not specified (or `auto`), return
an implementation defined set of suggestions.
--hints:on|off|list. `on|off` enables or disables hints.
--hints:on|off|list `on|off` enables or disables hints.
`list` reports which hints are selected.
--hint:X:on|off turn specific hint X on|off. `hint:X` means `hint:X:on`,
as with similar flags. `all` is the set of all hints
@@ -165,6 +165,7 @@ Advanced options:
--verbosity:0|1|2|3 set Nim's verbosity level (1 is default)
--errorMax:N stop compilation after N errors; 0 means unlimited
--maxLoopIterationsVM:N set max iterations for all VM loops
--maxCallDepthVM:N set max call depth in the VM
--experimental:$1
enable experimental language feature
--legacy:$2

View File

@@ -31,7 +31,7 @@ Objective-C targets and the JavaScript target. [The C like targets](
into a library or a final executable. [The JavaScript target](
#backends-the-javascript-target) can generate a ``.js`` file which you
reference from an HTML file or create a [standalone Node.js program](
http://nodejs.org).
https://nodejs.org).
On top of generating libraries or standalone applications, Nim offers
bidirectional interfacing with the backend targets through generic and
@@ -87,20 +87,19 @@ available. This includes:
* OS-specific operations
* threading, coroutines
* some modules of the standard library
* proper 64-bit integer arithmetic
To compensate, the standard library has modules [catered to the JS backend](
lib.html#pure-libraries-modules-for-js-backend)
lib.html#pure-libraries-modules-for-the-javascript-backend)
and more support will come in the future (for instance, Node.js bindings
to get OS info).
To compile a Nim module into a ``.js`` file use the `js`:option: command; the
default is a ``.js`` file that is supposed to be referenced in an ``.html``
file. However, you can also run the code with `nodejs`:idx:
(http://nodejs.org):
(https://nodejs.org):
```cmd
nim js -d:nodejs -r examples/hallo.nim
nim js -r examples/hallo.nim
```
If you experience errors saying that `globalThis` is not defined, be
@@ -250,7 +249,7 @@ which will likely make your program crash at runtime.
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
When compiling to static or dynamic libraries, they don't call destructors of global variables as normal Nim programs would do. A C API `NimDestroyGlobals` is provided to call these global destructors.
When compiling to static or dynamic libraries, they don't call destructors of global variables as normal Nim programs would do. A C API `NimDestroyGlobals` is provided to call these global destructors. It is influenced by the `--nimMainPrefix:prefix` switch, too.
### Nim invocation example from C
@@ -359,7 +358,7 @@ Memory management
In the previous sections, the `NimMain()` function reared its head. Since
JavaScript already provides automatic memory management, you can freely pass
objects between the two languages without problems. In C and derivate languages
objects between the two languages without problems. In C and derivative languages
you need to be careful about what you do and how you share memory. The
previous examples only dealt with simple scalar values, but passing a Nim
string to C, or reading back a C string in Nim already requires you to be

View File

@@ -67,7 +67,7 @@ Documentation Comments
Any comments which are preceded by a double-hash (`##`), are interpreted as
documentation. Comments are parsed as RST (see [reference](
http://docutils.sourceforge.net/docs/user/rst/quickref.html)), providing
https://docutils.sourceforge.net/docs/user/rst/quickref.html)), providing
Nim module authors the ability to easily generate richly formatted
documentation with only their well-documented code!
Basic Markdown syntax is also supported inside the doc comments.

View File

@@ -241,5 +241,5 @@ JavaScript target
=================
Once your code is compiled for hot reloading, a convenient solution for implementing the actual reloading
in the browser using a framework such as [LiveReload](http://livereload.com/)
in the browser using a framework such as [LiveReload](https://livereload.com/)
or [BrowserSync](https://browsersync.io/).

View File

@@ -2241,6 +2241,10 @@ Nim supports these `calling conventions`:idx:\:
only a hint for the compiler: it may completely ignore it, and
it may inline procedures that are not marked as `inline`.
`noinline`:idx:
: The backend compiler may inline procedures that are not marked as `inline`.
The noinline convention prevents it.
`fastcall`:idx:
: Fastcall means different things to different C compilers. One gets whatever
the C `__fastcall` means.
@@ -2623,12 +2627,12 @@ In a call `p(args)` where `p` may refer to more than one
candidate, it is said to be a symbol choice. Overload resolution will attempt to
find the best candidate, thus transforming the symbol choice into a resolved symbol.
The routine `p` that matches best is selected following a series of trials explained below.
In order: Catagory matching, Hierarchical Order Comparison, and finally, Complexity Analysis.
In order: Category matching, Hierarchical Order Comparison, and finally, Complexity Analysis.
If multiple candidates match equally well after all trials have been tested, the ambiguity
is reported during semantic analysis.
First Trial: Catagory matching
First Trial: Category matching
--------------------------------
Every arg in `args` needs to match and there are multiple different categories of matches.
@@ -2689,7 +2693,7 @@ Matching formals for this type include `T`, `object`, `A`, `A[...]` and `A[C]` w
is a generic typeclass composition and `T` is an unconstrained generic type variable. This list is in order of
specificity with respect to `A` as each subsequent category narrows the set of types that are members of their match set.
In this trail, the formal parameters of candidates are compared in order (1st parameter, 2nd parameter, etc.) to search for
In this trial, the formal parameters of candidates are compared in order (1st parameter, 2nd parameter, etc.) to search for
a candidate that has an unrivaled specificity. If such a formal parameter is found, the candidate it belongs to is chosen
as the resolved symbol.
@@ -5169,7 +5173,7 @@ It is possible to raise/catch imported C++ exceptions. Types imported using
`importcpp` can be raised or caught. Exceptions are raised by value and
caught by reference. Example:
```nim test = "nim cpp -r $1"
```nim
type
CStdException {.importcpp: "std::exception", header: "<exception>", inheritable.} = object
## does not inherit from `RootObj`, so we use `inheritable` instead
@@ -6260,7 +6264,7 @@ The default for symbols of entity `type`, `var`, `let` and `const`
is `gensym`. For `proc`, `iterator`, `converter`, `template`,
`macro`, the default is `inject`, but if a `gensym` symbol with the same name
is defined in the same syntax-level scope, it will be `gensym` by default.
This can be overriden by marking the routine as `inject`.
This can be overridden by marking the routine as `inject`.
If the name of the entity is passed as a template parameter, it is an `inject`'ed symbol:
@@ -8646,6 +8650,14 @@ pragma should be used in addition to the `exportc` pragma. See
[Dynlib pragma for export].
Exportcpp pragma
----------------
The `exportcpp` pragma works like the `exportc` pragma but it requires the `cpp` backend.
When compiled with the `cpp` backend, the `exportc` pragma adds `export "C"` to
the declaration in the generated code so that it can be called from both C and
C++ code. `exportcpp` pragma doesn't add `export "C"`.
Extern pragma
-------------
Like `exportc` or `importc`, the `extern` pragma affects name

View File

@@ -2667,3 +2667,114 @@ proc nothing() =
```
The current C(C++) backend implementation cannot generate code for gcc and for vcc at the same time. For example, `{.asmSyntax: "vcc".}` with the ICC compiler will not generate code with intel asm syntax, even though ICC can use both gcc-like and vcc-like asm.
Type-bound overloads
====================
With the experimental option `--experimental:typeBoundOps`, each "root"
nominal type (namely `object`, `enum`, `distinct`, direct `Foo = ref object`
types as well as their generic versions) can have operations attached to it.
Exported top-level routines declared in the same scope as a nominal type
with a parameter having a type directly deriving from that nominal type (i.e.
with `var`/`sink`/`typedesc` modifiers or being in a generic constraint)
are considered "attached" to the respective nominal type.
This applies to every parameter regardless of placement.
When a call to a symbol is openly overloaded and overload matching starts,
for all arguments in the call that have already undergone type checking,
routines with the same name attached to the root nominal type (if it exists)
of each given argument are added as a candidate to the overload match.
This also happens as arguments gradually get typed after every match to an overload.
This is so that the only overloads considered out of scope are
attached to the types of the given arguments, and that matches to
`untyped` or missing parameters are not influenced by outside overloads.
If no overloads with a given name are in scope, then overload matching
will not begin, and so type-bound overloads are not considered for that name.
Similarly, if the only overloads with a given name require a parameter to be
`untyped` or missing, then type-bound overloads will not be considered for
the argument in that position.
Generally this means that a "base" overload with a compliant signature should
be in scope so that type-bound overloads can be used.
In the case of ambiguity between distinct local/imported and type-bound symbols
in overload matching, type-bound symbols are considered as a less specific
scope than imports.
An example with the `hash` interface in the standard library is as follows:
```nim
# objs.nim
import std/hashes
type
Obj* = object
x*, y*: int
z*: string # to be ignored for equality
proc `==`*(a, b: Obj): bool =
a.x == b.x and a.y == b.y
proc hash*(a: Obj): Hash =
$!(hash(a.x) &! hash(a.y))
# here both `==` and `hash` are attached to Obj
# 1. they are both exported
# 2. they are in the same scope as Obj
# 3. they have parameters with types directly deriving from Obj
# 4. Obj is nominal
```
```nim
# main.nim
{.experimental: "typeBoundOps".}
from objs import Obj # objs.hash, objs.`==` not imported
import std/tables
# tables use `hash`, only using the overloads in `std/hashes` and
# the ones in instantiation scope (in this case, there are none)
var t: Table[Obj, int]
# because tables use `hash` and `==` in a compliant way,
# the overloads bound to Obj are also considered, and in this case match best
t[Obj(x: 3, y: 4, z: "debug")] = 34
# if `hash` for all objects as in `std/hashes` was used, this would error:
echo t[Obj(x: 3, y: 4, z: "ignored")] # 34
```
Another example, this time with `$` and indirect imports:
```nim
# foo.nim
type Foo* = object
x*, y*: int
proc `$`*(f: Foo): string =
"Foo(" & $f.x & ", " & $f.y & ")"
```
```nim
# bar.nim
import foo
proc makeFoo*(x, y: int): Foo =
Foo(x: x, y: y)
proc useFoo*(f: Foo) =
echo "used: ", f # directly calls `foo.$` from scope
```
```nim
# debugger.nim
proc debug*[T](obj: T) =
echo "debugging: ", obj # calls generic `$`
```
```nim
# main.nim
{.experimental: "typeBoundOps".}
import bar, debugger # `foo` not imported, so `foo.$` not in scope
let f = makeFoo(123, 456)
useFoo(f) # used: Foo(123, 456)
debug(f) # debugging: Foo(123, 456)
```

View File

@@ -21,7 +21,7 @@ library should follow.
Note that there can be exceptions to these rules. Nim being as flexible as it
is, there will be parts of this style guide that don't make sense in certain
contexts. Furthermore, just as
[Python's style guide](http://legacy.python.org/dev/peps/pep-0008/) changes
[Python's style guide](https://legacy.python.org/dev/peps/pep-0008/) changes
over time, this style guide will too.
These rules will only be enforced for contributions to the Nim

View File

@@ -24,7 +24,7 @@ on the different supported platforms. It is not a definition of the Nim
programming language (which is covered in the [manual](manual.html)).
Nim is free software; it is licensed under the
[MIT License](http://www.opensource.org/licenses/mit-license.php).
[MIT License](https://www.opensource.org/licenses/mit-license.php).
Compiler Usage

View File

@@ -770,11 +770,10 @@ div.topic {
div.search_results {
background-color: var(--third-background);
margin: 3vh 5vw;
padding: 1em;
border: 1px solid #4d4d4d;
position: fixed;
top: 10px;
position: sticky;
top: 1em;
isolation: isolate;
max-width: calc(100vw - 6em);
z-index: 1;

View File

@@ -14,7 +14,7 @@ Introduction
niminst is a tool to generate an installer for a Nim program. Currently
it can create an installer for Windows
via [Inno Setup](http://www.jrsoftware.org/isinfo.php) as well as
via [Inno Setup](https://www.jrsoftware.org/isinfo.php) as well as
installation/deinstallation scripts for UNIX. Later versions will support
Linux' package management systems.

View File

@@ -41,7 +41,7 @@ Regular expression syntax and semantics
=======================================
As the regular expressions supported by this module are enormous,
the reader is referred to http://perldoc.perl.org/perlre.html for the
the reader is referred to https://perldoc.perl.org/perlre.html for the
full documentation of Perl's regular expressions.
Because the backslash ``\`` is a meta character both in the Nim

View File

@@ -30,28 +30,30 @@ a working NodeJS on `PATH`.
Commands
========
========================== ==========================
p|pat|pattern <glob> run all the tests matching the given pattern
all run all tests inside of category folders
c|cat|category <category> run all the tests of a certain category
r|run <test> run single test file
html generate testresults.html from the database
========================== ==========================
Options
=======
--print print results to the console
--verbose print commands (compiling and running tests)
--simulate see what tests would be run but don't run them (for debugging)
--failing only show failing/ignored tests
--targets:"c cpp js objc" run tests for specified targets (default: c)
--nim:path use a particular nim executable (default: $PATH/nim)
--directory:dir Change to directory dir before reading the tests or doing anything else.
--colors:on|off Turn messages coloring on|off.
--backendLogging:on|off Disable or enable backend logging. By default turned on.
--megatest:on|off Enable or disable megatest. Default is on.
--valgrind:on|off Enable or disable valgrind support. Default is on.
--skipFrom:file Read tests to skip from `file` - one test per line, # comments ignored
--print print results to the console
--verbose print commands (compiling and running tests)
--simulate see what tests would be run but don't run them (for debugging)
--failing only show failing/ignored tests
--targets:"c cpp js objc" run tests for specified targets (default: c)
--nim:path use a particular nim executable (default: $PATH/nim)
--directory:dir Change to directory dir before reading the tests or doing anything else.
--colors:on|off Turn messages coloring on|off.
--backendLogging:on|off Disable or enable backend logging. By default turned on.
--megatest:on|off Enable or disable megatest. Default is on.
--valgrind:on|off Enable or disable valgrind support. Default is on.
--skipFrom:file Read tests to skip from `file` - one test per line, # comments ignored
Running a single test

View File

@@ -1182,6 +1182,9 @@ at runtime by 0, the second by 1, and so on. For example:
var x = south # `x` is of type `Direction`; its value is `south`
echo x # prints "south"
if x == Direction.south:
echo "It's south!"
```
All the comparison operators can be used with enumeration types.

View File

@@ -11,7 +11,7 @@
const
# examples of possible values for repos: Head, ea82b54
NimbleStableCommit = "4fb6f8e6c33963f6f510fe82d09ad2a61b5e4265" # 0.16.1
NimbleStableCommit = "123f97a5e4ee9ba35720c0869e19a047c43c797e" # 0.16.4
AtlasStableCommit = "5faec3e9a33afe99a7d22377dd1b45a5391f5504"
ChecksumsStableCommit = "bd9bf4eaea124bf8d01e08f92ac1b14c6879d8d3"
SatStableCommit = "faf1617f44d7632ee9601ebc13887644925dcc01"
@@ -159,13 +159,12 @@ proc bundleNimbleExe(latest: bool, args: string) =
let commit = if latest: "HEAD" else: NimbleStableCommit
cloneDependency(distDir, "https://github.com/nim-lang/nimble.git",
commit = commit, allowBundled = true)
cloneDependency(distDir / "nimble" / distDir, "https://github.com/nim-lang/checksums.git",
commit = ChecksumsStableCommit, allowBundled = true) # or copy it from dist?
cloneDependency(distDir / "nimble" / distDir, "https://github.com/nim-lang/sat.git",
commit = SatStableCommit, allowBundled = true)
# installer.ini expects it under $nim/bin
updateSubmodules(distDir / "nimble", allowBundled = true)
nimCompile("dist/nimble/src/nimble.nim",
options = "-d:release -d:nimNimbleBootstrap --noNimblePath " & args)
options = "-d:release --noNimblePath " & args)
const zippyTests = "dist/nimble/vendor/zippy/tests"
if dirExists(zippyTests):
removeDir(zippyTests)
proc bundleAtlasExe(latest: bool, args: string) =
let commit = if latest: "HEAD" else: AtlasStableCommit

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